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