VirtualBox

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

Last change on this file since 100686 was 100686, checked in by vboxsync, 17 months ago

Installer/win: Fix MSCRT 2019 Redistributable Package version check. bugref:10284

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

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