Index: base/applications/rapps/loaddlg.c =================================================================== --- base/applications/rapps/loaddlg.c (revision 43946) +++ base/applications/rapps/loaddlg.c (working copy) @@ -35,6 +35,7 @@ #include #include #include +#include static PAPPLICATION_INFO AppInfo; static HICON hIcon = NULL; @@ -47,6 +48,77 @@ BOOL *pbCancelled; } IBindStatusCallbackImpl; +#if DBG +#define TRACEW(_va_) DbgPrintW _va_ +#else +#define TRACEW(_va_) +#endif + +ULONG __cdecl DbgPrintW( IN LPWSTR Format, IN ... ) +{ + WCHAR Buf[ MAX_PATH*2 ]; + ULONG Len; + va_list va; + + va_start( va, Format ); + Len = wvsprintfW( Buf, Format, va ); + va_end( va ); + OutputDebugStringW( Buf ); + return Len; +} + +// UserIsAdmin - Standard method for Administrator determination + +BOOL UserIsAdmin() +{ + HANDLE hThreadTok; + DWORD cbTokenGrp; + TOKEN_GROUPS* pTokenGrp; + UINT Grp; + PSID psidAdmin; + BOOL isAdmin = FALSE; + + SID_IDENTIFIER_AUTHORITY SecAuthority = { + SECURITY_NT_AUTHORITY + }; + if (!OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, FALSE, &hThreadTok )) + { + if (ERROR_NO_TOKEN == GetLastError()) + { + if (!OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &hThreadTok )) + return FALSE; + } + else return FALSE; + } + if (!GetTokenInformation( hThreadTok, TokenGroups, NULL,0, &cbTokenGrp ) + && ERROR_INSUFFICIENT_BUFFER != GetLastError()) + return FALSE; + + pTokenGrp = LocalAlloc( LPTR,cbTokenGrp ); + if (!pTokenGrp) return FALSE; + + if (!GetTokenInformation( hThreadTok, + TokenGroups, pTokenGrp, cbTokenGrp, &cbTokenGrp + )) goto free_pgroup; + + if (!AllocateAndInitializeSid( &SecAuthority, 2, + SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0,0,0,0,0,0, + &psidAdmin + )) goto free_pgroup; + + for( Grp = 0; Grp < pTokenGrp->GroupCount; Grp++ ) + if (EqualSid( pTokenGrp->Groups[Grp].Sid, psidAdmin )) + { + isAdmin = TRUE; + break; + } + FreeSid( psidAdmin ); +free_pgroup: + LocalFree( pTokenGrp ); + CloseHandle( hThreadTok ); + return isAdmin; +} + static HRESULT WINAPI dlQueryInterface(IBindStatusCallback* This, REFIID riid, void** ppvObject) @@ -208,6 +280,16 @@ return (IBindStatusCallback*) This; } +#define MB_QUERY MB_YESNO |MB_ICONQUESTION +LPWSTR szWaitMoreCap = L"Installer Timeout"; +LPWSTR szWaitMore = L"The installation program appears to have stalled.\n" + "Would You like to wait a bit longer to see if it runs to completion ?"; + +LPWSTR szTermProcCap = L"Terminate Installer"; +LPWSTR szTermProc = L"Would You like to try terminating the installer by force ?\n\n" + "Be aware that this can have serious consequences, and may leave the system\n" + "in an inconsistent state which prohibits other installers from running."; + static DWORD WINAPI ThreadFunc(LPVOID Context) @@ -218,21 +300,25 @@ STARTUPINFOW si; PROCESS_INFORMATION pi; HWND Dlg = (HWND) Context; - DWORD r; + DWORD r, wr; BOOL bCancelled = FALSE; BOOL bTempfile = FALSE; BOOL bCab = FALSE; + BOOL makeNoise = FALSE; + BOOL instRunning = FALSE; + UINT Len, timeoutMinutes; /* built the path for the download */ p = wcsrchr(AppInfo->szUrlDownload, L'/'); if (!p) goto end; - if (wcslen(AppInfo->szUrlDownload) > 4) + Len = wcslen(AppInfo->szUrlDownload); + if (Len > 4) { - if (AppInfo->szUrlDownload[wcslen(AppInfo->szUrlDownload) - 4] == '.' && - AppInfo->szUrlDownload[wcslen(AppInfo->szUrlDownload) - 3] == 'c' && - AppInfo->szUrlDownload[wcslen(AppInfo->szUrlDownload) - 2] == 'a' && - AppInfo->szUrlDownload[wcslen(AppInfo->szUrlDownload) - 1] == 'b') + if (AppInfo->szUrlDownload[Len - 4] == '.' && + AppInfo->szUrlDownload[Len - 3] == 'c' && + AppInfo->szUrlDownload[Len - 2] == 'a' && + AppInfo->szUrlDownload[Len - 1] == 'b') { bCab = TRUE; if (!GetCurrentDirectoryW(MAX_PATH, path)) @@ -256,7 +342,9 @@ /* download it */ bTempfile = TRUE; - dl = CreateDl(Context, &bCancelled); + dl = CreateDl( Context, &bCancelled ); + if (!dl) DbgPrint( "err:(%s:%d) CreateDl returned NULL!\n", __FILE__, __LINE__ ); + r = URLDownloadToFileW(NULL, AppInfo->szUrlDownload, path, 0, dl); if (dl) IBindStatusCallback_Release(dl); if (S_OK != r) goto end; @@ -267,22 +355,45 @@ /* run it */ memset(&si, 0, sizeof(si)); si.cb = sizeof(si); - r = CreateProcessW(path, NULL, NULL, NULL, 0, 0, NULL, NULL, &si, &pi); - if (0 == r) goto end; + instRunning = CreateProcessW(path, NULL, NULL, NULL, 0, 0, NULL, NULL, &si, &pi); + if (!instRunning) goto end; - CloseHandle(pi.hThread); - WaitForSingleObject(pi.hProcess, INFINITE); - CloseHandle(pi.hProcess); + CloseHandle( pi.hThread ); + DbgPrint( "fixme:(%s:%d) Installer timeout should be configurable.\n", __FILE__, __LINE__ ); + timeoutMinutes = 5; + while( instRunning ) + { + // Wait 'timeoutMinutes' for the installer to complete + wr = WaitForSingleObject( pi.hProcess, timeoutMinutes*60000 ); + instRunning = (wr == WAIT_TIMEOUT); + if (instRunning) + { + if (makeNoise) MessageBeep( 0 ); + if (IDNO == MessageBoxW( + GetParent( Dlg ), szWaitMore, szWaitMoreCap, MB_QUERY + )) break; + } + } + if (instRunning && UserIsAdmin() + && IDYES == MessageBoxW( GetParent( Dlg ),szTermProc,szTermProcCap,MB_QUERY )) + { + DbgPrint( "ALERT (%s:%d) Terminating stalled installer.\n", __FILE__, __LINE__ ); + instRunning = !TerminateProcess( pi.hProcess, EXIT_FAILURE ); + if (instRunning) + DbgPrint( "err:(%s:%d) TerminateProcess failed. Error code = %d.\n", + __FILE__, __LINE__, GetLastError() + ); + } + CloseHandle( pi.hProcess ); end: - if (bTempfile) + if (bTempfile && !instRunning) { if (bCancelled || (SettingsInfo.bDelInstaller && !bCab)) - DeleteFileW(path); + DeleteFileW( path ); } - EndDialog(Dlg, 0); - + EndDialog( Dlg, 0 ); return 0; }