xref: /reactos/dll/directx/wine/dplayx/dplobby.c (revision c2c66aff)
1 /* Direct Play Lobby 2 & 3 Implementation
2  *
3  * Copyright 1998,1999,2000 - Peter Hunnisett
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19 
20 #include "dplayx_global.h"
21 
22 /* Forward declarations for this module helper methods */
23 HRESULT DPL_CreateCompoundAddress ( LPCDPCOMPOUNDADDRESSELEMENT lpElements, DWORD dwElementCount,
24                                     LPVOID lpAddress, LPDWORD lpdwAddressSize, BOOL bAnsiInterface )DECLSPEC_HIDDEN;
25 
26 static HRESULT DPL_CreateAddress( REFGUID guidSP, REFGUID guidDataType, LPCVOID lpData, DWORD dwDataSize,
27                            LPVOID lpAddress, LPDWORD lpdwAddressSize, BOOL bAnsiInterface );
28 
29 
30 /*****************************************************************************
31  * IDirectPlayLobby {1,2,3} implementation structure
32  *
33  * The philosophy behind this extra pointer dereference is that I wanted to
34  * have the same structure for all types of objects without having to do
35  * a lot of casting. I also only wanted to implement an interface in the
36  * object it was "released" with IUnknown interface being implemented in the 1 version.
37  * Of course, with these new interfaces comes the data required to keep the state required
38  * by these interfaces. So, basically, the pointers contain the data associated with
39  * a release. If you use the data associated with release 3 in a release 2 object, you'll
40  * get a run time trap, as that won't have any data.
41  *
42  */
43 struct DPLMSG
44 {
45   DPQ_ENTRY( DPLMSG ) msgs;  /* Link to next queued message */
46 };
47 typedef struct DPLMSG* LPDPLMSG;
48 
49 typedef struct IDirectPlayLobbyImpl
50 {
51     IDirectPlayLobby IDirectPlayLobby_iface;
52     IDirectPlayLobbyA IDirectPlayLobbyA_iface;
53     IDirectPlayLobby2 IDirectPlayLobby2_iface;
54     IDirectPlayLobby2A IDirectPlayLobby2A_iface;
55     IDirectPlayLobby3 IDirectPlayLobby3_iface;
56     IDirectPlayLobby3A IDirectPlayLobby3A_iface;
57     LONG numIfaces; /* "in use interfaces" refcount */
58     LONG ref, refA, ref2, ref2A, ref3, ref3A;
59     CRITICAL_SECTION lock;
60     HKEY cbkeyhack;
61     DWORD msgtid;
62     DPQ_HEAD( DPLMSG ) msgs; /* List of messages received */
63 } IDirectPlayLobbyImpl;
64 
65 static inline IDirectPlayLobbyImpl *impl_from_IDirectPlayLobby( IDirectPlayLobby *iface )
66 {
67     return CONTAINING_RECORD( iface, IDirectPlayLobbyImpl, IDirectPlayLobby_iface );
68 }
69 
70 static inline IDirectPlayLobbyImpl *impl_from_IDirectPlayLobbyA( IDirectPlayLobbyA *iface )
71 {
72     return CONTAINING_RECORD( iface, IDirectPlayLobbyImpl, IDirectPlayLobbyA_iface );
73 }
74 
75 static inline IDirectPlayLobbyImpl *impl_from_IDirectPlayLobby2( IDirectPlayLobby2 *iface )
76 {
77     return CONTAINING_RECORD( iface, IDirectPlayLobbyImpl, IDirectPlayLobby2_iface );
78 }
79 
80 static inline IDirectPlayLobbyImpl *impl_from_IDirectPlayLobby2A( IDirectPlayLobby2A *iface )
81 {
82     return CONTAINING_RECORD( iface, IDirectPlayLobbyImpl, IDirectPlayLobby2A_iface );
83 }
84 
85 static inline IDirectPlayLobbyImpl *impl_from_IDirectPlayLobby3( IDirectPlayLobby3 *iface )
86 {
87     return CONTAINING_RECORD( iface, IDirectPlayLobbyImpl, IDirectPlayLobby3_iface );
88 }
89 
90 static inline IDirectPlayLobbyImpl *impl_from_IDirectPlayLobby3A( IDirectPlayLobby3A *iface )
91 {
92     return CONTAINING_RECORD( iface, IDirectPlayLobbyImpl, IDirectPlayLobby3A_iface );
93 }
94 
95 static void dplobby_destroy(IDirectPlayLobbyImpl *obj)
96 {
97     if ( obj->msgtid )
98         FIXME( "Should kill the msg thread\n" );
99 
100     DPQ_DELETEQ( obj->msgs, msgs, LPDPLMSG, cbDeleteElemFromHeap );
101     obj->lock.DebugInfo->Spare[0] = 0;
102     DeleteCriticalSection( &obj->lock );
103     HeapFree( GetProcessHeap(), 0, obj );
104 }
105 
106 static HRESULT WINAPI IDirectPlayLobbyAImpl_QueryInterface( IDirectPlayLobbyA *iface, REFIID riid,
107         void **ppv )
108 {
109     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobbyA( iface );
110     return IDirectPlayLobby_QueryInterface( &This->IDirectPlayLobby3_iface, riid, ppv );
111 }
112 
113 static HRESULT WINAPI IDirectPlayLobbyImpl_QueryInterface( IDirectPlayLobby *iface, REFIID riid,
114         void **ppv )
115 {
116     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby( iface );
117     return IDirectPlayLobby_QueryInterface( &This->IDirectPlayLobby3_iface, riid, ppv );
118 }
119 
120 static HRESULT WINAPI IDirectPlayLobby2AImpl_QueryInterface( IDirectPlayLobby2A *iface, REFIID riid,
121         void **ppv )
122 {
123     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby2A( iface );
124     return IDirectPlayLobby_QueryInterface( &This->IDirectPlayLobby3_iface, riid, ppv );
125 }
126 
127 static HRESULT WINAPI IDirectPlayLobby2Impl_QueryInterface( IDirectPlayLobby2 *iface, REFIID riid,
128         void **ppv )
129 {
130     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby2( iface );
131     return IDirectPlayLobby_QueryInterface( &This->IDirectPlayLobby3_iface, riid, ppv );
132 }
133 
134 static HRESULT WINAPI IDirectPlayLobby3AImpl_QueryInterface( IDirectPlayLobby3A *iface, REFIID riid,
135         void **ppv )
136 {
137     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby3A( iface );
138     return IDirectPlayLobby_QueryInterface( &This->IDirectPlayLobby3_iface, riid, ppv );
139 }
140 
141 static HRESULT WINAPI IDirectPlayLobby3Impl_QueryInterface( IDirectPlayLobby3 *iface, REFIID riid,
142         void **ppv )
143 {
144     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby3( iface );
145 
146     if ( IsEqualGUID( &IID_IUnknown, riid ) )
147     {
148         TRACE( "(%p)->(IID_IUnknown %p)\n", This, ppv );
149         *ppv = &This->IDirectPlayLobby_iface;
150     }
151     else if ( IsEqualGUID( &IID_IDirectPlayLobby, riid ) )
152     {
153         TRACE( "(%p)->(IID_IDirectPlayLobby %p)\n", This, ppv );
154         *ppv = &This->IDirectPlayLobby_iface;
155     }
156     else if ( IsEqualGUID( &IID_IDirectPlayLobbyA, riid ) )
157     {
158         TRACE( "(%p)->(IID_IDirectPlayLobbyA %p)\n", This, ppv );
159         *ppv = &This->IDirectPlayLobbyA_iface;
160     }
161     else if ( IsEqualGUID( &IID_IDirectPlayLobby2, riid ) )
162     {
163         TRACE( "(%p)->(IID_IDirectPlayLobby2 %p)\n", This, ppv );
164         *ppv = &This->IDirectPlayLobby2_iface;
165     }
166     else if ( IsEqualGUID( &IID_IDirectPlayLobby2A, riid ) )
167     {
168         TRACE( "(%p)->(IID_IDirectPlayLobby2A %p)\n", This, ppv );
169         *ppv = &This->IDirectPlayLobby2A_iface;
170     }
171     else if ( IsEqualGUID( &IID_IDirectPlayLobby3, riid ) )
172     {
173         TRACE( "(%p)->(IID_IDirectPlay3 %p)\n", This, ppv );
174         *ppv = &This->IDirectPlayLobby3_iface;
175     }
176     else if ( IsEqualGUID( &IID_IDirectPlayLobby3A, riid ) )
177     {
178         TRACE( "(%p)->(IID_IDirectPlayLobby3A %p)\n", This, ppv );
179         *ppv = &This->IDirectPlayLobby3A_iface;
180     }
181     else
182     {
183         WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
184         *ppv = NULL;
185         return E_NOINTERFACE;
186     }
187 
188     IUnknown_AddRef((IUnknown*)*ppv);
189     return S_OK;
190 }
191 
192 static ULONG WINAPI IDirectPlayLobbyAImpl_AddRef( IDirectPlayLobbyA *iface )
193 {
194     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobbyA( iface );
195     ULONG ref = InterlockedIncrement( &This->refA );
196 
197     TRACE( "(%p) refA=%d\n", This, ref );
198 
199     if ( ref == 1 )
200         InterlockedIncrement( &This->numIfaces );
201 
202     return ref;
203 }
204 
205 static ULONG WINAPI IDirectPlayLobbyImpl_AddRef( IDirectPlayLobby *iface )
206 {
207     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby( iface );
208     ULONG ref = InterlockedIncrement( &This->ref );
209 
210     TRACE( "(%p) ref=%d\n", This, ref );
211 
212     if ( ref == 1 )
213         InterlockedIncrement( &This->numIfaces );
214 
215     return ref;
216 }
217 
218 static ULONG WINAPI IDirectPlayLobby2AImpl_AddRef(IDirectPlayLobby2A *iface)
219 {
220     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby2A( iface );
221     ULONG ref = InterlockedIncrement( &This->ref2A );
222 
223     TRACE( "(%p) ref2A=%d\n", This, ref );
224 
225     if ( ref == 1 )
226         InterlockedIncrement( &This->numIfaces );
227 
228     return ref;
229 }
230 
231 static ULONG WINAPI IDirectPlayLobby2Impl_AddRef(IDirectPlayLobby2 *iface)
232 {
233     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby2( iface );
234     ULONG ref = InterlockedIncrement( &This->ref2 );
235 
236     TRACE( "(%p) ref2=%d\n", This, ref );
237 
238     if ( ref == 1 )
239         InterlockedIncrement( &This->numIfaces );
240 
241     return ref;
242 }
243 
244 static ULONG WINAPI IDirectPlayLobby3AImpl_AddRef(IDirectPlayLobby3A *iface)
245 {
246     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby3A( iface );
247     ULONG ref = InterlockedIncrement( &This->ref3A );
248 
249     TRACE( "(%p) ref3A=%d\n", This, ref );
250 
251     if ( ref == 1 )
252         InterlockedIncrement( &This->numIfaces );
253 
254     return ref;
255 }
256 
257 static ULONG WINAPI IDirectPlayLobby3Impl_AddRef(IDirectPlayLobby3 *iface)
258 {
259     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby3( iface );
260     ULONG ref = InterlockedIncrement( &This->ref3 );
261 
262     TRACE( "(%p) ref3=%d\n", This, ref );
263 
264     if ( ref == 1 )
265         InterlockedIncrement( &This->numIfaces );
266 
267     return ref;
268 }
269 
270 static ULONG WINAPI IDirectPlayLobbyAImpl_Release( IDirectPlayLobbyA *iface )
271 {
272     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobbyA( iface );
273     ULONG ref = InterlockedDecrement( &This->refA );
274 
275     TRACE( "(%p) refA=%d\n", This, ref );
276 
277     if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
278         dplobby_destroy( This );
279 
280     return ref;
281 }
282 
283 static ULONG WINAPI IDirectPlayLobbyImpl_Release( IDirectPlayLobby *iface )
284 {
285     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby( iface );
286     ULONG ref = InterlockedDecrement( &This->ref );
287 
288     TRACE( "(%p) ref=%d\n", This, ref );
289 
290     if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
291         dplobby_destroy( This );
292 
293     return ref;
294 }
295 
296 static ULONG WINAPI IDirectPlayLobby2AImpl_Release(IDirectPlayLobby2A *iface)
297 {
298     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby2A( iface );
299     ULONG ref = InterlockedDecrement( &This->ref2A );
300 
301     TRACE( "(%p) ref2A=%d\n", This, ref );
302 
303     if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
304         dplobby_destroy( This );
305 
306     return ref;
307 }
308 
309 static ULONG WINAPI IDirectPlayLobby2Impl_Release(IDirectPlayLobby2 *iface)
310 {
311     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby2( iface );
312     ULONG ref = InterlockedDecrement( &This->ref2 );
313 
314     TRACE( "(%p) ref2=%d\n", This, ref );
315 
316     if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
317         dplobby_destroy( This );
318 
319     return ref;
320 }
321 
322 static ULONG WINAPI IDirectPlayLobby3AImpl_Release(IDirectPlayLobby3A *iface)
323 {
324     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby3A( iface );
325     ULONG ref = InterlockedDecrement( &This->ref3A );
326 
327     TRACE( "(%p) ref3A=%d\n", This, ref );
328 
329     if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
330         dplobby_destroy( This );
331 
332     return ref;
333 }
334 
335 static ULONG WINAPI IDirectPlayLobby3Impl_Release(IDirectPlayLobby3 *iface)
336 {
337     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby3( iface );
338     ULONG ref = InterlockedDecrement( &This->ref3 );
339 
340     TRACE( "(%p) ref3=%d\n", This, ref );
341 
342     if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
343         dplobby_destroy( This );
344 
345     return ref;
346 }
347 
348 
349 /********************************************************************
350  *
351  * Connects an application to the session specified by the DPLCONNECTION
352  * structure currently stored with the DirectPlayLobby object.
353  *
354  * Returns an IDirectPlay interface.
355  *
356  */
357 static HRESULT DPL_ConnectEx( IDirectPlayLobbyImpl *This, DWORD dwFlags, REFIID riid, void **lplpDP,
358         IUnknown* pUnk)
359 {
360   HRESULT         hr;
361   DWORD           dwOpenFlags = 0;
362   DWORD           dwConnSize = 0;
363   LPDPLCONNECTION lpConn;
364 
365   FIXME("(%p)->(0x%08x,%p,%p): semi stub\n", This, dwFlags, lplpDP, pUnk );
366 
367   if( pUnk )
368   {
369      return DPERR_INVALIDPARAMS;
370   }
371 
372   /* Backwards compatibility */
373   if( dwFlags == 0 )
374   {
375     dwFlags = DPCONNECT_RETURNSTATUS;
376   }
377 
378   if ( ( hr = dplay_create( riid, lplpDP ) ) != DP_OK )
379   {
380      ERR( "error creating interface for %s:%s.\n",
381           debugstr_guid( riid ), DPLAYX_HresultToString( hr ) );
382      return hr;
383   }
384 
385   /* FIXME: Is it safe/correct to use appID of 0? */
386   hr = IDirectPlayLobby_GetConnectionSettings( &This->IDirectPlayLobby3_iface,
387                                                0, NULL, &dwConnSize );
388   if( hr != DPERR_BUFFERTOOSMALL )
389   {
390     return hr;
391   }
392 
393   lpConn = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwConnSize );
394 
395   if( lpConn == NULL )
396   {
397     return DPERR_NOMEMORY;
398   }
399 
400   /* FIXME: Is it safe/correct to use appID of 0? */
401   hr = IDirectPlayLobby_GetConnectionSettings( &This->IDirectPlayLobby3_iface,
402                                                0, lpConn, &dwConnSize );
403   if( FAILED( hr ) )
404   {
405     HeapFree( GetProcessHeap(), 0, lpConn );
406     return hr;
407   }
408 
409 #if 0
410   /* - Need to call IDirectPlay::EnumConnections with the service provider to get that good information
411    * - Need to call CreateAddress to create the lpConnection param for IDirectPlay::InitializeConnection
412    * - Call IDirectPlay::InitializeConnection
413    */
414 
415   /* Now initialize the Service Provider */
416   hr = IDirectPlayX_InitializeConnection( (*(LPDIRECTPLAY2*)lplpDP),
417 #endif
418 
419 
420   /* Setup flags to pass into DirectPlay::Open */
421   if( dwFlags & DPCONNECT_RETURNSTATUS )
422   {
423     dwOpenFlags |= DPOPEN_RETURNSTATUS;
424   }
425   dwOpenFlags |= lpConn->dwFlags;
426 
427   hr = IDirectPlayX_Open( (*(LPDIRECTPLAY2*)lplpDP), lpConn->lpSessionDesc,
428                           dwOpenFlags );
429 
430   HeapFree( GetProcessHeap(), 0, lpConn );
431 
432   return hr;
433 }
434 
435 static HRESULT WINAPI IDirectPlayLobbyAImpl_Connect( IDirectPlayLobbyA *iface, DWORD flags,
436     IDirectPlay2A **dp, IUnknown *unk )
437 {
438     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobbyA( iface );
439     return IDirectPlayLobby_Connect( &This->IDirectPlayLobby3A_iface, flags, dp, unk );
440 }
441 
442 static HRESULT WINAPI IDirectPlayLobbyImpl_Connect( IDirectPlayLobby *iface, DWORD flags,
443     IDirectPlay2A **dp, IUnknown *unk )
444 {
445     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby( iface );
446     return IDirectPlayLobby_Connect( &This->IDirectPlayLobby3_iface, flags, dp, unk );
447 }
448 
449 static HRESULT WINAPI IDirectPlayLobby2AImpl_Connect( IDirectPlayLobby2A *iface, DWORD flags,
450     IDirectPlay2A **dp, IUnknown *unk )
451 {
452     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby2A( iface );
453     return IDirectPlayLobby_Connect( &This->IDirectPlayLobby3A_iface, flags, dp, unk );
454 }
455 
456 static HRESULT WINAPI IDirectPlayLobby2Impl_Connect( IDirectPlayLobby2 *iface, DWORD flags,
457     IDirectPlay2A **dp, IUnknown *unk )
458 {
459     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby2( iface );
460     return IDirectPlayLobby_Connect( &This->IDirectPlayLobby3_iface, flags, dp, unk );
461 }
462 
463 static HRESULT WINAPI IDirectPlayLobby3AImpl_Connect( IDirectPlayLobby3A *iface, DWORD flags,
464     IDirectPlay2A **dp, IUnknown *unk)
465 {
466     return IDirectPlayLobby_ConnectEx( iface, flags, &IID_IDirectPlay2A, (void**)dp, unk );
467 }
468 
469 static HRESULT WINAPI IDirectPlayLobby3Impl_Connect( IDirectPlayLobby3 *iface, DWORD flags,
470         IDirectPlay2 **dp, IUnknown *unk)
471 {
472     return IDirectPlayLobby_ConnectEx( iface, flags, &IID_IDirectPlay2A, (void**)dp, unk );
473 }
474 
475 /********************************************************************
476  *
477  * Creates a DirectPlay Address, given a service provider-specific network
478  * address.
479  * Returns an address contains the globally unique identifier
480  * (GUID) of the service provider and data that the service provider can
481  * interpret as a network address.
482  *
483  * NOTE: It appears that this method is supposed to be really really stupid
484  *       with no error checking on the contents.
485  */
486 static HRESULT WINAPI IDirectPlayLobbyAImpl_CreateAddress( IDirectPlayLobbyA *iface, REFGUID sp,
487         REFGUID datatype, const void *data, DWORD datasize, void *address, DWORD *addrsize )
488 {
489     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobbyA( iface );
490     return IDirectPlayLobby_CreateAddress( &This->IDirectPlayLobby3A_iface, sp, datatype, data,
491             datasize, address, addrsize );
492 }
493 
494 static HRESULT WINAPI IDirectPlayLobbyImpl_CreateAddress( IDirectPlayLobby *iface, REFGUID sp,
495         REFGUID datatype, const void *data, DWORD datasize, void *address, DWORD *addrsize )
496 {
497     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby( iface );
498     return IDirectPlayLobby_CreateAddress( &This->IDirectPlayLobby3_iface, sp, datatype, data,
499             datasize, address, addrsize );
500 }
501 
502 static HRESULT WINAPI IDirectPlayLobby2AImpl_CreateAddress( IDirectPlayLobby2A *iface, REFGUID sp,
503         REFGUID datatype, const void *data, DWORD datasize, void *address, DWORD *addrsize )
504 {
505     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby2A( iface );
506     return IDirectPlayLobby_CreateAddress( &This->IDirectPlayLobby3A_iface, sp, datatype, data,
507             datasize, address, addrsize );
508 }
509 
510 static HRESULT WINAPI IDirectPlayLobby2Impl_CreateAddress( IDirectPlayLobby2 *iface, REFGUID sp,
511         REFGUID datatype, const void *data, DWORD datasize, void *address, DWORD *addrsize )
512 {
513     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby2( iface );
514     return IDirectPlayLobby_CreateAddress( &This->IDirectPlayLobby3_iface, sp, datatype, data,
515             datasize, address, addrsize );
516 }
517 
518 static HRESULT WINAPI IDirectPlayLobby3AImpl_CreateAddress( IDirectPlayLobby3A *iface,
519         REFGUID guidSP, REFGUID guidDataType, const void *lpData, DWORD dwDataSize, void *lpAddress,
520         DWORD *lpdwAddressSize )
521 {
522   return DPL_CreateAddress( guidSP, guidDataType, lpData, dwDataSize,
523                             lpAddress, lpdwAddressSize, TRUE );
524 }
525 
526 static HRESULT WINAPI IDirectPlayLobby3Impl_CreateAddress( IDirectPlayLobby3 *iface, REFGUID guidSP,
527         REFGUID guidDataType, const void *lpData, DWORD dwDataSize, void *lpAddress,
528         DWORD *lpdwAddressSize )
529 {
530   return DPL_CreateAddress( guidSP, guidDataType, lpData, dwDataSize,
531                             lpAddress, lpdwAddressSize, FALSE );
532 }
533 
534 static HRESULT DPL_CreateAddress(
535   REFGUID guidSP,
536   REFGUID guidDataType,
537   LPCVOID lpData,
538   DWORD dwDataSize,
539   LPVOID lpAddress,
540   LPDWORD lpdwAddressSize,
541   BOOL bAnsiInterface )
542 {
543   const DWORD dwNumAddElements = 2; /* Service Provide & address data type */
544   DPCOMPOUNDADDRESSELEMENT addressElements[ 2 /* dwNumAddElements */ ];
545 
546   TRACE( "(%p)->(%p,%p,0x%08x,%p,%p,%d)\n", guidSP, guidDataType, lpData, dwDataSize,
547                                              lpAddress, lpdwAddressSize, bAnsiInterface );
548 
549   addressElements[ 0 ].guidDataType = DPAID_ServiceProvider;
550   addressElements[ 0 ].dwDataSize = sizeof( GUID );
551   addressElements[ 0 ].lpData = (LPVOID)guidSP;
552 
553   addressElements[ 1 ].guidDataType = *guidDataType;
554   addressElements[ 1 ].dwDataSize = dwDataSize;
555   addressElements[ 1 ].lpData = (LPVOID)lpData;
556 
557   /* Call CreateCompoundAddress to cut down on code.
558      NOTE: We can do this because we don't support DPL 1 interfaces! */
559   return DPL_CreateCompoundAddress( addressElements, dwNumAddElements,
560                                     lpAddress, lpdwAddressSize, bAnsiInterface );
561 }
562 
563 
564 
565 /********************************************************************
566  *
567  * Parses out chunks from the DirectPlay Address buffer by calling the
568  * given callback function, with lpContext, for each of the chunks.
569  *
570  */
571 static HRESULT WINAPI IDirectPlayLobbyAImpl_EnumAddress( IDirectPlayLobbyA *iface,
572         LPDPENUMADDRESSCALLBACK enumaddrcb, const void *address, DWORD size, void *context )
573 {
574     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobbyA( iface );
575     return IDirectPlayLobby_EnumAddress( &This->IDirectPlayLobby3A_iface, enumaddrcb, address, size,
576             context );
577 }
578 
579 static HRESULT WINAPI IDirectPlayLobbyImpl_EnumAddress( IDirectPlayLobby *iface,
580         LPDPENUMADDRESSCALLBACK enumaddrcb, const void *address, DWORD size, void *context )
581 {
582     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby( iface );
583     return IDirectPlayLobby_EnumAddress( &This->IDirectPlayLobby3_iface, enumaddrcb, address, size,
584             context );
585 }
586 
587 static HRESULT WINAPI IDirectPlayLobby2AImpl_EnumAddress( IDirectPlayLobby2A *iface,
588         LPDPENUMADDRESSCALLBACK enumaddrcb, const void *address, DWORD size, void *context )
589 {
590     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby2A( iface );
591     return IDirectPlayLobby_EnumAddress( &This->IDirectPlayLobby3A_iface, enumaddrcb, address, size,
592             context );
593 }
594 
595 static HRESULT WINAPI IDirectPlayLobby2Impl_EnumAddress( IDirectPlayLobby2 *iface,
596         LPDPENUMADDRESSCALLBACK enumaddrcb, const void *address, DWORD size, void *context )
597 {
598     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby2( iface );
599     return IDirectPlayLobby_EnumAddress( &This->IDirectPlayLobby3_iface, enumaddrcb, address, size,
600             context );
601 }
602 
603 static HRESULT WINAPI IDirectPlayLobby3AImpl_EnumAddress( IDirectPlayLobby3A *iface,
604         LPDPENUMADDRESSCALLBACK lpEnumAddressCallback, const void *lpAddress, DWORD dwAddressSize,
605         void *lpContext )
606 {
607   IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby3A( iface );
608 
609   TRACE("(%p)->(%p,%p,0x%08x,%p)\n", This, lpEnumAddressCallback, lpAddress,
610                                       dwAddressSize, lpContext );
611 
612   return DPL_EnumAddress( lpEnumAddressCallback, lpAddress, dwAddressSize, lpContext );
613 }
614 
615 static HRESULT WINAPI IDirectPlayLobby3Impl_EnumAddress( IDirectPlayLobby3 *iface,
616         LPDPENUMADDRESSCALLBACK lpEnumAddressCallback, const void *lpAddress, DWORD dwAddressSize,
617         void *lpContext )
618 {
619   IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby3( iface );
620 
621   TRACE("(%p)->(%p,%p,0x%08x,%p)\n", This, lpEnumAddressCallback, lpAddress,
622                                       dwAddressSize, lpContext );
623 
624   return DPL_EnumAddress( lpEnumAddressCallback, lpAddress, dwAddressSize, lpContext );
625 }
626 
627 HRESULT DPL_EnumAddress( LPDPENUMADDRESSCALLBACK lpEnumAddressCallback, LPCVOID lpAddress,
628                          DWORD dwAddressSize, LPVOID lpContext )
629 {
630   DWORD dwTotalSizeEnumerated = 0;
631 
632   /* FIXME: First chunk is always the total size chunk - Should we report it? */
633 
634   while ( dwTotalSizeEnumerated < dwAddressSize )
635   {
636     const DPADDRESS* lpElements = lpAddress;
637     DWORD dwSizeThisEnumeration;
638 
639     /* Invoke the enum method. If false is returned, stop enumeration */
640     if ( !lpEnumAddressCallback( &lpElements->guidDataType,
641                                  lpElements->dwDataSize,
642                                  (const BYTE *)lpElements + sizeof( DPADDRESS ),
643                                  lpContext ) )
644     {
645       break;
646     }
647 
648     dwSizeThisEnumeration  = sizeof( DPADDRESS ) + lpElements->dwDataSize;
649     lpAddress = (const BYTE*) lpAddress + dwSizeThisEnumeration;
650     dwTotalSizeEnumerated += dwSizeThisEnumeration;
651   }
652 
653   return DP_OK;
654 }
655 
656 /********************************************************************
657  *
658  * Enumerates all the address types that a given service provider needs to
659  * build the DirectPlay Address.
660  *
661  */
662 static HRESULT WINAPI IDirectPlayLobbyAImpl_EnumAddressTypes( IDirectPlayLobbyA *iface,
663         LPDPLENUMADDRESSTYPESCALLBACK enumaddrtypecb, REFGUID sp, void *context, DWORD flags )
664 {
665     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobbyA( iface );
666     return IDirectPlayLobby_EnumAddressTypes( &This->IDirectPlayLobby3A_iface, enumaddrtypecb, sp,
667             context, flags );
668 }
669 
670 static HRESULT WINAPI IDirectPlayLobbyImpl_EnumAddressTypes( IDirectPlayLobby *iface,
671         LPDPLENUMADDRESSTYPESCALLBACK enumaddrtypecb, REFGUID sp, void *context, DWORD flags )
672 {
673     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby( iface );
674     return IDirectPlayLobby_EnumAddressTypes( &This->IDirectPlayLobby3_iface, enumaddrtypecb, sp,
675             context, flags );
676 }
677 
678 static HRESULT WINAPI IDirectPlayLobby2AImpl_EnumAddressTypes( IDirectPlayLobby2A *iface,
679         LPDPLENUMADDRESSTYPESCALLBACK enumaddrtypecb, REFGUID sp, void *context, DWORD flags )
680 {
681     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby2A( iface );
682     return IDirectPlayLobby_EnumAddressTypes( &This->IDirectPlayLobby3A_iface, enumaddrtypecb, sp,
683             context, flags );
684 }
685 
686 static HRESULT WINAPI IDirectPlayLobby2Impl_EnumAddressTypes( IDirectPlayLobby2 *iface,
687         LPDPLENUMADDRESSTYPESCALLBACK enumaddrtypecb, REFGUID sp, void *context, DWORD flags )
688 {
689     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby2( iface );
690     return IDirectPlayLobby_EnumAddressTypes( &This->IDirectPlayLobby3_iface, enumaddrtypecb, sp,
691             context, flags );
692 }
693 
694 static HRESULT WINAPI IDirectPlayLobby3AImpl_EnumAddressTypes( IDirectPlayLobby3A *iface,
695         LPDPLENUMADDRESSTYPESCALLBACK lpEnumAddressTypeCallback, REFGUID guidSP, void *lpContext,
696         DWORD dwFlags )
697 {
698   IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby3A( iface );
699 
700   HKEY   hkResult;
701   LPCSTR searchSubKey    = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
702   DWORD  dwIndex, sizeOfSubKeyName=50;
703   char   subKeyName[51];
704   FILETIME filetime;
705 
706   TRACE(" (%p)->(%p,%p,%p,0x%08x)\n", This, lpEnumAddressTypeCallback, guidSP, lpContext, dwFlags );
707 
708   if( dwFlags != 0 )
709   {
710     return DPERR_INVALIDPARAMS;
711   }
712 
713   if( !lpEnumAddressTypeCallback )
714   {
715      return DPERR_INVALIDPARAMS;
716   }
717 
718   if( guidSP == NULL )
719   {
720     return DPERR_INVALIDOBJECT;
721   }
722 
723     /* Need to loop over the service providers in the registry */
724     if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
725                          0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
726     {
727       /* Hmmm. Does this mean that there are no service providers? */
728       ERR(": no service providers?\n");
729       return DP_OK;
730     }
731 
732     /* Traverse all the service providers we have available */
733     for( dwIndex=0;
734          RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
735                         NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
736          ++dwIndex, sizeOfSubKeyName=50 )
737     {
738 
739       HKEY     hkServiceProvider, hkServiceProviderAt;
740       GUID     serviceProviderGUID;
741       DWORD    returnTypeGUID, sizeOfReturnBuffer = 50;
742       char     atSubKey[51];
743       char     returnBuffer[51];
744       WCHAR    buff[51];
745       DWORD    dwAtIndex;
746       LPCSTR   atKey = "Address Types";
747       LPCSTR   guidDataSubKey   = "Guid";
748 
749       TRACE(" this time through: %s\n", subKeyName );
750 
751       /* Get a handle for this particular service provider */
752       if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
753                          &hkServiceProvider ) != ERROR_SUCCESS )
754       {
755          ERR(": what the heck is going on?\n" );
756          continue;
757       }
758 
759       if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
760                             NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
761                             &sizeOfReturnBuffer ) != ERROR_SUCCESS )
762       {
763         ERR(": missing GUID registry data members\n" );
764         continue;
765       }
766 
767       /* FIXME: Check return types to ensure we're interpreting data right */
768       MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
769       CLSIDFromString( buff, &serviceProviderGUID );
770       /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
771 
772       /* Determine if this is the Service Provider that the user asked for */
773       if( !IsEqualGUID( &serviceProviderGUID, guidSP ) )
774       {
775         continue;
776       }
777 
778       /* Get a handle for this particular service provider */
779       if( RegOpenKeyExA( hkServiceProvider, atKey, 0, KEY_READ,
780                          &hkServiceProviderAt ) != ERROR_SUCCESS )
781       {
782         TRACE(": No Address Types registry data sub key/members\n" );
783         break;
784       }
785 
786       /* Traverse all the address type we have available */
787       for( dwAtIndex=0;
788            RegEnumKeyExA( hkServiceProviderAt, dwAtIndex, atSubKey, &sizeOfSubKeyName,
789                           NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
790            ++dwAtIndex, sizeOfSubKeyName=50 )
791       {
792         TRACE( "Found Address Type GUID %s\n", atSubKey );
793 
794         /* FIXME: Check return types to ensure we're interpreting data right */
795         MultiByteToWideChar( CP_ACP, 0, atSubKey, -1, buff, sizeof(buff)/sizeof(WCHAR) );
796         CLSIDFromString( buff, &serviceProviderGUID );
797         /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
798 
799         /* The enumeration will return FALSE if we are not to continue */
800         if( !lpEnumAddressTypeCallback( &serviceProviderGUID, lpContext, 0 ) )
801         {
802            WARN("lpEnumCallback returning FALSE\n" );
803            break; /* FIXME: This most likely has to break from the procedure...*/
804         }
805 
806       }
807 
808       /* We only enumerate address types for 1 GUID. We've found it, so quit looking */
809       break;
810     }
811 
812   return DP_OK;
813 }
814 
815 static HRESULT WINAPI IDirectPlayLobby3Impl_EnumAddressTypes( IDirectPlayLobby3 *iface,
816         LPDPLENUMADDRESSTYPESCALLBACK enumaddrtypecb, REFGUID sp, void *context, DWORD flags )
817 {
818     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby3( iface );
819     return IDirectPlayLobby_EnumAddressTypes( &This->IDirectPlayLobby3A_iface, enumaddrtypecb, sp,
820           context, flags );
821 }
822 
823 /********************************************************************
824  *
825  * Enumerates what applications are registered with DirectPlay by
826  * invoking the callback function with lpContext.
827  *
828  */
829 static HRESULT WINAPI IDirectPlayLobby3Impl_EnumLocalApplications( IDirectPlayLobby3 *iface,
830         LPDPLENUMLOCALAPPLICATIONSCALLBACK lpEnumLocalAppCallback, void *lpContext, DWORD dwFlags )
831 {
832   IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby3( iface );
833 
834   FIXME("(%p)->(%p,%p,0x%08x):stub\n", This, lpEnumLocalAppCallback, lpContext, dwFlags );
835 
836   return DPERR_OUTOFMEMORY;
837 }
838 
839 static HRESULT WINAPI IDirectPlayLobbyAImpl_EnumLocalApplications( IDirectPlayLobbyA *iface,
840         LPDPLENUMLOCALAPPLICATIONSCALLBACK enumlocalappcb, void *context, DWORD flags )
841 {
842     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobbyA( iface );
843     return IDirectPlayLobby_EnumLocalApplications( &This->IDirectPlayLobby3A_iface, enumlocalappcb,
844             context, flags );
845 }
846 
847 static HRESULT WINAPI IDirectPlayLobbyImpl_EnumLocalApplications( IDirectPlayLobby *iface,
848         LPDPLENUMLOCALAPPLICATIONSCALLBACK enumlocalappcb, void *context, DWORD flags )
849 {
850     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby( iface );
851     return IDirectPlayLobby_EnumLocalApplications( &This->IDirectPlayLobby3_iface, enumlocalappcb,
852             context, flags );
853 }
854 
855 static HRESULT WINAPI IDirectPlayLobby2AImpl_EnumLocalApplications( IDirectPlayLobby2A *iface,
856         LPDPLENUMLOCALAPPLICATIONSCALLBACK enumlocalappcb, void *context, DWORD flags )
857 {
858     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby2A( iface );
859     return IDirectPlayLobby_EnumLocalApplications( &This->IDirectPlayLobby3A_iface, enumlocalappcb,
860             context, flags );
861 }
862 
863 static HRESULT WINAPI IDirectPlayLobby2Impl_EnumLocalApplications( IDirectPlayLobby2 *iface,
864         LPDPLENUMLOCALAPPLICATIONSCALLBACK enumlocalappcb, void *context, DWORD flags )
865 {
866     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby2( iface );
867     return IDirectPlayLobby_EnumLocalApplications( &This->IDirectPlayLobby3_iface, enumlocalappcb,
868             context, flags );
869 }
870 
871 static HRESULT WINAPI IDirectPlayLobby3AImpl_EnumLocalApplications( IDirectPlayLobby3A *iface,
872         LPDPLENUMLOCALAPPLICATIONSCALLBACK lpEnumLocalAppCallback, void *lpContext, DWORD dwFlags )
873 {
874   IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby3A( iface );
875 
876   HKEY hkResult;
877   LPCSTR searchSubKey    = "SOFTWARE\\Microsoft\\DirectPlay\\Applications";
878   LPCSTR guidDataSubKey  = "Guid";
879   DWORD dwIndex, sizeOfSubKeyName=50;
880   char subKeyName[51];
881   FILETIME filetime;
882 
883   TRACE("(%p)->(%p,%p,0x%08x)\n", This, lpEnumLocalAppCallback, lpContext, dwFlags );
884 
885   if( dwFlags != 0 )
886   {
887     return DPERR_INVALIDPARAMS;
888   }
889 
890   if( !lpEnumLocalAppCallback )
891   {
892      return DPERR_INVALIDPARAMS;
893   }
894 
895   /* Need to loop over the service providers in the registry */
896   if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
897                      0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
898   {
899     /* Hmmm. Does this mean that there are no service providers? */
900     ERR(": no service providers?\n");
901     return DP_OK;
902   }
903 
904   /* Traverse all registered applications */
905   for( dwIndex=0;
906        RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName, NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
907        ++dwIndex, sizeOfSubKeyName=50 )
908   {
909 
910     HKEY       hkServiceProvider;
911     GUID       serviceProviderGUID;
912     DWORD      returnTypeGUID, sizeOfReturnBuffer = 50;
913     char       returnBuffer[51];
914     WCHAR      buff[51];
915     DPLAPPINFO dplAppInfo;
916 
917     TRACE(" this time through: %s\n", subKeyName );
918 
919     /* Get a handle for this particular service provider */
920     if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
921                        &hkServiceProvider ) != ERROR_SUCCESS )
922     {
923        ERR(": what the heck is going on?\n" );
924        continue;
925     }
926 
927     if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
928                           NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
929                           &sizeOfReturnBuffer ) != ERROR_SUCCESS )
930     {
931       ERR(": missing GUID registry data members\n" );
932       continue;
933     }
934 
935     /* FIXME: Check return types to ensure we're interpreting data right */
936     MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
937     CLSIDFromString( buff, &serviceProviderGUID );
938     /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
939 
940     dplAppInfo.dwSize               = sizeof( dplAppInfo );
941     dplAppInfo.guidApplication      = serviceProviderGUID;
942     dplAppInfo.u.lpszAppNameA = subKeyName;
943 
944     EnterCriticalSection( &This->lock );
945 
946     memcpy( &This->cbkeyhack, &hkServiceProvider, sizeof( hkServiceProvider ) );
947 
948     if( !lpEnumLocalAppCallback( &dplAppInfo, lpContext, dwFlags ) )
949     {
950        LeaveCriticalSection( &This->lock );
951        break;
952     }
953 
954     LeaveCriticalSection( &This->lock );
955   }
956 
957   return DP_OK;
958 }
959 
960 /********************************************************************
961  *
962  * Retrieves the DPLCONNECTION structure that contains all the information
963  * needed to start and connect an application. This was generated using
964  * either the RunApplication or SetConnectionSettings methods.
965  *
966  * NOTES: If lpData is NULL then just return lpdwDataSize. This allows
967  *        the data structure to be allocated by our caller which can then
968  *        call this procedure/method again with a valid data pointer.
969  */
970 static HRESULT WINAPI IDirectPlayLobbyAImpl_GetConnectionSettings( IDirectPlayLobbyA *iface,
971         DWORD appid, void *data, DWORD *size )
972 {
973     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobbyA( iface );
974     return IDirectPlayLobby_GetConnectionSettings( &This->IDirectPlayLobby3A_iface, appid, data,
975             size );
976 }
977 
978 static HRESULT WINAPI IDirectPlayLobbyImpl_GetConnectionSettings( IDirectPlayLobby *iface,
979         DWORD appid, void *data, DWORD *size )
980 {
981     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby( iface );
982     return IDirectPlayLobby_GetConnectionSettings( &This->IDirectPlayLobby3_iface, appid, data,
983             size );
984 }
985 
986 static HRESULT WINAPI IDirectPlayLobby2AImpl_GetConnectionSettings( IDirectPlayLobby2A *iface,
987         DWORD appid, void *data, DWORD *size )
988 {
989     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby2A( iface );
990     return IDirectPlayLobby_GetConnectionSettings( &This->IDirectPlayLobby3A_iface, appid, data,
991             size );
992 }
993 
994 static HRESULT WINAPI IDirectPlayLobby2Impl_GetConnectionSettings( IDirectPlayLobby2 *iface,
995         DWORD appid, void *data, DWORD *size )
996 {
997     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby2( iface );
998     return IDirectPlayLobby_GetConnectionSettings( &This->IDirectPlayLobby3_iface, appid, data,
999             size );
1000 }
1001 
1002 static HRESULT WINAPI IDirectPlayLobby3AImpl_GetConnectionSettings( IDirectPlayLobby3A *iface,
1003         DWORD dwAppID, void *lpData, DWORD *lpdwDataSize )
1004 {
1005   IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby3A( iface );
1006   HRESULT hr;
1007 
1008   TRACE("(%p)->(0x%08x,%p,%p)\n", This, dwAppID, lpData, lpdwDataSize );
1009 
1010   EnterCriticalSection( &This->lock );
1011 
1012   hr = DPLAYX_GetConnectionSettingsA( dwAppID,
1013                                       lpData,
1014                                       lpdwDataSize
1015                                     );
1016 
1017   LeaveCriticalSection( &This->lock );
1018 
1019   return hr;
1020 }
1021 
1022 static HRESULT WINAPI IDirectPlayLobby3Impl_GetConnectionSettings( IDirectPlayLobby3 *iface,
1023         DWORD dwAppID, void *lpData, DWORD *lpdwDataSize )
1024 {
1025   IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby3( iface );
1026   HRESULT hr;
1027 
1028   TRACE("(%p)->(0x%08x,%p,%p)\n", This, dwAppID, lpData, lpdwDataSize );
1029 
1030   EnterCriticalSection( &This->lock );
1031 
1032   hr = DPLAYX_GetConnectionSettingsW( dwAppID,
1033                                       lpData,
1034                                       lpdwDataSize
1035                                     );
1036 
1037   LeaveCriticalSection( &This->lock );
1038 
1039   return hr;
1040 }
1041 
1042 /********************************************************************
1043  *
1044  * Retrieves the message sent between a lobby client and a DirectPlay
1045  * application. All messages are queued until received.
1046  *
1047  */
1048 static HRESULT WINAPI IDirectPlayLobbyAImpl_ReceiveLobbyMessage( IDirectPlayLobbyA *iface,
1049         DWORD flags, DWORD appid, DWORD *msgflags, void *data, DWORD *size )
1050 {
1051     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobbyA( iface );
1052     return IDirectPlayLobby_ReceiveLobbyMessage( &This->IDirectPlayLobby3A_iface, flags, appid,
1053             msgflags, data, size );
1054 }
1055 
1056 static HRESULT WINAPI IDirectPlayLobbyImpl_ReceiveLobbyMessage( IDirectPlayLobby *iface,
1057         DWORD flags, DWORD appid, DWORD *msgflags, void *data, DWORD *size )
1058 {
1059     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby( iface );
1060     return IDirectPlayLobby_ReceiveLobbyMessage( &This->IDirectPlayLobby3_iface, flags, appid,
1061             msgflags, data, size );
1062 }
1063 
1064 static HRESULT WINAPI IDirectPlayLobby2AImpl_ReceiveLobbyMessage( IDirectPlayLobby2A *iface,
1065         DWORD flags, DWORD appid, DWORD *msgflags, void *data, DWORD *size )
1066 {
1067     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby2A( iface );
1068     return IDirectPlayLobby_ReceiveLobbyMessage( &This->IDirectPlayLobby3A_iface, flags, appid,
1069             msgflags, data, size );
1070 }
1071 
1072 static HRESULT WINAPI IDirectPlayLobby2Impl_ReceiveLobbyMessage( IDirectPlayLobby2 *iface,
1073         DWORD flags, DWORD appid, DWORD *msgflags, void *data, DWORD *size )
1074 {
1075     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby2( iface );
1076     return IDirectPlayLobby_ReceiveLobbyMessage( &This->IDirectPlayLobby3_iface, flags, appid,
1077             msgflags, data, size );
1078 }
1079 
1080 static HRESULT WINAPI IDirectPlayLobby3AImpl_ReceiveLobbyMessage( IDirectPlayLobby3A *iface,
1081         DWORD dwFlags, DWORD dwAppID, DWORD *lpdwMessageFlags, void *lpData,
1082         DWORD *lpdwDataSize )
1083 {
1084   IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby3A( iface );
1085   FIXME(":stub %p %08x %08x %p %p %p\n", This, dwFlags, dwAppID, lpdwMessageFlags, lpData,
1086          lpdwDataSize );
1087   return DPERR_OUTOFMEMORY;
1088 }
1089 
1090 static HRESULT WINAPI IDirectPlayLobby3Impl_ReceiveLobbyMessage( IDirectPlayLobby3 *iface,
1091         DWORD dwFlags, DWORD dwAppID, DWORD *lpdwMessageFlags, void *lpData,
1092         DWORD *lpdwDataSize )
1093 {
1094   IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby3( iface );
1095   FIXME(":stub %p %08x %08x %p %p %p\n", This, dwFlags, dwAppID, lpdwMessageFlags, lpData,
1096          lpdwDataSize );
1097   return DPERR_OUTOFMEMORY;
1098 }
1099 
1100 typedef struct tagRunApplicationEnumStruct
1101 {
1102   IDirectPlayLobbyImpl *This;
1103 
1104   GUID  appGUID;
1105   LPSTR lpszPath;
1106   LPSTR lpszFileName;
1107   LPSTR lpszCommandLine;
1108   LPSTR lpszCurrentDirectory;
1109 } RunApplicationEnumStruct, *lpRunApplicationEnumStruct;
1110 
1111 /* To be called by RunApplication to find how to invoke the function */
1112 static BOOL CALLBACK RunApplicationA_EnumLocalApplications
1113 ( LPCDPLAPPINFO   lpAppInfo,
1114   LPVOID          lpContext,
1115   DWORD           dwFlags )
1116 {
1117   lpRunApplicationEnumStruct lpData = (lpRunApplicationEnumStruct)lpContext;
1118 
1119   if( IsEqualGUID( &lpAppInfo->guidApplication, &lpData->appGUID ) )
1120   {
1121     char  returnBuffer[200];
1122     DWORD returnType, sizeOfReturnBuffer;
1123     LPCSTR clSubKey   = "CommandLine";
1124     LPCSTR cdSubKey   = "CurrentDirectory";
1125     LPCSTR fileSubKey = "File";
1126     LPCSTR pathSubKey = "Path";
1127 
1128     /* FIXME: Lazy man hack - dplay struct has the present reg key saved */
1129 
1130     sizeOfReturnBuffer = 200;
1131 
1132     /* Get all the appropriate data from the registry */
1133     if( RegQueryValueExA( lpData->This->cbkeyhack, clSubKey,
1134                           NULL, &returnType, (LPBYTE)returnBuffer,
1135                           &sizeOfReturnBuffer ) != ERROR_SUCCESS )
1136     {
1137        ERR( ": missing CommandLine registry data member\n" );
1138     }
1139     else
1140     {
1141         if ((lpData->lpszCommandLine = HeapAlloc( GetProcessHeap(), 0, strlen(returnBuffer)+1 )))
1142             strcpy( lpData->lpszCommandLine, returnBuffer );
1143     }
1144 
1145     sizeOfReturnBuffer = 200;
1146 
1147     if( RegQueryValueExA( lpData->This->cbkeyhack, cdSubKey,
1148                           NULL, &returnType, (LPBYTE)returnBuffer,
1149                           &sizeOfReturnBuffer ) != ERROR_SUCCESS )
1150     {
1151        ERR( ": missing CurrentDirectory registry data member\n" );
1152     }
1153     else
1154     {
1155         if ((lpData->lpszCurrentDirectory = HeapAlloc( GetProcessHeap(), 0, strlen(returnBuffer)+1 )))
1156             strcpy( lpData->lpszCurrentDirectory, returnBuffer );
1157     }
1158 
1159     sizeOfReturnBuffer = 200;
1160 
1161     if( RegQueryValueExA( lpData->This->cbkeyhack, fileSubKey,
1162                           NULL, &returnType, (LPBYTE)returnBuffer,
1163                           &sizeOfReturnBuffer ) != ERROR_SUCCESS )
1164     {
1165        ERR( ": missing File registry data member\n" );
1166     }
1167     else
1168     {
1169         if ((lpData->lpszFileName = HeapAlloc( GetProcessHeap(), 0, strlen(returnBuffer)+1 )))
1170             strcpy( lpData->lpszFileName, returnBuffer );
1171     }
1172 
1173     sizeOfReturnBuffer = 200;
1174 
1175     if( RegQueryValueExA( lpData->This->cbkeyhack, pathSubKey,
1176                           NULL, &returnType, (LPBYTE)returnBuffer,
1177                           &sizeOfReturnBuffer ) != ERROR_SUCCESS )
1178     {
1179        ERR( ": missing Path registry data member\n" );
1180     }
1181     else
1182     {
1183         if ((lpData->lpszPath = HeapAlloc( GetProcessHeap(), 0, strlen(returnBuffer)+1 )))
1184             strcpy( lpData->lpszPath, returnBuffer );
1185     }
1186 
1187     return FALSE; /* No need to keep going as we found what we wanted */
1188   }
1189 
1190   return TRUE; /* Keep enumerating, haven't found the application yet */
1191 }
1192 
1193 static BOOL DPL_CreateAndSetLobbyHandles( DWORD dwDestProcessId, HANDLE hDestProcess,
1194                                    LPHANDLE lphStart, LPHANDLE lphDeath,
1195                                    LPHANDLE lphRead )
1196 {
1197   /* These are the handles for the created process */
1198   HANDLE hAppStart = 0, hAppDeath = 0, hAppRead  = 0;
1199   SECURITY_ATTRIBUTES s_attrib;
1200 
1201   s_attrib.nLength              = sizeof( s_attrib );
1202   s_attrib.lpSecurityDescriptor = NULL;
1203   s_attrib.bInheritHandle       = TRUE;
1204 
1205   *lphStart = CreateEventW( &s_attrib, TRUE, FALSE, NULL );
1206   *lphDeath = CreateEventW( &s_attrib, TRUE, FALSE, NULL );
1207   *lphRead  = CreateEventW( &s_attrib, TRUE, FALSE, NULL );
1208 
1209   if( ( !DuplicateHandle( GetCurrentProcess(), *lphStart,
1210                           hDestProcess, &hAppStart,
1211                           0, FALSE, DUPLICATE_SAME_ACCESS ) ) ||
1212       ( !DuplicateHandle( GetCurrentProcess(), *lphDeath,
1213                           hDestProcess, &hAppDeath,
1214                           0, FALSE, DUPLICATE_SAME_ACCESS ) ) ||
1215       ( !DuplicateHandle( GetCurrentProcess(), *lphRead,
1216                           hDestProcess, &hAppRead,
1217                           0, FALSE, DUPLICATE_SAME_ACCESS ) )
1218     )
1219   {
1220     if (*lphStart) { CloseHandle(*lphStart); *lphStart = 0; }
1221     if (*lphDeath) { CloseHandle(*lphDeath); *lphDeath = 0; }
1222     if (*lphRead)  { CloseHandle(*lphRead);  *lphRead  = 0; }
1223     /* FIXME: Handle leak... */
1224     ERR( "Unable to dup handles\n" );
1225     return FALSE;
1226   }
1227 
1228   if( !DPLAYX_SetLobbyHandles( dwDestProcessId,
1229                                hAppStart, hAppDeath, hAppRead ) )
1230   {
1231     /* FIXME: Handle leak... */
1232     return FALSE;
1233   }
1234 
1235   return TRUE;
1236 }
1237 
1238 
1239 /********************************************************************
1240  *
1241  * Starts an application and passes to it all the information to
1242  * connect to a session.
1243  *
1244  */
1245 static HRESULT WINAPI IDirectPlayLobbyAImpl_RunApplication( IDirectPlayLobbyA *iface, DWORD flags,
1246         DWORD *appid, DPLCONNECTION *conn, HANDLE event )
1247 {
1248     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobbyA( iface );
1249     return IDirectPlayLobby_RunApplication( &This->IDirectPlayLobby3A_iface, flags, appid, conn,
1250             event );
1251 }
1252 
1253 static HRESULT WINAPI IDirectPlayLobbyImpl_RunApplication( IDirectPlayLobby *iface, DWORD flags,
1254         DWORD *appid, DPLCONNECTION *conn, HANDLE event )
1255 {
1256     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby( iface );
1257     return IDirectPlayLobby_RunApplication( &This->IDirectPlayLobby3_iface, flags, appid, conn,
1258             event );
1259 }
1260 
1261 static HRESULT WINAPI IDirectPlayLobby2AImpl_RunApplication( IDirectPlayLobby2A *iface, DWORD flags,
1262         DWORD *appid, DPLCONNECTION *conn, HANDLE event )
1263 {
1264     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby2A( iface );
1265     return IDirectPlayLobby_RunApplication( &This->IDirectPlayLobby3A_iface, flags, appid, conn,
1266             event );
1267 }
1268 
1269 static HRESULT WINAPI IDirectPlayLobby2Impl_RunApplication( IDirectPlayLobby2 *iface, DWORD flags,
1270         DWORD *appid, DPLCONNECTION *conn, HANDLE event )
1271 {
1272     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby2( iface );
1273     return IDirectPlayLobby_RunApplication( &This->IDirectPlayLobby3_iface, flags, appid, conn,
1274             event );
1275 }
1276 
1277 static HRESULT WINAPI IDirectPlayLobby3AImpl_RunApplication( IDirectPlayLobby3A *iface,
1278         DWORD dwFlags, DWORD *lpdwAppID, DPLCONNECTION *lpConn, HANDLE hReceiveEvent )
1279 {
1280   IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby3A( iface );
1281   HRESULT hr;
1282   RunApplicationEnumStruct enumData;
1283   char temp[200];
1284   STARTUPINFOA startupInfo;
1285   PROCESS_INFORMATION newProcessInfo;
1286   LPSTR appName;
1287   DWORD dwSuspendCount;
1288   HANDLE hStart, hDeath, hSettingRead;
1289 
1290   TRACE( "(%p)->(0x%08x,%p,%p,%p)\n",
1291          This, dwFlags, lpdwAppID, lpConn, hReceiveEvent );
1292 
1293   if( dwFlags != 0 )
1294   {
1295     return DPERR_INVALIDPARAMS;
1296   }
1297 
1298   if( DPLAYX_AnyLobbiesWaitingForConnSettings() )
1299   {
1300     FIXME( "Waiting lobby not being handled correctly\n" );
1301   }
1302 
1303   EnterCriticalSection( &This->lock );
1304 
1305   ZeroMemory( &enumData, sizeof( enumData ) );
1306   enumData.This    = This;
1307   enumData.appGUID = lpConn->lpSessionDesc->guidApplication;
1308 
1309   /* Our callback function will fill up the enumData structure with all the information
1310      required to start a new process */
1311   IDirectPlayLobby_EnumLocalApplications( iface, RunApplicationA_EnumLocalApplications,
1312                                           (&enumData), 0 );
1313 
1314   /* First the application name */
1315   strcpy( temp, enumData.lpszPath );
1316   strcat( temp, "\\" );
1317   strcat( temp, enumData.lpszFileName );
1318   HeapFree( GetProcessHeap(), 0, enumData.lpszPath );
1319   HeapFree( GetProcessHeap(), 0, enumData.lpszFileName );
1320   if ((appName = HeapAlloc( GetProcessHeap(), 0, strlen(temp)+1 ))) strcpy( appName, temp );
1321 
1322   /* Now the command line */
1323   strcat( temp, " " );
1324   strcat( temp, enumData.lpszCommandLine );
1325   HeapFree( GetProcessHeap(), 0, enumData.lpszCommandLine );
1326   if ((enumData.lpszCommandLine = HeapAlloc( GetProcessHeap(), 0, strlen(temp)+1 )))
1327       strcpy( enumData.lpszCommandLine, temp );
1328 
1329   ZeroMemory( &startupInfo, sizeof( startupInfo ) );
1330   startupInfo.cb = sizeof( startupInfo );
1331   /* FIXME: Should any fields be filled in? */
1332 
1333   ZeroMemory( &newProcessInfo, sizeof( newProcessInfo ) );
1334 
1335   if( !CreateProcessA( appName,
1336                        enumData.lpszCommandLine,
1337                        NULL,
1338                        NULL,
1339                        FALSE,
1340                        CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_CONSOLE | CREATE_SUSPENDED, /* Creation Flags */
1341                        NULL,
1342                        enumData.lpszCurrentDirectory,
1343                        &startupInfo,
1344                        &newProcessInfo
1345                      )
1346     )
1347   {
1348     ERR( "Failed to create process for app %s\n", appName );
1349 
1350     HeapFree( GetProcessHeap(), 0, appName );
1351     HeapFree( GetProcessHeap(), 0, enumData.lpszCommandLine );
1352     HeapFree( GetProcessHeap(), 0, enumData.lpszCurrentDirectory );
1353 
1354     LeaveCriticalSection( &This->lock );
1355     return DPERR_CANTCREATEPROCESS;
1356   }
1357 
1358   HeapFree( GetProcessHeap(), 0, appName );
1359   HeapFree( GetProcessHeap(), 0, enumData.lpszCommandLine );
1360   HeapFree( GetProcessHeap(), 0, enumData.lpszCurrentDirectory );
1361 
1362   /* Reserve this global application id! */
1363   if( !DPLAYX_CreateLobbyApplication( newProcessInfo.dwProcessId ) )
1364   {
1365     ERR( "Unable to create global application data for 0x%08x\n",
1366            newProcessInfo.dwProcessId );
1367   }
1368 
1369   hr = IDirectPlayLobby_SetConnectionSettings( iface, 0, newProcessInfo.dwProcessId, lpConn );
1370 
1371   if( hr != DP_OK )
1372   {
1373     ERR( "SetConnectionSettings failure %s\n", DPLAYX_HresultToString( hr ) );
1374     LeaveCriticalSection( &This->lock );
1375     return hr;
1376   }
1377 
1378   /* Setup the handles for application notification */
1379   DPL_CreateAndSetLobbyHandles( newProcessInfo.dwProcessId,
1380                                 newProcessInfo.hProcess,
1381                                 &hStart, &hDeath, &hSettingRead );
1382 
1383   /* Setup the message thread ID */
1384   This->msgtid = CreateLobbyMessageReceptionThread( hReceiveEvent, hStart, hDeath, hSettingRead );
1385 
1386   DPLAYX_SetLobbyMsgThreadId( newProcessInfo.dwProcessId, This->msgtid );
1387 
1388   LeaveCriticalSection( &This->lock );
1389 
1390   /* Everything seems to have been set correctly, update the dwAppID */
1391   *lpdwAppID = newProcessInfo.dwProcessId;
1392 
1393   /* Unsuspend the process - should return the prev suspension count */
1394   if( ( dwSuspendCount = ResumeThread( newProcessInfo.hThread ) ) != 1 )
1395   {
1396     ERR( "ResumeThread failed with 0x%08x\n", dwSuspendCount );
1397   }
1398 
1399   return DP_OK;
1400 }
1401 
1402 static HRESULT WINAPI IDirectPlayLobby3Impl_RunApplication( IDirectPlayLobby3 *iface, DWORD dwFlags,
1403         DWORD *lpdwAppID, DPLCONNECTION *lpConn, HANDLE hReceiveEvent )
1404 {
1405   IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby3( iface );
1406   FIXME( "(%p)->(0x%08x,%p,%p,%p):stub\n", This, dwFlags, lpdwAppID, lpConn, hReceiveEvent );
1407   return DPERR_OUTOFMEMORY;
1408 }
1409 
1410 /********************************************************************
1411  *
1412  * Sends a message between the application and the lobby client.
1413  * All messages are queued until received.
1414  *
1415  */
1416 static HRESULT WINAPI IDirectPlayLobbyAImpl_SendLobbyMessage( IDirectPlayLobbyA *iface, DWORD flags,
1417         DWORD appid, void *data, DWORD size )
1418 {
1419     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobbyA( iface );
1420     return IDirectPlayLobby_SendLobbyMessage( &This->IDirectPlayLobby3A_iface, flags, appid, data,
1421             size );
1422 }
1423 
1424 static HRESULT WINAPI IDirectPlayLobbyImpl_SendLobbyMessage( IDirectPlayLobby *iface, DWORD flags,
1425         DWORD appid, void *data, DWORD size )
1426 {
1427     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby( iface );
1428     return IDirectPlayLobby_SendLobbyMessage( &This->IDirectPlayLobby3_iface, flags, appid, data,
1429             size );
1430 }
1431 
1432 static HRESULT WINAPI IDirectPlayLobby2AImpl_SendLobbyMessage( IDirectPlayLobby2A *iface,
1433         DWORD flags, DWORD appid, void *data, DWORD size )
1434 {
1435     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby2A( iface );
1436     return IDirectPlayLobby_SendLobbyMessage( &This->IDirectPlayLobby3A_iface, flags, appid, data,
1437             size );
1438 }
1439 
1440 static HRESULT WINAPI IDirectPlayLobby2Impl_SendLobbyMessage( IDirectPlayLobby2 *iface, DWORD flags,
1441         DWORD appid, void *data, DWORD size )
1442 {
1443     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby2( iface );
1444     return IDirectPlayLobby_SendLobbyMessage( &This->IDirectPlayLobby3_iface, flags, appid, data,
1445             size );
1446 }
1447 
1448 static HRESULT WINAPI IDirectPlayLobby3AImpl_SendLobbyMessage( IDirectPlayLobby3A *iface,
1449         DWORD flags, DWORD appid, void *data, DWORD size )
1450 {
1451   FIXME(":stub\n");
1452   return DPERR_OUTOFMEMORY;
1453 }
1454 
1455 static HRESULT WINAPI IDirectPlayLobby3Impl_SendLobbyMessage( IDirectPlayLobby3 *iface,
1456         DWORD flags, DWORD appid, void *data, DWORD size )
1457 {
1458   FIXME(":stub\n");
1459   return DPERR_OUTOFMEMORY;
1460 }
1461 
1462 /********************************************************************
1463  *
1464  * Modifies the DPLCONNECTION structure to contain all information
1465  * needed to start and connect an application.
1466  *
1467  */
1468 static HRESULT WINAPI IDirectPlayLobby3Impl_SetConnectionSettings( IDirectPlayLobby3 *iface,
1469         DWORD dwFlags, DWORD dwAppID, DPLCONNECTION *lpConn )
1470 {
1471   IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby3( iface );
1472   HRESULT hr;
1473 
1474   TRACE("(%p)->(0x%08x,0x%08x,%p)\n", This, dwFlags, dwAppID, lpConn );
1475 
1476   EnterCriticalSection( &This->lock );
1477 
1478   hr = DPLAYX_SetConnectionSettingsW( dwFlags, dwAppID, lpConn );
1479 
1480   /* FIXME: Don't think that this is supposed to fail, but the documentation
1481             is somewhat sketchy. I'll try creating a lobby application
1482             for this... */
1483   if( hr == DPERR_NOTLOBBIED )
1484   {
1485     FIXME( "Unlobbied app setting connections. Is this correct behavior?\n" );
1486     if( dwAppID == 0 )
1487     {
1488        dwAppID = GetCurrentProcessId();
1489     }
1490     DPLAYX_CreateLobbyApplication( dwAppID );
1491     hr = DPLAYX_SetConnectionSettingsW( dwFlags, dwAppID, lpConn );
1492   }
1493 
1494   LeaveCriticalSection( &This->lock );
1495 
1496   return hr;
1497 }
1498 
1499 static HRESULT WINAPI IDirectPlayLobbyAImpl_SetConnectionSettings( IDirectPlayLobbyA *iface,
1500         DWORD flags, DWORD appid, DPLCONNECTION *conn )
1501 {
1502     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobbyA( iface );
1503     return IDirectPlayLobby_SetConnectionSettings( &This->IDirectPlayLobby3A_iface, flags,
1504             appid, conn );
1505 }
1506 
1507 static HRESULT WINAPI IDirectPlayLobbyImpl_SetConnectionSettings( IDirectPlayLobby *iface,
1508         DWORD flags, DWORD appid, DPLCONNECTION *conn )
1509 {
1510     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby( iface );
1511     return IDirectPlayLobby_SetConnectionSettings( &This->IDirectPlayLobby3_iface, flags,
1512             appid, conn );
1513 }
1514 
1515 static HRESULT WINAPI IDirectPlayLobby2AImpl_SetConnectionSettings( IDirectPlayLobby2A *iface,
1516         DWORD flags, DWORD appid, DPLCONNECTION *conn )
1517 {
1518     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby2A( iface );
1519     return IDirectPlayLobby_SetConnectionSettings( &This->IDirectPlayLobby3A_iface, flags,
1520             appid, conn );
1521 }
1522 
1523 static HRESULT WINAPI IDirectPlayLobby2Impl_SetConnectionSettings( IDirectPlayLobby2 *iface,
1524         DWORD flags, DWORD appid, DPLCONNECTION *conn )
1525 {
1526     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby2( iface );
1527     return IDirectPlayLobby_SetConnectionSettings( &This->IDirectPlayLobby3_iface, flags,
1528             appid, conn );
1529 }
1530 
1531 static HRESULT WINAPI IDirectPlayLobby3AImpl_SetConnectionSettings( IDirectPlayLobby3A *iface,
1532         DWORD dwFlags, DWORD dwAppID, DPLCONNECTION *lpConn )
1533 {
1534   IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby3A( iface );
1535   HRESULT hr;
1536 
1537   TRACE("(%p)->(0x%08x,0x%08x,%p)\n", This, dwFlags, dwAppID, lpConn );
1538 
1539   EnterCriticalSection( &This->lock );
1540 
1541   hr = DPLAYX_SetConnectionSettingsA( dwFlags, dwAppID, lpConn );
1542 
1543   /* FIXME: Don't think that this is supposed to fail, but the documentation
1544             is somewhat sketchy. I'll try creating a lobby application
1545             for this... */
1546   if( hr == DPERR_NOTLOBBIED )
1547   {
1548     FIXME( "Unlobbied app setting connections. Is this correct behavior?\n" );
1549     dwAppID = GetCurrentProcessId();
1550     DPLAYX_CreateLobbyApplication( dwAppID );
1551     hr = DPLAYX_SetConnectionSettingsA( dwFlags, dwAppID, lpConn );
1552   }
1553 
1554   LeaveCriticalSection( &This->lock );
1555 
1556   return hr;
1557 }
1558 
1559 /********************************************************************
1560  *
1561  * Registers an event that will be set when a lobby message is received.
1562  *
1563  */
1564 static HRESULT WINAPI IDirectPlayLobbyAImpl_SetLobbyMessageEvent( IDirectPlayLobbyA *iface,
1565         DWORD flags, DWORD appid, HANDLE event )
1566 {
1567     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobbyA( iface );
1568     return IDirectPlayLobby_SetLobbyMessageEvent( &This->IDirectPlayLobby3A_iface, flags, appid,
1569             event );
1570 }
1571 
1572 static HRESULT WINAPI IDirectPlayLobbyImpl_SetLobbyMessageEvent( IDirectPlayLobby *iface,
1573         DWORD flags, DWORD appid, HANDLE event )
1574 {
1575     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby( iface );
1576     return IDirectPlayLobby_SetLobbyMessageEvent( &This->IDirectPlayLobby3_iface, flags, appid,
1577             event );
1578 }
1579 
1580 static HRESULT WINAPI IDirectPlayLobby2AImpl_SetLobbyMessageEvent( IDirectPlayLobby2A *iface,
1581         DWORD flags, DWORD appid, HANDLE event )
1582 {
1583     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby2A( iface );
1584     return IDirectPlayLobby_SetLobbyMessageEvent( &This->IDirectPlayLobby3A_iface, flags, appid,
1585             event );
1586 }
1587 
1588 static HRESULT WINAPI IDirectPlayLobby2Impl_SetLobbyMessageEvent( IDirectPlayLobby2 *iface,
1589         DWORD flags, DWORD appid, HANDLE event )
1590 {
1591     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby2( iface );
1592     return IDirectPlayLobby_SetLobbyMessageEvent( &This->IDirectPlayLobby3_iface, flags, appid,
1593             event );
1594 }
1595 
1596 static HRESULT WINAPI IDirectPlayLobby3AImpl_SetLobbyMessageEvent( IDirectPlayLobby3A *iface,
1597         DWORD flags, DWORD appid, HANDLE event )
1598 {
1599   FIXME(":stub\n");
1600   return DPERR_OUTOFMEMORY;
1601 }
1602 
1603 static HRESULT WINAPI IDirectPlayLobby3Impl_SetLobbyMessageEvent( IDirectPlayLobby3 *iface,
1604         DWORD flags, DWORD appid, HANDLE event )
1605 {
1606   FIXME(":stub\n");
1607   return DPERR_OUTOFMEMORY;
1608 }
1609 
1610 
1611 /* DPL 2 methods */
1612 static HRESULT WINAPI IDirectPlayLobby2AImpl_CreateCompoundAddress( IDirectPlayLobby2A *iface,
1613         const DPCOMPOUNDADDRESSELEMENT *elements, DWORD count, void *address, DWORD *size )
1614 {
1615     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby2A( iface );
1616     return IDirectPlayLobby_CreateCompoundAddress( &This->IDirectPlayLobby3A_iface, elements,
1617             count, address, size );
1618 }
1619 
1620 static HRESULT WINAPI IDirectPlayLobby2Impl_CreateCompoundAddress( IDirectPlayLobby2 *iface,
1621         const DPCOMPOUNDADDRESSELEMENT *elements, DWORD count, void *address, DWORD *size )
1622 {
1623     IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby2( iface );
1624     return IDirectPlayLobby_CreateCompoundAddress( &This->IDirectPlayLobby3_iface, elements,
1625             count, address, size );
1626 }
1627 
1628 static HRESULT WINAPI IDirectPlayLobby3Impl_CreateCompoundAddress( IDirectPlayLobby3 *iface,
1629         const DPCOMPOUNDADDRESSELEMENT *lpElements, DWORD dwElementCount, void *lpAddress,
1630         DWORD *lpdwAddressSize )
1631 {
1632   return DPL_CreateCompoundAddress( lpElements, dwElementCount, lpAddress, lpdwAddressSize, FALSE );
1633 }
1634 
1635 static HRESULT WINAPI IDirectPlayLobby3AImpl_CreateCompoundAddress( IDirectPlayLobby3A *iface,
1636         const DPCOMPOUNDADDRESSELEMENT *lpElements, DWORD dwElementCount, void *lpAddress,
1637         DWORD *lpdwAddressSize )
1638 {
1639   return DPL_CreateCompoundAddress( lpElements, dwElementCount, lpAddress, lpdwAddressSize, TRUE );
1640 }
1641 
1642 HRESULT DPL_CreateCompoundAddress
1643 ( LPCDPCOMPOUNDADDRESSELEMENT lpElements,
1644   DWORD dwElementCount,
1645   LPVOID lpAddress,
1646   LPDWORD lpdwAddressSize,
1647   BOOL bAnsiInterface )
1648 {
1649   DWORD dwSizeRequired = 0;
1650   DWORD dwElements;
1651   LPCDPCOMPOUNDADDRESSELEMENT lpOrigElements = lpElements;
1652 
1653   TRACE("(%p,0x%08x,%p,%p)\n", lpElements, dwElementCount, lpAddress, lpdwAddressSize );
1654 
1655   /* Parameter check */
1656   if( ( lpElements == NULL ) ||
1657       ( dwElementCount == 0 )   /* FIXME: Not sure if this is a failure case */
1658     )
1659   {
1660     return DPERR_INVALIDPARAMS;
1661   }
1662 
1663   /* Add the total size chunk */
1664   dwSizeRequired += sizeof( DPADDRESS ) + sizeof( DWORD );
1665 
1666   /* Calculate the size of the buffer required */
1667   for ( dwElements = dwElementCount; dwElements > 0; --dwElements, ++lpElements )
1668   {
1669     if ( ( IsEqualGUID( &lpElements->guidDataType, &DPAID_ServiceProvider ) ) ||
1670          ( IsEqualGUID( &lpElements->guidDataType, &DPAID_LobbyProvider ) )
1671        )
1672     {
1673       dwSizeRequired += sizeof( DPADDRESS ) + sizeof( GUID );
1674     }
1675     else if ( ( IsEqualGUID( &lpElements->guidDataType, &DPAID_Phone ) ) ||
1676               ( IsEqualGUID( &lpElements->guidDataType, &DPAID_Modem ) ) ||
1677               ( IsEqualGUID( &lpElements->guidDataType, &DPAID_INet ) )
1678             )
1679     {
1680       if( !bAnsiInterface )
1681       {
1682         ERR( "Ansi GUIDs used for unicode interface\n" );
1683         return DPERR_INVALIDFLAGS;
1684       }
1685 
1686       dwSizeRequired += sizeof( DPADDRESS ) + lpElements->dwDataSize;
1687     }
1688     else if ( ( IsEqualGUID( &lpElements->guidDataType, &DPAID_PhoneW ) ) ||
1689               ( IsEqualGUID( &lpElements->guidDataType, &DPAID_ModemW ) ) ||
1690               ( IsEqualGUID( &lpElements->guidDataType, &DPAID_INetW ) )
1691             )
1692     {
1693       if( bAnsiInterface )
1694       {
1695         ERR( "Unicode GUIDs used for ansi interface\n" );
1696         return DPERR_INVALIDFLAGS;
1697       }
1698 
1699       FIXME( "Right size for unicode interface?\n" );
1700       dwSizeRequired += sizeof( DPADDRESS ) + lpElements->dwDataSize * sizeof( WCHAR );
1701     }
1702     else if ( IsEqualGUID( &lpElements->guidDataType, &DPAID_INetPort ) )
1703     {
1704       dwSizeRequired += sizeof( DPADDRESS ) + sizeof( WORD );
1705     }
1706     else if ( IsEqualGUID( &lpElements->guidDataType, &DPAID_ComPort ) )
1707     {
1708       FIXME( "Right size for unicode interface?\n" );
1709       dwSizeRequired += sizeof( DPADDRESS ) + sizeof( DPCOMPORTADDRESS ); /* FIXME: Right size? */
1710     }
1711     else
1712     {
1713       WARN( "Skipping Unknown GUID %s\n", debugstr_guid(&lpElements->guidDataType) );
1714     }
1715   }
1716 
1717   /* The user wants to know how big a buffer to allocate for us */
1718   if( ( lpAddress == NULL ) ||
1719       ( *lpdwAddressSize < dwSizeRequired )
1720     )
1721   {
1722     *lpdwAddressSize = dwSizeRequired;
1723     return DPERR_BUFFERTOOSMALL;
1724   }
1725 
1726   /* Add the total size chunk */
1727   {
1728     LPDPADDRESS lpdpAddress = lpAddress;
1729 
1730     lpdpAddress->guidDataType = DPAID_TotalSize;
1731     lpdpAddress->dwDataSize = sizeof( DWORD );
1732     lpAddress = (char *) lpAddress + sizeof( DPADDRESS );
1733 
1734     *(LPDWORD)lpAddress = dwSizeRequired;
1735     lpAddress = (char *) lpAddress + sizeof( DWORD );
1736   }
1737 
1738   /* Calculate the size of the buffer required */
1739   for( dwElements = dwElementCount, lpElements = lpOrigElements;
1740        dwElements > 0;
1741        --dwElements, ++lpElements )
1742   {
1743     if ( ( IsEqualGUID( &lpElements->guidDataType, &DPAID_ServiceProvider ) ) ||
1744          ( IsEqualGUID( &lpElements->guidDataType, &DPAID_LobbyProvider ) )
1745        )
1746     {
1747       LPDPADDRESS lpdpAddress = lpAddress;
1748 
1749       lpdpAddress->guidDataType = lpElements->guidDataType;
1750       lpdpAddress->dwDataSize = sizeof( GUID );
1751       lpAddress = (char *) lpAddress + sizeof( DPADDRESS );
1752 
1753       CopyMemory( lpAddress, lpElements->lpData, sizeof( GUID ) );
1754       lpAddress = (char *) lpAddress + sizeof( GUID );
1755     }
1756     else if ( ( IsEqualGUID( &lpElements->guidDataType, &DPAID_Phone ) ) ||
1757               ( IsEqualGUID( &lpElements->guidDataType, &DPAID_Modem ) ) ||
1758               ( IsEqualGUID( &lpElements->guidDataType, &DPAID_INet ) )
1759             )
1760     {
1761       LPDPADDRESS lpdpAddress = lpAddress;
1762 
1763       lpdpAddress->guidDataType = lpElements->guidDataType;
1764       lpdpAddress->dwDataSize = lpElements->dwDataSize;
1765       lpAddress = (char *) lpAddress + sizeof( DPADDRESS );
1766 
1767       lstrcpynA( lpAddress, lpElements->lpData, lpElements->dwDataSize );
1768       lpAddress = (char *) lpAddress + lpElements->dwDataSize;
1769     }
1770     else if ( ( IsEqualGUID( &lpElements->guidDataType, &DPAID_PhoneW ) ) ||
1771               ( IsEqualGUID( &lpElements->guidDataType, &DPAID_ModemW ) ) ||
1772               ( IsEqualGUID( &lpElements->guidDataType, &DPAID_INetW ) )
1773             )
1774     {
1775       LPDPADDRESS lpdpAddress = lpAddress;
1776 
1777       lpdpAddress->guidDataType = lpElements->guidDataType;
1778       lpdpAddress->dwDataSize = lpElements->dwDataSize;
1779       lpAddress = (char *) lpAddress + sizeof( DPADDRESS );
1780 
1781       lstrcpynW( lpAddress, lpElements->lpData, lpElements->dwDataSize );
1782       lpAddress = (char *) lpAddress + lpElements->dwDataSize * sizeof( WCHAR );
1783     }
1784     else if ( IsEqualGUID( &lpElements->guidDataType, &DPAID_INetPort ) )
1785     {
1786       LPDPADDRESS lpdpAddress = lpAddress;
1787 
1788       lpdpAddress->guidDataType = lpElements->guidDataType;
1789       lpdpAddress->dwDataSize = lpElements->dwDataSize;
1790       lpAddress = (char *) lpAddress + sizeof( DPADDRESS );
1791 
1792       *((LPWORD)lpAddress) = *((LPWORD)lpElements->lpData);
1793       lpAddress = (char *) lpAddress + sizeof( WORD );
1794     }
1795     else if ( IsEqualGUID( &lpElements->guidDataType, &DPAID_ComPort ) )
1796     {
1797       LPDPADDRESS lpdpAddress = lpAddress;
1798 
1799       lpdpAddress->guidDataType = lpElements->guidDataType;
1800       lpdpAddress->dwDataSize = lpElements->dwDataSize;
1801       lpAddress = (char *) lpAddress + sizeof( DPADDRESS );
1802 
1803       CopyMemory( lpAddress, lpElements->lpData, sizeof( DPADDRESS ) );
1804       lpAddress = (char *) lpAddress + sizeof( DPADDRESS );
1805     }
1806   }
1807 
1808   return DP_OK;
1809 }
1810 
1811 /* DPL 3 methods */
1812 
1813 static HRESULT WINAPI IDirectPlayLobby3Impl_ConnectEx( IDirectPlayLobby3 *iface, DWORD dwFlags,
1814         REFIID riid, LPVOID* lplpDP, IUnknown* pUnk )
1815 {
1816   IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby3( iface );
1817   return DPL_ConnectEx( This, dwFlags, riid, lplpDP, pUnk );
1818 }
1819 
1820 static HRESULT WINAPI IDirectPlayLobby3AImpl_ConnectEx( IDirectPlayLobby3A *iface, DWORD dwFlags,
1821         REFIID riid, void **lplpDP, IUnknown *pUnk )
1822 {
1823   IDirectPlayLobbyImpl *This = impl_from_IDirectPlayLobby3A( iface );
1824   return DPL_ConnectEx( This, dwFlags, riid, lplpDP, pUnk );
1825 }
1826 
1827 static HRESULT WINAPI IDirectPlayLobby3Impl_RegisterApplication( IDirectPlayLobby3 *iface,
1828         DWORD flags, DPAPPLICATIONDESC *appdesc )
1829 {
1830   FIXME(":stub\n");
1831   return DP_OK;
1832 }
1833 
1834 static HRESULT WINAPI IDirectPlayLobby3AImpl_RegisterApplication( IDirectPlayLobby3A *iface,
1835         DWORD flags, DPAPPLICATIONDESC *appdesc )
1836 {
1837   FIXME(":stub\n");
1838   return DP_OK;
1839 }
1840 
1841 static HRESULT WINAPI IDirectPlayLobby3Impl_UnregisterApplication( IDirectPlayLobby3 *iface,
1842         DWORD flags, REFGUID appdesc )
1843 {
1844   FIXME(":stub\n");
1845   return DP_OK;
1846 }
1847 
1848 static HRESULT WINAPI IDirectPlayLobby3AImpl_UnregisterApplication( IDirectPlayLobby3A *iface,
1849         DWORD flags, REFGUID appdesc )
1850 {
1851   FIXME(":stub\n");
1852   return DP_OK;
1853 }
1854 
1855 static HRESULT WINAPI IDirectPlayLobby3Impl_WaitForConnectionSettings( IDirectPlayLobby3 *iface,
1856         DWORD dwFlags )
1857 {
1858   HRESULT hr         = DP_OK;
1859   BOOL    bStartWait = !(dwFlags & DPLWAIT_CANCEL);
1860 
1861   TRACE( "(%p)->(0x%08x)\n", iface, dwFlags );
1862 
1863   if( DPLAYX_WaitForConnectionSettings( bStartWait ) )
1864   {
1865     /* FIXME: What is the correct error return code? */
1866     hr = DPERR_NOTLOBBIED;
1867   }
1868 
1869   return hr;
1870 }
1871 
1872 static HRESULT WINAPI IDirectPlayLobby3AImpl_WaitForConnectionSettings( IDirectPlayLobby3A *iface,
1873         DWORD dwFlags )
1874 {
1875   HRESULT hr         = DP_OK;
1876   BOOL    bStartWait = !(dwFlags & DPLWAIT_CANCEL);
1877 
1878   TRACE( "(%p)->(0x%08x)\n", iface, dwFlags );
1879 
1880   if( DPLAYX_WaitForConnectionSettings( bStartWait ) )
1881   {
1882     /* FIXME: What is the correct error return code? */
1883     hr = DPERR_NOTLOBBIED;
1884   }
1885 
1886   return hr;
1887 }
1888 
1889 static const IDirectPlayLobbyVtbl dplA_vt =
1890 {
1891     IDirectPlayLobbyAImpl_QueryInterface,
1892     IDirectPlayLobbyAImpl_AddRef,
1893     IDirectPlayLobbyAImpl_Release,
1894     IDirectPlayLobbyAImpl_Connect,
1895     IDirectPlayLobbyAImpl_CreateAddress,
1896     IDirectPlayLobbyAImpl_EnumAddress,
1897     IDirectPlayLobbyAImpl_EnumAddressTypes,
1898     IDirectPlayLobbyAImpl_EnumLocalApplications,
1899     IDirectPlayLobbyAImpl_GetConnectionSettings,
1900     IDirectPlayLobbyAImpl_ReceiveLobbyMessage,
1901     IDirectPlayLobbyAImpl_RunApplication,
1902     IDirectPlayLobbyAImpl_SendLobbyMessage,
1903     IDirectPlayLobbyAImpl_SetConnectionSettings,
1904     IDirectPlayLobbyAImpl_SetLobbyMessageEvent
1905 };
1906 
1907 static const IDirectPlayLobbyVtbl dpl_vt =
1908 {
1909     IDirectPlayLobbyImpl_QueryInterface,
1910     IDirectPlayLobbyImpl_AddRef,
1911     IDirectPlayLobbyImpl_Release,
1912     IDirectPlayLobbyImpl_Connect,
1913     IDirectPlayLobbyImpl_CreateAddress,
1914     IDirectPlayLobbyImpl_EnumAddress,
1915     IDirectPlayLobbyImpl_EnumAddressTypes,
1916     IDirectPlayLobbyImpl_EnumLocalApplications,
1917     IDirectPlayLobbyImpl_GetConnectionSettings,
1918     IDirectPlayLobbyImpl_ReceiveLobbyMessage,
1919     IDirectPlayLobbyImpl_RunApplication,
1920     IDirectPlayLobbyImpl_SendLobbyMessage,
1921     IDirectPlayLobbyImpl_SetConnectionSettings,
1922     IDirectPlayLobbyImpl_SetLobbyMessageEvent
1923 };
1924 
1925 static const IDirectPlayLobby2Vtbl dpl2A_vt =
1926 {
1927     IDirectPlayLobby2AImpl_QueryInterface,
1928     IDirectPlayLobby2AImpl_AddRef,
1929     IDirectPlayLobby2AImpl_Release,
1930     IDirectPlayLobby2AImpl_Connect,
1931     IDirectPlayLobby2AImpl_CreateAddress,
1932     IDirectPlayLobby2AImpl_EnumAddress,
1933     IDirectPlayLobby2AImpl_EnumAddressTypes,
1934     IDirectPlayLobby2AImpl_EnumLocalApplications,
1935     IDirectPlayLobby2AImpl_GetConnectionSettings,
1936     IDirectPlayLobby2AImpl_ReceiveLobbyMessage,
1937     IDirectPlayLobby2AImpl_RunApplication,
1938     IDirectPlayLobby2AImpl_SendLobbyMessage,
1939     IDirectPlayLobby2AImpl_SetConnectionSettings,
1940     IDirectPlayLobby2AImpl_SetLobbyMessageEvent,
1941     IDirectPlayLobby2AImpl_CreateCompoundAddress
1942 };
1943 
1944 static const IDirectPlayLobby2Vtbl dpl2_vt =
1945 {
1946     IDirectPlayLobby2Impl_QueryInterface,
1947     IDirectPlayLobby2Impl_AddRef,
1948     IDirectPlayLobby2Impl_Release,
1949     IDirectPlayLobby2Impl_Connect,
1950     IDirectPlayLobby2Impl_CreateAddress,
1951     IDirectPlayLobby2Impl_EnumAddress,
1952     IDirectPlayLobby2Impl_EnumAddressTypes,
1953     IDirectPlayLobby2Impl_EnumLocalApplications,
1954     IDirectPlayLobby2Impl_GetConnectionSettings,
1955     IDirectPlayLobby2Impl_ReceiveLobbyMessage,
1956     IDirectPlayLobby2Impl_RunApplication,
1957     IDirectPlayLobby2Impl_SendLobbyMessage,
1958     IDirectPlayLobby2Impl_SetConnectionSettings,
1959     IDirectPlayLobby2Impl_SetLobbyMessageEvent,
1960     IDirectPlayLobby2Impl_CreateCompoundAddress
1961 };
1962 
1963 static const IDirectPlayLobby3Vtbl dpl3A_vt =
1964 {
1965     IDirectPlayLobby3AImpl_QueryInterface,
1966     IDirectPlayLobby3AImpl_AddRef,
1967     IDirectPlayLobby3AImpl_Release,
1968     IDirectPlayLobby3AImpl_Connect,
1969     IDirectPlayLobby3AImpl_CreateAddress,
1970     IDirectPlayLobby3AImpl_EnumAddress,
1971     IDirectPlayLobby3AImpl_EnumAddressTypes,
1972     IDirectPlayLobby3AImpl_EnumLocalApplications,
1973     IDirectPlayLobby3AImpl_GetConnectionSettings,
1974     IDirectPlayLobby3AImpl_ReceiveLobbyMessage,
1975     IDirectPlayLobby3AImpl_RunApplication,
1976     IDirectPlayLobby3AImpl_SendLobbyMessage,
1977     IDirectPlayLobby3AImpl_SetConnectionSettings,
1978     IDirectPlayLobby3AImpl_SetLobbyMessageEvent,
1979     IDirectPlayLobby3AImpl_CreateCompoundAddress,
1980     IDirectPlayLobby3AImpl_ConnectEx,
1981     IDirectPlayLobby3AImpl_RegisterApplication,
1982     IDirectPlayLobby3AImpl_UnregisterApplication,
1983     IDirectPlayLobby3AImpl_WaitForConnectionSettings
1984 };
1985 
1986 static const IDirectPlayLobby3Vtbl dpl3_vt =
1987 {
1988     IDirectPlayLobby3Impl_QueryInterface,
1989     IDirectPlayLobby3Impl_AddRef,
1990     IDirectPlayLobby3Impl_Release,
1991     IDirectPlayLobby3Impl_Connect,
1992     IDirectPlayLobby3Impl_CreateAddress,
1993     IDirectPlayLobby3Impl_EnumAddress,
1994     IDirectPlayLobby3Impl_EnumAddressTypes,
1995     IDirectPlayLobby3Impl_EnumLocalApplications,
1996     IDirectPlayLobby3Impl_GetConnectionSettings,
1997     IDirectPlayLobby3Impl_ReceiveLobbyMessage,
1998     IDirectPlayLobby3Impl_RunApplication,
1999     IDirectPlayLobby3Impl_SendLobbyMessage,
2000     IDirectPlayLobby3Impl_SetConnectionSettings,
2001     IDirectPlayLobby3Impl_SetLobbyMessageEvent,
2002     IDirectPlayLobby3Impl_CreateCompoundAddress,
2003     IDirectPlayLobby3Impl_ConnectEx,
2004     IDirectPlayLobby3Impl_RegisterApplication,
2005     IDirectPlayLobby3Impl_UnregisterApplication,
2006     IDirectPlayLobby3Impl_WaitForConnectionSettings
2007 };
2008 
2009 HRESULT dplobby_create( REFIID riid, void **ppv )
2010 {
2011     IDirectPlayLobbyImpl *obj;
2012     HRESULT hr;
2013 
2014     TRACE( "(%s, %p)\n", debugstr_guid( riid ), ppv );
2015 
2016     *ppv = NULL;
2017     obj = HeapAlloc( GetProcessHeap(), 0, sizeof( *obj ) );
2018     if ( !obj )
2019         return DPERR_OUTOFMEMORY;
2020 
2021     obj->IDirectPlayLobby_iface.lpVtbl = &dpl_vt;
2022     obj->IDirectPlayLobbyA_iface.lpVtbl = &dplA_vt;
2023     obj->IDirectPlayLobby2_iface.lpVtbl = &dpl2_vt;
2024     obj->IDirectPlayLobby2A_iface.lpVtbl = &dpl2A_vt;
2025     obj->IDirectPlayLobby3_iface.lpVtbl = &dpl3_vt;
2026     obj->IDirectPlayLobby3A_iface.lpVtbl = &dpl3A_vt;
2027     obj->numIfaces = 1;
2028     obj->msgtid = 0;
2029     obj->ref = 0;
2030     obj->refA = 0;
2031     obj->ref2 = 0;
2032     obj->ref2A = 0;
2033     obj->ref3 = 1;
2034     obj->ref3A = 0;
2035 
2036     InitializeCriticalSection( &obj->lock );
2037     obj->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectPlayLobbyImpl.lock");
2038     DPQ_INIT( obj->msgs );
2039 
2040     hr = IDirectPlayLobby_QueryInterface( &obj->IDirectPlayLobby3_iface, riid, ppv );
2041     IDirectPlayLobby_Release( &obj->IDirectPlayLobby3_iface );
2042 
2043     return hr;
2044 }
2045 
2046 
2047 
2048 /***************************************************************************
2049  *  DirectPlayLobbyCreateA   (DPLAYX.4)
2050  *
2051  */
2052 HRESULT WINAPI DirectPlayLobbyCreateA( GUID *lpGUIDDSP, IDirectPlayLobbyA **lplpDPL,
2053         IUnknown *lpUnk, void *lpData, DWORD dwDataSize )
2054 {
2055   TRACE("lpGUIDDSP=%p lplpDPL=%p lpUnk=%p lpData=%p dwDataSize=%08x\n",
2056         lpGUIDDSP,lplpDPL,lpUnk,lpData,dwDataSize);
2057 
2058   /* Parameter Check: lpGUIDSP, lpUnk & lpData must be NULL. dwDataSize must
2059    * equal 0. These fields are mostly for future expansion.
2060    */
2061   if ( lpGUIDDSP || lpData || dwDataSize )
2062   {
2063      *lplpDPL = NULL;
2064      return DPERR_INVALIDPARAMS;
2065   }
2066 
2067   if( lpUnk )
2068   {
2069      *lplpDPL = NULL;
2070      ERR("Bad parameters!\n" );
2071      return CLASS_E_NOAGGREGATION;
2072   }
2073 
2074   return dplobby_create( &IID_IDirectPlayLobbyA, (void**)lplpDPL );
2075 }
2076 
2077 /***************************************************************************
2078  *  DirectPlayLobbyCreateW   (DPLAYX.5)
2079  *
2080  */
2081 HRESULT WINAPI DirectPlayLobbyCreateW( GUID *lpGUIDDSP, IDirectPlayLobby **lplpDPL,
2082         IUnknown *lpUnk, void *lpData, DWORD dwDataSize )
2083 {
2084   TRACE("lpGUIDDSP=%p lplpDPL=%p lpUnk=%p lpData=%p dwDataSize=%08x\n",
2085         lpGUIDDSP,lplpDPL,lpUnk,lpData,dwDataSize);
2086 
2087   /* Parameter Check: lpGUIDSP, lpUnk & lpData must be NULL. dwDataSize must
2088    * equal 0. These fields are mostly for future expansion.
2089    */
2090   if ( lpGUIDDSP || lpData || dwDataSize )
2091   {
2092      *lplpDPL = NULL;
2093      ERR("Bad parameters!\n" );
2094      return DPERR_INVALIDPARAMS;
2095   }
2096 
2097   if( lpUnk )
2098   {
2099      *lplpDPL = NULL;
2100      ERR("Bad parameters!\n" );
2101      return CLASS_E_NOAGGREGATION;
2102   }
2103 
2104   return dplobby_create( &IID_IDirectPlayLobby, (void**)lplpDPL );
2105 }
2106