VirtualBox

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

Last change on this file since 58832 was 58040, checked in by vboxsync, 9 years ago

warning

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