VirtualBox

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

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

nit

  • 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 39743 2012-01-10 17:48: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 *pwsz = L'\0';
217 }
218
219 /*
220 * Start the process.
221 */
222 int iRet = 0;
223 STARTUPINFOW StartupInfo = { sizeof(StartupInfo), 0 };
224 PROCESS_INFORMATION ProcInfo = { 0 };
225 SetLastError(740);
226 BOOL fOk = CreateProcessW(wszModule,
227 pwszNewCmdLine,
228 NULL /*pProcessAttributes*/,
229 NULL /*pThreadAttributes*/,
230 TRUE /*fInheritHandles*/,
231 0 /*dwCreationFlags*/,
232 NULL /*pEnvironment*/,
233 NULL /*pCurrentDirectory*/,
234 &StartupInfo,
235 &ProcInfo);
236 if (fOk)
237 {
238 /* Wait for the process to finish. */
239 CloseHandle(ProcInfo.hThread);
240 WaitForProcess(ProcInfo.hProcess, &iRet);
241 CloseHandle(ProcInfo.hProcess);
242 }
243 else if (GetLastError() == ERROR_ELEVATION_REQUIRED)
244 {
245 /*
246 * Elevation is required. That can be accomplished via ShellExecuteEx
247 * and the runas atom.
248 */
249 MSG Msg;
250 PeekMessage(&Msg, NULL, 0, 0, PM_NOREMOVE);
251 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
252
253 SHELLEXECUTEINFOW ShExecInfo = { 0 };
254 ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFOW);
255 ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
256 ShExecInfo.hwnd = NULL;
257 ShExecInfo.lpVerb = L"runas" ;
258 ShExecInfo.lpFile = wszModule;
259 ShExecInfo.lpParameters = pwszNewCmdLine;
260 ShExecInfo.lpDirectory = wszCurDir;
261 ShExecInfo.nShow = SW_NORMAL;
262 ShExecInfo.hProcess = INVALID_HANDLE_VALUE;
263 if (ShellExecuteExW(&ShExecInfo))
264 {
265 if (ShExecInfo.hProcess != INVALID_HANDLE_VALUE)
266 {
267 WaitForProcess2(ShExecInfo.hProcess, &iRet);
268 CloseHandle(ShExecInfo.hProcess);
269 }
270 else
271 {
272 fwprintf(stderr, L"ERROR: ShellExecuteExW did not return a valid process handle!\n");
273 iRet = 1;
274 }
275 }
276 else
277 {
278 fwprintf(stderr, L"ERROR: Failed to execute '%ws' via ShellExecuteExW: %u\n", wszModule, GetLastError());
279 iRet = 9;
280 }
281 }
282 else
283 {
284 fwprintf(stderr, L"ERROR: Failed to execute '%ws' via CreateProcessW: %u\n", wszModule, GetLastError());
285 iRet = 8;
286 }
287
288 if (pwszNewCmdLine)
289 LocalFree(pwszNewCmdLine);
290
291#if 0
292 fwprintf(stderr, L"DEBUG: iRet=%d\n", iRet);
293 fflush(stderr);
294#endif
295 return iRet;
296}
297
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