dinput SetDataFormat support

Robert Reif reif at earthlink.net
Wed Sep 1 18:11:40 CDT 2004


Add support for alternate data formats.
-------------- next part --------------
Index: dlls/dinput/device.c
===================================================================
RCS file: /home/wine/wine/dlls/dinput/device.c,v
retrieving revision 1.18
diff -u -r1.18 device.c
--- dlls/dinput/device.c	31 Aug 2004 18:51:23 -0000	1.18
+++ dlls/dinput/device.c	1 Sep 2004 23:06:48 -0000
@@ -211,7 +211,7 @@
 }
 
 /* Conversion between internal data buffer and external data buffer */
-void fill_DataFormat(void *out, void *in, DataFormat *df) {
+void fill_DataFormat(void *out, const void *in, DataFormat *df) {
     int i;
     char *in_c = (char *) in;
     char *out_c = (char *) out;
@@ -272,6 +272,13 @@
 	    }
 	}
     }
+}
+
+void release_DataFormat(DataFormat * format)
+{
+    TRACE("Deleting DataTransform : \n");
+
+    HeapFree(GetProcessHeap(), 0, format->dt);
 }
 
 DataFormat *create_DataFormat(const DIDATAFORMAT *wine_format, LPCDIDATAFORMAT asked_format, int *offset) {
Index: dlls/dinput/device_private.h
===================================================================
RCS file: /home/wine/wine/dlls/dinput/device_private.h,v
retrieving revision 1.9
diff -u -r1.9 device_private.h
--- dlls/dinput/device_private.h	31 Aug 2004 18:51:23 -0000	1.9
+++ dlls/dinput/device_private.h	1 Sep 2004 23:06:48 -0000
@@ -48,8 +48,9 @@
   int internal_format_size;
   DataTransform *dt;
 } DataFormat;
-extern void fill_DataFormat(void *out, void *in, DataFormat *df) ;
+extern void fill_DataFormat(void *out, const void *in, DataFormat *df) ;
 extern DataFormat *create_DataFormat(const DIDATAFORMAT *wine_format, LPCDIDATAFORMAT asked_format, int *offset) ;
+extern void release_DataFormat(DataFormat *df) ;
 
 /* Used to fill events in the queue */
 #define GEN_EVENT(offset,data,xtime,seq)					\
Index: dlls/dinput/joystick_linux.c
===================================================================
RCS file: /home/wine/wine/dlls/dinput/joystick_linux.c,v
retrieving revision 1.8
diff -u -r1.8 joystick_linux.c
--- dlls/dinput/joystick_linux.c	31 Aug 2004 18:51:23 -0000	1.8
+++ dlls/dinput/joystick_linux.c	1 Sep 2004 23:06:49 -0000
@@ -28,6 +28,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <time.h>
+#include <errno.h>
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif
@@ -87,12 +88,14 @@
 
 	/* joystick private */
 	int				joyfd;
-	LPDIDATAFORMAT			df;
+	DIJOYSTATE2			js;		/* wine data */
+	LPDIDATAFORMAT			user_df;	/* user defined format */
+	DataFormat			*transform;	/* wine to user format converter */
+	int				*offsets;	/* object offsets */
 	ObjProps			*props;
         HANDLE				hEvent;
         LPDIDEVICEOBJECTDATA 		data_queue;
         int				queue_head, queue_tail, queue_len;
-	DIJOYSTATE2			js;
 	BOOL				acquired;
 };
 
