VirtualBox

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

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

Installer/win: Added custom action for removing old VBoxDrv service. bugref:10162

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