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