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