Skip to content

Commit 38c155c

Browse files
authored
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
1 parent b4d2be1 commit 38c155c

File tree

1 file changed

+102
-66
lines changed

1 file changed

+102
-66
lines changed

Src/StartMenu/StartMenu.cpp

Lines changed: 102 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,97 @@ IWpnPlatform : public IUnknown
274274
//const wchar_t *g_AppId=L"Microsoft.BingWeather_8wekyb3d8bbwe!App";
275275
const wchar_t *g_AppId=L"microsoft.windowscommunicationsapps_8wekyb3d8bbwe!microsoft.windowslive.calendar";
276276

277+
static DWORD g_winVer = GetVersionEx(GetModuleHandle(L"user32.dll"));
278+
279+
bool WasOsUpgrade()
280+
{
281+
CRegKey regKey;
282+
if (regKey.Open(HKEY_LOCAL_MACHINE, L"Software\\OpenShell\\OpenShell", KEY_READ | KEY_WOW64_64KEY) == ERROR_SUCCESS)
283+
{
284+
DWORD ver;
285+
if (regKey.QueryDWORDValue(L"WinVersion", ver) == ERROR_SUCCESS)
286+
{
287+
if (ver < g_winVer)
288+
return true;
289+
}
290+
}
291+
292+
return false;
293+
}
294+
295+
// starts new instance of StartMenu.exe with "-upgrade" command line parameter
296+
// UAC dialog is shown to ensure it will run with administrator privileges
297+
void RunOsUpgradeTaskAsAdmin()
298+
{
299+
#ifdef _WIN64
300+
wchar_t path[_MAX_PATH] = L"%windir%\\System32\\StartMenuHelper64.dll";
301+
#else
302+
wchar_t path[_MAX_PATH] = L"%windir%\\System32\\StartMenuHelper32.dll";
303+
#endif
304+
DoEnvironmentSubst(path, _countof(path));
305+
if (GetFileAttributes(path) != INVALID_FILE_ATTRIBUTES)
306+
{
307+
GetModuleFileName(NULL, path, _countof(path));
308+
CoInitialize(NULL);
309+
ShellExecute(NULL, L"runas", path, L"-upgrade", NULL, SW_SHOWNORMAL);
310+
CoUninitialize();
311+
}
312+
}
313+
314+
DWORD PerformOsUpgradeTask(bool silent)
315+
{
316+
CRegKey regKey;
317+
DWORD error = regKey.Open(HKEY_LOCAL_MACHINE, L"Software\\OpenShell\\OpenShell", KEY_WRITE | KEY_WOW64_64KEY);
318+
const wchar_t *nl = error == ERROR_SUCCESS ? L"\r\n\r\n" : L"\r\n";
319+
if (error == ERROR_SUCCESS)
320+
{
321+
regKey.SetDWORDValue(L"WinVersion", g_winVer);
322+
323+
// run regsvr32 StartMenuHelper
324+
#ifdef _WIN64
325+
wchar_t cmdLine[_MAX_PATH] = L"regsvr32 /s \"%windir%\\System32\\StartMenuHelper64.dll\"";
326+
#else
327+
wchar_t cmdLine[_MAX_PATH] = L"regsvr32 /s \"%windir%\\System32\\StartMenuHelper32.dll\"";
328+
#endif
329+
DoEnvironmentSubst(cmdLine, _countof(cmdLine));
330+
331+
wchar_t exe[_MAX_PATH] = L"%windir%\\System32\\regsvr32.exe";
332+
DoEnvironmentSubst(exe, _countof(exe));
333+
334+
STARTUPINFO startupInfo = { sizeof(startupInfo) };
335+
PROCESS_INFORMATION processInfo;
336+
memset(&processInfo, 0, sizeof(processInfo));
337+
if (CreateProcess(exe, cmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo))
338+
{
339+
CloseHandle(processInfo.hThread);
340+
WaitForSingleObject(processInfo.hProcess, INFINITE);
341+
GetExitCodeProcess(processInfo.hProcess, &error);
342+
CloseHandle(processInfo.hProcess);
343+
}
344+
else
345+
{
346+
error = GetLastError();
347+
}
348+
}
349+
350+
if (!silent)
351+
{
352+
if (error)
353+
{
354+
wchar_t msg[1024];
355+
int len = Sprintf(msg, _countof(msg), L"%s%s", DllLoadStringEx(IDS_UPGRADE_ERROR), nl);
356+
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, 0, msg + len, _countof(msg) - len, NULL);
357+
MessageBox(NULL, msg, DllLoadStringEx(IDS_APP_TITLE), MB_OK | MB_ICONERROR);
358+
}
359+
else
360+
{
361+
MessageBox(NULL, DllLoadStringEx(IDS_UPGRADE_SUCCESS), DllLoadStringEx(IDS_APP_TITLE), MB_OK | MB_ICONINFORMATION);
362+
}
363+
}
364+
365+
return error;
366+
}
367+
277368
int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpstrCmdLine, int nCmdShow )
278369
{
279370
/* CoInitialize(NULL);
@@ -340,8 +431,8 @@ int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpstrC
340431
ImportLegacyData();
341432

342433
DllLogToFile(STARTUP_LOG,L"StartMenu: start '%s'",lpstrCmdLine);
343-
DWORD winVer=GetVersionEx(GetModuleHandle(L"user32.dll"));
344-
if (wcsstr(lpstrCmdLine,L"-startup") || (wcsstr(lpstrCmdLine,L"-autorun") && HIWORD(winVer)<WIN_VER_WIN8))
434+
435+
if (wcsstr(lpstrCmdLine,L"-startup") || (wcsstr(lpstrCmdLine,L"-autorun") && HIWORD(g_winVer)<WIN_VER_WIN8))
345436
{
346437
WaitDllInitThread();
347438
if (!DllGetSettingBool(L"AutoStart"))
@@ -360,31 +451,11 @@ int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpstrC
360451
else if (wcsstr(lpstrCmdLine,L"-autorun")) // on Win8+
361452
{
362453
WaitDllInitThread();
363-
CRegKey regKey;
364-
if (regKey.Open(HKEY_LOCAL_MACHINE,L"Software\\OpenShell\\OpenShell",KEY_READ|KEY_WOW64_64KEY)==ERROR_SUCCESS)
454+
if (WasOsUpgrade())
365455
{
366-
DWORD ver1;
367-
if (regKey.QueryDWORDValue(L"WinVersion",ver1)==ERROR_SUCCESS)
368-
{
369-
if (ver1<winVer)
370-
{
371-
// this is an upgrade
372-
MessageBox(NULL,DllLoadStringEx(IDS_UPGRADE_WIN),DllLoadStringEx(IDS_APP_TITLE),MB_OK);
373-
#ifdef _WIN64
374-
wchar_t path[_MAX_PATH]=L"%windir%\\System32\\StartMenuHelper64.dll";
375-
#else
376-
wchar_t path[_MAX_PATH]=L"%windir%\\System32\\StartMenuHelper32.dll";
377-
#endif
378-
DoEnvironmentSubst(path,_countof(path));
379-
if (GetFileAttributes(path)!=INVALID_FILE_ATTRIBUTES)
380-
{
381-
GetModuleFileName(NULL,path,_countof(path));
382-
CoInitialize(NULL);
383-
ShellExecute(NULL,L"runas",path,L"-upgrade",NULL,SW_SHOWNORMAL);
384-
CoUninitialize();
385-
}
386-
}
387-
}
456+
// this is an upgrade
457+
MessageBox(NULL, DllLoadStringEx(IDS_UPGRADE_WIN), DllLoadStringEx(IDS_APP_TITLE), MB_OK);
458+
RunOsUpgradeTaskAsAdmin();
388459
}
389460
if (!DllGetSettingBool(L"AutoStart"))
390461
{
@@ -399,49 +470,14 @@ int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpstrC
399470
if (wcsstr(lpstrCmdLine,L"-upgrade"))
400471
{
401472
WaitDllInitThread();
402-
CRegKey regKey;
403-
DWORD error=regKey.Open(HKEY_LOCAL_MACHINE,L"Software\\OpenShell\\OpenShell",KEY_WRITE|KEY_WOW64_64KEY);
404-
const wchar_t *nl=error==ERROR_SUCCESS?L"\r\n\r\n":L"\r\n";
405-
if (error==ERROR_SUCCESS)
406-
{
407-
regKey.SetDWORDValue(L"WinVersion",winVer);
408-
409-
// run regsvr32 StartMenuHelper
410-
#ifdef _WIN64
411-
wchar_t cmdLine[_MAX_PATH]=L"regsvr32 /s \"%windir%\\System32\\StartMenuHelper64.dll\"";
412-
#else
413-
wchar_t cmdLine[_MAX_PATH]=L"regsvr32 /s \"%windir%\\System32\\StartMenuHelper32.dll\"";
414-
#endif
415-
DoEnvironmentSubst(cmdLine,_countof(cmdLine));
416473

417-
wchar_t exe[_MAX_PATH]=L"%windir%\\System32\\regsvr32.exe";
418-
DoEnvironmentSubst(exe,_countof(exe));
419-
420-
STARTUPINFO startupInfo={sizeof(startupInfo)};
421-
PROCESS_INFORMATION processInfo;
422-
memset(&processInfo,0,sizeof(processInfo));
423-
if (CreateProcess(exe,cmdLine,NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo))
424-
{
425-
CloseHandle(processInfo.hThread);
426-
WaitForSingleObject(processInfo.hProcess,INFINITE);
427-
GetExitCodeProcess(processInfo.hProcess,&error);
428-
CloseHandle(processInfo.hProcess);
429-
}
430-
else
431-
error=GetLastError();
432-
}
433-
if (error)
434-
{
435-
wchar_t msg[1024];
436-
int len=Sprintf(msg,_countof(msg),L"%s%s",DllLoadStringEx(IDS_UPGRADE_ERROR),nl);
437-
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,NULL,error,0,msg+len,_countof(msg)-len,NULL);
438-
MessageBox(NULL,msg,DllLoadStringEx(IDS_APP_TITLE),MB_OK|MB_ICONERROR);
439-
}
440-
else
474+
if (WasOsUpgrade())
441475
{
442-
MessageBox(NULL,DllLoadStringEx(IDS_UPGRADE_SUCCESS),DllLoadStringEx(IDS_APP_TITLE),MB_OK|MB_ICONINFORMATION);
476+
const bool silent = wcsstr(lpstrCmdLine, L"-silent") != nullptr;
477+
return PerformOsUpgradeTask(silent);
443478
}
444-
return error;
479+
480+
return 0;
445481
}
446482

447483
const wchar_t *pCmd=wcsstr(lpstrCmdLine,L"-cmd ");

0 commit comments

Comments
 (0)