@@ -113,7 +116,7 @@
   if ((dwDevType==0) || (GET_DIDEVICE_TYPE(dwDevType)==DIDEVTYPE_JOYSTICK)) {
     /* check whether we have a joystick */
     if ((fd = open(JOYDEV,O_RDONLY) != -1) || (errno!=ENODEV && errno!=ENOENT)) {
-      TRACE("Enumerating the linux Joystick device\n");
+      TRACE("Enumerating the linux Joystick device: %s\n",JOYDEV);
 
       /* Return joystick */
       lpddi->guidInstance	= GUID_Joystick;
@@ -185,31 +188,25 @@
     newDevice->acquired = FALSE;
     CopyMemory(&(newDevice->guid),rguid,sizeof(*rguid));
 
-    /* copy default data format */
-    newDevice->df = HeapAlloc(GetProcessHeap(),0,c_dfDIJoystick2.dwSize);
-    if (newDevice->df == 0) {
-        HeapFree(GetProcessHeap(), 0, newDevice);
-        return 0;
-    }
-    CopyMemory(newDevice->df, &c_dfDIJoystick2, c_dfDIJoystick2.dwSize);
+    /* wine uses DIJOYSTATE2 as it's internal format so copy
+     * the already defined format c_dfDIJoystick2 */
+    newDevice->user_df = HeapAlloc(GetProcessHeap(),0,c_dfDIJoystick2.dwSize);
+    if (newDevice->user_df == 0)
+        goto FAILED;
+
+    CopyMemory(newDevice->user_df, &c_dfDIJoystick2, c_dfDIJoystick2.dwSize);
 
     /* copy default objects */
-    newDevice->df->rgodf = HeapAlloc(GetProcessHeap(),0,c_dfDIJoystick2.dwNumObjs*c_dfDIJoystick2.dwObjSize);
-    if (newDevice->df->rgodf == 0) {
-        HeapFree(GetProcessHeap(), 0, newDevice->df);
-        HeapFree(GetProcessHeap(), 0, newDevice);
-        return 0;
-    }
-    CopyMemory(newDevice->df->rgodf,c_dfDIJoystick2.rgodf,c_dfDIJoystick2.dwNumObjs*c_dfDIJoystick2.dwObjSize);
+    newDevice->user_df->rgodf = HeapAlloc(GetProcessHeap(),0,c_dfDIJoystick2.dwNumObjs*c_dfDIJoystick2.dwObjSize);
+    if (newDevice->user_df->rgodf == 0)
+        goto FAILED;
+
+    CopyMemory(newDevice->user_df->rgodf,c_dfDIJoystick2.rgodf,c_dfDIJoystick2.dwNumObjs*c_dfDIJoystick2.dwObjSize);
 
     /* create default properties */
     newDevice->props = HeapAlloc(GetProcessHeap(),0,c_dfDIJoystick2.dwNumObjs*sizeof(ObjProps));
-    if (newDevice->props == 0) {
-        HeapFree(GetProcessHeap(), 0, newDevice->df->rgodf);
-        HeapFree(GetProcessHeap(), 0, newDevice->df);
-        HeapFree(GetProcessHeap(), 0, newDevice);
-        return 0;
-    }
+    if (newDevice->props == 0)
+        goto FAILED;
 
     /* initialize default properties */
     for (i = 0; i < c_dfDIJoystick2.dwNumObjs; i++) {
@@ -219,10 +216,31 @@
         newDevice->props[i].lSaturation = 0;
     }
 
+    /* create an offsets array */
+    newDevice->offsets = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,c_dfDIJoystick2.dwNumObjs*sizeof(int));
+    if (newDevice->offsets == 0)
+        goto FAILED;
+
+    /* create the default transform filter */
+    newDevice->transform = create_DataFormat(&c_dfDIJoystick2, newDevice->user_df, newDevice->offsets);
+
+    IDirectInputDevice_AddRef((LPDIRECTINPUTDEVICE8A)newDevice->dinput);
+
     if (TRACE_ON(dinput))
-        _dump_DIDATAFORMAT(newDevice->df);
+        _dump_DIDATAFORMAT(newDevice->user_df);
 
     return newDevice;
+
+FAILED:
+    if (newDevice->props)
+        HeapFree(GetProcessHeap(),0,newDevice->props);
+    if (newDevice->user_df->rgodf)
+        HeapFree(GetProcessHeap(),0,newDevice->user_df->rgodf);
+    if (newDevice->user_df)
+        HeapFree(GetProcessHeap(),0,newDevice->user_df);
+    if (newDevice)
+        HeapFree(GetProcessHeap(),0,newDevice);
+    return 0;
 }
 
 static HRESULT joydev_create_deviceA(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev)
@@ -310,12 +328,20 @@
         HeapFree(GetProcessHeap(),0,This->data_queue);
 
     /* Free the DataFormat */
-    HeapFree(GetProcessHeap(), 0, This->df->rgodf);
-    HeapFree(GetProcessHeap(), 0, This->df);
+    HeapFree(GetProcessHeap(), 0, This->user_df->rgodf);
+    HeapFree(GetProcessHeap(), 0, This->user_df);
 
     /* Free the properties */
     HeapFree(GetProcessHeap(), 0, This->props);
 
