VirtualBox

source: vbox/trunk/src/VBox/Installer/win/InstallHelper/VBoxInstallHelper.cpp@ 96428

Last change on this file since 96428 was 96428, checked in by vboxsync, 3 years ago

Installer/win: Added new build define VBOX_WITH_CRT_PACKING, which leaves out packing the MSCRT with the Windows installer and also checks if the MSCRT 2019 Redistributable Package is installed on the system as a prerequisite (via a custom action). bugref:10284

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 73.9 KB
Line 
1/* $Id: VBoxInstallHelper.cpp 96428 2022-08-23 07:27:21Z vboxsync $ */
2/** @file
3 * VBoxInstallHelper - Various helper routines for Windows host installer.
4 */
5
6/*
7 * Copyright (C) 2008-2022 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.215389.xyz.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#ifdef VBOX_WITH_NETFLT
33# include "VBox/VBoxNetCfg-win.h"
34# include "VBox/VBoxDrvCfg-win.h"
35#endif
36
37#include <VBox/version.h>
38
39#include <wchar.h>
40#include <stdio.h>
41
42#include <msi.h>
43#include <msiquery.h>
44
45#define _WIN32_DCOM
46#include <iprt/win/windows.h>
47
48#include <assert.h>
49#include <shellapi.h>
50#define INITGUID
51#include <guiddef.h>
52#include <cfgmgr32.h>
53#include <devguid.h>
54
55#include <iprt/alloca.h>
56#include <iprt/string.h> /* RT_ZERO */
57#include <iprt/path.h> /* RTPATH_MAX, RTPATH_IS_SLASH */
58
59#include <iprt/win/objbase.h>
60#include <iprt/win/setupapi.h>
61#include <iprt/win/shlobj.h>
62
63#include "VBoxCommon.h"
64
65#ifndef VBOX_OSE
66# include "internal/VBoxSerial.h"
67#endif
68
69
70/*********************************************************************************************************************************
71* Defined Constants And Macros *
72*********************************************************************************************************************************/
73#ifdef DEBUG
74# define NonStandardAssert(_expr) assert(_expr)
75#else
76# define NonStandardAssert(_expr) do{ }while(0)
77#endif
78
79#define MY_WTEXT_HLP(a_str) L##a_str
80#define MY_WTEXT(a_str) MY_WTEXT_HLP(a_str)
81
82
83
84/**
85 * DLL entry point.
86 */
87BOOL WINAPI DllMain(HANDLE hInst, ULONG uReason, LPVOID pReserved)
88{
89 RT_NOREF(hInst, uReason, pReserved);
90 return TRUE;
91}
92
93/**
94 * Format and add message to the MSI log.
95 *
96 * UTF-16 strings are formatted using '%s' (lowercase).
97 * ANSI strings are formatted using '%S' (uppercase).
98 */
99static UINT logStringF(MSIHANDLE hInstall, const wchar_t *pwszFmt, ...)
100{
101 PMSIHANDLE hMSI = MsiCreateRecord(2 /* cParms */);
102 if (hMSI)
103 {
104 wchar_t wszBuf[RTPATH_MAX + 256];
105 va_list va;
106 va_start(va, pwszFmt);
107 ssize_t cwc = _vsnwprintf(wszBuf, RT_ELEMENTS(wszBuf), pwszFmt, va);
108 va_end(va);
109 wszBuf[RT_ELEMENTS(wszBuf) - 1] = '\0';
110
111 MsiRecordSetStringW(hMSI, 0, wszBuf);
112 MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_INFO), hMSI);
113
114 MsiCloseHandle(hMSI);
115 return cwc < RT_ELEMENTS(wszBuf) ? ERROR_SUCCESS : ERROR_BUFFER_OVERFLOW;
116 }
117 return ERROR_ACCESS_DENIED;
118}
119
120UINT __stdcall IsSerialCheckNeeded(MSIHANDLE hModule)
121{
122#ifndef VBOX_OSE
123 /*BOOL fRet =*/ serialCheckNeeded(hModule);
124#else
125 RT_NOREF(hModule);
126#endif
127 return ERROR_SUCCESS;
128}
129
130UINT __stdcall CheckSerial(MSIHANDLE hModule)
131{
132#ifndef VBOX_OSE
133 /*BOOL bRet =*/ serialIsValid(hModule);
134#else
135 RT_NOREF(hModule);
136#endif
137 return ERROR_SUCCESS;
138}
139
140/**
141 * Runs an executable on the OS.
142 *
143 * @returns Windows error code.
144 * @param hModule Windows installer module handle.
145 * @param pwszImage The executable to run.
146 * @param pwszArgs The arguments (command line w/o executable).
147 */
148static UINT procRun(MSIHANDLE hModule, const wchar_t *pwszImage, wchar_t const *pwszArgs)
149{
150 /*
151 * Construct a full command line.
152 */
153 size_t const cwcImage = wcslen(pwszImage);
154 size_t const cwcArgs = wcslen(pwszArgs);
155
156 wchar_t *pwszCmdLine = (wchar_t *)alloca((1 + cwcImage + 1 + 1 + cwcArgs + 1) * sizeof(wchar_t));
157 pwszCmdLine[0] = '"';
158 memcpy(&pwszCmdLine[1], pwszImage, cwcImage * sizeof(wchar_t));
159 pwszCmdLine[1 + cwcImage] = '"';
160 pwszCmdLine[1 + cwcImage + 1] = ' ';
161 memcpy(&pwszCmdLine[1 + cwcImage + 1 + 1], pwszArgs, (cwcArgs + 1) * sizeof(wchar_t));
162
163 /*
164 * Construct startup info.
165 */
166 STARTUPINFOW StartupInfo;
167 RT_ZERO(StartupInfo);
168 StartupInfo.cb = sizeof(StartupInfo);
169 StartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
170 StartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
171 StartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
172 StartupInfo.dwFlags = STARTF_USESTDHANDLES;
173#ifndef DEBUG
174 StartupInfo.dwFlags |= STARTF_USESHOWWINDOW;
175 StartupInfo.wShowWindow = SW_HIDE;
176#endif
177
178 /*
179 * Start it.
180 */
181 UINT rcWin;
182 PROCESS_INFORMATION ChildInfo = { NULL, NULL, 0, 0 };
183 if (CreateProcessW(pwszImage, pwszCmdLine, NULL /*pProcessAttribs*/, NULL /*pThreadAttribs*/, TRUE /*fInheritHandles*/,
184 0 /*fFlags*/, NULL /*pwszEnv*/, NULL /*pwszCwd*/, &StartupInfo, &ChildInfo))
185 {
186 logStringF(hModule, L"procRun: Info: Started process %u: %s", ChildInfo.dwProcessId, pwszCmdLine);
187 CloseHandle(ChildInfo.hThread);
188 DWORD const dwWait = WaitForSingleObject(ChildInfo.hProcess, RT_MS_30SEC);
189 DWORD dwExitCode = 0xf00dface;
190 if (GetExitCodeProcess(ChildInfo.hProcess, &dwExitCode))
191 {
192 if (dwExitCode == 0)
193 {
194 logStringF(hModule, L"procRun: Info: Process '%s' terminated exit code zero", pwszCmdLine);
195 rcWin = ERROR_SUCCESS;
196 }
197 else
198 {
199 logStringF(hModule, L"procRun: Process '%s' terminated with non-zero exit code: %u (%#x)",
200 pwszCmdLine, dwExitCode, dwExitCode);
201 rcWin = ERROR_GEN_FAILURE;
202 }
203 }
204 else
205 {
206 rcWin = GetLastError();
207 logStringF(hModule, L"procRun: Process '%s' is probably still running: rcWin=%u dwWait=%u (%#x)",
208 pwszCmdLine, rcWin, dwWait, dwWait);
209 }
210 }
211 else
212 {
213 rcWin = GetLastError();
214 logStringF(hModule, L"procRun: Creating process '%s' failed: rcWin=%u\n", pwszCmdLine, rcWin);
215 }
216 return rcWin;
217}
218
219/**
220 * Tries to retrieve the Python installation path on the system, extended version.
221 *
222 * @returns Windows error code.
223 * @param hModule Windows installer module handle.
224 * @param hKeyRoot Registry root key to use, e.g. HKEY_LOCAL_MACHINE.
225 * @param pwszPythonPath Buffer to return the path for python.exe in.
226 * @param cwcPythonPath Buffer size in UTF-16 units.
227 * @param fReturnExe Return the path to python.exe if true, otherwise
228 * just the python install directory.
229 */
230static UINT getPythonPathEx(MSIHANDLE hModule, HKEY hKeyRoot, wchar_t *pwszPythonPath, size_t cwcPythonPath, bool fReturnExe)
231{
232 *pwszPythonPath = '\0';
233
234 /*
235 * Enumerate the subkeys of python core installation key.
236 *
237 * Note: The loop ASSUMES that later found versions are higher, e.g. newer
238 * Python versions. For now we always go by the newest version.
239 */
240 HKEY hKeyPythonCore = NULL;
241 LSTATUS dwErr = RegOpenKeyExW(hKeyRoot, L"SOFTWARE\\Python\\PythonCore", 0, KEY_READ, &hKeyPythonCore);
242 if (dwErr != ERROR_SUCCESS)
243 return dwErr;
244
245 UINT rcWinRet = ERROR_PATH_NOT_FOUND;
246 for (DWORD i = 0; i < 16384; ++i)
247 {
248 static wchar_t const s_wszInstallPath[] = L"\\InstallPath";
249 static wchar_t const s_wszPythonExe[] = L"python.exe";
250
251 /* Get key name: */
252 wchar_t wszBuf[RTPATH_MAX + RT_MAX(RT_ELEMENTS(s_wszInstallPath), RT_ELEMENTS(s_wszPythonExe)) + 2];
253 DWORD cwcKeyNm = RTPATH_MAX;
254 DWORD dwKeyType = REG_SZ;
255 dwErr = RegEnumKeyExW(hKeyPythonCore, i, wszBuf, &cwcKeyNm, NULL, NULL, NULL, NULL);
256 if (dwErr == ERROR_NO_MORE_ITEMS)
257 break;
258 if (dwErr != ERROR_SUCCESS)
259 continue;
260 if (dwKeyType != REG_SZ)
261 continue;
262 if (cwcKeyNm == 0)
263 continue;
264 NonStandardAssert(cwcKeyNm <= sizeof(wszBuf));
265
266 /* Try Open the InstallPath subkey: */
267 memcpy(&wszBuf[cwcKeyNm], s_wszInstallPath, sizeof(s_wszInstallPath));
268
269 HKEY hKeyInstallPath = NULL;
270 dwErr = RegOpenKeyExW(hKeyPythonCore, wszBuf, 0, KEY_READ, &hKeyInstallPath);
271 if (dwErr != ERROR_SUCCESS)
272 continue;
273
274 /* Query the value. We double buffer this so we don't overwrite an okay
275 return value with this. Use the smaller of cwcPythonPath and wszValue
276 so RegQueryValueExW can do all the buffer overflow checking for us.
277 For paranoid reasons, we reserve a space for a terminator as well as
278 a slash. (ASSUMES reasonably sized output buffer.) */
279 NonStandardAssert(cwcPythonPath > RT_ELEMENTS(s_wszPythonExe) + 16);
280 DWORD cbValue = (DWORD)RT_MIN( cwcPythonPath * sizeof(wchar_t)
281 - (fReturnExe ? sizeof(s_wszInstallPath) - sizeof(wchar_t) * 2 : sizeof(wchar_t) * 2),
282 RTPATH_MAX * sizeof(wchar_t));
283 DWORD dwValueType = REG_SZ;
284 dwErr = RegQueryValueExW(hKeyInstallPath, L"", NULL, &dwValueType, (LPBYTE)wszBuf, &cbValue);
285 RegCloseKey(hKeyInstallPath);
286 if ( dwErr == ERROR_SUCCESS
287 && dwValueType == REG_SZ
288 && cbValue >= sizeof(L"C:\\") - sizeof(L""))
289 {
290 /* Find length in wchar_t unit w/o terminator: */
291 DWORD cwc = cbValue / sizeof(wchar_t);
292 while (cwc > 0 && wszBuf[cwc - 1] == '\0')
293 cwc--;
294 wszBuf[cwc] = '\0';
295 if (cwc > 2)
296 {
297 /* Check if the path leads to a directory with a python.exe file in it. */
298 if (!RTPATH_IS_SLASH(wszBuf[cwc - 1]))
299 wszBuf[cwc++] = '\\';
300 memcpy(&wszBuf[cwc], s_wszPythonExe, sizeof(s_wszPythonExe));
301 DWORD const fAttribs = GetFileAttributesW(wszBuf);
302 if (fAttribs != INVALID_FILE_ATTRIBUTES)
303 {
304 if (!(fAttribs & FILE_ATTRIBUTE_DIRECTORY))
305 {
306 /* Okay, we found something that can be returned. */
307 if (fReturnExe)
308 cwc += RT_ELEMENTS(s_wszPythonExe) - 1;
309 wszBuf[cwc] = '\0';
310 logStringF(hModule, L"getPythonPath: Found: \"%s\"", wszBuf);
311
312 NonStandardAssert(cwcPythonPath > cwc);
313 memcpy(pwszPythonPath, wszBuf, cwc * sizeof(wchar_t));
314 pwszPythonPath[cwc] = '\0';
315 rcWinRet = ERROR_SUCCESS;
316 }
317 else
318 logStringF(hModule, L"getPythonPath: Warning: Skipping \"%s\": is a directory (%#x)", wszBuf, fAttribs);
319 }
320 else
321 logStringF(hModule, L"getPythonPath: Warning: Skipping \"%s\": Does not exist (%u)", wszBuf, GetLastError());
322 }
323 }
324 }
325
326 RegCloseKey(hKeyPythonCore);
327 if (rcWinRet != ERROR_SUCCESS)
328 logStringF(hModule, L"getPythonPath: Unable to find python");
329 return rcWinRet;
330}
331
332/**
333 * Retrieves the absolute path of the Python installation.
334 *
335 * @returns Windows error code.
336 * @param hModule Windows installer module handle.
337 * @param pwszPythonPath Buffer to return the path for python.exe in.
338 * @param cwcPythonPath Buffer size in UTF-16 units.
339 * @param fReturnExe Return the path to python.exe if true, otherwise
340 * just the python install directory.
341 */
342static UINT getPythonPath(MSIHANDLE hModule, wchar_t *pwszPythonPath, size_t cwcPythonPath, bool fReturnExe = false)
343{
344 UINT rcWin = getPythonPathEx(hModule, HKEY_LOCAL_MACHINE, pwszPythonPath, cwcPythonPath, fReturnExe);
345 if (rcWin != ERROR_SUCCESS)
346 rcWin = getPythonPathEx(hModule, HKEY_CURRENT_USER, pwszPythonPath, cwcPythonPath, fReturnExe);
347 return rcWin;
348}
349
350/**
351 * Retrieves the absolute path of the Python executable.
352 *
353 * @returns Windows error code.
354 * @param hModule Windows installer module handle.
355 * @param pwszPythonExe Buffer to return the path for python.exe in.
356 * @param cwcPythonExe Buffer size in UTF-16 units.
357 */
358static UINT getPythonExe(MSIHANDLE hModule, wchar_t *pwszPythonExe, size_t cwcPythonExe)
359{
360 return getPythonPath(hModule, pwszPythonExe, cwcPythonExe, true /*fReturnExe*/);
361}
362
363/**
364 * Checks if all dependencies for running the VBox Python API bindings are met.
365 *
366 * @returns VBox status code, or error if depedencies are not met.
367 * @param hModule Windows installer module handle.
368 * @param pwszPythonExe Path to Python interpreter image (.exe).
369 */
370static int checkPythonDependencies(MSIHANDLE hModule, const wchar_t *pwszPythonExe)
371{
372 /*
373 * Check if importing the win32api module works.
374 * This is a prerequisite for setting up the VBox API.
375 */
376 logStringF(hModule, L"checkPythonDependencies: Checking for win32api extensions ...");
377
378 UINT rcWin = procRun(hModule, pwszPythonExe, L"-c \"import win32api\"");
379 if (rcWin == ERROR_SUCCESS)
380 logStringF(hModule, L"checkPythonDependencies: win32api found\n");
381 else
382 logStringF(hModule, L"checkPythonDependencies: Importing win32api failed with %u (%#x)\n", rcWin, rcWin);
383
384 return rcWin;
385}
386
387/**
388 * Checks for a valid Python installation on the system.
389 *
390 * Called from the MSI installer as custom action.
391 *
392 * @returns Always ERROR_SUCCESS.
393 * Sets public property VBOX_PYTHON_INSTALLED to "0" (false) or "1" (success).
394 * Sets public property VBOX_PYTHON_PATH to the Python installation path (if found).
395 *
396 * @param hModule Windows installer module handle.
397 */
398UINT __stdcall IsPythonInstalled(MSIHANDLE hModule)
399{
400 wchar_t wszPythonPath[RTPATH_MAX];
401 UINT rcWin = getPythonPath(hModule, wszPythonPath, RTPATH_MAX);
402 if (rcWin == ERROR_SUCCESS)
403 {
404 logStringF(hModule, L"IsPythonInstalled: Python installation found at \"%s\"", wszPythonPath);
405 VBoxSetMsiProp(hModule, L"VBOX_PYTHON_PATH", wszPythonPath);
406 VBoxSetMsiProp(hModule, L"VBOX_PYTHON_INSTALLED", L"1");
407 }
408 else
409 {
410 logStringF(hModule, L"IsPythonInstalled: Error: No suitable Python installation found (%u), skipping installation.", rcWin);
411 logStringF(hModule, L"IsPythonInstalled: Python seems not to be installed; please download + install the Python Core package.");
412 VBoxSetMsiProp(hModule, L"VBOX_PYTHON_INSTALLED", L"0");
413 }
414
415 return ERROR_SUCCESS; /* Never return failure. */
416}
417
418/**
419 * Checks if all dependencies for running the VBox Python API bindings are met.
420 *
421 * Called from the MSI installer as custom action.
422 *
423 * @returns Always ERROR_SUCCESS.
424 * Sets public property VBOX_PYTHON_DEPS_INSTALLED to "0" (false) or "1" (success).
425 *
426 * @param hModule Windows installer module handle.
427 */
428UINT __stdcall ArePythonAPIDepsInstalled(MSIHANDLE hModule)
429{
430 wchar_t wszPythonExe[RTPATH_MAX];
431 UINT dwErr = getPythonExe(hModule, wszPythonExe, RTPATH_MAX);
432 if (dwErr == ERROR_SUCCESS)
433 {
434 dwErr = checkPythonDependencies(hModule, wszPythonExe);
435 if (dwErr == ERROR_SUCCESS)
436 logStringF(hModule, L"ArePythonAPIDepsInstalled: Dependencies look good.");
437 }
438
439 if (dwErr != ERROR_SUCCESS)
440 logStringF(hModule, L"ArePythonAPIDepsInstalled: Failed with dwErr=%u", dwErr);
441
442 VBoxSetMsiProp(hModule, L"VBOX_PYTHON_DEPS_INSTALLED", dwErr == ERROR_SUCCESS ? L"1" : L"0");
443 return ERROR_SUCCESS; /* Never return failure. */
444}
445
446/**
447 * Checks if all required MS CRTs (Visual Studio Redistributable Package) are installed on the system.
448 *
449 * Called from the MSI installer as custom action.
450 *
451 * @returns Always ERROR_SUCCESS.
452 * Sets public property VBOX_MSCRT_INSTALLED to "" (false, to use "NOT" in WiX) or "1" (success).
453 *
454 * Also exposes public properties VBOX_MSCRT_VER_MIN + VBOX_MSCRT_VER_MAJ strings
455 * with the most recent MSCRT version detected.
456 *
457 * @param hModule Windows installer module handle.
458 *
459 * @sa https://docs.microsoft.com/en-us/cpp/windows/redistributing-visual-cpp-files?view=msvc-170
460 */
461UINT __stdcall IsMSCRTInstalled(MSIHANDLE hModule)
462{
463 HKEY hKeyVS = NULL;
464 LSTATUS dwErr = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
465 L"SOFTWARE\\Microsoft\\VisualStudio\\14.0\\VC\\Runtimes\\X64",
466 0, KEY_READ, &hKeyVS);
467 if (dwErr == ERROR_SUCCESS)
468 {
469 DWORD dwVal = 0;
470 DWORD cbVal = sizeof(dwVal);
471 DWORD dwValueType = REG_DWORD;
472
473 dwErr = RegQueryValueExW(hKeyVS, L"Installed", NULL, &dwValueType, (LPBYTE)&dwVal, &cbVal);
474 if (dwErr == ERROR_SUCCESS)
475 {
476 if (dwVal >= 1)
477 {
478 DWORD dwMin, dwMaj;
479 dwErr = RegQueryValueExW(hKeyVS, L"Major", NULL, &dwValueType, (LPBYTE)&dwMaj, &cbVal);
480 if (dwErr == ERROR_SUCCESS)
481 {
482 VBoxSetMsiPropDWORD(hModule, L"VBOX_MSCRT_VER_MAJ", dwMaj);
483
484 dwErr = RegQueryValueExW(hKeyVS, L"Minor", NULL, &dwValueType, (LPBYTE)&dwMin, &cbVal);
485 if (dwErr == ERROR_SUCCESS)
486 {
487 VBoxSetMsiPropDWORD(hModule, L"VBOX_MSCRT_VER_MIN", dwMin);
488
489 logStringF(hModule, L"IsMSCRTInstalled: Found v%ld.%ld\n", dwMaj, dwMin);
490
491 /* Check for at least 2019. */
492 if (dwMaj >= 14 && dwMin >= 20)
493 VBoxSetMsiProp(hModule, L"VBOX_MSCRT_INSTALLED", L"1");
494 }
495 else
496 logStringF(hModule, L"IsMSCRTInstalled: Found, but 'Minor' key not present");
497 }
498 else
499 logStringF(hModule, L"IsMSCRTInstalled: Found, but 'Major' key not present");
500 }
501 else
502 {
503 logStringF(hModule, L"IsMSCRTInstalled: Found, but not marked as installed");
504 dwErr = ERROR_NOT_INSTALLED;
505 }
506 }
507 else
508 logStringF(hModule, L"IsMSCRTInstalled: Found, but 'Installed' key not present");
509 }
510
511 if (dwErr != ERROR_SUCCESS)
512 logStringF(hModule, L"IsMSCRTInstalled: Failed with dwErr=%ld", dwErr);
513
514 return ERROR_SUCCESS; /* Never return failure. */
515}
516
517/**
518 * Checks if the running OS is (at least) Windows 10 (e.g. >= build 10000).
519 *
520 * Called from the MSI installer as custom action.
521 *
522 * @returns Always ERROR_SUCCESS.
523 * Sets public property VBOX_IS_WINDOWS_10 to "" (empty / false) or "1" (success).
524 *
525 * @param hModule Windows installer module handle.
526 */
527UINT __stdcall IsWindows10(MSIHANDLE hModule)
528{
529 /*
530 * Note: We cannot use RtlGetVersion() / GetVersionExW() here, as the Windows Installer service
531 * all shims this, unfortunately. So we have to go another route by querying the major version
532 * number from the registry.
533 */
534 HKEY hKeyCurVer = NULL;
535 LSTATUS dwErr = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0, KEY_READ, &hKeyCurVer);
536 if (dwErr == ERROR_SUCCESS)
537 {
538 DWORD dwVal = 0;
539 DWORD cbVal = sizeof(dwVal);
540 DWORD dwValueType = REG_DWORD;
541 dwErr = RegQueryValueExW(hKeyCurVer, L"CurrentMajorVersionNumber", NULL, &dwValueType, (LPBYTE)&dwVal, &cbVal);
542 if (dwErr == ERROR_SUCCESS)
543 {
544 logStringF(hModule, L"IsWindows10/CurrentMajorVersionNumber: %ld", dwVal);
545
546 VBoxSetMsiProp(hModule, L"VBOX_IS_WINDOWS_10", dwVal >= 10 ? L"1" : L"");
547 }
548 else
549 logStringF(hModule, L"IsWindows10/RegOpenKeyExW: Error reading CurrentMajorVersionNumber (%ld)", dwErr);
550
551 RegCloseKey(hKeyCurVer);
552 }
553 else
554 logStringF(hModule, L"IsWindows10/RegOpenKeyExW: Error opening CurrentVersion key (%ld)", dwErr);
555
556 return ERROR_SUCCESS; /* Never return failure. */
557}
558
559/**
560 * Installs and compiles the VBox Python bindings.
561 *
562 * Called from the MSI installer as custom action.
563 *
564 * @returns Always ERROR_SUCCESS.
565 * Sets public property VBOX_API_INSTALLED to "0" (false) or "1" (success).
566 *
567 * @param hModule Windows installer module handle.
568 */
569UINT __stdcall InstallPythonAPI(MSIHANDLE hModule)
570{
571 logStringF(hModule, L"InstallPythonAPI: Checking for installed Python environment(s) ...");
572
573 /** @todo r=bird: Can't we get the VBOX_PYTHON_PATH property here? */
574 wchar_t wszPythonExe[RTPATH_MAX];
575 UINT rcWin = getPythonExe(hModule, wszPythonExe, RTPATH_MAX);
576 if (rcWin != ERROR_SUCCESS)
577 {
578 VBoxSetMsiProp(hModule, L"VBOX_API_INSTALLED", L"0");
579 return ERROR_SUCCESS;
580 }
581
582 /*
583 * Set up the VBox API.
584 */
585 /* Get the VBox API setup string. */
586 WCHAR wszVBoxSDKPath[RTPATH_MAX];
587 rcWin = VBoxGetMsiProp(hModule, L"CustomActionData", wszVBoxSDKPath, sizeof(wszVBoxSDKPath));
588 if (rcWin == ERROR_SUCCESS)
589 {
590 /* Make sure our current working directory is the VBox installation path. */
591 if (SetCurrentDirectoryW(wszVBoxSDKPath))
592 {
593 /* Set required environment variables. */
594 if (SetEnvironmentVariableW(L"VBOX_INSTALL_PATH", wszVBoxSDKPath))
595 {
596 logStringF(hModule, L"InstallPythonAPI: Invoking vboxapisetup.py in \"%s\" ...", wszVBoxSDKPath);
597
598 rcWin = procRun(hModule, wszPythonExe, L"vboxapisetup.py install");
599 if (rcWin == ERROR_SUCCESS)
600 {
601 logStringF(hModule, L"InstallPythonAPI: Installation of vboxapisetup.py successful");
602
603 /*
604 * Do some sanity checking if the VBox API works.
605 */
606 logStringF(hModule, L"InstallPythonAPI: Validating VBox API ...");
607
608 rcWin = procRun(hModule, wszPythonExe, L"-c \"from vboxapi import VirtualBoxManager\"");
609 if (rcWin == ERROR_SUCCESS)
610 {
611 logStringF(hModule, L"InstallPythonAPI: VBox API looks good.");
612 VBoxSetMsiProp(hModule, L"VBOX_API_INSTALLED", L"1");
613 return ERROR_SUCCESS;
614 }
615
616 /* failed */
617 logStringF(hModule, L"InstallPythonAPI: Validating VBox API failed with %u (%#x)", rcWin, rcWin);
618 }
619 else
620 logStringF(hModule, L"InstallPythonAPI: Calling vboxapisetup.py failed with %u (%#x)", rcWin, rcWin);
621 }
622 else
623 logStringF(hModule, L"InstallPythonAPI: Could set environment variable VBOX_INSTALL_PATH: LastError=%u",
624 GetLastError());
625 }
626 else
627 logStringF(hModule, L"InstallPythonAPI: Could set working directory to \"%s\": LastError=%u",
628 wszVBoxSDKPath, GetLastError());
629 }
630 else
631 logStringF(hModule, L"InstallPythonAPI: Unable to retrieve VBox installation directory: rcWin=%u (%#x)", rcWin, rcWin);
632
633 VBoxSetMsiProp(hModule, L"VBOX_API_INSTALLED", L"0");
634 logStringF(hModule, L"InstallPythonAPI: Installation failed");
635 return ERROR_SUCCESS; /* Do not fail here. */
636}
637
638static LONG installBrandingValue(MSIHANDLE hModule,
639 const WCHAR *pwszFileName,
640 const WCHAR *pwszSection,
641 const WCHAR *pwszValue)
642{
643 LONG rc;
644 WCHAR wszValue[_MAX_PATH];
645 if (GetPrivateProfileStringW(pwszSection, pwszValue, NULL, wszValue, sizeof(wszValue), pwszFileName) > 0)
646 {
647 WCHAR wszKey[_MAX_PATH + 64];
648 if (wcsicmp(L"General", pwszSection) != 0)
649 swprintf_s(wszKey, RT_ELEMENTS(wszKey), L"SOFTWARE\\%S\\VirtualBox\\Branding\\%s", VBOX_VENDOR_SHORT, pwszSection);
650 else
651 swprintf_s(wszKey, RT_ELEMENTS(wszKey), L"SOFTWARE\\%S\\VirtualBox\\Branding", VBOX_VENDOR_SHORT);
652
653 HKEY hkBranding = NULL;
654 rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszKey, 0, KEY_WRITE, &hkBranding);
655 if (rc == ERROR_SUCCESS)
656 {
657 rc = RegSetValueExW(hkBranding,
658 pwszValue,
659 NULL,
660 REG_SZ,
661 (BYTE *)wszValue,
662 (DWORD)wcslen(wszValue));
663 if (rc != ERROR_SUCCESS)
664 logStringF(hModule, L"InstallBranding: Could not write value %s! Error %d", pwszValue, rc);
665 RegCloseKey(hkBranding);
666 }
667 }
668 else
669 rc = ERROR_NOT_FOUND;
670 return rc;
671}
672
673/**
674 * @note Both paths strings must have an extra terminator.
675 */
676static UINT CopyDir(MSIHANDLE hModule, const WCHAR *pwszzDstDir, const WCHAR *pwszzSrcDir)
677{
678 NonStandardAssert(pwszzDstDir[wcslen(pwszzDstDir) + 1] == '\0');
679 NonStandardAssert(pwszzSrcDir[wcslen(pwszzSrcDir) + 1] == '\0');
680
681 SHFILEOPSTRUCTW s = {0};
682 s.hwnd = NULL;
683 s.wFunc = FO_COPY;
684 s.pTo = pwszzDstDir;
685 s.pFrom = pwszzSrcDir;
686 s.fFlags = FOF_SILENT
687 | FOF_NOCONFIRMATION
688 | FOF_NOCONFIRMMKDIR
689 | FOF_NOERRORUI;
690
691 logStringF(hModule, L"CopyDir: pwszzDstDir=%s, pwszzSrcDir=%s", pwszzDstDir, pwszzSrcDir);
692 int r = SHFileOperationW(&s);
693 if (r == 0)
694 return ERROR_SUCCESS;
695 logStringF(hModule, L"CopyDir: Copy operation returned status %#x", r);
696 return ERROR_GEN_FAILURE;
697}
698
699/**
700 * @note The directory string must have two zero terminators!
701 */
702static UINT RemoveDir(MSIHANDLE hModule, const WCHAR *pwszzDstDir)
703{
704 NonStandardAssert(pwszzDstDir[wcslen(pwszzDstDir) + 1] == '\0');
705
706 SHFILEOPSTRUCTW s = {0};
707 s.hwnd = NULL;
708 s.wFunc = FO_DELETE;
709 s.pFrom = pwszzDstDir;
710 s.fFlags = FOF_SILENT
711 | FOF_NOCONFIRMATION
712 | FOF_NOCONFIRMMKDIR
713 | FOF_NOERRORUI;
714
715 logStringF(hModule, L"RemoveDir: pwszzDstDir=%s", pwszzDstDir);
716 int r = SHFileOperationW(&s);
717 if (r == 0)
718 return ERROR_SUCCESS;
719 logStringF(hModule, L"RemoveDir: Remove operation returned status %#x", r);
720 return ERROR_GEN_FAILURE;
721}
722
723/**
724 * @note Both paths strings must have an extra terminator.
725 */
726static UINT RenameDir(MSIHANDLE hModule, const WCHAR *pwszzDstDir, const WCHAR *pwszzSrcDir)
727{
728 NonStandardAssert(pwszzDstDir[wcslen(pwszzDstDir) + 1] == '\0');
729 NonStandardAssert(pwszzSrcDir[wcslen(pwszzSrcDir) + 1] == '\0');
730
731 SHFILEOPSTRUCTW s = {0};
732 s.hwnd = NULL;
733 s.wFunc = FO_RENAME;
734 s.pTo = pwszzDstDir;
735 s.pFrom = pwszzSrcDir;
736 s.fFlags = FOF_SILENT
737 | FOF_NOCONFIRMATION
738 | FOF_NOCONFIRMMKDIR
739 | FOF_NOERRORUI;
740
741 logStringF(hModule, L"RenameDir: pwszzDstDir=%s, pwszzSrcDir=%s", pwszzDstDir, pwszzSrcDir);
742 int r = SHFileOperationW(&s);
743 if (r == 0)
744 return ERROR_SUCCESS;
745 logStringF(hModule, L"RenameDir: Rename operation returned status %#x", r);
746 return ERROR_GEN_FAILURE;
747}
748
749/** RTPathAppend-like function. */
750static UINT AppendToPath(wchar_t *pwszPath, size_t cwcPath, wchar_t *pwszAppend, bool fDoubleTerm = false)
751{
752 size_t cwcCurPath = wcslen(pwszPath);
753 size_t cwcSlash = cwcCurPath > 1 && RTPATH_IS_SLASH(pwszPath[cwcCurPath - 1]) ? 0 : 1;
754 while (RTPATH_IS_SLASH(*pwszAppend))
755 pwszAppend++;
756 size_t cwcAppend = wcslen(pwszAppend);
757 if (cwcCurPath + cwcCurPath + cwcAppend + fDoubleTerm < cwcPath)
758 {
759 if (cwcSlash)
760 pwszPath[cwcCurPath++] = '\\';
761 memcpy(&pwszPath[cwcCurPath], pwszAppend, (cwcAppend + 1) * sizeof(wchar_t));
762 if (fDoubleTerm)
763 pwszPath[cwcCurPath + cwcAppend + 1] = '\0';
764 return ERROR_SUCCESS;
765 }
766 return ERROR_BUFFER_OVERFLOW;
767}
768
769/** RTPathJoin-like function. */
770static UINT JoinPaths(wchar_t *pwszPath, size_t cwcPath, wchar_t *pwszPath1, wchar_t *pwszAppend, bool fDoubleTerm = false)
771{
772 size_t cwcCurPath = wcslen(pwszPath1);
773 if (cwcCurPath < cwcPath)
774 {
775 memcpy(pwszPath, pwszPath1, (cwcCurPath + 1) * sizeof(wchar_t));
776 return AppendToPath(pwszPath, cwcPath, pwszAppend, fDoubleTerm);
777 }
778 return ERROR_BUFFER_OVERFLOW;
779}
780
781UINT __stdcall UninstallBranding(MSIHANDLE hModule)
782{
783 logStringF(hModule, L"UninstallBranding: Handling branding file ...");
784
785 WCHAR wszPath[RTPATH_MAX];
786 UINT rc = VBoxGetMsiProp(hModule, L"CustomActionData", wszPath, sizeof(wszPath));
787 if (rc == ERROR_SUCCESS)
788 {
789 size_t const cwcPath = wcslen(wszPath);
790 rc = AppendToPath(wszPath, RTPATH_MAX, L"custom", true /*fDoubleTerm*/);
791 if (rc == ERROR_SUCCESS)
792 rc = RemoveDir(hModule, wszPath);
793
794 /* Check for .custom directory from a failed install and remove it. */
795 wszPath[cwcPath] = '\0';
796 rc = AppendToPath(wszPath, RTPATH_MAX, L".custom", true /*fDoubleTerm*/);
797 if (rc == ERROR_SUCCESS)
798 rc = RemoveDir(hModule, wszPath);
799 }
800
801 logStringF(hModule, L"UninstallBranding: Handling done. (rc=%u (ignored))", rc);
802 return ERROR_SUCCESS; /* Do not fail here. */
803}
804
805UINT __stdcall InstallBranding(MSIHANDLE hModule)
806{
807 logStringF(hModule, L"InstallBranding: Handling branding file ...");
808
809 /*
810 * Get the paths.
811 */
812 wchar_t wszSrcPath[RTPATH_MAX];
813 UINT rc = VBoxGetMsiProp(hModule, L"SOURCEDIR", wszSrcPath, RT_ELEMENTS(wszSrcPath));
814 if (rc == ERROR_SUCCESS)
815 {
816 wchar_t wszDstPath[RTPATH_MAX];
817 rc = VBoxGetMsiProp(hModule, L"CustomActionData", wszDstPath, RT_ELEMENTS(wszDstPath) - 1);
818 if (rc == ERROR_SUCCESS)
819 {
820 /*
821 * First we copy the src\.custom dir to the target.
822 */
823 rc = AppendToPath(wszSrcPath, RT_ELEMENTS(wszSrcPath) - 1, L".custom", true /*fDoubleTerm*/);
824 if (rc == ERROR_SUCCESS)
825 {
826 rc = CopyDir(hModule, wszDstPath, wszSrcPath);
827 if (rc == ERROR_SUCCESS)
828 {
829 /*
830 * The rename the '.custom' directory we now got in the target area to 'custom'.
831 */
832 rc = JoinPaths(wszSrcPath, RT_ELEMENTS(wszSrcPath), wszDstPath, L".custom", true /*fDoubleTerm*/);
833 if (rc == ERROR_SUCCESS)
834 {
835 rc = AppendToPath(wszDstPath, RT_ELEMENTS(wszDstPath), L"custom", true /*fDoubleTerm*/);
836 if (rc == ERROR_SUCCESS)
837 rc = RenameDir(hModule, wszDstPath, wszSrcPath);
838 }
839 }
840 }
841 }
842 }
843
844 logStringF(hModule, L"InstallBranding: Handling done. (rc=%u (ignored))", rc);
845 return ERROR_SUCCESS; /* Do not fail here. */
846}
847
848#ifdef VBOX_WITH_NETFLT
849
850/** @todo should use some real VBox app name */
851#define VBOX_NETCFG_APP_NAME L"VirtualBox Installer"
852#define VBOX_NETCFG_MAX_RETRIES 10
853#define NETFLT_PT_INF_REL_PATH L"VBoxNetFlt.inf"
854#define NETFLT_MP_INF_REL_PATH L"VBoxNetFltM.inf"
855#define NETFLT_ID L"sun_VBoxNetFlt" /** @todo Needs to be changed (?). */
856#define NETADP_ID L"sun_VBoxNetAdp" /** @todo Needs to be changed (?). */
857
858#define NETLWF_INF_NAME L"VBoxNetLwf.inf"
859
860static MSIHANDLE g_hCurrentModule = NULL;
861
862static UINT _uninstallNetFlt(MSIHANDLE hModule);
863static UINT _uninstallNetLwf(MSIHANDLE hModule);
864
865static VOID vboxDrvLoggerCallback(VBOXDRVCFG_LOG_SEVERITY enmSeverity, char *pszMsg, void *pvContext)
866{
867 RT_NOREF1(pvContext);
868 switch (enmSeverity)
869 {
870 case VBOXDRVCFG_LOG_SEVERITY_FLOW:
871 case VBOXDRVCFG_LOG_SEVERITY_REGULAR:
872 break;
873 case VBOXDRVCFG_LOG_SEVERITY_REL:
874 if (g_hCurrentModule)
875 logStringF(g_hCurrentModule, L"%S", pszMsg);
876 break;
877 default:
878 break;
879 }
880}
881
882static DECLCALLBACK(void) netCfgLoggerCallback(const char *pszString)
883{
884 if (g_hCurrentModule)
885 logStringF(g_hCurrentModule, L"%S", pszString);
886}
887
888static VOID netCfgLoggerDisable()
889{
890 if (g_hCurrentModule)
891 {
892 VBoxNetCfgWinSetLogging(NULL);
893 g_hCurrentModule = NULL;
894 }
895}
896
897static VOID netCfgLoggerEnable(MSIHANDLE hModule)
898{
899 NonStandardAssert(hModule);
900
901 if (g_hCurrentModule)
902 netCfgLoggerDisable();
903
904 g_hCurrentModule = hModule;
905
906 VBoxNetCfgWinSetLogging(netCfgLoggerCallback);
907 /* uncomment next line if you want to add logging information from VBoxDrvCfg.cpp */
908// VBoxDrvCfgLoggerSet(vboxDrvLoggerCallback, NULL);
909}
910
911static UINT errorConvertFromHResult(MSIHANDLE hModule, HRESULT hr)
912{
913 UINT uRet;
914 switch (hr)
915 {
916 case S_OK:
917 uRet = ERROR_SUCCESS;
918 break;
919
920 case NETCFG_S_REBOOT:
921 {
922 logStringF(hModule, L"Reboot required, setting REBOOT property to \"force\"");
923 HRESULT hr2 = MsiSetPropertyW(hModule, L"REBOOT", L"Force");
924 if (hr2 != ERROR_SUCCESS)
925 logStringF(hModule, L"Failed to set REBOOT property, error = %#x", hr2);
926 uRet = ERROR_SUCCESS; /* Never fail here. */
927 break;
928 }
929
930 default:
931 logStringF(hModule, L"Converting unhandled HRESULT (%#x) to ERROR_GEN_FAILURE", hr);
932 uRet = ERROR_GEN_FAILURE;
933 }
934 return uRet;
935}
936
937static MSIHANDLE createNetCfgLockedMsgRecord(MSIHANDLE hModule)
938{
939 MSIHANDLE hRecord = MsiCreateRecord(2);
940 if (hRecord)
941 {
942 UINT uErr = MsiRecordSetInteger(hRecord, 1, 25001);
943 if (uErr != ERROR_SUCCESS)
944 {
945 logStringF(hModule, L"createNetCfgLockedMsgRecord: MsiRecordSetInteger failed, error = %#x", uErr);
946 MsiCloseHandle(hRecord);
947 hRecord = NULL;
948 }
949 }
950 else
951 logStringF(hModule, L"createNetCfgLockedMsgRecord: Failed to create a record");
952
953 return hRecord;
954}
955
956static UINT doNetCfgInit(MSIHANDLE hModule, INetCfg **ppnc, BOOL bWrite)
957{
958 MSIHANDLE hMsg = NULL;
959 UINT uErr = ERROR_GEN_FAILURE;
960 int MsgResult;
961 int cRetries = 0;
962
963 do
964 {
965 LPWSTR lpszLockedBy;
966 HRESULT hr = VBoxNetCfgWinQueryINetCfg(ppnc, bWrite, VBOX_NETCFG_APP_NAME, 10000, &lpszLockedBy);
967 if (hr != NETCFG_E_NO_WRITE_LOCK)
968 {
969 if (FAILED(hr))
970 logStringF(hModule, L"doNetCfgInit: VBoxNetCfgWinQueryINetCfg failed, error = %#x", hr);
971 uErr = errorConvertFromHResult(hModule, hr);
972 break;
973 }
974
975 /* hr == NETCFG_E_NO_WRITE_LOCK */
976
977 if (!lpszLockedBy)
978 {
979 logStringF(hModule, L"doNetCfgInit: lpszLockedBy == NULL, breaking");
980 break;
981 }
982
983 /* on vista the 6to4svc.dll periodically maintains the lock for some reason,
984 * if this is the case, increase the wait period by retrying multiple times
985 * NOTE: we could alternatively increase the wait timeout,
986 * however it seems unneeded for most cases, e.g. in case some network connection property
987 * dialog is opened, it would be better to post a notification to the user as soon as possible
988 * rather than waiting for a longer period of time before displaying it */
989 if ( cRetries < VBOX_NETCFG_MAX_RETRIES
990 && !wcscmp(lpszLockedBy, L"6to4svc.dll"))
991 {
992 cRetries++;
993 logStringF(hModule, L"doNetCfgInit: lpszLockedBy is 6to4svc.dll, retrying %d out of %d", cRetries, VBOX_NETCFG_MAX_RETRIES);
994 MsgResult = IDRETRY;
995 }
996 else
997 {
998 if (!hMsg)
999 {
1000 hMsg = createNetCfgLockedMsgRecord(hModule);
1001 if (!hMsg)
1002 {
1003 logStringF(hModule, L"doNetCfgInit: Failed to create a message record, breaking");
1004 CoTaskMemFree(lpszLockedBy);
1005 break;
1006 }
1007 }
1008
1009 UINT rTmp = MsiRecordSetStringW(hMsg, 2, lpszLockedBy);
1010 NonStandardAssert(rTmp == ERROR_SUCCESS);
1011 if (rTmp != ERROR_SUCCESS)
1012 {
1013 logStringF(hModule, L"doNetCfgInit: MsiRecordSetStringW failed, error = #%x", rTmp);
1014 CoTaskMemFree(lpszLockedBy);
1015 break;
1016 }
1017
1018 MsgResult = MsiProcessMessage(hModule, (INSTALLMESSAGE)(INSTALLMESSAGE_USER | MB_RETRYCANCEL), hMsg);
1019 NonStandardAssert(MsgResult == IDRETRY || MsgResult == IDCANCEL);
1020 logStringF(hModule, L"doNetCfgInit: MsiProcessMessage returned (%#x)", MsgResult);
1021 }
1022 CoTaskMemFree(lpszLockedBy);
1023 } while(MsgResult == IDRETRY);
1024
1025 if (hMsg)
1026 MsiCloseHandle(hMsg);
1027
1028 return uErr;
1029}
1030
1031static UINT vboxNetFltQueryInfArray(MSIHANDLE hModule, OUT LPWSTR pwszPtInf, OUT LPWSTR pwszMpInf, DWORD dwSize)
1032{
1033 DWORD dwBuf = dwSize - RT_MAX(sizeof(NETFLT_PT_INF_REL_PATH), sizeof(NETFLT_MP_INF_REL_PATH));
1034 UINT uErr = MsiGetPropertyW(hModule, L"CustomActionData", pwszPtInf, &dwBuf);
1035 if ( uErr == ERROR_SUCCESS
1036 && dwBuf)
1037 {
1038 wcscpy(pwszMpInf, pwszPtInf);
1039
1040 wcsncat(pwszPtInf, NETFLT_PT_INF_REL_PATH, sizeof(NETFLT_PT_INF_REL_PATH));
1041 logStringF(hModule, L"vboxNetFltQueryInfArray: INF 1: %s", pwszPtInf);
1042
1043 wcsncat(pwszMpInf, NETFLT_MP_INF_REL_PATH, sizeof(NETFLT_MP_INF_REL_PATH));
1044 logStringF(hModule, L"vboxNetFltQueryInfArray: INF 2: %s", pwszMpInf);
1045 }
1046 else if (uErr != ERROR_SUCCESS)
1047 logStringF(hModule, L"vboxNetFltQueryInfArray: MsiGetPropertyW failed, error = %#x", uErr);
1048 else
1049 {
1050 logStringF(hModule, L"vboxNetFltQueryInfArray: Empty installation directory");
1051 uErr = ERROR_GEN_FAILURE;
1052 }
1053
1054 return uErr;
1055}
1056
1057#endif /*VBOX_WITH_NETFLT*/
1058
1059/*static*/ UINT _uninstallNetFlt(MSIHANDLE hModule)
1060{
1061#ifdef VBOX_WITH_NETFLT
1062 INetCfg *pNetCfg;
1063 UINT uErr;
1064
1065 netCfgLoggerEnable(hModule);
1066
1067 BOOL bOldIntMode = SetupSetNonInteractiveMode(FALSE);
1068
1069 __try
1070 {
1071 logStringF(hModule, L"Uninstalling NetFlt");
1072
1073 uErr = doNetCfgInit(hModule, &pNetCfg, TRUE);
1074 if (uErr == ERROR_SUCCESS)
1075 {
1076 HRESULT hr = VBoxNetCfgWinNetFltUninstall(pNetCfg);
1077 if (hr != S_OK)
1078 logStringF(hModule, L"UninstallNetFlt: VBoxNetCfgWinUninstallComponent failed, error = %#x", hr);
1079
1080 uErr = errorConvertFromHResult(hModule, hr);
1081
1082 VBoxNetCfgWinReleaseINetCfg(pNetCfg, TRUE);
1083
1084 logStringF(hModule, L"Uninstalling NetFlt done, error = %#x", uErr);
1085 }
1086 else
1087 logStringF(hModule, L"UninstallNetFlt: doNetCfgInit failed, error = %#x", uErr);
1088 }
1089 __finally
1090 {
1091 if (bOldIntMode)
1092 {
1093 /* The prev mode != FALSE, i.e. non-interactive. */
1094 SetupSetNonInteractiveMode(bOldIntMode);
1095 }
1096 netCfgLoggerDisable();
1097 }
1098#endif /* VBOX_WITH_NETFLT */
1099
1100 /* Never fail the uninstall even if we did not succeed. */
1101 return ERROR_SUCCESS;
1102}
1103
1104UINT __stdcall UninstallNetFlt(MSIHANDLE hModule)
1105{
1106 (void)_uninstallNetLwf(hModule);
1107 return _uninstallNetFlt(hModule);
1108}
1109
1110static UINT _installNetFlt(MSIHANDLE hModule)
1111{
1112#ifdef VBOX_WITH_NETFLT
1113 UINT uErr;
1114 INetCfg *pNetCfg;
1115
1116 netCfgLoggerEnable(hModule);
1117
1118 BOOL bOldIntMode = SetupSetNonInteractiveMode(FALSE);
1119
1120 __try
1121 {
1122
1123 logStringF(hModule, L"InstallNetFlt: Installing NetFlt");
1124
1125 uErr = doNetCfgInit(hModule, &pNetCfg, TRUE);
1126 if (uErr == ERROR_SUCCESS)
1127 {
1128 WCHAR wszPtInf[MAX_PATH];
1129 WCHAR wszMpInf[MAX_PATH];
1130 uErr = vboxNetFltQueryInfArray(hModule, wszPtInf, wszMpInf, sizeof(wszMpInf));
1131 if (uErr == ERROR_SUCCESS)
1132 {
1133 LPCWSTR const apwszInfs[] = { wszPtInf, wszMpInf };
1134 HRESULT hr = VBoxNetCfgWinNetFltInstall(pNetCfg, &apwszInfs[0], RT_ELEMENTS(apwszInfs));
1135 if (FAILED(hr))
1136 logStringF(hModule, L"InstallNetFlt: VBoxNetCfgWinNetFltInstall failed, error = %#x", hr);
1137
1138 uErr = errorConvertFromHResult(hModule, hr);
1139 }
1140 else
1141 logStringF(hModule, L"InstallNetFlt: vboxNetFltQueryInfArray failed, error = %#x", uErr);
1142
1143 VBoxNetCfgWinReleaseINetCfg(pNetCfg, TRUE);
1144
1145 logStringF(hModule, L"InstallNetFlt: Done");
1146 }
1147 else
1148 logStringF(hModule, L"InstallNetFlt: doNetCfgInit failed, error = %#x", uErr);
1149 }
1150 __finally
1151 {
1152 if (bOldIntMode)
1153 {
1154 /* The prev mode != FALSE, i.e. non-interactive. */
1155 SetupSetNonInteractiveMode(bOldIntMode);
1156 }
1157 netCfgLoggerDisable();
1158 }
1159#endif /* VBOX_WITH_NETFLT */
1160
1161 /* Never fail the install even if we did not succeed. */
1162 return ERROR_SUCCESS;
1163}
1164
1165UINT __stdcall InstallNetFlt(MSIHANDLE hModule)
1166{
1167 (void)_uninstallNetLwf(hModule);
1168 return _installNetFlt(hModule);
1169}
1170
1171
1172/*static*/ UINT _uninstallNetLwf(MSIHANDLE hModule)
1173{
1174#ifdef VBOX_WITH_NETFLT
1175 INetCfg *pNetCfg;
1176 UINT uErr;
1177
1178 netCfgLoggerEnable(hModule);
1179
1180 BOOL bOldIntMode = SetupSetNonInteractiveMode(FALSE);
1181
1182 __try
1183 {
1184 logStringF(hModule, L"Uninstalling NetLwf");
1185
1186 uErr = doNetCfgInit(hModule, &pNetCfg, TRUE);
1187 if (uErr == ERROR_SUCCESS)
1188 {
1189 HRESULT hr = VBoxNetCfgWinNetLwfUninstall(pNetCfg);
1190 if (hr != S_OK)
1191 logStringF(hModule, L"UninstallNetLwf: VBoxNetCfgWinUninstallComponent failed, error = %#x", hr);
1192
1193 uErr = errorConvertFromHResult(hModule, hr);
1194
1195 VBoxNetCfgWinReleaseINetCfg(pNetCfg, TRUE);
1196
1197 logStringF(hModule, L"Uninstalling NetLwf done, error = %#x", uErr);
1198 }
1199 else
1200 logStringF(hModule, L"UninstallNetLwf: doNetCfgInit failed, error = %#x", uErr);
1201 }
1202 __finally
1203 {
1204 if (bOldIntMode)
1205 {
1206 /* The prev mode != FALSE, i.e. non-interactive. */
1207 SetupSetNonInteractiveMode(bOldIntMode);
1208 }
1209 netCfgLoggerDisable();
1210 }
1211#endif /* VBOX_WITH_NETFLT */
1212
1213 /* Never fail the uninstall even if we did not succeed. */
1214 return ERROR_SUCCESS;
1215}
1216
1217UINT __stdcall UninstallNetLwf(MSIHANDLE hModule)
1218{
1219 (void)_uninstallNetFlt(hModule);
1220 return _uninstallNetLwf(hModule);
1221}
1222
1223static UINT _installNetLwf(MSIHANDLE hModule)
1224{
1225#ifdef VBOX_WITH_NETFLT
1226 UINT uErr;
1227 INetCfg *pNetCfg;
1228
1229 netCfgLoggerEnable(hModule);
1230
1231 BOOL bOldIntMode = SetupSetNonInteractiveMode(FALSE);
1232
1233 __try
1234 {
1235
1236 logStringF(hModule, L"InstallNetLwf: Installing NetLwf");
1237
1238 uErr = doNetCfgInit(hModule, &pNetCfg, TRUE);
1239 if (uErr == ERROR_SUCCESS)
1240 {
1241 WCHAR wszInf[MAX_PATH];
1242 DWORD cwcInf = RT_ELEMENTS(wszInf) - sizeof(NETLWF_INF_NAME) - 1;
1243 uErr = MsiGetPropertyW(hModule, L"CustomActionData", wszInf, &cwcInf);
1244 if (uErr == ERROR_SUCCESS)
1245 {
1246 if (cwcInf)
1247 {
1248 if (wszInf[cwcInf - 1] != L'\\')
1249 {
1250 wszInf[cwcInf++] = L'\\';
1251 wszInf[cwcInf] = L'\0';
1252 }
1253
1254 wcscat(wszInf, NETLWF_INF_NAME);
1255
1256 HRESULT hr = VBoxNetCfgWinNetLwfInstall(pNetCfg, wszInf);
1257 if (FAILED(hr))
1258 logStringF(hModule, L"InstallNetLwf: VBoxNetCfgWinNetLwfInstall failed, error = %#x", hr);
1259
1260 uErr = errorConvertFromHResult(hModule, hr);
1261 }
1262 else
1263 {
1264 logStringF(hModule, L"vboxNetFltQueryInfArray: Empty installation directory");
1265 uErr = ERROR_GEN_FAILURE;
1266 }
1267 }
1268 else
1269 logStringF(hModule, L"vboxNetFltQueryInfArray: MsiGetPropertyW failed, error = %#x", uErr);
1270
1271 VBoxNetCfgWinReleaseINetCfg(pNetCfg, TRUE);
1272
1273 logStringF(hModule, L"InstallNetLwf: Done");
1274 }
1275 else
1276 logStringF(hModule, L"InstallNetLwf: doNetCfgInit failed, error = %#x", uErr);
1277 }
1278 __finally
1279 {
1280 if (bOldIntMode)
1281 {
1282 /* The prev mode != FALSE, i.e. non-interactive. */
1283 SetupSetNonInteractiveMode(bOldIntMode);
1284 }
1285 netCfgLoggerDisable();
1286 }
1287#endif /* VBOX_WITH_NETFLT */
1288
1289 /* Never fail the install even if we did not succeed. */
1290 return ERROR_SUCCESS;
1291}
1292
1293UINT __stdcall InstallNetLwf(MSIHANDLE hModule)
1294{
1295 (void)_uninstallNetFlt(hModule);
1296 return _installNetLwf(hModule);
1297}
1298
1299
1300#if 0
1301static BOOL RenameHostOnlyConnectionsCallback(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pDev, PVOID pContext)
1302{
1303 WCHAR DevName[256];
1304 DWORD winEr;
1305
1306 if (SetupDiGetDeviceRegistryPropertyW(hDevInfo, pDev,
1307 SPDRP_FRIENDLYNAME , /* IN DWORD Property,*/
1308 NULL, /*OUT PDWORD PropertyRegDataType, OPTIONAL*/
1309 (PBYTE)DevName, /*OUT PBYTE PropertyBuffer,*/
1310 sizeof(DevName), /* IN DWORD PropertyBufferSize,*/
1311 NULL /*OUT PDWORD RequiredSize OPTIONAL*/
1312 ))
1313 {
1314 HKEY hKey = SetupDiOpenDevRegKey(hDevInfo, pDev,
1315 DICS_FLAG_GLOBAL, /* IN DWORD Scope,*/
1316 0, /*IN DWORD HwProfile, */
1317 DIREG_DRV, /* IN DWORD KeyType, */
1318 KEY_READ /*IN REGSAM samDesired*/
1319 );
1320 NonStandardAssert(hKey != INVALID_HANDLE_VALUE);
1321 if (hKey != INVALID_HANDLE_VALUE)
1322 {
1323 WCHAR guid[50];
1324 DWORD cbGuid=sizeof(guid);
1325 winEr = RegQueryValueExW(hKey,
1326 L"NetCfgInstanceId", /*__in_opt LPCTSTR lpValueName,*/
1327 NULL, /*__reserved LPDWORD lpReserved,*/
1328 NULL, /*__out_opt LPDWORD lpType,*/
1329 (LPBYTE)guid, /*__out_opt LPBYTE lpData,*/
1330 &cbGuid /*guid__inout_opt LPDWORD lpcbData*/
1331 );
1332 NonStandardAssert(winEr == ERROR_SUCCESS);
1333 if (winEr == ERROR_SUCCESS)
1334 {
1335 WCHAR ConnectoinName[128];
1336 ULONG cbName = sizeof(ConnectoinName);
1337
1338 HRESULT hr = VBoxNetCfgWinGenHostonlyConnectionName (DevName, ConnectoinName, &cbName);
1339 NonStandardAssert(hr == S_OK);
1340 if (SUCCEEDED(hr))
1341 {
1342 hr = VBoxNetCfgWinRenameConnection(guid, ConnectoinName);
1343 NonStandardAssert(hr == S_OK);
1344 }
1345 }
1346 }
1347 RegCloseKey(hKey);
1348 }
1349 else
1350 {
1351 NonStandardAssert(0);
1352 }
1353
1354 return TRUE;
1355}
1356#endif
1357
1358static UINT _createHostOnlyInterface(MSIHANDLE hModule, LPCWSTR pwszId, LPCWSTR pwszInfName)
1359{
1360#ifdef VBOX_WITH_NETFLT
1361 netCfgLoggerEnable(hModule);
1362
1363 BOOL fSetupModeInteractive = SetupSetNonInteractiveMode(FALSE);
1364
1365 logStringF(hModule, L"CreateHostOnlyInterface: Creating host-only interface");
1366
1367 HRESULT hr = E_FAIL;
1368 GUID guid;
1369 WCHAR wszMpInf[MAX_PATH];
1370 DWORD cchMpInf = RT_ELEMENTS(wszMpInf) - (DWORD)wcslen(pwszInfName) - 1 - 1;
1371 LPCWSTR pwszInfPath = NULL;
1372 bool fIsFile = false;
1373 UINT uErr = MsiGetPropertyW(hModule, L"CustomActionData", wszMpInf, &cchMpInf);
1374 if (uErr == ERROR_SUCCESS)
1375 {
1376 if (cchMpInf)
1377 {
1378 logStringF(hModule, L"CreateHostOnlyInterface: NetAdpDir property = %s", wszMpInf);
1379 if (wszMpInf[cchMpInf - 1] != L'\\')
1380 {
1381 wszMpInf[cchMpInf++] = L'\\';
1382 wszMpInf[cchMpInf] = L'\0';
1383 }
1384
1385 wcscat(wszMpInf, pwszInfName);
1386 pwszInfPath = wszMpInf;
1387 fIsFile = true;
1388
1389 logStringF(hModule, L"CreateHostOnlyInterface: Resulting INF path = %s", pwszInfPath);
1390 }
1391 else
1392 logStringF(hModule, L"CreateHostOnlyInterface: VBox installation path is empty");
1393 }
1394 else
1395 logStringF(hModule, L"CreateHostOnlyInterface: Unable to retrieve VBox installation path, error = %#x", uErr);
1396
1397 /* Make sure the inf file is installed. */
1398 if (pwszInfPath != NULL && fIsFile)
1399 {
1400 logStringF(hModule, L"CreateHostOnlyInterface: Calling VBoxDrvCfgInfInstall(%s)", pwszInfPath);
1401 hr = VBoxDrvCfgInfInstall(pwszInfPath);
1402 logStringF(hModule, L"CreateHostOnlyInterface: VBoxDrvCfgInfInstall returns %#x", hr);
1403 if (FAILED(hr))
1404 logStringF(hModule, L"CreateHostOnlyInterface: Failed to install INF file, error = %#x", hr);
1405 }
1406
1407 if (SUCCEEDED(hr))
1408 {
1409 //first, try to update Host Only Network Interface
1410 BOOL fRebootRequired = FALSE;
1411 hr = VBoxNetCfgWinUpdateHostOnlyNetworkInterface(pwszInfPath, &fRebootRequired, pwszId);
1412 if (SUCCEEDED(hr))
1413 {
1414 if (fRebootRequired)
1415 {
1416 logStringF(hModule, L"CreateHostOnlyInterface: Reboot required for update, setting REBOOT property to force");
1417 HRESULT hr2 = MsiSetPropertyW(hModule, L"REBOOT", L"Force");
1418 if (hr2 != ERROR_SUCCESS)
1419 logStringF(hModule, L"CreateHostOnlyInterface: Failed to set REBOOT property for update, error = %#x", hr2);
1420 }
1421 }
1422 else
1423 {
1424 //in fail case call CreateHostOnlyInterface
1425 logStringF(hModule, L"CreateHostOnlyInterface: VBoxNetCfgWinUpdateHostOnlyNetworkInterface failed, hr = %#x", hr);
1426 logStringF(hModule, L"CreateHostOnlyInterface: calling VBoxNetCfgWinCreateHostOnlyNetworkInterface");
1427#ifdef VBOXNETCFG_DELAYEDRENAME
1428 BSTR devId;
1429 hr = VBoxNetCfgWinCreateHostOnlyNetworkInterface(pwszInfPath, fIsFile, NULL, &guid, &devId, NULL);
1430#else /* !VBOXNETCFG_DELAYEDRENAME */
1431 hr = VBoxNetCfgWinCreateHostOnlyNetworkInterface(pwszInfPath, fIsFile, NULL, &guid, NULL, NULL);
1432#endif /* !VBOXNETCFG_DELAYEDRENAME */
1433 logStringF(hModule, L"CreateHostOnlyInterface: VBoxNetCfgWinCreateHostOnlyNetworkInterface returns %#x", hr);
1434 if (SUCCEEDED(hr))
1435 {
1436 ULONG ip = inet_addr("192.168.56.1");
1437 ULONG mask = inet_addr("255.255.255.0");
1438 logStringF(hModule, L"CreateHostOnlyInterface: calling VBoxNetCfgWinEnableStaticIpConfig");
1439 hr = VBoxNetCfgWinEnableStaticIpConfig(&guid, ip, mask);
1440 logStringF(hModule, L"CreateHostOnlyInterface: VBoxNetCfgWinEnableStaticIpConfig returns %#x", hr);
1441 if (FAILED(hr))
1442 logStringF(hModule, L"CreateHostOnlyInterface: VBoxNetCfgWinEnableStaticIpConfig failed, error = %#x", hr);
1443#ifdef VBOXNETCFG_DELAYEDRENAME
1444 hr = VBoxNetCfgWinRenameHostOnlyConnection(&guid, devId, NULL);
1445 if (FAILED(hr))
1446 logStringF(hModule, L"CreateHostOnlyInterface: VBoxNetCfgWinRenameHostOnlyConnection failed, error = %#x", hr);
1447 SysFreeString(devId);
1448#endif /* VBOXNETCFG_DELAYEDRENAME */
1449 }
1450 else
1451 logStringF(hModule, L"CreateHostOnlyInterface: VBoxNetCfgWinCreateHostOnlyNetworkInterface failed, error = %#x", hr);
1452 }
1453 }
1454
1455 if (SUCCEEDED(hr))
1456 logStringF(hModule, L"CreateHostOnlyInterface: Creating host-only interface done");
1457
1458 /* Restore original setup mode. */
1459 logStringF(hModule, L"CreateHostOnlyInterface: Almost done...");
1460 if (fSetupModeInteractive)
1461 SetupSetNonInteractiveMode(fSetupModeInteractive);
1462
1463 netCfgLoggerDisable();
1464
1465#endif /* VBOX_WITH_NETFLT */
1466
1467 logStringF(hModule, L"CreateHostOnlyInterface: Returns success (ignoring all failures)");
1468 /* Never fail the install even if we did not succeed. */
1469 return ERROR_SUCCESS;
1470}
1471
1472UINT __stdcall CreateHostOnlyInterface(MSIHANDLE hModule)
1473{
1474 return _createHostOnlyInterface(hModule, NETADP_ID, L"VBoxNetAdp.inf");
1475}
1476
1477UINT __stdcall Ndis6CreateHostOnlyInterface(MSIHANDLE hModule)
1478{
1479 return _createHostOnlyInterface(hModule, NETADP_ID, L"VBoxNetAdp6.inf");
1480}
1481
1482static UINT _removeHostOnlyInterfaces(MSIHANDLE hModule, LPCWSTR pwszId)
1483{
1484#ifdef VBOX_WITH_NETFLT
1485 netCfgLoggerEnable(hModule);
1486
1487 logStringF(hModule, L"RemoveHostOnlyInterfaces: Removing all host-only interfaces");
1488
1489 BOOL fSetupModeInteractive = SetupSetNonInteractiveMode(FALSE);
1490
1491 HRESULT hr = VBoxNetCfgWinRemoveAllNetDevicesOfId(pwszId);
1492 if (SUCCEEDED(hr))
1493 {
1494 hr = VBoxDrvCfgInfUninstallAllSetupDi(&GUID_DEVCLASS_NET, L"Net", pwszId, SUOI_FORCEDELETE/* could be SUOI_FORCEDELETE */);
1495 if (FAILED(hr))
1496 logStringF(hModule, L"RemoveHostOnlyInterfaces: NetAdp uninstalled successfully, but failed to remove INF files");
1497 else
1498 logStringF(hModule, L"RemoveHostOnlyInterfaces: NetAdp uninstalled successfully");
1499 }
1500 else
1501 logStringF(hModule, L"RemoveHostOnlyInterfaces: NetAdp uninstall failed, hr = %#x", hr);
1502
1503 /* Restore original setup mode. */
1504 if (fSetupModeInteractive)
1505 SetupSetNonInteractiveMode(fSetupModeInteractive);
1506
1507 netCfgLoggerDisable();
1508#endif /* VBOX_WITH_NETFLT */
1509
1510 /* Never fail the uninstall even if we did not succeed. */
1511 return ERROR_SUCCESS;
1512}
1513
1514UINT __stdcall RemoveHostOnlyInterfaces(MSIHANDLE hModule)
1515{
1516 return _removeHostOnlyInterfaces(hModule, NETADP_ID);
1517}
1518
1519static UINT _stopHostOnlyInterfaces(MSIHANDLE hModule, LPCWSTR pwszId)
1520{
1521#ifdef VBOX_WITH_NETFLT
1522 netCfgLoggerEnable(hModule);
1523
1524 logStringF(hModule, L"StopHostOnlyInterfaces: Stopping all host-only interfaces");
1525
1526 BOOL fSetupModeInteractive = SetupSetNonInteractiveMode(FALSE);
1527
1528 HRESULT hr = VBoxNetCfgWinPropChangeAllNetDevicesOfId(pwszId, VBOXNECTFGWINPROPCHANGE_TYPE_DISABLE);
1529 if (SUCCEEDED(hr))
1530 logStringF(hModule, L"StopHostOnlyInterfaces: Disabling host interfaces was successful, hr = %#x", hr);
1531 else
1532 logStringF(hModule, L"StopHostOnlyInterfaces: Disabling host interfaces failed, hr = %#x", hr);
1533
1534 /* Restore original setup mode. */
1535 if (fSetupModeInteractive)
1536 SetupSetNonInteractiveMode(fSetupModeInteractive);
1537
1538 netCfgLoggerDisable();
1539#endif /* VBOX_WITH_NETFLT */
1540
1541 /* Never fail the uninstall even if we did not succeed. */
1542 return ERROR_SUCCESS;
1543}
1544
1545UINT __stdcall StopHostOnlyInterfaces(MSIHANDLE hModule)
1546{
1547 return _stopHostOnlyInterfaces(hModule, NETADP_ID);
1548}
1549
1550static UINT _updateHostOnlyInterfaces(MSIHANDLE hModule, LPCWSTR pwszInfName, LPCWSTR pwszId)
1551{
1552#ifdef VBOX_WITH_NETFLT
1553 netCfgLoggerEnable(hModule);
1554
1555 logStringF(hModule, L"UpdateHostOnlyInterfaces: Updating all host-only interfaces");
1556
1557 BOOL fSetupModeInteractive = SetupSetNonInteractiveMode(FALSE);
1558
1559 WCHAR wszMpInf[MAX_PATH];
1560 DWORD cchMpInf = RT_ELEMENTS(wszMpInf) - (DWORD)wcslen(pwszInfName) - 1 - 1;
1561 LPCWSTR pwszInfPath = NULL;
1562 bool fIsFile = false;
1563 UINT uErr = MsiGetPropertyW(hModule, L"CustomActionData", wszMpInf, &cchMpInf);
1564 if (uErr == ERROR_SUCCESS)
1565 {
1566 if (cchMpInf)
1567 {
1568 logStringF(hModule, L"UpdateHostOnlyInterfaces: NetAdpDir property = %s", wszMpInf);
1569 if (wszMpInf[cchMpInf - 1] != L'\\')
1570 {
1571 wszMpInf[cchMpInf++] = L'\\';
1572 wszMpInf[cchMpInf] = L'\0';
1573 }
1574
1575 wcscat(wszMpInf, pwszInfName);
1576 pwszInfPath = wszMpInf;
1577 fIsFile = true;
1578
1579 logStringF(hModule, L"UpdateHostOnlyInterfaces: Resulting INF path = %s", pwszInfPath);
1580
1581 DWORD attrFile = GetFileAttributesW(pwszInfPath);
1582 if (attrFile == INVALID_FILE_ATTRIBUTES)
1583 {
1584 DWORD dwErr = GetLastError();
1585 logStringF(hModule, L"UpdateHostOnlyInterfaces: File \"%s\" not found, dwErr=%ld", pwszInfPath, dwErr);
1586 }
1587 else
1588 {
1589 logStringF(hModule, L"UpdateHostOnlyInterfaces: File \"%s\" exists", pwszInfPath);
1590
1591 BOOL fRebootRequired = FALSE;
1592 HRESULT hr = VBoxNetCfgWinUpdateHostOnlyNetworkInterface(pwszInfPath, &fRebootRequired, pwszId);
1593 if (SUCCEEDED(hr))
1594 {
1595 if (fRebootRequired)
1596 {
1597 logStringF(hModule, L"UpdateHostOnlyInterfaces: Reboot required, setting REBOOT property to force");
1598 HRESULT hr2 = MsiSetPropertyW(hModule, L"REBOOT", L"Force");
1599 if (hr2 != ERROR_SUCCESS)
1600 logStringF(hModule, L"UpdateHostOnlyInterfaces: Failed to set REBOOT property, error = %#x", hr2);
1601 }
1602 }
1603 else
1604 logStringF(hModule, L"UpdateHostOnlyInterfaces: VBoxNetCfgWinUpdateHostOnlyNetworkInterface failed, hr = %#x", hr);
1605 }
1606 }
1607 else
1608 logStringF(hModule, L"UpdateHostOnlyInterfaces: VBox installation path is empty");
1609 }
1610 else
1611 logStringF(hModule, L"UpdateHostOnlyInterfaces: Unable to retrieve VBox installation path, error = %#x", uErr);
1612
1613 /* Restore original setup mode. */
1614 if (fSetupModeInteractive)
1615 SetupSetNonInteractiveMode(fSetupModeInteractive);
1616
1617 netCfgLoggerDisable();
1618#endif /* VBOX_WITH_NETFLT */
1619
1620 /* Never fail the update even if we did not succeed. */
1621 return ERROR_SUCCESS;
1622}
1623
1624UINT __stdcall UpdateHostOnlyInterfaces(MSIHANDLE hModule)
1625{
1626 return _updateHostOnlyInterfaces(hModule, L"VBoxNetAdp.inf", NETADP_ID);
1627}
1628
1629UINT __stdcall Ndis6UpdateHostOnlyInterfaces(MSIHANDLE hModule)
1630{
1631 return _updateHostOnlyInterfaces(hModule, L"VBoxNetAdp6.inf", NETADP_ID);
1632}
1633
1634static UINT _uninstallNetAdp(MSIHANDLE hModule, LPCWSTR pwszId)
1635{
1636#ifdef VBOX_WITH_NETFLT
1637 INetCfg *pNetCfg;
1638 UINT uErr;
1639
1640 netCfgLoggerEnable(hModule);
1641
1642 BOOL bOldIntMode = SetupSetNonInteractiveMode(FALSE);
1643
1644 __try
1645 {
1646 logStringF(hModule, L"Uninstalling NetAdp");
1647
1648 uErr = doNetCfgInit(hModule, &pNetCfg, TRUE);
1649 if (uErr == ERROR_SUCCESS)
1650 {
1651 HRESULT hr = VBoxNetCfgWinNetAdpUninstall(pNetCfg, pwszId);
1652 if (hr != S_OK)
1653 logStringF(hModule, L"UninstallNetAdp: VBoxNetCfgWinUninstallComponent failed, error = %#x", hr);
1654
1655 uErr = errorConvertFromHResult(hModule, hr);
1656
1657 VBoxNetCfgWinReleaseINetCfg(pNetCfg, TRUE);
1658
1659 logStringF(hModule, L"Uninstalling NetAdp done, error = %#x", uErr);
1660 }
1661 else
1662 logStringF(hModule, L"UninstallNetAdp: doNetCfgInit failed, error = %#x", uErr);
1663 }
1664 __finally
1665 {
1666 if (bOldIntMode)
1667 {
1668 /* The prev mode != FALSE, i.e. non-interactive. */
1669 SetupSetNonInteractiveMode(bOldIntMode);
1670 }
1671 netCfgLoggerDisable();
1672 }
1673#endif /* VBOX_WITH_NETFLT */
1674
1675 /* Never fail the uninstall even if we did not succeed. */
1676 return ERROR_SUCCESS;
1677}
1678
1679UINT __stdcall UninstallNetAdp(MSIHANDLE hModule)
1680{
1681 return _uninstallNetAdp(hModule, NETADP_ID);
1682}
1683
1684static bool isTAPDevice(const WCHAR *pwszGUID)
1685{
1686 HKEY hNetcard;
1687 bool bIsTapDevice = false;
1688 LONG lStatus = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1689 L"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}",
1690 0, KEY_READ, &hNetcard);
1691 if (lStatus != ERROR_SUCCESS)
1692 return false;
1693
1694 int i = 0;
1695 for (;;)
1696 {
1697 WCHAR wszEnumName[256];
1698 WCHAR wszNetCfgInstanceId[256];
1699 DWORD dwKeyType;
1700 HKEY hNetCardGUID;
1701
1702 DWORD dwLen = sizeof(wszEnumName);
1703 lStatus = RegEnumKeyExW(hNetcard, i, wszEnumName, &dwLen, NULL, NULL, NULL, NULL);
1704 if (lStatus != ERROR_SUCCESS)
1705 break;
1706
1707 lStatus = RegOpenKeyExW(hNetcard, wszEnumName, 0, KEY_READ, &hNetCardGUID);
1708 if (lStatus == ERROR_SUCCESS)
1709 {
1710 dwLen = sizeof(wszNetCfgInstanceId);
1711 lStatus = RegQueryValueExW(hNetCardGUID, L"NetCfgInstanceId", NULL, &dwKeyType, (LPBYTE)wszNetCfgInstanceId, &dwLen);
1712 if ( lStatus == ERROR_SUCCESS
1713 && dwKeyType == REG_SZ)
1714 {
1715 WCHAR wszNetProductName[256];
1716 WCHAR wszNetProviderName[256];
1717
1718 wszNetProductName[0] = 0;
1719 dwLen = sizeof(wszNetProductName);
1720 lStatus = RegQueryValueExW(hNetCardGUID, L"ProductName", NULL, &dwKeyType, (LPBYTE)wszNetProductName, &dwLen);
1721
1722 wszNetProviderName[0] = 0;
1723 dwLen = sizeof(wszNetProviderName);
1724 lStatus = RegQueryValueExW(hNetCardGUID, L"ProviderName", NULL, &dwKeyType, (LPBYTE)wszNetProviderName, &dwLen);
1725
1726 if ( !wcscmp(wszNetCfgInstanceId, pwszGUID)
1727 && !wcscmp(wszNetProductName, L"VirtualBox TAP Adapter")
1728 && ( (!wcscmp(wszNetProviderName, L"innotek GmbH")) /* Legacy stuff. */
1729 || (!wcscmp(wszNetProviderName, L"Sun Microsystems, Inc.")) /* Legacy stuff. */
1730 || (!wcscmp(wszNetProviderName, MY_WTEXT(VBOX_VENDOR))) /* Reflects current vendor string. */
1731 )
1732 )
1733 {
1734 bIsTapDevice = true;
1735 RegCloseKey(hNetCardGUID);
1736 break;
1737 }
1738 }
1739 RegCloseKey(hNetCardGUID);
1740 }
1741 ++i;
1742 }
1743
1744 RegCloseKey(hNetcard);
1745 return bIsTapDevice;
1746}
1747
1748/** @todo r=andy BUGBUG WTF! Why do we a) set the rc to 0 (success), and b) need this macro at all!? */
1749#define SetErrBreak(args) \
1750 if (1) { \
1751 rc = 0; \
1752 logStringF args; \
1753 break; \
1754 } else do {} while (0)
1755
1756int removeNetworkInterface(MSIHANDLE hModule, const WCHAR *pwszGUID)
1757{
1758 int rc = 1;
1759 do /* break-loop */
1760 {
1761 WCHAR wszPnPInstanceId[512] = {0};
1762
1763 /* We have to find the device instance ID through a registry search */
1764
1765 HKEY hkeyNetwork = 0;
1766 HKEY hkeyConnection = 0;
1767
1768 do /* break-loop */
1769 {
1770 WCHAR wszRegLocation[256];
1771 swprintf_s(wszRegLocation, RT_ELEMENTS(wszRegLocation),
1772 L"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s", pwszGUID);
1773 LONG lStatus = RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRegLocation, 0, KEY_READ, &hkeyNetwork);
1774 if (lStatus != ERROR_SUCCESS || !hkeyNetwork)
1775 SetErrBreak((hModule, L"VBox HostInterfaces: Host interface network was not found in registry (%s)! [1]",
1776 wszRegLocation));
1777
1778 lStatus = RegOpenKeyExW(hkeyNetwork, L"Connection", 0, KEY_READ, &hkeyConnection);
1779 if (lStatus != ERROR_SUCCESS || !hkeyConnection)
1780 SetErrBreak((hModule, L"VBox HostInterfaces: Host interface network was not found in registry (%s)! [2]",
1781 wszRegLocation));
1782
1783 DWORD len = sizeof(wszPnPInstanceId);
1784 DWORD dwKeyType;
1785 lStatus = RegQueryValueExW(hkeyConnection, L"PnPInstanceID", NULL, &dwKeyType, (LPBYTE)&wszPnPInstanceId[0], &len);
1786 if (lStatus != ERROR_SUCCESS || (dwKeyType != REG_SZ))
1787 SetErrBreak((hModule, L"VBox HostInterfaces: Host interface network was not found in registry (%s)! [3]",
1788 wszRegLocation));
1789 }
1790 while (0);
1791
1792 if (hkeyConnection)
1793 RegCloseKey(hkeyConnection);
1794 if (hkeyNetwork)
1795 RegCloseKey(hkeyNetwork);
1796
1797 /*
1798 * Now we are going to enumerate all network devices and
1799 * wait until we encounter the right device instance ID
1800 */
1801
1802 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
1803 BOOL fResult;
1804
1805 do /* break-loop */
1806 {
1807 GUID netGuid;
1808 SP_DEVINFO_DATA DeviceInfoData;
1809 DWORD index = 0;
1810 DWORD size = 0;
1811
1812 /* initialize the structure size */
1813 DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
1814
1815 /* copy the net class GUID */
1816 memcpy(&netGuid, &GUID_DEVCLASS_NET, sizeof (GUID_DEVCLASS_NET));
1817
1818 /* return a device info set contains all installed devices of the Net class */
1819 hDeviceInfo = SetupDiGetClassDevs(&netGuid, NULL, NULL, DIGCF_PRESENT);
1820 if (hDeviceInfo == INVALID_HANDLE_VALUE)
1821 {
1822 logStringF(hModule, L"VBox HostInterfaces: SetupDiGetClassDevs failed (0x%08X)!", GetLastError());
1823 SetErrBreak((hModule, L"VBox HostInterfaces: Uninstallation failed!"));
1824 }
1825
1826 BOOL fFoundDevice = FALSE;
1827
1828 /* enumerate the driver info list */
1829 while (TRUE)
1830 {
1831 WCHAR *pwszDeviceHwid;
1832
1833 fResult = SetupDiEnumDeviceInfo(hDeviceInfo, index, &DeviceInfoData);
1834 if (!fResult)
1835 {
1836 if (GetLastError() == ERROR_NO_MORE_ITEMS)
1837 break;
1838 else
1839 {
1840 index++;
1841 continue;
1842 }
1843 }
1844
1845 /* try to get the hardware ID registry property */
1846 fResult = SetupDiGetDeviceRegistryProperty(hDeviceInfo,
1847 &DeviceInfoData,
1848 SPDRP_HARDWAREID,
1849 NULL,
1850 NULL,
1851 0,
1852 &size);
1853 if (!fResult)
1854 {
1855 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
1856 {
1857 index++;
1858 continue;
1859 }
1860
1861 pwszDeviceHwid = (WCHAR *)malloc(size);
1862 if (pwszDeviceHwid)
1863 {
1864 fResult = SetupDiGetDeviceRegistryProperty(hDeviceInfo,
1865 &DeviceInfoData,
1866 SPDRP_HARDWAREID,
1867 NULL,
1868 (PBYTE)pwszDeviceHwid,
1869 size,
1870 NULL);
1871 if (!fResult)
1872 {
1873 free(pwszDeviceHwid);
1874 pwszDeviceHwid = NULL;
1875 index++;
1876 continue;
1877 }
1878 }
1879 }
1880 else
1881 {
1882 /* something is wrong. This shouldn't have worked with a NULL buffer */
1883 index++;
1884 continue;
1885 }
1886
1887 for (WCHAR *t = pwszDeviceHwid;
1888 t && *t && t < &pwszDeviceHwid[size / sizeof(WCHAR)];
1889 t += wcslen(t) + 1)
1890 {
1891 if (!_wcsicmp(L"vboxtap", t))
1892 {
1893 /* get the device instance ID */
1894 WCHAR wszDevID[MAX_DEVICE_ID_LEN];
1895 if (CM_Get_Device_IDW(DeviceInfoData.DevInst,
1896 wszDevID, MAX_DEVICE_ID_LEN, 0) == CR_SUCCESS)
1897 {
1898 /* compare to what we determined before */
1899 if (!wcscmp(wszDevID, wszPnPInstanceId))
1900 {
1901 fFoundDevice = TRUE;
1902 break;
1903 }
1904 }
1905 }
1906 }
1907
1908 if (pwszDeviceHwid)
1909 {
1910 free(pwszDeviceHwid);
1911 pwszDeviceHwid = NULL;
1912 }
1913
1914 if (fFoundDevice)
1915 break;
1916
1917 index++;
1918 }
1919
1920 if (fFoundDevice)
1921 {
1922 fResult = SetupDiSetSelectedDevice(hDeviceInfo, &DeviceInfoData);
1923 if (!fResult)
1924 {
1925 logStringF(hModule, L"VBox HostInterfaces: SetupDiSetSelectedDevice failed (0x%08X)!", GetLastError());
1926 SetErrBreak((hModule, L"VBox HostInterfaces: Uninstallation failed!"));
1927 }
1928
1929 fResult = SetupDiCallClassInstaller(DIF_REMOVE, hDeviceInfo, &DeviceInfoData);
1930 if (!fResult)
1931 {
1932 logStringF(hModule, L"VBox HostInterfaces: SetupDiCallClassInstaller (DIF_REMOVE) failed (0x%08X)!", GetLastError());
1933 SetErrBreak((hModule, L"VBox HostInterfaces: Uninstallation failed!"));
1934 }
1935 }
1936 else
1937 SetErrBreak((hModule, L"VBox HostInterfaces: Host interface network device not found!"));
1938 } while (0);
1939
1940 /* clean up the device info set */
1941 if (hDeviceInfo != INVALID_HANDLE_VALUE)
1942 SetupDiDestroyDeviceInfoList(hDeviceInfo);
1943 } while (0);
1944 return rc;
1945}
1946
1947UINT __stdcall UninstallTAPInstances(MSIHANDLE hModule)
1948{
1949 static const wchar_t s_wszNetworkKey[] = L"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}";
1950 HKEY hCtrlNet;
1951
1952 LONG lStatus = RegOpenKeyExW(HKEY_LOCAL_MACHINE, s_wszNetworkKey, 0, KEY_READ, &hCtrlNet);
1953 if (lStatus == ERROR_SUCCESS)
1954 {
1955 logStringF(hModule, L"VBox HostInterfaces: Enumerating interfaces ...");
1956 for (int i = 0; ; ++i)
1957 {
1958 WCHAR wszNetworkGUID[256] = { 0 };
1959 DWORD dwLen = (DWORD)sizeof(wszNetworkGUID);
1960 lStatus = RegEnumKeyExW(hCtrlNet, i, wszNetworkGUID, &dwLen, NULL, NULL, NULL, NULL);
1961 if (lStatus != ERROR_SUCCESS)
1962 {
1963 switch (lStatus)
1964 {
1965 case ERROR_NO_MORE_ITEMS:
1966 logStringF(hModule, L"VBox HostInterfaces: No interfaces found.");
1967 break;
1968 default:
1969 logStringF(hModule, L"VBox HostInterfaces: Enumeration failed: %ld", lStatus);
1970 break;
1971 }
1972 break;
1973 }
1974
1975 if (isTAPDevice(wszNetworkGUID))
1976 {
1977 logStringF(hModule, L"VBox HostInterfaces: Removing interface \"%s\" ...", wszNetworkGUID);
1978 removeNetworkInterface(hModule, wszNetworkGUID);
1979 lStatus = RegDeleteKeyW(hCtrlNet, wszNetworkGUID);
1980 }
1981 }
1982 RegCloseKey(hCtrlNet);
1983 logStringF(hModule, L"VBox HostInterfaces: Removing interfaces done.");
1984 }
1985 return ERROR_SUCCESS;
1986}
1987
1988
1989/**
1990 * This is used to remove the old VBoxDrv service before installation.
1991 *
1992 * The current service name is VBoxSup but the INF file won't remove the old
1993 * one, so we do it manually to try prevent trouble as the device nodes are the
1994 * same and we would fail starting VBoxSup.sys if VBoxDrv.sys is still loading.
1995 *
1996 * Status code is ignored for now as a reboot should fix most potential trouble
1997 * here (and I don't want to break stuff too badly).
1998 *
1999 * @sa @bugref{10162}
2000 */
2001UINT __stdcall UninstallVBoxDrv(MSIHANDLE hModule)
2002{
2003 /*
2004 * Try open the service.
2005 */
2006 SC_HANDLE hSMgr = OpenSCManager(NULL, NULL, SERVICE_CHANGE_CONFIG | SERVICE_STOP | SERVICE_QUERY_STATUS);
2007 if (hSMgr)
2008 {
2009 SC_HANDLE hService = OpenServiceW(hSMgr, L"VBoxDrv", DELETE | SERVICE_STOP | SERVICE_QUERY_STATUS);
2010 if (hService)
2011 {
2012 /*
2013 * Try stop it before we delete it.
2014 */
2015 SERVICE_STATUS Status = { 0, 0, 0, 0, 0, 0, 0 };
2016 QueryServiceStatus(hService, &Status);
2017 if (Status.dwCurrentState == SERVICE_STOPPED)
2018 logStringF(hModule, L"VBoxDrv: The service old service was already stopped");
2019 else
2020 {
2021 logStringF(hModule, L"VBoxDrv: Stopping the service (state %u)", Status.dwCurrentState);
2022 if (ControlService(hService, SERVICE_CONTROL_STOP, &Status))
2023 {
2024 /* waiting for it to stop: */
2025 int iWait = 100;
2026 while (Status.dwCurrentState == SERVICE_STOP_PENDING && iWait-- > 0)
2027 {
2028 Sleep(100);
2029 QueryServiceStatus(hService, &Status);
2030 }
2031
2032 if (Status.dwCurrentState == SERVICE_STOPPED)
2033 logStringF(hModule, L"VBoxDrv: Stopped service");
2034 else
2035 logStringF(hModule, L"VBoxDrv: Failed to stop the service, status: %u", Status.dwCurrentState);
2036 }
2037 else
2038 {
2039 DWORD const dwErr = GetLastError();
2040 if ( Status.dwCurrentState == SERVICE_STOP_PENDING
2041 && dwErr == ERROR_SERVICE_CANNOT_ACCEPT_CTRL)
2042 logStringF(hModule, L"VBoxDrv: Failed to stop the service: stop pending, not accepting control messages");
2043 else
2044 logStringF(hModule, L"VBoxDrv: Failed to stop the service: dwErr=%u status=%u", dwErr, Status.dwCurrentState);
2045 }
2046 }
2047
2048 /*
2049 * Delete the service, or at least mark it for deletion.
2050 */
2051 if (DeleteService(hService))
2052 logStringF(hModule, L"VBoxDrv: Successfully delete service");
2053 else
2054 logStringF(hModule, L"VBoxDrv: Failed to delete the service: %u", GetLastError());
2055
2056 CloseServiceHandle(hService);
2057 }
2058 else
2059 {
2060 DWORD const dwErr = GetLastError();
2061 if (dwErr == ERROR_SERVICE_DOES_NOT_EXIST)
2062 logStringF(hModule, L"VBoxDrv: Nothing to do, the old service does not exist");
2063 else
2064 logStringF(hModule, L"VBoxDrv: Failed to open the service: %u", dwErr);
2065 }
2066
2067 CloseServiceHandle(hSMgr);
2068 }
2069 else
2070 logStringF(hModule, L"VBoxDrv: Failed to open service manager (%u).", GetLastError());
2071
2072 return ERROR_SUCCESS;
2073}
2074
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette