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