VirtualBox

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

Last change on this file since 85800 was 83843, checked in by vboxsync, 5 years ago

Additions/NT/Installer: VC++ 14.1 warnings. bugref:8489

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