VirtualBox

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

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

scm copyright and license note update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 71.1 KB
Line 
1/* $Id: VBoxInstallHelper.cpp 96407 2022-08-22 17:43:14Z 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.virtualbox.org.
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 the running OS is (at least) Windows 10 (e.g. >= build 10000).
448 *
449 * Called from the MSI installer as custom action.
450 *
451 * @returns Always ERROR_SUCCESS.
452 * Sets public property VBOX_IS_WINDOWS_10 to "" (empty / false) or "1" (success).
453 *
454 * @param hModule Windows installer module handle.
455 */
456UINT __stdcall IsWindows10(MSIHANDLE hModule)
457{
458 /*
459 * Note: We cannot use RtlGetVersion() / GetVersionExW() here, as the Windows Installer service
460 * all shims this, unfortunately. So we have to go another route by querying the major version
461 * number from the registry.
462 */
463 HKEY hKeyCurVer = NULL;
464 LSTATUS dwErr = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0, KEY_READ, &hKeyCurVer);
465 if (dwErr == ERROR_SUCCESS)
466 {
467 DWORD dwVal = 0;
468 DWORD cbVal = sizeof(dwVal);
469 DWORD dwValueType = REG_DWORD;
470 dwErr = RegQueryValueExW(hKeyCurVer, L"CurrentMajorVersionNumber", NULL, &dwValueType, (LPBYTE)&dwVal, &cbVal);
471 if (dwErr == ERROR_SUCCESS)
472 {
473 logStringF(hModule, L"IsWindows10/CurrentMajorVersionNumber: %ld", dwVal);
474
475 VBoxSetMsiProp(hModule, L"VBOX_IS_WINDOWS_10", dwVal >= 10 ? L"1" : L"");
476 }
477 else
478 logStringF(hModule, L"IsWindows10/RegOpenKeyExW: Error reading CurrentMajorVersionNumber (%ld)", dwErr);
479
480 RegCloseKey(hKeyCurVer);
481 }
482 else
483 logStringF(hModule, L"IsWindows10/RegOpenKeyExW: Error opening CurrentVersion key (%ld)", dwErr);
484
485 return ERROR_SUCCESS; /* Never return failure. */
486}
487
488/**
489 * Installs and compiles the VBox Python bindings.
490 *
491 * Called from the MSI installer as custom action.
492 *
493 * @returns Always ERROR_SUCCESS.
494 * Sets public property VBOX_API_INSTALLED to "0" (false) or "1" (success).
495 *
496 * @param hModule Windows installer module handle.
497 */
498UINT __stdcall InstallPythonAPI(MSIHANDLE hModule)
499{
500 logStringF(hModule, L"InstallPythonAPI: Checking for installed Python environment(s) ...");
501
502 /** @todo r=bird: Can't we get the VBOX_PYTHON_PATH property here? */
503 wchar_t wszPythonExe[RTPATH_MAX];
504 UINT rcWin = getPythonExe(hModule, wszPythonExe, RTPATH_MAX);
505 if (rcWin != ERROR_SUCCESS)
506 {
507 VBoxSetMsiProp(hModule, L"VBOX_API_INSTALLED", L"0");
508 return ERROR_SUCCESS;
509 }
510
511 /*
512 * Set up the VBox API.
513 */
514 /* Get the VBox API setup string. */
515 WCHAR wszVBoxSDKPath[RTPATH_MAX];
516 rcWin = VBoxGetMsiProp(hModule, L"CustomActionData", wszVBoxSDKPath, sizeof(wszVBoxSDKPath));
517 if (rcWin == ERROR_SUCCESS)
518 {
519 /* Make sure our current working directory is the VBox installation path. */
520 if (SetCurrentDirectoryW(wszVBoxSDKPath))
521 {
522 /* Set required environment variables. */
523 if (SetEnvironmentVariableW(L"VBOX_INSTALL_PATH", wszVBoxSDKPath))
524 {
525 logStringF(hModule, L"InstallPythonAPI: Invoking vboxapisetup.py in \"%s\" ...", wszVBoxSDKPath);
526
527 rcWin = procRun(hModule, wszPythonExe, L"vboxapisetup.py install");
528 if (rcWin == ERROR_SUCCESS)
529 {
530 logStringF(hModule, L"InstallPythonAPI: Installation of vboxapisetup.py successful");
531
532 /*
533 * Do some sanity checking if the VBox API works.
534 */
535 logStringF(hModule, L"InstallPythonAPI: Validating VBox API ...");
536
537 rcWin = procRun(hModule, wszPythonExe, L"-c \"from vboxapi import VirtualBoxManager\"");
538 if (rcWin == ERROR_SUCCESS)
539 {
540 logStringF(hModule, L"InstallPythonAPI: VBox API looks good.");
541 VBoxSetMsiProp(hModule, L"VBOX_API_INSTALLED", L"1");
542 return ERROR_SUCCESS;
543 }
544
545 /* failed */
546 logStringF(hModule, L"InstallPythonAPI: Validating VBox API failed with %u (%#x)", rcWin, rcWin);
547 }
548 else
549 logStringF(hModule, L"InstallPythonAPI: Calling vboxapisetup.py failed with %u (%#x)", rcWin, rcWin);
550 }
551 else
552 logStringF(hModule, L"InstallPythonAPI: Could set environment variable VBOX_INSTALL_PATH: LastError=%u",
553 GetLastError());
554 }
555 else
556 logStringF(hModule, L"InstallPythonAPI: Could set working directory to \"%s\": LastError=%u",
557 wszVBoxSDKPath, GetLastError());
558 }
559 else
560 logStringF(hModule, L"InstallPythonAPI: Unable to retrieve VBox installation directory: rcWin=%u (%#x)", rcWin, rcWin);
561
562 VBoxSetMsiProp(hModule, L"VBOX_API_INSTALLED", L"0");
563 logStringF(hModule, L"InstallPythonAPI: Installation failed");
564 return ERROR_SUCCESS; /* Do not fail here. */
565}
566
567static LONG installBrandingValue(MSIHANDLE hModule,
568 const WCHAR *pwszFileName,
569 const WCHAR *pwszSection,
570 const WCHAR *pwszValue)
571{
572 LONG rc;
573 WCHAR wszValue[_MAX_PATH];
574 if (GetPrivateProfileStringW(pwszSection, pwszValue, NULL, wszValue, sizeof(wszValue), pwszFileName) > 0)
575 {
576 WCHAR wszKey[_MAX_PATH + 64];
577 if (wcsicmp(L"General", pwszSection) != 0)
578 swprintf_s(wszKey, RT_ELEMENTS(wszKey), L"SOFTWARE\\%S\\VirtualBox\\Branding\\%s", VBOX_VENDOR_SHORT, pwszSection);
579 else
580 swprintf_s(wszKey, RT_ELEMENTS(wszKey), L"SOFTWARE\\%S\\VirtualBox\\Branding", VBOX_VENDOR_SHORT);
581
582 HKEY hkBranding = NULL;
583 rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszKey, 0, KEY_WRITE, &hkBranding);
584 if (rc == ERROR_SUCCESS)
585 {
586 rc = RegSetValueExW(hkBranding,
587 pwszValue,
588 NULL,
589 REG_SZ,
590 (BYTE *)wszValue,
591 (DWORD)wcslen(wszValue));
592 if (rc != ERROR_SUCCESS)
593 logStringF(hModule, L"InstallBranding: Could not write value %s! Error %d", pwszValue, rc);
594 RegCloseKey(hkBranding);
595 }
596 }
597 else
598 rc = ERROR_NOT_FOUND;
599 return rc;
600}
601
602/**
603 * @note Both paths strings must have an extra terminator.
604 */
605static UINT CopyDir(MSIHANDLE hModule, const WCHAR *pwszzDstDir, const WCHAR *pwszzSrcDir)
606{
607 NonStandardAssert(pwszzDstDir[wcslen(pwszzDstDir) + 1] == '\0');
608 NonStandardAssert(pwszzSrcDir[wcslen(pwszzSrcDir) + 1] == '\0');
609
610 SHFILEOPSTRUCTW s = {0};
611 s.hwnd = NULL;
612 s.wFunc = FO_COPY;
613 s.pTo = pwszzDstDir;
614 s.pFrom = pwszzSrcDir;
615 s.fFlags = FOF_SILENT
616 | FOF_NOCONFIRMATION
617 | FOF_NOCONFIRMMKDIR
618 | FOF_NOERRORUI;
619
620 logStringF(hModule, L"CopyDir: pwszzDstDir=%s, pwszzSrcDir=%s", pwszzDstDir, pwszzSrcDir);
621 int r = SHFileOperationW(&s);
622 if (r == 0)
623 return ERROR_SUCCESS;
624 logStringF(hModule, L"CopyDir: Copy operation returned status %#x", r);
625 return ERROR_GEN_FAILURE;
626}
627
628/**
629 * @note The directory string must have two zero terminators!
630 */
631static UINT RemoveDir(MSIHANDLE hModule, const WCHAR *pwszzDstDir)
632{
633 NonStandardAssert(pwszzDstDir[wcslen(pwszzDstDir) + 1] == '\0');
634
635 SHFILEOPSTRUCTW s = {0};
636 s.hwnd = NULL;
637 s.wFunc = FO_DELETE;
638 s.pFrom = pwszzDstDir;
639 s.fFlags = FOF_SILENT
640 | FOF_NOCONFIRMATION
641 | FOF_NOCONFIRMMKDIR
642 | FOF_NOERRORUI;
643
644 logStringF(hModule, L"RemoveDir: pwszzDstDir=%s", pwszzDstDir);
645 int r = SHFileOperationW(&s);
646 if (r == 0)
647 return ERROR_SUCCESS;
648 logStringF(hModule, L"RemoveDir: Remove operation returned status %#x", r);
649 return ERROR_GEN_FAILURE;
650}
651
652/**
653 * @note Both paths strings must have an extra terminator.
654 */
655static UINT RenameDir(MSIHANDLE hModule, const WCHAR *pwszzDstDir, const WCHAR *pwszzSrcDir)
656{
657 NonStandardAssert(pwszzDstDir[wcslen(pwszzDstDir) + 1] == '\0');
658 NonStandardAssert(pwszzSrcDir[wcslen(pwszzSrcDir) + 1] == '\0');
659
660 SHFILEOPSTRUCTW s = {0};
661 s.hwnd = NULL;
662 s.wFunc = FO_RENAME;
663 s.pTo = pwszzDstDir;
664 s.pFrom = pwszzSrcDir;
665 s.fFlags = FOF_SILENT
666 | FOF_NOCONFIRMATION
667 | FOF_NOCONFIRMMKDIR
668 | FOF_NOERRORUI;
669
670 logStringF(hModule, L"RenameDir: pwszzDstDir=%s, pwszzSrcDir=%s", pwszzDstDir, pwszzSrcDir);
671 int r = SHFileOperationW(&s);
672 if (r == 0)
673 return ERROR_SUCCESS;
674 logStringF(hModule, L"RenameDir: Rename operation returned status %#x", r);
675 return ERROR_GEN_FAILURE;
676}
677
678/** RTPathAppend-like function. */
679static UINT AppendToPath(wchar_t *pwszPath, size_t cwcPath, wchar_t *pwszAppend, bool fDoubleTerm = false)
680{
681 size_t cwcCurPath = wcslen(pwszPath);
682 size_t cwcSlash = cwcCurPath > 1 && RTPATH_IS_SLASH(pwszPath[cwcCurPath - 1]) ? 0 : 1;
683 while (RTPATH_IS_SLASH(*pwszAppend))
684 pwszAppend++;
685 size_t cwcAppend = wcslen(pwszAppend);
686 if (cwcCurPath + cwcCurPath + cwcAppend + fDoubleTerm < cwcPath)
687 {
688 if (cwcSlash)
689 pwszPath[cwcCurPath++] = '\\';
690 memcpy(&pwszPath[cwcCurPath], pwszAppend, (cwcAppend + 1) * sizeof(wchar_t));
691 if (fDoubleTerm)
692 pwszPath[cwcCurPath + cwcAppend + 1] = '\0';
693 return ERROR_SUCCESS;
694 }
695 return ERROR_BUFFER_OVERFLOW;
696}
697
698/** RTPathJoin-like function. */
699static UINT JoinPaths(wchar_t *pwszPath, size_t cwcPath, wchar_t *pwszPath1, wchar_t *pwszAppend, bool fDoubleTerm = false)
700{
701 size_t cwcCurPath = wcslen(pwszPath1);
702 if (cwcCurPath < cwcPath)
703 {
704 memcpy(pwszPath, pwszPath1, (cwcCurPath + 1) * sizeof(wchar_t));
705 return AppendToPath(pwszPath, cwcPath, pwszAppend, fDoubleTerm);
706 }
707 return ERROR_BUFFER_OVERFLOW;
708}
709
710UINT __stdcall UninstallBranding(MSIHANDLE hModule)
711{
712 logStringF(hModule, L"UninstallBranding: Handling branding file ...");
713
714 WCHAR wszPath[RTPATH_MAX];
715 UINT rc = VBoxGetMsiProp(hModule, L"CustomActionData", wszPath, sizeof(wszPath));
716 if (rc == ERROR_SUCCESS)
717 {
718 size_t const cwcPath = wcslen(wszPath);
719 rc = AppendToPath(wszPath, RTPATH_MAX, L"custom", true /*fDoubleTerm*/);
720 if (rc == ERROR_SUCCESS)
721 rc = RemoveDir(hModule, wszPath);
722
723 /* Check for .custom directory from a failed install and remove it. */
724 wszPath[cwcPath] = '\0';
725 rc = AppendToPath(wszPath, RTPATH_MAX, L".custom", true /*fDoubleTerm*/);
726 if (rc == ERROR_SUCCESS)
727 rc = RemoveDir(hModule, wszPath);
728 }
729
730 logStringF(hModule, L"UninstallBranding: Handling done. (rc=%u (ignored))", rc);
731 return ERROR_SUCCESS; /* Do not fail here. */
732}
733
734UINT __stdcall InstallBranding(MSIHANDLE hModule)
735{
736 logStringF(hModule, L"InstallBranding: Handling branding file ...");
737
738 /*
739 * Get the paths.
740 */
741 wchar_t wszSrcPath[RTPATH_MAX];
742 UINT rc = VBoxGetMsiProp(hModule, L"SOURCEDIR", wszSrcPath, RT_ELEMENTS(wszSrcPath));
743 if (rc == ERROR_SUCCESS)
744 {
745 wchar_t wszDstPath[RTPATH_MAX];
746 rc = VBoxGetMsiProp(hModule, L"CustomActionData", wszDstPath, RT_ELEMENTS(wszDstPath) - 1);
747 if (rc == ERROR_SUCCESS)
748 {
749 /*
750 * First we copy the src\.custom dir to the target.
751 */
752 rc = AppendToPath(wszSrcPath, RT_ELEMENTS(wszSrcPath) - 1, L".custom", true /*fDoubleTerm*/);
753 if (rc == ERROR_SUCCESS)
754 {
755 rc = CopyDir(hModule, wszDstPath, wszSrcPath);
756 if (rc == ERROR_SUCCESS)
757 {
758 /*
759 * The rename the '.custom' directory we now got in the target area to 'custom'.
760 */
761 rc = JoinPaths(wszSrcPath, RT_ELEMENTS(wszSrcPath), wszDstPath, L".custom", true /*fDoubleTerm*/);
762 if (rc == ERROR_SUCCESS)
763 {
764 rc = AppendToPath(wszDstPath, RT_ELEMENTS(wszDstPath), L"custom", true /*fDoubleTerm*/);
765 if (rc == ERROR_SUCCESS)
766 rc = RenameDir(hModule, wszDstPath, wszSrcPath);
767 }
768 }
769 }
770 }
771 }
772
773 logStringF(hModule, L"InstallBranding: Handling done. (rc=%u (ignored))", rc);
774 return ERROR_SUCCESS; /* Do not fail here. */
775}
776
777#ifdef VBOX_WITH_NETFLT
778
779/** @todo should use some real VBox app name */
780#define VBOX_NETCFG_APP_NAME L"VirtualBox Installer"
781#define VBOX_NETCFG_MAX_RETRIES 10
782#define NETFLT_PT_INF_REL_PATH L"VBoxNetFlt.inf"
783#define NETFLT_MP_INF_REL_PATH L"VBoxNetFltM.inf"
784#define NETFLT_ID L"sun_VBoxNetFlt" /** @todo Needs to be changed (?). */
785#define NETADP_ID L"sun_VBoxNetAdp" /** @todo Needs to be changed (?). */
786
787#define NETLWF_INF_NAME L"VBoxNetLwf.inf"
788
789static MSIHANDLE g_hCurrentModule = NULL;
790
791static UINT _uninstallNetFlt(MSIHANDLE hModule);
792static UINT _uninstallNetLwf(MSIHANDLE hModule);
793
794static VOID vboxDrvLoggerCallback(VBOXDRVCFG_LOG_SEVERITY enmSeverity, char *pszMsg, void *pvContext)
795{
796 RT_NOREF1(pvContext);
797 switch (enmSeverity)
798 {
799 case VBOXDRVCFG_LOG_SEVERITY_FLOW:
800 case VBOXDRVCFG_LOG_SEVERITY_REGULAR:
801 break;
802 case VBOXDRVCFG_LOG_SEVERITY_REL:
803 if (g_hCurrentModule)
804 logStringF(g_hCurrentModule, L"%S", pszMsg);
805 break;
806 default:
807 break;
808 }
809}
810
811static DECLCALLBACK(void) netCfgLoggerCallback(const char *pszString)
812{
813 if (g_hCurrentModule)
814 logStringF(g_hCurrentModule, L"%S", pszString);
815}
816
817static VOID netCfgLoggerDisable()
818{
819 if (g_hCurrentModule)
820 {
821 VBoxNetCfgWinSetLogging(NULL);
822 g_hCurrentModule = NULL;
823 }
824}
825
826static VOID netCfgLoggerEnable(MSIHANDLE hModule)
827{
828 NonStandardAssert(hModule);
829
830 if (g_hCurrentModule)
831 netCfgLoggerDisable();
832
833 g_hCurrentModule = hModule;
834
835 VBoxNetCfgWinSetLogging(netCfgLoggerCallback);
836 /* uncomment next line if you want to add logging information from VBoxDrvCfg.cpp */
837// VBoxDrvCfgLoggerSet(vboxDrvLoggerCallback, NULL);
838}
839
840static UINT errorConvertFromHResult(MSIHANDLE hModule, HRESULT hr)
841{
842 UINT uRet;
843 switch (hr)
844 {
845 case S_OK:
846 uRet = ERROR_SUCCESS;
847 break;
848
849 case NETCFG_S_REBOOT:
850 {
851 logStringF(hModule, L"Reboot required, setting REBOOT property to \"force\"");
852 HRESULT hr2 = MsiSetPropertyW(hModule, L"REBOOT", L"Force");
853 if (hr2 != ERROR_SUCCESS)
854 logStringF(hModule, L"Failed to set REBOOT property, error = %#x", hr2);
855 uRet = ERROR_SUCCESS; /* Never fail here. */
856 break;
857 }
858
859 default:
860 logStringF(hModule, L"Converting unhandled HRESULT (%#x) to ERROR_GEN_FAILURE", hr);
861 uRet = ERROR_GEN_FAILURE;
862 }
863 return uRet;
864}
865
866static MSIHANDLE createNetCfgLockedMsgRecord(MSIHANDLE hModule)
867{
868 MSIHANDLE hRecord = MsiCreateRecord(2);
869 if (hRecord)
870 {
871 UINT uErr = MsiRecordSetInteger(hRecord, 1, 25001);
872 if (uErr != ERROR_SUCCESS)
873 {
874 logStringF(hModule, L"createNetCfgLockedMsgRecord: MsiRecordSetInteger failed, error = %#x", uErr);
875 MsiCloseHandle(hRecord);
876 hRecord = NULL;
877 }
878 }
879 else
880 logStringF(hModule, L"createNetCfgLockedMsgRecord: Failed to create a record");
881
882 return hRecord;
883}
884
885static UINT doNetCfgInit(MSIHANDLE hModule, INetCfg **ppnc, BOOL bWrite)
886{
887 MSIHANDLE hMsg = NULL;
888 UINT uErr = ERROR_GEN_FAILURE;
889 int MsgResult;
890 int cRetries = 0;
891
892 do
893 {
894 LPWSTR lpszLockedBy;
895 HRESULT hr = VBoxNetCfgWinQueryINetCfg(ppnc, bWrite, VBOX_NETCFG_APP_NAME, 10000, &lpszLockedBy);
896 if (hr != NETCFG_E_NO_WRITE_LOCK)
897 {
898 if (FAILED(hr))
899 logStringF(hModule, L"doNetCfgInit: VBoxNetCfgWinQueryINetCfg failed, error = %#x", hr);
900 uErr = errorConvertFromHResult(hModule, hr);
901 break;
902 }
903
904 /* hr == NETCFG_E_NO_WRITE_LOCK */
905
906 if (!lpszLockedBy)
907 {
908 logStringF(hModule, L"doNetCfgInit: lpszLockedBy == NULL, breaking");
909 break;
910 }
911
912 /* on vista the 6to4svc.dll periodically maintains the lock for some reason,
913 * if this is the case, increase the wait period by retrying multiple times
914 * NOTE: we could alternatively increase the wait timeout,
915 * however it seems unneeded for most cases, e.g. in case some network connection property
916 * dialog is opened, it would be better to post a notification to the user as soon as possible
917 * rather than waiting for a longer period of time before displaying it */
918 if ( cRetries < VBOX_NETCFG_MAX_RETRIES
919 && !wcscmp(lpszLockedBy, L"6to4svc.dll"))
920 {
921 cRetries++;
922 logStringF(hModule, L"doNetCfgInit: lpszLockedBy is 6to4svc.dll, retrying %d out of %d", cRetries, VBOX_NETCFG_MAX_RETRIES);
923 MsgResult = IDRETRY;
924 }
925 else
926 {
927 if (!hMsg)
928 {
929 hMsg = createNetCfgLockedMsgRecord(hModule);
930 if (!hMsg)
931 {
932 logStringF(hModule, L"doNetCfgInit: Failed to create a message record, breaking");
933 CoTaskMemFree(lpszLockedBy);
934 break;
935 }
936 }
937
938 UINT rTmp = MsiRecordSetStringW(hMsg, 2, lpszLockedBy);
939 NonStandardAssert(rTmp == ERROR_SUCCESS);
940 if (rTmp != ERROR_SUCCESS)
941 {
942 logStringF(hModule, L"doNetCfgInit: MsiRecordSetStringW failed, error = #%x", rTmp);
943 CoTaskMemFree(lpszLockedBy);
944 break;
945 }
946
947 MsgResult = MsiProcessMessage(hModule, (INSTALLMESSAGE)(INSTALLMESSAGE_USER | MB_RETRYCANCEL), hMsg);
948 NonStandardAssert(MsgResult == IDRETRY || MsgResult == IDCANCEL);
949 logStringF(hModule, L"doNetCfgInit: MsiProcessMessage returned (%#x)", MsgResult);
950 }
951 CoTaskMemFree(lpszLockedBy);
952 } while(MsgResult == IDRETRY);
953
954 if (hMsg)
955 MsiCloseHandle(hMsg);
956
957 return uErr;
958}
959
960static UINT vboxNetFltQueryInfArray(MSIHANDLE hModule, OUT LPWSTR pwszPtInf, OUT LPWSTR pwszMpInf, DWORD dwSize)
961{
962 DWORD dwBuf = dwSize - RT_MAX(sizeof(NETFLT_PT_INF_REL_PATH), sizeof(NETFLT_MP_INF_REL_PATH));
963 UINT uErr = MsiGetPropertyW(hModule, L"CustomActionData", pwszPtInf, &dwBuf);
964 if ( uErr == ERROR_SUCCESS
965 && dwBuf)
966 {
967 wcscpy(pwszMpInf, pwszPtInf);
968
969 wcsncat(pwszPtInf, NETFLT_PT_INF_REL_PATH, sizeof(NETFLT_PT_INF_REL_PATH));
970 logStringF(hModule, L"vboxNetFltQueryInfArray: INF 1: %s", pwszPtInf);
971
972 wcsncat(pwszMpInf, NETFLT_MP_INF_REL_PATH, sizeof(NETFLT_MP_INF_REL_PATH));
973 logStringF(hModule, L"vboxNetFltQueryInfArray: INF 2: %s", pwszMpInf);
974 }
975 else if (uErr != ERROR_SUCCESS)
976 logStringF(hModule, L"vboxNetFltQueryInfArray: MsiGetPropertyW failed, error = %#x", uErr);
977 else
978 {
979 logStringF(hModule, L"vboxNetFltQueryInfArray: Empty installation directory");
980 uErr = ERROR_GEN_FAILURE;
981 }
982
983 return uErr;
984}
985
986#endif /*VBOX_WITH_NETFLT*/
987
988/*static*/ UINT _uninstallNetFlt(MSIHANDLE hModule)
989{
990#ifdef VBOX_WITH_NETFLT
991 INetCfg *pNetCfg;
992 UINT uErr;
993
994 netCfgLoggerEnable(hModule);
995
996 BOOL bOldIntMode = SetupSetNonInteractiveMode(FALSE);
997
998 __try
999 {
1000 logStringF(hModule, L"Uninstalling NetFlt");
1001
1002 uErr = doNetCfgInit(hModule, &pNetCfg, TRUE);
1003 if (uErr == ERROR_SUCCESS)
1004 {
1005 HRESULT hr = VBoxNetCfgWinNetFltUninstall(pNetCfg);
1006 if (hr != S_OK)
1007 logStringF(hModule, L"UninstallNetFlt: VBoxNetCfgWinUninstallComponent failed, error = %#x", hr);
1008
1009 uErr = errorConvertFromHResult(hModule, hr);
1010
1011 VBoxNetCfgWinReleaseINetCfg(pNetCfg, TRUE);
1012
1013 logStringF(hModule, L"Uninstalling NetFlt done, error = %#x", uErr);
1014 }
1015 else
1016 logStringF(hModule, L"UninstallNetFlt: doNetCfgInit failed, error = %#x", uErr);
1017 }
1018 __finally
1019 {
1020 if (bOldIntMode)
1021 {
1022 /* The prev mode != FALSE, i.e. non-interactive. */
1023 SetupSetNonInteractiveMode(bOldIntMode);
1024 }
1025 netCfgLoggerDisable();
1026 }
1027#endif /* VBOX_WITH_NETFLT */
1028
1029 /* Never fail the uninstall even if we did not succeed. */
1030 return ERROR_SUCCESS;
1031}
1032
1033UINT __stdcall UninstallNetFlt(MSIHANDLE hModule)
1034{
1035 (void)_uninstallNetLwf(hModule);
1036 return _uninstallNetFlt(hModule);
1037}
1038
1039static UINT _installNetFlt(MSIHANDLE hModule)
1040{
1041#ifdef VBOX_WITH_NETFLT
1042 UINT uErr;
1043 INetCfg *pNetCfg;
1044
1045 netCfgLoggerEnable(hModule);
1046
1047 BOOL bOldIntMode = SetupSetNonInteractiveMode(FALSE);
1048
1049 __try
1050 {
1051
1052 logStringF(hModule, L"InstallNetFlt: Installing NetFlt");
1053
1054 uErr = doNetCfgInit(hModule, &pNetCfg, TRUE);
1055 if (uErr == ERROR_SUCCESS)
1056 {
1057 WCHAR wszPtInf[MAX_PATH];
1058 WCHAR wszMpInf[MAX_PATH];
1059 uErr = vboxNetFltQueryInfArray(hModule, wszPtInf, wszMpInf, sizeof(wszMpInf));
1060 if (uErr == ERROR_SUCCESS)
1061 {
1062 LPCWSTR const apwszInfs[] = { wszPtInf, wszMpInf };
1063 HRESULT hr = VBoxNetCfgWinNetFltInstall(pNetCfg, &apwszInfs[0], RT_ELEMENTS(apwszInfs));
1064 if (FAILED(hr))
1065 logStringF(hModule, L"InstallNetFlt: VBoxNetCfgWinNetFltInstall failed, error = %#x", hr);
1066
1067 uErr = errorConvertFromHResult(hModule, hr);
1068 }
1069 else
1070 logStringF(hModule, L"InstallNetFlt: vboxNetFltQueryInfArray failed, error = %#x", uErr);
1071
1072 VBoxNetCfgWinReleaseINetCfg(pNetCfg, TRUE);
1073
1074 logStringF(hModule, L"InstallNetFlt: Done");
1075 }
1076 else
1077 logStringF(hModule, L"InstallNetFlt: doNetCfgInit failed, error = %#x", uErr);
1078 }
1079 __finally
1080 {
1081 if (bOldIntMode)
1082 {
1083 /* The prev mode != FALSE, i.e. non-interactive. */
1084 SetupSetNonInteractiveMode(bOldIntMode);
1085 }
1086 netCfgLoggerDisable();
1087 }
1088#endif /* VBOX_WITH_NETFLT */
1089
1090 /* Never fail the install even if we did not succeed. */
1091 return ERROR_SUCCESS;
1092}
1093
1094UINT __stdcall InstallNetFlt(MSIHANDLE hModule)
1095{
1096 (void)_uninstallNetLwf(hModule);
1097 return _installNetFlt(hModule);
1098}
1099
1100
1101/*static*/ UINT _uninstallNetLwf(MSIHANDLE hModule)
1102{
1103#ifdef VBOX_WITH_NETFLT
1104 INetCfg *pNetCfg;
1105 UINT uErr;
1106
1107 netCfgLoggerEnable(hModule);
1108
1109 BOOL bOldIntMode = SetupSetNonInteractiveMode(FALSE);
1110
1111 __try
1112 {
1113 logStringF(hModule, L"Uninstalling NetLwf");
1114
1115 uErr = doNetCfgInit(hModule, &pNetCfg, TRUE);
1116 if (uErr == ERROR_SUCCESS)
1117 {
1118 HRESULT hr = VBoxNetCfgWinNetLwfUninstall(pNetCfg);
1119 if (hr != S_OK)
1120 logStringF(hModule, L"UninstallNetLwf: VBoxNetCfgWinUninstallComponent failed, error = %#x", hr);
1121
1122 uErr = errorConvertFromHResult(hModule, hr);
1123
1124 VBoxNetCfgWinReleaseINetCfg(pNetCfg, TRUE);
1125
1126 logStringF(hModule, L"Uninstalling NetLwf done, error = %#x", uErr);
1127 }
1128 else
1129 logStringF(hModule, L"UninstallNetLwf: doNetCfgInit failed, error = %#x", uErr);
1130 }
1131 __finally
1132 {
1133 if (bOldIntMode)
1134 {
1135 /* The prev mode != FALSE, i.e. non-interactive. */
1136 SetupSetNonInteractiveMode(bOldIntMode);
1137 }
1138 netCfgLoggerDisable();
1139 }
1140#endif /* VBOX_WITH_NETFLT */
1141
1142 /* Never fail the uninstall even if we did not succeed. */
1143 return ERROR_SUCCESS;
1144}
1145
1146UINT __stdcall UninstallNetLwf(MSIHANDLE hModule)
1147{
1148 (void)_uninstallNetFlt(hModule);
1149 return _uninstallNetLwf(hModule);
1150}
1151
1152static UINT _installNetLwf(MSIHANDLE hModule)
1153{
1154#ifdef VBOX_WITH_NETFLT
1155 UINT uErr;
1156 INetCfg *pNetCfg;
1157
1158 netCfgLoggerEnable(hModule);
1159
1160 BOOL bOldIntMode = SetupSetNonInteractiveMode(FALSE);
1161
1162 __try
1163 {
1164
1165 logStringF(hModule, L"InstallNetLwf: Installing NetLwf");
1166
1167 uErr = doNetCfgInit(hModule, &pNetCfg, TRUE);
1168 if (uErr == ERROR_SUCCESS)
1169 {
1170 WCHAR wszInf[MAX_PATH];
1171 DWORD cwcInf = RT_ELEMENTS(wszInf) - sizeof(NETLWF_INF_NAME) - 1;
1172 uErr = MsiGetPropertyW(hModule, L"CustomActionData", wszInf, &cwcInf);
1173 if (uErr == ERROR_SUCCESS)
1174 {
1175 if (cwcInf)
1176 {
1177 if (wszInf[cwcInf - 1] != L'\\')
1178 {
1179 wszInf[cwcInf++] = L'\\';
1180 wszInf[cwcInf] = L'\0';
1181 }
1182
1183 wcscat(wszInf, NETLWF_INF_NAME);
1184
1185 HRESULT hr = VBoxNetCfgWinNetLwfInstall(pNetCfg, wszInf);
1186 if (FAILED(hr))
1187 logStringF(hModule, L"InstallNetLwf: VBoxNetCfgWinNetLwfInstall failed, error = %#x", hr);
1188
1189 uErr = errorConvertFromHResult(hModule, hr);
1190 }
1191 else
1192 {
1193 logStringF(hModule, L"vboxNetFltQueryInfArray: Empty installation directory");
1194 uErr = ERROR_GEN_FAILURE;
1195 }
1196 }
1197 else
1198 logStringF(hModule, L"vboxNetFltQueryInfArray: MsiGetPropertyW failed, error = %#x", uErr);
1199
1200 VBoxNetCfgWinReleaseINetCfg(pNetCfg, TRUE);
1201
1202 logStringF(hModule, L"InstallNetLwf: Done");
1203 }
1204 else
1205 logStringF(hModule, L"InstallNetLwf: doNetCfgInit failed, error = %#x", uErr);
1206 }
1207 __finally
1208 {
1209 if (bOldIntMode)
1210 {
1211 /* The prev mode != FALSE, i.e. non-interactive. */
1212 SetupSetNonInteractiveMode(bOldIntMode);
1213 }
1214 netCfgLoggerDisable();
1215 }
1216#endif /* VBOX_WITH_NETFLT */
1217
1218 /* Never fail the install even if we did not succeed. */
1219 return ERROR_SUCCESS;
1220}
1221
1222UINT __stdcall InstallNetLwf(MSIHANDLE hModule)
1223{
1224 (void)_uninstallNetFlt(hModule);
1225 return _installNetLwf(hModule);
1226}
1227
1228
1229#if 0
1230static BOOL RenameHostOnlyConnectionsCallback(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pDev, PVOID pContext)
1231{
1232 WCHAR DevName[256];
1233 DWORD winEr;
1234
1235 if (SetupDiGetDeviceRegistryPropertyW(hDevInfo, pDev,
1236 SPDRP_FRIENDLYNAME , /* IN DWORD Property,*/
1237 NULL, /*OUT PDWORD PropertyRegDataType, OPTIONAL*/
1238 (PBYTE)DevName, /*OUT PBYTE PropertyBuffer,*/
1239 sizeof(DevName), /* IN DWORD PropertyBufferSize,*/
1240 NULL /*OUT PDWORD RequiredSize OPTIONAL*/
1241 ))
1242 {
1243 HKEY hKey = SetupDiOpenDevRegKey(hDevInfo, pDev,
1244 DICS_FLAG_GLOBAL, /* IN DWORD Scope,*/
1245 0, /*IN DWORD HwProfile, */
1246 DIREG_DRV, /* IN DWORD KeyType, */
1247 KEY_READ /*IN REGSAM samDesired*/
1248 );
1249 NonStandardAssert(hKey != INVALID_HANDLE_VALUE);
1250 if (hKey != INVALID_HANDLE_VALUE)
1251 {
1252 WCHAR guid[50];
1253 DWORD cbGuid=sizeof(guid);
1254 winEr = RegQueryValueExW(hKey,
1255 L"NetCfgInstanceId", /*__in_opt LPCTSTR lpValueName,*/
1256 NULL, /*__reserved LPDWORD lpReserved,*/
1257 NULL, /*__out_opt LPDWORD lpType,*/
1258 (LPBYTE)guid, /*__out_opt LPBYTE lpData,*/
1259 &cbGuid /*guid__inout_opt LPDWORD lpcbData*/
1260 );
1261 NonStandardAssert(winEr == ERROR_SUCCESS);
1262 if (winEr == ERROR_SUCCESS)
1263 {
1264 WCHAR ConnectoinName[128];
1265 ULONG cbName = sizeof(ConnectoinName);
1266
1267 HRESULT hr = VBoxNetCfgWinGenHostonlyConnectionName (DevName, ConnectoinName, &cbName);
1268 NonStandardAssert(hr == S_OK);
1269 if (SUCCEEDED(hr))
1270 {
1271 hr = VBoxNetCfgWinRenameConnection(guid, ConnectoinName);
1272 NonStandardAssert(hr == S_OK);
1273 }
1274 }
1275 }
1276 RegCloseKey(hKey);
1277 }
1278 else
1279 {
1280 NonStandardAssert(0);
1281 }
1282
1283 return TRUE;
1284}
1285#endif
1286
1287static UINT _createHostOnlyInterface(MSIHANDLE hModule, LPCWSTR pwszId, LPCWSTR pwszInfName)
1288{
1289#ifdef VBOX_WITH_NETFLT
1290 netCfgLoggerEnable(hModule);
1291
1292 BOOL fSetupModeInteractive = SetupSetNonInteractiveMode(FALSE);
1293
1294 logStringF(hModule, L"CreateHostOnlyInterface: Creating host-only interface");
1295
1296 HRESULT hr = E_FAIL;
1297 GUID guid;
1298 WCHAR wszMpInf[MAX_PATH];
1299 DWORD cchMpInf = RT_ELEMENTS(wszMpInf) - (DWORD)wcslen(pwszInfName) - 1 - 1;
1300 LPCWSTR pwszInfPath = NULL;
1301 bool fIsFile = false;
1302 UINT uErr = MsiGetPropertyW(hModule, L"CustomActionData", wszMpInf, &cchMpInf);
1303 if (uErr == ERROR_SUCCESS)
1304 {
1305 if (cchMpInf)
1306 {
1307 logStringF(hModule, L"CreateHostOnlyInterface: NetAdpDir property = %s", wszMpInf);
1308 if (wszMpInf[cchMpInf - 1] != L'\\')
1309 {
1310 wszMpInf[cchMpInf++] = L'\\';
1311 wszMpInf[cchMpInf] = L'\0';
1312 }
1313
1314 wcscat(wszMpInf, pwszInfName);
1315 pwszInfPath = wszMpInf;
1316 fIsFile = true;
1317
1318 logStringF(hModule, L"CreateHostOnlyInterface: Resulting INF path = %s", pwszInfPath);
1319 }
1320 else
1321 logStringF(hModule, L"CreateHostOnlyInterface: VBox installation path is empty");
1322 }
1323 else
1324 logStringF(hModule, L"CreateHostOnlyInterface: Unable to retrieve VBox installation path, error = %#x", uErr);
1325
1326 /* Make sure the inf file is installed. */
1327 if (pwszInfPath != NULL && fIsFile)
1328 {
1329 logStringF(hModule, L"CreateHostOnlyInterface: Calling VBoxDrvCfgInfInstall(%s)", pwszInfPath);
1330 hr = VBoxDrvCfgInfInstall(pwszInfPath);
1331 logStringF(hModule, L"CreateHostOnlyInterface: VBoxDrvCfgInfInstall returns %#x", hr);
1332 if (FAILED(hr))
1333 logStringF(hModule, L"CreateHostOnlyInterface: Failed to install INF file, error = %#x", hr);
1334 }
1335
1336 if (SUCCEEDED(hr))
1337 {
1338 //first, try to update Host Only Network Interface
1339 BOOL fRebootRequired = FALSE;
1340 hr = VBoxNetCfgWinUpdateHostOnlyNetworkInterface(pwszInfPath, &fRebootRequired, pwszId);
1341 if (SUCCEEDED(hr))
1342 {
1343 if (fRebootRequired)
1344 {
1345 logStringF(hModule, L"CreateHostOnlyInterface: Reboot required for update, setting REBOOT property to force");
1346 HRESULT hr2 = MsiSetPropertyW(hModule, L"REBOOT", L"Force");
1347 if (hr2 != ERROR_SUCCESS)
1348 logStringF(hModule, L"CreateHostOnlyInterface: Failed to set REBOOT property for update, error = %#x", hr2);
1349 }
1350 }
1351 else
1352 {
1353 //in fail case call CreateHostOnlyInterface
1354 logStringF(hModule, L"CreateHostOnlyInterface: VBoxNetCfgWinUpdateHostOnlyNetworkInterface failed, hr = %#x", hr);
1355 logStringF(hModule, L"CreateHostOnlyInterface: calling VBoxNetCfgWinCreateHostOnlyNetworkInterface");
1356#ifdef VBOXNETCFG_DELAYEDRENAME
1357 BSTR devId;
1358 hr = VBoxNetCfgWinCreateHostOnlyNetworkInterface(pwszInfPath, fIsFile, NULL, &guid, &devId, NULL);
1359#else /* !VBOXNETCFG_DELAYEDRENAME */
1360 hr = VBoxNetCfgWinCreateHostOnlyNetworkInterface(pwszInfPath, fIsFile, NULL, &guid, NULL, NULL);
1361#endif /* !VBOXNETCFG_DELAYEDRENAME */
1362 logStringF(hModule, L"CreateHostOnlyInterface: VBoxNetCfgWinCreateHostOnlyNetworkInterface returns %#x", hr);
1363 if (SUCCEEDED(hr))
1364 {
1365 ULONG ip = inet_addr("192.168.56.1");
1366 ULONG mask = inet_addr("255.255.255.0");
1367 logStringF(hModule, L"CreateHostOnlyInterface: calling VBoxNetCfgWinEnableStaticIpConfig");
1368 hr = VBoxNetCfgWinEnableStaticIpConfig(&guid, ip, mask);
1369 logStringF(hModule, L"CreateHostOnlyInterface: VBoxNetCfgWinEnableStaticIpConfig returns %#x", hr);
1370 if (FAILED(hr))
1371 logStringF(hModule, L"CreateHostOnlyInterface: VBoxNetCfgWinEnableStaticIpConfig failed, error = %#x", hr);
1372#ifdef VBOXNETCFG_DELAYEDRENAME
1373 hr = VBoxNetCfgWinRenameHostOnlyConnection(&guid, devId, NULL);
1374 if (FAILED(hr))
1375 logStringF(hModule, L"CreateHostOnlyInterface: VBoxNetCfgWinRenameHostOnlyConnection failed, error = %#x", hr);
1376 SysFreeString(devId);
1377#endif /* VBOXNETCFG_DELAYEDRENAME */
1378 }
1379 else
1380 logStringF(hModule, L"CreateHostOnlyInterface: VBoxNetCfgWinCreateHostOnlyNetworkInterface failed, error = %#x", hr);
1381 }
1382 }
1383
1384 if (SUCCEEDED(hr))
1385 logStringF(hModule, L"CreateHostOnlyInterface: Creating host-only interface done");
1386
1387 /* Restore original setup mode. */
1388 logStringF(hModule, L"CreateHostOnlyInterface: Almost done...");
1389 if (fSetupModeInteractive)
1390 SetupSetNonInteractiveMode(fSetupModeInteractive);
1391
1392 netCfgLoggerDisable();
1393
1394#endif /* VBOX_WITH_NETFLT */
1395
1396 logStringF(hModule, L"CreateHostOnlyInterface: Returns success (ignoring all failures)");
1397 /* Never fail the install even if we did not succeed. */
1398 return ERROR_SUCCESS;
1399}
1400
1401UINT __stdcall CreateHostOnlyInterface(MSIHANDLE hModule)
1402{
1403 return _createHostOnlyInterface(hModule, NETADP_ID, L"VBoxNetAdp.inf");
1404}
1405
1406UINT __stdcall Ndis6CreateHostOnlyInterface(MSIHANDLE hModule)
1407{
1408 return _createHostOnlyInterface(hModule, NETADP_ID, L"VBoxNetAdp6.inf");
1409}
1410
1411static UINT _removeHostOnlyInterfaces(MSIHANDLE hModule, LPCWSTR pwszId)
1412{
1413#ifdef VBOX_WITH_NETFLT
1414 netCfgLoggerEnable(hModule);
1415
1416 logStringF(hModule, L"RemoveHostOnlyInterfaces: Removing all host-only interfaces");
1417
1418 BOOL fSetupModeInteractive = SetupSetNonInteractiveMode(FALSE);
1419
1420 HRESULT hr = VBoxNetCfgWinRemoveAllNetDevicesOfId(pwszId);
1421 if (SUCCEEDED(hr))
1422 {
1423 hr = VBoxDrvCfgInfUninstallAllSetupDi(&GUID_DEVCLASS_NET, L"Net", pwszId, SUOI_FORCEDELETE/* could be SUOI_FORCEDELETE */);
1424 if (FAILED(hr))
1425 logStringF(hModule, L"RemoveHostOnlyInterfaces: NetAdp uninstalled successfully, but failed to remove INF files");
1426 else
1427 logStringF(hModule, L"RemoveHostOnlyInterfaces: NetAdp uninstalled successfully");
1428 }
1429 else
1430 logStringF(hModule, L"RemoveHostOnlyInterfaces: NetAdp uninstall failed, hr = %#x", hr);
1431
1432 /* Restore original setup mode. */
1433 if (fSetupModeInteractive)
1434 SetupSetNonInteractiveMode(fSetupModeInteractive);
1435
1436 netCfgLoggerDisable();
1437#endif /* VBOX_WITH_NETFLT */
1438
1439 /* Never fail the uninstall even if we did not succeed. */
1440 return ERROR_SUCCESS;
1441}
1442
1443UINT __stdcall RemoveHostOnlyInterfaces(MSIHANDLE hModule)
1444{
1445 return _removeHostOnlyInterfaces(hModule, NETADP_ID);
1446}
1447
1448static UINT _stopHostOnlyInterfaces(MSIHANDLE hModule, LPCWSTR pwszId)
1449{
1450#ifdef VBOX_WITH_NETFLT
1451 netCfgLoggerEnable(hModule);
1452
1453 logStringF(hModule, L"StopHostOnlyInterfaces: Stopping all host-only interfaces");
1454
1455 BOOL fSetupModeInteractive = SetupSetNonInteractiveMode(FALSE);
1456
1457 HRESULT hr = VBoxNetCfgWinPropChangeAllNetDevicesOfId(pwszId, VBOXNECTFGWINPROPCHANGE_TYPE_DISABLE);
1458 if (SUCCEEDED(hr))
1459 logStringF(hModule, L"StopHostOnlyInterfaces: Disabling host interfaces was successful, hr = %#x", hr);
1460 else
1461 logStringF(hModule, L"StopHostOnlyInterfaces: Disabling host interfaces failed, hr = %#x", hr);
1462
1463 /* Restore original setup mode. */
1464 if (fSetupModeInteractive)
1465 SetupSetNonInteractiveMode(fSetupModeInteractive);
1466
1467 netCfgLoggerDisable();
1468#endif /* VBOX_WITH_NETFLT */
1469
1470 /* Never fail the uninstall even if we did not succeed. */
1471 return ERROR_SUCCESS;
1472}
1473
1474UINT __stdcall StopHostOnlyInterfaces(MSIHANDLE hModule)
1475{
1476 return _stopHostOnlyInterfaces(hModule, NETADP_ID);
1477}
1478
1479static UINT _updateHostOnlyInterfaces(MSIHANDLE hModule, LPCWSTR pwszInfName, LPCWSTR pwszId)
1480{
1481#ifdef VBOX_WITH_NETFLT
1482 netCfgLoggerEnable(hModule);
1483
1484 logStringF(hModule, L"UpdateHostOnlyInterfaces: Updating all host-only interfaces");
1485
1486 BOOL fSetupModeInteractive = SetupSetNonInteractiveMode(FALSE);
1487
1488 WCHAR wszMpInf[MAX_PATH];
1489 DWORD cchMpInf = RT_ELEMENTS(wszMpInf) - (DWORD)wcslen(pwszInfName) - 1 - 1;
1490 LPCWSTR pwszInfPath = NULL;
1491 bool fIsFile = false;
1492 UINT uErr = MsiGetPropertyW(hModule, L"CustomActionData", wszMpInf, &cchMpInf);
1493 if (uErr == ERROR_SUCCESS)
1494 {
1495 if (cchMpInf)
1496 {
1497 logStringF(hModule, L"UpdateHostOnlyInterfaces: NetAdpDir property = %s", wszMpInf);
1498 if (wszMpInf[cchMpInf - 1] != L'\\')
1499 {
1500 wszMpInf[cchMpInf++] = L'\\';
1501 wszMpInf[cchMpInf] = L'\0';
1502 }
1503
1504 wcscat(wszMpInf, pwszInfName);
1505 pwszInfPath = wszMpInf;
1506 fIsFile = true;
1507
1508 logStringF(hModule, L"UpdateHostOnlyInterfaces: Resulting INF path = %s", pwszInfPath);
1509
1510 DWORD attrFile = GetFileAttributesW(pwszInfPath);
1511 if (attrFile == INVALID_FILE_ATTRIBUTES)
1512 {
1513 DWORD dwErr = GetLastError();
1514 logStringF(hModule, L"UpdateHostOnlyInterfaces: File \"%s\" not found, dwErr=%ld", pwszInfPath, dwErr);
1515 }
1516 else
1517 {
1518 logStringF(hModule, L"UpdateHostOnlyInterfaces: File \"%s\" exists", pwszInfPath);
1519
1520 BOOL fRebootRequired = FALSE;
1521 HRESULT hr = VBoxNetCfgWinUpdateHostOnlyNetworkInterface(pwszInfPath, &fRebootRequired, pwszId);
1522 if (SUCCEEDED(hr))
1523 {
1524 if (fRebootRequired)
1525 {
1526 logStringF(hModule, L"UpdateHostOnlyInterfaces: Reboot required, setting REBOOT property to force");
1527 HRESULT hr2 = MsiSetPropertyW(hModule, L"REBOOT", L"Force");
1528 if (hr2 != ERROR_SUCCESS)
1529 logStringF(hModule, L"UpdateHostOnlyInterfaces: Failed to set REBOOT property, error = %#x", hr2);
1530 }
1531 }
1532 else
1533 logStringF(hModule, L"UpdateHostOnlyInterfaces: VBoxNetCfgWinUpdateHostOnlyNetworkInterface failed, hr = %#x", hr);
1534 }
1535 }
1536 else
1537 logStringF(hModule, L"UpdateHostOnlyInterfaces: VBox installation path is empty");
1538 }
1539 else
1540 logStringF(hModule, L"UpdateHostOnlyInterfaces: Unable to retrieve VBox installation path, error = %#x", uErr);
1541
1542 /* Restore original setup mode. */
1543 if (fSetupModeInteractive)
1544 SetupSetNonInteractiveMode(fSetupModeInteractive);
1545
1546 netCfgLoggerDisable();
1547#endif /* VBOX_WITH_NETFLT */
1548
1549 /* Never fail the update even if we did not succeed. */
1550 return ERROR_SUCCESS;
1551}
1552
1553UINT __stdcall UpdateHostOnlyInterfaces(MSIHANDLE hModule)
1554{
1555 return _updateHostOnlyInterfaces(hModule, L"VBoxNetAdp.inf", NETADP_ID);
1556}
1557
1558UINT __stdcall Ndis6UpdateHostOnlyInterfaces(MSIHANDLE hModule)
1559{
1560 return _updateHostOnlyInterfaces(hModule, L"VBoxNetAdp6.inf", NETADP_ID);
1561}
1562
1563static UINT _uninstallNetAdp(MSIHANDLE hModule, LPCWSTR pwszId)
1564{
1565#ifdef VBOX_WITH_NETFLT
1566 INetCfg *pNetCfg;
1567 UINT uErr;
1568
1569 netCfgLoggerEnable(hModule);
1570
1571 BOOL bOldIntMode = SetupSetNonInteractiveMode(FALSE);
1572
1573 __try
1574 {
1575 logStringF(hModule, L"Uninstalling NetAdp");
1576
1577 uErr = doNetCfgInit(hModule, &pNetCfg, TRUE);
1578 if (uErr == ERROR_SUCCESS)
1579 {
1580 HRESULT hr = VBoxNetCfgWinNetAdpUninstall(pNetCfg, pwszId);
1581 if (hr != S_OK)
1582 logStringF(hModule, L"UninstallNetAdp: VBoxNetCfgWinUninstallComponent failed, error = %#x", hr);
1583
1584 uErr = errorConvertFromHResult(hModule, hr);
1585
1586 VBoxNetCfgWinReleaseINetCfg(pNetCfg, TRUE);
1587
1588 logStringF(hModule, L"Uninstalling NetAdp done, error = %#x", uErr);
1589 }
1590 else
1591 logStringF(hModule, L"UninstallNetAdp: doNetCfgInit failed, error = %#x", uErr);
1592 }
1593 __finally
1594 {
1595 if (bOldIntMode)
1596 {
1597 /* The prev mode != FALSE, i.e. non-interactive. */
1598 SetupSetNonInteractiveMode(bOldIntMode);
1599 }
1600 netCfgLoggerDisable();
1601 }
1602#endif /* VBOX_WITH_NETFLT */
1603
1604 /* Never fail the uninstall even if we did not succeed. */
1605 return ERROR_SUCCESS;
1606}
1607
1608UINT __stdcall UninstallNetAdp(MSIHANDLE hModule)
1609{
1610 return _uninstallNetAdp(hModule, NETADP_ID);
1611}
1612
1613static bool isTAPDevice(const WCHAR *pwszGUID)
1614{
1615 HKEY hNetcard;
1616 bool bIsTapDevice = false;
1617 LONG lStatus = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1618 L"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}",
1619 0, KEY_READ, &hNetcard);
1620 if (lStatus != ERROR_SUCCESS)
1621 return false;
1622
1623 int i = 0;
1624 for (;;)
1625 {
1626 WCHAR wszEnumName[256];
1627 WCHAR wszNetCfgInstanceId[256];
1628 DWORD dwKeyType;
1629 HKEY hNetCardGUID;
1630
1631 DWORD dwLen = sizeof(wszEnumName);
1632 lStatus = RegEnumKeyExW(hNetcard, i, wszEnumName, &dwLen, NULL, NULL, NULL, NULL);
1633 if (lStatus != ERROR_SUCCESS)
1634 break;
1635
1636 lStatus = RegOpenKeyExW(hNetcard, wszEnumName, 0, KEY_READ, &hNetCardGUID);
1637 if (lStatus == ERROR_SUCCESS)
1638 {
1639 dwLen = sizeof(wszNetCfgInstanceId);
1640 lStatus = RegQueryValueExW(hNetCardGUID, L"NetCfgInstanceId", NULL, &dwKeyType, (LPBYTE)wszNetCfgInstanceId, &dwLen);
1641 if ( lStatus == ERROR_SUCCESS
1642 && dwKeyType == REG_SZ)
1643 {
1644 WCHAR wszNetProductName[256];
1645 WCHAR wszNetProviderName[256];
1646
1647 wszNetProductName[0] = 0;
1648 dwLen = sizeof(wszNetProductName);
1649 lStatus = RegQueryValueExW(hNetCardGUID, L"ProductName", NULL, &dwKeyType, (LPBYTE)wszNetProductName, &dwLen);
1650
1651 wszNetProviderName[0] = 0;
1652 dwLen = sizeof(wszNetProviderName);
1653 lStatus = RegQueryValueExW(hNetCardGUID, L"ProviderName", NULL, &dwKeyType, (LPBYTE)wszNetProviderName, &dwLen);
1654
1655 if ( !wcscmp(wszNetCfgInstanceId, pwszGUID)
1656 && !wcscmp(wszNetProductName, L"VirtualBox TAP Adapter")
1657 && ( (!wcscmp(wszNetProviderName, L"innotek GmbH")) /* Legacy stuff. */
1658 || (!wcscmp(wszNetProviderName, L"Sun Microsystems, Inc.")) /* Legacy stuff. */
1659 || (!wcscmp(wszNetProviderName, MY_WTEXT(VBOX_VENDOR))) /* Reflects current vendor string. */
1660 )
1661 )
1662 {
1663 bIsTapDevice = true;
1664 RegCloseKey(hNetCardGUID);
1665 break;
1666 }
1667 }
1668 RegCloseKey(hNetCardGUID);
1669 }
1670 ++i;
1671 }
1672
1673 RegCloseKey(hNetcard);
1674 return bIsTapDevice;
1675}
1676
1677/** @todo r=andy BUGBUG WTF! Why do we a) set the rc to 0 (success), and b) need this macro at all!? */
1678#define SetErrBreak(args) \
1679 if (1) { \
1680 rc = 0; \
1681 logStringF args; \
1682 break; \
1683 } else do {} while (0)
1684
1685int removeNetworkInterface(MSIHANDLE hModule, const WCHAR *pwszGUID)
1686{
1687 int rc = 1;
1688 do /* break-loop */
1689 {
1690 WCHAR wszPnPInstanceId[512] = {0};
1691
1692 /* We have to find the device instance ID through a registry search */
1693
1694 HKEY hkeyNetwork = 0;
1695 HKEY hkeyConnection = 0;
1696
1697 do /* break-loop */
1698 {
1699 WCHAR wszRegLocation[256];
1700 swprintf_s(wszRegLocation, RT_ELEMENTS(wszRegLocation),
1701 L"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s", pwszGUID);
1702 LONG lStatus = RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRegLocation, 0, KEY_READ, &hkeyNetwork);
1703 if (lStatus != ERROR_SUCCESS || !hkeyNetwork)
1704 SetErrBreak((hModule, L"VBox HostInterfaces: Host interface network was not found in registry (%s)! [1]",
1705 wszRegLocation));
1706
1707 lStatus = RegOpenKeyExW(hkeyNetwork, L"Connection", 0, KEY_READ, &hkeyConnection);
1708 if (lStatus != ERROR_SUCCESS || !hkeyConnection)
1709 SetErrBreak((hModule, L"VBox HostInterfaces: Host interface network was not found in registry (%s)! [2]",
1710 wszRegLocation));
1711
1712 DWORD len = sizeof(wszPnPInstanceId);
1713 DWORD dwKeyType;
1714 lStatus = RegQueryValueExW(hkeyConnection, L"PnPInstanceID", NULL, &dwKeyType, (LPBYTE)&wszPnPInstanceId[0], &len);
1715 if (lStatus != ERROR_SUCCESS || (dwKeyType != REG_SZ))
1716 SetErrBreak((hModule, L"VBox HostInterfaces: Host interface network was not found in registry (%s)! [3]",
1717 wszRegLocation));
1718 }
1719 while (0);
1720
1721 if (hkeyConnection)
1722 RegCloseKey(hkeyConnection);
1723 if (hkeyNetwork)
1724 RegCloseKey(hkeyNetwork);
1725
1726 /*
1727 * Now we are going to enumerate all network devices and
1728 * wait until we encounter the right device instance ID
1729 */
1730
1731 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
1732 BOOL fResult;
1733
1734 do /* break-loop */
1735 {
1736 GUID netGuid;
1737 SP_DEVINFO_DATA DeviceInfoData;
1738 DWORD index = 0;
1739 DWORD size = 0;
1740
1741 /* initialize the structure size */
1742 DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
1743
1744 /* copy the net class GUID */
1745 memcpy(&netGuid, &GUID_DEVCLASS_NET, sizeof (GUID_DEVCLASS_NET));
1746
1747 /* return a device info set contains all installed devices of the Net class */
1748 hDeviceInfo = SetupDiGetClassDevs(&netGuid, NULL, NULL, DIGCF_PRESENT);
1749 if (hDeviceInfo == INVALID_HANDLE_VALUE)
1750 {
1751 logStringF(hModule, L"VBox HostInterfaces: SetupDiGetClassDevs failed (0x%08X)!", GetLastError());
1752 SetErrBreak((hModule, L"VBox HostInterfaces: Uninstallation failed!"));
1753 }
1754
1755 BOOL fFoundDevice = FALSE;
1756
1757 /* enumerate the driver info list */
1758 while (TRUE)
1759 {
1760 WCHAR *pwszDeviceHwid;
1761
1762 fResult = SetupDiEnumDeviceInfo(hDeviceInfo, index, &DeviceInfoData);
1763 if (!fResult)
1764 {
1765 if (GetLastError() == ERROR_NO_MORE_ITEMS)
1766 break;
1767 else
1768 {
1769 index++;
1770 continue;
1771 }
1772 }
1773
1774 /* try to get the hardware ID registry property */
1775 fResult = SetupDiGetDeviceRegistryProperty(hDeviceInfo,
1776 &DeviceInfoData,
1777 SPDRP_HARDWAREID,
1778 NULL,
1779 NULL,
1780 0,
1781 &size);
1782 if (!fResult)
1783 {
1784 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
1785 {
1786 index++;
1787 continue;
1788 }
1789
1790 pwszDeviceHwid = (WCHAR *)malloc(size);
1791 if (pwszDeviceHwid)
1792 {
1793 fResult = SetupDiGetDeviceRegistryProperty(hDeviceInfo,
1794 &DeviceInfoData,
1795 SPDRP_HARDWAREID,
1796 NULL,
1797 (PBYTE)pwszDeviceHwid,
1798 size,
1799 NULL);
1800 if (!fResult)
1801 {
1802 free(pwszDeviceHwid);
1803 pwszDeviceHwid = NULL;
1804 index++;
1805 continue;
1806 }
1807 }
1808 }
1809 else
1810 {
1811 /* something is wrong. This shouldn't have worked with a NULL buffer */
1812 index++;
1813 continue;
1814 }
1815
1816 for (WCHAR *t = pwszDeviceHwid;
1817 t && *t && t < &pwszDeviceHwid[size / sizeof(WCHAR)];
1818 t += wcslen(t) + 1)
1819 {
1820 if (!_wcsicmp(L"vboxtap", t))
1821 {
1822 /* get the device instance ID */
1823 WCHAR wszDevID[MAX_DEVICE_ID_LEN];
1824 if (CM_Get_Device_IDW(DeviceInfoData.DevInst,
1825 wszDevID, MAX_DEVICE_ID_LEN, 0) == CR_SUCCESS)
1826 {
1827 /* compare to what we determined before */
1828 if (!wcscmp(wszDevID, wszPnPInstanceId))
1829 {
1830 fFoundDevice = TRUE;
1831 break;
1832 }
1833 }
1834 }
1835 }
1836
1837 if (pwszDeviceHwid)
1838 {
1839 free(pwszDeviceHwid);
1840 pwszDeviceHwid = NULL;
1841 }
1842
1843 if (fFoundDevice)
1844 break;
1845
1846 index++;
1847 }
1848
1849 if (fFoundDevice)
1850 {
1851 fResult = SetupDiSetSelectedDevice(hDeviceInfo, &DeviceInfoData);
1852 if (!fResult)
1853 {
1854 logStringF(hModule, L"VBox HostInterfaces: SetupDiSetSelectedDevice failed (0x%08X)!", GetLastError());
1855 SetErrBreak((hModule, L"VBox HostInterfaces: Uninstallation failed!"));
1856 }
1857
1858 fResult = SetupDiCallClassInstaller(DIF_REMOVE, hDeviceInfo, &DeviceInfoData);
1859 if (!fResult)
1860 {
1861 logStringF(hModule, L"VBox HostInterfaces: SetupDiCallClassInstaller (DIF_REMOVE) failed (0x%08X)!", GetLastError());
1862 SetErrBreak((hModule, L"VBox HostInterfaces: Uninstallation failed!"));
1863 }
1864 }
1865 else
1866 SetErrBreak((hModule, L"VBox HostInterfaces: Host interface network device not found!"));
1867 } while (0);
1868
1869 /* clean up the device info set */
1870 if (hDeviceInfo != INVALID_HANDLE_VALUE)
1871 SetupDiDestroyDeviceInfoList(hDeviceInfo);
1872 } while (0);
1873 return rc;
1874}
1875
1876UINT __stdcall UninstallTAPInstances(MSIHANDLE hModule)
1877{
1878 static const wchar_t s_wszNetworkKey[] = L"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}";
1879 HKEY hCtrlNet;
1880
1881 LONG lStatus = RegOpenKeyExW(HKEY_LOCAL_MACHINE, s_wszNetworkKey, 0, KEY_READ, &hCtrlNet);
1882 if (lStatus == ERROR_SUCCESS)
1883 {
1884 logStringF(hModule, L"VBox HostInterfaces: Enumerating interfaces ...");
1885 for (int i = 0; ; ++i)
1886 {
1887 WCHAR wszNetworkGUID[256] = { 0 };
1888 DWORD dwLen = (DWORD)sizeof(wszNetworkGUID);
1889 lStatus = RegEnumKeyExW(hCtrlNet, i, wszNetworkGUID, &dwLen, NULL, NULL, NULL, NULL);
1890 if (lStatus != ERROR_SUCCESS)
1891 {
1892 switch (lStatus)
1893 {
1894 case ERROR_NO_MORE_ITEMS:
1895 logStringF(hModule, L"VBox HostInterfaces: No interfaces found.");
1896 break;
1897 default:
1898 logStringF(hModule, L"VBox HostInterfaces: Enumeration failed: %ld", lStatus);
1899 break;
1900 }
1901 break;
1902 }
1903
1904 if (isTAPDevice(wszNetworkGUID))
1905 {
1906 logStringF(hModule, L"VBox HostInterfaces: Removing interface \"%s\" ...", wszNetworkGUID);
1907 removeNetworkInterface(hModule, wszNetworkGUID);
1908 lStatus = RegDeleteKeyW(hCtrlNet, wszNetworkGUID);
1909 }
1910 }
1911 RegCloseKey(hCtrlNet);
1912 logStringF(hModule, L"VBox HostInterfaces: Removing interfaces done.");
1913 }
1914 return ERROR_SUCCESS;
1915}
1916
1917
1918/**
1919 * This is used to remove the old VBoxDrv service before installation.
1920 *
1921 * The current service name is VBoxSup but the INF file won't remove the old
1922 * one, so we do it manually to try prevent trouble as the device nodes are the
1923 * same and we would fail starting VBoxSup.sys if VBoxDrv.sys is still loading.
1924 *
1925 * Status code is ignored for now as a reboot should fix most potential trouble
1926 * here (and I don't want to break stuff too badly).
1927 *
1928 * @sa @bugref{10162}
1929 */
1930UINT __stdcall UninstallVBoxDrv(MSIHANDLE hModule)
1931{
1932 /*
1933 * Try open the service.
1934 */
1935 SC_HANDLE hSMgr = OpenSCManager(NULL, NULL, SERVICE_CHANGE_CONFIG | SERVICE_STOP | SERVICE_QUERY_STATUS);
1936 if (hSMgr)
1937 {
1938 SC_HANDLE hService = OpenServiceW(hSMgr, L"VBoxDrv", DELETE | SERVICE_STOP | SERVICE_QUERY_STATUS);
1939 if (hService)
1940 {
1941 /*
1942 * Try stop it before we delete it.
1943 */
1944 SERVICE_STATUS Status = { 0, 0, 0, 0, 0, 0, 0 };
1945 QueryServiceStatus(hService, &Status);
1946 if (Status.dwCurrentState == SERVICE_STOPPED)
1947 logStringF(hModule, L"VBoxDrv: The service old service was already stopped");
1948 else
1949 {
1950 logStringF(hModule, L"VBoxDrv: Stopping the service (state %u)", Status.dwCurrentState);
1951 if (ControlService(hService, SERVICE_CONTROL_STOP, &Status))
1952 {
1953 /* waiting for it to stop: */
1954 int iWait = 100;
1955 while (Status.dwCurrentState == SERVICE_STOP_PENDING && iWait-- > 0)
1956 {
1957 Sleep(100);
1958 QueryServiceStatus(hService, &Status);
1959 }
1960
1961 if (Status.dwCurrentState == SERVICE_STOPPED)
1962 logStringF(hModule, L"VBoxDrv: Stopped service");
1963 else
1964 logStringF(hModule, L"VBoxDrv: Failed to stop the service, status: %u", Status.dwCurrentState);
1965 }
1966 else
1967 {
1968 DWORD const dwErr = GetLastError();
1969 if ( Status.dwCurrentState == SERVICE_STOP_PENDING
1970 && dwErr == ERROR_SERVICE_CANNOT_ACCEPT_CTRL)
1971 logStringF(hModule, L"VBoxDrv: Failed to stop the service: stop pending, not accepting control messages");
1972 else
1973 logStringF(hModule, L"VBoxDrv: Failed to stop the service: dwErr=%u status=%u", dwErr, Status.dwCurrentState);
1974 }
1975 }
1976
1977 /*
1978 * Delete the service, or at least mark it for deletion.
1979 */
1980 if (DeleteService(hService))
1981 logStringF(hModule, L"VBoxDrv: Successfully delete service");
1982 else
1983 logStringF(hModule, L"VBoxDrv: Failed to delete the service: %u", GetLastError());
1984
1985 CloseServiceHandle(hService);
1986 }
1987 else
1988 {
1989 DWORD const dwErr = GetLastError();
1990 if (dwErr == ERROR_SERVICE_DOES_NOT_EXIST)
1991 logStringF(hModule, L"VBoxDrv: Nothing to do, the old service does not exist");
1992 else
1993 logStringF(hModule, L"VBoxDrv: Failed to open the service: %u", dwErr);
1994 }
1995
1996 CloseServiceHandle(hSMgr);
1997 }
1998 else
1999 logStringF(hModule, L"VBoxDrv: Failed to open service manager (%u).", GetLastError());
2000
2001 return ERROR_SUCCESS;
2002}
2003
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