[Wine-patches] [6/10] Implement IoRegisterDeviceInterface and IoSetDeviceInterfaceState.

Alexander Morozov =?iso-8859-1?q?amorozov_=CE=C1_etersoft=2Eru?=
Пн Ноя 24 19:01:51 MSK 2008


----------- следующая часть -----------
From 9a891300928443808cfc3b97a927d7d804f72515 Mon Sep 17 00:00:00 2001
From: Alexander Morozov <amorozov на etersoft.ru>
Date: Mon, 24 Nov 2008 17:47:30 +0300
Subject: [PATCH] Implement IoRegisterDeviceInterface and IoSetDeviceInterfaceState.

---
 dlls/ntoskrnl.exe/Makefile.in   |    2 +-
 dlls/ntoskrnl.exe/ntoskrnl.c    |  193 ++++++++++++++++++++++++++++++++++++++-
 dlls/wineusbhub/wineusbhub.c    |   52 +++++++++-
 dlls/wineusbhub/wineusbhub.spec |    4 +
 include/cfgmgr32.h              |    1 +
 programs/winedevice/device.c    |    3 +-
 programs/wineusb/main.c         |   38 +++++++-
 7 files changed, 278 insertions(+), 15 deletions(-)

diff --git a/dlls/ntoskrnl.exe/Makefile.in b/dlls/ntoskrnl.exe/Makefile.in
index f7787d8..3c63e8e 100644
--- a/dlls/ntoskrnl.exe/Makefile.in
+++ b/dlls/ntoskrnl.exe/Makefile.in
@@ -4,7 +4,7 @@ SRCDIR    = @srcdir@
 VPATH     = @srcdir@
 MODULE    = ntoskrnl.exe
 IMPORTLIB = ntoskrnl.exe
-IMPORTS   = kernel32 ntdll
+IMPORTS   = kernel32 ntdll wineusbhub setupapi
 
 C_SRCS = \
 	ntoskrnl.c
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c
index 18ad4e5..7d2319b 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/ntoskrnl.c
@@ -31,6 +31,11 @@
 #include "windef.h"
 #include "winternl.h"
 #include "winioctl.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "winreg.h"
+#include "setupapi.h"
+#include "cfgmgr32.h"
 #include "excpt.h"
 #include "ddk/ntddk.h"
 #include "wine/unicode.h"
@@ -42,6 +47,11 @@ WINE_DEFAULT_DEBUG_CHANNEL(ntoskrnl);
 WINE_DECLARE_DEBUG_CHANNEL(relay);
 
 
+extern UNICODE_STRING *__wine_usbhub_get_pdo_name();
+extern char *__wine_usbhub_get_instance_id();
+extern USHORT __wine_usbhub_get_vid();
+extern USHORT __wine_usbhub_get_pid();
+
 KSYSTEM_TIME KeTickCount = { 0, 0, 0 };
 
 typedef struct _KSERVICE_TABLE_DESCRIPTOR
@@ -364,6 +374,8 @@ NTSTATUS wine_ntoskrnl_main_loop( HANDLE stop_event )
             HeapFree( GetProcessHeap(), 0, out_buff );
             if (out_size) out_buff = HeapAlloc( GetProcessHeap(), 0, out_size );
             else out_buff = NULL;
+            while (device->AttachedDevice)
+                device = device->AttachedDevice;
             status = process_ioctl( device, code, in_buff, in_size, out_buff, &out_size );
             break;
         case STATUS_BUFFER_OVERFLOW:
