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