Fixed crash in winamp reported by Andreas Mohr.
[wine] / dlls / dplayx / lobbysp.c
1 /* This contains the implementation of the Lobby Service
2  * Providers interface required to communicate with Direct Play
3  *
4  * Copyright 2001 Peter Hunnisett <hunnise@nortelnetworks.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "winerror.h"
22 #include "wine/debug.h"
23
24 #include "lobbysp.h"
25 #include "dplay_global.h"
26 #include "dpinit.h"
27
28 WINE_DEFAULT_DEBUG_CHANNEL(dplay);
29
30 /* Prototypes */
31 static BOOL DPLSP_CreateIUnknown( LPVOID lpSP );
32 static BOOL DPLSP_DestroyIUnknown( LPVOID lpSP );
33 static BOOL DPLSP_CreateDPLobbySP( LPVOID lpSP, IDirectPlay2Impl* dp );
34 static BOOL DPLSP_DestroyDPLobbySP( LPVOID lpSP );
35
36
37 /* Predefine the interface */
38 typedef struct IDPLobbySPImpl IDPLobbySPImpl;
39
40 typedef struct tagDPLobbySPIUnknownData
41 {
42   ULONG             ulObjRef;
43   CRITICAL_SECTION  DPLSP_lock;
44 } DPLobbySPIUnknownData;
45
46 typedef struct tagDPLobbySPData
47 {
48   IDirectPlay2Impl* dplay;
49 } DPLobbySPData;
50
51 #define DPLSP_IMPL_FIELDS \
52    ULONG ulInterfaceRef; \
53    DPLobbySPIUnknownData* unk; \
54    DPLobbySPData* sp;
55
56 struct IDPLobbySPImpl
57 {
58   ICOM_VFIELD(IDPLobbySP);
59   DPLSP_IMPL_FIELDS
60 };
61
62 /* Forward declaration of virtual tables */
63 static ICOM_VTABLE(IDPLobbySP) dpLobbySPVT;
64
65 extern
66 HRESULT DPLSP_CreateInterface( REFIID riid, LPVOID* ppvObj, IDirectPlay2Impl* dp )
67 {
68   TRACE( " for %s\n", debugstr_guid( riid ) );
69
70   *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
71                        sizeof( IDPLobbySPImpl ) );
72
73   if( *ppvObj == NULL )
74   {
75     return DPERR_OUTOFMEMORY;
76   }
77
78   if( IsEqualGUID( &IID_IDPLobbySP, riid ) )
79   {
80     ICOM_THIS(IDPLobbySPImpl,*ppvObj);
81     ICOM_VTBL(This) = &dpLobbySPVT;
82   }
83   else
84   {
85     /* Unsupported interface */
86     HeapFree( GetProcessHeap(), 0, *ppvObj );
87     *ppvObj = NULL;
88
89     return E_NOINTERFACE;
90   }
91
92   /* Initialize it */
93   if( DPLSP_CreateIUnknown( *ppvObj ) &&
94       DPLSP_CreateDPLobbySP( *ppvObj, dp )
95     )
96   {
97     IDPLobbySP_AddRef( (LPDPLOBBYSP)*ppvObj );
98     return S_OK;
99   }
100
101   /* Initialize failed, destroy it */
102   DPLSP_DestroyDPLobbySP( *ppvObj );
103   DPLSP_DestroyIUnknown( *ppvObj );
104
105   HeapFree( GetProcessHeap(), 0, *ppvObj );
106   *ppvObj = NULL;
107
108   return DPERR_NOMEMORY;
109 }
110
111 static BOOL DPLSP_CreateIUnknown( LPVOID lpSP )
112 {
113   ICOM_THIS(IDPLobbySPImpl,lpSP);
114
115   This->unk = (DPLobbySPIUnknownData*)HeapAlloc( GetProcessHeap(),
116                                                     HEAP_ZERO_MEMORY,
117                                                     sizeof( *(This->unk) ) );
118
119   if ( This->unk == NULL )
120   {
121     return FALSE;
122   }
123
124   InitializeCriticalSection( &This->unk->DPLSP_lock );
125
126   return TRUE;
127 }
128
129 static BOOL DPLSP_DestroyIUnknown( LPVOID lpSP )
130 {
131   ICOM_THIS(IDPLobbySPImpl,lpSP);
132
133   DeleteCriticalSection( &This->unk->DPLSP_lock );
134   HeapFree( GetProcessHeap(), 0, This->unk );
135
136   return TRUE;
137 }
138
139 static BOOL DPLSP_CreateDPLobbySP( LPVOID lpSP, IDirectPlay2Impl* dp )
140 {
141   ICOM_THIS(IDPLobbySPImpl,lpSP);
142
143   This->sp = (DPLobbySPData*)HeapAlloc( GetProcessHeap(),
144                                         HEAP_ZERO_MEMORY,
145                                         sizeof( *(This->sp) ) );
146
147   if ( This->sp == NULL )
148   {
149     return FALSE;
150   }
151
152   This->sp->dplay = dp;
153
154   /* Normally we should be keeping a reference, but since only the dplay
155    * interface that created us can destroy us, we do not keep a reference
156    * to it (ie we'd be stuck with always having one reference to the dplay
157    * object, and hence us, around).
158    * NOTE: The dp object does reference count us.
159    *
160    * FIXME: This is a kludge to get around a problem where a queryinterface
161    *        is used to get a new interface and then is closed. We will then
162    *        reference garbage. However, with this we will never deallocate
163    *        the interface we store. The correct fix is to require all
164    *        DP internal interfaces to use the This->dp2 interface which
165    *        should be changed to This->dp
166    */
167   IDirectPlayX_AddRef( (LPDIRECTPLAY2)dp );
168
169
170   return TRUE;
171 }
172
173 static BOOL DPLSP_DestroyDPLobbySP( LPVOID lpSP )
174 {
175   ICOM_THIS(IDPLobbySPImpl,lpSP);
176
177   HeapFree( GetProcessHeap(), 0, This->sp );
178
179   return TRUE;
180 }
181
182 static
183 HRESULT WINAPI DPLSP_QueryInterface
184 ( LPDPLOBBYSP iface,
185   REFIID riid,
186   LPVOID* ppvObj
187 )
188 {
189   ICOM_THIS(IDPLobbySPImpl,iface);
190   TRACE("(%p)->(%s,%p)\n", This, debugstr_guid( riid ), ppvObj );
191
192   *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
193                        sizeof( *This ) );
194
195   if( *ppvObj == NULL )
196   {
197     return DPERR_OUTOFMEMORY;
198   }
199
200   CopyMemory( *ppvObj, This, sizeof( *This )  );
201   (*(IDPLobbySPImpl**)ppvObj)->ulInterfaceRef = 0;
202
203   if( IsEqualGUID( &IID_IDPLobbySP, riid ) )
204   {
205     ICOM_THIS(IDPLobbySPImpl,*ppvObj);
206     ICOM_VTBL(This) = &dpLobbySPVT;
207   }
208   else
209   {
210     /* Unsupported interface */
211     HeapFree( GetProcessHeap(), 0, *ppvObj );
212     *ppvObj = NULL;
213
214     return E_NOINTERFACE;
215   }
216
217   IDPLobbySP_AddRef( (LPDPLOBBYSP)*ppvObj );
218
219   return S_OK;
220 }
221
222 static
223 ULONG WINAPI DPLSP_AddRef
224 ( LPDPLOBBYSP iface )
225 {
226   ULONG ulInterfaceRefCount, ulObjRefCount;
227   ICOM_THIS(IDPLobbySPImpl,iface);
228
229   ulObjRefCount       = InterlockedIncrement( &This->unk->ulObjRef );
230   ulInterfaceRefCount = InterlockedIncrement( &This->ulInterfaceRef );
231
232   TRACE( "ref count incremented to %lu:%lu for %p\n",
233          ulInterfaceRefCount, ulObjRefCount, This );
234
235   return ulObjRefCount;
236 }
237
238 static
239 ULONG WINAPI DPLSP_Release
240 ( LPDPLOBBYSP iface )
241 {
242   ULONG ulInterfaceRefCount, ulObjRefCount;
243   ICOM_THIS(IDPLobbySPImpl,iface);
244
245   ulObjRefCount       = InterlockedDecrement( &This->unk->ulObjRef );
246   ulInterfaceRefCount = InterlockedDecrement( &This->ulInterfaceRef );
247
248   TRACE( "ref count decremented to %lu:%lu for %p\n",
249          ulInterfaceRefCount, ulObjRefCount, This );
250
251   /* Deallocate if this is the last reference to the object */
252   if( ulObjRefCount == 0 )
253   {
254      DPLSP_DestroyDPLobbySP( This );
255      DPLSP_DestroyIUnknown( This );
256   }
257
258   if( ulInterfaceRefCount == 0 )
259   {
260     HeapFree( GetProcessHeap(), 0, This );
261   }
262
263   return ulInterfaceRefCount;
264 }
265
266 static
267 HRESULT WINAPI IDPLobbySPImpl_AddGroupToGroup
268 ( LPDPLOBBYSP iface,
269   LPSPDATA_ADDREMOTEGROUPTOGROUP argtg
270 )
271 {
272   ICOM_THIS(IDPLobbySPImpl,iface);
273   FIXME( "(%p)->(%p):stub\n", This, argtg );
274   return DP_OK;
275 }
276
277 static
278 HRESULT WINAPI IDPLobbySPImpl_AddPlayerToGroup
279 ( LPDPLOBBYSP iface,
280   LPSPDATA_ADDREMOTEPLAYERTOGROUP arptg
281 )
282 {
283   ICOM_THIS(IDPLobbySPImpl,iface);
284   FIXME( "(%p)->(%p):stub\n", This, arptg );
285   return DP_OK;
286 }
287
288 static
289 HRESULT WINAPI IDPLobbySPImpl_CreateGroup
290 ( LPDPLOBBYSP iface,
291   LPSPDATA_CREATEREMOTEGROUP crg
292 )
293 {
294   ICOM_THIS(IDPLobbySPImpl,iface);
295   FIXME( "(%p)->(%p):stub\n", This, crg );
296   return DP_OK;
297 }
298
299 static
300 HRESULT WINAPI IDPLobbySPImpl_CreateGroupInGroup
301 ( LPDPLOBBYSP iface,
302   LPSPDATA_CREATEREMOTEGROUPINGROUP crgig
303 )
304 {
305   ICOM_THIS(IDPLobbySPImpl,iface);
306   FIXME( "(%p)->(%p):stub\n", This, crgig );
307   return DP_OK;
308 }
309
310 static
311 HRESULT WINAPI IDPLobbySPImpl_DeleteGroupFromGroup
312 ( LPDPLOBBYSP iface,
313   LPSPDATA_DELETEREMOTEGROUPFROMGROUP drgfg
314 )
315 {
316   ICOM_THIS(IDPLobbySPImpl,iface);
317   FIXME( "(%p)->(%p):stub\n", This, drgfg );
318   return DP_OK;
319 }
320
321 static
322 HRESULT WINAPI IDPLobbySPImpl_DeletePlayerFromGroup
323 ( LPDPLOBBYSP iface,
324   LPSPDATA_DELETEREMOTEPLAYERFROMGROUP drpfg
325 )
326 {
327   ICOM_THIS(IDPLobbySPImpl,iface);
328   FIXME( "(%p)->(%p):stub\n", This, drpfg );
329   return DP_OK;
330 }
331
332 static
333 HRESULT WINAPI IDPLobbySPImpl_DestroyGroup
334 ( LPDPLOBBYSP iface,
335   LPSPDATA_DESTROYREMOTEGROUP drg
336 )
337 {
338   ICOM_THIS(IDPLobbySPImpl,iface);
339   FIXME( "(%p)->(%p):stub\n", This, drg );
340   return DP_OK;
341 }
342
343 static
344 HRESULT WINAPI IDPLobbySPImpl_EnumSessionsResponse
345 ( LPDPLOBBYSP iface,
346   LPSPDATA_ENUMSESSIONSRESPONSE er
347 )
348 {
349   ICOM_THIS(IDPLobbySPImpl,iface);
350   FIXME( "(%p)->(%p):stub\n", This, er );
351   return DP_OK;
352 }
353
354 static
355 HRESULT WINAPI IDPLobbySPImpl_GetSPDataPointer
356 ( LPDPLOBBYSP iface,
357   LPVOID* lplpData
358 )
359 {
360   ICOM_THIS(IDPLobbySPImpl,iface);
361   FIXME( "(%p)->(%p):stub\n", This, lplpData );
362   return DP_OK;
363 }
364
365 static
366 HRESULT WINAPI IDPLobbySPImpl_HandleMessage
367 ( LPDPLOBBYSP iface,
368   LPSPDATA_HANDLEMESSAGE hm
369 )
370 {
371   ICOM_THIS(IDPLobbySPImpl,iface);
372   FIXME( "(%p)->(%p):stub\n", This, hm );
373   return DP_OK;
374 }
375
376 static
377 HRESULT WINAPI IDPLobbySPImpl_SendChatMessage
378 ( LPDPLOBBYSP iface,
379   LPSPDATA_CHATMESSAGE cm
380 )
381 {
382   ICOM_THIS(IDPLobbySPImpl,iface);
383   FIXME( "(%p)->(%p):stub\n", This, cm );
384   return DP_OK;
385 }
386
387 static
388 HRESULT WINAPI IDPLobbySPImpl_SetGroupName
389 ( LPDPLOBBYSP iface,
390   LPSPDATA_SETREMOTEGROUPNAME srgn
391 )
392 {
393   ICOM_THIS(IDPLobbySPImpl,iface);
394   FIXME( "(%p)->(%p):stub\n", This, srgn );
395   return DP_OK;
396 }
397
398 static
399 HRESULT WINAPI IDPLobbySPImpl_SetPlayerName
400 ( LPDPLOBBYSP iface,
401   LPSPDATA_SETREMOTEPLAYERNAME srpn
402 )
403 {
404   ICOM_THIS(IDPLobbySPImpl,iface);
405   FIXME( "(%p)->(%p):stub\n", This, srpn );
406   return DP_OK;
407 }
408
409 static
410 HRESULT WINAPI IDPLobbySPImpl_SetSessionDesc
411 ( LPDPLOBBYSP iface,
412   LPSPDATA_SETSESSIONDESC ssd
413 )
414 {
415   ICOM_THIS(IDPLobbySPImpl,iface);
416   FIXME( "(%p)->(%p):stub\n", This, ssd );
417   return DP_OK;
418 }
419
420 static
421 HRESULT WINAPI IDPLobbySPImpl_SetSPDataPointer
422 ( LPDPLOBBYSP iface,
423   LPVOID lpData
424 )
425 {
426   ICOM_THIS(IDPLobbySPImpl,iface);
427   FIXME( "(%p)->(%p):stub\n", This, lpData );
428   return DP_OK;
429 }
430
431 static
432 HRESULT WINAPI IDPLobbySPImpl_StartSession
433 ( LPDPLOBBYSP iface,
434   LPSPDATA_STARTSESSIONCOMMAND ssc
435 )
436 {
437   ICOM_THIS(IDPLobbySPImpl,iface);
438   FIXME( "(%p)->(%p):stub\n", This, ssc );
439   return DP_OK;
440 }
441
442
443 static struct ICOM_VTABLE(IDPLobbySP) dpLobbySPVT =
444 {
445   ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
446
447   DPLSP_QueryInterface,
448   DPLSP_AddRef,
449   DPLSP_Release,
450
451   IDPLobbySPImpl_AddGroupToGroup,
452   IDPLobbySPImpl_AddPlayerToGroup,
453   IDPLobbySPImpl_CreateGroup,
454   IDPLobbySPImpl_CreateGroupInGroup,
455   IDPLobbySPImpl_DeleteGroupFromGroup,
456   IDPLobbySPImpl_DeletePlayerFromGroup,
457   IDPLobbySPImpl_DestroyGroup,
458   IDPLobbySPImpl_EnumSessionsResponse,
459   IDPLobbySPImpl_GetSPDataPointer,
460   IDPLobbySPImpl_HandleMessage,
461   IDPLobbySPImpl_SendChatMessage,
462   IDPLobbySPImpl_SetGroupName,
463   IDPLobbySPImpl_SetPlayerName,
464   IDPLobbySPImpl_SetSessionDesc,
465   IDPLobbySPImpl_SetSPDataPointer,
466   IDPLobbySPImpl_StartSession
467
468 };