@@ -782,10 +794,102 @@ NTSTATUS WINAPI IoRegisterDeviceInterface( PDEVICE_OBJECT PhysicalDeviceObject,
                                            PUNICODE_STRING ReferenceString,
                                            PUNICODE_STRING SymbolicLinkName )
 {
-    FIXME( "%p %s %s %p\n", PhysicalDeviceObject,
+    /* Now this function is implemented only for USB devices */
+    static const WCHAR usb[] = {'U','S','B',0};
+    static const WCHAR link_name[] = {'\\','\?','\?','\\','U','S','B','#',
+            'V','i','d','_','%','0','4','x','&','P','i','d','_','%','0','4','x',
+            '#','%','s','#','%','s',0};
+    static const WCHAR device_name[] = {'U','S','B','\\','V','i','d','_',
+            '%','0','4','x','&','P','i','d','_','%','0','4','x',0};
+    PWSTR buf, hardware_id;
+    UNICODE_STRING guid_str;
+    WCHAR instance_id[MAX_DEVICE_ID_LEN];
+    char *inst_ptr;
+    HDEVINFO set;
+    SP_DEVINFO_DATA devInfo = { 0 };
+    DWORD i = 0;
+    int found = 0;
+    NTSTATUS status = STATUS_UNSUCCESSFUL;
+
+    TRACE( "%p %s %s %p\n", PhysicalDeviceObject,
            debugstr_guid(InterfaceClassGuid), debugstr_us(ReferenceString),
            SymbolicLinkName );
-    return STATUS_SUCCESS;
+
+    inst_ptr = __wine_usbhub_get_instance_id();
+    RtlMultiByteToUnicodeN( instance_id, MAX_DEVICE_ID_LEN, NULL,
+            inst_ptr, strlen( inst_ptr ) );
+    instance_id[strlen( inst_ptr )] = 0;
+
+    buf = RtlAllocateHeap( GetProcessHeap(), 0, (strlenW( link_name )
+            + strlenW( instance_id ) + 34 /* 37 - 4  + 1 */ ) * sizeof(WCHAR) );
+    if (NULL == buf)
+        return STATUS_NO_MEMORY;
+    if (STATUS_SUCCESS != RtlStringFromGUID( InterfaceClassGuid, &guid_str ))
+    {
+        RtlFreeHeap( GetProcessHeap(), 0, buf );
+        /* RtlStringFromGUID returns STATUS_NO_MEMORY if unsuccessful */
+        return STATUS_NO_MEMORY;
+    }
+    /* guid_str.Buffer contains null-terminated string */
+    sprintfW( buf, link_name, __wine_usbhub_get_vid(),
+            __wine_usbhub_get_pid(), instance_id, guid_str.Buffer );
+    RtlFreeUnicodeString( &guid_str );
+
+    hardware_id = RtlAllocateHeap( GetProcessHeap(), 0,
+            (strlenW( device_name ) + 1) * sizeof(WCHAR) );
+    if (NULL == hardware_id)
+    {
+        RtlFreeHeap( GetProcessHeap(), 0, buf );
+        return STATUS_NO_MEMORY;
+    }
+    sprintfW( hardware_id, device_name, __wine_usbhub_get_vid(),
+            __wine_usbhub_get_pid(), instance_id );
+
+    set = SetupDiGetClassDevsW( NULL, usb, NULL, DIGCF_ALLCLASSES );
+    if (INVALID_HANDLE_VALUE == set)
+    {
+        RtlFreeHeap( GetProcessHeap(), 0, buf );
+        return STATUS_UNSUCCESSFUL;
+    }
+    devInfo.cbSize = sizeof(devInfo);
+    while (!found && SetupDiEnumDeviceInfo( set, i++, &devInfo ))
+    {
+        PWSTR id;
+        DWORD size;
+
+        SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_HARDWAREID,
+                NULL, NULL, 0, &size );
+        id = RtlAllocateHeap( GetProcessHeap(), 0, size );
+        if (NULL == id)
+        {
+            status = STATUS_NO_MEMORY;
+            break;
+        }
+        if (SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_HARDWAREID,
+                NULL, (PBYTE)id, size, NULL ))
+            while (*id)
+            {
+                if (!strcmpiW( id, hardware_id ))
+                {
+                    found = 1;
+                    if (SetupDiCreateDeviceInterfaceW( set, &devInfo,
+                            InterfaceClassGuid, NULL, 0, NULL ))
+                        status = STATUS_SUCCESS;
+                    break;
+                }
+                id += strlenW( id ) + 1;
+            }
+        RtlFreeHeap( GetProcessHeap(), 0, id );
+    }
+    RtlFreeHeap( GetProcessHeap(), 0, hardware_id );
+    SetupDiDestroyDeviceInfoList( set );
+
+    if (STATUS_SUCCESS == status)
+        RtlInitUnicodeString( SymbolicLinkName, buf );
+    else
+        RtlFreeHeap( GetProcessHeap(), 0, buf );
+
+    return status;
 }
 
 /***********************************************************************
@@ -824,8 +928,89 @@ NTSTATUS WINAPI IoDeleteSymbolicLink( UNICODE_STRING *name )
 NTSTATUS WINAPI IoSetDeviceInterfaceState( PUNICODE_STRING SymbolicLinkName,
                                            BOOLEAN Enable )
 {
-    FIXME( "%s %d\n", debugstr_us(SymbolicLinkName), Enable );
-    return STATUS_SUCCESS;
+    NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND;
+
+    TRACE( "%s %d\n", debugstr_us(SymbolicLinkName), Enable );
+
+    if (Enable)
+    {
+        HDEVINFO set;
+        UNICODE_STRING link_name;
+        DWORD i, k = 0;
+        SP_DEVICE_INTERFACE_DATA ifaceData;
+        SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail;
+        SIZE_T size;
+        GUID guid;
+        WCHAR buf[39];
+        UNICODE_STRING guid_str;
+        BOOL copy = FALSE;
+
+        for (i = 0; i < (SymbolicLinkName->Length / sizeof(WCHAR)) && k < 38; ++i)
+        {
+            if (SymbolicLinkName->Buffer[i] == '{')
+                copy = TRUE;
+            if (copy)
+                buf[k++] = SymbolicLinkName->Buffer[i];
+        }
+        if (k != 38)
+            return STATUS_INVALID_PARAMETER;
+        buf[38] = 0;
+        RtlInitUnicodeString( &guid_str, buf );
+        if (STATUS_SUCCESS != RtlGUIDFromString( &guid_str, &guid ))
+            return STATUS_INVALID_PARAMETER;
+
+        set = SetupDiGetClassDevsW( &guid, NULL, NULL, DIGCF_DEVICEINTERFACE );
+        if (INVALID_HANDLE_VALUE == set)
+            return STATUS_UNSUCCESSFUL;
+        ifaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
+        size = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + SymbolicLinkName->Length;
+        detail = HeapAlloc( GetProcessHeap(), 0, size );
+        if (NULL != detail)
+        {
+            i = 0;
+            detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
+            while (SetupDiEnumDeviceInterfaces( set, NULL, &guid, i++, &ifaceData ))
+            {
+                if (SetupDiGetDeviceInterfaceDetailW( set, &ifaceData, detail,
+                        size, NULL, NULL))
+                    if (!strncmpiW( SymbolicLinkName->Buffer + 3,
+                            detail->DevicePath + 3,
+                            SymbolicLinkName->Length / sizeof(WCHAR) - 3 ))
+                    {
+                        static const WCHAR DosDevices[] =
+                                {'\\','D','o','s','D','e','v','i','c','e','s',0};
+                        PWSTR ptr;
+
+                        ptr = HeapAlloc( GetProcessHeap(), 0,
+                                (strlenW( detail->DevicePath ) - 3
+                                + strlenW( DosDevices ) + 1) * sizeof(WCHAR) );
+                        if (NULL != ptr)
+                        {
+                            strcpyW( ptr, DosDevices );
+                            strcatW( ptr, detail->DevicePath + 3 );
+                            RtlInitUnicodeString( &link_name, ptr );
+                            status = IoCreateSymbolicLink( &link_name,
+                                    __wine_usbhub_get_pdo_name() );
+                            HeapFree( GetProcessHeap(), 0, ptr );
+                        }
+                        else
+                            status = STATUS_NO_MEMORY;
+                        break;
+                    }
+            }
+            HeapFree( GetProcessHeap(), 0, detail );
+        }
+        else
+            status = STATUS_NO_MEMORY;
+        SetupDiDestroyDeviceInfoList( set );
+    }
+    else
+    {
+        FIXME( "Disabling interface is not supported\n" );
+        status = STATUS_NOT_IMPLEMENTED;
+    }
+
+    return status;
 }
 
 
diff --git a/dlls/wineusbhub/wineusbhub.c b/dlls/wineusbhub/wineusbhub.c
index a7985cf..eb94445 100644
--- a/dlls/wineusbhub/wineusbhub.c
+++ b/dlls/wineusbhub/wineusbhub.c
@@ -31,6 +31,7 @@
 #include "windef.h"
 #include "winbase.h"
 #include "winternl.h"
+#include "cfgmgr32.h"
 #include "ddk/ntddk.h"
 #include "ddk/usb.h"
 #include "wine/unicode.h"
@@ -42,8 +43,11 @@ WINE_DEFAULT_DEBUG_CHANNEL(wineusbhub);
 extern void WINAPI IofCompleteRequest( IRP *irp, UCHAR priority_boost );
 
 DRIVER_OBJECT hubdrv;
-DEVICE_OBJECT *usbdev;      /* USB PDO */
+DEVICE_OBJECT *usbdev = NULL;      /* USB PDO */
 static struct usb_device *dev;
