Skip to content

Instantly share code, notes, and snippets.

@yajd
Last active August 29, 2015 14:03
Show Gist options
  • Save yajd/862832b07a1d46caef8b to your computer and use it in GitHub Desktop.
Save yajd/862832b07a1d46caef8b to your computer and use it in GitHub Desktop.
_ff-addon-snippet-RelaunchCommand - Working on Relaunch properties of Win7.
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);
@Noitidart
Copy link

Here's how to QI IPropertyStore from ShelLink to set properties on a shortcut I would think:

https://github.com/dlunch/foo_alsong_lyric/blob/aba6c9061213d37980c010025263ffae31a752de/src/foo_alsong_lyric/UIWnd.cpp#L211

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;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment