Files
Open-Shell-Menu/Src/StartMenu/StartMenu.cpp
ge0rdi 38c155cc95 Add support for silent OS upgrade task (#176)
`Open-Shell` needs to adjust itself after OS upgrade. It seems that
`StartMenuHelper` registration is lost after such upgrade:

http://www.classicshell.net/forum/viewtopic.php?f=7&t=8082#p34821

To fix this registration, administrator rights are required (means user
interaction, UAC).

While this is acceptable in consumer environment, it is typically not
desired in business environment where users typically doesn't have
administrator rights.

This patch allows to run `Open-Shell` in silent upgrade mode that will:
* check if OS version changed (otherwise end immediately)
* perform OS upgrade tasks without any user interraction

Such mode can be then used to create scheduled task that will run this
silent upgrade check on every boot with system rights:

`schtasks /Create /RU "NT AUTHORITY\SYSTEM" /SC ONSTART /TN "Open-Shell OS updgrade check" /TR "%ProgramFiles%\Open-Shell\StartMenu.exe -upgrade -silent"`

 #167
2019-06-09 20:27:49 +02:00

738 lines
22 KiB
C++

// Classic Shell (c) 2009-2017, Ivo Beltchev
// Open-Shell (c) 2017-2018, The Open-Shell Team
// Confidential information of Ivo Beltchev. Not for disclosure or distribution without prior written consent from the author
#include <stdafx.h>
#include <dbghelp.h>
#include <wuapi.h>
#include "StringUtils.h"
#include "ResourceHelper.h"
#include "TrackResources.h"
#include "ComHelper.h"
#include "Settings.h"
#include "psapi.h"
#include "Legacy.h"
#include "StartMenuDLL\StartMenuDLL.h"
#include "StartMenuDLL\SettingsUI.h"
#include "StartMenuDLL\resource.h"
#include "StartMenuDLL\LogManager.h"
static HHOOK g_StartHook;
static void UnhookStartMenu( void )
{
if (g_StartHook)
UnhookWindowsHookEx(g_StartHook);
g_StartHook=NULL;
}
enum THookMode
{
HOOK_NONE, // don't hook Explorer, running as a separate exe
HOOK_NORMAL, // hook Explorer normally, no retry
HOOK_STARTUP, // retry to hook Explorer
HOOK_STARTUP2, // retry to hook Explorer (for secondary desktops)
};
static bool HookStartMenu( THookMode mode, HWND &menu )
{
HMODULE hHookModule=GetModuleHandle(L"StartMenuDLL.dll");
// find the Progman window and the start button
DllLogToFile(STARTUP_LOG,L"StartMenu: hooking Explorer");
HWND progWin=NULL;
bool bFindAppManager=(mode==HOOK_STARTUP && GetWinVersion()>=WIN_VER_WIN8 && GetWinVersion()<=WIN_VER_WIN81);
for (int i=0;i<120;i++) // retry for 1 minute
{
if (bFindAppManager)
bFindAppManager=!FindWindow(L"ApplicationManager_DesktopShellWindow",NULL);
if (!bFindAppManager)
{
progWin=FindWindowEx(NULL,NULL,L"Progman",NULL);
if (progWin) break;
if (mode!=HOOK_STARTUP && mode!=HOOK_STARTUP2) return true; // the Progman window may not be created yet (if Explorer is currently restarting)
}
DllLogToFile(STARTUP_LOG,L"StartMenu: can't find Progman, retrying");
Sleep(500);
}
if (!progWin)
return true;
DWORD process=0;
DWORD thread=GetWindowThreadProcessId(progWin,&process);
HANDLE hProcess=OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,FALSE,process);
if (hProcess)
{
bool success=false;
wchar_t path[MAX_PATH];
if (GetModuleFileNameEx(hProcess,NULL,path,_countof(path)))
{
if (_wcsicmp(PathFindFileName(path),L"explorer.exe")==0)
success=true;
else
DllLogToFile(STARTUP_LOG,L"StartMenu: found wrong process %s",path);
}
else
DllLogToFile(STARTUP_LOG,L"StartMenu: failed to get process name");
CloseHandle(hProcess);
if (!success)
return false;
}
else
DllLogToFile(STARTUP_LOG,L"StartMenu: failed to open process %d",process);
for (int i=0;i<10;i++) // retry for 5 sec
{
if (FindTaskBar(process)) break;
if (mode!=HOOK_STARTUP && mode!=HOOK_STARTUP2) return false; // the taskbar may not be created yet (if Explorer is currently restarting)
DllLogToFile(STARTUP_LOG,L"StartMenu: can't find taskbar, retrying");
Sleep(500);
}
if (mode==HOOK_NONE)
{
menu=ToggleStartMenu(-1,false);
return true;
}
// install hooks in the explorer process
thread=GetWindowThreadProcessId(g_TaskBar,NULL);
g_StartHook=SetWindowsHookEx(WH_GETMESSAGE,HookInject,hHookModule,thread);
if (!g_StartHook)
{
int err=GetLastError();
DllLogToFile(STARTUP_LOG,L"StartMenu: hook failed: 0x%08X",err);
}
PostMessage(g_TaskBar,WM_NULL,0,0); // make sure there is one message in the queue
return true;
}
static UINT g_TaskbarCreatedMsg; // the "TaskbarCreated" message
// CStartHookWindow is a hidden window that waits for the "TaskbarCreated" message and rehooks the explorer process
// Also when the start menu wants to shut down it sends WM_CLOSE to this window, which unhooks explorer and exits
const int WM_OPEN=WM_USER+10;
const int TIMER_HOOK=1;
class CStartHookWindow: public CWindowImpl<CStartHookWindow>
{
public:
DECLARE_WND_CLASS(L"OpenShellMenu.CStartHookWindow")
BEGIN_MSG_MAP( CStartHookWindow )
MESSAGE_HANDLER( WM_OPEN, OnOpen )
MESSAGE_HANDLER( WM_CLOSE, OnClose )
MESSAGE_HANDLER( WM_CLEAR, OnClear )
MESSAGE_HANDLER( WM_TIMER, OnTimer )
MESSAGE_HANDLER( g_TaskbarCreatedMsg, OnTaskbarCreated )
END_MSG_MAP()
protected:
// Handler prototypes:
// LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
// LRESULT CommandHandler(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
// LRESULT NotifyHandler(int idCtrl, LPNMHDR pnmh, BOOL& bHandled);
LRESULT OnOpen( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled );
LRESULT OnClose( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled );
LRESULT OnClear( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled );
LRESULT OnTimer( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled );
LRESULT OnTaskbarCreated( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled );
};
LRESULT CStartHookWindow::OnOpen( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
{
if (g_TaskBar) ::PostMessage(g_TaskBar,RegisterWindowMessage(L"OpenShellMenu.StartMenuMsg"),wParam,lParam);
return 0;
}
LRESULT CStartHookWindow::OnClose( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
{
UnhookStartMenu();
Sleep(100);
PostQuitMessage(0);
return 0;
}
LRESULT CStartHookWindow::OnClear( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
{
UnhookStartMenu();
return 0;
}
LRESULT CStartHookWindow::OnTaskbarCreated( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
{
DllLogToFile(STARTUP_LOG,L"StartMenu: Taskbar Created");
SetTimer(TIMER_HOOK,100);
return 0;
}
LRESULT CStartHookWindow::OnTimer( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
{
if (wParam==TIMER_HOOK)
{
UnhookStartMenu();
HWND menu;
HookStartMenu(HOOK_NORMAL,menu);
if (g_StartHook)
KillTimer(TIMER_HOOK);
}
return 0;
}
enum
{
CMD_NONE=-1,
CMD_TOGGLE_NEW=-2,
};
static const GUID IID_IWpnTileSink={0xe716b283,0x6be7,0x4e6f,{0xa8,0x8f,0x1c,0xde,0x47,0xd5,0xe3,0x55}};
interface IWpnTileSink : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE TileSessionUpdated(unsigned long,void const *,unsigned long) = 0;
virtual HRESULT STDMETHODCALLTYPE TileSessionNotificationCleared(unsigned long,void const *,unsigned long) = 0;
virtual HRESULT STDMETHODCALLTYPE TileSessionImageDownloadUpdated(unsigned long,int) = 0;
virtual HRESULT STDMETHODCALLTYPE TileRequestNotificationCompleted(void const * ptr64,unsigned long) = 0;
virtual HRESULT STDMETHODCALLTYPE TileSessionImageDownloadUpdated2(unsigned long,int) = 0;
};
class CWpnTileSink : public IWpnTileSink
{
// from IUnknown
virtual HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, void **ppvObject );
virtual ULONG STDMETHODCALLTYPE AddRef( void ) { return 1; }
virtual ULONG STDMETHODCALLTYPE Release( void ) { return 1; }
virtual HRESULT STDMETHODCALLTYPE TileSessionUpdated(unsigned long a,void const *b,unsigned long c)
{
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE TileSessionNotificationCleared(unsigned long a,void const *b,unsigned long c)
{
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE TileSessionImageDownloadUpdated(unsigned long a,int b)
{
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE TileRequestNotificationCompleted(void const * a,unsigned long b)
{
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE TileSessionImageDownloadUpdated2(unsigned long a,int b)
{
return S_OK;
}
};
HRESULT STDMETHODCALLTYPE CWpnTileSink::QueryInterface( REFIID riid, void **ppvObject )
{
*ppvObject=NULL;
if (riid==IID_IUnknown || riid==IID_IWpnTileSink)
{
*ppvObject=this;
return S_OK;
}
return E_NOINTERFACE;
}
MIDL_INTERFACE("0e467ac1-65f2-48d6-8bf2-375430548a87")
IWpnPresentationEndpoint : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE TileCreateSession( unsigned long * ) = 0;
virtual HRESULT STDMETHODCALLTYPE TileCloseSession( unsigned long ) = 0;
virtual HRESULT STDMETHODCALLTYPE TileUpdateSession( unsigned long,const void *,unsigned long ) = 0; // (1, str, 1)
virtual HRESULT STDMETHODCALLTYPE TileRequestNotification( const void *, unsigned long ) = 0; // (str, 1)*/
};
const CLSID CLSID_WpnPlatform={0x0c9281f9, 0x6da1, 0x4006, {0x87, 0x29, 0xde, 0x6e, 0x6b, 0x61, 0x58, 0x1c}};
MIDL_INTERFACE("9fa045cb-b9b3-47ba-842f-e2ab458f2b0c")
IWpnPlatform : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE CreateAppEndpoint( struct IWpnAppEndpoint **ppEndpoint ) = 0;
virtual HRESULT STDMETHODCALLTYPE CreatePresentationEndpoint(struct IWpnPresentationEndpoint ** ppEndpoint ) = 0;
/* virtual HRESULT STDMETHODCALLTYPE CreateRegistrationEndpoint(struct IWpnRegistrationEndpoint * ptr64 * ptr64) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateSettingsEndpoint(struct IWpnSettingsEndpoint * ptr64 * ptr64) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateIdleTaskEndpoint(struct IWpnIdleTaskEndpoint * ptr64 * ptr64) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateTestEndpoint(struct IWpnTestEndpoint * ptr64 * ptr64) = 0;*/
};
//const wchar_t *g_AppId=L"microsoft.windowscommunicationsapps_8wekyb3d8bbwe!microsoft.windowslive.mail";
//const wchar_t *g_AppId=L"Microsoft.BingNews_8wekyb3d8bbwe!AppexNews";
//const wchar_t *g_AppId=L"Microsoft.WindowsStore_8wekyb3d8bbwe!App";
//const wchar_t *g_AppId=L"Microsoft.BingWeather_8wekyb3d8bbwe!App";
const wchar_t *g_AppId=L"microsoft.windowscommunicationsapps_8wekyb3d8bbwe!microsoft.windowslive.calendar";
static DWORD g_winVer = GetVersionEx(GetModuleHandle(L"user32.dll"));
bool WasOsUpgrade()
{
CRegKey regKey;
if (regKey.Open(HKEY_LOCAL_MACHINE, L"Software\\OpenShell\\OpenShell", KEY_READ | KEY_WOW64_64KEY) == ERROR_SUCCESS)
{
DWORD ver;
if (regKey.QueryDWORDValue(L"WinVersion", ver) == ERROR_SUCCESS)
{
if (ver < g_winVer)
return true;
}
}
return false;
}
// starts new instance of StartMenu.exe with "-upgrade" command line parameter
// UAC dialog is shown to ensure it will run with administrator privileges
void RunOsUpgradeTaskAsAdmin()
{
#ifdef _WIN64
wchar_t path[_MAX_PATH] = L"%windir%\\System32\\StartMenuHelper64.dll";
#else
wchar_t path[_MAX_PATH] = L"%windir%\\System32\\StartMenuHelper32.dll";
#endif
DoEnvironmentSubst(path, _countof(path));
if (GetFileAttributes(path) != INVALID_FILE_ATTRIBUTES)
{
GetModuleFileName(NULL, path, _countof(path));
CoInitialize(NULL);
ShellExecute(NULL, L"runas", path, L"-upgrade", NULL, SW_SHOWNORMAL);
CoUninitialize();
}
}
DWORD PerformOsUpgradeTask(bool silent)
{
CRegKey regKey;
DWORD error = regKey.Open(HKEY_LOCAL_MACHINE, L"Software\\OpenShell\\OpenShell", KEY_WRITE | KEY_WOW64_64KEY);
const wchar_t *nl = error == ERROR_SUCCESS ? L"\r\n\r\n" : L"\r\n";
if (error == ERROR_SUCCESS)
{
regKey.SetDWORDValue(L"WinVersion", g_winVer);
// run regsvr32 StartMenuHelper
#ifdef _WIN64
wchar_t cmdLine[_MAX_PATH] = L"regsvr32 /s \"%windir%\\System32\\StartMenuHelper64.dll\"";
#else
wchar_t cmdLine[_MAX_PATH] = L"regsvr32 /s \"%windir%\\System32\\StartMenuHelper32.dll\"";
#endif
DoEnvironmentSubst(cmdLine, _countof(cmdLine));
wchar_t exe[_MAX_PATH] = L"%windir%\\System32\\regsvr32.exe";
DoEnvironmentSubst(exe, _countof(exe));
STARTUPINFO startupInfo = { sizeof(startupInfo) };
PROCESS_INFORMATION processInfo;
memset(&processInfo, 0, sizeof(processInfo));
if (CreateProcess(exe, cmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo))
{
CloseHandle(processInfo.hThread);
WaitForSingleObject(processInfo.hProcess, INFINITE);
GetExitCodeProcess(processInfo.hProcess, &error);
CloseHandle(processInfo.hProcess);
}
else
{
error = GetLastError();
}
}
if (!silent)
{
if (error)
{
wchar_t msg[1024];
int len = Sprintf(msg, _countof(msg), L"%s%s", DllLoadStringEx(IDS_UPGRADE_ERROR), nl);
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, 0, msg + len, _countof(msg) - len, NULL);
MessageBox(NULL, msg, DllLoadStringEx(IDS_APP_TITLE), MB_OK | MB_ICONERROR);
}
else
{
MessageBox(NULL, DllLoadStringEx(IDS_UPGRADE_SUCCESS), DllLoadStringEx(IDS_APP_TITLE), MB_OK | MB_ICONINFORMATION);
}
}
return error;
}
int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpstrCmdLine, int nCmdShow )
{
/* CoInitialize(NULL);
{
CComPtr<IWpnPlatform> pWpnPlatform;
HRESULT hr=pWpnPlatform.CoCreateInstance(CLSID_WpnPlatform);
CComPtr<IWpnPresentationEndpoint> pUnknown;
hr=pWpnPlatform->CreatePresentationEndpoint(&pUnknown);
CWpnTileSink sink;
DWORD cookie;
CComQIPtr<IConnectionPoint> pConnectionPoint=pUnknown;
hr=pConnectionPoint->Advise(&sink,&cookie);
CComPtr<IWpnPresentationEndpoint> pWpnPresentationEndpoint=pUnknown;
DWORD session;
hr=pWpnPresentationEndpoint->TileCreateSession(&session);
struct
{
const wchar_t *appid;
void *ptr1;
void *ptr2;
__int64 idx;
} request={g_AppId,0,0,1};
hr=pWpnPresentationEndpoint->TileRequestNotification(&request,1);
MSG msg;
while(true)
{
struct
{
const wchar_t *appid;
__int64 idx;
} updateData={g_AppId,1};
hr=pWpnPresentationEndpoint->TileUpdateSession(session,&updateData,1);
while (PeekMessage(&msg,0,0,0,PM_REMOVE))
// while (GetMessage(&msg,0,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Sleep(100);
}
int q=0;
}
CoUninitialize();
return 0;*/
/* DWORD count;
pStore->GetCount(&count);
for (DWORD i=0;i<count;i++)
{
PROPERTYKEY key;
if (SUCCEEDED(pStore->GetAt(i,&key)))
{
CComString pPropName;
PSGetNameFromPropertyKey(key,&pPropName);
PROPVARIANT val;
PropVariantInit(&val);
pStore->GetValue(key,&val);
PropVariantClear(&val);
}
}*/
// one-time import from Classic Shell
ImportLegacyData();
DllLogToFile(STARTUP_LOG,L"StartMenu: start '%s'",lpstrCmdLine);
if (wcsstr(lpstrCmdLine,L"-startup") || (wcsstr(lpstrCmdLine,L"-autorun") && HIWORD(g_winVer)<WIN_VER_WIN8))
{
WaitDllInitThread();
if (!DllGetSettingBool(L"AutoStart"))
{
DllLogToFile(STARTUP_LOG,L"StartMenu: quit - no AutoStart");
return 0;
}
#ifdef BUILD_BETA
if (GetKeyState(VK_SHIFT)<0)
return 0;
#endif
int sleep=DllGetSettingInt(L"AutoStartDelay");
if (sleep>0)
Sleep(sleep);
}
else if (wcsstr(lpstrCmdLine,L"-autorun")) // on Win8+
{
WaitDllInitThread();
if (WasOsUpgrade())
{
// this is an upgrade
MessageBox(NULL, DllLoadStringEx(IDS_UPGRADE_WIN), DllLoadStringEx(IDS_APP_TITLE), MB_OK);
RunOsUpgradeTaskAsAdmin();
}
if (!DllGetSettingBool(L"AutoStart"))
{
DllLogToFile(STARTUP_LOG,L"StartMenu: quit - no AutoStart");
return 0;
}
int sleep=DllGetSettingInt(L"AutoStartDelay");
if (sleep>0)
Sleep(sleep);
}
if (wcsstr(lpstrCmdLine,L"-upgrade"))
{
WaitDllInitThread();
if (WasOsUpgrade())
{
const bool silent = wcsstr(lpstrCmdLine, L"-silent") != nullptr;
return PerformOsUpgradeTask(silent);
}
return 0;
}
const wchar_t *pCmd=wcsstr(lpstrCmdLine,L"-cmd ");
if (pCmd)
{
WaitDllInitThread();
CoInitialize(NULL);
wchar_t command[100];
GetToken(pCmd+5,command,_countof(command),L" ");
if (DllExecuteNamedCommand(command))
{
MSG msg;
while (PeekMessage(&msg,0,0,0,PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
CoUninitialize();
return 0;
}
#ifndef _WIN64
const wchar_t *pSaveAdmx=wcsstr(lpstrCmdLine,L"-saveadmx ");
if (pSaveAdmx)
{
WaitDllInitThread();
wchar_t language[100];
GetToken(pSaveAdmx+10,language,_countof(language),L" ");
HMODULE dll=NULL;
if (language[0])
{
wchar_t path[_MAX_PATH];
GetCurrentDirectory(_countof(path),path);
PathAppend(path,language);
PathAddExtension(path,L".dll");
dll=LoadLibraryEx(path,NULL,LOAD_LIBRARY_AS_DATAFILE|LOAD_LIBRARY_AS_IMAGE_RESOURCE);
}
DllLoadTranslationResources(dll,NULL);
if (!DllSaveAdmx(COMPONENT_MENU,"OpenShellStartMenu.admx","OpenShellStartMenu.adml","MenuADMX.txt"))
return 1;
if (!DllSaveAdmx(COMPONENT_SHARED,"OpenShell.admx","OpenShell.adml","OpenShellADMX.txt"))
return 1;
return 0;
}
#endif
wchar_t path[_MAX_PATH];
GetModuleFileName(NULL,path,_countof(path));
*PathFindFileName(path)=0;
SetCurrentDirectory(path);
const wchar_t *pRunAs=wcsstr(lpstrCmdLine,L"-runas");
if (pRunAs)
{
pRunAs+=7;
CoInitialize(NULL);
wchar_t exe[_MAX_PATH];
const wchar_t *args=NULL;
CComString strExe, strArgs;
if (SUCCEEDED(SHEvaluateSystemCommandTemplate(pRunAs,&strExe,NULL,&strArgs)))
{
args=strArgs;
Strcpy(exe,_countof(exe),strExe);
}
else
{
args=SeparateArguments(pRunAs,exe);
}
SHELLEXECUTEINFO execute={sizeof(execute),SEE_MASK_DOENVSUBST|SEE_MASK_FLAG_LOG_USAGE};
execute.lpFile=exe;
execute.lpParameters=args;
execute.nShow=SW_SHOWNORMAL;
ShellExecuteEx(&execute);
CoUninitialize();
return 0;
}
WaitDllInitThread();
int open=CMD_NONE;
if (wcsstr(lpstrCmdLine,L"-togglenew")!=NULL) open=CMD_TOGGLE_NEW;
else if (wcsstr(lpstrCmdLine,L"-toggle")!=NULL) open=MSG_TOGGLE;
else if (wcsstr(lpstrCmdLine,L"-open")!=NULL) open=MSG_OPEN;
else if (wcsstr(lpstrCmdLine,L"-settings")!=NULL) open=MSG_SETTINGS;
else if (wcsstr(lpstrCmdLine,L"-exit")!=NULL) open=MSG_EXIT;
{
const wchar_t *pXml=wcsstr(lpstrCmdLine,L"-xml ");
if (pXml)
{
wchar_t xml[_MAX_PATH];
GetToken(pXml+5,xml,_countof(xml),L" ");
CoInitialize(NULL);
bool res=DllImportSettingsXml(xml);
CoUninitialize();
if (res)
open=MSG_RELOADSETTINGS;
else
return 1;
}
}
{
const wchar_t *pBackup=wcsstr(lpstrCmdLine,L"-backup ");
if (pBackup)
{
wchar_t xml[_MAX_PATH];
GetToken(pBackup+8,xml,_countof(xml),L" ");
CoInitialize(NULL);
bool res=DllExportSettingsXml(xml);
CoUninitialize();
return res?0:1;
}
}
const wchar_t *pNoHook=wcsstr(lpstrCmdLine,L"-nohook");
bool bHookExplorer=!pNoHook;
if (pNoHook)
{
pNoHook+=7;
if (*pNoHook=='1') MiniDumpType=MiniDumpNormal;
if (*pNoHook=='2') MiniDumpType=MiniDumpWithDataSegs;
if (*pNoHook=='3') MiniDumpType=MiniDumpWithFullMemory;
}
if (!bHookExplorer)
SetUnhandledExceptionFilter(TopLevelFilter);
#ifndef BUILD_SETUP
if (wcsstr(lpstrCmdLine,L"-testsettings")!=NULL || GetKeyState(VK_SHIFT)<0)
{
CoInitialize(NULL);
InitManagers(true);
EditSettings(true,0);
CloseManagers(true);
CoUninitialize();
#ifdef TRACK_GDI_RESOURCES
DllDumpResourceLeaks();
#endif
return 0;
}
#endif
// prevent multiple instances from running on the same desktop
// the assumption is that multiple desktops for the same user will have different name (but may repeat across users)
wchar_t userName[256];
DWORD len=_countof(userName);
GetUserName(userName,&len);
len=0;
HANDLE desktop=GetThreadDesktop(GetCurrentThreadId());
GetUserObjectInformation(desktop,UOI_NAME,NULL,0,&len);
wchar_t *deskName=(wchar_t*)malloc(len);
GetUserObjectInformation(desktop,UOI_NAME,deskName,len,&len);
bool bDefaultDesktop=(_wcsicmp(deskName,L"Default")==0);
wchar_t mutexName[1024];
Sprintf(mutexName,_countof(mutexName),L"OpenShellMenu.Mutex.%s.%s",userName,deskName);
free(deskName);
if (open==CMD_NONE)
DllLogToFile(STARTUP_LOG,L"StartMenu: mutex %s",mutexName);
HWND progWin=FindWindowEx(NULL,NULL,L"Progman",NULL);
DWORD process;
if (progWin)
GetWindowThreadProcessId(progWin,&process);
HANDLE hMutex=NULL;
if (bHookExplorer)
{
hMutex=CreateMutex(NULL,TRUE,mutexName);
if (GetLastError()==ERROR_ALREADY_EXISTS || GetLastError()==ERROR_ACCESS_DENIED)
{
if (open==MSG_TOGGLE || open==CMD_TOGGLE_NEW)
{
if (progWin)
{
AllowSetForegroundWindow(process);
HWND taskBar=FindTaskBar(process);
if (taskBar)
PostMessage(taskBar,RegisterWindowMessage(L"OpenShellMenu.StartMenuMsg"),(open==CMD_TOGGLE_NEW)?MSG_TOGGLENEW:MSG_TOGGLE,0);
else
PostMessage(progWin,WM_SYSCOMMAND,SC_TASKLIST,(open==CMD_TOGGLE_NEW)?'WSMK':'CSM');
}
}
else if (open!=CMD_NONE)
{
AllowSetForegroundWindow(process);
HWND hwnd=FindWindow(L"OpenShellMenu.CStartHookWindow",L"StartHookWindow");
if (hwnd) PostMessage(hwnd,WM_OPEN,open,0);
}
if (open==MSG_EXIT && hMutex && WaitForSingleObject(hMutex,2000)==WAIT_OBJECT_0)
ReleaseMutex(hMutex);
if (open==CMD_NONE)
DllLogToFile(STARTUP_LOG,L"StartMenu: exit (mutex exists)");
return 0;
}
}
if (open!=CMD_NONE && open!=MSG_OPEN && open!=MSG_SETTINGS)
{
if (hMutex) ReleaseMutex(hMutex);
return 0;
}
OleInitialize(NULL);
if (!bHookExplorer)
{
DllUpdateSettings();
InitManagers(true);
}
CStartHookWindow window;
window.Create(NULL,NULL,L"StartHookWindow",WS_POPUP);
g_TaskbarCreatedMsg=RegisterWindowMessage(L"TaskbarCreated");
typedef BOOL (WINAPI *tChangeWindowMessageFilterEx)(HWND hWnd, UINT message, DWORD action, PCHANGEFILTERSTRUCT pChangeFilterStruct );
HMODULE hUser32=GetModuleHandle(L"user32.dll");
tChangeWindowMessageFilterEx ChangeWindowMessageFilterEx=(tChangeWindowMessageFilterEx)GetProcAddress(hUser32,"ChangeWindowMessageFilterEx");
if (ChangeWindowMessageFilterEx)
{
ChangeWindowMessageFilterEx(window,g_TaskbarCreatedMsg,MSGFLT_ADD,NULL);
ChangeWindowMessageFilterEx(window,WM_CLEAR,MSGFLT_ADD,NULL);
ChangeWindowMessageFilterEx(window,WM_OPEN,MSGFLT_ADD,NULL);
ChangeWindowMessageFilterEx(window,WM_CLOSE,MSGFLT_ADD,NULL);
}
else
{
ChangeWindowMessageFilter(g_TaskbarCreatedMsg,MSGFLT_ADD);
ChangeWindowMessageFilter(WM_CLEAR,MSGFLT_ADD);
ChangeWindowMessageFilter(WM_OPEN,MSGFLT_ADD);
ChangeWindowMessageFilter(WM_CLOSE,MSGFLT_ADD);
}
MSG msg;
HWND menu=NULL;
if (HookStartMenu(bHookExplorer?(bDefaultDesktop?HOOK_STARTUP:HOOK_STARTUP2):HOOK_NONE,menu))
{
if (bHookExplorer && open>=0)
window.PostMessage(WM_OPEN,open,MSG_OPEN);
DllLogToFile(STARTUP_LOG,L"StartMenu: start message loop");
while ((bHookExplorer || IsWindow(menu)) && GetMessage(&msg,0,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
DllLogToFile(STARTUP_LOG,L"StartMenu: end message loop");
window.DestroyWindow();
if (!bHookExplorer)
{
CloseManagers(true);
}
OleUninitialize();
if (hMutex) ReleaseMutex(hMutex);
#ifdef TRACK_GDI_RESOURCES
DllDumpResourceLeaks();
#endif
return 0;
}