+WCHAR bufW[20];
+UNICODE_STRING pdo_name = {0, 0, NULL};
+char instance_id[MAX_DEVICE_ID_LEN] = {0};
 
 static void add_data( char **dst, int *dst_size, void *src, int src_size )
 {
@@ -249,21 +253,21 @@ DEVICE_OBJECT *__wine_usbhub_get_pdo( UCHAR *pdo_info )
 #if defined(HAVE_LIBUSB) && defined(HAVE_USB_H)
     static const WCHAR usbpdoW[] = {'\\','D','e','v','i','c','e','\\',
                                     'U','S','B','P','D','O','-','%','u',0};
-    static WCHAR bufW[20];
-    UNICODE_STRING pdo_name;
     struct usb_bus *bus;
 
-    TRACE( "%u, %s, %s\n", pdo_info[0], pdo_info + 1,
-            pdo_info + 2 + strlen( (char *)(pdo_info + 1) ) );
+    TRACE( "%u, %s, %s, %s\n", pdo_info[0], debugstr_a((char *)pdo_info + 1),
+            debugstr_a((char *)pdo_info + 2 + PATH_MAX),
+            debugstr_a((char *)pdo_info + 3 + 2 * PATH_MAX) );
 
     for (bus = usb_busses; bus; bus = bus->next)
         for (dev = bus->devices; dev; dev = dev->next)
             if (!strcmp( bus->dirname, (char *)(pdo_info + 1) ) &&
-                    !strcmp( dev->filename, (char *)(pdo_info + 2 + strlen( bus->dirname )) ))
+                    !strcmp( dev->filename, (char *)(pdo_info + 2 + PATH_MAX) ))
             {
                 hubdrv.MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = __wine_usbhub_internal_ioctl;
                 hubdrv.MajorFunction[IRP_MJ_PNP] = __wine_usbhub_dispatch_pnp;
 
+                strcpy( instance_id, (char *)pdo_info + 3 + 2 * PATH_MAX );
                 snprintfW( bufW, sizeof(bufW), usbpdoW, pdo_info[0] );
                 RtlInitUnicodeString( &pdo_name, bufW );
 
@@ -277,6 +281,42 @@ DEVICE_OBJECT *__wine_usbhub_get_pdo( UCHAR *pdo_info )
     return NULL;
 }
 
