VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Installer/Loader/VBoxWindowsAdditions.cpp@ 51287

Last change on this file since 51287 was 40363, checked in by vboxsync, 13 years ago

GA installer/win: fix a usage dialog issue being displayed on run

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.5 KB
Line 
1/* $Id: VBoxWindowsAdditions.cpp 40363 2012-03-05 16:52:22Z vboxsync $ */
2/** @file
3 * VBoxWindowsAdditions - The Windows Guest Additions Loader.
4 *
5 * This is STUB which select whether to install 32-bit or 64-bit additions.
6 */
7
8/*
9 * Copyright (C) 2006-2012 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20/*******************************************************************************
21* Header Files *
22*******************************************************************************/
23#include <Windows.h>
24#ifndef ERROR_ELEVATION_REQUIRED /* Windows Vista and later. */
25# define ERROR_ELEVATION_REQUIRED 740
26#endif
27
28#include <stdio.h>
29#include <string.h>
30
31
32static BOOL IsWow64(void)
33{
34 BOOL bIsWow64 = FALSE;
35 typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS)(HANDLE, PBOOL);
36 LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle(L"kernel32"), "IsWow64Process");
37 if (fnIsWow64Process != NULL)
38 {
39 if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64))
40 {
41 fwprintf(stderr, L"ERROR: Could not determine process type!\n");
42
43 /* Error in retrieving process type - assume that we're running on 32bit. */
44 bIsWow64 = FALSE;
45 }
46 }
47 return bIsWow64;
48}
49
50static void WaitForProcess2(HANDLE hProcess, int *piExitCode)
51{
52 /*
53 * Wait for the process, make sure the deal with messages.
54 */
55 for (;;)
56 {
57 DWORD dwRc = MsgWaitForMultipleObjects(1, &hProcess, FALSE, 5000/*ms*/, QS_ALLEVENTS);
58
59 MSG Msg;
60 while (PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE))
61 {
62 TranslateMessage(&Msg);
63 DispatchMessageW(&Msg);
64 }
65
66 if (dwRc == WAIT_OBJECT_0)
67 break;
68 if ( dwRc != WAIT_TIMEOUT
69 && dwRc != WAIT_OBJECT_0 + 1)
70 {
71 fwprintf(stderr, L"ERROR: MsgWaitForMultipleObjects failed: %u (%u)\n", dwRc, GetLastError());
72 break;
73 }
74 }
75
76 /*
77 * Collect the process info.
78 */
79 DWORD dwExitCode;
80 if (GetExitCodeProcess(hProcess, &dwExitCode))
81 *piExitCode = (int)dwExitCode;
82 else
83 {
84 fwprintf(stderr, L"ERROR: GetExitCodeProcess failed: %u\n", GetLastError());
85 *piExitCode = 16;
86 }
87}
88
89static void WaitForProcess(HANDLE hProcess, int *piExitCode)
90{
91 DWORD WaitRc = WaitForSingleObjectEx(hProcess, INFINITE, TRUE);
92 while ( WaitRc == WAIT_IO_COMPLETION
93 || WaitRc == WAIT_TIMEOUT)
94 WaitRc = WaitForSingleObjectEx(hProcess, INFINITE, TRUE);
95 if (WaitRc == WAIT_OBJECT_0)
96 {
97 DWORD dwExitCode;
98 if (GetExitCodeProcess(hProcess, &dwExitCode))
99 *piExitCode = (int)dwExitCode;
100 else
101 {
102 fwprintf(stderr, L"ERROR: GetExitCodeProcess failed: %u\n", GetLastError());
103 *piExitCode = 16;
104 }
105 }
106 else
107 {
108 fwprintf(stderr, L"ERROR: WaitForSingleObjectEx failed: %u (%u)\n", WaitRc, GetLastError());
109 *piExitCode = 16;
110 }
111}
112
113int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
114{
115 /*
116 * Gather the parameters of the real installer program.
117 */
118
119 SetLastError(NO_ERROR);
120 WCHAR wszCurDir[_MAX_PATH] = { 0 };
121 DWORD cchCurDir = GetCurrentDirectoryW(sizeof(wszCurDir), wszCurDir);
122 if (cchCurDir == 0 || cchCurDir >= sizeof(wszCurDir))
123 {
124 fwprintf(stderr, L"ERROR: GetCurrentDirectoryW failed: %u (ret %u)\n", GetLastError(), cchCurDir);
125 return 12;
126 }
127
128 SetLastError(NO_ERROR);
129 WCHAR wszModule[_MAX_PATH] = { 0 };
130 DWORD cchModule = GetModuleFileNameW(NULL, wszModule, sizeof(wszModule));
131 if (cchModule == 0 || cchModule >= sizeof(wszModule))
132 {
133 fwprintf(stderr, L"ERROR: GetModuleFileNameW failed: %u (ret %u)\n", GetLastError(), cchModule);
134 return 13;
135 }
136
137 /* Strip the extension off the module name and construct the arch specific
138 one of the real installer program. */
139 DWORD off = cchModule - 1;
140 while ( off > 0
141 && ( wszModule[off] != '/'
142 && wszModule[off] != '\\'
143 && wszModule[off] != ':'))
144 {
145 if (wszModule[off] == '.')
146 {
147 wszModule[off] = '\0';
148 cchModule = off;
149 break;
150 }
151 off--;
152 }
153
154 WCHAR const *pwszSuff = IsWow64() ? L"-amd64.exe" : L"-x86.exe";
155 size_t cchSuff = wcslen(pwszSuff);
156 if (cchSuff + cchModule >= sizeof(wszModule))
157 {
158 fwprintf(stderr, L"ERROR: Real installer name is too long (%u chars)\n", cchSuff + cchModule);
159 return 14;
160 }
161 wcscpy(&wszModule[cchModule], pwszSuff);
162 cchModule += cchSuff;
163
164 /* Replace the first argument of the argument list. */
165 PWCHAR pwszNewCmdLine = NULL;
166 LPCWSTR pwszOrgCmdLine = GetCommandLineW();
167 if (pwszOrgCmdLine) /* Dunno if this can be NULL, but whatever. */
168 {
169 /* Skip the first argument in the original. */
170 /** @todo Is there some ISBLANK or ISSPACE macro/function in Win32 that we could
171 * use here, if it's correct wrt. command line conventions? */
172 WCHAR wch;
173 while ((wch = *pwszOrgCmdLine) == L' ' || wch == L'\t')
174 pwszOrgCmdLine++;
175 if (wch == L'"')
176 {
177 pwszOrgCmdLine++;
178 while ((wch = *pwszOrgCmdLine) != L'\0')
179 {
180 pwszOrgCmdLine++;
181 if (wch == L'"')
182 break;
183 }
184 }
185 else
186 {
187 while ((wch = *pwszOrgCmdLine) != L'\0')
188 {
189 pwszOrgCmdLine++;
190 if (wch == L' ' || wch == L'\t')
191 break;
192 }
193 }
194 while ((wch = *pwszOrgCmdLine) == L' ' || wch == L'\t')
195 pwszOrgCmdLine++;
196
197 /* Join up "szModule" with the remainder of the original command line. */
198 size_t cchOrgCmdLine = wcslen(pwszOrgCmdLine);
199 size_t cchNewCmdLine = 1 + cchModule + 1 + 1 + cchOrgCmdLine + 1;
200 PWCHAR pwsz = pwszNewCmdLine = (PWCHAR)LocalAlloc(LPTR, cchNewCmdLine * sizeof(WCHAR));
201 if (!pwsz)
202 {
203 fwprintf(stderr, L"ERROR: Out of memory (%u bytes)\n", cchNewCmdLine);
204 return 15;
205 }
206 *pwsz++ = L'"';
207 wcscpy(pwsz, wszModule);
208 pwsz += cchModule;
209 *pwsz++ = L'"';
210 if (cchOrgCmdLine)
211 {
212 *pwsz++ = L' ';
213 wcscpy(pwsz, pwszOrgCmdLine);
214 }
215 else
216 {
217 *pwsz = L'\0';
218 pwszOrgCmdLine = NULL;
219 }
220 }
221
222 /*
223 * Start the process.
224 */
225 int iRet = 0;
226 STARTUPINFOW StartupInfo = { sizeof(StartupInfo), 0 };
227 PROCESS_INFORMATION ProcInfo = { 0 };
228 SetLastError(740);
229 BOOL fOk = CreateProcessW(wszModule,
230 pwszNewCmdLine,
231 NULL /*pProcessAttributes*/,
232 NULL /*pThreadAttributes*/,
233 TRUE /*fInheritHandles*/,
234 0 /*dwCreationFlags*/,
235 NULL /*pEnvironment*/,
236 NULL /*pCurrentDirectory*/,
237 &StartupInfo,
238 &ProcInfo);
239 if (fOk)
240 {
241 /* Wait for the process to finish. */
242 CloseHandle(ProcInfo.hThread);
243 WaitForProcess(ProcInfo.hProcess, &iRet);
244 CloseHandle(ProcInfo.hProcess);
245 }
246 else if (GetLastError() == ERROR_ELEVATION_REQUIRED)
247 {
248 /*
249 * Elevation is required. That can be accomplished via ShellExecuteEx
250 * and the runas atom.
251 */
252 MSG Msg;
253 PeekMessage(&Msg, NULL, 0, 0, PM_NOREMOVE);
254 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
255
256 SHELLEXECUTEINFOW ShExecInfo = { 0 };
257 ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFOW);
258 ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
259 ShExecInfo.hwnd = NULL;
260 ShExecInfo.lpVerb = L"runas" ;
261 ShExecInfo.lpFile = wszModule;
262 ShExecInfo.lpParameters = pwszOrgCmdLine; /* pass only args here!!! */
263 ShExecInfo.lpDirectory = wszCurDir;
264 ShExecInfo.nShow = SW_NORMAL;
265 ShExecInfo.hProcess = INVALID_HANDLE_VALUE;
266 if (ShellExecuteExW(&ShExecInfo))
267 {
268 if (ShExecInfo.hProcess != INVALID_HANDLE_VALUE)
269 {
270 WaitForProcess2(ShExecInfo.hProcess, &iRet);
271 CloseHandle(ShExecInfo.hProcess);
272 }
273 else
274 {
275 fwprintf(stderr, L"ERROR: ShellExecuteExW did not return a valid process handle!\n");
276 iRet = 1;
277 }
278 }
279 else
280 {
281 fwprintf(stderr, L"ERROR: Failed to execute '%ws' via ShellExecuteExW: %u\n", wszModule, GetLastError());
282 iRet = 9;
283 }
284 }
285 else
286 {
287 fwprintf(stderr, L"ERROR: Failed to execute '%ws' via CreateProcessW: %u\n", wszModule, GetLastError());
288 iRet = 8;
289 }
290
291 if (pwszNewCmdLine)
292 LocalFree(pwszNewCmdLine);
293
294#if 0
295 fwprintf(stderr, L"DEBUG: iRet=%d\n", iRet);
296 fflush(stderr);
297#endif
298 return iRet;
299}
300
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette