VirtualBox

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

Last change on this file since 106061 was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.6 KB
Line 
1/* $Id: VBoxWindowsAdditions.cpp 106061 2024-09-16 14:03:52Z 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-2024 Oracle and/or its affiliates.
10 *
11 * This file is part of VirtualBox base platform packages, as
12 * available from https://www.virtualbox.org.
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation, in version 3 of the
17 * License.
18 *
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see <https://www.gnu.org/licenses>.
26 *
27 * SPDX-License-Identifier: GPL-3.0-only
28 */
29
30
31/*********************************************************************************************************************************
32* Header Files *
33*********************************************************************************************************************************/
34#include <iprt/cdefs.h>
35#include <iprt/win/windows.h>
36#ifndef ERROR_ELEVATION_REQUIRED /* Windows Vista and later. */
37# define ERROR_ELEVATION_REQUIRED 740
38#endif
39
40#include <iprt/string.h>
41#include <iprt/utf16.h>
42
43#include "NoCrtOutput.h"
44
45
46static BOOL IsWow64(void)
47{
48 BOOL fIsWow64 = FALSE;
49 typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS)(HANDLE, PBOOL);
50 LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandleW(L"kernel32"), "IsWow64Process");
51 if (fnIsWow64Process != NULL)
52 {
53 if (!fnIsWow64Process(GetCurrentProcess(), &fIsWow64))
54 {
55 ErrorMsgLastErr("Unable to determine the process type!");
56
57 /* Error in retrieving process type - assume that we're running on 32bit. */
58 fIsWow64 = FALSE;
59 }
60 }
61 return fIsWow64;
62}
63
64static int WaitForProcess2(HANDLE hProcess)
65{
66 /*
67 * Wait for the process, make sure the deal with messages.
68 */
69 for (;;)
70 {
71 DWORD dwRc = MsgWaitForMultipleObjects(1, &hProcess, FALSE, 5000/*ms*/, QS_ALLEVENTS);
72
73 MSG Msg;
74 while (PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE))
75 {
76 TranslateMessage(&Msg);
77 DispatchMessageW(&Msg);
78 }
79
80 if (dwRc == WAIT_OBJECT_0)
81 break;
82 if ( dwRc != WAIT_TIMEOUT
83 && dwRc != WAIT_OBJECT_0 + 1)
84 {
85 ErrorMsgLastErrSUR("MsgWaitForMultipleObjects failed: ", dwRc);
86 break;
87 }
88 }
89
90 /*
91 * Collect the process info.
92 */
93 DWORD dwExitCode;
94 if (GetExitCodeProcess(hProcess, &dwExitCode))
95 return (int)dwExitCode;
96 return ErrorMsgRcLastErr(16, "GetExitCodeProcess failed");
97}
98
99static int WaitForProcess(HANDLE hProcess)
100{
101 DWORD WaitRc = WaitForSingleObjectEx(hProcess, INFINITE, TRUE);
102 while ( WaitRc == WAIT_IO_COMPLETION
103 || WaitRc == WAIT_TIMEOUT)
104 WaitRc = WaitForSingleObjectEx(hProcess, INFINITE, TRUE);
105 if (WaitRc == WAIT_OBJECT_0)
106 {
107 DWORD dwExitCode;
108 if (GetExitCodeProcess(hProcess, &dwExitCode))
109 return (int)dwExitCode;
110 return ErrorMsgRcLastErr(16, "GetExitCodeProcess failed");
111 }
112 return ErrorMsgRcLastErrSUR(16, "MsgWaitForMultipleObjects failed: ", WaitRc);
113}
114
115#ifndef IPRT_NO_CRT
116int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
117#else
118int main()
119#endif
120{
121#ifndef IPRT_NO_CRT
122 RT_NOREF(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
123#endif
124
125 /*
126 * Gather the parameters of the real installer program.
127 */
128 SetLastError(NO_ERROR);
129 WCHAR wszCurDir[MAX_PATH] = { 0 };
130 DWORD cwcCurDir = GetCurrentDirectoryW(sizeof(wszCurDir), wszCurDir);
131 if (cwcCurDir == 0 || cwcCurDir >= sizeof(wszCurDir))
132 return ErrorMsgRcLastErrSUR(12, "GetCurrentDirectoryW failed: ", cwcCurDir);
133
134 SetLastError(NO_ERROR);
135 WCHAR wszExePath[MAX_PATH] = { 0 };
136 DWORD cwcExePath = GetModuleFileNameW(NULL, wszExePath, sizeof(wszExePath));
137 if (cwcExePath == 0 || cwcExePath >= sizeof(wszExePath))
138 return ErrorMsgRcLastErrSUR(13, "GetModuleFileNameW failed: ", cwcExePath);
139
140 /*
141 * Strip the extension off the module name and construct the arch specific
142 * one of the real installer program.
143 */
144 DWORD off = cwcExePath - 1;
145 while ( off > 0
146 && ( wszExePath[off] != '/'
147 && wszExePath[off] != '\\'
148 && wszExePath[off] != ':'))
149 {
150 if (wszExePath[off] == '.')
151 {
152 wszExePath[off] = '\0';
153 cwcExePath = off;
154 break;
155 }
156 off--;
157 }
158
159 WCHAR const *pwszSuff = IsWow64() ? L"-amd64.exe" : L"-x86.exe";
160 int rc = RTUtf16Copy(&wszExePath[cwcExePath], RT_ELEMENTS(wszExePath) - cwcExePath, pwszSuff);
161 if (RT_FAILURE(rc))
162 return ErrorMsgRc(14, "Real installer name is too long!");
163 cwcExePath += RTUtf16Len(&wszExePath[cwcExePath]);
164
165 /*
166 * Replace the first argument of the argument list.
167 */
168 PWCHAR pwszNewCmdLine = NULL;
169 LPCWSTR pwszOrgCmdLine = GetCommandLineW();
170 if (pwszOrgCmdLine) /* Dunno if this can be NULL, but whatever. */
171 {
172 /* Skip the first argument in the original. */
173 /** @todo Is there some ISBLANK or ISSPACE macro/function in Win32 that we could
174 * use here, if it's correct wrt. command line conventions? */
175 WCHAR wch;
176 while ((wch = *pwszOrgCmdLine) == L' ' || wch == L'\t')
177 pwszOrgCmdLine++;
178 if (wch == L'"')
179 {
180 pwszOrgCmdLine++;
181 while ((wch = *pwszOrgCmdLine) != L'\0')
182 {
183 pwszOrgCmdLine++;
184 if (wch == L'"')
185 break;
186 }
187 }
188 else
189 {
190 while ((wch = *pwszOrgCmdLine) != L'\0')
191 {
192 pwszOrgCmdLine++;
193 if (wch == L' ' || wch == L'\t')
194 break;
195 }
196 }
197 while ((wch = *pwszOrgCmdLine) == L' ' || wch == L'\t')
198 pwszOrgCmdLine++;
199
200 /* Join up "wszExePath" with the remainder of the original command line. */
201 size_t cwcOrgCmdLine = RTUtf16Len(pwszOrgCmdLine);
202 size_t cwcNewCmdLine = 1 + cwcExePath + 1 + 1 + cwcOrgCmdLine + 1;
203 PWCHAR pwsz = pwszNewCmdLine = (PWCHAR)LocalAlloc(LPTR, cwcNewCmdLine * sizeof(WCHAR));
204 if (!pwsz)
205 return ErrorMsgRcSUS(15, "Out of memory (", cwcNewCmdLine * sizeof(WCHAR), " bytes)");
206 *pwsz++ = L'"';
207 memcpy(pwsz, wszExePath, cwcExePath * sizeof(pwsz[0]));
208 pwsz += cwcExePath;
209 *pwsz++ = L'"';
210 if (cwcOrgCmdLine)
211 {
212 *pwsz++ = L' ';
213 memcpy(pwsz, pwszOrgCmdLine, cwcOrgCmdLine * sizeof(pwsz[0]));
214 }
215 else
216 {
217 *pwsz = L'\0';
218 pwszOrgCmdLine = NULL;
219 }
220 }
221
222 /*
223 * Start the process.
224 */
225 int rcExit = 0;
226 STARTUPINFOW StartupInfo = { sizeof(StartupInfo), 0 };
227 PROCESS_INFORMATION ProcInfo = { 0 };
228 SetLastError(740);
229 BOOL fOk = CreateProcessW(wszExePath,
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 rcExit = WaitForProcess(ProcInfo.hProcess);
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 = wszExePath;
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 rcExit = WaitForProcess2(ShExecInfo.hProcess);
271 CloseHandle(ShExecInfo.hProcess);
272 }
273 else
274 rcExit = ErrorMsgRc(1, "ShellExecuteExW did not return a valid process handle!");
275 }
276 else
277 rcExit = ErrorMsgRcLastErrSWSR(9, "Failed to execute '", wszExePath, "' via ShellExecuteExW!");
278 }
279 else
280 rcExit = ErrorMsgRcLastErrSWSR(8, "Failed to execute '", wszExePath, "' via CreateProcessW!");
281
282 if (pwszNewCmdLine)
283 LocalFree(pwszNewCmdLine);
284
285 return rcExit;
286}
287
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