- Fix epic naming fail (DhcpEnabled -> EnableDHCP
[reactos.git] / reactos / dll / win32 / netcfgx / netcfgx.c
index ee03c28..1fb9fc1 100644 (file)
 /*
  * COPYRIGHT:       See COPYING in the top level directory
- * PROJECT:         ReactOS Configuration of networkd devices
- * FILE:            lib/netcfgx/netcfgx.c
+ * PROJECT:         ReactOS Configuration of network devices
+ * FILE:            dll/win32/netcfgx/netcfgx.c
  * PURPOSE:         Network devices installer
  *
  * PROGRAMMERS:     HervĂ© Poussineau (hpoussin@reactos.org)
  */
 
+
+#include "precomp.h"
+#include <initguid.h>
+#include <devguid.h>
 #define NDEBUG
 #include <debug.h>
 
-#include "netcfgx.h"
+HINSTANCE netcfgx_hInstance;
+const GUID CLSID_TcpipConfigNotifyObject      = {0xA907657F, 0x6FDF, 0x11D0, {0x8E, 0xFB, 0x00, 0xC0, 0x4F, 0xD9, 0x12, 0xB2}};
+
+
+
+
+static INTERFACE_TABLE InterfaceTable[] =
+{
+    {
+        &CLSID_CNetCfg,
+        INetCfg_Constructor
+    },
+    {
+        &CLSID_TcpipConfigNotifyObject,
+        TcpipConfigNotify_Constructor
+    },
+    {
+        NULL,
+        NULL
+    }
+};
+
+BOOL
+WINAPI
+DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
+{
+    switch (fdwReason)
+    {
+        case DLL_PROCESS_ATTACH:
+            netcfgx_hInstance = hinstDLL;
+            DisableThreadLibraryCalls(netcfgx_hInstance);
+            break;
+    default:
+        break;
+    }
+
+    return TRUE;
+}
+
+HRESULT
+WINAPI
+DllCanUnloadNow(void)
+{
+    return S_FALSE;
+}
+
+STDAPI
+DllRegisterServer(void)
+{
+    HKEY hKey, hSubKey;
+    LPOLESTR pStr;
+    WCHAR szName[MAX_PATH] = L"CLSID\\";
+
+    if (FAILED(StringFromCLSID(&CLSID_CNetCfg, &pStr)))
+        return SELFREG_E_CLASS;
+
+    wcscpy(&szName[6], pStr);
+    CoTaskMemFree(pStr);
+
+    if (RegCreateKeyExW(HKEY_CLASSES_ROOT, szName, 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL) != ERROR_SUCCESS)
+        return SELFREG_E_CLASS;
+
+    if (RegCreateKeyExW(hKey, L"InProcServer32", 0, NULL, 0, KEY_WRITE, NULL, &hSubKey, NULL) == ERROR_SUCCESS)
+    {
+        if (!GetModuleFileNameW(netcfgx_hInstance, szName, sizeof(szName)/sizeof(WCHAR)))
+        {
+            RegCloseKey(hSubKey);
+            RegCloseKey(hKey);
+            return SELFREG_E_CLASS;
+        }
+        szName[(sizeof(szName)/sizeof(WCHAR))-1] = L'\0';
+        RegSetValueW(hSubKey, NULL, REG_SZ, szName, (wcslen(szName)+1) * sizeof(WCHAR));
+        RegSetValueExW(hSubKey, L"ThreadingModel", 0, REG_SZ, (LPBYTE)L"Both", 10);
+        RegCloseKey(hSubKey);
+    }
+
+    RegCloseKey(hKey);
+    return S_OK;
+}
+
+STDAPI
+DllUnregisterServer(void)
+{
+    //FIXME
+    // implement unregistering services
+    //
+    return S_OK;
+}
+
+STDAPI
+DllGetClassObject(
+  REFCLSID rclsid,
+  REFIID riid,
+  LPVOID* ppv 
+)
+{
+    UINT i;
+    HRESULT    hres = E_OUTOFMEMORY;
+    IClassFactory * pcf = NULL;        
+
+    if (!ppv)
+        return E_INVALIDARG;
+
+    *ppv = NULL;
+
+    for (i = 0; InterfaceTable[i].riid; i++) 
+    {
+        if (IsEqualIID(InterfaceTable[i].riid, rclsid)) 
+        {
+            pcf = IClassFactory_fnConstructor(InterfaceTable[i].lpfnCI, NULL, NULL);
+            break;
+        }
+    }
+
+    if (!pcf) 
+    {
+        return CLASS_E_CLASSNOTAVAILABLE;
+    }
+
+    hres = IClassFactory_QueryInterface(pcf, riid, ppv);
+    IClassFactory_Release(pcf);
+
+    return hres;
+}
+
 
 /* Append a REG_SZ to an existing REG_MULTI_SZ string in the registry.
  * If the value doesn't exist, create it.
@@ -100,7 +228,8 @@ static BOOL
 InstallInfSection(
        IN HWND hWnd,
        IN LPCWSTR InfFile,
-       IN LPCWSTR InfSection)
+       IN LPCWSTR InfSection OPTIONAL,
+       IN LPCWSTR InfService OPTIONAL)
 {
        WCHAR Buffer[MAX_PATH];
        HINF hInf = INVALID_HANDLE_VALUE;
@@ -131,12 +260,21 @@ InstallInfSection(
        if (Context == NULL)
                goto cleanup;
 
-       ret = SetupInstallFromInfSectionW(
-               hWnd, hInf,
-               InfSection, SPINST_ALL,
-               NULL, NULL, SP_COPY_NEWER,
-               SetupDefaultQueueCallbackW, Context,
-               NULL, NULL);
+       ret = TRUE;
+       if (ret && InfSection)
+       {
+               ret = SetupInstallFromInfSectionW(
+                       hWnd, hInf,
+                       InfSection, SPINST_ALL,
+                       NULL, NULL, SP_COPY_NEWER,
+                       SetupDefaultQueueCallbackW, Context,
+                       NULL, NULL);
+       }
+       if (ret && InfService)
+       {
+               ret = SetupInstallServicesFromInfSectionW(
+                       hInf, InfService, 0);
+       }
 
 cleanup:
        if (Context)
@@ -152,47 +290,53 @@ InstallAdditionalServices(
        IN HWND hWnd)
 {
        BOOL ret;
+       UNICODE_STRING TcpipServicePath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Tcpip");
 
        /* Install TCP/IP protocol */
        ret = InstallInfSection(
                hWnd,
                L"nettcpip.inf",
-               L"MS_TCPIP.PrimaryInstall");
+               L"MS_TCPIP.PrimaryInstall",
+               L"MS_TCPIP.PrimaryInstall.Services");
        if (!ret && GetLastError() != ERROR_FILE_NOT_FOUND)
        {
                DPRINT("InstallInfSection() failed with error 0x%lx\n", GetLastError());
                return GetLastError();
        }