+    /* Free the offsets array */
+    HeapFree(GetProcessHeap(),0,This->offsets);
+
+    /* release the data transform filter */
+    release_DataFormat(This->transform);
+
+    IDirectInputDevice_Release((LPDIRECTINPUTDEVICE8A)This->dinput);
+
     HeapFree(GetProcessHeap(),0,This);
     return 0;
 }
@@ -330,13 +356,14 @@
 {
     ICOM_THIS(JoystickImpl,iface);
     int i;
-    LPDIDATAFORMAT new_df;
-    LPDIOBJECTDATAFORMAT new_rgodf;
-    ObjProps * new_props;
+    LPDIDATAFORMAT new_df = 0;
+    LPDIOBJECTDATAFORMAT new_rgodf = 0;
+    ObjProps * new_props = 0;
+    int * new_offsets = 0;
 
     TRACE("(%p,%p)\n",This,df);
 
-    if (This->acquired == TRUE) {
+    if (This->acquired) {
         WARN("acquired\n");
         return DIERR_ACQUIRED;
     }
@@ -346,43 +373,54 @@
 
     /* Store the new data format */
     new_df = HeapAlloc(GetProcessHeap(),0,df->dwSize);
-    if (new_df == 0) {
-        WARN("out of memory\n");
-        return DIERR_OUTOFMEMORY;
-    }
+    if (new_df == 0)
+        goto FAILED;
 
     new_rgodf = HeapAlloc(GetProcessHeap(),0,df->dwNumObjs*df->dwObjSize);
-    if (new_rgodf == 0) {
-        WARN("out of memory\n");
-        HeapFree(GetProcessHeap(),0,new_df);
-        return DIERR_OUTOFMEMORY;
-    }
+    if (new_rgodf == 0)
+        goto FAILED;
 
     new_props = HeapAlloc(GetProcessHeap(),0,df->dwNumObjs*sizeof(ObjProps));
-    if (This->props == 0) {
-        WARN("out of memory\n");
-        HeapFree(GetProcessHeap(),0,new_rgodf);
-        HeapFree(GetProcessHeap(),0,new_df);
-        return DIERR_OUTOFMEMORY;
-    }
+    if (new_props == 0)
+        goto FAILED;
+
+    new_offsets = HeapAlloc(GetProcessHeap(),0,df->dwNumObjs*sizeof(int));
+    if (new_offsets == 0)
+        goto FAILED;
 
-    HeapFree(GetProcessHeap(),0,This->df);
-    HeapFree(GetProcessHeap(),0,This->df->rgodf);
+    HeapFree(GetProcessHeap(),0,This->user_df);
+    HeapFree(GetProcessHeap(),0,This->user_df->rgodf);
     HeapFree(GetProcessHeap(),0,This->props);
+    HeapFree(GetProcessHeap(),0,This->offsets);
+    release_DataFormat(This->transform);
 
-    This->df = new_df;
-    CopyMemory(This->df, df, df->dwSize);
-    This->df->rgodf = new_rgodf;
-    CopyMemory(This->df->rgodf,df->rgodf,df->dwNumObjs*df->dwObjSize);
+    This->user_df = new_df;
+    CopyMemory(This->user_df, df, df->dwSize);
+    This->user_df->rgodf = new_rgodf;
+    CopyMemory(This->user_df->rgodf,df->rgodf,df->dwNumObjs*df->dwObjSize);
     This->props = new_props;
     for (i = 0; i < df->dwNumObjs; i++) {
         This->props[i].lMin = 0;
-	This->props[i].lMax = 0xffff;
+        This->props[i].lMax = 0xffff;
         This->props[i].lDeadZone = 1000;
         This->props[i].lSaturation = 0;
     }
+    This->offsets = new_offsets;
+    This->transform = create_DataFormat(&c_dfDIJoystick2, This->user_df, This->offsets);
 
     return DI_OK;
+
+FAILED:
+    WARN("out of memory\n");
+    if (new_offsets)
+        HeapFree(GetProcessHeap(),0,new_offsets);
+    if (new_props)
+        HeapFree(GetProcessHeap(),0,new_props);
+    if (new_rgodf)
+        HeapFree(GetProcessHeap(),0,new_rgodf);
+    if (new_df)
+        HeapFree(GetProcessHeap(),0,new_df);
+    return DIERR_OUTOFMEMORY;
 }
 
 /******************************************************************************
@@ -392,13 +430,26 @@
 {
     ICOM_THIS(JoystickImpl,iface);
 
-    TRACE("(this=%p)\n",This);
-    if (This->joyfd!=-1)
-    	return 0;
-    This->joyfd=open(JOYDEV,O_RDONLY);
-    if (This->joyfd==-1)
-    	return DIERR_NOTFOUND;
+    TRACE("(%p)\n",This);
+
+    if (This->acquired) {
+        WARN("already acquired\n");
+        return S_FALSE;
+    }
+
+    /* open the joystick device */
+    if (This->joyfd==-1) {
+        TRACE("opening joystick device %s\n", JOYDEV);
+
+        This->joyfd=open(JOYDEV,O_RDONLY);
+        if (This->joyfd==-1) {
+            ERR("open(%s) failed: %s\n", JOYDEV, strerror(errno));
+            return DIERR_NOTFOUND;
+        }
+    }
+
     This->acquired = TRUE;
+
     return DI_OK;
 }
 
