VirtualBox

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

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

Installer/win/InstallHelper: Deal with the swprintf todo (should be harmless, as it's in unused branding code, but anyway).

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