+       else if (ret)
+       {
+               /* Start the TCP/IP driver */
+               ret = NtLoadDriver(&TcpipServicePath);
+               if (ret)
+               {
+                       /* This isn't really fatal but we want to warn anyway */
+                       DPRINT1("NtLoadDriver(TCPIP) failed with NTSTATUS 0x%lx\n", (NTSTATUS)ret);
+               }
+       }
+        
 
        /* You can add here more clients (SMB...) and services (DHCP server...) */
 
        return ERROR_SUCCESS;
 }
 
-DWORD WINAPI
-NetClassInstaller(
-       IN DI_FUNCTION InstallFunction,
+static DWORD
+InstallNetDevice(
        IN HDEVINFO DeviceInfoSet,
-       IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
+       IN PSP_DEVINFO_DATA DeviceInfoData,
+       LPCWSTR UuidString,
+       DWORD Characteristics,
+       LPCWSTR BusType)
 {
-       RPC_STATUS RpcStatus;
-       UUID Uuid;
        LPWSTR InstanceId = NULL;
-       LPWSTR UuidRpcString = NULL;
-       LPWSTR UuidString = NULL;
        LPWSTR DeviceName = NULL;
        LPWSTR ExportName = NULL;
        LONG rc;
-       DWORD dwShowIcon, dwLength;
        HKEY hKey = NULL;
-       HKEY hLinkageKey = NULL;
        HKEY hNetworkKey = NULL;
+       HKEY hLinkageKey = NULL;
        HKEY hConnectionKey = NULL;
-       
-       if (InstallFunction != DIF_INSTALLDEVICE)
-               return ERROR_DI_DO_DEFAULT;
-
-       DPRINT("%lu %p %p\n", InstallFunction, DeviceInfoSet, DeviceInfoData);
+       DWORD dwShowIcon, dwLength, dwValue;
 
        /* Get Instance ID */
        if (SetupDiGetDeviceInstanceIdW(DeviceInfoSet, DeviceInfoData, NULL, 0, &dwLength))
@@ -201,7 +345,7 @@ NetClassInstaller(
                rc = ERROR_GEN_FAILURE;
                goto cleanup;
        }
-       InstanceId = HeapAlloc(GetProcessHeap(), 0, dwLength);
+       InstanceId = HeapAlloc(GetProcessHeap(), 0, dwLength * sizeof(WCHAR));
        if (!InstanceId)
        {
                DPRINT("HeapAlloc() failed\n");
@@ -215,34 +359,6 @@ NetClassInstaller(
                goto cleanup;
        }
 
-       /* Create a new UUID */
-       RpcStatus = UuidCreate(&Uuid);
-       if (RpcStatus != RPC_S_OK && RpcStatus != RPC_S_UUID_LOCAL_ONLY)
-       {
-               DPRINT("UuidCreate() failed with RPC status 0x%lx\n", RpcStatus);
-               rc = ERROR_GEN_FAILURE;
-               goto cleanup;
-       }
-       RpcStatus = UuidToStringW(&Uuid, &UuidRpcString);
-       if (RpcStatus != RPC_S_OK)
-       {
-               DPRINT("UuidToStringW() failed with RPC status 0x%lx\n", RpcStatus);
-               rc = ERROR_GEN_FAILURE;
-               goto cleanup;
-       }
-
-       /* Add curly braces around Uuid */
-       UuidString = HeapAlloc(GetProcessHeap(), 0, (2 + wcslen(UuidRpcString)) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
-       if (!UuidString)
-       {
-               DPRINT("HeapAlloc() failed\n");
-               rc = ERROR_NOT_ENOUGH_MEMORY;
-               goto cleanup;
-       }
-       wcscpy(UuidString, L"{");
-       wcscat(UuidString, UuidRpcString);
-       wcscat(UuidString, L"}");
-
        /* Create device name */
        DeviceName = HeapAlloc(GetProcessHeap(), 0, (wcslen(L"\\Device\\") + wcslen(UuidString)) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
        if (!DeviceName)
@@ -253,7 +369,7 @@ NetClassInstaller(
        }
        wcscpy(DeviceName, L"\\Device\\");
        wcscat(DeviceName, UuidString);
-       
+
        /* Create export name */
        ExportName = HeapAlloc(GetProcessHeap(), 0, (wcslen(L"\\Device\\Tcpip_") + wcslen(UuidString)) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
        if (!ExportName)
@@ -306,6 +422,13 @@ NetClassInstaller(
                DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
                goto cleanup;
        }
+        dwValue = 1;
+       rc = RegSetValueExW(hKey, L"EnableDHCP", 0, REG_DWORD, (const BYTE*)&dwValue, sizeof(DWORD));
+       if (rc != ERROR_SUCCESS)
+       {
+               DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
+               goto cleanup;
+       }
        RegCloseKey(hKey);
        hKey = NULL;
 
@@ -330,6 +453,19 @@ NetClassInstaller(
                DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
                goto cleanup;
        }
+       rc = RegSetValueExW(hKey, L"Characteristics", 0, REG_DWORD, (const BYTE*)&Characteristics, sizeof(DWORD));
+       if (rc != ERROR_SUCCESS)
+       {
+               DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
+               goto cleanup;
+       }
+       if (BusType)
+               rc = RegSetValueExW(hKey, L"BusType", 0, REG_SZ, (const BYTE*)BusType, (wcslen(BusType) + 1) * sizeof(WCHAR));
+               if (rc != ERROR_SUCCESS)
+               {
+                       DPRINT("RegSetValueExW() failed with error 0x%lx\n", rc);
+                       goto cleanup;
+               }
        rc = RegCreateKeyExW(hKey, L"Linkage", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hLinkageKey, NULL);
        if (rc != ERROR_SUCCESS)
        {
@@ -425,7 +561,6 @@ NetClassInstaller(
        }
 
        /* Install additionnal services */
-       /* FIXME: do it only if it is a network adapter! */
        rc = InstallAdditionalServices(NULL);
        if (rc != ERROR_SUCCESS)
        {
@@ -433,28 +568,191 @@ NetClassInstaller(
                goto cleanup;
        }
 
-       /* HACK: hpoussin, Dec 2005. TCP/IP driver is not able to manage devices
-        * which are installed after its startup. So, we have to reboot to take
-        * this new netcard into account.
-        */
-       MessageBox(NULL, TEXT("You need to reboot to finish the installation of your network card."), TEXT("Reboot required"), MB_OK | MB_ICONWARNING);
        rc = ERROR_SUCCESS;
 
 cleanup:
-       if (UuidRpcString != NULL)
-               RpcStringFreeW(&UuidRpcString);
        HeapFree(GetProcessHeap(), 0, InstanceId);
-       HeapFree(GetProcessHeap(), 0, UuidString);
        HeapFree(GetProcessHeap(), 0, DeviceName);
        HeapFree(GetProcessHeap(), 0, ExportName);
        if (hKey != NULL)
                RegCloseKey(hKey);
-       if (hLinkageKey != NULL)
-               RegCloseKey(hLinkageKey);
        if (hNetworkKey != NULL)
                RegCloseKey(hNetworkKey);
+       if (hLinkageKey != NULL)
+               RegCloseKey(hLinkageKey);
        if (hConnectionKey != NULL)
                RegCloseKey(hConnectionKey);
+       return rc;
+}
+
+static DWORD
+InstallNetClient(VOID)
+{
+       DPRINT1("Installation of network clients is not yet supported\n");
+       return ERROR_GEN_FAILURE;
+}
+
+static DWORD
+InstallNetService(VOID)
+{
+       DPRINT1("Installation of network services is not yet supported\n");
+       return ERROR_GEN_FAILURE;
+}
+
+static DWORD
+InstallNetTransport(VOID)
+{
+       DPRINT1("Installation of network protocols is not yet supported\n");
+       return ERROR_GEN_FAILURE;
+}
+
+DWORD WINAPI
+NetClassInstaller(
+       IN DI_FUNCTION InstallFunction,
+       IN HDEVINFO DeviceInfoSet,
+       IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
+{
+       SP_DRVINFO_DATA_W DriverInfoData;
+       SP_DRVINFO_DETAIL_DATA_W DriverInfoDetail;
+       WCHAR SectionName[LINE_LEN];
+       HINF hInf = INVALID_HANDLE_VALUE;
+       INFCONTEXT InfContext;
+       UINT ErrorLine;
+       INT CharacteristicsInt;
+       DWORD Characteristics;
+       LPWSTR BusType = NULL;
+       RPC_STATUS RpcStatus;
+       UUID Uuid;
+       LPWSTR UuidRpcString = NULL;
+       LPWSTR UuidString = NULL;
+       LONG rc;
+       DWORD dwLength;
+
+       if (InstallFunction != DIF_INSTALLDEVICE)
+               return ERROR_DI_DO_DEFAULT;
+
+       DPRINT("%lu %p %p\n", InstallFunction, DeviceInfoSet, DeviceInfoData);
+
+       /* Get driver info details */
+       DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA_W);
+       if (!SetupDiGetSelectedDriverW(DeviceInfoSet, DeviceInfoData, &DriverInfoData))
+       {
+               rc = GetLastError();
+               DPRINT("SetupDiGetSelectedDriverW() failed with error 0x%lx\n", rc);
+               goto cleanup;
+       }
+       DriverInfoDetail.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_W);
+       if (!SetupDiGetDriverInfoDetailW(DeviceInfoSet, DeviceInfoData, &DriverInfoData, &DriverInfoDetail, sizeof(DriverInfoDetail), NULL)
+        && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+       {
+               rc = GetLastError();
+               DPRINT("SetupDiGetDriverInfoDetailW() failed with error 0x%lx\n", rc);
+               goto cleanup;
+       }
+       hInf = SetupOpenInfFileW(DriverInfoDetail.InfFileName, NULL, INF_STYLE_WIN4, &ErrorLine);
+       if (hInf == INVALID_HANDLE_VALUE)
+       {
+               rc = GetLastError();
+               DPRINT("SetupOpenInfFileW() failed with error 0x%lx\n", rc);
+               goto cleanup;
+       }
+       if (!SetupDiGetActualSectionToInstallW(hInf, DriverInfoDetail.SectionName, SectionName, LINE_LEN, NULL, NULL))
+       {
+               rc = GetLastError();
+               DPRINT("SetupDiGetActualSectionToInstallW() failed with error 0x%lx\n", rc);
+               goto cleanup;
+       }
+
+       /* Get Characteristics and BusType (optional) from .inf file */
+       if (!SetupFindFirstLineW(hInf, SectionName, L"Characteristics", &InfContext))
+       {
+               rc = GetLastError();
+               DPRINT("Unable to find key %S in section %S of file %S (error 0x%lx)\n",
+                       L"Characteristics", SectionName, DriverInfoDetail.InfFileName, rc);
+               goto cleanup;
+       }
+       if (!SetupGetIntField(&InfContext, 1, &CharacteristicsInt))
+       {
+               rc = GetLastError();
+               DPRINT("SetupGetIntField() failed with error 0x%lx\n", rc);
+               goto cleanup;
+       }
+       Characteristics = (DWORD)CharacteristicsInt;
+       if (IsEqualIID(&DeviceInfoData->ClassGuid, &GUID_DEVCLASS_NET))
+       {
+               if (SetupFindFirstLineW(hInf, SectionName, L"BusType", &InfContext))
+               {
+                       if (!SetupGetStringFieldW(&InfContext, 1, NULL, 0, &dwLength))
+                       {
+                               rc = GetLastError();
+                               DPRINT("SetupGetStringFieldW() failed with error 0x%lx\n", rc);
+                               goto cleanup;
+                       }
+                       BusType = HeapAlloc(GetProcessHeap(), 0, dwLength * sizeof(WCHAR));
+                       if (!BusType)
+                       {
+                               DPRINT("HeapAlloc() failed\n");
+                               rc = ERROR_NOT_ENOUGH_MEMORY;
+                               goto cleanup;
+                       }
+                       if (!SetupGetStringFieldW(&InfContext, 1, BusType, dwLength, NULL))
+                       {
+                               rc = GetLastError();
+                               DPRINT("SetupGetStringFieldW() failed with error 0x%lx\n", rc);
+                               goto cleanup;
+                       }
+               }
+       }
+
+       /* Create a new UUID */
+       RpcStatus = UuidCreate(&Uuid);
+       if (RpcStatus != RPC_S_OK && RpcStatus != RPC_S_UUID_LOCAL_ONLY)
+       {
+               DPRINT("UuidCreate() failed with RPC status 0x%lx\n", RpcStatus);
+               rc = ERROR_GEN_FAILURE;
+               goto cleanup;
+       }
+       RpcStatus = UuidToStringW(&Uuid, &UuidRpcString);
+       if (RpcStatus != RPC_S_OK)
+       {
+               DPRINT("UuidToStringW() failed with RPC status 0x%lx\n", RpcStatus);
+               rc = ERROR_GEN_FAILURE;
+               goto cleanup;
+       }
+
+       /* Add curly braces around Uuid */
+       UuidString = HeapAlloc(GetProcessHeap(), 0, (2 + wcslen(UuidRpcString)) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
+       if (!UuidString)
+       {
+               DPRINT("HeapAlloc() failed\n");
+               rc = ERROR_NOT_ENOUGH_MEMORY;
+               goto cleanup;
+       }
+       wcscpy(UuidString, L"{");
+       wcscat(UuidString, UuidRpcString);
+       wcscat(UuidString, L"}");
+
+       if (IsEqualIID(&DeviceInfoData->ClassGuid, &GUID_DEVCLASS_NET))
+               rc = InstallNetDevice(DeviceInfoSet, DeviceInfoData, UuidString, Characteristics, BusType);
+       else if (IsEqualIID(&DeviceInfoData->ClassGuid, &GUID_DEVCLASS_NETCLIENT))
+               rc = InstallNetClient();
+       else if (IsEqualIID(&DeviceInfoData->ClassGuid, &GUID_DEVCLASS_NETSERVICE))
+               rc = InstallNetService();
+       else if (IsEqualIID(&DeviceInfoData->ClassGuid, &GUID_DEVCLASS_NETTRANS))
+               rc = InstallNetTransport();
+       else
+       {
+               DPRINT("Invalid class guid\n");
+               rc = ERROR_GEN_FAILURE;
+       }
+
+cleanup:
+       if (hInf != INVALID_HANDLE_VALUE)
+               SetupCloseInfFile(hInf);
+       if (UuidRpcString != NULL)
+               RpcStringFreeW(&UuidRpcString);
+       HeapFree(GetProcessHeap(), 0, BusType);
+       HeapFree(GetProcessHeap(), 0, UuidString);
 
        if (rc == ERROR_SUCCESS)
                rc = ERROR_DI_DO_DEFAULT;