@@ -409,24 +460,32 @@
 {
     ICOM_THIS(JoystickImpl,iface);
 
-    TRACE("(this=%p)\n",This);
+    TRACE("(%p)\n",This);
+
+    if (!This->acquired) {
+        WARN("not acquired\n");
+        return DIERR_NOTACQUIRED;
+    }
+
     if (This->joyfd!=-1) {
-  	close(This->joyfd);
-	This->joyfd = -1;
+        TRACE("closing joystick device\n");
+        close(This->joyfd);
+        This->joyfd = -1;
         This->acquired = FALSE;
-	return DI_OK;
+        return DI_OK;
     }
 
     This->acquired = FALSE;
+
     return DI_NOEFFECT;
 }
 
 LONG map_axis(JoystickImpl * This, short val, short index)
 {
-    double	fval = val;
-    double	fmin = This->props[index].lMin;
-    double	fmax = This->props[index].lMax;
-    double	fret;
+    double    fval = val;
+    double    fmin = This->props[index].lMin;
+    double    fmax = This->props[index].lMax;
+    double    fret;
 
     fret = (((fval + 32767.0) * (fmax - fmin)) / (32767.0*2.0)) + fmin;
 
@@ -438,14 +497,28 @@
     return fret;
 }
 
+/* convert user format offset to user format object index */
+int offset_to_object(JoystickImpl *This, int offset)
+{
+    int i;
+
+    for (i = 0; i < This->user_df->dwNumObjs; i++) {
+        if (This->user_df->rgodf[i].dwOfs == offset)
+            return i;
+    }
+
+    return -1;
+}
+
 static void joy_polldev(JoystickImpl *This) {
     struct timeval tv;
     fd_set	readfds;
     struct	js_event jse;
+    TRACE("(%p)\n", This);
 
     if (This->joyfd==-1) {
-        WARN("device not open\n");
-	return;
+        WARN("no device\n");
+        return;
     }
     while (1) {
 	memset(&tv,0,sizeof(tv));
@@ -456,51 +529,53 @@
 	if (sizeof(jse)!=read(This->joyfd,&jse,sizeof(jse))) {
 	    return;
 	}
-	TRACE("js_event: type 0x%x, number %d, value %d\n",
+        TRACE("js_event: type 0x%x, number %d, value %d\n",
               jse.type,jse.number,jse.value);
-	if (jse.type & JS_EVENT_BUTTON) {
-	    GEN_EVENT(DIJOFS_BUTTON(jse.number),jse.value?0x80:0x00,jse.time,(This->dinput->evsequence)++);
-	    This->js.rgbButtons[jse.number] = jse.value?0x80:0x00;
-	}
-	if (jse.type & JS_EVENT_AXIS) {
-	    switch (jse.number) {
-	    case 0:
-		GEN_EVENT(jse.number*4,jse.value,jse.time,(This->dinput->evsequence)++);
-		This->js.lX = map_axis(This, jse.value, jse.number);
-		break;
-	    case 1:
-		GEN_EVENT(jse.number*4,jse.value,jse.time,(This->dinput->evsequence)++);
-		This->js.lY = map_axis(This, jse.value, jse.number);
-		break;
-	    case 2:
-		GEN_EVENT(jse.number*4,jse.value,jse.time,(This->dinput->evsequence)++);
-		This->js.lZ = map_axis(This, jse.value, jse.number);
-		break;
-	    case 3:
-		GEN_EVENT(jse.number*4,jse.value,jse.time,(This->dinput->evsequence)++);
-		This->js.lRx = map_axis(This, jse.value, jse.number);
-		break;
-	    case 4:
-		GEN_EVENT(jse.number*4,jse.value,jse.time,(This->dinput->evsequence)++);
-		This->js.lRy = map_axis(This, jse.value, jse.number);
-		break;
-	    case 5:
-		GEN_EVENT(jse.number*4,jse.value,jse.time,(This->dinput->evsequence)++);
-		This->js.lRz = map_axis(This, jse.value, jse.number);
-		break;
-	    case 6:
-		GEN_EVENT(jse.number*4,jse.value,jse.time,(This->dinput->evsequence)++);
-		This->js.rglSlider[0] = map_axis(This, jse.value, jse.number);
-		break;
-	    case 7:
-		GEN_EVENT(jse.number*4,jse.value,jse.time,(This->dinput->evsequence)++);
-		This->js.rglSlider[1] = map_axis(This, jse.value, jse.number);
-		break;
-	    default:
-		FIXME("more than 8 axes (%d) not handled!\n",jse.number);
-		break;
-	    }
-	}
+        if (jse.type & JS_EVENT_BUTTON) {
+            int offset = This->offsets[jse.number + 12];
+            int value = jse.value?0x80:0x00;
+
+            This->js.rgbButtons[jse.number] = value;
+            GEN_EVENT(offset,value,jse.time,(This->dinput->evsequence)++);
+        } else if (jse.type & JS_EVENT_AXIS) {
+            if (jse.number < 8) {
+                int offset = This->offsets[jse.number];
+                int index = offset_to_object(This, offset);
+                LONG value = map_axis(This, jse.value, index);
+
+                /* FIXME do deadzone and saturation here */
+
+                switch (jse.number) {
+                case 0:
+                    This->js.lX = value;
+                    break;
+                case 1:
+                    This->js.lY = value;
+                    break;
+                case 2:
+                    This->js.lZ = value;
+                    break;
+                case 3:
+                    This->js.lRx = value;
+                    break;
+                case 4:
+                    This->js.lRy = value;
+                    break;
+                case 5:
+                    This->js.lRz = value;
+                    break;
+                case 6:
+                    This->js.rglSlider[0] = value;
+                    break;
+                case 7:
+                    This->js.rglSlider[1] = value;
+                    break;
+                }
+
+                GEN_EVENT(offset,value,jse.time,(This->dinput->evsequence)++);
+            } else 
+                WARN("axis %d not supported\n", jse.number);
+        }
     }
 }
 
@@ -517,14 +592,17 @@
 
     TRACE("(%p,0x%08lx,%p)\n",This,len,ptr);
 
+    if (!This->acquired) {
+        WARN("not acquired\n");
+        return DIERR_NOTACQUIRED;
+    }
+
+    /* update joystick state */
     joy_polldev(This);
-    if ((len != sizeof(DIJOYSTATE)) && (len != sizeof(DIJOYSTATE2))) {
-    	FIXME("len %ld is not sizeof(DIJOYSTATE), unsupported format.\n",len);
-	return E_FAIL;
-    }
-    memcpy(ptr,&(This->js),len);
-    This->queue_head = 0;
-    This->queue_tail = 0;
+
+    /* convert and copy data to user supplied buffer */
+    fill_DataFormat(ptr, &This->js, This->transform);
+
     return DI_OK;
 }
 
