VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxNetFlt/win/cfg/VBoxNetCfg.cpp@ 51871

Last change on this file since 51871 was 51871, checked in by vboxsync, 11 years ago

NetFlt (un)installation: Bugfixes, logging.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 102.9 KB
Line 
1/* $Id: VBoxNetCfg.cpp 51871 2014-07-04 14:21:03Z vboxsync $ */
2/** @file
3 * VBoxNetCfg.cpp - Network Configuration API.
4 */
5/*
6 * Copyright (C) 2011-2012 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 */
16#include "VBox/VBoxNetCfg-win.h"
17#include "VBox/VBoxDrvCfg-win.h"
18
19#define _WIN32_DCOM
20
21#include <iphlpapi.h>
22
23#include <devguid.h>
24#include <stdio.h>
25#include <regstr.h>
26#include <shlobj.h>
27#include <cfgmgr32.h>
28#include <tchar.h>
29#include <objbase.h>
30
31#include <crtdbg.h>
32#include <stdlib.h>
33#include <string.h>
34
35#include <Wbemidl.h>
36#include <comdef.h>
37
38
39#ifndef Assert /** @todo r=bird: where would this be defined? */
40//# ifdef DEBUG
41//# define Assert(_expr) assert(_expr)
42//# else
43//# define Assert(_expr) do{ }while (0)
44//# endif
45# define Assert _ASSERT
46# define AssertMsg(expr, msg) do{}while (0)
47#endif
48static LOG_ROUTINE g_Logger = NULL;
49
50static VOID DoLogging(LPCSTR szString, ...);
51#define NonStandardLog DoLogging
52#define NonStandardLogFlow(x) DoLogging x
53
54#define DbgLog /** @todo r=bird: What does this do? */
55
56#define VBOX_NETCFG_LOCK_TIME_OUT 5000 /** @todo r=bird: What does this do? */
57
58
59static HRESULT vboxNetCfgWinINetCfgLock(IN INetCfg *pNetCfg,
60 IN LPCWSTR pszwClientDescription,
61 IN DWORD cmsTimeout,
62 OUT LPWSTR *ppszwClientDescription)
63{
64 INetCfgLock *pLock;
65 HRESULT hr = pNetCfg->QueryInterface(IID_INetCfgLock, (PVOID*)&pLock);
66 if (FAILED(hr))
67 {
68 NonStandardLogFlow(("QueryInterface failed, hr (0x%x)\n", hr));
69 return hr;
70 }
71
72 hr = pLock->AcquireWriteLock(cmsTimeout, pszwClientDescription, ppszwClientDescription);
73 if (hr == S_FALSE)
74 {
75 NonStandardLogFlow(("Write lock busy\n"));
76 }
77 else if (FAILED(hr))
78 {
79 NonStandardLogFlow(("AcquireWriteLock failed, hr (0x%x)\n", hr));
80 }
81
82 pLock->Release();
83 return hr;
84}
85
86static HRESULT vboxNetCfgWinINetCfgUnlock(IN INetCfg *pNetCfg)
87{
88 INetCfgLock *pLock;
89 HRESULT hr = pNetCfg->QueryInterface(IID_INetCfgLock, (PVOID*)&pLock);
90 if (FAILED(hr))
91 {
92 NonStandardLogFlow(("QueryInterface failed, hr (0x%x)\n", hr));
93 return hr;
94 }
95
96 hr = pLock->ReleaseWriteLock();
97 if (FAILED(hr))
98 NonStandardLogFlow(("ReleaseWriteLock failed, hr (0x%x)\n", hr));
99
100 pLock->Release();
101 return hr;
102}
103
104VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinQueryINetCfg(OUT INetCfg **ppNetCfg,
105 IN BOOL fGetWriteLock,
106 IN LPCWSTR pszwClientDescription,
107 IN DWORD cmsTimeout,
108 OUT LPWSTR *ppszwClientDescription)
109{
110 INetCfg *pNetCfg;
111 HRESULT hr = CoCreateInstance(CLSID_CNetCfg, NULL, CLSCTX_INPROC_SERVER, IID_INetCfg, (PVOID*)&pNetCfg);
112 if (FAILED(hr))
113 {
114 NonStandardLogFlow(("CoCreateInstance failed, hr (0x%x)\n", hr));
115 return hr;
116 }
117
118 if (fGetWriteLock)
119 {
120 hr = vboxNetCfgWinINetCfgLock(pNetCfg, pszwClientDescription, cmsTimeout, ppszwClientDescription);
121 if (hr == S_FALSE)
122 {
123 NonStandardLogFlow(("Write lock is busy\n", hr));
124 hr = NETCFG_E_NO_WRITE_LOCK;
125 }
126 }
127
128 if (SUCCEEDED(hr))
129 {
130 hr = pNetCfg->Initialize(NULL);
131 if (SUCCEEDED(hr))
132 {
133 *ppNetCfg = pNetCfg;
134 return S_OK;
135 }
136 else
137 NonStandardLogFlow(("Initialize failed, hr (0x%x)\n", hr));
138 }
139
140 pNetCfg->Release();
141 return hr;
142}
143
144VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinReleaseINetCfg(IN INetCfg *pNetCfg, IN BOOL fHasWriteLock)
145{
146 if (!pNetCfg) /* If network config has been released already, just bail out. */
147 {
148 NonStandardLogFlow(("Warning: No network config given but write lock is set to TRUE\n"));
149 return S_OK;
150 }
151
152 HRESULT hr = pNetCfg->Uninitialize();
153 if (FAILED(hr))
154 {
155 NonStandardLogFlow(("Uninitialize failed, hr (0x%x)\n", hr));
156 /* Try to release the write lock below. */
157 }
158
159 if (fHasWriteLock)
160 {
161 HRESULT hr2 = vboxNetCfgWinINetCfgUnlock(pNetCfg);
162 if (FAILED(hr2))
163 NonStandardLogFlow(("vboxNetCfgWinINetCfgUnlock failed, hr (0x%x)\n", hr2));
164 if (SUCCEEDED(hr))
165 hr = hr2;
166 }
167
168 pNetCfg->Release();
169 return hr;
170}
171
172static HRESULT vboxNetCfgWinGetComponentByGuidEnum(IEnumNetCfgComponent *pEnumNcc,
173 IN const GUID *pGuid,
174 OUT INetCfgComponent **ppNcc)
175{
176 HRESULT hr = pEnumNcc->Reset();
177 if (FAILED(hr))
178 {
179 NonStandardLogFlow(("Reset failed, hr (0x%x)\n", hr));
180 return hr;
181 }
182
183 INetCfgComponent *pNcc;
184 while ((hr = pEnumNcc->Next(1, &pNcc, NULL)) == S_OK)
185 {
186 ULONG uComponentStatus;
187 hr = pNcc->GetDeviceStatus(&uComponentStatus);
188 if (SUCCEEDED(hr))
189 {
190 if (uComponentStatus == 0)
191 {
192 GUID NccGuid;
193 hr = pNcc->GetInstanceGuid(&NccGuid);
194
195 if (SUCCEEDED(hr))
196 {
197 if (NccGuid == *pGuid)
198 {
199 /* found the needed device */
200 *ppNcc = pNcc;
201 break;
202 }
203 }
204 else
205 NonStandardLogFlow(("GetInstanceGuid failed, hr (0x%x)\n", hr));
206 }
207 }
208
209 pNcc->Release();
210 }
211 return hr;
212}
213
214VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGetComponentByGuid(IN INetCfg *pNc,
215 IN const GUID *pguidClass,
216 IN const GUID * pComponentGuid,
217 OUT INetCfgComponent **ppncc)
218{
219 IEnumNetCfgComponent *pEnumNcc;
220 HRESULT hr = pNc->EnumComponents(pguidClass, &pEnumNcc);
221
222 if (SUCCEEDED(hr))
223 {
224 hr = vboxNetCfgWinGetComponentByGuidEnum(pEnumNcc, pComponentGuid, ppncc);
225 if (hr == S_FALSE)
226 {
227 NonStandardLogFlow(("Component not found\n"));
228 }
229 else if (FAILED(hr))
230 {
231 NonStandardLogFlow(("vboxNetCfgWinGetComponentByGuidEnum failed, hr (0x%x)\n", hr));
232 }
233 pEnumNcc->Release();
234 }
235 else
236 NonStandardLogFlow(("EnumComponents failed, hr (0x%x)\n", hr));
237 return hr;
238}
239
240static HRESULT vboxNetCfgWinQueryInstaller(IN INetCfg *pNetCfg, IN const GUID *pguidClass, INetCfgClassSetup **ppSetup)
241{
242 HRESULT hr = pNetCfg->QueryNetCfgClass(pguidClass, IID_INetCfgClassSetup, (void**)ppSetup);
243 if (FAILED(hr))
244 NonStandardLogFlow(("QueryNetCfgClass failed, hr (0x%x)\n", hr));
245 return hr;
246}
247
248VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinInstallComponent(IN INetCfg *pNetCfg, IN LPCWSTR pszwComponentId, IN const GUID *pguidClass,
249 OUT INetCfgComponent **ppComponent)
250{
251 INetCfgClassSetup *pSetup;
252 HRESULT hr = vboxNetCfgWinQueryInstaller(pNetCfg, pguidClass, &pSetup);
253 if (FAILED(hr))
254 {
255 NonStandardLogFlow(("vboxNetCfgWinQueryInstaller failed, hr (0x%x)\n", hr));
256 return hr;
257 }
258
259 OBO_TOKEN Token;
260 ZeroMemory(&Token, sizeof (Token));
261 Token.Type = OBO_USER;
262
263 hr = pSetup->Install(pszwComponentId, &Token,
264 0, /* IN DWORD dwSetupFlags */
265 0, /* IN DWORD dwUpgradeFromBuildNo */
266 NULL, /* IN LPCWSTR pszwAnswerFile */
267 NULL, /* IN LPCWSTR pszwAnswerSections */
268 ppComponent);
269 if (SUCCEEDED(hr))
270 {
271 /* ignore the apply failure */
272 HRESULT tmpHr = pNetCfg->Apply();
273 Assert(tmpHr == S_OK);
274 if (tmpHr != S_OK)
275 NonStandardLogFlow(("Apply failed, hr (0x%x)\n", tmpHr));
276 }
277 else
278 NonStandardLogFlow(("Install failed, hr (0x%x)\n", hr));
279
280 pSetup->Release();
281 return hr;
282}
283
284static HRESULT vboxNetCfgWinInstallInfAndComponent(IN INetCfg *pNetCfg, IN LPCWSTR pszwComponentId, IN const GUID *pguidClass,
285 IN LPCWSTR const *apInfPaths, IN UINT cInfPaths,
286 OUT INetCfgComponent **ppComponent)
287{
288 HRESULT hr = S_OK;
289 UINT cFilesProcessed = 0;
290
291 NonStandardLogFlow(("Installing %u INF files ...\n", cInfPaths));
292
293 for (; cFilesProcessed < cInfPaths; cFilesProcessed++)
294 {
295 NonStandardLogFlow(("Installing INF file \"%ws\" ...\n", apInfPaths[cFilesProcessed]));
296 hr = VBoxDrvCfgInfInstall(apInfPaths[cFilesProcessed]);
297 if (FAILED(hr))
298 {
299 NonStandardLogFlow(("VBoxNetCfgWinInfInstall failed, hr (0x%x)\n", hr));
300 break;
301 }
302 }
303
304 if (SUCCEEDED(hr))
305 {
306 hr = VBoxNetCfgWinInstallComponent(pNetCfg, pszwComponentId, pguidClass, ppComponent);
307 if (FAILED(hr))
308 NonStandardLogFlow(("VBoxNetCfgWinInstallComponent failed, hr (0x%x)\n", hr));
309 }
310
311 if (FAILED(hr))
312 {
313 NonStandardLogFlow(("Installation failed, rolling back installation set ...\n"));
314
315 do
316 {
317 HRESULT hr2 = VBoxDrvCfgInfUninstall(apInfPaths[cFilesProcessed], 0);
318 if (FAILED(hr2))
319 NonStandardLogFlow(("VBoxDrvCfgInfUninstall failed, hr (0x%x)\n", hr2));
320 /* Keep going. */
321 if (!cFilesProcessed)
322 break;
323 } while (cFilesProcessed--);
324
325 NonStandardLogFlow(("Rollback complete\n"));
326 }
327
328 return hr;
329}
330
331VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinUninstallComponent(IN INetCfg *pNetCfg, IN INetCfgComponent *pComponent)
332{
333 GUID GuidClass;
334 HRESULT hr = pComponent->GetClassGuid(&GuidClass);
335 if (FAILED(hr))
336 {
337 NonStandardLogFlow(("GetClassGuid failed, hr (0x%x)\n", hr));
338 return hr;
339 }
340
341 INetCfgClassSetup *pSetup = NULL;
342 hr = vboxNetCfgWinQueryInstaller(pNetCfg, &GuidClass, &pSetup);
343 if (FAILED(hr))
344 {
345 NonStandardLogFlow(("vboxNetCfgWinQueryInstaller failed, hr (0x%x)\n", hr));
346 return hr;
347 }
348
349 OBO_TOKEN Token;
350 ZeroMemory(&Token, sizeof(Token));
351 Token.Type = OBO_USER;
352
353 hr = pSetup->DeInstall(pComponent, &Token, NULL /* OUT LPWSTR *pmszwRefs */);
354 if (SUCCEEDED(hr))
355 {
356 hr = pNetCfg->Apply();
357 if (FAILED(hr))
358 NonStandardLogFlow(("Apply failed, hr (0x%x)\n", hr));
359 }
360 else
361 NonStandardLogFlow(("DeInstall failed, hr (0x%x)\n", hr));
362
363 if (pSetup)
364 pSetup->Release();
365 return hr;
366}
367
368typedef BOOL (*VBOXNETCFGWIN_NETCFGENUM_CALLBACK) (IN INetCfg *pNetCfg, IN INetCfgComponent *pNetCfgComponent, PVOID pContext);
369
370static HRESULT vboxNetCfgWinEnumNetCfgComponents(IN INetCfg *pNetCfg,
371 IN const GUID *pguidClass,
372 VBOXNETCFGWIN_NETCFGENUM_CALLBACK callback,
373 PVOID pContext)
374{
375 IEnumNetCfgComponent *pEnumComponent;
376 HRESULT hr = pNetCfg->EnumComponents(pguidClass, &pEnumComponent);
377 if (SUCCEEDED(hr))
378 {
379 INetCfgComponent *pNetCfgComponent;
380 hr = pEnumComponent->Reset();
381 do
382 {
383 hr = pEnumComponent->Next(1, &pNetCfgComponent, NULL);
384 if (hr == S_OK)
385 {
386// ULONG uComponentStatus;
387// hr = pNcc->GetDeviceStatus(&uComponentStatus);
388// if (SUCCEEDED(hr))
389 BOOL fResult = FALSE;
390 if (pNetCfgComponent)
391 {
392 if (pContext)
393 fResult = callback(pNetCfg, pNetCfgComponent, pContext);
394 pNetCfgComponent->Release();
395 }
396
397 if (!fResult)
398 break;
399 }
400 else
401 {
402 if (hr == S_FALSE)
403 {
404 hr = S_OK;
405 }
406 else
407 NonStandardLogFlow(("Next failed, hr (0x%x)\n", hr));
408 break;
409 }
410 } while (true);
411 pEnumComponent->Release();
412 }
413 return hr;
414}
415
416/*
417 * Forward declarations of functions used in vboxNetCfgWinRemoveAllNetDevicesOfIdCallback.
418 */
419VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGenHostonlyConnectionName(PCWSTR DevName, WCHAR *pBuf, PULONG pcbBuf);
420VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRenameConnection(LPWSTR pGuid, PCWSTR NewName);
421
422static BOOL vboxNetCfgWinRemoveAllNetDevicesOfIdCallback(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pDev, PVOID pContext)
423{
424 SP_REMOVEDEVICE_PARAMS rmdParams;
425 memset(&rmdParams, 0, sizeof(SP_REMOVEDEVICE_PARAMS));
426 rmdParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
427 rmdParams.ClassInstallHeader.InstallFunction = DIF_REMOVE;
428 rmdParams.Scope = DI_REMOVEDEVICE_GLOBAL;
429
430 if (SetupDiSetClassInstallParams(hDevInfo,pDev,
431 &rmdParams.ClassInstallHeader, sizeof(rmdParams)))
432 {
433 if (SetupDiSetSelectedDevice(hDevInfo, pDev))
434 {
435 /* Figure out NetCfgInstanceId. */
436 HKEY hKey = SetupDiOpenDevRegKey(hDevInfo,
437 pDev,
438 DICS_FLAG_GLOBAL,
439 0,
440 DIREG_DRV,
441 KEY_READ);
442 if (hKey == INVALID_HANDLE_VALUE)
443 {
444 NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: SetupDiOpenDevRegKey failed with error %ld\n",
445 GetLastError()));
446 }
447 else
448 {
449 WCHAR wszCfgGuidString[50] = { L'' };
450 DWORD cbSize = sizeof(wszCfgGuidString);
451 DWORD dwValueType;
452 DWORD ret = RegQueryValueExW(hKey, L"NetCfgInstanceId", NULL,
453 &dwValueType, (LPBYTE)wszCfgGuidString, &cbSize);
454 if (ret == ERROR_SUCCESS)
455 {
456 NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: Processing device ID \"%S\"\n",
457 wszCfgGuidString));
458
459 /* Figure out device name. */
460 WCHAR wszDevName[256], wszTempName[256];
461 ULONG cbName = sizeof(wszTempName);
462
463 if (SetupDiGetDeviceRegistryPropertyW(hDevInfo, pDev,
464 SPDRP_FRIENDLYNAME, /* IN DWORD Property,*/
465 NULL, /* OUT PDWORD PropertyRegDataType, OPTIONAL*/
466 (PBYTE)wszDevName, /* OUT PBYTE PropertyBuffer,*/
467 sizeof(wszDevName), /* IN DWORD PropertyBufferSize,*/
468 NULL /* OUT PDWORD RequiredSize OPTIONAL*/))
469 {
470 /*
471 * Rename the connection before removing the device. This will
472 * hopefully prevent an error when we will be attempting
473 * to rename a newly created connection (see @bugref{6740}).
474 */
475 HRESULT hr = VBoxNetCfgWinGenHostonlyConnectionName(wszDevName, wszTempName, &cbName);
476 wcscat_s(wszTempName, sizeof(wszTempName), L" removed");
477 if (SUCCEEDED(hr))
478 hr = VBoxNetCfgWinRenameConnection(wszCfgGuidString, wszTempName);
479 //NonStandardLogFlow(("VBoxNetCfgWinRenameConnection(%S,%S) => 0x%x\n", pWCfgGuidString, TempName, hr_tmp));
480 }
481 else
482 {
483 NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: Failed to get friendly name for device \"%S\"\n",
484 wszCfgGuidString));
485 }
486 }
487 else
488 {
489 NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: Querying instance ID failed with %d\n",
490 ret));
491 }
492
493 RegCloseKey(hKey);
494 }
495
496 if (SetupDiCallClassInstaller(DIF_REMOVE, hDevInfo, pDev))
497 {
498 SP_DEVINSTALL_PARAMS devParams;
499 memset(&devParams, 0, sizeof(SP_DEVINSTALL_PARAMS));
500 devParams.cbSize = sizeof(devParams);
501
502 if (SetupDiGetDeviceInstallParams(hDevInfo, pDev, &devParams))
503 {
504 if ( (devParams.Flags & DI_NEEDRESTART)
505 || (devParams.Flags & DI_NEEDREBOOT))
506 {
507 NonStandardLog(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: A reboot is required\n"));
508 }
509 }
510 else
511 NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: SetupDiGetDeviceInstallParams failed with %ld\n",
512 GetLastError()));
513 }
514 else
515 NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: SetupDiCallClassInstaller failed with %ld\n",
516 GetLastError()));
517 }
518 else
519 NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: SetupDiSetSelectedDevice failed with %ld\n",
520 GetLastError()));
521 }
522 else
523 NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: SetupDiSetClassInstallParams failed with %ld\n",
524 GetLastError()));
525
526 /* Continue enumeration. */
527 return TRUE;
528}
529
530typedef struct VBOXNECTFGWINPROPCHANGE
531{
532 VBOXNECTFGWINPROPCHANGE_TYPE enmPcType;
533 HRESULT hr;
534} VBOXNECTFGWINPROPCHANGE ,*PVBOXNECTFGWINPROPCHANGE;
535
536static BOOL vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pDev, PVOID pContext)
537{
538 PVBOXNECTFGWINPROPCHANGE pPc = (PVBOXNECTFGWINPROPCHANGE)pContext;
539
540 SP_PROPCHANGE_PARAMS PcParams;
541 memset (&PcParams, 0, sizeof (PcParams));
542 PcParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
543 PcParams.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
544 PcParams.Scope = DICS_FLAG_GLOBAL;
545
546 switch(pPc->enmPcType)
547 {
548 case VBOXNECTFGWINPROPCHANGE_TYPE_DISABLE:
549 PcParams.StateChange = DICS_DISABLE;
550 break;
551 case VBOXNECTFGWINPROPCHANGE_TYPE_ENABLE:
552 PcParams.StateChange = DICS_ENABLE;
553 break;
554 default:
555 NonStandardLogFlow(("vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback: Unexpected prop change type: %d\n", pPc->enmPcType));
556 pPc->hr = E_INVALIDARG;
557 return FALSE;
558 }
559
560 if (SetupDiSetClassInstallParams(hDevInfo, pDev, &PcParams.ClassInstallHeader, sizeof(PcParams)))
561 {
562 if (SetupDiSetSelectedDevice(hDevInfo, pDev))
563 {
564 if (SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, hDevInfo, pDev))
565 {
566 SP_DEVINSTALL_PARAMS devParams;
567 devParams.cbSize = sizeof(devParams);
568 if (SetupDiGetDeviceInstallParams(hDevInfo,pDev,&devParams))
569 {
570 if ( (devParams.Flags & DI_NEEDRESTART)
571 || (devParams.Flags & DI_NEEDREBOOT))
572 {
573 NonStandardLog(("vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback: A reboot is required\n"));
574 }
575 }
576 else
577 NonStandardLogFlow(("vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback: SetupDiGetDeviceInstallParams failed with %ld\n",
578 GetLastError()));
579 }
580 else
581 NonStandardLogFlow(("vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback: SetupDiCallClassInstaller failed with %ld\n",
582 GetLastError()));
583 }
584 else
585 NonStandardLogFlow(("SetupDiSetSelectedDevice failed with %ld\n", GetLastError()));
586 }
587 else
588 NonStandardLogFlow(("SetupDiSetClassInstallParams failed with %ld\n", GetLastError()));
589
590 /* Continue enumeration. */
591 return TRUE;
592}
593
594typedef BOOL (*VBOXNETCFGWIN_NETENUM_CALLBACK) (HDEVINFO hDevInfo, PSP_DEVINFO_DATA pDev, PVOID pContext);
595VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinEnumNetDevices(LPCWSTR pwszPnPID,
596 VBOXNETCFGWIN_NETENUM_CALLBACK callback, PVOID pContext)
597{
598 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: Searching for: %S\n", pwszPnPID));
599
600 HRESULT hr;
601 HDEVINFO hDevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET,
602 NULL, /* IN PCTSTR Enumerator, OPTIONAL */
603 NULL, /* IN HWND hwndParent, OPTIONAL */
604 DIGCF_PRESENT, /* IN DWORD Flags,*/
605 NULL, /* IN HDEVINFO DeviceInfoSet, OPTIONAL */
606 NULL, /* IN PCTSTR MachineName, OPTIONAL */
607 NULL /* IN PVOID Reserved */);
608 if (hDevInfo != INVALID_HANDLE_VALUE)
609 {
610 DWORD winEr;
611
612 DWORD dwDevID = 0;
613 size_t cPnPId = wcslen(pwszPnPID);
614
615 PBYTE pBuffer = NULL;
616
617 for (;;)
618 {
619 SP_DEVINFO_DATA Dev;
620 memset(&Dev, 0, sizeof(SP_DEVINFO_DATA));
621 Dev.cbSize = sizeof(SP_DEVINFO_DATA);
622
623 if (!SetupDiEnumDeviceInfo(hDevInfo, dwDevID, &Dev))
624 {
625 winEr = GetLastError();
626 if (winEr == ERROR_NO_MORE_ITEMS)
627 winEr = ERROR_SUCCESS;
628 break;
629 }
630
631 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: Enumerating device %ld ... \n", dwDevID));
632 dwDevID++;
633
634 if (pBuffer)
635 free(pBuffer);
636 pBuffer = NULL;
637 DWORD cbBuffer = 0;
638 DWORD cbRequired = 0;
639
640 if (!SetupDiGetDeviceRegistryPropertyW(hDevInfo, &Dev,
641 SPDRP_HARDWAREID, /* IN DWORD Property */
642 NULL, /* OUT PDWORD PropertyRegDataType OPTIONAL */
643 pBuffer, /* OUT PBYTE PropertyBuffer */
644 cbBuffer, /* IN DWORD PropertyBufferSize */
645 &cbRequired /* OUT PDWORD RequiredSize OPTIONAL */))
646 {
647 winEr = GetLastError();
648 if (winEr != ERROR_INSUFFICIENT_BUFFER)
649 {
650 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: SetupDiGetDeviceRegistryPropertyW (1) failed with %ld\n", winEr));
651 break;
652 }
653
654 pBuffer = (PBYTE)malloc(cbRequired);
655 if (!pBuffer)
656 {
657 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: Out of memory allocating %ld bytes\n",
658 cbRequired));
659 winEr = ERROR_OUTOFMEMORY;
660 break;
661 }
662
663 cbBuffer = cbRequired;
664
665 if (!SetupDiGetDeviceRegistryPropertyW(hDevInfo,&Dev,
666 SPDRP_HARDWAREID, /* IN DWORD Property */
667 NULL, /* OUT PDWORD PropertyRegDataType, OPTIONAL */
668 pBuffer, /* OUT PBYTE PropertyBuffer */
669 cbBuffer, /* IN DWORD PropertyBufferSize */
670 &cbRequired /* OUT PDWORD RequiredSize OPTIONAL */))
671 {
672 winEr = GetLastError();
673 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: SetupDiGetDeviceRegistryPropertyW (2) failed with %ld\n",
674 winEr));
675 break;
676 }
677 }
678
679 PWSTR pCurID = (PWSTR)pBuffer;
680 size_t cCurId = wcslen(pCurID);
681
682 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: Device %ld: %S\n", dwDevID, pCurID));
683
684 if (cCurId >= cPnPId)
685 {
686 pCurID += cCurId - cPnPId;
687 if (!wcsnicmp(pCurID, pwszPnPID, cPnPId))
688 {
689 if (!callback(hDevInfo, &Dev, pContext))
690 break;
691 }
692 }
693 }
694
695 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: Found %ld devices total\n", dwDevID));
696
697 if (pBuffer)
698 free(pBuffer);
699
700 hr = HRESULT_FROM_WIN32(winEr);
701
702 SetupDiDestroyDeviceInfoList(hDevInfo);
703 }
704 else
705 {
706 DWORD winEr = GetLastError();
707 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: SetupDiGetClassDevsExW failed with %ld\n", winEr));
708 hr = HRESULT_FROM_WIN32(winEr);
709 }
710
711 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: Ended with hr (0x%x)\n", hr));
712 return hr;
713}
714
715VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRemoveAllNetDevicesOfId(IN LPCWSTR lpszPnPId)
716{
717 return VBoxNetCfgWinEnumNetDevices(lpszPnPId, vboxNetCfgWinRemoveAllNetDevicesOfIdCallback, NULL);
718}
719
720VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinPropChangeAllNetDevicesOfId(IN LPCWSTR lpszPnPId, VBOXNECTFGWINPROPCHANGE_TYPE enmPcType)
721{
722 VBOXNECTFGWINPROPCHANGE Pc;
723 Pc.enmPcType = enmPcType;
724 Pc.hr = S_OK;
725 HRESULT hr = VBoxNetCfgWinEnumNetDevices(lpszPnPId, vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback, &Pc);
726 if (!SUCCEEDED(hr))
727 {
728 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices failed 0x%x\n", hr));
729 return hr;
730 }
731
732 if (!SUCCEEDED(Pc.hr))
733 {
734 NonStandardLogFlow(("vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback failed 0x%x\n", Pc.hr));
735 return Pc.hr;
736 }
737
738 return S_OK;
739}
740
741/*
742 * logging
743 */
744static VOID DoLogging(LPCSTR szString, ...)
745{
746 LOG_ROUTINE pfnRoutine = (LOG_ROUTINE)(*((void * volatile *)&g_Logger));
747 if (pfnRoutine)
748 {
749 char szBuffer[4096] = {0};
750 va_list va;
751 va_start(va, szString);
752 _vsnprintf(szBuffer, RT_ELEMENTS(szBuffer), szString, va);
753 va_end(va);
754
755 pfnRoutine(szBuffer);
756 }
757}
758
759VBOXNETCFGWIN_DECL(VOID) VBoxNetCfgWinSetLogging(IN LOG_ROUTINE pfnLog)
760{
761 *((void * volatile *)&g_Logger) = pfnLog;
762}
763
764/*
765 * IP configuration API
766 */
767/* network settings config */
768/**
769 * Strong referencing operators. Used as a second argument to ComPtr<>/ComObjPtr<>.
770 */
771template <class C>
772class ComStrongRef
773{
774protected:
775
776 static void addref (C *p) { p->AddRef(); }
777 static void release (C *p) { p->Release(); }
778};
779
780
781/**
782 * Base template for smart COM pointers. Not intended to be used directly.
783 */
784template <class C, template <class> class RefOps = ComStrongRef>
785class ComPtrBase : protected RefOps <C>
786{
787public:
788
789 /* special template to disable AddRef()/Release() */
790 template <class I>
791 class NoAddRefRelease : public I
792 {
793 private:
794#if !defined (VBOX_WITH_XPCOM)
795 STDMETHOD_(ULONG, AddRef)() = 0;
796 STDMETHOD_(ULONG, Release)() = 0;
797#else /* !defined (VBOX_WITH_XPCOM) */
798 NS_IMETHOD_(nsrefcnt) AddRef(void) = 0;
799 NS_IMETHOD_(nsrefcnt) Release(void) = 0;
800#endif /* !defined (VBOX_WITH_XPCOM) */
801 };
802
803protected:
804
805 ComPtrBase () : p (NULL) {}
806 ComPtrBase (const ComPtrBase &that) : p (that.p) { addref(); }
807 ComPtrBase (C *that_p) : p (that_p) { addref(); }
808
809 ~ComPtrBase() { release(); }
810
811 ComPtrBase &operator= (const ComPtrBase &that)
812 {
813 safe_assign (that.p);
814 return *this;
815 }
816
817 ComPtrBase &operator= (C *that_p)
818 {
819 safe_assign (that_p);
820 return *this;
821 }
822
823public:
824
825 void setNull()
826 {
827 release();
828 p = NULL;
829 }
830
831 bool isNull() const
832 {
833 return (p == NULL);
834 }
835
836 bool operator! () const { return isNull(); }
837
838 bool operator< (C* that_p) const { return p < that_p; }
839 bool operator== (C* that_p) const { return p == that_p; }
840
841 template <class I>
842 bool equalsTo (I *aThat) const
843 {
844 return ComPtrEquals (p, aThat);
845 }
846
847 template <class OC>
848 bool equalsTo (const ComPtrBase <OC> &oc) const
849 {
850 return equalsTo ((OC *) oc);
851 }
852
853 /** Intended to pass instances as in parameters to interface methods */
854 operator C* () const { return p; }
855
856 /**
857 * Dereferences the instance (redirects the -> operator to the managed
858 * pointer).
859 */
860 NoAddRefRelease <C> *operator-> () const
861 {
862 AssertMsg (p, ("Managed pointer must not be null\n"));
863 return (NoAddRefRelease <C> *) p;
864 }
865
866 template <class I>
867 HRESULT queryInterfaceTo (I **pp) const
868 {
869 if (pp)
870 {
871 if (p)
872 {
873 return p->QueryInterface (COM_IIDOF (I), (void **) pp);
874 }
875 else
876 {
877 *pp = NULL;
878 return S_OK;
879 }
880 }
881
882 return E_INVALIDARG;
883 }
884
885 /** Intended to pass instances as out parameters to interface methods */
886 C **asOutParam()
887 {
888 setNull();
889 return &p;
890 }
891
892private:
893
894 void addref()
895 {
896 if (p)
897 RefOps <C>::addref (p);
898 }
899
900 void release()
901 {
902 if (p)
903 RefOps <C>::release (p);
904 }
905
906 void safe_assign (C *that_p)
907 {
908 /* be aware of self-assignment */
909 if (that_p)
910 RefOps <C>::addref (that_p);
911 release();
912 p = that_p;
913 }
914
915 C *p;
916};
917
918/**
919 * Smart COM pointer wrapper that automatically manages refcounting of
920 * interface pointers.
921 *
922 * @param I COM interface class
923 */
924template <class I, template <class> class RefOps = ComStrongRef>
925class ComPtr : public ComPtrBase <I, RefOps>
926{
927 typedef ComPtrBase <I, RefOps> Base;
928
929public:
930
931 ComPtr () : Base() {}
932 ComPtr (const ComPtr &that) : Base(that) {}
933 ComPtr &operator= (const ComPtr &that)
934 {
935 Base::operator= (that);
936 return *this;
937 }
938
939 template <class OI>
940 ComPtr (OI *that_p) : Base () { operator= (that_p); }
941
942 /* specialization for I */
943 ComPtr (I *that_p) : Base (that_p) {}
944
945 template <class OC>
946 ComPtr (const ComPtr <OC, RefOps> &oc) : Base () { operator= ((OC *) oc); }
947
948 template <class OI>
949 ComPtr &operator= (OI *that_p)
950 {
951 if (that_p)
952 that_p->QueryInterface (COM_IIDOF (I), (void **) Base::asOutParam());
953 else
954 Base::setNull();
955 return *this;
956 }
957
958 /* specialization for I */
959 ComPtr &operator=(I *that_p)
960 {
961 Base::operator= (that_p);
962 return *this;
963 }
964
965 template <class OC>
966 ComPtr &operator= (const ComPtr <OC, RefOps> &oc)
967 {
968 return operator= ((OC *) oc);
969 }
970};
971
972static HRESULT netIfWinFindAdapterClassById(IWbemServices * pSvc, const GUID * pGuid, IWbemClassObject **pAdapterConfig)
973{
974 HRESULT hr;
975 WCHAR wszQuery[256];
976 WCHAR wszGuid[50];
977
978 int length = StringFromGUID2(*pGuid, wszGuid, RT_ELEMENTS(wszGuid));
979 if (length)
980 {
981 swprintf(wszQuery, L"SELECT * FROM Win32_NetworkAdapterConfiguration WHERE SettingID = \"%s\"", wszGuid);
982 IEnumWbemClassObject* pEnumerator = NULL;
983 hr = pSvc->ExecQuery(bstr_t("WQL"), bstr_t(wszQuery), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
984 NULL, &pEnumerator);
985 if (SUCCEEDED(hr))
986 {
987 if (pEnumerator)
988 {
989 IWbemClassObject *pclsObj;
990 ULONG uReturn = 0;
991 hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
992 NonStandardLogFlow(("netIfWinFindAdapterClassById: IEnumWbemClassObject::Next -> hr=0x%x pclsObj=%p uReturn=%u 42=%u\n",
993 hr, (void *)pclsObj, uReturn, 42));
994 if (SUCCEEDED(hr))
995 {
996 if (uReturn && pclsObj != NULL)
997 {
998 *pAdapterConfig = pclsObj;
999 pEnumerator->Release();
1000 NonStandardLogFlow(("netIfWinFindAdapterClassById: S_OK and %p\n", *pAdapterConfig));
1001 return S_OK;
1002 }
1003
1004 hr = E_FAIL;
1005 }
1006
1007 pEnumerator->Release();
1008 }
1009 else
1010 {
1011 NonStandardLogFlow(("ExecQuery returned no enumerator\n"));
1012 hr = E_FAIL;
1013 }
1014 }
1015 else
1016 NonStandardLogFlow(("ExecQuery failed (0x%x)\n", hr));
1017 }
1018 else
1019 {
1020 DWORD winEr = GetLastError();
1021 hr = HRESULT_FROM_WIN32( winEr );
1022 if (SUCCEEDED(hr))
1023 hr = E_FAIL;
1024 NonStandardLogFlow(("StringFromGUID2 failed winEr=%u, hr=0x%x\n", winEr, hr));
1025 }
1026
1027 NonStandardLogFlow(("netIfWinFindAdapterClassById: 0x%x and %p\n", hr, *pAdapterConfig));
1028 return hr;
1029}
1030
1031static HRESULT netIfWinIsHostOnly(IWbemClassObject * pAdapterConfig, BOOL * pbIsHostOnly)
1032{
1033 VARIANT vtServiceName;
1034 BOOL bIsHostOnly = FALSE;
1035 VariantInit(&vtServiceName);
1036
1037 HRESULT hr = pAdapterConfig->Get(L"ServiceName", 0 /*lFlags*/, &vtServiceName, NULL /*pvtType*/, NULL /*plFlavor*/);
1038 if (SUCCEEDED(hr))
1039 {
1040 *pbIsHostOnly = bstr_t(vtServiceName.bstrVal) == bstr_t("VBoxNetAdp");
1041
1042 VariantClear(&vtServiceName);
1043 }
1044
1045 return hr;
1046}
1047
1048static HRESULT netIfWinGetIpSettings(IWbemClassObject * pAdapterConfig, ULONG *pIpv4, ULONG *pMaskv4)
1049{
1050 VARIANT vtIp;
1051 HRESULT hr;
1052 VariantInit(&vtIp);
1053
1054 *pIpv4 = 0;
1055 *pMaskv4 = 0;
1056
1057 hr = pAdapterConfig->Get(L"IPAddress", 0, &vtIp, 0, 0);
1058 if (SUCCEEDED(hr))
1059 {
1060 if (vtIp.vt == (VT_ARRAY | VT_BSTR))
1061 {
1062 VARIANT vtMask;
1063 VariantInit(&vtMask);
1064 hr = pAdapterConfig->Get(L"IPSubnet", 0, &vtMask, 0, 0);
1065 if (SUCCEEDED(hr))
1066 {
1067 if (vtMask.vt == (VT_ARRAY | VT_BSTR))
1068 {
1069 SAFEARRAY * pIpArray = vtIp.parray;
1070 SAFEARRAY * pMaskArray = vtMask.parray;
1071 if (pIpArray && pMaskArray)
1072 {
1073 BSTR pCurIp;
1074 BSTR pCurMask;
1075 for (LONG i = 0;
1076 SafeArrayGetElement(pIpArray, &i, (PVOID)&pCurIp) == S_OK
1077 && SafeArrayGetElement(pMaskArray, &i, (PVOID)&pCurMask) == S_OK;
1078 i++)
1079 {
1080 bstr_t ip(pCurIp);
1081
1082 ULONG Ipv4 = inet_addr((char*)(ip));
1083 if (Ipv4 != INADDR_NONE)
1084 {
1085 *pIpv4 = Ipv4;
1086 bstr_t mask(pCurMask);
1087 *pMaskv4 = inet_addr((char*)(mask));
1088 break;
1089 }
1090 }
1091 }
1092 }
1093 else
1094 {
1095 *pIpv4 = 0;
1096 *pMaskv4 = 0;
1097 }
1098
1099 VariantClear(&vtMask);
1100 }
1101 }
1102 else
1103 {
1104 *pIpv4 = 0;
1105 *pMaskv4 = 0;
1106 }
1107
1108 VariantClear(&vtIp);
1109 }
1110
1111 return hr;
1112}
1113
1114
1115static HRESULT netIfWinHasIpSettings(IWbemClassObject * pAdapterConfig, SAFEARRAY * pCheckIp, SAFEARRAY * pCheckMask, bool *pFound)
1116{
1117 VARIANT vtIp;
1118 HRESULT hr;
1119 VariantInit(&vtIp);
1120
1121 *pFound = false;
1122
1123 hr = pAdapterConfig->Get(L"IPAddress", 0, &vtIp, 0, 0);
1124 if (SUCCEEDED(hr))
1125 {
1126 VARIANT vtMask;
1127 VariantInit(&vtMask);
1128 hr = pAdapterConfig->Get(L"IPSubnet", 0, &vtMask, 0, 0);
1129 if (SUCCEEDED(hr))
1130 {
1131 SAFEARRAY * pIpArray = vtIp.parray;
1132 SAFEARRAY * pMaskArray = vtMask.parray;
1133 if (pIpArray && pMaskArray)
1134 {
1135 BSTR pIp, pMask;
1136 for (LONG k = 0;
1137 SafeArrayGetElement(pCheckIp, &k, (PVOID)&pIp) == S_OK
1138 && SafeArrayGetElement(pCheckMask, &k, (PVOID)&pMask) == S_OK;
1139 k++)
1140 {
1141 BSTR pCurIp;
1142 BSTR pCurMask;
1143 for (LONG i = 0;
1144 SafeArrayGetElement(pIpArray, &i, (PVOID)&pCurIp) == S_OK
1145 && SafeArrayGetElement(pMaskArray, &i, (PVOID)&pCurMask) == S_OK;
1146 i++)
1147 {
1148 if (!wcsicmp(pCurIp, pIp))
1149 {
1150 if (!wcsicmp(pCurMask, pMask))
1151 *pFound = true;
1152 break;
1153 }
1154 }
1155 }
1156 }
1157
1158
1159 VariantClear(&vtMask);
1160 }
1161
1162 VariantClear(&vtIp);
1163 }
1164
1165 return hr;
1166}
1167
1168static HRESULT netIfWinWaitIpSettings(IWbemServices *pSvc, const GUID * pGuid, SAFEARRAY * pCheckIp, SAFEARRAY * pCheckMask, ULONG sec2Wait, bool *pFound)
1169{
1170 /* on Vista we need to wait for the address to get applied */
1171 /* wait for the address to appear in the list */
1172 HRESULT hr = S_OK;
1173 ULONG i;
1174 *pFound = false;
1175 ComPtr <IWbemClassObject> pAdapterConfig;
1176 for (i = 0;
1177 (hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam())) == S_OK
1178 && (hr = netIfWinHasIpSettings(pAdapterConfig, pCheckIp, pCheckMask, pFound)) == S_OK
1179 && !(*pFound)
1180 && i < sec2Wait/6;
1181 i++)
1182 {
1183 Sleep(6000);
1184 }
1185
1186 return hr;
1187}
1188
1189static HRESULT netIfWinCreateIWbemServices(IWbemServices ** ppSvc)
1190{
1191 IWbemLocator *pLoc = NULL;
1192 HRESULT hr = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pLoc);
1193 if (SUCCEEDED(hr))
1194 {
1195 IWbemServices *pSvc = NULL;
1196 hr = pLoc->ConnectServer(bstr_t(L"ROOT\\CIMV2"), /* [in] const BSTR strNetworkResource */
1197 NULL, /* [in] const BSTR strUser */
1198 NULL, /* [in] const BSTR strPassword */
1199 0, /* [in] const BSTR strLocale */
1200 NULL, /* [in] LONG lSecurityFlags */
1201 0, /* [in] const BSTR strAuthority */
1202 0, /* [in] IWbemContext* pCtx */
1203 &pSvc /* [out] IWbemServices** ppNamespace */);
1204 if (SUCCEEDED(hr))
1205 {
1206 hr = CoSetProxyBlanket(pSvc, /* IUnknown * pProxy */
1207 RPC_C_AUTHN_WINNT, /* DWORD dwAuthnSvc */
1208 RPC_C_AUTHZ_NONE, /* DWORD dwAuthzSvc */
1209 NULL, /* WCHAR * pServerPrincName */
1210 RPC_C_AUTHN_LEVEL_CALL, /* DWORD dwAuthnLevel */
1211 RPC_C_IMP_LEVEL_IMPERSONATE, /* DWORD dwImpLevel */
1212 NULL, /* RPC_AUTH_IDENTITY_HANDLE pAuthInfo */
1213 EOAC_NONE /* DWORD dwCapabilities */
1214 );
1215 if (SUCCEEDED(hr))
1216 {
1217 *ppSvc = pSvc;
1218 /* do not need it any more */
1219 pLoc->Release();
1220 return hr;
1221 }
1222 else
1223 NonStandardLogFlow(("CoSetProxyBlanket failed, hr (0x%x)\n", hr));
1224
1225 pSvc->Release();
1226 }
1227 else
1228 NonStandardLogFlow(("ConnectServer failed, hr (0x%x)\n", hr));
1229 pLoc->Release();
1230 }
1231 else
1232 NonStandardLogFlow(("CoCreateInstance failed, hr (0x%x)\n", hr));
1233 return hr;
1234}
1235
1236static HRESULT netIfWinAdapterConfigPath(IWbemClassObject *pObj, BSTR * pStr)
1237{
1238 VARIANT index;
1239 HRESULT hr = pObj->Get(L"Index", 0, &index, 0, 0);
1240 if (SUCCEEDED(hr))
1241 {
1242 WCHAR strIndex[8];
1243 swprintf(strIndex, L"%u", index.uintVal);
1244 *pStr = (bstr_t(L"Win32_NetworkAdapterConfiguration.Index='") + strIndex + "'").copy();
1245 }
1246 else
1247 NonStandardLogFlow(("Get failed, hr (0x%x)\n", hr));
1248 return hr;
1249}
1250
1251static HRESULT netIfExecMethod(IWbemServices * pSvc, IWbemClassObject *pClass, BSTR ObjPath,
1252 BSTR MethodName, LPWSTR *pArgNames, LPVARIANT *pArgs, UINT cArgs,
1253 IWbemClassObject** ppOutParams
1254 )
1255{
1256 HRESULT hr = S_OK;
1257 ComPtr<IWbemClassObject> pInParamsDefinition;
1258 ComPtr<IWbemClassObject> pClassInstance;
1259
1260 if (cArgs)
1261 {
1262 hr = pClass->GetMethod(MethodName, 0, pInParamsDefinition.asOutParam(), NULL);
1263 if (SUCCEEDED(hr))
1264 {
1265 hr = pInParamsDefinition->SpawnInstance(0, pClassInstance.asOutParam());
1266 if (SUCCEEDED(hr))
1267 {
1268 for (UINT i = 0; i < cArgs; i++)
1269 {
1270 hr = pClassInstance->Put(pArgNames[i], 0,
1271 pArgs[i], 0);
1272 if (FAILED(hr))
1273 break;
1274 }
1275 }
1276 }
1277 }
1278
1279 if (SUCCEEDED(hr))
1280 {
1281 IWbemClassObject* pOutParams = NULL;
1282 hr = pSvc->ExecMethod(ObjPath, MethodName, 0, NULL, pClassInstance, &pOutParams, NULL);
1283 if (SUCCEEDED(hr))
1284 {
1285 *ppOutParams = pOutParams;
1286 }
1287 }
1288
1289 return hr;
1290}
1291
1292static HRESULT netIfWinCreateIpArray(SAFEARRAY **ppArray, in_addr* aIp, UINT cIp)
1293{
1294 HRESULT hr;
1295 SAFEARRAY * pIpArray = SafeArrayCreateVector(VT_BSTR, 0, cIp);
1296 if (pIpArray)
1297 {
1298 for (UINT i = 0; i < cIp; i++)
1299 {
1300 char* addr = inet_ntoa(aIp[i]);
1301 BSTR val = bstr_t(addr).copy();
1302 long aIndex[1];
1303 aIndex[0] = i;
1304 hr = SafeArrayPutElement(pIpArray, aIndex, val);
1305 if (FAILED(hr))
1306 {
1307 SysFreeString(val);
1308 SafeArrayDestroy(pIpArray);
1309 break;
1310 }
1311 }
1312
1313 if (SUCCEEDED(hr))
1314 {
1315 *ppArray = pIpArray;
1316 }
1317 }
1318 else
1319 hr = HRESULT_FROM_WIN32(GetLastError());
1320
1321 return hr;
1322}
1323
1324static HRESULT netIfWinCreateIpArrayV4V6(SAFEARRAY **ppArray, BSTR Ip)
1325{
1326 HRESULT hr;
1327 SAFEARRAY *pIpArray = SafeArrayCreateVector(VT_BSTR, 0, 1);
1328 if (pIpArray)
1329 {
1330 BSTR val = bstr_t(Ip, false).copy();
1331 long aIndex[1];
1332 aIndex[0] = 0;
1333 hr = SafeArrayPutElement(pIpArray, aIndex, val);
1334 if (FAILED(hr))
1335 {
1336 SysFreeString(val);
1337 SafeArrayDestroy(pIpArray);
1338 }
1339
1340 if (SUCCEEDED(hr))
1341 {
1342 *ppArray = pIpArray;
1343 }
1344 }
1345 else
1346 hr = HRESULT_FROM_WIN32(GetLastError());
1347
1348 return hr;
1349}
1350
1351
1352static HRESULT netIfWinCreateIpArrayVariantV4(VARIANT * pIpAddresses, in_addr* aIp, UINT cIp)
1353{
1354 HRESULT hr;
1355 VariantInit(pIpAddresses);
1356 pIpAddresses->vt = VT_ARRAY | VT_BSTR;
1357 SAFEARRAY *pIpArray;
1358 hr = netIfWinCreateIpArray(&pIpArray, aIp, cIp);
1359 if (SUCCEEDED(hr))
1360 {
1361 pIpAddresses->parray = pIpArray;
1362 }
1363 return hr;
1364}
1365
1366static HRESULT netIfWinCreateIpArrayVariantV4V6(VARIANT * pIpAddresses, BSTR Ip)
1367{
1368 HRESULT hr;
1369 VariantInit(pIpAddresses);
1370 pIpAddresses->vt = VT_ARRAY | VT_BSTR;
1371 SAFEARRAY *pIpArray;
1372 hr = netIfWinCreateIpArrayV4V6(&pIpArray, Ip);
1373 if (SUCCEEDED(hr))
1374 {
1375 pIpAddresses->parray = pIpArray;
1376 }
1377 return hr;
1378}
1379
1380static HRESULT netIfWinEnableStatic(IWbemServices * pSvc, const GUID * pGuid, BSTR ObjPath, VARIANT * pIp, VARIANT * pMask)
1381{
1382 ComPtr<IWbemClassObject> pClass;
1383 BSTR ClassName = SysAllocString(L"Win32_NetworkAdapterConfiguration");
1384 HRESULT hr;
1385 if (ClassName)
1386 {
1387 hr = pSvc->GetObject(ClassName, 0, NULL, pClass.asOutParam(), NULL);
1388 if (SUCCEEDED(hr))
1389 {
1390 LPWSTR argNames[] = {L"IPAddress", L"SubnetMask"};
1391 LPVARIANT args[] = {pIp, pMask};
1392 ComPtr<IWbemClassObject> pOutParams;
1393
1394 hr = netIfExecMethod(pSvc, pClass, ObjPath, bstr_t(L"EnableStatic"), argNames, args, 2, pOutParams.asOutParam());
1395 if (SUCCEEDED(hr))
1396 {
1397 VARIANT varReturnValue;
1398 hr = pOutParams->Get(bstr_t(L"ReturnValue"), 0,
1399 &varReturnValue, NULL, 0);
1400 Assert(SUCCEEDED(hr));
1401 if (SUCCEEDED(hr))
1402 {
1403// Assert(varReturnValue.vt == VT_UINT);
1404 int winEr = varReturnValue.uintVal;
1405 switch (winEr)
1406 {
1407 case 0:
1408 {
1409 hr = S_OK;
1410// bool bFound;
1411// HRESULT tmpHr = netIfWinWaitIpSettings(pSvc, pGuid, pIp->parray, pMask->parray, 180, &bFound);
1412 }
1413 break;
1414 default:
1415 hr = HRESULT_FROM_WIN32( winEr );
1416 break;
1417 }
1418 }
1419 }
1420 }
1421 SysFreeString(ClassName);
1422 }
1423 else
1424 hr = HRESULT_FROM_WIN32(GetLastError());
1425
1426 return hr;
1427}
1428
1429
1430static HRESULT netIfWinEnableStaticV4(IWbemServices * pSvc, const GUID * pGuid, BSTR ObjPath, in_addr* aIp, in_addr * aMask, UINT cIp)
1431{
1432 VARIANT ipAddresses;
1433 HRESULT hr = netIfWinCreateIpArrayVariantV4(&ipAddresses, aIp, cIp);
1434 if (SUCCEEDED(hr))
1435 {
1436 VARIANT ipMasks;
1437 hr = netIfWinCreateIpArrayVariantV4(&ipMasks, aMask, cIp);
1438 if (SUCCEEDED(hr))
1439 {
1440 hr = netIfWinEnableStatic(pSvc, pGuid, ObjPath, &ipAddresses, &ipMasks);
1441 VariantClear(&ipMasks);
1442 }
1443 VariantClear(&ipAddresses);
1444 }
1445 return hr;
1446}
1447
1448static HRESULT netIfWinEnableStaticV4V6(IWbemServices * pSvc, const GUID * pGuid, BSTR ObjPath, BSTR Ip, BSTR Mask)
1449{
1450 VARIANT ipAddresses;
1451 HRESULT hr = netIfWinCreateIpArrayVariantV4V6(&ipAddresses, Ip);
1452 if (SUCCEEDED(hr))
1453 {
1454 VARIANT ipMasks;
1455 hr = netIfWinCreateIpArrayVariantV4V6(&ipMasks, Mask);
1456 if (SUCCEEDED(hr))
1457 {
1458 hr = netIfWinEnableStatic(pSvc, pGuid, ObjPath, &ipAddresses, &ipMasks);
1459 VariantClear(&ipMasks);
1460 }
1461 VariantClear(&ipAddresses);
1462 }
1463 return hr;
1464}
1465
1466/* win API allows to set gw metrics as well, we are not setting them */
1467static HRESULT netIfWinSetGateways(IWbemServices * pSvc, BSTR ObjPath, VARIANT * pGw)
1468{
1469 ComPtr<IWbemClassObject> pClass;
1470 BSTR ClassName = SysAllocString(L"Win32_NetworkAdapterConfiguration");
1471 HRESULT hr;
1472 if (ClassName)
1473 {
1474 hr = pSvc->GetObject(ClassName, 0, NULL, pClass.asOutParam(), NULL);
1475 if (SUCCEEDED(hr))
1476 {
1477 LPWSTR argNames[] = {L"DefaultIPGateway"};
1478 LPVARIANT args[] = {pGw};
1479 ComPtr<IWbemClassObject> pOutParams;
1480
1481 hr = netIfExecMethod(pSvc, pClass, ObjPath, bstr_t(L"SetGateways"), argNames, args, 1, pOutParams.asOutParam());
1482 if (SUCCEEDED(hr))
1483 {
1484 VARIANT varReturnValue;
1485 hr = pOutParams->Get(bstr_t(L"ReturnValue"), 0, &varReturnValue, NULL, 0);
1486 Assert(SUCCEEDED(hr));
1487 if (SUCCEEDED(hr))
1488 {
1489// Assert(varReturnValue.vt == VT_UINT);
1490 int winEr = varReturnValue.uintVal;
1491 switch (winEr)
1492 {
1493 case 0:
1494 hr = S_OK;
1495 break;
1496 default:
1497 hr = HRESULT_FROM_WIN32( winEr );
1498 break;
1499 }
1500 }
1501 }
1502 }
1503 SysFreeString(ClassName);
1504 }
1505 else
1506 hr = HRESULT_FROM_WIN32(GetLastError());
1507
1508 return hr;
1509}
1510
1511/* win API allows to set gw metrics as well, we are not setting them */
1512static HRESULT netIfWinSetGatewaysV4(IWbemServices * pSvc, BSTR ObjPath, in_addr* aGw, UINT cGw)
1513{
1514 VARIANT gwais;
1515 HRESULT hr = netIfWinCreateIpArrayVariantV4(&gwais, aGw, cGw);
1516 if (SUCCEEDED(hr))
1517 {
1518 netIfWinSetGateways(pSvc, ObjPath, &gwais);
1519 VariantClear(&gwais);
1520 }
1521 return hr;
1522}
1523
1524/* win API allows to set gw metrics as well, we are not setting them */
1525static HRESULT netIfWinSetGatewaysV4V6(IWbemServices * pSvc, BSTR ObjPath, BSTR Gw)
1526{
1527 VARIANT vGw;
1528 HRESULT hr = netIfWinCreateIpArrayVariantV4V6(&vGw, Gw);
1529 if (SUCCEEDED(hr))
1530 {
1531 netIfWinSetGateways(pSvc, ObjPath, &vGw);
1532 VariantClear(&vGw);
1533 }
1534 return hr;
1535}
1536
1537static HRESULT netIfWinEnableDHCP(IWbemServices * pSvc, BSTR ObjPath)
1538{
1539 ComPtr<IWbemClassObject> pClass;
1540 BSTR ClassName = SysAllocString(L"Win32_NetworkAdapterConfiguration");
1541 HRESULT hr;
1542 if (ClassName)
1543 {
1544 hr = pSvc->GetObject(ClassName, 0, NULL, pClass.asOutParam(), NULL);
1545 if (SUCCEEDED(hr))
1546 {
1547 ComPtr<IWbemClassObject> pOutParams;
1548
1549 hr = netIfExecMethod(pSvc, pClass, ObjPath, bstr_t(L"EnableDHCP"), NULL, NULL, 0, pOutParams.asOutParam());
1550 if (SUCCEEDED(hr))
1551 {
1552 VARIANT varReturnValue;
1553 hr = pOutParams->Get(bstr_t(L"ReturnValue"), 0,
1554 &varReturnValue, NULL, 0);
1555 Assert(SUCCEEDED(hr));
1556 if (SUCCEEDED(hr))
1557 {
1558// Assert(varReturnValue.vt == VT_UINT);
1559 int winEr = varReturnValue.uintVal;
1560 switch (winEr)
1561 {
1562 case 0:
1563 hr = S_OK;
1564 break;
1565 default:
1566 hr = HRESULT_FROM_WIN32( winEr );
1567 break;
1568 }
1569 }
1570 }
1571 }
1572 SysFreeString(ClassName);
1573 }
1574 else
1575 hr = HRESULT_FROM_WIN32(GetLastError());
1576
1577 return hr;
1578}
1579
1580static HRESULT netIfWinDhcpRediscover(IWbemServices * pSvc, BSTR ObjPath)
1581{
1582 ComPtr<IWbemClassObject> pClass;
1583 BSTR ClassName = SysAllocString(L"Win32_NetworkAdapterConfiguration");
1584 HRESULT hr;
1585 if (ClassName)
1586 {
1587 hr = pSvc->GetObject(ClassName, 0, NULL, pClass.asOutParam(), NULL);
1588 if (SUCCEEDED(hr))
1589 {
1590 ComPtr<IWbemClassObject> pOutParams;
1591
1592 hr = netIfExecMethod(pSvc, pClass, ObjPath, bstr_t(L"ReleaseDHCPLease"), NULL, NULL, 0, pOutParams.asOutParam());
1593 if (SUCCEEDED(hr))
1594 {
1595 VARIANT varReturnValue;
1596 hr = pOutParams->Get(bstr_t(L"ReturnValue"), 0, &varReturnValue, NULL, 0);
1597 Assert(SUCCEEDED(hr));
1598 if (SUCCEEDED(hr))
1599 {
1600// Assert(varReturnValue.vt == VT_UINT);
1601 int winEr = varReturnValue.uintVal;
1602 if (winEr == 0)
1603 {
1604 hr = netIfExecMethod(pSvc, pClass, ObjPath, bstr_t(L"RenewDHCPLease"), NULL, NULL, 0, pOutParams.asOutParam());
1605 if (SUCCEEDED(hr))
1606 {
1607 VARIANT varReturnValue;
1608 hr = pOutParams->Get(bstr_t(L"ReturnValue"), 0, &varReturnValue, NULL, 0);
1609 Assert(SUCCEEDED(hr));
1610 if (SUCCEEDED(hr))
1611 {
1612 // Assert(varReturnValue.vt == VT_UINT);
1613 int winEr = varReturnValue.uintVal;
1614 if (winEr == 0)
1615 hr = S_OK;
1616 else
1617 hr = HRESULT_FROM_WIN32( winEr );
1618 }
1619 }
1620 }
1621 else
1622 hr = HRESULT_FROM_WIN32( winEr );
1623 }
1624 }
1625 }
1626 SysFreeString(ClassName);
1627 }
1628 else
1629 hr = HRESULT_FROM_WIN32(GetLastError());
1630
1631 return hr;
1632}
1633
1634static HRESULT vboxNetCfgWinIsDhcpEnabled(IWbemClassObject * pAdapterConfig, BOOL *pEnabled)
1635{
1636 VARIANT vtEnabled;
1637 HRESULT hr = pAdapterConfig->Get(L"DHCPEnabled", 0, &vtEnabled, 0, 0);
1638 if (SUCCEEDED(hr))
1639 *pEnabled = vtEnabled.boolVal;
1640 return hr;
1641}
1642
1643VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGetAdapterSettings(IN const GUID * pGuid, OUT PADAPTER_SETTINGS pSettings)
1644{
1645 HRESULT hr;
1646 ComPtr <IWbemServices> pSvc;
1647 hr = netIfWinCreateIWbemServices(pSvc.asOutParam());
1648 if (SUCCEEDED(hr))
1649 {
1650 ComPtr<IWbemClassObject> pAdapterConfig;
1651 hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam());
1652 if (SUCCEEDED(hr))
1653 {
1654 hr = vboxNetCfgWinIsDhcpEnabled(pAdapterConfig, &pSettings->bDhcp);
1655 if (SUCCEEDED(hr))
1656 hr = netIfWinGetIpSettings(pAdapterConfig, &pSettings->ip, &pSettings->mask);
1657 }
1658 }
1659
1660 return hr;
1661}
1662
1663VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinIsDhcpEnabled(const GUID * pGuid, BOOL *pEnabled)
1664{
1665 HRESULT hr;
1666 ComPtr <IWbemServices> pSvc;
1667 hr = netIfWinCreateIWbemServices(pSvc.asOutParam());
1668 if (SUCCEEDED(hr))
1669 {
1670 ComPtr<IWbemClassObject> pAdapterConfig;
1671 hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam());
1672 if (SUCCEEDED(hr))
1673 {
1674 VARIANT vtEnabled;
1675 hr = pAdapterConfig->Get(L"DHCPEnabled", 0, &vtEnabled, 0, 0);
1676 if (SUCCEEDED(hr))
1677 *pEnabled = vtEnabled.boolVal;
1678 }
1679 }
1680
1681 return hr;
1682}
1683
1684VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinEnableStaticIpConfig(IN const GUID *pGuid, IN ULONG ip, IN ULONG mask)
1685{
1686 NonStandardLogFlow(("VBoxNetCfgWinEnableStaticIpConfig: ip=0x%x mask=0x%x", ip, mask));
1687 ComPtr<IWbemServices> pSvc;
1688 HRESULT hr = netIfWinCreateIWbemServices(pSvc.asOutParam());
1689 if (SUCCEEDED(hr))
1690 {
1691 ComPtr<IWbemClassObject> pAdapterConfig;
1692 hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam());
1693 if (SUCCEEDED(hr))
1694 {
1695 BOOL bIsHostOnly;
1696 hr = netIfWinIsHostOnly(pAdapterConfig, &bIsHostOnly);
1697 if (SUCCEEDED(hr))
1698 {
1699 if (bIsHostOnly)
1700 {
1701 in_addr aIp[1];
1702 in_addr aMask[1];
1703 aIp[0].S_un.S_addr = ip;
1704 aMask[0].S_un.S_addr = mask;
1705
1706 BSTR ObjPath;
1707 hr = netIfWinAdapterConfigPath(pAdapterConfig, &ObjPath);
1708 if (SUCCEEDED(hr))
1709 {
1710 hr = netIfWinEnableStaticV4(pSvc, pGuid, ObjPath, aIp, aMask, ip != 0 ? 1 : 0);
1711 if (SUCCEEDED(hr))
1712 {
1713#if 0
1714 in_addr aGw[1];
1715 aGw[0].S_un.S_addr = gw;
1716 hr = netIfWinSetGatewaysV4(pSvc, ObjPath, aGw, 1);
1717 if (SUCCEEDED(hr))
1718#endif
1719 {
1720 }
1721 }
1722 SysFreeString(ObjPath);
1723 }
1724 }
1725 else
1726 {
1727 hr = E_FAIL;
1728 }
1729 }
1730 }
1731 }
1732
1733 NonStandardLogFlow(("VBoxNetCfgWinEnableStaticIpConfig: returns 0x%x", hr));
1734 return hr;
1735}
1736
1737#if 0
1738static HRESULT netIfEnableStaticIpConfigV6(const GUID *pGuid, IN_BSTR aIPV6Address, IN_BSTR aIPV6Mask, IN_BSTR aIPV6DefaultGateway)
1739{
1740 HRESULT hr;
1741 ComPtr <IWbemServices> pSvc;
1742 hr = netIfWinCreateIWbemServices(pSvc.asOutParam());
1743 if (SUCCEEDED(hr))
1744 {
1745 ComPtr<IWbemClassObject> pAdapterConfig;
1746 hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam());
1747 if (SUCCEEDED(hr))
1748 {
1749 BSTR ObjPath;
1750 hr = netIfWinAdapterConfigPath(pAdapterConfig, &ObjPath);
1751 if (SUCCEEDED(hr))
1752 {
1753 hr = netIfWinEnableStaticV4V6(pSvc, pAdapterConfig, ObjPath, aIPV6Address, aIPV6Mask);
1754 if (SUCCEEDED(hr))
1755 {
1756 if (aIPV6DefaultGateway)
1757 {
1758 hr = netIfWinSetGatewaysV4V6(pSvc, ObjPath, aIPV6DefaultGateway);
1759 }
1760 if (SUCCEEDED(hr))
1761 {
1762// hr = netIfWinUpdateConfig(pIf);
1763 }
1764 }
1765 SysFreeString(ObjPath);
1766 }
1767 }
1768 }
1769
1770 return SUCCEEDED(hr) ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
1771}
1772
1773static HRESULT netIfEnableStaticIpConfigV6(const GUID *pGuid, IN_BSTR aIPV6Address, ULONG aIPV6MaskPrefixLength)
1774{
1775 RTNETADDRIPV6 Mask;
1776 int rc = prefixLength2IPv6Address(aIPV6MaskPrefixLength, &Mask);
1777 if (RT_SUCCESS(rc))
1778 {
1779 Bstr maskStr = composeIPv6Address(&Mask);
1780 rc = netIfEnableStaticIpConfigV6(pGuid, aIPV6Address, maskStr, NULL);
1781 }
1782 return rc;
1783}
1784#endif
1785
1786VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinEnableDynamicIpConfig(IN const GUID *pGuid)
1787{
1788 HRESULT hr;
1789 ComPtr <IWbemServices> pSvc;
1790 hr = netIfWinCreateIWbemServices(pSvc.asOutParam());
1791 if (SUCCEEDED(hr))
1792 {
1793 ComPtr<IWbemClassObject> pAdapterConfig;
1794 hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam());
1795 if (SUCCEEDED(hr))
1796 {
1797 BOOL bIsHostOnly;
1798 hr = netIfWinIsHostOnly(pAdapterConfig, &bIsHostOnly);
1799 if (SUCCEEDED(hr))
1800 {
1801 if (bIsHostOnly)
1802 {
1803 BSTR ObjPath;
1804 hr = netIfWinAdapterConfigPath(pAdapterConfig, &ObjPath);
1805 if (SUCCEEDED(hr))
1806 {
1807 hr = netIfWinEnableDHCP(pSvc, ObjPath);
1808 if (SUCCEEDED(hr))
1809 {
1810// hr = netIfWinUpdateConfig(pIf);
1811 }
1812 SysFreeString(ObjPath);
1813 }
1814 }
1815 else
1816 {
1817 hr = E_FAIL;
1818 }
1819 }
1820 }
1821 }
1822
1823
1824 return hr;
1825}
1826
1827VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinDhcpRediscover(IN const GUID *pGuid)
1828{
1829 HRESULT hr;
1830 ComPtr <IWbemServices> pSvc;
1831 hr = netIfWinCreateIWbemServices(pSvc.asOutParam());
1832 if (SUCCEEDED(hr))
1833 {
1834 ComPtr<IWbemClassObject> pAdapterConfig;
1835 hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam());
1836 if (SUCCEEDED(hr))
1837 {
1838 BOOL bIsHostOnly;
1839 hr = netIfWinIsHostOnly(pAdapterConfig, &bIsHostOnly);
1840 if (SUCCEEDED(hr))
1841 {
1842 if (bIsHostOnly)
1843 {
1844 BSTR ObjPath;
1845 hr = netIfWinAdapterConfigPath(pAdapterConfig, &ObjPath);
1846 if (SUCCEEDED(hr))
1847 {
1848 hr = netIfWinDhcpRediscover(pSvc, ObjPath);
1849 if (SUCCEEDED(hr))
1850 {
1851 //hr = netIfWinUpdateConfig(pIf);
1852 }
1853 SysFreeString(ObjPath);
1854 }
1855 }
1856 else
1857 {
1858 hr = E_FAIL;
1859 }
1860 }
1861 }
1862 }
1863
1864
1865 return hr;
1866}
1867
1868typedef bool (*PFNVBOXNETCFG_IPSETTINGS_CALLBACK) (ULONG ip, ULONG mask, PVOID pContext);
1869
1870static void vboxNetCfgWinEnumIpConfig(PIP_ADAPTER_ADDRESSES pAddresses, PFNVBOXNETCFG_IPSETTINGS_CALLBACK pfnCallback, PVOID pContext)
1871{
1872 PIP_ADAPTER_ADDRESSES pAdapter;
1873 for (pAdapter = pAddresses; pAdapter; pAdapter = pAdapter->Next)
1874 {
1875 PIP_ADAPTER_UNICAST_ADDRESS pAddr = pAdapter->FirstUnicastAddress;
1876 PIP_ADAPTER_PREFIX pPrefix = pAdapter->FirstPrefix;
1877
1878 if (pAddr && pPrefix)
1879 {
1880 do
1881 {
1882 bool fIPFound, fMaskFound;
1883 fIPFound = fMaskFound = false;
1884 ULONG ip, mask;
1885 for (; pAddr && !fIPFound; pAddr = pAddr->Next)
1886 {
1887 switch (pAddr->Address.lpSockaddr->sa_family)
1888 {
1889 case AF_INET:
1890 fIPFound = true;
1891 memcpy(&ip,
1892 &((struct sockaddr_in *)pAddr->Address.lpSockaddr)->sin_addr.s_addr,
1893 sizeof(ip));
1894 break;
1895// case AF_INET6:
1896// break;
1897 }
1898 }
1899
1900 for (; pPrefix && !fMaskFound; pPrefix = pPrefix->Next)
1901 {
1902 switch (pPrefix->Address.lpSockaddr->sa_family)
1903 {
1904 case AF_INET:
1905 if (!pPrefix->PrefixLength || pPrefix->PrefixLength > 31) /* in case the ip helper API is queried while NetCfg write lock is held */
1906 break; /* the address values can contain illegal values */
1907 fMaskFound = true;
1908 mask = (~(((ULONG)~0) >> pPrefix->PrefixLength));
1909 mask = htonl(mask);
1910 break;
1911// case AF_INET6:
1912// break;
1913 }
1914 }
1915
1916 if (!fIPFound || !fMaskFound)
1917 break;
1918
1919 if (!pfnCallback(ip, mask, pContext))
1920 return;
1921 } while (true);
1922 }
1923 }
1924}
1925
1926typedef struct _IPPROBE_CONTEXT
1927{
1928 ULONG Prefix;
1929 bool bConflict;
1930}IPPROBE_CONTEXT, *PIPPROBE_CONTEXT;
1931
1932#define IPPROBE_INIT(_pContext, _addr) \
1933 ((_pContext)->bConflict = false, \
1934 (_pContext)->Prefix = _addr)
1935
1936#define IPPROBE_INIT_STR(_pContext, _straddr) \
1937 IPROBE_INIT(_pContext, inet_addr(_straddr))
1938
1939static bool vboxNetCfgWinIpProbeCallback (ULONG ip, ULONG mask, PVOID pContext)
1940{
1941 PIPPROBE_CONTEXT pProbe = (PIPPROBE_CONTEXT)pContext;
1942
1943 if ((ip & mask) == (pProbe->Prefix & mask))
1944 {
1945 pProbe->bConflict = true;
1946 return false;
1947 }
1948
1949 return true;
1950}
1951
1952VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGenHostOnlyNetworkNetworkIp(OUT PULONG pNetIp, OUT PULONG pNetMask)
1953{
1954 DWORD dwRc;
1955 HRESULT hr = S_OK;
1956 /*
1957 * Most of the hosts probably have less than 10 adapters,
1958 * so we'll mostly succeed from the first attempt.
1959 */
1960 ULONG uBufLen = sizeof(IP_ADAPTER_ADDRESSES) * 10;
1961 PIP_ADAPTER_ADDRESSES pAddresses = (PIP_ADAPTER_ADDRESSES)malloc(uBufLen);
1962 if (!pAddresses)
1963 return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
1964 dwRc = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, pAddresses, &uBufLen);
1965 if (dwRc == ERROR_BUFFER_OVERFLOW)
1966 {
1967 /* Impressive! More than 10 adapters! Get more memory and try again. */
1968 free(pAddresses);
1969 pAddresses = (PIP_ADAPTER_ADDRESSES)malloc(uBufLen);
1970 if (!pAddresses)
1971 return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
1972 dwRc = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, pAddresses, &uBufLen);
1973 }
1974 if (dwRc == NO_ERROR)
1975 {
1976 IPPROBE_CONTEXT Context;
1977 const ULONG ip192168 = inet_addr("192.168.0.0");
1978 srand(GetTickCount());
1979
1980 *pNetIp = 0;
1981 *pNetMask = 0;
1982
1983 for (int i = 0; i < 255; i++)
1984 {
1985 ULONG ipProbe = rand()*255/RAND_MAX;
1986 ipProbe = ip192168 | (ipProbe << 16);
1987 IPPROBE_INIT(&Context, ipProbe);
1988 vboxNetCfgWinEnumIpConfig(pAddresses, vboxNetCfgWinIpProbeCallback, &Context);
1989 if (!Context.bConflict)
1990 {
1991 *pNetIp = ipProbe;
1992 *pNetMask = inet_addr("255.255.255.0");
1993 break;
1994 }
1995 }
1996 if (*pNetIp == 0)
1997 dwRc = ERROR_DHCP_ADDRESS_CONFLICT;
1998 }
1999 else
2000 NonStandardLogFlow(("GetAdaptersAddresses err (%d)\n", dwRc));
2001
2002 if (pAddresses)
2003 free(pAddresses);
2004
2005 if (dwRc != NO_ERROR)
2006 {
2007 hr = HRESULT_FROM_WIN32(dwRc);
2008 }
2009
2010 return hr;
2011}
2012
2013/*
2014 * convenience functions to perform netflt/adp manipulations
2015 */
2016#define VBOXNETCFGWIN_NETFLT_ID L"sun_VBoxNetFlt"
2017#define VBOXNETCFGWIN_NETFLT_MP_ID L"sun_VBoxNetFltmp"
2018
2019static HRESULT vboxNetCfgWinNetFltUninstall(IN INetCfg *pNc, DWORD InfRmFlags)
2020{
2021 INetCfgComponent *pNcc = NULL;
2022 HRESULT hr = pNc->FindComponent(VBOXNETCFGWIN_NETFLT_ID, &pNcc);
2023 if (hr == S_OK)
2024 {
2025 NonStandardLog("NetFlt is installed currently, uninstalling ...\n");
2026
2027 hr = VBoxNetCfgWinUninstallComponent(pNc, pNcc);
2028 NonStandardLogFlow(("NetFlt component uninstallation ended with hr (0x%x)\n", hr));
2029
2030 pNcc->Release();
2031 }
2032 else if (hr == S_FALSE)
2033 {
2034 NonStandardLog("NetFlt is not installed currently\n");
2035 }
2036 else
2037 {
2038 NonStandardLogFlow(("FindComponent failed, hr (0x%x)\n", hr));
2039 }
2040
2041 VBoxDrvCfgInfUninstallAllF(L"NetService", VBOXNETCFGWIN_NETFLT_ID, InfRmFlags);
2042 VBoxDrvCfgInfUninstallAllF(L"Net", VBOXNETCFGWIN_NETFLT_MP_ID, InfRmFlags);
2043
2044 return hr;
2045}
2046
2047VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetFltUninstall(IN INetCfg *pNc)
2048{
2049 return vboxNetCfgWinNetFltUninstall(pNc, 0);
2050}
2051
2052VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetFltInstall(IN INetCfg *pNc,
2053 IN LPCWSTR const *apInfFullPaths, IN UINT cInfFullPaths)
2054{
2055 HRESULT hr = vboxNetCfgWinNetFltUninstall(pNc, SUOI_FORCEDELETE);
2056 if (SUCCEEDED(hr))
2057 {
2058 NonStandardLog("NetFlt will be installed ...\n");
2059 hr = vboxNetCfgWinInstallInfAndComponent(pNc, VBOXNETCFGWIN_NETFLT_ID,
2060 &GUID_DEVCLASS_NETSERVICE,
2061 apInfFullPaths,
2062 cInfFullPaths,
2063 NULL);
2064 }
2065 return hr;
2066}
2067
2068/*
2069 * Use the same id as does the old implementation for NDIS 5
2070 * #define VBOXNETCFGWIN_NETLWF_ID L"oracle_VBoxNetLwf"
2071 */
2072#define VBOXNETCFGWIN_NETLWF_ID L"sun_VBoxNetFlt"
2073
2074static HRESULT vboxNetCfgWinNetLwfUninstall(IN INetCfg *pNc, DWORD InfRmFlags)
2075{
2076 INetCfgComponent * pNcc = NULL;
2077 HRESULT hr = pNc->FindComponent(VBOXNETCFGWIN_NETLWF_ID, &pNcc);
2078 if (hr == S_OK)
2079 {
2080 NonStandardLog("NetLwf is installed currently, uninstalling ...\n");
2081
2082 hr = VBoxNetCfgWinUninstallComponent(pNc, pNcc);
2083
2084 pNcc->Release();
2085 }
2086 else if (hr == S_FALSE)
2087 {
2088 NonStandardLog("NetLwf is not installed currently\n");
2089 hr = S_OK;
2090 }
2091 else
2092 {
2093 NonStandardLogFlow(("FindComponent failed, hr (0x%x)\n", hr));
2094 hr = S_OK;
2095 }
2096
2097 VBoxDrvCfgInfUninstallAllF(L"NetService", VBOXNETCFGWIN_NETLWF_ID, InfRmFlags);
2098
2099 return hr;
2100}
2101
2102VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetLwfUninstall(IN INetCfg *pNc)
2103{
2104 return vboxNetCfgWinNetLwfUninstall(pNc, 0);
2105}
2106
2107VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetLwfInstall(IN INetCfg *pNc,
2108 IN LPCWSTR const pInfFullPath)
2109{
2110 HRESULT hr = vboxNetCfgWinNetLwfUninstall(pNc, SUOI_FORCEDELETE);
2111 if (SUCCEEDED(hr))
2112 {
2113 NonStandardLog("NetLwf will be installed ...\n");
2114 hr = vboxNetCfgWinInstallInfAndComponent(pNc, VBOXNETCFGWIN_NETLWF_ID,
2115 &GUID_DEVCLASS_NETSERVICE,
2116 &pInfFullPath,
2117 1,
2118 NULL);
2119 }
2120 return hr;
2121}
2122
2123#define VBOX_CONNECTION_NAME L"VirtualBox Host-Only Network"
2124VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGenHostonlyConnectionName(PCWSTR DevName, WCHAR *pBuf, PULONG pcbBuf)
2125{
2126 const WCHAR * pSuffix = wcsrchr( DevName, L'#' );
2127 ULONG cbSize = sizeof(VBOX_CONNECTION_NAME);
2128 ULONG cbSufSize = 0;
2129
2130 if (pSuffix)
2131 {
2132 cbSize += (ULONG)wcslen(pSuffix) * 2;
2133 cbSize += 2; /* for space */
2134 }
2135
2136 if (*pcbBuf < cbSize)
2137 {
2138 *pcbBuf = cbSize;
2139 return E_FAIL;
2140 }
2141
2142 wcscpy(pBuf, VBOX_CONNECTION_NAME);
2143 if (pSuffix)
2144 {
2145 wcscat(pBuf, L" ");
2146 wcscat(pBuf, pSuffix);
2147 }
2148
2149 return S_OK;
2150}
2151
2152static BOOL vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority(IN INetCfg *pNc, IN INetCfgComponent *pNcc, PVOID pContext)
2153{
2154 INetCfgComponentBindings *pNetCfgBindings;
2155 GUID *pGuid = (GUID*)pContext;
2156
2157 /* Get component's binding. */
2158 HRESULT hr = pNcc->QueryInterface(IID_INetCfgComponentBindings, (PVOID*)&pNetCfgBindings);
2159 if (SUCCEEDED(hr))
2160 {
2161 /* Get binding path enumerator reference. */
2162 IEnumNetCfgBindingPath *pEnumNetCfgBindPath;
2163 hr = pNetCfgBindings->EnumBindingPaths(EBP_BELOW, &pEnumNetCfgBindPath);
2164 if (SUCCEEDED(hr))
2165 {
2166 bool bFoundIface = false;
2167 hr = pEnumNetCfgBindPath->Reset();
2168 do
2169 {
2170 INetCfgBindingPath *pNetCfgBindPath;
2171 hr = pEnumNetCfgBindPath->Next(1, &pNetCfgBindPath, NULL);
2172 if (hr == S_OK)
2173 {
2174 IEnumNetCfgBindingInterface *pEnumNetCfgBindIface;
2175 hr = pNetCfgBindPath->EnumBindingInterfaces(&pEnumNetCfgBindIface);
2176 if (hr == S_OK)
2177 {
2178 pEnumNetCfgBindIface->Reset();
2179 do
2180 {
2181 INetCfgBindingInterface *pNetCfgBindIfce;
2182 hr = pEnumNetCfgBindIface->Next(1, &pNetCfgBindIfce, NULL);
2183 if (hr == S_OK)
2184 {
2185 INetCfgComponent *pNetCfgCompo;
2186 hr = pNetCfgBindIfce->GetLowerComponent(&pNetCfgCompo);
2187 if (hr == S_OK)
2188 {
2189 ULONG uComponentStatus;
2190 hr = pNetCfgCompo->GetDeviceStatus(&uComponentStatus);
2191 if (hr == S_OK)
2192 {
2193 GUID guid;
2194 hr = pNetCfgCompo->GetInstanceGuid(&guid);
2195 if ( hr == S_OK
2196 && guid == *pGuid)
2197 {
2198 hr = pNetCfgBindings->MoveAfter(pNetCfgBindPath, NULL);
2199 if (FAILED(hr))
2200 NonStandardLogFlow(("Unable to move interface, hr (0x%x)\n", hr));
2201 bFoundIface = true;
2202 }
2203 }
2204 pNetCfgCompo->Release();
2205 }
2206 else
2207 NonStandardLogFlow(("GetLowerComponent failed, hr (0x%x)\n", hr));
2208 pNetCfgBindIfce->Release();
2209 }
2210 else
2211 {
2212 if (hr == S_FALSE) /* No more binding interfaces? */
2213 hr = S_OK;
2214 else
2215 NonStandardLogFlow(("Next binding interface failed, hr (0x%x)\n", hr));
2216 break;
2217 }
2218 } while (!bFoundIface);
2219 pEnumNetCfgBindIface->Release();
2220 }
2221 else
2222 NonStandardLogFlow(("EnumBindingInterfaces failed, hr (0x%x)\n", hr));
2223 pNetCfgBindPath->Release();
2224 }
2225 else
2226 {
2227 if (hr == S_FALSE) /* No more binding paths? */
2228 hr = S_OK;
2229 else
2230 NonStandardLogFlow(("Next bind path failed, hr (0x%x)\n", hr));
2231 break;
2232 }
2233 } while (!bFoundIface);
2234 pEnumNetCfgBindPath->Release();
2235 }
2236 else
2237 NonStandardLogFlow(("EnumBindingPaths failed, hr (0x%x)\n", hr));
2238 pNetCfgBindings->Release();
2239 }
2240 else
2241 NonStandardLogFlow(("QueryInterface for IID_INetCfgComponentBindings failed, hr (0x%x)\n", hr));
2242 return TRUE;
2243}
2244
2245static UINT WINAPI vboxNetCfgWinPspFileCallback(
2246 PVOID Context,
2247 UINT Notification,
2248 UINT_PTR Param1,
2249 UINT_PTR Param2
2250 )
2251{
2252 switch (Notification)
2253 {
2254 case SPFILENOTIFY_TARGETNEWER:
2255 case SPFILENOTIFY_TARGETEXISTS:
2256 return TRUE;
2257 }
2258 return SetupDefaultQueueCallback(Context, Notification, Param1, Param2);
2259}
2260
2261/* The original source of the VBoxNetAdp adapter creation/destruction code has the following copyright */
2262/*
2263 Copyright 2004 by the Massachusetts Institute of Technology
2264
2265 All rights reserved.
2266
2267 Permission to use, copy, modify, and distribute this software and its
2268 documentation for any purpose and without fee is hereby granted,
2269 provided that the above copyright notice appear in all copies and that
2270 both that copyright notice and this permission notice appear in
2271 supporting documentation, and that the name of the Massachusetts
2272 Institute of Technology (M.I.T.) not be used in advertising or publicity
2273 pertaining to distribution of the software without specific, written
2274 prior permission.
2275
2276 M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
2277 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
2278 M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
2279 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
2280 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2281 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2282 SOFTWARE.
2283*/
2284
2285
2286/**
2287 * Use the IShellFolder API to rename the connection.
2288 */
2289static HRESULT rename_shellfolder (PCWSTR wGuid, PCWSTR wNewName)
2290{
2291 /* This is the GUID for the network connections folder. It is constant.
2292 * {7007ACC7-3202-11D1-AAD2-00805FC1270E} */
2293 const GUID CLSID_NetworkConnections = {
2294 0x7007ACC7, 0x3202, 0x11D1, {
2295 0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E
2296 }
2297 };
2298
2299 LPITEMIDLIST pidl = NULL;
2300 IShellFolder *pShellFolder = NULL;
2301 HRESULT hr;
2302
2303 /* Build the display name in the form "::{GUID}". */
2304 if (wcslen(wGuid) >= MAX_PATH)
2305 return E_INVALIDARG;
2306 WCHAR szAdapterGuid[MAX_PATH + 2] = {0};
2307 swprintf(szAdapterGuid, L"::%ls", wGuid);
2308
2309 /* Create an instance of the network connections folder. */
2310 hr = CoCreateInstance(CLSID_NetworkConnections, NULL,
2311 CLSCTX_INPROC_SERVER, IID_IShellFolder,
2312 reinterpret_cast<LPVOID *>(&pShellFolder));
2313 /* Parse the display name. */
2314 if (SUCCEEDED (hr))
2315 {
2316 hr = pShellFolder->ParseDisplayName (NULL, NULL, szAdapterGuid, NULL,
2317 &pidl, NULL);
2318 }
2319 if (SUCCEEDED (hr))
2320 {
2321 hr = pShellFolder->SetNameOf (NULL, pidl, wNewName, SHGDN_NORMAL,
2322 &pidl);
2323 }
2324
2325 CoTaskMemFree (pidl);
2326
2327 if (pShellFolder)
2328 pShellFolder->Release();
2329
2330 return hr;
2331}
2332
2333/**
2334 * Loads a system DLL.
2335 *
2336 * @returns Module handle or NULL
2337 * @param pszName The DLL name.
2338 */
2339static HMODULE loadSystemDll(const char *pszName)
2340{
2341 char szPath[MAX_PATH];
2342 UINT cchPath = GetSystemDirectoryA(szPath, sizeof(szPath));
2343 size_t cbName = strlen(pszName) + 1;
2344 if (cchPath + 1 + cbName > sizeof(szPath))
2345 return NULL;
2346 szPath[cchPath] = '\\';
2347 memcpy(&szPath[cchPath + 1], pszName, cbName);
2348 return LoadLibraryA(szPath);
2349}
2350
2351VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRenameConnection (LPWSTR pGuid, PCWSTR NewName)
2352{
2353 typedef HRESULT (WINAPI *lpHrRenameConnection) (const GUID *, PCWSTR);
2354 lpHrRenameConnection RenameConnectionFunc = NULL;
2355 HRESULT status;
2356
2357 /* First try the IShellFolder interface, which was unimplemented
2358 * for the network connections folder before XP. */
2359 status = rename_shellfolder (pGuid, NewName);
2360 if (status == E_NOTIMPL)
2361 {
2362/** @todo that code doesn't seem to work! */
2363 /* The IShellFolder interface is not implemented on this platform.
2364 * Try the (undocumented) HrRenameConnection API in the netshell
2365 * library. */
2366 CLSID clsid;
2367 HINSTANCE hNetShell;
2368 status = CLSIDFromString ((LPOLESTR) pGuid, &clsid);
2369 if (FAILED(status))
2370 return E_FAIL;
2371 hNetShell = loadSystemDll("netshell.dll");
2372 if (hNetShell == NULL)
2373 return E_FAIL;
2374 RenameConnectionFunc =
2375 (lpHrRenameConnection) GetProcAddress (hNetShell,
2376 "HrRenameConnection");
2377 if (RenameConnectionFunc == NULL)
2378 {
2379 FreeLibrary (hNetShell);
2380 return E_FAIL;
2381 }
2382 status = RenameConnectionFunc (&clsid, NewName);
2383 FreeLibrary (hNetShell);
2384 }
2385 if (FAILED (status))
2386 return status;
2387
2388 return S_OK;
2389}
2390
2391#define DRIVERHWID _T("sun_VBoxNetAdp")
2392
2393#define SetErrBreak(strAndArgs) \
2394 if (1) { \
2395 hrc = E_FAIL; \
2396 NonStandardLog strAndArgs; \
2397 break; \
2398 } else do {} while (0)
2399
2400VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRemoveHostOnlyNetworkInterface(IN const GUID *pGUID, OUT BSTR *pErrMsg)
2401{
2402 HRESULT hrc = S_OK;
2403
2404 do
2405 {
2406 TCHAR lszPnPInstanceId [512] = {0};
2407
2408 /* We have to find the device instance ID through a registry search */
2409
2410 HKEY hkeyNetwork = 0;
2411 HKEY hkeyConnection = 0;
2412
2413 do
2414 {
2415 WCHAR strRegLocation [256];
2416 WCHAR wszGuid[50];
2417
2418 int length = StringFromGUID2(*pGUID, wszGuid, RT_ELEMENTS(wszGuid));
2419 if (!length)
2420 SetErrBreak(("Failed to create a Guid string"));
2421
2422 swprintf (strRegLocation,
2423 L"SYSTEM\\CurrentControlSet\\Control\\Network\\"
2424 L"{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s",
2425 wszGuid);
2426
2427 LONG status;
2428 status = RegOpenKeyExW (HKEY_LOCAL_MACHINE, strRegLocation, 0,
2429 KEY_READ, &hkeyNetwork);
2430 if ((status != ERROR_SUCCESS) || !hkeyNetwork)
2431 SetErrBreak (("Host interface network is not found in registry (%S) [1]",
2432 strRegLocation));
2433
2434 status = RegOpenKeyExW (hkeyNetwork, L"Connection", 0,
2435 KEY_READ, &hkeyConnection);
2436 if ((status != ERROR_SUCCESS) || !hkeyConnection)
2437 SetErrBreak (("Host interface network is not found in registry (%S) [2]",
2438 strRegLocation));
2439
2440 DWORD len = sizeof (lszPnPInstanceId);
2441 DWORD dwKeyType;
2442 status = RegQueryValueExW (hkeyConnection, L"PnPInstanceID", NULL,
2443 &dwKeyType, (LPBYTE) lszPnPInstanceId, &len);
2444 if ((status != ERROR_SUCCESS) || (dwKeyType != REG_SZ))
2445 SetErrBreak (("Host interface network is not found in registry (%S) [3]",
2446 strRegLocation));
2447 }
2448 while (0);
2449
2450 if (hkeyConnection)
2451 RegCloseKey (hkeyConnection);
2452 if (hkeyNetwork)
2453 RegCloseKey (hkeyNetwork);
2454
2455 if (FAILED (hrc))
2456 break;
2457
2458 /*
2459 * Now we are going to enumerate all network devices and
2460 * wait until we encounter the right device instance ID
2461 */
2462
2463 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
2464
2465 do
2466 {
2467 BOOL ok;
2468 DWORD ret = 0;
2469 GUID netGuid;
2470 SP_DEVINFO_DATA DeviceInfoData;
2471 DWORD index = 0;
2472 BOOL found = FALSE;
2473 DWORD size = 0;
2474
2475 /* initialize the structure size */
2476 DeviceInfoData.cbSize = sizeof (SP_DEVINFO_DATA);
2477
2478 /* copy the net class GUID */
2479 memcpy (&netGuid, &GUID_DEVCLASS_NET, sizeof (GUID_DEVCLASS_NET));
2480
2481 /* return a device info set contains all installed devices of the Net class */
2482 hDeviceInfo = SetupDiGetClassDevs (&netGuid, NULL, NULL, DIGCF_PRESENT);
2483
2484 if (hDeviceInfo == INVALID_HANDLE_VALUE)
2485 SetErrBreak (("SetupDiGetClassDevs failed (0x%08X)", GetLastError()));
2486
2487 /* enumerate the driver info list */
2488 while (TRUE)
2489 {
2490 TCHAR *deviceHwid;
2491
2492 ok = SetupDiEnumDeviceInfo (hDeviceInfo, index, &DeviceInfoData);
2493
2494 if (!ok)
2495 {
2496 if (GetLastError() == ERROR_NO_MORE_ITEMS)
2497 break;
2498 else
2499 {
2500 index++;
2501 continue;
2502 }
2503 }
2504
2505 /* try to get the hardware ID registry property */
2506 ok = SetupDiGetDeviceRegistryProperty (hDeviceInfo,
2507 &DeviceInfoData,
2508 SPDRP_HARDWAREID,
2509 NULL,
2510 NULL,
2511 0,
2512 &size);
2513 if (!ok)
2514 {
2515 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
2516 {
2517 index++;
2518 continue;
2519 }
2520
2521 deviceHwid = (TCHAR *) malloc (size);
2522 ok = SetupDiGetDeviceRegistryProperty (hDeviceInfo,
2523 &DeviceInfoData,
2524 SPDRP_HARDWAREID,
2525 NULL,
2526 (PBYTE)deviceHwid,
2527 size,
2528 NULL);
2529 if (!ok)
2530 {
2531 free (deviceHwid);
2532 deviceHwid = NULL;
2533 index++;
2534 continue;
2535 }
2536 }
2537 else
2538 {
2539 /* something is wrong. This shouldn't have worked with a NULL buffer */
2540 index++;
2541 continue;
2542 }
2543
2544 for (TCHAR *t = deviceHwid;
2545 t && *t && t < &deviceHwid[size / sizeof(TCHAR)];
2546 t += _tcslen (t) + 1)
2547 {
2548 if (!_tcsicmp (DRIVERHWID, t))
2549 {
2550 /* get the device instance ID */
2551 TCHAR devID [MAX_DEVICE_ID_LEN];
2552 if (CM_Get_Device_ID(DeviceInfoData.DevInst,
2553 devID, MAX_DEVICE_ID_LEN, 0) == CR_SUCCESS)
2554 {
2555 /* compare to what we determined before */
2556 if (wcscmp(devID, lszPnPInstanceId) == 0)
2557 {
2558 found = TRUE;
2559 break;
2560 }
2561 }
2562 }
2563 }
2564
2565 if (deviceHwid)
2566 {
2567 free (deviceHwid);
2568 deviceHwid = NULL;
2569 }
2570
2571 if (found)
2572 break;
2573
2574 index++;
2575 }
2576
2577 if (found == FALSE)
2578 SetErrBreak (("Host Interface Network driver not found (0x%08X)",
2579 GetLastError()));
2580
2581 ok = SetupDiSetSelectedDevice (hDeviceInfo, &DeviceInfoData);
2582 if (!ok)
2583 SetErrBreak (("SetupDiSetSelectedDevice failed (0x%08X)",
2584 GetLastError()));
2585
2586 ok = SetupDiCallClassInstaller (DIF_REMOVE, hDeviceInfo, &DeviceInfoData);
2587 if (!ok)
2588 SetErrBreak (("SetupDiCallClassInstaller (DIF_REMOVE) failed (0x%08X)",
2589 GetLastError()));
2590 }
2591 while (0);
2592
2593 /* clean up the device info set */
2594 if (hDeviceInfo != INVALID_HANDLE_VALUE)
2595 SetupDiDestroyDeviceInfoList (hDeviceInfo);
2596
2597 if (FAILED (hrc))
2598 break;
2599 }
2600 while (0);
2601
2602 return hrc;
2603}
2604
2605VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinUpdateHostOnlyNetworkInterface(LPCWSTR pcsxwInf, BOOL *pbRebootRequired)
2606{
2607 return VBoxDrvCfgDrvUpdate(DRIVERHWID, pcsxwInf, pbRebootRequired);
2608}
2609
2610VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinCreateHostOnlyNetworkInterface(IN LPCWSTR pInfPath, IN bool bIsInfPathFile,
2611 OUT GUID *pGuid, OUT BSTR *lppszName, OUT BSTR *pErrMsg)
2612{
2613 HRESULT hrc = S_OK;
2614
2615 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
2616 SP_DEVINFO_DATA DeviceInfoData;
2617 PVOID pQueueCallbackContext = NULL;
2618 DWORD ret = 0;
2619 BOOL found = FALSE;
2620 BOOL registered = FALSE;
2621 BOOL destroyList = FALSE;
2622 WCHAR pWCfgGuidString [50];
2623 WCHAR DevName[256];
2624
2625 do
2626 {
2627 GUID netGuid;
2628 SP_DRVINFO_DATA DriverInfoData;
2629 SP_DEVINSTALL_PARAMS DeviceInstallParams;
2630 TCHAR className [MAX_PATH];
2631 DWORD index = 0;
2632 PSP_DRVINFO_DETAIL_DATA pDriverInfoDetail;
2633 /* for our purposes, 2k buffer is more
2634 * than enough to obtain the hardware ID
2635 * of the VBoxNetAdp driver. */
2636 DWORD detailBuf [2048];
2637
2638 HKEY hkey = NULL;
2639 DWORD cbSize;
2640 DWORD dwValueType;
2641
2642 /* initialize the structure size */
2643 DeviceInfoData.cbSize = sizeof (SP_DEVINFO_DATA);
2644 DriverInfoData.cbSize = sizeof (SP_DRVINFO_DATA);
2645
2646 /* copy the net class GUID */
2647 memcpy(&netGuid, &GUID_DEVCLASS_NET, sizeof(GUID_DEVCLASS_NET));
2648
2649 /* create an empty device info set associated with the net class GUID */
2650 hDeviceInfo = SetupDiCreateDeviceInfoList(&netGuid, NULL);
2651 if (hDeviceInfo == INVALID_HANDLE_VALUE)
2652 SetErrBreak (("SetupDiCreateDeviceInfoList failed (0x%08X)",
2653 GetLastError()));
2654
2655 /* get the class name from GUID */
2656 BOOL fResult = SetupDiClassNameFromGuid (&netGuid, className, MAX_PATH, NULL);
2657 if (!fResult)
2658 SetErrBreak (("SetupDiClassNameFromGuid failed (0x%08X)",
2659 GetLastError()));
2660
2661 /* create a device info element and add the new device instance
2662 * key to registry */
2663 fResult = SetupDiCreateDeviceInfo (hDeviceInfo, className, &netGuid, NULL, NULL,
2664 DICD_GENERATE_ID, &DeviceInfoData);
2665 if (!fResult)
2666 SetErrBreak (("SetupDiCreateDeviceInfo failed (0x%08X)",
2667 GetLastError()));
2668
2669 /* select the newly created device info to be the currently
2670 selected member */
2671 fResult = SetupDiSetSelectedDevice (hDeviceInfo, &DeviceInfoData);
2672 if (!fResult)
2673 SetErrBreak (("SetupDiSetSelectedDevice failed (0x%08X)",
2674 GetLastError()));
2675
2676 if (pInfPath)
2677 {
2678 /* get the device install parameters and disable filecopy */
2679 DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
2680 fResult = SetupDiGetDeviceInstallParams (hDeviceInfo, &DeviceInfoData,
2681 &DeviceInstallParams);
2682 if (fResult)
2683 {
2684 memset(DeviceInstallParams.DriverPath, 0, sizeof(DeviceInstallParams.DriverPath));
2685 size_t pathLenght = wcslen(pInfPath) + 1/* null terminator */;
2686 if (pathLenght < sizeof(DeviceInstallParams.DriverPath)/sizeof(DeviceInstallParams.DriverPath[0]))
2687 {
2688 memcpy(DeviceInstallParams.DriverPath, pInfPath, pathLenght*sizeof(DeviceInstallParams.DriverPath[0]));
2689
2690 if (bIsInfPathFile)
2691 {
2692 DeviceInstallParams.Flags |= DI_ENUMSINGLEINF;
2693 }
2694
2695 fResult = SetupDiSetDeviceInstallParams(hDeviceInfo, &DeviceInfoData,
2696 &DeviceInstallParams);
2697 if (!fResult)
2698 {
2699 DWORD winEr = GetLastError();
2700 NonStandardLogFlow(("SetupDiSetDeviceInstallParams failed, winEr (%d)\n", winEr));
2701 break;
2702 }
2703 }
2704 else
2705 {
2706 NonStandardLogFlow(("SetupDiSetDeviceInstallParams faileed: INF path is too long\n"));
2707 break;
2708 }
2709 }
2710 else
2711 {
2712 DWORD winEr = GetLastError();
2713 NonStandardLogFlow(("SetupDiGetDeviceInstallParams failed, winEr (%d)\n", winEr));
2714 }
2715 }
2716
2717 /* build a list of class drivers */
2718 fResult = SetupDiBuildDriverInfoList (hDeviceInfo, &DeviceInfoData,
2719 SPDIT_CLASSDRIVER);
2720 if (!fResult)
2721 SetErrBreak (("SetupDiBuildDriverInfoList failed (0x%08X)",
2722 GetLastError()));
2723
2724 destroyList = TRUE;
2725
2726 /* enumerate the driver info list */
2727 while (TRUE)
2728 {
2729 BOOL ret;
2730
2731 ret = SetupDiEnumDriverInfo (hDeviceInfo, &DeviceInfoData,
2732 SPDIT_CLASSDRIVER, index, &DriverInfoData);
2733
2734 /* if the function failed and GetLastError() returned
2735 * ERROR_NO_MORE_ITEMS, then we have reached the end of the
2736 * list. Otherwise there was something wrong with this
2737 * particular driver. */
2738 if (!ret)
2739 {
2740 if (GetLastError() == ERROR_NO_MORE_ITEMS)
2741 break;
2742 else
2743 {
2744 index++;
2745 continue;
2746 }
2747 }
2748
2749 pDriverInfoDetail = (PSP_DRVINFO_DETAIL_DATA) detailBuf;
2750 pDriverInfoDetail->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
2751
2752 /* if we successfully find the hardware ID and it turns out to
2753 * be the one for the loopback driver, then we are done. */
2754 if (SetupDiGetDriverInfoDetail (hDeviceInfo,
2755 &DeviceInfoData,
2756 &DriverInfoData,
2757 pDriverInfoDetail,
2758 sizeof (detailBuf),
2759 NULL))
2760 {
2761 TCHAR * t;
2762
2763 /* pDriverInfoDetail->HardwareID is a MULTISZ string. Go through the
2764 * whole list and see if there is a match somewhere. */
2765 t = pDriverInfoDetail->HardwareID;
2766 while (t && *t && t < (TCHAR *) &detailBuf [RT_ELEMENTS(detailBuf)])
2767 {
2768 if (!_tcsicmp(t, DRIVERHWID))
2769 break;
2770
2771 t += _tcslen(t) + 1;
2772 }
2773
2774 if (t && *t && t < (TCHAR *) &detailBuf [RT_ELEMENTS(detailBuf)])
2775 {
2776 found = TRUE;
2777 break;
2778 }
2779 }
2780
2781 index ++;
2782 }
2783
2784 if (!found)
2785 SetErrBreak(("Could not find Host Interface Networking driver! Please reinstall"));
2786
2787 /* set the loopback driver to be the currently selected */
2788 fResult = SetupDiSetSelectedDriver (hDeviceInfo, &DeviceInfoData,
2789 &DriverInfoData);
2790 if (!fResult)
2791 SetErrBreak(("SetupDiSetSelectedDriver failed (0x%08X)",
2792 GetLastError()));
2793
2794 /* register the phantom device to prepare for install */
2795 fResult = SetupDiCallClassInstaller (DIF_REGISTERDEVICE, hDeviceInfo,
2796 &DeviceInfoData);
2797 if (!fResult)
2798 {
2799 DWORD err = GetLastError();
2800 SetErrBreak (("SetupDiCallClassInstaller failed (0x%08X)",
2801 err));
2802 }
2803
2804 /* registered, but remove if errors occur in the following code */
2805 registered = TRUE;
2806
2807 /* ask the installer if we can install the device */
2808 fResult = SetupDiCallClassInstaller (DIF_ALLOW_INSTALL, hDeviceInfo,
2809 &DeviceInfoData);
2810 if (!fResult)
2811 {
2812 if (GetLastError() != ERROR_DI_DO_DEFAULT)
2813 SetErrBreak (("SetupDiCallClassInstaller (DIF_ALLOW_INSTALL) failed (0x%08X)",
2814 GetLastError()));
2815 /* that's fine */
2816 }
2817
2818 /* get the device install parameters and disable filecopy */
2819 DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
2820 fResult = SetupDiGetDeviceInstallParams (hDeviceInfo, &DeviceInfoData,
2821 &DeviceInstallParams);
2822 if (fResult)
2823 {
2824 pQueueCallbackContext = SetupInitDefaultQueueCallback(NULL);
2825 if (pQueueCallbackContext)
2826 {
2827 DeviceInstallParams.InstallMsgHandlerContext = pQueueCallbackContext;
2828 DeviceInstallParams.InstallMsgHandler = (PSP_FILE_CALLBACK)vboxNetCfgWinPspFileCallback;
2829 fResult = SetupDiSetDeviceInstallParams (hDeviceInfo, &DeviceInfoData,
2830 &DeviceInstallParams);
2831 if (!fResult)
2832 {
2833 DWORD winEr = GetLastError();
2834 NonStandardLogFlow(("SetupDiSetDeviceInstallParams failed, winEr (%d)\n", winEr));
2835 }
2836 Assert(fResult);
2837 }
2838 else
2839 {
2840 DWORD winEr = GetLastError();
2841 NonStandardLogFlow(("SetupInitDefaultQueueCallback failed, winEr (%d)\n", winEr));
2842 }
2843 }
2844 else
2845 {
2846 DWORD winEr = GetLastError();
2847 NonStandardLogFlow(("SetupDiGetDeviceInstallParams failed, winEr (%d)\n", winEr));
2848 }
2849
2850 /* install the files first */
2851 fResult = SetupDiCallClassInstaller (DIF_INSTALLDEVICEFILES, hDeviceInfo,
2852 &DeviceInfoData);
2853 if (!fResult)
2854 SetErrBreak (("SetupDiCallClassInstaller (DIF_INSTALLDEVICEFILES) failed (0x%08X)",
2855 GetLastError()));
2856 /* get the device install parameters and disable filecopy */
2857 DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
2858 fResult = SetupDiGetDeviceInstallParams (hDeviceInfo, &DeviceInfoData,
2859 &DeviceInstallParams);
2860 if (fResult)
2861 {
2862 DeviceInstallParams.Flags |= DI_NOFILECOPY;
2863 fResult = SetupDiSetDeviceInstallParams(hDeviceInfo, &DeviceInfoData,
2864 &DeviceInstallParams);
2865 if (!fResult)
2866 SetErrBreak (("SetupDiSetDeviceInstallParams failed (0x%08X)",
2867 GetLastError()));
2868 }
2869
2870 /*
2871 * Register any device-specific co-installers for this device,
2872 */
2873 fResult = SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS,
2874 hDeviceInfo,
2875 &DeviceInfoData);
2876 if (!fResult)
2877 SetErrBreak (("SetupDiCallClassInstaller (DIF_REGISTER_COINSTALLERS) failed (0x%08X)",
2878 GetLastError()));
2879
2880 /*
2881 * install any installer-specified interfaces.
2882 * and then do the real install
2883 */
2884 fResult = SetupDiCallClassInstaller(DIF_INSTALLINTERFACES,
2885 hDeviceInfo,
2886 &DeviceInfoData);
2887 if (!fResult)
2888 SetErrBreak (("SetupDiCallClassInstaller (DIF_INSTALLINTERFACES) failed (0x%08X)",
2889 GetLastError()));
2890
2891 fResult = SetupDiCallClassInstaller(DIF_INSTALLDEVICE,
2892 hDeviceInfo,
2893 &DeviceInfoData);
2894 if (!fResult)
2895 SetErrBreak (("SetupDiCallClassInstaller (DIF_INSTALLDEVICE) failed (0x%08X)",
2896 GetLastError()));
2897
2898 /* Figure out NetCfgInstanceId */
2899 hkey = SetupDiOpenDevRegKey(hDeviceInfo,
2900 &DeviceInfoData,
2901 DICS_FLAG_GLOBAL,
2902 0,
2903 DIREG_DRV,
2904 KEY_READ);
2905 if (hkey == INVALID_HANDLE_VALUE)
2906 SetErrBreak(("SetupDiOpenDevRegKey failed (0x%08X)", GetLastError()));
2907
2908 cbSize = sizeof(pWCfgGuidString);
2909 DWORD ret;
2910 ret = RegQueryValueExW (hkey, L"NetCfgInstanceId", NULL,
2911 &dwValueType, (LPBYTE) pWCfgGuidString, &cbSize);
2912
2913 RegCloseKey (hkey);
2914
2915 if (!SetupDiGetDeviceRegistryPropertyW(hDeviceInfo, &DeviceInfoData,
2916 SPDRP_FRIENDLYNAME , /* IN DWORD Property,*/
2917 NULL, /*OUT PDWORD PropertyRegDataType, OPTIONAL*/
2918 (PBYTE)DevName, /*OUT PBYTE PropertyBuffer,*/
2919 sizeof(DevName), /* IN DWORD PropertyBufferSize,*/
2920 NULL /*OUT PDWORD RequiredSize OPTIONAL*/))
2921 {
2922 int err = GetLastError();
2923 if (err != ERROR_INVALID_DATA)
2924 {
2925 SetErrBreak (("SetupDiGetDeviceRegistryProperty failed (0x%08X)",
2926 err));
2927 }
2928
2929 if (!SetupDiGetDeviceRegistryPropertyW(hDeviceInfo, &DeviceInfoData,
2930 SPDRP_DEVICEDESC, /* IN DWORD Property,*/
2931 NULL, /*OUT PDWORD PropertyRegDataType, OPTIONAL*/
2932 (PBYTE)DevName, /*OUT PBYTE PropertyBuffer,*/
2933 sizeof(DevName), /* IN DWORD PropertyBufferSize,*/
2934 NULL /*OUT PDWORD RequiredSize OPTIONAL*/
2935 ))
2936 {
2937 err = GetLastError();
2938 SetErrBreak (("SetupDiGetDeviceRegistryProperty failed (0x%08X)",
2939 err));
2940 }
2941 }
2942 }
2943 while (0);
2944
2945 /*
2946 * cleanup
2947 */
2948 if (pQueueCallbackContext)
2949 SetupTermDefaultQueueCallback(pQueueCallbackContext);
2950
2951 if (hDeviceInfo != INVALID_HANDLE_VALUE)
2952 {
2953 /* an error has occurred, but the device is registered, we must remove it */
2954 if (ret != 0 && registered)
2955 SetupDiCallClassInstaller(DIF_REMOVE, hDeviceInfo, &DeviceInfoData);
2956
2957 found = SetupDiDeleteDeviceInfo(hDeviceInfo, &DeviceInfoData);
2958
2959 /* destroy the driver info list */
2960 if (destroyList)
2961 SetupDiDestroyDriverInfoList(hDeviceInfo, &DeviceInfoData,
2962 SPDIT_CLASSDRIVER);
2963 /* clean up the device info set */
2964 SetupDiDestroyDeviceInfoList (hDeviceInfo);
2965 }
2966
2967 /* return the network connection GUID on success */
2968 if (SUCCEEDED(hrc))
2969 {
2970 WCHAR ConnectoinName[128];
2971 ULONG cbName = sizeof(ConnectoinName);
2972
2973 HRESULT hr = VBoxNetCfgWinGenHostonlyConnectionName(DevName, ConnectoinName, &cbName);
2974 if (SUCCEEDED(hr))
2975 hr = VBoxNetCfgWinRenameConnection(pWCfgGuidString, ConnectoinName);
2976
2977 if (lppszName)
2978 {
2979 *lppszName = SysAllocString((const OLECHAR *) DevName);
2980 if (!*lppszName)
2981 {
2982 NonStandardLogFlow(("SysAllocString failed\n"));
2983 hrc = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
2984 }
2985 }
2986
2987 if (pGuid)
2988 {
2989 hrc = CLSIDFromString(pWCfgGuidString, (LPCLSID)pGuid);
2990 if (FAILED(hrc))
2991 NonStandardLogFlow(("CLSIDFromString failed, hrc (0x%x)\n", hrc));
2992 }
2993
2994 INetCfg *pNetCfg = NULL;
2995 LPWSTR lpszApp = NULL;
2996 hr = VBoxNetCfgWinQueryINetCfg(&pNetCfg, TRUE, L"VirtualBox Host-Only Creation",
2997 30 * 1000, /* on Vista we often get 6to4svc.dll holding the lock, wait for 30 sec. */
2998 /* TODO: special handling for 6to4svc.dll ???, i.e. several retrieves */
2999 &lpszApp);
3000 if (hr == S_OK)
3001 {
3002 hr = vboxNetCfgWinEnumNetCfgComponents(pNetCfg,
3003 &GUID_DEVCLASS_NETSERVICE,
3004 vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority,
3005 pGuid);
3006 if (SUCCEEDED(hr))
3007 {
3008 hr = vboxNetCfgWinEnumNetCfgComponents(pNetCfg,
3009 &GUID_DEVCLASS_NETTRANS,
3010 vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority,
3011 pGuid);
3012 if (SUCCEEDED(hr))
3013 hr = vboxNetCfgWinEnumNetCfgComponents(pNetCfg,
3014 &GUID_DEVCLASS_NETCLIENT,
3015 vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority,
3016 pGuid);
3017 }
3018
3019 if (SUCCEEDED(hr))
3020 {
3021 hr = pNetCfg->Apply();
3022 }
3023 else
3024 NonStandardLogFlow(("Enumeration failed, hr 0x%x\n", hr));
3025 VBoxNetCfgWinReleaseINetCfg(pNetCfg, TRUE);
3026 }
3027 else if (hr == NETCFG_E_NO_WRITE_LOCK && lpszApp)
3028 {
3029 NonStandardLogFlow(("Application %ws is holding the lock, failed\n", lpszApp));
3030 CoTaskMemFree(lpszApp);
3031 }
3032 else
3033 NonStandardLogFlow(("VBoxNetCfgWinQueryINetCfg failed, hr 0x%x\n", hr));
3034 }
3035 return hrc;
3036}
3037
3038#undef SetErrBreak
3039
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