VirtualBox

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

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

Windows host installer: More fun for Windows 10 detection, as the former way often did not work and thus wrong / missing certificates were being installed (running .msi directly vs. .exe installer). We now use a custom action via VBoxInstallHelper.dll, which in turn queries the registry for the (hopefully) correct build number. Note that we cannot use any of the RtlGetVersion() / GetVersion[Ex]W() APIs here, as the Windows Installer service seems to shims those, sigh. bugref:8691

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