@@ -555,26 +633,22 @@
 {
     int i;
     if (ph->dwHow == DIPH_BYOFFSET) {
-        for (i = 0; i < This->df->dwNumObjs; i++) {
-            if (This->df->rgodf[i].dwOfs == ph->dwObj) {
-                return i;
-            }
-        }
+        return offset_to_object(This, ph->dwObj);
     } else if (ph->dwHow == DIPH_BYID) {
         int axis = 0;
         int button = 0;
-        for (i = 0; i < This->df->dwNumObjs; i++) {
+        for (i = 0; i < This->user_df->dwNumObjs; i++) {
             DWORD type = 0;
-            if (DIDFT_GETTYPE(This->df->rgodf[i].dwType) & DIDFT_AXIS) {
-                axis++;  
-                type = DIDFT_GETTYPE(This->df->rgodf[i].dwType) | 
-                    DIDFT_MAKEINSTANCE(axis << WINE_JOYSTICK_AXIS_BASE); 
+            if (DIDFT_GETTYPE(This->user_df->rgodf[i].dwType) & DIDFT_AXIS) {
+                axis++;
+                type = DIDFT_GETTYPE(This->user_df->rgodf[i].dwType) |
+                    DIDFT_MAKEINSTANCE(axis << WINE_JOYSTICK_AXIS_BASE);
                 TRACE("type = 0x%08lx\n", type);
             }
-            if (DIDFT_GETTYPE(This->df->rgodf[i].dwType) & DIDFT_BUTTON) {
-                button++;  
-                type = DIDFT_GETTYPE(This->df->rgodf[i].dwType) |
-                    DIDFT_MAKEINSTANCE(button << WINE_JOYSTICK_BUTTON_BASE); 
+            if (DIDFT_GETTYPE(This->user_df->rgodf[i].dwType) & DIDFT_BUTTON) {
+                button++;
+                type = DIDFT_GETTYPE(This->user_df->rgodf[i].dwType) |
+                    DIDFT_MAKEINSTANCE(button << WINE_JOYSTICK_BUTTON_BASE);
                 TRACE("type = 0x%08lx\n", type);
             }
             if (type == ph->dwObj) {
@@ -616,7 +690,7 @@
                 This->props[obj].lMin = pr->lMin;
                 This->props[obj].lMax = pr->lMax;
                 return DI_OK;
-            }       
+            }
             break;
         }
         case (DWORD)DIPROP_DEADZONE: {
@@ -727,7 +801,13 @@
 static HRESULT WINAPI JoystickAImpl_Poll(LPDIRECTINPUTDEVICE8A iface)
 {
     ICOM_THIS(JoystickImpl,iface);
-    TRACE("()\n");
+
+    TRACE("(%p)\n",This);
+
+    if (!This->acquired) {
+        WARN("not acquired\n");
+        return DIERR_NOTACQUIRED;
+    }
 
     joy_polldev(This);
     return DI_OK;
@@ -883,7 +963,7 @@
         case (DWORD) DIPROP_RANGE: {
             LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph;
             int obj = find_property(This, pdiph);
-            /* The app is querying the current range of the axis 
+            /* The app is querying the current range of the axis
              * return the lMin and lMax values */
             if (obj >= 0) {
                 pr->lMin = This->props[obj].lMin;
@@ -960,16 +1040,16 @@
 
     switch (dwHow) {
     case DIPH_BYOFFSET:
-        for (i = 0; i < This->df->dwNumObjs; i++) {
-            if (This->df->rgodf[i].dwOfs == dwObj) {
-                if (This->df->rgodf[i].pguid)
-                    didoiA.guidType = *This->df->rgodf[i].pguid;
+        for (i = 0; i < This->user_df->dwNumObjs; i++) {
+            if (This->user_df->rgodf[i].dwOfs == dwObj) {
+                if (This->user_df->rgodf[i].pguid)
+                    didoiA.guidType = *This->user_df->rgodf[i].pguid;
                 else
                     didoiA.guidType = GUID_NULL;
                 didoiA.dwOfs = dwObj;
-                didoiA.dwType = This->df->rgodf[i].dwType;
-                didoiA.dwFlags = This->df->rgodf[i].dwFlags;
-                strcpy(didoiA.tszName, "?????"); 
+                didoiA.dwType = This->user_df->rgodf[i].dwType;
+                didoiA.dwFlags = This->user_df->rgodf[i].dwFlags;
+                strcpy(didoiA.tszName, "?????");
                 CopyMemory(pdidoi, &didoiA, pdidoi->dwSize);
                 return DI_OK;
             }


More information about the wine-patches mailing list