VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 16 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
RevLine 
[31634]1/* $Id: VBoxWindowsAdditions.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
[39742]3 * VBoxWindowsAdditions - The Windows Guest Additions Loader.
4 *
5 * This is STUB which select whether to install 32-bit or 64-bit additions.
[31634]6 */
7
8/*
[98103]9 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
[31634]10 *
[96407]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
[31634]28 */
29
[57358]30
31/*********************************************************************************************************************************
32* Header Files *
33*********************************************************************************************************************************/
[63091]34#include <iprt/cdefs.h>
[62679]35#include <iprt/win/windows.h>
[39742]36#ifndef ERROR_ELEVATION_REQUIRED /* Windows Vista and later. */
37# define ERROR_ELEVATION_REQUIRED 740
[31634]38#endif
39
[96449]40#include <iprt/string.h>
41#include <iprt/utf16.h>
[31634]42
[96449]43#include "NoCrtOutput.h"
[31634]44
[96449]45
[39742]46static BOOL IsWow64(void)
[31634]47{
[63091]48 BOOL fIsWow64 = FALSE;
[39742]49 typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS)(HANDLE, PBOOL);
[96449]50 LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandleW(L"kernel32"), "IsWow64Process");
[39742]51 if (fnIsWow64Process != NULL)
[31634]52 {
[63091]53 if (!fnIsWow64Process(GetCurrentProcess(), &fIsWow64))
[31634]54 {
[96449]55 ErrorMsgLastErr("Unable to determine the process type!");
[31634]56
57 /* Error in retrieving process type - assume that we're running on 32bit. */
[63091]58 fIsWow64 = FALSE;
[31634]59 }
60 }
[63091]61 return fIsWow64;
[31634]62}
63
[96449]64static int WaitForProcess2(HANDLE hProcess)
[31634]65{
[39742]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);
[31634]72
[39742]73 MSG Msg;
74 while (PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE))
75 {
76 TranslateMessage(&Msg);
77 DispatchMessageW(&Msg);
78 }
[31634]79
[39742]80 if (dwRc == WAIT_OBJECT_0)
81 break;
82 if ( dwRc != WAIT_TIMEOUT
83 && dwRc != WAIT_OBJECT_0 + 1)
84 {
[96449]85 ErrorMsgLastErrSUR("MsgWaitForMultipleObjects failed: ", dwRc);
[39742]86 break;
87 }
88 }
[31634]89
[39742]90 /*
91 * Collect the process info.
92 */
93 DWORD dwExitCode;
94 if (GetExitCodeProcess(hProcess, &dwExitCode))
[96449]95 return (int)dwExitCode;
96 return ErrorMsgRcLastErr(16, "GetExitCodeProcess failed");
[39742]97}
[31634]98
[96449]99static int WaitForProcess(HANDLE hProcess)
[39742]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)
[31634]106 {
[39742]107 DWORD dwExitCode;
108 if (GetExitCodeProcess(hProcess, &dwExitCode))
[96449]109 return (int)dwExitCode;
110 return ErrorMsgRcLastErr(16, "GetExitCodeProcess failed");
[31634]111 }
[96449]112 return ErrorMsgRcLastErrSUR(16, "MsgWaitForMultipleObjects failed: ", WaitRc);
[39742]113}
[31634]114
[96449]115#ifndef IPRT_NO_CRT
[39742]116int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
[96449]117#else
118int main()
119#endif
[39742]120{
[96449]121#ifndef IPRT_NO_CRT
[63091]122 RT_NOREF(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
[96449]123#endif
[63091]124
[39742]125 /*
126 * Gather the parameters of the real installer program.
127 */
128 SetLastError(NO_ERROR);
[96449]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);
[39742]133
134 SetLastError(NO_ERROR);
[96449]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);
[31634]139
[96449]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;
[39742]145 while ( off > 0
[96449]146 && ( wszExePath[off] != '/'
147 && wszExePath[off] != '\\'
148 && wszExePath[off] != ':'))
[39742]149 {
[96449]150 if (wszExePath[off] == '.')
[39742]151 {
[96449]152 wszExePath[off] = '\0';
153 cwcExePath = off;
[39742]154 break;
155 }
156 off--;
157 }
[31634]158
[39742]159 WCHAR const *pwszSuff = IsWow64() ? L"-amd64.exe" : L"-x86.exe";
[96449]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]);
[31634]164
[96449]165 /*
166 * Replace the first argument of the argument list.
167 */
[39742]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'"')
[31634]179 {
[39742]180 pwszOrgCmdLine++;
181 while ((wch = *pwszOrgCmdLine) != L'\0')
[31634]182 {
[39742]183 pwszOrgCmdLine++;
184 if (wch == L'"')
185 break;
[31634]186 }
187 }
[39742]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
[96449]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));
[39742]204 if (!pwsz)
[96449]205 return ErrorMsgRcSUS(15, "Out of memory (", cwcNewCmdLine * sizeof(WCHAR), " bytes)");
[39742]206 *pwsz++ = L'"';
[96449]207 memcpy(pwsz, wszExePath, cwcExePath * sizeof(pwsz[0]));
208 pwsz += cwcExePath;
[39742]209 *pwsz++ = L'"';
[96449]210 if (cwcOrgCmdLine)
[39742]211 {
212 *pwsz++ = L' ';
[96449]213 memcpy(pwsz, pwszOrgCmdLine, cwcOrgCmdLine * sizeof(pwsz[0]));
[39742]214 }
215 else
[40363]216 {
[39742]217 *pwsz = L'\0';
[40363]218 pwszOrgCmdLine = NULL;
219 }
[31634]220 }
221
[39742]222 /*
223 * Start the process.
224 */
[96449]225 int rcExit = 0;
[39742]226 STARTUPINFOW StartupInfo = { sizeof(StartupInfo), 0 };
[96449]227 PROCESS_INFORMATION ProcInfo = { 0 };
[39742]228 SetLastError(740);
[96449]229 BOOL fOk = CreateProcessW(wszExePath,
[39742]230 pwszNewCmdLine,
231 NULL /*pProcessAttributes*/,
232 NULL /*pThreadAttributes*/,
233 TRUE /*fInheritHandles*/,
[39743]234 0 /*dwCreationFlags*/,
[39742]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);
[96449]243 rcExit = WaitForProcess(ProcInfo.hProcess);
[39742]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);
[31634]255
[39742]256 SHELLEXECUTEINFOW ShExecInfo = { 0 };
257 ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFOW);
258 ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
259 ShExecInfo.hwnd = NULL;
260 ShExecInfo.lpVerb = L"runas" ;
[96449]261 ShExecInfo.lpFile = wszExePath;
[40363]262 ShExecInfo.lpParameters = pwszOrgCmdLine; /* pass only args here!!! */
[39742]263 ShExecInfo.lpDirectory = wszCurDir;
264 ShExecInfo.nShow = SW_NORMAL;
265 ShExecInfo.hProcess = INVALID_HANDLE_VALUE;
266 if (ShellExecuteExW(&ShExecInfo))
[31634]267 {
[39742]268 if (ShExecInfo.hProcess != INVALID_HANDLE_VALUE)
269 {
[96449]270 rcExit = WaitForProcess2(ShExecInfo.hProcess);
[39742]271 CloseHandle(ShExecInfo.hProcess);
272 }
273 else
[96449]274 rcExit = ErrorMsgRc(1, "ShellExecuteExW did not return a valid process handle!");
[31634]275 }
[39742]276 else
[96449]277 rcExit = ErrorMsgRcLastErrSWSR(9, "Failed to execute '", wszExePath, "' via ShellExecuteExW!");
[31634]278 }
[39742]279 else
[96449]280 rcExit = ErrorMsgRcLastErrSWSR(8, "Failed to execute '", wszExePath, "' via CreateProcessW!");
[31634]281
[39742]282 if (pwszNewCmdLine)
283 LocalFree(pwszNewCmdLine);
[31634]284
[96449]285 return rcExit;
[31634]286}
287
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use