summaryrefslogtreecommitdiffstats
path: root/src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobj.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobj.cpp')
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobj.cpp747
1 files changed, 747 insertions, 0 deletions
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobj.cpp b/src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobj.cpp
new file mode 100644
index 00000000..a5cf004c
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobj.cpp
@@ -0,0 +1,747 @@
+/* $Id: VBoxNetFltNobj.cpp $ */
+/** @file
+ * VBoxNetFltNobj.cpp - Notify Object for Bridged Networking Driver.
+ *
+ * Used to filter Bridged Networking Driver bindings
+ */
+
+/*
+ * Copyright (C) 2011-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "VBoxNetFltNobj.h"
+#include <iprt/win/ntddndis.h>
+#include <iprt/win/windows.h>
+#include <winreg.h>
+#include <Olectl.h>
+
+#include <VBoxNetFltNobjT_i.c>
+
+#include <iprt/assert.h>
+#include <iprt/utf16.h>
+#include <iprt/string.h>
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+//# define VBOXNETFLTNOTIFY_DEBUG_BIND
+
+#ifdef DEBUG
+# define NonStandardAssert(a) Assert(a)
+# define NonStandardAssertBreakpoint() AssertFailed()
+#else
+# define NonStandardAssert(a) do{}while (0)
+# define NonStandardAssertBreakpoint() do{}while (0)
+#endif
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+static HMODULE g_hModSelf = (HMODULE)~(uintptr_t)0;
+
+
+VBoxNetFltNobj::VBoxNetFltNobj()
+ : mpNetCfg(NULL)
+ , mpNetCfgComponent(NULL)
+ , mbInstalling(FALSE)
+{
+}
+
+VBoxNetFltNobj::~VBoxNetFltNobj()
+{
+ cleanup();
+}
+
+void VBoxNetFltNobj::cleanup()
+{
+ if (mpNetCfg)
+ {
+ mpNetCfg->Release();
+ mpNetCfg = NULL;
+ }
+
+ if (mpNetCfgComponent)
+ {
+ mpNetCfgComponent->Release();
+ mpNetCfgComponent = NULL;
+ }
+}
+
+void VBoxNetFltNobj::init(IN INetCfgComponent *pNetCfgComponent, IN INetCfg *pNetCfg, IN BOOL bInstalling)
+{
+ cleanup();
+
+ NonStandardAssert(pNetCfg);
+ NonStandardAssert(pNetCfgComponent);
+ if (pNetCfg)
+ {
+ pNetCfg->AddRef();
+ mpNetCfg = pNetCfg;
+ }
+
+ if (pNetCfgComponent)
+ {
+ pNetCfgComponent->AddRef();
+ mpNetCfgComponent = pNetCfgComponent;
+ }
+
+ mbInstalling = bInstalling;
+}
+
+/* INetCfgComponentControl methods */
+STDMETHODIMP VBoxNetFltNobj::Initialize(IN INetCfgComponent *pNetCfgComponent, IN INetCfg *pNetCfg, IN BOOL bInstalling)
+{
+ init(pNetCfgComponent, pNetCfg, bInstalling);
+ return S_OK;
+}
+
+STDMETHODIMP VBoxNetFltNobj::ApplyRegistryChanges()
+{
+ return S_OK;
+}
+
+STDMETHODIMP VBoxNetFltNobj::ApplyPnpChanges(IN INetCfgPnpReconfigCallback *pCallback)
+{
+ RT_NOREF1(pCallback);
+ return S_OK;
+}
+
+STDMETHODIMP VBoxNetFltNobj::CancelChanges()
+{
+ return S_OK;
+}
+
+static HRESULT vboxNetFltWinQueryInstanceKey(IN INetCfgComponent *pComponent, OUT PHKEY phKey)
+{
+ LPWSTR pwszPnpId;
+ HRESULT hrc = pComponent->GetPnpDevNodeId(&pwszPnpId);
+ if (hrc == S_OK)
+ {
+ WCHAR wszKeyName[MAX_PATH];
+ RTUtf16Copy(wszKeyName, MAX_PATH, L"SYSTEM\\CurrentControlSet\\Enum\\");
+ int rc = RTUtf16Cat(wszKeyName, MAX_PATH, pwszPnpId);
+ if (RT_SUCCESS(rc))
+ {
+ LSTATUS lrc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszKeyName, 0 /*ulOptions*/, KEY_READ, phKey);
+ if (lrc != ERROR_SUCCESS)
+ {
+ hrc = HRESULT_FROM_WIN32(lrc);
+ NonStandardAssertBreakpoint();
+ }
+ }
+ else
+ AssertRCStmt(rc, hrc = ERROR_BUFFER_OVERFLOW);
+
+ CoTaskMemFree(pwszPnpId);
+ }
+ else
+ NonStandardAssertBreakpoint();
+ return hrc;
+}
+
+static HRESULT vboxNetFltWinQueryDriverKey(IN HKEY InstanceKey, OUT PHKEY phKey)
+{
+ HRESULT hrc = S_OK;
+
+ WCHAR wszValue[MAX_PATH];
+ DWORD cbValue = sizeof(wszValue) - sizeof(WCHAR);
+ DWORD dwType = REG_SZ;
+ LSTATUS lrc = RegQueryValueExW(InstanceKey, L"Driver", NULL /*lpReserved*/, &dwType, (LPBYTE)wszValue, &cbValue);
+ if (lrc == ERROR_SUCCESS)
+ {
+ if (dwType == REG_SZ)
+ {
+ wszValue[RT_ELEMENTS(wszValue) - 1] = '\0'; /* registry strings does not need to be zero terminated. */
+
+ WCHAR wszKeyName[MAX_PATH];
+ RTUtf16Copy(wszKeyName, MAX_PATH, L"SYSTEM\\CurrentControlSet\\Control\\Class\\");
+ int rc = RTUtf16Cat(wszKeyName, MAX_PATH, wszValue);
+ if (RT_SUCCESS(rc))
+ {
+ lrc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszKeyName, 0 /*ulOptions*/, KEY_READ, phKey);
+ if (lrc != ERROR_SUCCESS)
+ {
+ hrc = HRESULT_FROM_WIN32(lrc);
+ NonStandardAssertBreakpoint();
+ }
+ }
+ else
+ AssertRCStmt(rc, hrc = ERROR_BUFFER_OVERFLOW);
+ }
+ else
+ {
+ hrc = HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH);
+ NonStandardAssertBreakpoint();
+ }
+ }
+ else
+ {
+ hrc = HRESULT_FROM_WIN32(lrc);
+ NonStandardAssertBreakpoint();
+ }
+
+ return hrc;
+}
+
+static HRESULT vboxNetFltWinQueryDriverKey(IN INetCfgComponent *pComponent, OUT PHKEY phKey)
+{
+ HKEY hKeyInstance = NULL;
+ HRESULT hrc = vboxNetFltWinQueryInstanceKey(pComponent, &hKeyInstance);
+ if (hrc == S_OK)
+ {
+ hrc = vboxNetFltWinQueryDriverKey(hKeyInstance, phKey);
+ if (hrc != S_OK)
+ NonStandardAssertBreakpoint();
+ RegCloseKey(hKeyInstance);
+ }
+ else
+ NonStandardAssertBreakpoint();
+ return hrc;
+}
+
+static HRESULT vboxNetFltWinNotifyCheckNetAdp(IN INetCfgComponent *pComponent, OUT bool *pfShouldBind)
+{
+ *pfShouldBind = false;
+
+ LPWSTR pwszDevId = NULL;
+ HRESULT hrc = pComponent->GetId(&pwszDevId);
+ if (hrc == S_OK)
+ {
+ /** @todo r=bird: This was _wcsnicmp(pwszDevId, L"sun_VBoxNetAdp", sizeof(L"sun_VBoxNetAdp")/2))
+ * which includes the terminator, so it translates to a full compare. Goes way back. */
+ if (RTUtf16ICmpAscii(pwszDevId, "sun_VBoxNetAdp") == 0)
+ *pfShouldBind = false;
+ else
+ hrc = S_FALSE;
+ CoTaskMemFree(pwszDevId);
+ }
+ else
+ NonStandardAssertBreakpoint();
+
+ return hrc;
+}
+
+static HRESULT vboxNetFltWinNotifyCheckMsLoop(IN INetCfgComponent *pComponent, OUT bool *pfShouldBind)
+{
+ *pfShouldBind = false;
+
+ LPWSTR pwszDevId = NULL;
+ HRESULT hrc = pComponent->GetId(&pwszDevId);
+ if (hrc == S_OK)
+ {
+ /** @todo r=bird: This was _wcsnicmp(pwszDevId, L"*msloop", sizeof(L"*msloop")/2)
+ * which includes the terminator, making it a full compare. Goes way back. */
+ if (RTUtf16ICmpAscii(pwszDevId, "*msloop") == 0)
+ {
+ /* we need to detect the medium the adapter is presenting
+ * to do that we could examine in the registry the *msloop params */
+ HKEY hKeyDriver;
+ hrc = vboxNetFltWinQueryDriverKey(pComponent, &hKeyDriver);
+ if (hrc == S_OK)
+ {
+ WCHAR wszValue[64]; /* 2 should be enough actually, paranoid check for extra spaces */
+ DWORD cbValue = sizeof(wszValue) - sizeof(WCHAR);
+ DWORD dwType = REG_SZ;
+ LSTATUS lrc = RegQueryValueExW(hKeyDriver, L"Medium", NULL /*lpReserved*/, &dwType, (LPBYTE)wszValue, &cbValue);
+ if (lrc == ERROR_SUCCESS)
+ {
+ if (dwType == REG_SZ)
+ {
+ wszValue[RT_ELEMENTS(wszValue) - 1] = '\0';
+
+ char szUtf8[256];
+ char *pszUtf8 = szUtf8;
+ RTUtf16ToUtf8Ex(wszValue, RTSTR_MAX, &pszUtf8, sizeof(szUtf8), NULL);
+ pszUtf8 = RTStrStrip(pszUtf8);
+
+ uint64_t uValue = 0;
+ int rc = RTStrToUInt64Ex(pszUtf8, NULL, 0, &uValue);
+ if (RT_SUCCESS(rc))
+ {
+ if (uValue == 0) /* 0 is Ethernet */
+ *pfShouldBind = true;
+ else
+ *pfShouldBind = false;
+ }
+ else
+ {
+ NonStandardAssertBreakpoint();
+ *pfShouldBind = true;
+ }
+ }
+ else
+ NonStandardAssertBreakpoint();
+ }
+ else
+ {
+ /** @todo we should check the default medium in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002bE10318}\<driver_id>\Ndi\Params\Medium, REG_SZ "Default" value */
+ NonStandardAssertBreakpoint();
+ *pfShouldBind = true;
+ }
+
+ RegCloseKey(hKeyDriver);
+ }
+ else
+ NonStandardAssertBreakpoint();
+ }
+ else
+ hrc = S_FALSE;
+ CoTaskMemFree(pwszDevId);
+ }
+ else
+ NonStandardAssertBreakpoint();
+ return hrc;
+}
+
+static HRESULT vboxNetFltWinNotifyCheckLowerRange(IN INetCfgComponent *pComponent, OUT bool *pfShouldBind)
+{
+ *pfShouldBind = false;
+
+ HKEY hKeyDriver = NULL;
+ HRESULT hrc = vboxNetFltWinQueryDriverKey(pComponent, &hKeyDriver);
+ if (hrc == S_OK)
+ {
+ HKEY hKeyInterfaces = NULL;
+ LSTATUS lrc = RegOpenKeyExW(hKeyDriver, L"Ndi\\Interfaces", 0 /*ulOptions*/, KEY_READ, &hKeyInterfaces);
+ if (lrc == ERROR_SUCCESS)
+ {
+ WCHAR wszValue[MAX_PATH];
+ DWORD cbValue = sizeof(wszValue) - sizeof(WCHAR);
+ DWORD dwType = REG_SZ;
+ lrc = RegQueryValueExW(hKeyInterfaces, L"LowerRange", NULL /*lpReserved*/, &dwType, (LPBYTE)wszValue, &cbValue);
+ if (lrc == ERROR_SUCCESS)
+ {
+ if (dwType == REG_SZ)
+ {
+ if (RTUtf16FindAscii(wszValue, "ethernet") >= 0 || RTUtf16FindAscii(wszValue, "wan") >= 0)
+ *pfShouldBind = true;
+ else
+ *pfShouldBind = false;
+ }
+ }
+ else
+ {
+ /* do not set err status to it */
+ *pfShouldBind = false;
+ NonStandardAssertBreakpoint();
+ }
+
+ RegCloseKey(hKeyInterfaces);
+ }
+ else
+ {
+ hrc = HRESULT_FROM_WIN32(lrc);
+ NonStandardAssertBreakpoint();
+ }
+
+ RegCloseKey(hKeyDriver);
+ }
+ else
+ NonStandardAssertBreakpoint();
+ return hrc;
+}
+
+static HRESULT vboxNetFltWinNotifyShouldBind(IN INetCfgComponent *pComponent, OUT bool *pfShouldBind)
+{
+ *pfShouldBind = false;
+
+ /* filter out only physical adapters */
+ DWORD fCharacteristics = 0;
+ HRESULT hrc = pComponent->GetCharacteristics(&fCharacteristics);
+ if (hrc != S_OK)
+ {
+ NonStandardAssertBreakpoint();
+ return hrc;
+ }
+
+ /* we are not binding to hidden adapters */
+ if (fCharacteristics & NCF_HIDDEN)
+ return S_OK;
+
+ hrc = vboxNetFltWinNotifyCheckMsLoop(pComponent, pfShouldBind);
+ if ( hrc == S_OK /* this is a loopback adapter, the pfShouldBind already contains the result */
+ || hrc != S_FALSE /* error occurred */)
+ return hrc;
+
+ hrc = vboxNetFltWinNotifyCheckNetAdp(pComponent, pfShouldBind);
+ if ( hrc == S_OK /* this is a VBoxNetAdp adapter, the pfShouldBind already contains the result */
+ || hrc != S_FALSE /* error occurred */)
+ return hrc;
+
+ //if (!(fCharacteristics & NCF_PHYSICAL))
+ //{
+ // *pfShouldBind = false; /* we are binding to physical adapters only */
+ // return S_OK;
+ //}
+
+ return vboxNetFltWinNotifyCheckLowerRange(pComponent, pfShouldBind);
+}
+
+
+static HRESULT vboxNetFltWinNotifyShouldBind(IN INetCfgBindingInterface *pIf, OUT bool *pfShouldBind)
+{
+ INetCfgComponent *pAdapterComponent = NULL;
+ HRESULT hrc = pIf->GetLowerComponent(&pAdapterComponent);
+ if (hrc == S_OK)
+ {
+ hrc = vboxNetFltWinNotifyShouldBind(pAdapterComponent, pfShouldBind);
+
+ pAdapterComponent->Release();
+ }
+ else
+ {
+ NonStandardAssertBreakpoint();
+ *pfShouldBind = false;
+ }
+ return hrc;
+}
+
+static HRESULT vboxNetFltWinNotifyShouldBind(IN INetCfgBindingPath *pPath, OUT bool *pfShouldBind)
+{
+ *pfShouldBind = false;
+
+ IEnumNetCfgBindingInterface *pIEnumBinding = NULL;
+ HRESULT hrc = pPath->EnumBindingInterfaces(&pIEnumBinding);
+ if (hrc == S_OK)
+ {
+ hrc = pIEnumBinding->Reset();
+ if (hrc == S_OK)
+ {
+ for (;;)
+ {
+ ULONG uCount = 0;
+ INetCfgBindingInterface *pIBinding = NULL;
+ hrc = pIEnumBinding->Next(1, &pIBinding, &uCount);
+ if (hrc == S_OK)
+ {
+ hrc = vboxNetFltWinNotifyShouldBind(pIBinding, pfShouldBind);
+ pIBinding->Release();
+
+ if (hrc != S_OK)
+ break; /* break on failure. */
+ if (!*pfShouldBind)
+ break;
+ }
+ else if (hrc == S_FALSE)
+ {
+ /* no more elements */
+ hrc = S_OK;
+ break;
+ }
+ else
+ {
+ NonStandardAssertBreakpoint();
+ /* break on falure */
+ break;
+ }
+ }
+ }
+ else
+ NonStandardAssertBreakpoint();
+
+ pIEnumBinding->Release();
+ }
+ else
+ NonStandardAssertBreakpoint();
+ return hrc;
+}
+
+static bool vboxNetFltWinNotifyShouldBind(IN INetCfgBindingPath *pPath)
+{
+#ifdef VBOXNETFLTNOTIFY_DEBUG_BIND
+ return VBOXNETFLTNOTIFY_DEBUG_BIND;
+#else
+ bool fShouldBind;
+ HRESULT hrc = vboxNetFltWinNotifyShouldBind(pPath, &fShouldBind);
+ if (hrc != S_OK)
+ fShouldBind = VBOXNETFLTNOTIFY_ONFAIL_BINDDEFAULT;
+
+ return fShouldBind;
+#endif
+}
+
+
+/* INetCfgComponentNotifyBinding methods */
+STDMETHODIMP VBoxNetFltNobj::NotifyBindingPath(IN DWORD dwChangeFlag, IN INetCfgBindingPath *pNetCfgBP)
+{
+ if (!(dwChangeFlag & NCN_ENABLE) || (dwChangeFlag & NCN_REMOVE) || vboxNetFltWinNotifyShouldBind(pNetCfgBP))
+ return S_OK;
+ return NETCFG_S_DISABLE_QUERY;
+}
+
+STDMETHODIMP VBoxNetFltNobj::QueryBindingPath(IN DWORD dwChangeFlag, IN INetCfgBindingPath *pNetCfgBP)
+{
+ RT_NOREF1(dwChangeFlag);
+ if (vboxNetFltWinNotifyShouldBind(pNetCfgBP))
+ return S_OK;
+ return NETCFG_S_DISABLE_QUERY;
+}
+
+
+static ATL::CComModule _Module;
+
+BEGIN_OBJECT_MAP(ObjectMap)
+ OBJECT_ENTRY(CLSID_VBoxNetFltNobj, VBoxNetFltNobj)
+END_OBJECT_MAP()
+
+
+extern "C"
+BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
+{
+ if (dwReason == DLL_PROCESS_ATTACH)
+ {
+ g_hModSelf = (HMODULE)hInstance;
+
+ _Module.Init(ObjectMap, hInstance);
+ DisableThreadLibraryCalls(hInstance);
+ }
+ else if (dwReason == DLL_PROCESS_DETACH)
+ {
+ _Module.Term();
+ }
+ return TRUE;
+}
+
+STDAPI DllCanUnloadNow(void)
+{
+ return _Module.GetLockCount() == 0 ? S_OK : S_FALSE;
+}
+
+STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
+{
+ return _Module.GetClassObject(rclsid, riid, ppv);
+}
+
+
+/*
+ * ATL::CComModule does not suport server registration/unregistration methods,
+ * so we need to do it manually. Since this is the only place we do registraton
+ * manually, we do it the quick-and-dirty way.
+ */
+
+#ifdef RT_EXCEPTIONS_ENABLED
+/* Someday we may want to log errors. */
+class AdHocRegError
+{
+public:
+ AdHocRegError(LSTATUS rc) { RT_NOREF1(rc); };
+};
+#endif
+
+/**
+ * A simple wrapper on Windows registry functions.
+ */
+class AdHocRegKey
+{
+public:
+ AdHocRegKey(HKEY hKey) : m_hKey(hKey) {};
+ AdHocRegKey(LPCWSTR pcwszName, HKEY hParent = HKEY_CLASSES_ROOT);
+ ~AdHocRegKey() { RegCloseKey(m_hKey); };
+
+ AdHocRegKey *create(LPCWSTR pcwszSubkey);
+ LSTATUS setValue(LPCWSTR pcwszName, LPCWSTR pcwszValue);
+ HKEY getKey(void) { return m_hKey; };
+private:
+ HKEY m_hKey;
+};
+
+AdHocRegKey::AdHocRegKey(LPCWSTR pcwszName, HKEY hParent) : m_hKey(NULL)
+{
+ LSTATUS rc = RegOpenKeyExW(hParent, pcwszName, 0, KEY_ALL_ACCESS, &m_hKey);
+ if (rc != ERROR_SUCCESS)
+#ifdef RT_EXCEPTIONS_ENABLED
+ throw AdHocRegError(rc);
+#else
+ m_hKey = NULL;
+#endif
+}
+
+AdHocRegKey *AdHocRegKey::create(LPCWSTR pcwszSubkey)
+{
+ HKEY hSubkey;
+ LSTATUS rc = RegCreateKeyExW(m_hKey, pcwszSubkey,
+ 0 /*Reserved*/, NULL /*pszClass*/, 0 /*fOptions*/,
+ KEY_ALL_ACCESS, NULL /*pSecAttr*/, &hSubkey, NULL /*pdwDisposition*/);
+ if (rc != ERROR_SUCCESS)
+#ifdef RT_EXCEPTIONS_ENABLED
+ throw AdHocRegError(rc);
+#else
+ return NULL;
+#endif
+ AdHocRegKey *pSubkey = new AdHocRegKey(hSubkey);
+ if (!pSubkey)
+ RegCloseKey(hSubkey);
+ return pSubkey;
+}
+
+LSTATUS AdHocRegKey::setValue(LPCWSTR pcwszName, LPCWSTR pcwszValue)
+{
+ LSTATUS rc = RegSetValueExW(m_hKey, pcwszName, 0, REG_SZ, (const BYTE *)pcwszValue,
+ (DWORD)((RTUtf16Len(pcwszValue) + 1) * sizeof(WCHAR)));
+#ifdef RT_EXCEPTIONS_ENABLED
+ if (rc != ERROR_SUCCESS)
+ throw AdHocRegError(rc);
+#endif
+ return rc;
+}
+
+/**
+ * Auxiliary class that facilitates automatic destruction of AdHocRegKey objects
+ * allocated in heap. No reference counting here!
+ */
+class AdHocRegKeyPtr
+{
+public:
+ AdHocRegKeyPtr(AdHocRegKey *pKey) : m_pKey(pKey) {};
+ ~AdHocRegKeyPtr()
+ {
+ if (m_pKey)
+ {
+ delete m_pKey;
+ m_pKey = NULL;
+ }
+ }
+
+ AdHocRegKey *create(LPCWSTR pcwszSubkey)
+ { return m_pKey ? m_pKey->create(pcwszSubkey) : NULL; };
+
+ LSTATUS setValue(LPCWSTR pcwszName, LPCWSTR pcwszValue)
+ { return m_pKey ? m_pKey->setValue(pcwszName, pcwszValue) : ERROR_INVALID_STATE; };
+
+private:
+ AdHocRegKey *m_pKey;
+ /* Prevent copying, since we do not support reference counting */
+ AdHocRegKeyPtr(const AdHocRegKeyPtr&);
+ AdHocRegKeyPtr& operator=(const AdHocRegKeyPtr&);
+};
+
+
+STDAPI DllRegisterServer(void)
+{
+ /* Get the path to the DLL we're running inside. */
+ WCHAR wszModule[MAX_PATH + 1];
+ UINT cwcModule = GetModuleFileNameW(g_hModSelf, wszModule, MAX_PATH);
+ if (cwcModule == 0 || cwcModule > MAX_PATH)
+ return SELFREG_E_CLASS;
+ wszModule[MAX_PATH] = '\0';
+
+ /*
+ * Create registry keys and values. When exceptions are disabled, we depend
+ * on setValue() to propagate fail key creation failures.
+ */
+#ifdef RT_EXCEPTIONS_ENABLED
+ try
+#endif
+ {
+ AdHocRegKey keyCLSID(L"CLSID");
+ AdHocRegKeyPtr pkeyNobjClass(keyCLSID.create(L"{f374d1a0-bf08-4bdc-9cb2-c15ddaeef955}"));
+ LSTATUS lrc = pkeyNobjClass.setValue(NULL, L"VirtualBox Bridged Networking Driver Notify Object v1.1");
+ if (lrc != ERROR_SUCCESS)
+ return SELFREG_E_CLASS;
+
+ AdHocRegKeyPtr pkeyNobjSrv(pkeyNobjClass.create(L"InProcServer32"));
+ lrc = pkeyNobjSrv.setValue(NULL, wszModule);
+ if (lrc != ERROR_SUCCESS)
+ return SELFREG_E_CLASS;
+ lrc = pkeyNobjSrv.setValue(L"ThreadingModel", L"Both");
+ if (lrc != ERROR_SUCCESS)
+ return SELFREG_E_CLASS;
+ }
+#ifdef RT_EXCEPTIONS_ENABLED
+ catch (AdHocRegError) { return SELFREG_E_CLASS; }
+#endif
+
+#ifdef RT_EXCEPTIONS_ENABLED
+ try
+#endif
+ {
+ AdHocRegKey keyTypeLib(L"TypeLib");
+ AdHocRegKeyPtr pkeyNobjLib(keyTypeLib.create(L"{2A0C94D1-40E1-439C-8FE8-24107CAB0840}\\1.1"));
+ LSTATUS lrc = pkeyNobjLib.setValue(NULL, L"VirtualBox Bridged Networking Driver Notify Object v1.1 Type Library");
+ if (lrc != ERROR_SUCCESS)
+ return SELFREG_E_TYPELIB;
+
+ AdHocRegKeyPtr pkeyNobjLib0(pkeyNobjLib.create(L"0\\win64"));
+ lrc = pkeyNobjLib0.setValue(NULL, wszModule);
+ if (lrc != ERROR_SUCCESS)
+ return SELFREG_E_TYPELIB;
+ AdHocRegKeyPtr pkeyNobjLibFlags(pkeyNobjLib.create(L"FLAGS"));
+ lrc = pkeyNobjLibFlags.setValue(NULL, L"0");
+ if (lrc != ERROR_SUCCESS)
+ return SELFREG_E_TYPELIB;
+
+ if (GetSystemDirectoryW(wszModule, MAX_PATH) == 0)
+ return SELFREG_E_TYPELIB;
+ AdHocRegKeyPtr pkeyNobjLibHelpDir(pkeyNobjLib.create(L"HELPDIR"));
+ lrc = pkeyNobjLibHelpDir.setValue(NULL, wszModule);
+ if (lrc != ERROR_SUCCESS)
+ return SELFREG_E_TYPELIB;
+ }
+#ifdef RT_EXCEPTIONS_ENABLED
+ catch (AdHocRegError) { return SELFREG_E_TYPELIB; }
+#endif
+
+ return S_OK;
+}
+
+
+STDAPI DllUnregisterServer(void)
+{
+ static struct { HKEY hKeyRoot; wchar_t const *pwszParentKey; wchar_t const *pwszKeyToDelete; HRESULT hrcFail; }
+ s_aKeys[] =
+ {
+ { HKEY_CLASSES_ROOT, L"TypeLib", L"{2A0C94D1-40E1-439C-8FE8-24107CAB0840}", SELFREG_E_TYPELIB },
+ { HKEY_CLASSES_ROOT, L"CLSID", L"{f374d1a0-bf08-4bdc-9cb2-c15ddaeef955}", SELFREG_E_CLASS },
+ };
+
+ HRESULT hrc = S_OK;
+ for (size_t i = 0; i < RT_ELEMENTS(s_aKeys); i++)
+ {
+ HKEY hKey = NULL;
+ LSTATUS lrc = RegOpenKeyExW(s_aKeys[i].hKeyRoot, s_aKeys[i].pwszParentKey, 0, KEY_ALL_ACCESS, &hKey);
+ if (lrc == ERROR_SUCCESS)
+ {
+ lrc = RegDeleteTreeW(hKey, s_aKeys[i].pwszKeyToDelete); /* Vista and later */
+ RegCloseKey(hKey);
+ }
+
+ if (lrc != ERROR_SUCCESS && lrc != ERROR_FILE_NOT_FOUND && hrc == S_OK)
+ hrc = s_aKeys[i].hrcFail;
+ }
+
+ return S_OK;
+}
+