+UNICODE_STRING *__wine_usbhub_get_pdo_name()
+{
+#if defined(HAVE_LIBUSB) && defined(HAVE_USB_H)
+    if (pdo_name.Length)
+        return &pdo_name;
+#endif
+    return NULL;
+}
+
+char *__wine_usbhub_get_instance_id()
+{
+#if defined(HAVE_LIBUSB) && defined(HAVE_USB_H)
+    if (*instance_id)
+        return instance_id;
+#endif
+    return NULL;
+}
+
+USHORT __wine_usbhub_get_vid()
+{
+#if defined(HAVE_LIBUSB) && defined(HAVE_USB_H)
+    if (usbdev != NULL)
+        return dev->descriptor.idVendor;
+#endif
+    return 0;
+}
+
+USHORT __wine_usbhub_get_pid()
+{
+#if defined(HAVE_LIBUSB) && defined(HAVE_USB_H)
+    if (usbdev != NULL)
+        return dev->descriptor.idProduct;
+#endif
+    return 0;
+}
+
 BOOL WINAPI DllMain( HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv )
 {
 #if defined(HAVE_LIBUSB) && defined(HAVE_USB_H)
diff --git a/dlls/wineusbhub/wineusbhub.spec b/dlls/wineusbhub/wineusbhub.spec
index 85e5361..f277e0e 100644
--- a/dlls/wineusbhub/wineusbhub.spec
+++ b/dlls/wineusbhub/wineusbhub.spec
@@ -5,3 +5,7 @@
 # or 'wine_' (for user-visible functions) to avoid namespace conflicts.
 
 @ cdecl __wine_usbhub_get_pdo(ptr)
+@ cdecl __wine_usbhub_get_pdo_name()
+@ cdecl __wine_usbhub_get_instance_id()
+@ cdecl __wine_usbhub_get_vid()
+@ cdecl __wine_usbhub_get_pid()
diff --git a/include/cfgmgr32.h b/include/cfgmgr32.h
index a4a4fc0..9d00b5a 100644
--- a/include/cfgmgr32.h
+++ b/include/cfgmgr32.h
@@ -90,6 +90,7 @@ typedef DWORD CONFIGRET;
 #define CR_INVALID_STRUCTURE_SIZE       0x3b
 #define NUM_CR_RESULTS                  0x3c
 
+#define MAX_DEVICE_ID_LEN               200
 #define MAX_CLASS_NAME_LEN              32
 #define MAX_GUID_STRING_LEN             39
 #define MAX_PROFILE_LEN                 80
diff --git a/programs/winedevice/device.c b/programs/winedevice/device.c
index bd11da9..e6b11b0 100644
--- a/programs/winedevice/device.c
+++ b/programs/winedevice/device.c
@@ -35,6 +35,7 @@
 #include "winreg.h"
 #include "winnls.h"
 #include "winsvc.h"
+#include "cfgmgr32.h"
 #include "ddk/ntddk.h"
 #include "wine/unicode.h"
 #include "wine/server.h"
@@ -292,7 +293,7 @@ static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv )
             NTSTATUS (WINAPI *AddDevice)( PDRIVER_OBJECT, PDEVICE_OBJECT ) =
                     driver_extension.AddDevice;
             PDEVICE_OBJECT pdev_obj = NULL;
