From a96eb81f0970c23c1e10f987ceb3f9a59cb30d6e Mon Sep 17 00:00:00 2001 From: Noitidart Date: Sun, 22 Mar 2015 04:51:36 -0700 Subject: [PATCH] 1.2.rev148 * Addressing issue #18 * On startup now applying the proper icon (if not pinned there is a couple seconds of lag for the icon to kick in as startup of browser takes place) * Previous rev implemented applying icon from badge selection process (by clicking on activity icon in Profilist menu) but it did not set it on the right profile, it would set on current profile, still working on targetting profile thats running but not itself --- bootstrap.js | 203 ++++++++++++++++++++++------ modules/ostypes_win.jsm | 208 +++++++++++++++++++++++++++- modules/workers/ProfilistWorker.js | 209 ++++++++++++++++++++++++++++- 3 files changed, 571 insertions(+), 49 deletions(-) diff --git a/bootstrap.js b/bootstrap.js index f2d2cba..1402f14 100644 --- a/bootstrap.js +++ b/bootstrap.js @@ -3453,6 +3453,11 @@ function updateIconToAllWindows(aProfilePath, useIconNameStr, aDOMWin) { // useIconNameStr should be string of path + // resolves + // true if done + // false if not needed + + console.log('in updateIconToAllWindows'); var deferredMain_updateIconToAllWindows = new Deferred(); @@ -3462,6 +3467,7 @@ function updateIconToAllWindows(aProfilePath, useIconNameStr, aDOMWin) { } var do_getIconName = function() { + /* var promise_getIconName = getProfileSpecs(aProfilePath); promise_getIconName.then( function(aVal) { @@ -3483,48 +3489,141 @@ function updateIconToAllWindows(aProfilePath, useIconNameStr, aDOMWin) { deferredMain_updateIconToAllWindows.reject(rejObj); } ); + */ + // have to do makeIcon because icon may not exist + var promise_getIconName = makeIcon(aProfilePath); + promise_getIconName.then( + function(aVal) { + console.log('Fullfilled - promise_getIconName - ', aVal); + // start - do stuff here - promise_getIconName + useIconNameStr = aVal.profSpecs.iconNameObj.str; + do_applyIcon(); + // end - do stuff here - promise_getIconName + }, + function(aReason) { + var rejObj = {name:'promise_getIconName', aReason:aReason}; + console.error('Rejected - promise_getIconName - ', rejObj); + deferredMain_updateIconToAllWindows.reject(rejObj); + } + ).catch( + function(aCaught) { + var rejObj = {name:'promise_getIconName', aCaught:aCaught}; + console.error('Caught - promise_getIconName - ', rejObj); + deferredMain_updateIconToAllWindows.reject(rejObj); + } + ); } var do_applyIcon = function() { switch (cOS) { case 'winnt': - if (!aDOMWin) { - aDOMWin = Services.wm.getMostRecentWindow(null); - } - var cBaseWin = aDOMWin.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIDocShellTreeItem) - .treeOwner - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIBaseWindow); - var cWinHandlePtrStr = cBaseWin.nativeHandle; + var cWinHandlePtrStr; + var do_theApply = function() { + console.info('cWinHandlePtrStr:', cWinHandlePtrStr); + useIconNameStr = OS.Path.join(profToolkit.path_profilistData_launcherIcons, useIconNameStr + '.ico'); + console.info('will apply this icon:', useIconNameStr); + var promise_changeIconForWindows = ProfilistWorker.post('changeIconForAllWindows', [ + useIconNameStr, // iconPath + [cWinHandlePtrStr] // arrWinHandlePtrStrs + ]); + promise_changeIconForWindows.then( + function(aVal) { + console.log('Fullfilled - promise_changeIconForWindows - ', aVal); + // start - do stuff here - promise_changeIconForWindows + deferredMain_updateIconToAllWindows.resolve(true); + // end - do stuff here - promise_changeIconForWindows + }, + function(aReason) { + var rejObj = {name:'promise_changeIconForWindows', aReason:aReason}; + console.warn('Rejected - promise_changeIconForWindows - ', rejObj); + deferredMain_updateIconToAllWindows.reject(rejObj); + } + ).catch( + function(aCaught) { + var rejObj = {name:'promise_changeIconForWindows', aCaught:aCaught}; + console.error('Caught - promise_changeIconForWindows - ', rejObj); + deferredMain_updateIconToAllWindows.reject(rejObj); + } + ); + }; - console.info('cWinHandlePtrStr:', cWinHandlePtrStr); - useIconNameStr = OS.Path.join(profToolkit.path_profilistData_launcherIcons, useIconNameStr + '.ico'); - console.info('will apply this icon:', useIconNameStr); - var promise_changeIconForWindows = ProfilistWorker.post('changeIconForAllWindows', [ - useIconNameStr, // iconPath - [cWinHandlePtrStr] // arrWinHandlePtrStrs - ]); - promise_changeIconForWindows.then( - function(aVal) { - console.log('Fullfilled - promise_changeIconForWindows - ', aVal); - // start - do stuff here - promise_changeIconForWindows - deferredMain_updateIconToAllWindows.resolve(true); - // end - do stuff here - promise_changeIconForWindows - }, - function(aReason) { - var rejObj = {name:'promise_changeIconForWindows', aReason:aReason}; - console.warn('Rejected - promise_changeIconForWindows - ', rejObj); - deferredMain_updateIconToAllWindows.reject(rejObj); - } - ).catch( - function(aCaught) { - var rejObj = {name:'promise_changeIconForWindows', aCaught:aCaught}; - console.error('Caught - promise_changeIconForWindows - ', rejObj); - deferredMain_updateIconToAllWindows.reject(rejObj); + if (!aDOMWin) { + if (aProfilePath == profToolkit.selectedProfile.iniKey) { + aDOMWin = Services.wm.getMostRecentWindow(null); + var cBaseWin = aDOMWin.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation) + .QueryInterface(Ci.nsIDocShellTreeItem) + .treeOwner + .QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIBaseWindow); + cWinHandlePtrStr = cBaseWin.nativeHandle; + + do_theApply(); + } else { + // test if profile at aProfilePath is running + // if it isnt then resolve + // if it is then continue to badge apply after getting handle for one of its windows + var do_getProfPid = function() { + var promise_pidOfProfile = ProfilistWorker.post('getPidForRunningProfile', [ini[aProfilePath].props.IsRelative, aProfilePath, profToolkit.rootPathDefault]); + promise_pidOfProfile.then( + function(aVal) { + console.log('Fullfilled - promise_pidOfProfile - ', aVal); + // start - do stuff here - promise_pidOfProfile + if (aVal > 0) { + do_getWinHandleForPid(aVal); + } else { + // not running + deferredMain_updateIconToAllWindows.resolve(false); + } + // end - do stuff here - promise_pidOfProfile + }, + function(aReason) { + var rejObj = {name:'promise_pidOfProfile', aReason:aReason}; + console.warn('Rejected - promise_pidOfProfile - ', rejObj); + deferredMain_updateIconToAllWindows.reject(rejObj); + } + ).catch( + function(aCaught) { + var rejObj = {name:'promise_pidOfProfile', aCaught:aCaught}; + console.error('Caught - promise_pidOfProfile - ', rejObj); + deferredMain_updateIconToAllWindows.reject(rejObj); + } + ); + }; + + var do_getWinHandleForPid = function(aProfPID) { + var promise_getWinHandleForPid = ProfilistWorker.post('getPtrStrToWinOfProf', [aProfPID]); + promise_getWinHandleForPid.then( + function(aVal) { + console.log('Fullfilled - promise_getWinHandleForPid - ', aVal); + // start - do stuff here - promise_getWinHandleForPid + // aVal is a string to pointer on success, else it is 0 + if (aVal !== 0) { + // no windows found, maybe not running anymore? unlikely but this should not happen as only get here if didnt get 0 for pid in `promise_pidOfProfile` + deferredMain_updateIconToAllWindows.resolve(false); + } else { + cWinHandlePtrStr = aVal; + do_theApply(); + } + // end - do stuff here - promise_getWinHandleForPid + }, + function(aReason) { + var rejObj = {name:'promise_getWinHandleForPid', aReason:aReason}; + console.warn('Rejected - promise_getWinHandleForPid - ', rejObj); + deferredMain_updateIconToAllWindows.reject(rejObj); + } + ).catch( + function(aCaught) { + var rejObj = {name:'promise_getWinHandleForPid', aCaught:aCaught}; + console.error('Caught - promise_getWinHandleForPid - ', rejObj); + deferredMain_updateIconToAllWindows.reject(rejObj); + } + ); + } + + do_getProfPid(); } - ); + } break; case 'linux': @@ -3554,8 +3653,10 @@ function updateIconToLauncher(aProfilePath) { // checks if the icon of launcher is correct, by reading icon file of that profile -- icon file is in form of `____BADGE-ID_#####__TIE-ID_#### or __BADGE-ID_#####__CHANNEL-REF_#### (does not have to have a BADGE_ID but has to have TIE-ID or CHANNEL_REF) // then using that TIE-ID or CHANNEL-REF it uses that as base (has to has one of the two) // if it has correct stuff then it doesnt update - + console.log('updateIconToLauncher run - not yet implemented'); + + // todo: for windows, make sure to check for pinned shortcuts and update those as well } function updateIconToDesktcut(aProfilePath) { @@ -7142,8 +7243,12 @@ function makeIcon(for_ini_key, iconNameObj, doc) { console.log('Fullfilled - promise_iconPrexists - ', aVal); // start - do stuff here - promise_iconPrexists resolveObj.OSPath = path_prexistanceIconOSPath; - resolveObj.alreadyExisted = true; - deferredMain_makeIcon.resolve(resolveObj); + if (aVal) { + resolveObj.alreadyExisted = true; + deferredMain_makeIcon.resolve(resolveObj); + } else { + // does not prexist, go forth making the icon + } deferred_notPrexisting.resolve({prexists:aVal}); // end - do stuff here - promise_iconPrexists }, @@ -7201,7 +7306,7 @@ function makeIcon(for_ini_key, iconNameObj, doc) { console.log('Fullfilled - promise_profSpecsToGetIconNameObj - ', aVal); // start - do stuff here - promise_profSpecsToGetIconNameObj resolveObj.profSpecs = aVal; - iconNameObj = aVal; + iconNameObj = aVal.iconNameObj; do_checkIfPreExisting_and_loadBadgeAndBaseSets(); // end - do stuff here - promise_profSpecsToGetIconNameObj }, @@ -8166,6 +8271,22 @@ function startup(aData, aReason) { //ifClientsAliveEnsure_thenEnsureListenersAlive(); onResponseEnsureEnabledElseDisabled(); //Services.obs.notifyObservers(null, 'profilist-update-cp-dom', 'restart'); + + // start - os specific post-startup stuff + switch (cOS) { + case 'winnt': + case 'winmo': + case 'wince': + + // apply icon to windows + updateIconToAllWindows(profToolkit.selectedProfile.iniKey); + break; + + default: + // do nothing + } + // end - os specific post-startup stuff + }, function(aReason) { var rejObj = {name:'promise_iniFirstRead', aReason:aReason}; @@ -8179,7 +8300,7 @@ function startup(aData, aReason) { ); }; - // os - mac specific stuff + // start - os specific pre-startup stuff if (cOS == 'darwin') { macStuff.isMac = true; @@ -8215,7 +8336,7 @@ function startup(aData, aReason) { } else { do_profilistStartup(); } - // end - os specific stuff + // end - os specific pre-startup stuff } diff --git a/modules/ostypes_win.jsm b/modules/ostypes_win.jsm index 13bdc96..fafd5b1 100644 --- a/modules/ostypes_win.jsm +++ b/modules/ostypes_win.jsm @@ -1,3 +1,6 @@ +//todo: figure out if for 64bit the abis are different as done here: https://gist.github.com/Noitidart/1f9d574451b8aaaef219#file-_ff-addon-snippet-winapi_getrunningpids-js-L16 +//todo: work on jscGetDeepest, in EnuMWindows it goes berserk but doesnt error, good place to experiemnt + var EXPORTED_SYMBOLS = ['ostypes']; //const {utils: Cu} = Components; //Cu.import('resource://gre/modules/ctypes.jsm'); @@ -52,7 +55,6 @@ var winTypes = function() { this.LPCSTR = ctypes.char.ptr; this.LPTSTR = ctypes.jschar.ptr; // UNICODE this.LPCTSTR = ctypes.jschar.ptr; - this.LPCWSTR = ctypes.jschar.ptr; this.LPWSTR = ctypes.jschar.ptr; // WCHAR this.LRESULT = this.LONG_PTR; this.WPARAM = this.UINT_PTR; @@ -63,11 +65,17 @@ var winTypes = function() { this.LPCVOID = ctypes.voidptr_t; + this.RM_APP_TYPE = ctypes.unsigned_int; this.VOID = ctypes.void_t; + this.WCHAR = ctypes.jschar; // ADVANCED TYPES this.NTSTATUS = this.LONG; this.SYSTEM_INFORMATION_CLASS = this.INT; + this.WNDENUMPROC = ctypes.FunctionType(ctypes.default_abi, this.BOOL, [this.HWND, this.LPARAM]); + + this.PCWSTR = new ctypes.PointerType(this.WCHAR); + this.LPCWSTR = this.PCWSTR; if (ctypes.size_t.size == 8) { this.CallBackABI = ctypes.default_abi; @@ -120,6 +128,71 @@ var winTypes = function() { {'Handles': ctypes.ArrayType(this.SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX, 1)} //{'Handles': this.TYPE.SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX.ptr.array()} ]); + + // start - structures used by Rstrtmgr.dll + /* http://msdn.microsoft.com/en-us/library/windows/desktop/ms724284%28v=vs.85%29.aspx + * typedef struct _FILETIME { + * DWORD dwLowDateTime; + * DWORD dwHighDateTime; + * } FILETIME, *PFILETIME; + */ + this.FILETIME = ctypes.StructType('_FILETIME', [ + { 'dwLowDateTime': this.DWORD }, + { 'dwHighDateTime': this.DWORD } + ]); + this.PFILETIME = this.FILETIME.ptr; + + /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa373677%28v=vs.85%29.aspx + * typedef struct { + * DWORD dwProcessId; + * FILETIME ProcessStartTime; + * } RM_UNIQUE_PROCESS, *PRM_UNIQUE_PROCESS; + */ + this.RM_UNIQUE_PROCESS = ctypes.StructType('RM_UNIQUE_PROCESS', [ + { 'dwProcessId': this.DWORD }, + { 'ProcessStartTime': this.FILETIME } + ]); + this.PRM_UNIQUE_PROCESS = this.RM_UNIQUE_PROCESS.ptr; + + this.CCH_RM_MAX_APP_NAME = 255; // should be in CONST section but needed for defining RM_PROCESS_INFO, so i put them there as well + this.CCH_RM_MAX_SVC_NAME = 63; // should be in CONST section but needed for defining RM_PROCESS_INFO, so i put them there as well + /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa373674%28v=vs.85%29.aspx + * typedef struct { + * RM_UNIQUE_PROCESS Process; + * WCHAR strAppName[CCH_RM_MAX_APP_NAME+1]; + * WCHAR strServiceShortName[CCH_RM_MAX_SVC_NAME+1]; + * RM_APP_TYPE ApplicationType; + * ULONG AppStatus; + * DWORD TSSessionId; + * BOOL bRestartable; + * } RM_PROCESS_INFO; + */ + this.RM_PROCESS_INFO = ctypes.StructType('RM_PROCESS_INFO', [ + { 'Process': this.RM_UNIQUE_PROCESS }, + { 'strAppName': this.WCHAR.array(this.CCH_RM_MAX_APP_NAME + 1) }, // WCHAR of size [CCH_RM_MAX_APP_NAME+1] + { 'strServiceShortName': this.WCHAR.array(this.CCH_RM_MAX_SVC_NAME + 1) }, // WCHAR of size [CCH_RM_MAX_SVC_NAME+1] + { 'ApplicationType': this.RM_APP_TYPE }, // integer of RM_APP_TYPE + { 'AppStatus': this.ULONG }, // ULONG + { 'TSSessionId': this.DWORD }, // DWORD + { 'bRestartable': this.BOOL } // BOOL + ]); + + /* 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; + */ + this.GUID = ctypes.StructType('GUID', [ + { 'Data1': this.ULONG }, + { 'Data2': this.USHORT }, + { 'Data3': this.USHORT }, + { 'Data4': this.BYTE.array(8) } + ]); + this.PGUID = this.GUID.ptr; + // end - structures used by Rstrtmgr.dll } var winInit = function() { @@ -131,6 +204,11 @@ var winInit = function() { // CONSTANTS this.CONST = { + // GetAncestor + GA_PARENT: 1, + GA_ROOT: 2, + GA_ROOTOWNER: 3, //same as if calling with GetParent + // GetWindow GW_OWNER: 4, @@ -138,6 +216,21 @@ var winInit = function() { IMAGE_ICON: 1, LR_LOADFROMFILE: 16, + // Rstrtmgr.dll + CCH_RM_MAX_APP_NAME: 255, // this is also in TYPES because I needed it to define a struct + CCH_RM_MAX_SVC_NAME: 63, // this is also in TYPES because I needed it to define a struct + ERROR_SUCCESS: 0, + ERROR_MORE_DATA: 234, + RM_SESSION_KEY_LEN: self.TYPE.GUID.size, //https://github.com/wine-mirror/wine/blob/c87901d3f8cebfb7d28b42718c1c78035730d6ce/include/restartmanager.h#L26 + CCH_RM_SESSION_KEY: /*this.RM_SESSION_KEY_LEN*/self.TYPE.GUID.size * 2, //https://github.com/wine-mirror/wine/blob/c87901d3f8cebfb7d28b42718c1c78035730d6ce/include/restartmanager.h#L27 + RmUnknownApp: 0, + RmMainWindow: 1, + RmOtherWindow: 2, + RmService: 3, + RmExplorer: 4, + RmConsole: 5, + RmCritical: 1000, + // SendMessage ICON_SMALL: 0, ICON_BIG: 1, @@ -219,6 +312,32 @@ var winInit = function() { self.TYPE.HICON // hIcon ); }, + EnumWindows: function() { + /* https://msdn.microsoft.com/en-us/library/windows/desktop/ms633497%28v=vs.85%29.aspx + * BOOL WINAPI EnumWindows( + * __in_ WNDENUMPROC lpEnumFunc, + * __in_ LPARAM lParam + * ); + */ + return lib('user32').declare('EnumWindows', ctypes.winapi_abi, + self.TYPE.BOOL, // return + self.TYPE.WNDENUMPROC.ptr, // lpEnumFunc + self.TYPE.LPARAM // lParam + ); + }, + GetAncestor: function() { + /* http://msdn.microsoft.com/en-us/library/windows/desktop/ms633502%28v=vs.85%29.aspx + * HWND WINAPI GetAncestor( + * __in_ HWND hwnd, + * __in_ UINT gaFlags + * ); + */ + return lib('user32').declare('GetAncestor', ctypes.winapi_abi, + self.TYPE.HWND, // return + self.TYPE.HWND, // hwnd + self.TYPE.UINT // gaFlags + ); + }, GetWindow: function() { /* http://msdn.microsoft.com/en-us/library/ms633515%28v=vs.85%29.aspx * HWND WINAPI GetWindow( @@ -232,6 +351,19 @@ var winInit = function() { self.TYPE.UINT // wCmd ); }, + GetWindowThreadProcessId: function() { + /* http://msdn.microsoft.com/en-us/library/windows/desktop/ms633522%28v=vs.85%29.aspx + * DWORD WINAPI GetWindowThreadProcessId( + * __in_ HWND hWnd, + * __out_opt_ LPDWORD lpdwProcessId + * ); + */ + return lib('user32').declare('GetWindowThreadProcessId', ctypes.winapi_abi, + self.TYPE.DWORD, // return + self.TYPE.HWND, // hWnd + self.TYPE.LPDWORD // lpdwProcessId + ); + }, LoadImage: function() { /* http://msdn.microsoft.com/en-us/library/windows/desktop/ms648045%28v=vs.85%29.aspx * HANDLE WINAPI LoadImage( @@ -385,12 +517,16 @@ var winInit = function() { this.HELPER = { jscGetDeepest: function(obj) { + try { + console.info(Math.round(Math.random() * 10) + ' starting jscGetDeepest:', obj, obj.toString()); + } catch(ignore) {} // used to get the deepest .contents .value and so on. expecting a number object - //console.info('start jscGetDeepest:', obj.toString()); - //while (/*isNaN(obj) && */('contents' in obj || 'value' in obj)) { - while (obj.hasOwnProperty && (obj.hasOwnProperty('contents') || obj.hasOwnProperty('value'))) { + //while (isNaN(obj) && ('contents' in obj || 'value' in obj)) { + while (obj && obj.hasOwnProperty && (obj.hasOwnProperty('contents') || obj.hasOwnProperty('value'))) { + //if ('contents' in obj) { if (obj.hasOwnProperty('contents')) { obj = obj.contents; + //} else if ('value' in obj) { } else if (obj.hasOwnProperty('value')) { obj = obj.value; } else { @@ -400,9 +536,10 @@ var winInit = function() { } //console.info('pre final jscGetDeepest:', obj.toString()); //if (!isNaN(obj)) { + if (obj || obj === 0) { obj = obj.toString(); - //} - //console.info('finaled jscGetDeepest:', obj.toString()); + } + console.info('finaled jscGetDeepest:', obj); return obj; }, jscEqual: function(obj1, obj2) { @@ -422,6 +559,65 @@ var winInit = function() { } else { return false; } + }, + memset: function memset(array, val, size) { + /* http://stackoverflow.com/questions/24466228/memset-has-no-dll-so-how-ctype-it + * https://gist.github.com/nmaier/ab4bfe59e8c8fcdc5b90 + * https://gist.github.com/Noitidart/2d9b44b18493f9339629 + * Note that size is the number of array elements to set, not the number of bytes. + */ + for (var i = 0; i < size; ++i) { + array[i] = val; + } + }, + readAsChar8ThenAsChar16: function(stringPtr, known_len, jschar) { + // when reading as jschar it assumes max length of 500 + + // stringPtr is either char or jschar, if you know its jschar for sure, pass 2nd arg as true + // if known_len is passed, then assumption is not made, at the known_len position in array we will see a null char + // i tried getting known_len from stringPtr but its not possible, it has be known, i tried this: + //"stringPtr.contents.toString()" "95" + //"stringPtr.toString()" "ctypes.unsigned_char.ptr(ctypes.UInt64("0x7f73d5c87650"))" + // so as we see neither of these is 77, this is for the example of "_scratchpad/EnTeHandle.js at master · Noitidart/_scratchpad - Mozilla Firefox" + + // tries to do read string on stringPtr, if it fails then it falls to read as jschar + + var readJSCharString = function() { + var assumption_max_len = known_len ? known_len : 500; + var ptrAsArr = ctypes.cast(stringPtr, ctypes.unsigned_char.array(assumption_max_len).ptr).contents; // MUST cast to unsigned char (not ctypes.jschar, or ctypes.char) as otherwise i dont get foreign characters, as they are got as negative values, and i should read till i find a 0 which is null terminator which will have unsigned_char code of 0 // can test this by reading a string like this: "_scratchpad/EnTeHandle.js at master · Noitidart/_scratchpad - Mozilla Firefox" at js array position 36 (so 37 if count from 1), we see 183, and at 77 we see char code of 0 IF casted to unsigned_char, if casted to char we see -73 at pos 36 but pos 77 still 0, if casted to jschar we see chineese characters in all spots expect spaces even null terminator is a chineese character + //console.info('ptrAsArr.length:', ptrAsArr.length); + //console.log('debug-msg :: dataCasted:', dataCasted, uneval(dataCasted), dataCasted.toString()); + var charCode = []; + var fromCharCode = [] + for (var i=0; i 0 if found + debugOutCLEAR(); + var rezMain; + if (IsRelative == '1') { + var cProfileDirName = OS.Path.basename(OS.Path.normalize(Path)); + var path_cProfRootDir = OS.Path.join(path_DefProfRt, cProfileDirName); + } else { + var path_cProfRootDir = Path; + } + + //note: im missing vms: http://mxr.mozilla.org/mozilla-release/source/profile/dirserviceprovider/src/nsProfileLock.cpp#581 + switch (cOS) { + case 'winnt': + case 'winmo': + case 'wince': + // returns + // if LOCKED - 1 + // if NOT locked - 0 + + var path_lock = OS.Path.join(path_cProfRootDir, 'parent.lock'); + + try { // using try-finally just for the finally + var dwSession; + rezMain = function() { + // START SESSION + dwSession = new ostypes.TYPE.DWORD(); + var szSessionKey = ostypes.TYPE.WCHAR.array(ostypes.CONST.CCH_RM_SESSION_KEY + 1)(); //this is a buffer + ostypes.HELPER.memset(szSessionKey, '0', ostypes.CONST.CCH_RM_SESSION_KEY ); // remove + 1 as we want null terminated // can do memset(szSessionKey, ostypes.WCHAR('0'), ostypes.CCH_RM_SESSION_KEY + 1); // js-ctypes initializes at 0 filled: ctypes.char16_t.array(33)(["\x00", "\x00", "\x00", "\x00", "\x00", "\x00", "\x00", "\x00", "\x00", "\x00", "\x00", "\x00", "\x00", "\x00", "\x00", "\x00", "\x00", "\x00", "\x00", "\x00", "\x00", "\x00", "\x00", "\x00", "\x00", "\x00", "\x00", "\x00", "\x00", "\x00", "\x00", "\x00", "\x00"])" + + var rez_RmStartSession = ostypes.API('RmStartSession')(dwSession.address(), 0, szSessionKey); + if (!ostypes.HELPER.jscEqual(rez_RmStartSession, ostypes.CONST.ERROR_SUCCESS)) { + throw new Error('RmEndSession Failed with error code:' + rez_RmStartSession); + } + + // REGISTER RESOURCES + var jsStr_pszFilepath1 = path_lock; //path to file name + var pszFilepath1 = ostypes.TYPE.WCHAR.array()(jsStr_pszFilepath1); //creates null terminated c string, null terminated string is required for RmRegisterResources + //console.info('pszFilepath1:', pszFilepath1, pszFilepath1.toString(), uneval(pszFilepath1)); + + var jsArr = [pszFilepath1]; + var pszFilepathsArr = ostypes.TYPE.PCWSTR.array(/*no need, but can have it*//*jsArr.length*/)(jsArr); // when 2 it is: [ctypes.char16_t.ptr(ctypes.UInt64("0x0")), ctypes.char16_t.ptr(ctypes.UInt64("0x0"))] + //console.info('pszFilepathsArr:', pszFilepathsArr, pszFilepathsArr.toString(), uneval(pszFilepathsArr)); + + var rez_RmRegisterResources = ostypes.API('RmRegisterResources')(dwSession, jsArr.length, pszFilepathsArr, 0, null, 0, null); + //console.info('rez_RmRegisterResources:', rez_RmRegisterResources, rez_RmRegisterResources.toString(), uneval(rez_RmRegisterResources)); + + if (!ostypes.HELPER.jscEqual(rez_RmRegisterResources, ostypes.CONST.ERROR_SUCCESS)) { + throw new Error('RmRegisterResources Failed with error code:', rez_RmRegisterResources); + } + + var nProcInfoNeeded = ostypes.TYPE.UINT(0); // 0 to fetch + var rgpi = null; + var nProcInfo = ostypes.TYPE.UINT(0); // this here is us telling how many array elements to fill, we initially provide null as rgpi so it has to be 0, otherwise it will probably crash asit will try to fill this number into null. after RmGetlist, it gets set to how many were actually filled + var dwReason = ostypes.TYPE.DWORD(0); + + //console.info('INIT nProcInfoNeeded:', nProcInfoNeeded, nProcInfoNeeded.toString()); + //console.info('INIT nProcInfo:', nProcInfo, nProcInfo.toString()); + + var rez_RmGetList_Query = ostypes.API('RmGetList')(dwSession, nProcInfoNeeded.address(), nProcInfo.address(), rgpi, dwReason.address()); + //console.info('rez_RmGetList_Query:', rez_RmGetList_Query, rez_RmGetList_Query.toString(), uneval(rez_RmGetList_Query)); + if (ostypes.HELPER.jscEqual(rez_RmGetList_Query, ostypes.ERROR_SUCCESS)) { + //console.log('RmGetList succeeded but there are no processes on this so return as I had capped it to 0, so it should return ERROR_MORE_DATA if there was more than 0, rez_RmGetList_Query:', rez_RmGetList_Query); + return 0; + } else if (!ostypes.HELPER.jscEqual(rez_RmGetList_Query, ostypes.CONST.ERROR_MORE_DATA)) { + throw new Error('RmGetList failed, rez_RmGetList_Query:' + rez_RmGetList_Query); + } + + //console.info('POST nProcInfoNeeded:', nProcInfoNeeded, nProcInfoNeeded.toString()); + //console.info('POST nProcInfo:', nProcInfo, nProcInfo.toString()); + //console.info('POST dwReason:', dwReason, dwReason.toString()); + + rgpi = ostypes.TYPE.RM_PROCESS_INFO.array(nProcInfoNeeded.value)(); //alrady ptr so dont need to pass rgpi.ptr to RmGetList + nProcInfo = ostypes.TYPE.UINT(rgpi.length); + + console.info('RE-INIT nProcInfo:', nProcInfo, nProcInfo.toString()); + + var rez_RmGetList_Fetch = ostypes.API('RmGetList')(dwSession, nProcInfoNeeded.address(), nProcInfo.address(), rgpi, dwReason.address()); + console.info('rez_RmGetList_Fetch:', rez_RmGetList_Fetch, rez_RmGetList_Fetch.toString(), uneval(rez_RmGetList_Fetch)); + + if (!ostypes.HELPER.jscEqual(rez_RmGetList_Fetch, ostypes.CONST.ERROR_SUCCESS)) { + if (ostypes.HELPER.jscEqual(rez_RmGetList_Fetch, ostypes.CONST.ERROR_MORE_DATA)) { + //console.warn('RmGetList found that since last RmGetList there is now new/more processes available, so you can opt to run again but I dont need to as I want the first process which opened it, which should be Firefox profile'); + } else { + throw new Error('RmGetList Failed with error code:' + rez_RmGetList_Fetch); + } + } + + //console.info('FINAL nProcInfoNeeded:', nProcInfoNeeded, nProcInfoNeeded.toString()); + //console.info('FINAL nProcInfo:', nProcInfo, nProcInfo.toString()); + //console.info('FINAL dwReason:', dwReason, dwReason.toString()); + //console.info('FINAL rgpi:', rgpi, rgpi.toString()); + + rezMain = []; + for (var i=0; i 1) { + rezMain.sort(function(a,b) { + return a.dwLowDateTime > b.dwLowDateTime; // sort asc + }); + } + + return parseInt(rezMain[0].pid); + // END SESSION // in finally so it will happen right after this line + }(); + } /*catch(mainEx) { // if do catch it wont reject promise + + } */finally { + if (dwSession && dwSession.value != 0) { // dwSession is new ostypes.DWORD so `if (dwSession)` will always be true, need to fix this here: https://gist.github.com/Noitidart/6203ba1b410b7bacaa82#file-_ff-addon-snippet-winapi_rstrtmgr-js-L234 + var rez_RmEndSession = ostypes.API('RmEndSession')(dwSession); + console.info('rez_RmEndSession:', rez_RmEndSession, rez_RmEndSession.toString(), uneval(rez_RmEndSession)); + if (!ostypes.HELPER.jscEqual(rez_RmEndSession, ostypes.CONST.ERROR_SUCCESS)) { + //console.error('RmEndSession Failed with error code:', rez_RmEndSession); + debugOut.push('failed to end session'); + } else { + debugOut.push('succesfully ended session'); + } + } else { + debugOut.push('NO NEED to end session'); + } + debugOutWRITE(); + // with or without catch, the finally does run. without catch, it even rejects the promise. this is good and expected!! + } + + break; + default: + throw new Error('os-unsupported'); + } + + return rezMain; + } \ No newline at end of file