Fixed DC leak.
[wine] / dlls / dinput / dinput_main.c
1 /*              DirectInput
2  *
3  * Copyright 1998 Marcus Meissner
4  * Copyright 1998,1999 Lionel Ulmer
5  *
6  */
7 /* Status:
8  *
9  * - Tomb Raider 2 Demo:
10  *   Playable using keyboard only.
11  * - WingCommander Prophecy Demo:
12  *   Doesn't get Input Focus.
13  * 
14  * - Fallout : works great in X and DGA mode
15  *
16  * FIXME: The keyboard handling needs to (and will) be merged into keyboard.c
17  *        (The current implementation is currently only a proof of concept and
18  *         an utter mess.)
19  */
20
21 #include "config.h"
22 #include <assert.h>
23 #include <string.h>
24
25 #include "debugtools.h"
26 #include "winbase.h"
27 #include "winerror.h"
28 #include "windef.h"
29 #include "dinput_private.h"
30
31 DEFAULT_DEBUG_CHANNEL(dinput);
32
33 static ICOM_VTABLE(IDirectInputA) ddiavt;
34 static ICOM_VTABLE(IDirectInput7A) ddi7avt;
35
36 /* This array will be filled a dinput.so loading */
37 #define MAX_WINE_DINPUT_DEVICES 4
38 static dinput_device * dinput_devices[MAX_WINE_DINPUT_DEVICES];
39 static int nrof_dinput_devices = 0;
40
41 /* register a direct draw driver. We better not use malloc for we are in 
42  * the ELF startup initialisation at this point.
43  */
44 void dinput_register_device(dinput_device *device) {
45     int i;
46
47     /* insert according to priority */
48     for (i=0;i<nrof_dinput_devices;i++) {
49         if (dinput_devices[i]->pref <= device->pref) {
50             memcpy(dinput_devices+i+1,dinput_devices+i,sizeof(dinput_devices[0])*(nrof_dinput_devices-i));
51             dinput_devices[i] = device;
52             break;
53         }
54     }
55     if (i==nrof_dinput_devices) /* not found, or too low priority */
56         dinput_devices[nrof_dinput_devices] = device;
57
58     nrof_dinput_devices++;
59
60     /* increase MAX_DDRAW_DRIVERS if the line below triggers */
61     assert(nrof_dinput_devices <= MAX_WINE_DINPUT_DEVICES);
62 }
63
64 /******************************************************************************
65  *      DirectInputCreateEx (DINPUT.@)
66  */
67 HRESULT WINAPI DirectInputCreateEx(
68         HINSTANCE hinst, DWORD dwVersion, REFIID riid, LPVOID *ppDI,
69         LPUNKNOWN punkOuter
70 ) {
71         IDirectInputAImpl* This;
72
73         TRACE("(0x%08lx,%04lx,%s,%p,%p)\n",
74                 (DWORD)hinst,dwVersion,debugstr_guid(riid),ppDI,punkOuter
75         );
76         if (IsEqualGUID(&IID_IDirectInputA,riid)) {
77           This = (IDirectInputAImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputAImpl));
78           This->ref = 1;
79           ICOM_VTBL(This) = &ddiavt;
80           *ppDI = This;
81           
82           return DI_OK;
83         }
84         
85         if (IsEqualGUID(&IID_IDirectInput7A,riid)) {
86           This = (IDirectInputAImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputAImpl));
87           This->ref = 1;
88           ICOM_VTBL(This) = (ICOM_VTABLE(IDirectInputA) *) &ddi7avt;
89           *ppDI = This;
90           
91           return DI_OK;
92         }
93
94         return DIERR_OLDDIRECTINPUTVERSION;
95 }
96
97 /******************************************************************************
98  *      DirectInputCreateA (DINPUT.@)
99  */
100 HRESULT WINAPI DirectInputCreateA(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTA *ppDI, LPUNKNOWN punkOuter)
101 {
102         IDirectInputAImpl* This;
103         TRACE("(0x%08lx,%04lx,%p,%p)\n",
104                 (DWORD)hinst,dwVersion,ppDI,punkOuter
105         );
106         This = (IDirectInputAImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputAImpl));
107         This->ref = 1;
108         ICOM_VTBL(This) = &ddiavt;
109         *ppDI=(IDirectInputA*)This;
110         return 0;
111 }
112 /******************************************************************************
113  *      IDirectInputA_EnumDevices
114  */
115 static HRESULT WINAPI IDirectInputAImpl_EnumDevices(
116         LPDIRECTINPUT7A iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKA lpCallback,
117         LPVOID pvRef, DWORD dwFlags
118 )
119 {
120         ICOM_THIS(IDirectInputAImpl,iface);
121         DIDEVICEINSTANCEA devInstance;
122         int i;
123
124         TRACE("(this=%p,0x%04lx,%p,%p,%04lx)\n", This, dwDevType, lpCallback, pvRef, dwFlags);
125
126         for (i = 0; i < nrof_dinput_devices; i++) {
127           if (dinput_devices[i]->enum_device(dwDevType, dwFlags, &devInstance)) {
128             if (lpCallback(&devInstance,pvRef) == DIENUM_STOP)
129               return 0;
130           }
131         }
132         
133         return 0;
134 }
135
136 static ULONG WINAPI IDirectInputAImpl_AddRef(LPDIRECTINPUT7A iface)
137 {
138         ICOM_THIS(IDirectInputAImpl,iface);
139         return ++(This->ref);
140 }
141
142 static ULONG WINAPI IDirectInputAImpl_Release(LPDIRECTINPUT7A iface)
143 {
144         ICOM_THIS(IDirectInputAImpl,iface);
145         if (!(--This->ref)) {
146                 HeapFree(GetProcessHeap(),0,This);
147                 return 0;
148         }
149         return This->ref;
150 }
151
152 static HRESULT WINAPI IDirectInputAImpl_CreateDevice(
153         LPDIRECTINPUT7A iface,REFGUID rguid,LPDIRECTINPUTDEVICEA* pdev,
154         LPUNKNOWN punk
155 ) {
156         ICOM_THIS(IDirectInputAImpl,iface);
157         HRESULT ret_value = DIERR_DEVICENOTREG;
158         int i;
159         
160         TRACE("(this=%p,%s,%p,%p)\n",This,debugstr_guid(rguid),pdev,punk);
161
162         /* Loop on all the devices to see if anyone matches the given GUID */
163         for (i = 0; i < nrof_dinput_devices; i++) {
164           HRESULT ret;
165           if ((ret = dinput_devices[i]->create_device(This, rguid, NULL, pdev)) == DI_OK)
166             return DI_OK;
167
168           if (ret == DIERR_NOINTERFACE)
169             ret_value = DIERR_NOINTERFACE;
170         }
171
172         return ret_value;
173 }
174
175 static HRESULT WINAPI IDirectInputAImpl_QueryInterface(
176         LPDIRECTINPUT7A iface,REFIID riid,LPVOID *ppobj
177 ) {
178         ICOM_THIS(IDirectInputAImpl,iface);
179
180         TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
181         if (IsEqualGUID(&IID_IUnknown,riid)) {
182                 IDirectInputA_AddRef(iface);
183                 *ppobj = This;
184                 return 0;
185         }
186         if (IsEqualGUID(&IID_IDirectInputA,riid)) {
187                 IDirectInputA_AddRef(iface);
188                 *ppobj = This;
189                 return 0;
190         }
191         TRACE("Unsupported interface !\n");
192         return E_FAIL;
193 }
194
195 static HRESULT WINAPI IDirectInputAImpl_Initialize(
196         LPDIRECTINPUT7A iface,HINSTANCE hinst,DWORD x
197 ) {
198         return DIERR_ALREADYINITIALIZED;
199 }
200
201 static HRESULT WINAPI IDirectInputAImpl_GetDeviceStatus(LPDIRECTINPUT7A iface,
202                                                         REFGUID rguid) {
203   ICOM_THIS(IDirectInputAImpl,iface);
204   
205   FIXME("(%p)->(%s): stub\n",This,debugstr_guid(rguid));
206   
207   return DI_OK;
208 }
209
210 static HRESULT WINAPI IDirectInputAImpl_RunControlPanel(LPDIRECTINPUT7A iface,
211                                                         HWND hwndOwner,
212                                                         DWORD dwFlags) {
213   ICOM_THIS(IDirectInputAImpl,iface);
214   FIXME("(%p)->(%08lx,%08lx): stub\n",This, (DWORD) hwndOwner, dwFlags);
215   
216   return DI_OK;
217 }
218
219 static HRESULT WINAPI IDirectInput2AImpl_FindDevice(LPDIRECTINPUT2A iface, REFGUID rguid,
220                                                     LPCSTR pszName, LPGUID pguidInstance) {
221   ICOM_THIS(IDirectInputAImpl,iface);
222   FIXME("(%p)->(%s, %s, %p): stub\n", This, debugstr_guid(rguid), pszName, pguidInstance);
223   
224   return DI_OK;
225 }
226
227 static HRESULT WINAPI IDirectInput7AImpl_CreateDeviceEx(LPDIRECTINPUT7A iface, REFGUID rguid,
228                                                         REFIID riid, LPVOID* pvOut, LPUNKNOWN lpUnknownOuter)
229 {
230   ICOM_THIS(IDirectInputAImpl,iface);
231   HRESULT ret_value = DIERR_DEVICENOTREG;
232   int i;
233         
234   TRACE("(%p)->(%s, %s, %p, %p)\n", This, debugstr_guid(rguid), debugstr_guid(riid), pvOut, lpUnknownOuter);
235
236   /* Loop on all the devices to see if anyone matches the given GUID */
237   for (i = 0; i < nrof_dinput_devices; i++) {
238     HRESULT ret;
239     if ((ret = dinput_devices[i]->create_device(This, rguid, riid, (LPDIRECTINPUTDEVICEA*) pvOut)) == DI_OK)
240       return DI_OK;
241     
242     if (ret == DIERR_NOINTERFACE)
243       ret_value = DIERR_NOINTERFACE;
244   }
245   
246   return ret_value;
247 }
248
249 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
250 # define XCAST(fun)     (typeof(ddiavt.fun))
251 #else
252 # define XCAST(fun)     (void*)
253 #endif
254
255 static ICOM_VTABLE(IDirectInputA) ddiavt = 
256 {
257         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
258         XCAST(QueryInterface)IDirectInputAImpl_QueryInterface,
259         XCAST(AddRef)IDirectInputAImpl_AddRef,
260         XCAST(Release)IDirectInputAImpl_Release,
261         XCAST(CreateDevice)IDirectInputAImpl_CreateDevice,
262         XCAST(EnumDevices)IDirectInputAImpl_EnumDevices,
263         XCAST(GetDeviceStatus)IDirectInputAImpl_GetDeviceStatus,
264         XCAST(RunControlPanel)IDirectInputAImpl_RunControlPanel,
265         XCAST(Initialize)IDirectInputAImpl_Initialize
266 };
267 #undef XCAST
268
269 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
270 # define XCAST(fun)     (typeof(ddi7avt.fun))
271 #else
272 # define XCAST(fun)     (void*)
273 #endif
274
275 static ICOM_VTABLE(IDirectInput7A) ddi7avt = {
276         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
277         XCAST(QueryInterface)IDirectInputAImpl_QueryInterface,
278         XCAST(AddRef)IDirectInputAImpl_AddRef,
279         XCAST(Release)IDirectInputAImpl_Release,
280         XCAST(CreateDevice)IDirectInputAImpl_CreateDevice,
281         XCAST(EnumDevices)IDirectInputAImpl_EnumDevices,
282         XCAST(GetDeviceStatus)IDirectInputAImpl_GetDeviceStatus,
283         XCAST(RunControlPanel)IDirectInputAImpl_RunControlPanel,
284         XCAST(Initialize)IDirectInputAImpl_Initialize,
285         XCAST(FindDevice)IDirectInput2AImpl_FindDevice,
286         IDirectInput7AImpl_CreateDeviceEx
287 };
288 #undef XCAST
289
290 /***********************************************************************
291  *              DllCanUnloadNow (DINPUT.@)
292  */
293 HRESULT WINAPI DINPUT_DllCanUnloadNow(void)
294 {
295     FIXME("(void): stub\n");
296
297     return S_FALSE;
298 }
299
300 /***********************************************************************
301  *              DllGetClassObject (DINPUT.@)
302  */
303 HRESULT WINAPI DINPUT_DllGetClassObject(REFCLSID rclsid, REFIID riid,
304                                         LPVOID *ppv)
305 {
306     FIXME("(%p, %p, %p): stub\n", debugstr_guid(rclsid), 
307           debugstr_guid(riid), ppv);
308
309     return CLASS_E_CLASSNOTAVAILABLE;
310 }
311
312 /***********************************************************************
313  *              DllRegisterServer (DINPUT.@)
314  */
315 HRESULT WINAPI DINPUT_DllRegisterServer(void)
316 {
317     FIXME("(void): stub\n");
318
319     return S_OK;
320 }
321
322 /***********************************************************************
323  *              DllUnregisterServer (DINPUT.@)
324  */
325 HRESULT WINAPI DINPUT_DllUnregisterServer(void)
326 {
327     FIXME("(void): stub\n");
328
329     return S_OK;
330 }