-            UCHAR pdo_info[2 * PATH_MAX + 3];
+            UCHAR pdo_info[2 * PATH_MAX + 3 + MAX_DEVICE_ID_LEN];
             data_size_t reply_size = 0;
 
             while (!reply_size)
diff --git a/programs/wineusb/main.c b/programs/wineusb/main.c
index 51fcd3c..d0957d0 100644
--- a/programs/wineusb/main.c
+++ b/programs/wineusb/main.c
@@ -37,6 +37,7 @@
 #include "winsvc.h"
 #include "winuser.h"
 #include "setupapi.h"
+#include "cfgmgr32.h"
 #include "ddk/wdm.h"
 #include "ddk/usb.h"
 #include "wine/unicode.h"
@@ -144,7 +145,8 @@ static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv )
     {
         struct DeviceInstance *instance, *instance2;
         UNICODE_STRING drvname;
-        UCHAR pdo_info[2 * PATH_MAX + 3] = {0};
+        UCHAR pdo_info[2 * PATH_MAX + 3 + MAX_DEVICE_ID_LEN] = {0};
+        char instance_id[MAX_DEVICE_ID_LEN];
         struct usb_device *dev;
         struct usb_bus *bus;
         SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } };
@@ -193,6 +195,32 @@ static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv )
             pid = strtol( str, NULL, 16 );
             HeapFree( GetProcessHeap(), 0, buf );
 
+            SetupDiGetDeviceInstanceIdA( set, &devInfo, NULL, 0, &size );
+            buf = HeapAlloc( GetProcessHeap(), 0, size );
+            if (buf == NULL)
+            {
+                WINE_ERR( "insufficient memory\n" );
+                continue;
+            }
+            ret = SetupDiGetDeviceInstanceIdA( set, &devInfo, (PSTR)buf, size, NULL );
+            if (!ret)
+            {
+                WINE_ERR( "SetupDiGetDeviceInstanceIdA failed\n" );
+                HeapFree( GetProcessHeap(), 0, buf );
+                continue;
+            }
+            str = strrchr( (char *)buf, '\\' );
+            if (str != NULL)
+                ++str;
+            if (str == NULL || *str == 0 || strlen( str ) >= MAX_DEVICE_ID_LEN)
+            {
+                WINE_ERR( "bad instance ID\n" );
+                HeapFree( GetProcessHeap(), 0, buf );
+                continue;
+            }
+            strcpy( instance_id, str );
+            HeapFree( GetProcessHeap(), 0, buf );
+
             for (bus = usb_busses; bus && ret; bus = bus->next)
                 for (dev = bus->devices; dev && ret; dev = dev->next)
                     if (dev->descriptor.idVendor == vid &&
@@ -247,8 +275,12 @@ static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv )
                         }
 
                         RtlInitUnicodeString( &drvname, (PWSTR)buf );
-                        strcpy( (char *)(pdo_info + 1), bus->dirname );
-                        strcpy( (char *)(pdo_info + 2 + strlen( bus->dirname )), dev->filename );
+                        str = (char *)pdo_info + 1;
+                        strcpy( str, bus->dirname );
+                        str += 1 + PATH_MAX;
+                        strcpy( str, dev->filename );
+                        str += 1 + PATH_MAX;
+                        strcpy( str, instance_id );
 
                         SERVER_START_REQ( call_add_device )
                         {
-- 
1.6.0.2.GIT



Подробная информация о списке рассылки Wine-patches