-
-
Save yajd/862832b07a1d46caef8b to your computer and use it in GitHub Desktop.
Cu.import('resource://gre/modules/ctypes.jsm'); | |
var shell32 = ctypes.open('shell32.dll'); | |
var ole32 = ctypes.open('Ole32.dll'); | |
var shlwapi = ctypes.open('Shlwapi.dll'); | |
/* http://msdn.microsoft.com/en-us/library/ff718266.aspx | |
* typedef struct { | |
* unsigned long Data1; | |
* unsigned short Data2; | |
* unsigned short Data3; | |
* byte Data4[8]; | |
* } GUID, UUID, *PGUID; | |
*/ | |
var struct_GUID = ctypes.StructType('GUID', [ | |
{'Data1': ctypes.unsigned_long}, | |
{'Data2': ctypes.unsigned_short}, | |
{'Data3': ctypes.unsigned_short}, | |
{'Data4': ctypes.char.array(8)} | |
]); | |
/* http://msdn.microsoft.com/en-us/library/cc237652.aspx | |
* typedef GUID IID; | |
*/ | |
var IID = struct_GUID; | |
/* http://msdn.microsoft.com/en-us/library/cc237816.aspx | |
* typedef IID* REFIID; | |
*/ | |
var REFIID = new ctypes.PointerType(IID); | |
/* http://msdn.microsoft.com/en-us/library/windows/desktop/ms680589%28v=vs.85%29.aspx | |
* HRESULT CLSIDFromString( | |
* __in_ LPCOLESTR lpsz, | |
* __out_ LPCLSID pclsid | |
); | |
*/ | |
var CLSIDFromString = ole32.declare('CLSIDFromString', ctypes.winapi_abi, ctypes.long, // HRESULT | |
new ctypes.PointerType(ctypes.jschar), // LPCOLESTR | |
struct_GUID.ptr // LPCLSID | |
); | |
/* http://msdn.microsoft.com/en-us/library/windows/desktop/dd378430%28v=vs.85%29.aspx | |
* HRESULT SHGetPropertyStoreForWindow( | |
* __in_ HWND hwnd, | |
* __in_ REFIID riid, | |
* __out_ void **ppv | |
* ); | |
*/ | |
var SHGetPropertyStoreForWindow = shell32.declare('SHGetPropertyStoreForWindow', ctypes.winapi_abi, ctypes.long, // HRESULT | |
ctypes.voidptr_t, // HWND | |
REFIID, // REFIID | |
ctypes.voidptr_t // VOID | |
); | |
/* http://msdn.microsoft.com/en-us/library/windows/desktop/bb773381%28v=vs.85%29.aspx | |
* typedef struct { | |
* GUID fmtid; | |
* DWORD pid; | |
* } PROPERTYKEY; | |
*/ | |
var struct_PROPERTYKEY = ctypes.StructType('PROPERTYKEY', [ // this is also known as PKEY i learned from seeing this: https://github.com/truonghinh/TnX/blob/260a8a623751ffbce14bad6018ea48febbc21bc6/TnX-v8/Microsoft.Windows.Shell/Standard/ShellProvider.cs#L345 | |
{'fmtid': struct_GUID}, // GUID | |
{'pid': ctypes.unsigned_long} // DWORD | |
]); | |
/* http://msdn.microsoft.com/en-us/library/windows/desktop/bb773381%28v=vs.85%29.aspx | |
* typedef struct PROPVARIANT { | |
* VARTYPE vt; | |
* WORD wReserved1; | |
* WORD wReserved2; | |
* WORD wReserved3; | |
* union { | |
* CHAR cVal; | |
* UCHAR bVal; | |
* SHORT iVal; | |
* USHORT uiVal; | |
* LONG lVal; | |
* ULONG ulVal; | |
* INT intVal; | |
* UINT uintVal; | |
* LARGE_INTEGER hVal; | |
* ULARGE_INTEGER uhVal; | |
* FLOAT fltVal; | |
* DOUBLE dblVal; | |
* VARIANT_BOOL boolVal; | |
* SCODE scode; | |
* CY cyVal; | |
* DATE date; | |
* FILETIME filetime; | |
* CLSID *puuid; | |
* CLIPDATA *pclipdata; | |
* BSTR bstrVal; | |
* BSTRBLOB bstrblobVal; | |
* BLOB blob; | |
* LPSTR pszVal; | |
* LPWSTR pwszVal; | |
* IUnknown *punkVal; | |
* IDispatch *pdispVal; | |
* IStream *pStream; | |
* IStorage *pStorage; | |
* LPVERSIONEDSTREAM pVersionedStream; | |
* LPSAFEARRAY parray; | |
* CAC cac; | |
* CAUB caub; | |
* CAI cai; | |
* CAUI caui; | |
* CAL cal; | |
* CAUL caul; | |
* CAH cah; | |
* CAUH cauh; | |
* CAFLT caflt; | |
* CADBL cadbl; | |
* CABOOL cabool; | |
* CASCODE cascode; | |
* CACY cacy; | |
* CADATE cadate; | |
* CAFILETIME cafiletime; | |
* CACLSID cauuid; | |
* CACLIPDATA caclipdata; | |
* CABSTR cabstr; | |
* CABSTRBLOB cabstrblob; | |
* CALPSTR calpstr; | |
* CALPWSTR calpwstr; | |
* CAPROPVARIANT capropvar; | |
* CHAR *pcVal; | |
* UCHAR *pbVal; | |
* SHORT *piVal; | |
* USHORT *puiVal; | |
* LONG *plVal; | |
* ULONG *pulVal; | |
* INT *pintVal; | |
* UINT *puintVal; | |
* FLOAT *pfltVal; | |
* DOUBLE *pdblVal; | |
* VARIANT_BOOL *pboolVal; | |
* DECIMAL *pdecVal; | |
* SCODE *pscode; | |
* CY *pcyVal; | |
* DATE *pdate; | |
* BSTR *pbstrVal; | |
* IUnknown **ppunkVal; | |
* IDispatch **ppdispVal; | |
* LPSAFEARRAY *pparray; | |
* PROPVARIANT *pvarVal; | |
* }; | |
* } PROPVARIANT; | |
*/ | |
var struct_PROPVARIANT = ctypes.StructType('PROPVARIANT', [ | |
{'fntud': struct_GUID}, // GUID | |
{'pid': ctypes.unsigned_long}, // DWORD | |
// union not supported by js-ctypes | |
// https://bugzilla.mozilla.org/show_bug.cgi?id=535378 "You can always | |
// typecast pointers, at least as long as you know which type is the biggest" | |
{'pwszVal': new ctypes.PointerType(ctypes.jschar)} // LPWSTR | |
]); | |
/* http://msdn.microsoft.com/en-us/library/windows/desktop/bb762305%28v=vs.85%29.aspx | |
* REMARKS: This is an inline function, with its source code provided in the header. It is not included in any .dll or .lib file. | |
* HRESULT InitPropVariantFromString( | |
* __in_ PCWSTR psz, | |
* __out_ PROPVARIANT *ppropvar | |
* ); | |
SOURCE2: https://github.com/dreamsxin/qutIM/blob/f4c4e4da3f82f14d82cfd42a16f31219c9e5cacb/plugins/docktile/qtdocktile/src/plugins/windows/wrapper/_winapi.h#L17 | |
inline HRESULT InitPropVariantFromString(PCWSTR string, PROPVARIANT *propvar) | |
{ | |
propvar->vt = VT_LPWSTR; | |
HRESULT hr = SHStrDupW(string, &propvar->pwszVal); | |
if (FAILED(hr)) { | |
WinApi::PropVariantInit(propvar); | |
} | |
return hr; | |
} | |
*/ | |
/* | |
* var InitPropVariantFromString = propsys.declare('InitPropVariantFromString', ctypes.winapi_abi, ctypes.long, // HRESULT | |
* ctypes.jschar.ptr, // PCWSTR | |
* struct_PROPVARIANT.ptr // PROPVARIANT | |
* ); | |
*/ | |
function InitPropVariantFromString(string /** PCWSTR **/, propvarPtr /** PROPVARIANT pointer **/) { | |
//console.log('propvarPtr.contents.pwszVal', propvarPtr.contents.pwszVal, propvarPtr.contents.pwszVal.toSource(), uneval(propvarPtr.contents.pwszVal)); | |
//console.log('propvarPtr', propvarPtr); | |
console.log('propvarPtr.contents.pwszVal', propvarPtr.contents.pwszVal); | |
console.log('propvarPtr.contents.pwszVal.address()', propvarPtr.contents.pwszVal.address()); | |
var hr = SHStrDup(string, propvarPtr.contents.pwszVal.address()); | |
console.error('hr = ', hr, hr.toSource(), uneval(hr), hr.toString()); | |
console.log('propvarPtr.contents.pwszVal', propvarPtr.contents.pwszVal); | |
if (!checkHRESULT(hr)) { | |
console.log('having to PropVariantInit'); | |
PropVariantInit(propvarPtr); | |
} else { | |
console.info('YAHOO SUCESSS'); | |
} | |
return true; | |
} | |
/* http://msdn.microsoft.com/en-us/library/windows/desktop/aa380293%28v=vs.85%29.aspx | |
* REMARKS: Probably no dll for this one... | |
* void PropVariantInit( | |
* __out_ PROPVARIANT *pvar | |
* ); | |
SOURCE2: https://github.com/dreamsxin/qutIM/blob/f4c4e4da3f82f14d82cfd42a16f31219c9e5cacb/plugins/docktile/qtdocktile/src/plugins/windows/wrapper/_winapi.h#L12 | |
void PropVariantInit(PROPVARIANT *variant) | |
{ | |
memset(variant, 0, sizeof(PROPVARIANT)); | |
} | |
*/ | |
var PropVariantInit = function(variantPointer) { | |
//memset(variantPointer, 0, variantPointer.size); //no need for this in js-ctypes because things always initialized at 0 | |
return true; | |
} | |
/* http://msdn.microsoft.com/en-us/library/windows/desktop/bb759924%28v=vs.85%29.aspx | |
* HRESULT SHStrDup( | |
* __in_ LPCTSTR pszSource, | |
* __out_ LPTSTR *ppwsz | |
* ); | |
*/ | |
var SHStrDup = shlwapi.declare('SHStrDupW', ctypes.winapi_abi, ctypes.long, // HRESULT | |
ctypes.voidptr_t, // LPCTSTR // can possibly also make this ctypes.char.ptr // im trying to pass PCWSTR here, i am making it as `ctypes.jschar.array()('blah blah').address()` | |
ctypes.voidptr_t // LPTSTR // can possibly also make this ctypes.char.ptr | |
); | |
/* http://msdn.microsoft.com/en-us/library/windows/desktop/aa380073%28v=vs.85%29.aspx | |
* WINOLEAPI PropVariantClear( | |
* __in_ PROPVARIANT *pvar | |
* ); | |
*/ | |
var PropVariantClear = ole32.declare('PropVariantClear', ctypes.winapi_abi, ctypes.voidptr_t, // WINOLEAPI | |
struct_PROPVARIANT.ptr // PROPVARIANT | |
); | |
/*http://msdn.microsoft.com/en-us/library/windows/desktop/ee330727%28v=vs.85%29.aspx | |
* void IID_PPV_ARGS( | |
* T **pType | |
* ); | |
*/ | |
// maybe: http://blogs.msdn.com/b/yvesdolc/archive/2006/12/27/iid-ppv-args-macro.aspx | |
// var IID_PPV_ARGS = shell32.declare('IID_PPV_ARGS', ctypes.winapi_abi, ctypes.voidptr_t, // void | |
// ctypes.voidptr_t // T | |
// ); | |
/* SOURCE1: http://msdn.microsoft.com/en-us/library/windows/desktop/bb761475%28v=vs.85%29.aspx | |
* HRESULT SetValue( | |
* __in_ REFPROPERTYKEY key, | |
* __in_ REFPROPVARIANT propvar | |
* ); | |
* SOURCE2: http://blogs.msdn.com/b/oldnewthing/archive/2011/06/01/10170113.aspx | |
* HRESULT IPropertyStore_SetValue(IPropertyStore *pps, | |
* REFPROPERTYKEY pkey, PCWSTR pszValue) | |
* { | |
* PROPVARIANT var; | |
* HRESULT hr = InitPropVariantFromString(pszValue, &var); | |
* if (SUCCEEDED(hr)) | |
* { | |
* hr = pps->SetValue(pkey, var); | |
* PropVariantClear(&var); | |
* } | |
* return hr; | |
* } | |
*/ | |
var IPropertyStore_SetValue = function(pps /** IPopertyStore pointer **/, pkey /** PROPERTYKEY **/, pszValue /** PCWSTR **/) { | |
//pps must be passed in as reference | |
var v = new struct_PROPVARIANT(); // PROPVARIANT | |
var rez = InitPropVariantFromString(pszValue, v.address()); | |
if (rez) { | |
console.info('pps.SetValue', pps.SetValue); | |
pps.SetValue(pkey, v); | |
} else { | |
throw new Error('failed InitPropVariantFromString'); | |
} | |
return true; | |
} | |
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa378137%28v=vs.85%29.aspx | |
var S_OK = 0; | |
var S_FALSE = 1; | |
function onCreate(hwnd) { | |
var ppv = ctypes.voidptr_t(0); | |
var pps = new IID(); | |
var HR_pps = CLSIDFromString('{886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99}', pps.address()); | |
if (!checkHRESULT(HR_pps)) { | |
throw new Error('checkHRESULT error'); | |
} | |
//console.log('pps', pps.toSource()); | |
var hr = SHGetPropertyStoreForWindow(hwnd, pps.address(), ppv.address()); | |
console.error('hr = ', hr, hr.toSource(), uneval(hr), hr.toString()); | |
if (!checkHRESULT(hr)) { //this throws so no need to do an if on hr brelow, im not sure that was possible anyways as hr is now `-2147467262` and its throwing, before thi, with my `if (hr)` it would continue thinking it passed | |
throw new Error('checkHRESULT error'); | |
} | |
var pszValue = ctypes.jschar.array()('Contoso.Scratch'); // PCWSTR | |
IPropertyStore_SetValue(pps.address(), PKEY_AppUserModel_ID, pszValue.address()); | |
var pszValue = ctypes.jschar.array()('notepad.exe %windir%\\system.ini'); // PCWSTR | |
IPropertyStore_SetValue(pps.address(), PKEY_AppUserModel_RelaunchCommand, pszValue.address()); //relaucnhcommand and relaunchdispnameresc must both be set otherise if just do one, then it will not take | |
var pszValue = ctypes.jschar.array()('C:\\full\\path\\to\\scratch.exe,-1'); // PCWSTR; | |
IPropertyStore_SetValue(pps.address(), PKEY_AppUserModel_RelaunchDisplayNameResource, pszValue.address()); //relaucnhcommand and relaunchdispnameresc must both be set otherise if just do one, then it will not take | |
//var pszValue = ctypes.jschar.array()('C:\\full\\path\\to\\scratch.ico'); // PCWSTR; | |
//IPropertyStore_SetValue(pps, PKEY_AppUserModel_RelaunchIconResource, pszValue.address()); //optional | |
return true; | |
} | |
// start - error handling funcs (Source: https://github.com/FunkMonkey/Loomo/blob/2c0a7a042b91c430ca89fd22d5003ccb7dbf57dd/Loomo/chrome/content/modules/Utils/COM/COM.jsm) | |
function checkHRESULT(hr) { | |
if (hr != S_OK) { | |
//throw new Error("TESTERR"); | |
console.error('checkHRESULT error = ', new COMError(hr)); | |
return false; | |
} | |
return true; | |
} | |
function COMError(hr) { | |
// Well, we don't subclass, cause for some reason that fucks up the callstack | |
var name = "COMError " + hr + " (0x" + decimalToHexString(parseInt(hr.toString())) + ")"; | |
var err = new Error(name); | |
err.isCOMError = true; | |
err.name = name; | |
err.message = name + " Well, go and bing!!!"; | |
return err; | |
} | |
function decimalToHexString(number) { | |
if (number < 0) { | |
number = 0xFFFFFFFF + number + 1; | |
} | |
return number.toString(16).toUpperCase(); | |
} | |
// end : error handling funcs | |
var me = Services.wm.getMostRecentWindow(null); | |
var baseWindow = me.QueryInterface(Ci.nsIInterfaceRequestor) | |
.getInterface(Ci.nsIWebNavigation) | |
.QueryInterface(Ci.nsIDocShellTreeItem) | |
.treeOwner | |
.QueryInterface(Ci.nsIInterfaceRequestor) | |
.nsIBaseWindow; | |
var nativeHandle = baseWindow.nativeHandle; | |
var targetWindow_handle = ctypes.voidptr_t(ctypes.UInt64(nativeHandle)); | |
/* pid's and guid string's for my 4 properties above (PKEY_AppUserModel_ID, PKEY_AppUserModel_RelaunchIconResource, etc) and more found at following two sources: | |
* setting pkey = https://github.com/truonghinh/TnX/blob/260a8a623751ffbce14bad6018ea48febbc21bc6/TnX-v8/Microsoft.Windows.Shell/Standard/ShellProvider.cs#L358 | |
* setting pkey in py = https://github.com/liuheng/byp/blob/28c26f8903dc122237982e2c19b58dce35612ad8/thirdlib/pywin32/com/win32comext/propsys/pscon.py#L712 | |
*/ | |
var myGUID = new struct_GUID(); | |
var HR_myGUID = CLSIDFromString('{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}', myGUID.address()); // same for guid for: id, relaubchcommand, relaunchdisp, and relaunchicon | |
if (!checkHRESULT(HR_myGUID)) { | |
throw new Error('checkHRESULT error'); | |
} | |
console.log('myGUID', myGUID); | |
// Create PKEY for AppUserModel_ID | |
var PKEY_AppUserModel_ID = new struct_PROPERTYKEY(); | |
PKEY_AppUserModel_ID.fmtid = myGUID; | |
PKEY_AppUserModel_ID.pid = 5; | |
// Create PKEY for AppUserModel_RelaunchCommand | |
var PKEY_AppUserModel_RelaunchCommand = new struct_PROPERTYKEY(); | |
PKEY_AppUserModel_RelaunchCommand.fmtid = myGUID; | |
PKEY_AppUserModel_RelaunchCommand.pid = 2; | |
// Create PKEY for AppUserModel_RelaunchDisplayNameResource | |
var PKEY_AppUserModel_RelaunchDisplayNameResource = new struct_PROPERTYKEY(); | |
PKEY_AppUserModel_RelaunchDisplayNameResource.fmtid = myGUID; | |
PKEY_AppUserModel_RelaunchDisplayNameResource.pid = 4; | |
// Create PKEY for AppUserModel_RelaunchIconResource | |
var PKEY_AppUserModel_RelaunchIconResource = new struct_PROPERTYKEY(); | |
PKEY_AppUserModel_RelaunchIconResource.fmtid = myGUID; | |
PKEY_AppUserModel_RelaunchIconResource.pid = 3; | |
onCreate(targetWindow_handle); |
Issues summary as of Rev5
- in the C code he's passing two arguments to
SHGetPropertyStoreForWindow
but it should take three. That's why in my jsctypes code it throws, not enough arguments. L#237 - He is also running
IID_PPV_ARGS
on thepps
, which is a macro. This macro takes one argumentT **pType
, what on earth is typeT
? I just set that tovoidptr_t
IID_PPV_ARGS
returnsWINOLEAPI
I can't figure out what the js-ctypes equivalent is so i set it tovoidptr_t
- The onCreate function takes a second argument
lpcs
but he doesnt use it anywhere in the code, is it safe to ommit? - The third argument to pass to
IPropertyStore_SetValue
is typePCWSTR
this translates toctypes.jschar.ptr
. Is it proper to pass it like this:new ctypes.PointerType(ctypes.jschar('blah'))
L#240 - I have no idea what DLL winapi functions like
PropVariantClear
andInitPropVariantFromString
are coming from, their MSDN pages don't say which DLL. - I'm conufsed on how to make the PROPVARIANT structure as it has something called a
VARTYPE
which I can't figure out the js-types equivalent. And aunion
which i found something on FireTray but is it rightly done? L#142
What is structure for pps
? I need to pass address of this to IID_PPV_ARGS
which I pass to SHGetPropertyStoreForWindow
For Rev9:
- Probably make that
unionOf72
to thepwszVal
as that is whatInitPropVariantFromString
is using on first line:var hr = SHStrDupW(string, propvar.pwszVal);
- Added the
checkHRESULT
for the other places I useHRESULT
s because right now like inInitPropVariantFromString
I'm just testing withif (hr)
and that will obviously fail because ifhr
is successful it is0
.
Rev11
Not yet added as rev of this gist but its over here: https://github.com/Noitidart/_scratchpad/blob/master/IPropertyStore%20COM%20jsctypes.js
- REAL progress, fixed up A LOT as I didn't know what I was doing back then
- Put code style into ostypes scratchpad format for easy porting
- Fixed up
InitPropVariantFromString
- Got
SetValue
andRelease
- Fixed up a lot of stuff, worked on it from ground up, based on Tim A.'s
shortcutservice.jsm
, and now Im not getting an error when trying to set ID of most recent window, however its not working in that its not actually setting the id, otherwise the window would move out of the tab group. I emailed Tim A for help.- By the way as I based it on shortcutservice.jsm i fixed up a lot of improperly defined functions in the
vtbl
ofIShellLink
, see previous rev of my scratchpad for my fixes of it, i ended up commenting it out as i didnt need it for iPropertyStore,: GitHub :: Noitidart / _scratchpad / IPropertyStore COM jsctypes.js - Rev95
- By the way as I based it on shortcutservice.jsm i fixed up a lot of improperly defined functions in the
This guy here does IShellLink and IPropertyStore via ctypes in java to change the icon of an exe. Real cool: https://github.com/FoxyCorndog/WorkspaceOld/blob/db920ee0628f0f6f1ef07f45ad86c4de97905f3d/SWT/src/org/eclipse/swt/widgets/TaskBar.java#L212
This also shows a case where I would need to QueryInterface IPropertyStore from IShellLink. Which I had but undid as I didn't need it for this purpose. I had it like this in rev95 here: https://github.com/Noitidart/_scratchpad/blob/f8ac49ffcaebee19ed5a2e8e29230d2e34bea899/IPropertyStore%20COM%20jsctypes.js#L668
Here is a copy paste of the code from that repo (just in case he deletes the repo or something):
It's in java:
int /*long*/ createShellLink (MenuItem item, String directory) {
int style = item.getStyle ();
if ((style & SWT.CASCADE) != 0) return 0;
int /*long*/ [] ppv = new int /*long*/ [1];
int hr = OS.CoCreateInstance (CLSID_ShellLink, 0, OS.CLSCTX_INPROC_SERVER, IID_IShellLinkW, ppv);
if (hr != OS.S_OK) error (SWT.ERROR_NO_HANDLES);
int /*long*/ pLink = ppv [0];
int /*long*/ hHeap = OS.GetProcessHeap ();
int /*long*/ pv = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, OS.PROPVARIANT_sizeof());
int /*long*/ titlePtr = 0;
PROPERTYKEY key;
if ((style & SWT.SEPARATOR) != 0) {
OS.MoveMemory (pv, new short [] {OS.VT_BOOL}, 2);
OS.MoveMemory (pv + 8, new short [] {OS.VARIANT_TRUE}, 2);
key = PKEY_AppUserModel_IsDestListSeparator;
} else {
String text = item.getText ();
int length = text.length ();
char [] buffer = new char [length + 1];
text.getChars (0, length, buffer, 0);
titlePtr = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, buffer.length * 2);
OS.MoveMemory (titlePtr, buffer, buffer.length * 2);
OS.MoveMemory (pv, new short [] {OS.VT_LPWSTR}, 2);
OS.MoveMemory (pv + 8, new int /*long*/ [] {titlePtr}, OS.PTR_SIZEOF);
key = PKEY_Title;
/*IShellLink::SetPath*/
String exePath = (String)item.getData (EXE_PATH_KEY);
if (exePath != null) {
length = exePath.length ();
buffer = new char [length + 1];
exePath.getChars (0, length, buffer, 0);
} else {
buffer = EXE_PATH;
}
hr = OS.VtblCall (20, pLink, buffer);
if (hr != OS.S_OK) error (SWT.ERROR_INVALID_ARGUMENT);
text = (String)item.getData (EXE_ARGS_KEY);
if (text == null) text = Display.LAUNCHER_PREFIX + Display.TASKBAR_EVENT + item.id;
length = text.length ();
buffer = new char [length + 1];
text.getChars (0, length, buffer, 0);
/*IShellLink::SetArguments*/
hr = OS.VtblCall (11, pLink, buffer);
if (hr != OS.S_OK) error (SWT.ERROR_INVALID_ARGUMENT);
/* This code is intentionally commented */
// String tooltip = item.tooltip;
// if (tooltip != null) {
// length = tooltip.length ();
// buffer = new char [length + 1];
// tooltip.getChars (0, length, buffer, 0);
// /*IShellLink::SetDescription*/
// hr = OS.VtblCall (7, pLink, buffer);
// if (hr != OS.S_OK) error (SWT.ERROR_INVALID_ARGUMENT);
// }
String icon = (String)item.getData (ICON_KEY);
int index = 0;
if (icon != null) {
text = (String)item.getData (ICON_INDEX_KEY);
if (text != null) index = Integer.parseInt (text);
} else {
Image image = item.getImage ();
if (image != null && directory != null) {
icon = directory + "\\menu" + item.id + ".ico" ;
ImageData data;
if (item.hBitmap != 0) {
Image image2 = Image.win32_new (display, SWT.BITMAP, item.hBitmap);
data = image2.getImageData ();
} else {
data = image.getImageData ();
}
ImageLoader loader = new ImageLoader ();
loader.data = new ImageData [] {data};
loader.save (icon, SWT.IMAGE_ICO);
}
}
if (icon != null) {
length = icon.length ();
buffer = new char [length + 1];
icon.getChars (0, length, buffer, 0);
/*IShellLink::SetIconLocation*/
hr = OS.VtblCall (17, pLink, buffer, index);
if (hr != OS.S_OK) error (SWT.ERROR_INVALID_ARGUMENT);
}
}
/*IUnknown::QueryInterface*/
hr = OS.VtblCall (0, pLink, IID_IPropertyStore, ppv);
if (hr != OS.S_OK) error (SWT.ERROR_NO_HANDLES);
int /*long*/ pPropStore = ppv [0];
/*IPropertyStore::SetValue*/
hr = OS.VtblCall (6, pPropStore, key, pv);
if (hr != OS.S_OK) error (SWT.ERROR_INVALID_ARGUMENT);
/*IPropertyStore::Commit*/
OS.VtblCall (7, pPropStore);
/*IUnknown::Release*/
OS.VtblCall (2, pPropStore);
OS.HeapFree (hHeap, 0, pv);
if (titlePtr != 0) OS.HeapFree (hHeap, 0, titlePtr);
return pLink;
}
Here's how to QI IPropertyStore from ShelLink to set properties on a shortcut I would think:
int UIWnd::AddTaskList(std::wstring command, std::wstring display, std::wstring appid)
{
ICustomDestinationList *destlist = NULL;
CoCreateInstance(CLSID_DestinationList, NULL, CLSCTX_INPROC_SERVER, IID_ICustomDestinationList, (void **)&destlist);
if(destlist) //main window list
{
UINT MinSlot;
IObjectArray *removed;
if(appid.size())
destlist->SetAppID(appid.c_str());
destlist->BeginList(&MinSlot, IID_IObjectArray, (void **)&removed);
IObjectCollection *tasks;
CoCreateInstance(CLSID_EnumerableObjectCollection, NULL, CLSCTX_INPROC_SERVER, IID_IObjectCollection, (void **)&tasks);
IShellLink *link;
CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&link);
wchar_t name[255];
GetModuleFileName(GetModuleHandle(L"foobar2000.exe"), name, 255);
link->SetPath(name);
link->SetArguments((std::wstring(L"/command:\"") + command + L"\"").c_str());
IPropertyStore *propstore;
link->QueryInterface(IID_IPropertyStore, (void **)&propstore);
PROPVARIANT pv;
InitPropVariantFromString(display.c_str(), &pv);
propstore->SetValue(PKEY_Title, pv);
propstore->Commit();
propstore->Release();
tasks->AddObject(link);
IObjectArray *arr;
tasks->QueryInterface(IID_IObjectArray, (void **)&arr);
destlist->AddUserTasks(arr);
destlist->CommitList();
destlist->Release();
tasks->Release();
arr->Release();
link->Release();
removed->Release();
return 1;
}
return 0;
}
DLL for
PropVariantClear
isOle32.dll
DLL for
InitPropVariantFromString
isPropsys.dll
maybe/probably.