|  | /* Direct Play Lobby 2 & 3 Implementation | 
|  | * | 
|  | * Copyright 1998,1999,2000 - Peter Hunnisett | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
|  | */ | 
|  | #include <stdarg.h> | 
|  | #include <string.h> | 
|  |  | 
|  | #define NONAMELESSUNION | 
|  | #define NONAMELESSSTRUCT | 
|  | #include "windef.h" | 
|  | #include "winbase.h" | 
|  | #include "winerror.h" | 
|  | #include "winreg.h" | 
|  | #include "winnls.h" | 
|  | #include "wine/debug.h" | 
|  |  | 
|  | #include "dplayx_global.h" | 
|  | #include "dplayx_messages.h" | 
|  | #include "dplayx_queue.h" | 
|  | #include "dplobby.h" | 
|  | #include "dpinit.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(dplay); | 
|  |  | 
|  | /***************************************************************************** | 
|  | * Predeclare the interface implementation structures | 
|  | */ | 
|  | typedef struct IDirectPlayLobbyImpl  IDirectPlayLobbyAImpl; | 
|  | typedef struct IDirectPlayLobbyImpl  IDirectPlayLobbyWImpl; | 
|  | typedef struct IDirectPlayLobby2Impl IDirectPlayLobby2AImpl; | 
|  | typedef struct IDirectPlayLobby2Impl IDirectPlayLobby2WImpl; | 
|  | typedef struct IDirectPlayLobby3Impl IDirectPlayLobby3AImpl; | 
|  | typedef struct IDirectPlayLobby3Impl IDirectPlayLobby3WImpl; | 
|  |  | 
|  | /* Forward declarations for this module helper methods */ | 
|  | HRESULT DPL_CreateCompoundAddress ( LPCDPCOMPOUNDADDRESSELEMENT lpElements, DWORD dwElementCount, | 
|  | LPVOID lpAddress, LPDWORD lpdwAddressSize, BOOL bAnsiInterface )DECLSPEC_HIDDEN; | 
|  |  | 
|  | static HRESULT DPL_CreateAddress( REFGUID guidSP, REFGUID guidDataType, LPCVOID lpData, DWORD dwDataSize, | 
|  | LPVOID lpAddress, LPDWORD lpdwAddressSize, BOOL bAnsiInterface ); | 
|  |  | 
|  |  | 
|  |  | 
|  | extern HRESULT DPL_EnumAddress( LPDPENUMADDRESSCALLBACK lpEnumAddressCallback, LPCVOID lpAddress, | 
|  | DWORD dwAddressSize, LPVOID lpContext ); | 
|  |  | 
|  | static HRESULT DPL_ConnectEx( IDirectPlayLobbyAImpl* This, | 
|  | DWORD dwFlags, REFIID riid, | 
|  | LPVOID* lplpDP, IUnknown* pUnk ); | 
|  |  | 
|  | static BOOL DPL_CreateAndSetLobbyHandles( DWORD dwDestProcessId, HANDLE hDestProcess, | 
|  | LPHANDLE lphStart, LPHANDLE lphDeath, | 
|  | LPHANDLE lphRead ); | 
|  |  | 
|  |  | 
|  | /***************************************************************************** | 
|  | * IDirectPlayLobby {1,2,3} implementation structure | 
|  | * | 
|  | * The philosophy behind this extra pointer dereference is that I wanted to | 
|  | * have the same structure for all types of objects without having to do | 
|  | * a lot of casting. I also only wanted to implement an interface in the | 
|  | * object it was "released" with IUnknown interface being implemented in the 1 version. | 
|  | * Of course, with these new interfaces comes the data required to keep the state required | 
|  | * by these interfaces. So, basically, the pointers contain the data associated with | 
|  | * a release. If you use the data associated with release 3 in a release 2 object, you'll | 
|  | * get a run time trap, as that won't have any data. | 
|  | * | 
|  | */ | 
|  | struct DPLMSG | 
|  | { | 
|  | DPQ_ENTRY( DPLMSG ) msgs;  /* Link to next queued message */ | 
|  | }; | 
|  | typedef struct DPLMSG* LPDPLMSG; | 
|  |  | 
|  | typedef struct tagDirectPlayLobbyIUnknownData | 
|  | { | 
|  | LONG              ulObjRef; | 
|  | CRITICAL_SECTION  DPL_lock; | 
|  | } DirectPlayLobbyIUnknownData; | 
|  |  | 
|  | typedef struct tagDirectPlayLobbyData | 
|  | { | 
|  | HKEY  hkCallbackKeyHack; | 
|  | DWORD dwMsgThread; | 
|  | DPQ_HEAD( DPLMSG ) msgs;  /* List of messages received */ | 
|  | } DirectPlayLobbyData; | 
|  |  | 
|  | typedef struct tagDirectPlayLobby2Data | 
|  | { | 
|  | BOOL dummy; | 
|  | } DirectPlayLobby2Data; | 
|  |  | 
|  | typedef struct tagDirectPlayLobby3Data | 
|  | { | 
|  | BOOL dummy; | 
|  | } DirectPlayLobby3Data; | 
|  |  | 
|  | #define DPL_IMPL_FIELDS \ | 
|  | LONG ulInterfaceRef; \ | 
|  | DirectPlayLobbyIUnknownData*  unk; \ | 
|  | DirectPlayLobbyData*          dpl; \ | 
|  | DirectPlayLobby2Data*         dpl2; \ | 
|  | DirectPlayLobby3Data*         dpl3; | 
|  |  | 
|  | struct IDirectPlayLobbyImpl | 
|  | { | 
|  | const IDirectPlayLobbyVtbl *lpVtbl; | 
|  | DPL_IMPL_FIELDS | 
|  | }; | 
|  |  | 
|  | struct IDirectPlayLobby2Impl | 
|  | { | 
|  | const IDirectPlayLobby2Vtbl *lpVtbl; | 
|  | DPL_IMPL_FIELDS | 
|  | }; | 
|  |  | 
|  | struct IDirectPlayLobby3Impl | 
|  | { | 
|  | const IDirectPlayLobby3Vtbl *lpVtbl; | 
|  | DPL_IMPL_FIELDS | 
|  | }; | 
|  |  | 
|  | /* Forward declarations of virtual tables */ | 
|  | static const IDirectPlayLobbyVtbl  directPlayLobbyWVT; | 
|  | static const IDirectPlayLobby2Vtbl directPlayLobby2WVT; | 
|  | static const IDirectPlayLobby3Vtbl directPlayLobby3WVT; | 
|  |  | 
|  | static const IDirectPlayLobbyVtbl  directPlayLobbyAVT; | 
|  | static const IDirectPlayLobby2Vtbl directPlayLobby2AVT; | 
|  | static const IDirectPlayLobby3Vtbl directPlayLobby3AVT; | 
|  |  | 
|  | static BOOL DPL_CreateIUnknown( LPVOID lpDPL ) | 
|  | { | 
|  | IDirectPlayLobbyAImpl *This = lpDPL; | 
|  |  | 
|  | This->unk = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->unk) ) ); | 
|  | if ( This->unk == NULL ) | 
|  | { | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | InitializeCriticalSection( &This->unk->DPL_lock ); | 
|  | This->unk->DPL_lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectPlayLobbyAImpl*->DirectPlayLobbyIUnknownData*->DPL_lock"); | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | static BOOL DPL_DestroyIUnknown( LPVOID lpDPL ) | 
|  | { | 
|  | IDirectPlayLobbyAImpl *This = lpDPL; | 
|  |  | 
|  | This->unk->DPL_lock.DebugInfo->Spare[0] = 0; | 
|  | DeleteCriticalSection( &This->unk->DPL_lock ); | 
|  | HeapFree( GetProcessHeap(), 0, This->unk ); | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | static BOOL DPL_CreateLobby1( LPVOID lpDPL ) | 
|  | { | 
|  | IDirectPlayLobbyAImpl *This = lpDPL; | 
|  |  | 
|  | This->dpl = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dpl) ) ); | 
|  | if ( This->dpl == NULL ) | 
|  | { | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | DPQ_INIT( This->dpl->msgs ); | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | static BOOL DPL_DestroyLobby1( LPVOID lpDPL ) | 
|  | { | 
|  | IDirectPlayLobbyAImpl *This = lpDPL; | 
|  |  | 
|  | if( This->dpl->dwMsgThread ) | 
|  | { | 
|  | FIXME( "Should kill the msg thread\n" ); | 
|  | } | 
|  |  | 
|  | DPQ_DELETEQ( This->dpl->msgs, msgs, LPDPLMSG, cbDeleteElemFromHeap ); | 
|  |  | 
|  | /* Delete the contents */ | 
|  | HeapFree( GetProcessHeap(), 0, This->dpl ); | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | static BOOL DPL_CreateLobby2( LPVOID lpDPL ) | 
|  | { | 
|  | IDirectPlayLobby2AImpl *This = lpDPL; | 
|  |  | 
|  | This->dpl2 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dpl2) ) ); | 
|  | if ( This->dpl2 == NULL ) | 
|  | { | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | static BOOL DPL_DestroyLobby2( LPVOID lpDPL ) | 
|  | { | 
|  | IDirectPlayLobby2AImpl *This = lpDPL; | 
|  |  | 
|  | HeapFree( GetProcessHeap(), 0, This->dpl2 ); | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | static BOOL DPL_CreateLobby3( LPVOID lpDPL ) | 
|  | { | 
|  | IDirectPlayLobby3AImpl *This = lpDPL; | 
|  |  | 
|  | This->dpl3 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dpl3) ) ); | 
|  | if ( This->dpl3 == NULL ) | 
|  | { | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | static BOOL DPL_DestroyLobby3( LPVOID lpDPL ) | 
|  | { | 
|  | IDirectPlayLobby3AImpl *This = lpDPL; | 
|  |  | 
|  | HeapFree( GetProcessHeap(), 0, This->dpl3 ); | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* The COM interface for upversioning an interface | 
|  | * We've been given a GUID (riid) and we need to replace the present | 
|  | * interface with that of the requested interface. | 
|  | * | 
|  | * Snip from some Microsoft document: | 
|  | * There are four requirements for implementations of QueryInterface (In these | 
|  | * cases, "must succeed" means "must succeed barring catastrophic failure."): | 
|  | * | 
|  | *  * The set of interfaces accessible on an object through | 
|  | *    IUnknown::QueryInterface must be static, not dynamic. This means that | 
|  | *    if a call to QueryInterface for a pointer to a specified interface | 
|  | *    succeeds the first time, it must succeed again, and if it fails the | 
|  | *    first time, it must fail on all subsequent queries. | 
|  | *  * It must be symmetric ~W if a client holds a pointer to an interface on | 
|  | *    an object, and queries for that interface, the call must succeed. | 
|  | *  * It must be reflexive ~W if a client holding a pointer to one interface | 
|  | *    queries successfully for another, a query through the obtained pointer | 
|  | *    for the first interface must succeed. | 
|  | *  * It must be transitive ~W if a client holding a pointer to one interface | 
|  | *    queries successfully for a second, and through that pointer queries | 
|  | *    successfully for a third interface, a query for the first interface | 
|  | *    through the pointer for the third interface must succeed. | 
|  | */ | 
|  | HRESULT DPL_CreateInterface | 
|  | ( REFIID riid, LPVOID* ppvObj ) | 
|  | { | 
|  | TRACE( " for %s\n", debugstr_guid( riid ) ); | 
|  |  | 
|  | *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, | 
|  | sizeof( IDirectPlayLobbyWImpl ) ); | 
|  |  | 
|  | if( *ppvObj == NULL ) | 
|  | { | 
|  | return DPERR_OUTOFMEMORY; | 
|  | } | 
|  |  | 
|  | if( IsEqualGUID( &IID_IDirectPlayLobby, riid ) ) | 
|  | { | 
|  | IDirectPlayLobbyWImpl *This = *ppvObj; | 
|  | This->lpVtbl = &directPlayLobbyWVT; | 
|  | } | 
|  | else if( IsEqualGUID( &IID_IDirectPlayLobbyA, riid ) ) | 
|  | { | 
|  | IDirectPlayLobbyAImpl *This = *ppvObj; | 
|  | This->lpVtbl = &directPlayLobbyAVT; | 
|  | } | 
|  | else if( IsEqualGUID( &IID_IDirectPlayLobby2, riid ) ) | 
|  | { | 
|  | IDirectPlayLobby2WImpl *This = *ppvObj; | 
|  | This->lpVtbl = &directPlayLobby2WVT; | 
|  | } | 
|  | else if( IsEqualGUID( &IID_IDirectPlayLobby2A, riid ) ) | 
|  | { | 
|  | IDirectPlayLobby2AImpl *This = *ppvObj; | 
|  | This->lpVtbl = &directPlayLobby2AVT; | 
|  | } | 
|  | else if( IsEqualGUID( &IID_IDirectPlayLobby3, riid ) ) | 
|  | { | 
|  | IDirectPlayLobby3WImpl *This = *ppvObj; | 
|  | This->lpVtbl = &directPlayLobby3WVT; | 
|  | } | 
|  | else if( IsEqualGUID( &IID_IDirectPlayLobby3A, riid ) ) | 
|  | { | 
|  | IDirectPlayLobby3AImpl *This = *ppvObj; | 
|  | This->lpVtbl = &directPlayLobby3AVT; | 
|  | } | 
|  | else | 
|  | { | 
|  | /* Unsupported interface */ | 
|  | HeapFree( GetProcessHeap(), 0, *ppvObj ); | 
|  | *ppvObj = NULL; | 
|  |  | 
|  | return E_NOINTERFACE; | 
|  | } | 
|  |  | 
|  | /* Initialize it */ | 
|  | if ( DPL_CreateIUnknown( *ppvObj ) && | 
|  | DPL_CreateLobby1( *ppvObj ) && | 
|  | DPL_CreateLobby2( *ppvObj ) && | 
|  | DPL_CreateLobby3( *ppvObj ) | 
|  | ) | 
|  | { | 
|  | IDirectPlayLobby_AddRef( (LPDIRECTPLAYLOBBY)*ppvObj ); | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | /* Initialize failed, destroy it */ | 
|  | DPL_DestroyLobby3( *ppvObj ); | 
|  | DPL_DestroyLobby2( *ppvObj ); | 
|  | DPL_DestroyLobby1( *ppvObj ); | 
|  | DPL_DestroyIUnknown( *ppvObj ); | 
|  | HeapFree( GetProcessHeap(), 0, *ppvObj ); | 
|  |  | 
|  | *ppvObj = NULL; | 
|  | return DPERR_NOMEMORY; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI DPL_QueryInterface | 
|  | ( LPDIRECTPLAYLOBBYA iface, | 
|  | REFIID riid, | 
|  | LPVOID* ppvObj ) | 
|  | { | 
|  | IDirectPlayLobbyAImpl *This = (IDirectPlayLobbyAImpl *)iface; | 
|  | TRACE("(%p)->(%s,%p)\n", This, debugstr_guid( riid ), ppvObj ); | 
|  |  | 
|  | *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, | 
|  | sizeof( *This ) ); | 
|  |  | 
|  | if( *ppvObj == NULL ) | 
|  | { | 
|  | return DPERR_OUTOFMEMORY; | 
|  | } | 
|  |  | 
|  | CopyMemory( *ppvObj, This, sizeof( *This )  ); | 
|  | (*(IDirectPlayLobbyAImpl**)ppvObj)->ulInterfaceRef = 0; | 
|  |  | 
|  | if( IsEqualGUID( &IID_IDirectPlayLobby, riid ) ) | 
|  | { | 
|  | IDirectPlayLobbyWImpl *This = *ppvObj; | 
|  | This->lpVtbl = &directPlayLobbyWVT; | 
|  | } | 
|  | else if( IsEqualGUID( &IID_IDirectPlayLobbyA, riid ) ) | 
|  | { | 
|  | IDirectPlayLobbyAImpl *This = *ppvObj; | 
|  | This->lpVtbl = &directPlayLobbyAVT; | 
|  | } | 
|  | else if( IsEqualGUID( &IID_IDirectPlayLobby2, riid ) ) | 
|  | { | 
|  | IDirectPlayLobby2WImpl *This = *ppvObj; | 
|  | This->lpVtbl = &directPlayLobby2WVT; | 
|  | } | 
|  | else if( IsEqualGUID( &IID_IDirectPlayLobby2A, riid ) ) | 
|  | { | 
|  | IDirectPlayLobby2AImpl *This = *ppvObj; | 
|  | This->lpVtbl = &directPlayLobby2AVT; | 
|  | } | 
|  | else if( IsEqualGUID( &IID_IDirectPlayLobby3, riid ) ) | 
|  | { | 
|  | IDirectPlayLobby3WImpl *This = *ppvObj; | 
|  | This->lpVtbl = &directPlayLobby3WVT; | 
|  | } | 
|  | else if( IsEqualGUID( &IID_IDirectPlayLobby3A, riid ) ) | 
|  | { | 
|  | IDirectPlayLobby3AImpl *This = *ppvObj; | 
|  | This->lpVtbl = &directPlayLobby3AVT; | 
|  | } | 
|  | else | 
|  | { | 
|  | /* Unsupported interface */ | 
|  | HeapFree( GetProcessHeap(), 0, *ppvObj ); | 
|  | *ppvObj = NULL; | 
|  |  | 
|  | return E_NOINTERFACE; | 
|  | } | 
|  |  | 
|  | IDirectPlayLobby_AddRef( (LPDIRECTPLAYLOBBY)*ppvObj ); | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Simple procedure. Just increment the reference count to this | 
|  | * structure and return the new reference count. | 
|  | */ | 
|  | static ULONG WINAPI DPL_AddRef | 
|  | ( LPDIRECTPLAYLOBBY iface ) | 
|  | { | 
|  | ULONG ulInterfaceRefCount, ulObjRefCount; | 
|  | IDirectPlayLobbyWImpl *This = (IDirectPlayLobbyWImpl *)iface; | 
|  |  | 
|  | ulObjRefCount       = InterlockedIncrement( &This->unk->ulObjRef ); | 
|  | ulInterfaceRefCount = InterlockedIncrement( &This->ulInterfaceRef ); | 
|  |  | 
|  | TRACE( "ref count incremented to %u:%u for %p\n", | 
|  | ulInterfaceRefCount, ulObjRefCount, This ); | 
|  |  | 
|  | return ulObjRefCount; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Simple COM procedure. Decrease the reference count to this object. | 
|  | * If the object no longer has any reference counts, free up the associated | 
|  | * memory. | 
|  | */ | 
|  | static ULONG WINAPI DPL_Release | 
|  | ( LPDIRECTPLAYLOBBYA iface ) | 
|  | { | 
|  | ULONG ulInterfaceRefCount, ulObjRefCount; | 
|  | IDirectPlayLobbyAImpl *This = (IDirectPlayLobbyAImpl *)iface; | 
|  |  | 
|  | ulObjRefCount       = InterlockedDecrement( &This->unk->ulObjRef ); | 
|  | ulInterfaceRefCount = InterlockedDecrement( &This->ulInterfaceRef ); | 
|  |  | 
|  | TRACE( "ref count decremented to %u:%u for %p\n", | 
|  | ulInterfaceRefCount, ulObjRefCount, This ); | 
|  |  | 
|  | /* Deallocate if this is the last reference to the object */ | 
|  | if( ulObjRefCount == 0 ) | 
|  | { | 
|  | DPL_DestroyLobby3( This ); | 
|  | DPL_DestroyLobby2( This ); | 
|  | DPL_DestroyLobby1( This ); | 
|  | DPL_DestroyIUnknown( This ); | 
|  | } | 
|  |  | 
|  | if( ulInterfaceRefCount == 0 ) | 
|  | { | 
|  | HeapFree( GetProcessHeap(), 0, This ); | 
|  | } | 
|  |  | 
|  | return ulInterfaceRefCount; | 
|  | } | 
|  |  | 
|  |  | 
|  | /******************************************************************** | 
|  | * | 
|  | * Connects an application to the session specified by the DPLCONNECTION | 
|  | * structure currently stored with the DirectPlayLobby object. | 
|  | * | 
|  | * Returns an IDirectPlay interface. | 
|  | * | 
|  | */ | 
|  | static HRESULT DPL_ConnectEx | 
|  | ( IDirectPlayLobbyAImpl* This, | 
|  | DWORD     dwFlags, | 
|  | REFIID    riid, | 
|  | LPVOID*   lplpDP, | 
|  | IUnknown* pUnk) | 
|  | { | 
|  | HRESULT         hr; | 
|  | DWORD           dwOpenFlags = 0; | 
|  | DWORD           dwConnSize = 0; | 
|  | LPDPLCONNECTION lpConn; | 
|  |  | 
|  | FIXME("(%p)->(0x%08x,%p,%p): semi stub\n", This, dwFlags, lplpDP, pUnk ); | 
|  |  | 
|  | if( pUnk ) | 
|  | { | 
|  | return DPERR_INVALIDPARAMS; | 
|  | } | 
|  |  | 
|  | /* Backwards compatibility */ | 
|  | if( dwFlags == 0 ) | 
|  | { | 
|  | dwFlags = DPCONNECT_RETURNSTATUS; | 
|  | } | 
|  |  | 
|  | /* Create the DirectPlay interface */ | 
|  | if( ( hr = DP_CreateInterface( riid, lplpDP ) ) != DP_OK ) | 
|  | { | 
|  | ERR( "error creating interface for %s:%s.\n", | 
|  | debugstr_guid( riid ), DPLAYX_HresultToString( hr ) ); | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | /* FIXME: Is it safe/correct to use appID of 0? */ | 
|  | hr = IDirectPlayLobby_GetConnectionSettings( (LPDIRECTPLAYLOBBY)This, | 
|  | 0, NULL, &dwConnSize ); | 
|  | if( hr != DPERR_BUFFERTOOSMALL ) | 
|  | { | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | lpConn = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwConnSize ); | 
|  |  | 
|  | if( lpConn == NULL ) | 
|  | { | 
|  | return DPERR_NOMEMORY; | 
|  | } | 
|  |  | 
|  | /* FIXME: Is it safe/correct to use appID of 0? */ | 
|  | hr = IDirectPlayLobby_GetConnectionSettings( (LPDIRECTPLAYLOBBY)This, | 
|  | 0, lpConn, &dwConnSize ); | 
|  | if( FAILED( hr ) ) | 
|  | { | 
|  | HeapFree( GetProcessHeap(), 0, lpConn ); | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | #if 0 | 
|  | /* - Need to call IDirectPlay::EnumConnections with the service provider to get that good information | 
|  | * - Need to call CreateAddress to create the lpConnection param for IDirectPlay::InitializeConnection | 
|  | * - Call IDirectPlay::InitializeConnection | 
|  | */ | 
|  |  | 
|  | /* Now initialize the Service Provider */ | 
|  | hr = IDirectPlayX_InitializeConnection( (*(LPDIRECTPLAY2*)lplpDP), | 
|  | #endif | 
|  |  | 
|  |  | 
|  | /* Setup flags to pass into DirectPlay::Open */ | 
|  | if( dwFlags & DPCONNECT_RETURNSTATUS ) | 
|  | { | 
|  | dwOpenFlags |= DPOPEN_RETURNSTATUS; | 
|  | } | 
|  | dwOpenFlags |= lpConn->dwFlags; | 
|  |  | 
|  | hr = IDirectPlayX_Open( (*(LPDIRECTPLAY2*)lplpDP), lpConn->lpSessionDesc, | 
|  | dwOpenFlags ); | 
|  |  | 
|  | HeapFree( GetProcessHeap(), 0, lpConn ); | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IDirectPlayLobbyAImpl_Connect | 
|  | ( LPDIRECTPLAYLOBBYA iface, | 
|  | DWORD dwFlags, | 
|  | LPDIRECTPLAY2A* lplpDP, | 
|  | IUnknown* pUnk) | 
|  | { | 
|  | IDirectPlayLobbyAImpl *This = (IDirectPlayLobbyAImpl *)iface; | 
|  | return DPL_ConnectEx( This, dwFlags, &IID_IDirectPlay2A, | 
|  | (LPVOID)lplpDP, pUnk ); | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IDirectPlayLobbyWImpl_Connect | 
|  | ( LPDIRECTPLAYLOBBY iface, | 
|  | DWORD dwFlags, | 
|  | LPDIRECTPLAY2* lplpDP, | 
|  | IUnknown* pUnk) | 
|  | { | 
|  | IDirectPlayLobbyAImpl *This = (IDirectPlayLobbyAImpl *)iface; /* Yes cast to A */ | 
|  | return DPL_ConnectEx( This, dwFlags, &IID_IDirectPlay2, | 
|  | (LPVOID)lplpDP, pUnk ); | 
|  | } | 
|  |  | 
|  | /******************************************************************** | 
|  | * | 
|  | * Creates a DirectPlay Address, given a service provider-specific network | 
|  | * address. | 
|  | * Returns an address contains the globally unique identifier | 
|  | * (GUID) of the service provider and data that the service provider can | 
|  | * interpret as a network address. | 
|  | * | 
|  | * NOTE: It appears that this method is supposed to be really really stupid | 
|  | *       with no error checking on the contents. | 
|  | */ | 
|  | static HRESULT WINAPI IDirectPlayLobbyAImpl_CreateAddress | 
|  | ( LPDIRECTPLAYLOBBYA iface, | 
|  | REFGUID guidSP, | 
|  | REFGUID guidDataType, | 
|  | LPCVOID lpData, | 
|  | DWORD dwDataSize, | 
|  | LPVOID lpAddress, | 
|  | LPDWORD lpdwAddressSize ) | 
|  | { | 
|  | return DPL_CreateAddress( guidSP, guidDataType, lpData, dwDataSize, | 
|  | lpAddress, lpdwAddressSize, TRUE ); | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IDirectPlayLobbyWImpl_CreateAddress | 
|  | ( LPDIRECTPLAYLOBBY iface, | 
|  | REFGUID guidSP, | 
|  | REFGUID guidDataType, | 
|  | LPCVOID lpData, | 
|  | DWORD dwDataSize, | 
|  | LPVOID lpAddress, | 
|  | LPDWORD lpdwAddressSize ) | 
|  | { | 
|  | return DPL_CreateAddress( guidSP, guidDataType, lpData, dwDataSize, | 
|  | lpAddress, lpdwAddressSize, FALSE ); | 
|  | } | 
|  |  | 
|  | static HRESULT DPL_CreateAddress( | 
|  | REFGUID guidSP, | 
|  | REFGUID guidDataType, | 
|  | LPCVOID lpData, | 
|  | DWORD dwDataSize, | 
|  | LPVOID lpAddress, | 
|  | LPDWORD lpdwAddressSize, | 
|  | BOOL bAnsiInterface ) | 
|  | { | 
|  | const DWORD dwNumAddElements = 2; /* Service Provide & address data type */ | 
|  | DPCOMPOUNDADDRESSELEMENT addressElements[ 2 /* dwNumAddElements */ ]; | 
|  |  | 
|  | TRACE( "(%p)->(%p,%p,0x%08x,%p,%p,%d)\n", guidSP, guidDataType, lpData, dwDataSize, | 
|  | lpAddress, lpdwAddressSize, bAnsiInterface ); | 
|  |  | 
|  | addressElements[ 0 ].guidDataType = DPAID_ServiceProvider; | 
|  | addressElements[ 0 ].dwDataSize = sizeof( GUID ); | 
|  | addressElements[ 0 ].lpData = (LPVOID)guidSP; | 
|  |  | 
|  | addressElements[ 1 ].guidDataType = *guidDataType; | 
|  | addressElements[ 1 ].dwDataSize = dwDataSize; | 
|  | addressElements[ 1 ].lpData = (LPVOID)lpData; | 
|  |  | 
|  | /* Call CreateCompoundAddress to cut down on code. | 
|  | NOTE: We can do this because we don't support DPL 1 interfaces! */ | 
|  | return DPL_CreateCompoundAddress( addressElements, dwNumAddElements, | 
|  | lpAddress, lpdwAddressSize, bAnsiInterface ); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | /******************************************************************** | 
|  | * | 
|  | * Parses out chunks from the DirectPlay Address buffer by calling the | 
|  | * given callback function, with lpContext, for each of the chunks. | 
|  | * | 
|  | */ | 
|  | static HRESULT WINAPI IDirectPlayLobbyAImpl_EnumAddress | 
|  | ( LPDIRECTPLAYLOBBYA iface, | 
|  | LPDPENUMADDRESSCALLBACK lpEnumAddressCallback, | 
|  | LPCVOID lpAddress, | 
|  | DWORD dwAddressSize, | 
|  | LPVOID lpContext ) | 
|  | { | 
|  | IDirectPlayLobbyAImpl *This = (IDirectPlayLobbyAImpl *)iface; | 
|  |  | 
|  | TRACE("(%p)->(%p,%p,0x%08x,%p)\n", This, lpEnumAddressCallback, lpAddress, | 
|  | dwAddressSize, lpContext ); | 
|  |  | 
|  | return DPL_EnumAddress( lpEnumAddressCallback, lpAddress, dwAddressSize, lpContext ); | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IDirectPlayLobbyWImpl_EnumAddress | 
|  | ( LPDIRECTPLAYLOBBY iface, | 
|  | LPDPENUMADDRESSCALLBACK lpEnumAddressCallback, | 
|  | LPCVOID lpAddress, | 
|  | DWORD dwAddressSize, | 
|  | LPVOID lpContext ) | 
|  | { | 
|  | IDirectPlayLobbyWImpl *This = (IDirectPlayLobbyWImpl *)iface; | 
|  |  | 
|  | TRACE("(%p)->(%p,%p,0x%08x,%p)\n", This, lpEnumAddressCallback, lpAddress, | 
|  | dwAddressSize, lpContext ); | 
|  |  | 
|  | return DPL_EnumAddress( lpEnumAddressCallback, lpAddress, dwAddressSize, lpContext ); | 
|  | } | 
|  |  | 
|  | HRESULT DPL_EnumAddress( LPDPENUMADDRESSCALLBACK lpEnumAddressCallback, LPCVOID lpAddress, | 
|  | DWORD dwAddressSize, LPVOID lpContext ) | 
|  | { | 
|  | DWORD dwTotalSizeEnumerated = 0; | 
|  |  | 
|  | /* FIXME: First chunk is always the total size chunk - Should we report it? */ | 
|  |  | 
|  | while ( dwTotalSizeEnumerated < dwAddressSize ) | 
|  | { | 
|  | const DPADDRESS* lpElements = lpAddress; | 
|  | DWORD dwSizeThisEnumeration; | 
|  |  | 
|  | /* Invoke the enum method. If false is returned, stop enumeration */ | 
|  | if ( !lpEnumAddressCallback( &lpElements->guidDataType, | 
|  | lpElements->dwDataSize, | 
|  | (const BYTE *)lpElements + sizeof( DPADDRESS ), | 
|  | lpContext ) ) | 
|  | { | 
|  | break; | 
|  | } | 
|  |  | 
|  | dwSizeThisEnumeration  = sizeof( DPADDRESS ) + lpElements->dwDataSize; | 
|  | lpAddress = (const BYTE*) lpAddress + dwSizeThisEnumeration; | 
|  | dwTotalSizeEnumerated += dwSizeThisEnumeration; | 
|  | } | 
|  |  | 
|  | return DP_OK; | 
|  | } | 
|  |  | 
|  | /******************************************************************** | 
|  | * | 
|  | * Enumerates all the address types that a given service provider needs to | 
|  | * build the DirectPlay Address. | 
|  | * | 
|  | */ | 
|  | static HRESULT WINAPI IDirectPlayLobbyAImpl_EnumAddressTypes | 
|  | ( LPDIRECTPLAYLOBBYA iface, | 
|  | LPDPLENUMADDRESSTYPESCALLBACK lpEnumAddressTypeCallback, | 
|  | REFGUID guidSP, | 
|  | LPVOID lpContext, | 
|  | DWORD dwFlags ) | 
|  | { | 
|  | IDirectPlayLobbyAImpl *This = (IDirectPlayLobbyAImpl *)iface; | 
|  |  | 
|  | HKEY   hkResult; | 
|  | LPCSTR searchSubKey    = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers"; | 
|  | DWORD  dwIndex, sizeOfSubKeyName=50; | 
|  | char   subKeyName[51]; | 
|  | FILETIME filetime; | 
|  |  | 
|  | TRACE(" (%p)->(%p,%p,%p,0x%08x)\n", This, lpEnumAddressTypeCallback, guidSP, lpContext, dwFlags ); | 
|  |  | 
|  | if( dwFlags != 0 ) | 
|  | { | 
|  | return DPERR_INVALIDPARAMS; | 
|  | } | 
|  |  | 
|  | if( !lpEnumAddressTypeCallback ) | 
|  | { | 
|  | return DPERR_INVALIDPARAMS; | 
|  | } | 
|  |  | 
|  | if( guidSP == NULL ) | 
|  | { | 
|  | return DPERR_INVALIDOBJECT; | 
|  | } | 
|  |  | 
|  | /* Need to loop over the service providers in the registry */ | 
|  | if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey, | 
|  | 0, KEY_READ, &hkResult ) != ERROR_SUCCESS ) | 
|  | { | 
|  | /* Hmmm. Does this mean that there are no service providers? */ | 
|  | ERR(": no service providers?\n"); | 
|  | return DP_OK; | 
|  | } | 
|  |  | 
|  | /* Traverse all the service providers we have available */ | 
|  | for( dwIndex=0; | 
|  | RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName, | 
|  | NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS; | 
|  | ++dwIndex, sizeOfSubKeyName=50 ) | 
|  | { | 
|  |  | 
|  | HKEY     hkServiceProvider, hkServiceProviderAt; | 
|  | GUID     serviceProviderGUID; | 
|  | DWORD    returnTypeGUID, sizeOfReturnBuffer = 50; | 
|  | char     atSubKey[51]; | 
|  | char     returnBuffer[51]; | 
|  | WCHAR    buff[51]; | 
|  | DWORD    dwAtIndex; | 
|  | LPCSTR   atKey = "Address Types"; | 
|  | LPCSTR   guidDataSubKey   = "Guid"; | 
|  | FILETIME filetime; | 
|  |  | 
|  |  | 
|  | TRACE(" this time through: %s\n", subKeyName ); | 
|  |  | 
|  | /* Get a handle for this particular service provider */ | 
|  | if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ, | 
|  | &hkServiceProvider ) != ERROR_SUCCESS ) | 
|  | { | 
|  | ERR(": what the heck is going on?\n" ); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if( RegQueryValueExA( hkServiceProvider, guidDataSubKey, | 
|  | NULL, &returnTypeGUID, (LPBYTE)returnBuffer, | 
|  | &sizeOfReturnBuffer ) != ERROR_SUCCESS ) | 
|  | { | 
|  | ERR(": missing GUID registry data members\n" ); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | /* FIXME: Check return types to ensure we're interpreting data right */ | 
|  | MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) ); | 
|  | CLSIDFromString( buff, &serviceProviderGUID ); | 
|  | /* FIXME: Have I got a memory leak on the serviceProviderGUID? */ | 
|  |  | 
|  | /* Determine if this is the Service Provider that the user asked for */ | 
|  | if( !IsEqualGUID( &serviceProviderGUID, guidSP ) ) | 
|  | { | 
|  | continue; | 
|  | } | 
|  |  | 
|  | /* Get a handle for this particular service provider */ | 
|  | if( RegOpenKeyExA( hkServiceProvider, atKey, 0, KEY_READ, | 
|  | &hkServiceProviderAt ) != ERROR_SUCCESS ) | 
|  | { | 
|  | TRACE(": No Address Types registry data sub key/members\n" ); | 
|  | break; | 
|  | } | 
|  |  | 
|  | /* Traverse all the address type we have available */ | 
|  | for( dwAtIndex=0; | 
|  | RegEnumKeyExA( hkServiceProviderAt, dwAtIndex, atSubKey, &sizeOfSubKeyName, | 
|  | NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS; | 
|  | ++dwAtIndex, sizeOfSubKeyName=50 ) | 
|  | { | 
|  | TRACE( "Found Address Type GUID %s\n", atSubKey ); | 
|  |  | 
|  | /* FIXME: Check return types to ensure we're interpreting data right */ | 
|  | MultiByteToWideChar( CP_ACP, 0, atSubKey, -1, buff, sizeof(buff)/sizeof(WCHAR) ); | 
|  | CLSIDFromString( buff, &serviceProviderGUID ); | 
|  | /* FIXME: Have I got a memory leak on the serviceProviderGUID? */ | 
|  |  | 
|  | /* The enumeration will return FALSE if we are not to continue */ | 
|  | if( !lpEnumAddressTypeCallback( &serviceProviderGUID, lpContext, 0 ) ) | 
|  | { | 
|  | WARN("lpEnumCallback returning FALSE\n" ); | 
|  | break; /* FIXME: This most likely has to break from the procedure...*/ | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | /* We only enumerate address types for 1 GUID. We've found it, so quit looking */ | 
|  | break; | 
|  | } | 
|  |  | 
|  | return DP_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IDirectPlayLobbyWImpl_EnumAddressTypes | 
|  | ( LPDIRECTPLAYLOBBY iface, | 
|  | LPDPLENUMADDRESSTYPESCALLBACK lpEnumAddressTypeCallback, | 
|  | REFGUID guidSP, | 
|  | LPVOID lpContext, | 
|  | DWORD dwFlags ) | 
|  | { | 
|  | FIXME(":stub\n"); | 
|  | return DPERR_OUTOFMEMORY; | 
|  | } | 
|  |  | 
|  | /******************************************************************** | 
|  | * | 
|  | * Enumerates what applications are registered with DirectPlay by | 
|  | * invoking the callback function with lpContext. | 
|  | * | 
|  | */ | 
|  | static HRESULT WINAPI IDirectPlayLobbyWImpl_EnumLocalApplications | 
|  | ( LPDIRECTPLAYLOBBY iface, | 
|  | LPDPLENUMLOCALAPPLICATIONSCALLBACK lpEnumLocalAppCallback, | 
|  | LPVOID lpContext, | 
|  | DWORD dwFlags ) | 
|  | { | 
|  | IDirectPlayLobbyWImpl *This = (IDirectPlayLobbyWImpl *)iface; | 
|  |  | 
|  | FIXME("(%p)->(%p,%p,0x%08x):stub\n", This, lpEnumLocalAppCallback, lpContext, dwFlags ); | 
|  |  | 
|  | return DPERR_OUTOFMEMORY; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IDirectPlayLobbyAImpl_EnumLocalApplications | 
|  | ( LPDIRECTPLAYLOBBYA iface, | 
|  | LPDPLENUMLOCALAPPLICATIONSCALLBACK lpEnumLocalAppCallback, | 
|  | LPVOID lpContext, | 
|  | DWORD dwFlags ) | 
|  | { | 
|  | IDirectPlayLobbyAImpl *This = (IDirectPlayLobbyAImpl *)iface; | 
|  |  | 
|  | HKEY hkResult; | 
|  | LPCSTR searchSubKey    = "SOFTWARE\\Microsoft\\DirectPlay\\Applications"; | 
|  | LPCSTR guidDataSubKey  = "Guid"; | 
|  | DWORD dwIndex, sizeOfSubKeyName=50; | 
|  | char subKeyName[51]; | 
|  | FILETIME filetime; | 
|  |  | 
|  | TRACE("(%p)->(%p,%p,0x%08x)\n", This, lpEnumLocalAppCallback, lpContext, dwFlags ); | 
|  |  | 
|  | if( dwFlags != 0 ) | 
|  | { | 
|  | return DPERR_INVALIDPARAMS; | 
|  | } | 
|  |  | 
|  | if( !lpEnumLocalAppCallback ) | 
|  | { | 
|  | return DPERR_INVALIDPARAMS; | 
|  | } | 
|  |  | 
|  | /* Need to loop over the service providers in the registry */ | 
|  | if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey, | 
|  | 0, KEY_READ, &hkResult ) != ERROR_SUCCESS ) | 
|  | { | 
|  | /* Hmmm. Does this mean that there are no service providers? */ | 
|  | ERR(": no service providers?\n"); | 
|  | return DP_OK; | 
|  | } | 
|  |  | 
|  | /* Traverse all registered applications */ | 
|  | for( dwIndex=0; | 
|  | RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName, NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS; | 
|  | ++dwIndex, sizeOfSubKeyName=50 ) | 
|  | { | 
|  |  | 
|  | HKEY       hkServiceProvider; | 
|  | GUID       serviceProviderGUID; | 
|  | DWORD      returnTypeGUID, sizeOfReturnBuffer = 50; | 
|  | char       returnBuffer[51]; | 
|  | WCHAR      buff[51]; | 
|  | DPLAPPINFO dplAppInfo; | 
|  |  | 
|  | TRACE(" this time through: %s\n", subKeyName ); | 
|  |  | 
|  | /* Get a handle for this particular service provider */ | 
|  | if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ, | 
|  | &hkServiceProvider ) != ERROR_SUCCESS ) | 
|  | { | 
|  | ERR(": what the heck is going on?\n" ); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if( RegQueryValueExA( hkServiceProvider, guidDataSubKey, | 
|  | NULL, &returnTypeGUID, (LPBYTE)returnBuffer, | 
|  | &sizeOfReturnBuffer ) != ERROR_SUCCESS ) | 
|  | { | 
|  | ERR(": missing GUID registry data members\n" ); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | /* FIXME: Check return types to ensure we're interpreting data right */ | 
|  | MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) ); | 
|  | CLSIDFromString( buff, &serviceProviderGUID ); | 
|  | /* FIXME: Have I got a memory leak on the serviceProviderGUID? */ | 
|  |  | 
|  | dplAppInfo.dwSize               = sizeof( dplAppInfo ); | 
|  | dplAppInfo.guidApplication      = serviceProviderGUID; | 
|  | dplAppInfo.u.lpszAppNameA = subKeyName; | 
|  |  | 
|  | EnterCriticalSection( &This->unk->DPL_lock ); | 
|  |  | 
|  | memcpy( &This->dpl->hkCallbackKeyHack, &hkServiceProvider, sizeof( hkServiceProvider ) ); | 
|  |  | 
|  | if( !lpEnumLocalAppCallback( &dplAppInfo, lpContext, dwFlags ) ) | 
|  | { | 
|  | LeaveCriticalSection( &This->unk->DPL_lock ); | 
|  | break; | 
|  | } | 
|  |  | 
|  | LeaveCriticalSection( &This->unk->DPL_lock ); | 
|  | } | 
|  |  | 
|  | return DP_OK; | 
|  | } | 
|  |  | 
|  | /******************************************************************** | 
|  | * | 
|  | * Retrieves the DPLCONNECTION structure that contains all the information | 
|  | * needed to start and connect an application. This was generated using | 
|  | * either the RunApplication or SetConnectionSettings methods. | 
|  | * | 
|  | * NOTES: If lpData is NULL then just return lpdwDataSize. This allows | 
|  | *        the data structure to be allocated by our caller which can then | 
|  | *        call this procedure/method again with a valid data pointer. | 
|  | */ | 
|  | static HRESULT WINAPI IDirectPlayLobbyAImpl_GetConnectionSettings | 
|  | ( LPDIRECTPLAYLOBBYA iface, | 
|  | DWORD dwAppID, | 
|  | LPVOID lpData, | 
|  | LPDWORD lpdwDataSize ) | 
|  | { | 
|  | IDirectPlayLobbyAImpl *This = (IDirectPlayLobbyAImpl *)iface; | 
|  | HRESULT hr; | 
|  |  | 
|  | TRACE("(%p)->(0x%08x,%p,%p)\n", This, dwAppID, lpData, lpdwDataSize ); | 
|  |  | 
|  | EnterCriticalSection( &This->unk->DPL_lock ); | 
|  |  | 
|  | hr = DPLAYX_GetConnectionSettingsA( dwAppID, | 
|  | lpData, | 
|  | lpdwDataSize | 
|  | ); | 
|  |  | 
|  | LeaveCriticalSection( &This->unk->DPL_lock ); | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IDirectPlayLobbyWImpl_GetConnectionSettings | 
|  | ( LPDIRECTPLAYLOBBY iface, | 
|  | DWORD dwAppID, | 
|  | LPVOID lpData, | 
|  | LPDWORD lpdwDataSize ) | 
|  | { | 
|  | IDirectPlayLobbyWImpl *This = (IDirectPlayLobbyWImpl *)iface; | 
|  | HRESULT hr; | 
|  |  | 
|  | TRACE("(%p)->(0x%08x,%p,%p)\n", This, dwAppID, lpData, lpdwDataSize ); | 
|  |  | 
|  | EnterCriticalSection( &This->unk->DPL_lock ); | 
|  |  | 
|  | hr = DPLAYX_GetConnectionSettingsW( dwAppID, | 
|  | lpData, | 
|  | lpdwDataSize | 
|  | ); | 
|  |  | 
|  | LeaveCriticalSection( &This->unk->DPL_lock ); | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | /******************************************************************** | 
|  | * | 
|  | * Retrieves the message sent between a lobby client and a DirectPlay | 
|  | * application. All messages are queued until received. | 
|  | * | 
|  | */ | 
|  | static HRESULT WINAPI IDirectPlayLobbyAImpl_ReceiveLobbyMessage | 
|  | ( LPDIRECTPLAYLOBBYA iface, | 
|  | DWORD dwFlags, | 
|  | DWORD dwAppID, | 
|  | LPDWORD lpdwMessageFlags, | 
|  | LPVOID lpData, | 
|  | LPDWORD lpdwDataSize ) | 
|  | { | 
|  | IDirectPlayLobbyAImpl *This = (IDirectPlayLobbyAImpl *)iface; | 
|  | FIXME(":stub %p %08x %08x %p %p %p\n", This, dwFlags, dwAppID, lpdwMessageFlags, lpData, | 
|  | lpdwDataSize ); | 
|  | return DPERR_OUTOFMEMORY; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IDirectPlayLobbyWImpl_ReceiveLobbyMessage | 
|  | ( LPDIRECTPLAYLOBBY iface, | 
|  | DWORD dwFlags, | 
|  | DWORD dwAppID, | 
|  | LPDWORD lpdwMessageFlags, | 
|  | LPVOID lpData, | 
|  | LPDWORD lpdwDataSize ) | 
|  | { | 
|  | IDirectPlayLobbyWImpl *This = (IDirectPlayLobbyWImpl *)iface; | 
|  | FIXME(":stub %p %08x %08x %p %p %p\n", This, dwFlags, dwAppID, lpdwMessageFlags, lpData, | 
|  | lpdwDataSize ); | 
|  | return DPERR_OUTOFMEMORY; | 
|  | } | 
|  |  | 
|  | typedef struct tagRunApplicationEnumStruct | 
|  | { | 
|  | IDirectPlayLobbyAImpl* This; | 
|  |  | 
|  | GUID  appGUID; | 
|  | LPSTR lpszPath; | 
|  | LPSTR lpszFileName; | 
|  | LPSTR lpszCommandLine; | 
|  | LPSTR lpszCurrentDirectory; | 
|  | } RunApplicationEnumStruct, *lpRunApplicationEnumStruct; | 
|  |  | 
|  | /* To be called by RunApplication to find how to invoke the function */ | 
|  | static BOOL CALLBACK RunApplicationA_EnumLocalApplications | 
|  | ( LPCDPLAPPINFO   lpAppInfo, | 
|  | LPVOID          lpContext, | 
|  | DWORD           dwFlags ) | 
|  | { | 
|  | lpRunApplicationEnumStruct lpData = (lpRunApplicationEnumStruct)lpContext; | 
|  |  | 
|  | if( IsEqualGUID( &lpAppInfo->guidApplication, &lpData->appGUID ) ) | 
|  | { | 
|  | char  returnBuffer[200]; | 
|  | DWORD returnType, sizeOfReturnBuffer; | 
|  | LPCSTR clSubKey   = "CommandLine"; | 
|  | LPCSTR cdSubKey   = "CurrentDirectory"; | 
|  | LPCSTR fileSubKey = "File"; | 
|  | LPCSTR pathSubKey = "Path"; | 
|  |  | 
|  | /* FIXME: Lazy man hack - dplay struct has the present reg key saved */ | 
|  |  | 
|  | sizeOfReturnBuffer = 200; | 
|  |  | 
|  | /* Get all the appropriate data from the registry */ | 
|  | if( RegQueryValueExA( lpData->This->dpl->hkCallbackKeyHack, clSubKey, | 
|  | NULL, &returnType, (LPBYTE)returnBuffer, | 
|  | &sizeOfReturnBuffer ) != ERROR_SUCCESS ) | 
|  | { | 
|  | ERR( ": missing CommandLine registry data member\n" ); | 
|  | } | 
|  | else | 
|  | { | 
|  | if ((lpData->lpszCommandLine = HeapAlloc( GetProcessHeap(), 0, strlen(returnBuffer)+1 ))) | 
|  | strcpy( lpData->lpszCommandLine, returnBuffer ); | 
|  | } | 
|  |  | 
|  | sizeOfReturnBuffer = 200; | 
|  |  | 
|  | if( RegQueryValueExA( lpData->This->dpl->hkCallbackKeyHack, cdSubKey, | 
|  | NULL, &returnType, (LPBYTE)returnBuffer, | 
|  | &sizeOfReturnBuffer ) != ERROR_SUCCESS ) | 
|  | { | 
|  | ERR( ": missing CurrentDirectory registry data member\n" ); | 
|  | } | 
|  | else | 
|  | { | 
|  | if ((lpData->lpszCurrentDirectory = HeapAlloc( GetProcessHeap(), 0, strlen(returnBuffer)+1 ))) | 
|  | strcpy( lpData->lpszCurrentDirectory, returnBuffer ); | 
|  | } | 
|  |  | 
|  | sizeOfReturnBuffer = 200; | 
|  |  | 
|  | if( RegQueryValueExA( lpData->This->dpl->hkCallbackKeyHack, fileSubKey, | 
|  | NULL, &returnType, (LPBYTE)returnBuffer, | 
|  | &sizeOfReturnBuffer ) != ERROR_SUCCESS ) | 
|  | { | 
|  | ERR( ": missing File registry data member\n" ); | 
|  | } | 
|  | else | 
|  | { | 
|  | if ((lpData->lpszFileName = HeapAlloc( GetProcessHeap(), 0, strlen(returnBuffer)+1 ))) | 
|  | strcpy( lpData->lpszFileName, returnBuffer ); | 
|  | } | 
|  |  | 
|  | sizeOfReturnBuffer = 200; | 
|  |  | 
|  | if( RegQueryValueExA( lpData->This->dpl->hkCallbackKeyHack, pathSubKey, | 
|  | NULL, &returnType, (LPBYTE)returnBuffer, | 
|  | &sizeOfReturnBuffer ) != ERROR_SUCCESS ) | 
|  | { | 
|  | ERR( ": missing Path registry data member\n" ); | 
|  | } | 
|  | else | 
|  | { | 
|  | if ((lpData->lpszPath = HeapAlloc( GetProcessHeap(), 0, strlen(returnBuffer)+1 ))) | 
|  | strcpy( lpData->lpszPath, returnBuffer ); | 
|  | } | 
|  |  | 
|  | return FALSE; /* No need to keep going as we found what we wanted */ | 
|  | } | 
|  |  | 
|  | return TRUE; /* Keep enumerating, haven't found the application yet */ | 
|  | } | 
|  |  | 
|  | static BOOL DPL_CreateAndSetLobbyHandles( DWORD dwDestProcessId, HANDLE hDestProcess, | 
|  | LPHANDLE lphStart, LPHANDLE lphDeath, | 
|  | LPHANDLE lphRead ) | 
|  | { | 
|  | /* These are the handles for the created process */ | 
|  | HANDLE hAppStart = 0, hAppDeath = 0, hAppRead  = 0; | 
|  | SECURITY_ATTRIBUTES s_attrib; | 
|  |  | 
|  | s_attrib.nLength              = sizeof( s_attrib ); | 
|  | s_attrib.lpSecurityDescriptor = NULL; | 
|  | s_attrib.bInheritHandle       = TRUE; | 
|  |  | 
|  | *lphStart = CreateEventW( &s_attrib, TRUE, FALSE, NULL ); | 
|  | *lphDeath = CreateEventW( &s_attrib, TRUE, FALSE, NULL ); | 
|  | *lphRead  = CreateEventW( &s_attrib, TRUE, FALSE, NULL ); | 
|  |  | 
|  | if( ( !DuplicateHandle( GetCurrentProcess(), *lphStart, | 
|  | hDestProcess, &hAppStart, | 
|  | 0, FALSE, DUPLICATE_SAME_ACCESS ) ) || | 
|  | ( !DuplicateHandle( GetCurrentProcess(), *lphDeath, | 
|  | hDestProcess, &hAppDeath, | 
|  | 0, FALSE, DUPLICATE_SAME_ACCESS ) ) || | 
|  | ( !DuplicateHandle( GetCurrentProcess(), *lphRead, | 
|  | hDestProcess, &hAppRead, | 
|  | 0, FALSE, DUPLICATE_SAME_ACCESS ) ) | 
|  | ) | 
|  | { | 
|  | if (*lphStart) { CloseHandle(*lphStart); *lphStart = 0; } | 
|  | if (*lphDeath) { CloseHandle(*lphDeath); *lphDeath = 0; } | 
|  | if (*lphRead)  { CloseHandle(*lphRead);  *lphRead  = 0; } | 
|  | /* FIXME: Handle leak... */ | 
|  | ERR( "Unable to dup handles\n" ); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | if( !DPLAYX_SetLobbyHandles( dwDestProcessId, | 
|  | hAppStart, hAppDeath, hAppRead ) ) | 
|  | { | 
|  | /* FIXME: Handle leak... */ | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  |  | 
|  | /******************************************************************** | 
|  | * | 
|  | * Starts an application and passes to it all the information to | 
|  | * connect to a session. | 
|  | * | 
|  | */ | 
|  | static HRESULT WINAPI IDirectPlayLobbyAImpl_RunApplication | 
|  | ( LPDIRECTPLAYLOBBYA iface, | 
|  | DWORD dwFlags, | 
|  | LPDWORD lpdwAppID, | 
|  | LPDPLCONNECTION lpConn, | 
|  | HANDLE hReceiveEvent ) | 
|  | { | 
|  | IDirectPlayLobbyAImpl *This = (IDirectPlayLobbyAImpl *)iface; | 
|  | HRESULT hr; | 
|  | RunApplicationEnumStruct enumData; | 
|  | char temp[200]; | 
|  | STARTUPINFOA startupInfo; | 
|  | PROCESS_INFORMATION newProcessInfo; | 
|  | LPSTR appName; | 
|  | DWORD dwSuspendCount; | 
|  | HANDLE hStart, hDeath, hSettingRead; | 
|  |  | 
|  | TRACE( "(%p)->(0x%08x,%p,%p,%p)\n", | 
|  | This, dwFlags, lpdwAppID, lpConn, hReceiveEvent ); | 
|  |  | 
|  | if( dwFlags != 0 ) | 
|  | { | 
|  | return DPERR_INVALIDPARAMS; | 
|  | } | 
|  |  | 
|  | if( DPLAYX_AnyLobbiesWaitingForConnSettings() ) | 
|  | { | 
|  | FIXME( "Waiting lobby not being handled correctly\n" ); | 
|  | } | 
|  |  | 
|  | EnterCriticalSection( &This->unk->DPL_lock ); | 
|  |  | 
|  | ZeroMemory( &enumData, sizeof( enumData ) ); | 
|  | enumData.This    = This; | 
|  | enumData.appGUID = lpConn->lpSessionDesc->guidApplication; | 
|  |  | 
|  | /* Our callback function will fill up the enumData structure with all the information | 
|  | required to start a new process */ | 
|  | IDirectPlayLobby_EnumLocalApplications( iface, RunApplicationA_EnumLocalApplications, | 
|  | (&enumData), 0 ); | 
|  |  | 
|  | /* First the application name */ | 
|  | strcpy( temp, enumData.lpszPath ); | 
|  | strcat( temp, "\\" ); | 
|  | strcat( temp, enumData.lpszFileName ); | 
|  | HeapFree( GetProcessHeap(), 0, enumData.lpszPath ); | 
|  | HeapFree( GetProcessHeap(), 0, enumData.lpszFileName ); | 
|  | if ((appName = HeapAlloc( GetProcessHeap(), 0, strlen(temp)+1 ))) strcpy( appName, temp ); | 
|  |  | 
|  | /* Now the command line */ | 
|  | strcat( temp, " " ); | 
|  | strcat( temp, enumData.lpszCommandLine ); | 
|  | HeapFree( GetProcessHeap(), 0, enumData.lpszCommandLine ); | 
|  | if ((enumData.lpszCommandLine = HeapAlloc( GetProcessHeap(), 0, strlen(temp)+1 ))) | 
|  | strcpy( enumData.lpszCommandLine, temp ); | 
|  |  | 
|  | ZeroMemory( &startupInfo, sizeof( startupInfo ) ); | 
|  | startupInfo.cb = sizeof( startupInfo ); | 
|  | /* FIXME: Should any fields be filled in? */ | 
|  |  | 
|  | ZeroMemory( &newProcessInfo, sizeof( newProcessInfo ) ); | 
|  |  | 
|  | if( !CreateProcessA( appName, | 
|  | enumData.lpszCommandLine, | 
|  | NULL, | 
|  | NULL, | 
|  | FALSE, | 
|  | CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_CONSOLE | CREATE_SUSPENDED, /* Creation Flags */ | 
|  | NULL, | 
|  | enumData.lpszCurrentDirectory, | 
|  | &startupInfo, | 
|  | &newProcessInfo | 
|  | ) | 
|  | ) | 
|  | { | 
|  | ERR( "Failed to create process for app %s\n", appName ); | 
|  |  | 
|  | HeapFree( GetProcessHeap(), 0, appName ); | 
|  | HeapFree( GetProcessHeap(), 0, enumData.lpszCommandLine ); | 
|  | HeapFree( GetProcessHeap(), 0, enumData.lpszCurrentDirectory ); | 
|  |  | 
|  | LeaveCriticalSection( &This->unk->DPL_lock ); | 
|  | return DPERR_CANTCREATEPROCESS; | 
|  | } | 
|  |  | 
|  | HeapFree( GetProcessHeap(), 0, appName ); | 
|  | HeapFree( GetProcessHeap(), 0, enumData.lpszCommandLine ); | 
|  | HeapFree( GetProcessHeap(), 0, enumData.lpszCurrentDirectory ); | 
|  |  | 
|  | /* Reserve this global application id! */ | 
|  | if( !DPLAYX_CreateLobbyApplication( newProcessInfo.dwProcessId ) ) | 
|  | { | 
|  | ERR( "Unable to create global application data for 0x%08x\n", | 
|  | newProcessInfo.dwProcessId ); | 
|  | } | 
|  |  | 
|  | hr = IDirectPlayLobby_SetConnectionSettings( iface, 0, newProcessInfo.dwProcessId, lpConn ); | 
|  |  | 
|  | if( hr != DP_OK ) | 
|  | { | 
|  | ERR( "SetConnectionSettings failure %s\n", DPLAYX_HresultToString( hr ) ); | 
|  | LeaveCriticalSection( &This->unk->DPL_lock ); | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | /* Setup the handles for application notification */ | 
|  | DPL_CreateAndSetLobbyHandles( newProcessInfo.dwProcessId, | 
|  | newProcessInfo.hProcess, | 
|  | &hStart, &hDeath, &hSettingRead ); | 
|  |  | 
|  | /* Setup the message thread ID */ | 
|  | This->dpl->dwMsgThread = | 
|  | CreateLobbyMessageReceptionThread( hReceiveEvent, hStart, hDeath, hSettingRead ); | 
|  |  | 
|  | DPLAYX_SetLobbyMsgThreadId( newProcessInfo.dwProcessId, This->dpl->dwMsgThread ); | 
|  |  | 
|  | LeaveCriticalSection( &This->unk->DPL_lock ); | 
|  |  | 
|  | /* Everything seems to have been set correctly, update the dwAppID */ | 
|  | *lpdwAppID = newProcessInfo.dwProcessId; | 
|  |  | 
|  | /* Unsuspend the process - should return the prev suspension count */ | 
|  | if( ( dwSuspendCount = ResumeThread( newProcessInfo.hThread ) ) != 1 ) | 
|  | { | 
|  | ERR( "ResumeThread failed with 0x%08x\n", dwSuspendCount ); | 
|  | } | 
|  |  | 
|  | return DP_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IDirectPlayLobbyWImpl_RunApplication | 
|  | ( LPDIRECTPLAYLOBBY iface, | 
|  | DWORD dwFlags, | 
|  | LPDWORD lpdwAppID, | 
|  | LPDPLCONNECTION lpConn, | 
|  | HANDLE hReceiveEvent ) | 
|  | { | 
|  | IDirectPlayLobbyWImpl *This = (IDirectPlayLobbyWImpl *)iface; | 
|  | FIXME( "(%p)->(0x%08x,%p,%p,%p):stub\n", This, dwFlags, lpdwAppID, lpConn, hReceiveEvent ); | 
|  | return DPERR_OUTOFMEMORY; | 
|  | } | 
|  |  | 
|  | /******************************************************************** | 
|  | * | 
|  | * Sends a message between the application and the lobby client. | 
|  | * All messages are queued until received. | 
|  | * | 
|  | */ | 
|  | static HRESULT WINAPI IDirectPlayLobbyAImpl_SendLobbyMessage | 
|  | ( LPDIRECTPLAYLOBBYA iface, | 
|  | DWORD dwFlags, | 
|  | DWORD dwAppID, | 
|  | LPVOID lpData, | 
|  | DWORD dwDataSize ) | 
|  | { | 
|  | FIXME(":stub\n"); | 
|  | return DPERR_OUTOFMEMORY; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IDirectPlayLobbyWImpl_SendLobbyMessage | 
|  | ( LPDIRECTPLAYLOBBY iface, | 
|  | DWORD dwFlags, | 
|  | DWORD dwAppID, | 
|  | LPVOID lpData, | 
|  | DWORD dwDataSize ) | 
|  | { | 
|  | FIXME(":stub\n"); | 
|  | return DPERR_OUTOFMEMORY; | 
|  | } | 
|  |  | 
|  | /******************************************************************** | 
|  | * | 
|  | * Modifies the DPLCONNECTION structure to contain all information | 
|  | * needed to start and connect an application. | 
|  | * | 
|  | */ | 
|  | static HRESULT WINAPI IDirectPlayLobbyWImpl_SetConnectionSettings | 
|  | ( LPDIRECTPLAYLOBBY iface, | 
|  | DWORD dwFlags, | 
|  | DWORD dwAppID, | 
|  | LPDPLCONNECTION lpConn ) | 
|  | { | 
|  | IDirectPlayLobbyWImpl *This = (IDirectPlayLobbyWImpl *)iface; | 
|  | HRESULT hr; | 
|  |  | 
|  | TRACE("(%p)->(0x%08x,0x%08x,%p)\n", This, dwFlags, dwAppID, lpConn ); | 
|  |  | 
|  | EnterCriticalSection( &This->unk->DPL_lock ); | 
|  |  | 
|  | hr = DPLAYX_SetConnectionSettingsW( dwFlags, dwAppID, lpConn ); | 
|  |  | 
|  | /* FIXME: Don't think that this is supposed to fail, but the documentation | 
|  | is somewhat sketchy. I'll try creating a lobby application | 
|  | for this... */ | 
|  | if( hr == DPERR_NOTLOBBIED ) | 
|  | { | 
|  | FIXME( "Unlobbied app setting connections. Is this correct behavior?\n" ); | 
|  | if( dwAppID == 0 ) | 
|  | { | 
|  | dwAppID = GetCurrentProcessId(); | 
|  | } | 
|  | DPLAYX_CreateLobbyApplication( dwAppID ); | 
|  | hr = DPLAYX_SetConnectionSettingsW( dwFlags, dwAppID, lpConn ); | 
|  | } | 
|  |  | 
|  | LeaveCriticalSection( &This->unk->DPL_lock ); | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IDirectPlayLobbyAImpl_SetConnectionSettings | 
|  | ( LPDIRECTPLAYLOBBYA iface, | 
|  | DWORD dwFlags, | 
|  | DWORD dwAppID, | 
|  | LPDPLCONNECTION lpConn ) | 
|  | { | 
|  | IDirectPlayLobbyAImpl *This = (IDirectPlayLobbyAImpl *)iface; | 
|  | HRESULT hr; | 
|  |  | 
|  | TRACE("(%p)->(0x%08x,0x%08x,%p)\n", This, dwFlags, dwAppID, lpConn ); | 
|  |  | 
|  | EnterCriticalSection( &This->unk->DPL_lock ); | 
|  |  | 
|  | hr = DPLAYX_SetConnectionSettingsA( dwFlags, dwAppID, lpConn ); | 
|  |  | 
|  | /* FIXME: Don't think that this is supposed to fail, but the documentation | 
|  | is somewhat sketchy. I'll try creating a lobby application | 
|  | for this... */ | 
|  | if( hr == DPERR_NOTLOBBIED ) | 
|  | { | 
|  | FIXME( "Unlobbied app setting connections. Is this correct behavior?\n" ); | 
|  | dwAppID = GetCurrentProcessId(); | 
|  | DPLAYX_CreateLobbyApplication( dwAppID ); | 
|  | hr = DPLAYX_SetConnectionSettingsA( dwFlags, dwAppID, lpConn ); | 
|  | } | 
|  |  | 
|  | LeaveCriticalSection( &This->unk->DPL_lock ); | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | /******************************************************************** | 
|  | * | 
|  | * Registers an event that will be set when a lobby message is received. | 
|  | * | 
|  | */ | 
|  | static HRESULT WINAPI IDirectPlayLobbyAImpl_SetLobbyMessageEvent | 
|  | ( LPDIRECTPLAYLOBBYA iface, | 
|  | DWORD dwFlags, | 
|  | DWORD dwAppID, | 
|  | HANDLE hReceiveEvent ) | 
|  | { | 
|  | FIXME(":stub\n"); | 
|  | return DPERR_OUTOFMEMORY; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IDirectPlayLobbyWImpl_SetLobbyMessageEvent | 
|  | ( LPDIRECTPLAYLOBBY iface, | 
|  | DWORD dwFlags, | 
|  | DWORD dwAppID, | 
|  | HANDLE hReceiveEvent ) | 
|  | { | 
|  | FIXME(":stub\n"); | 
|  | return DPERR_OUTOFMEMORY; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* DPL 2 methods */ | 
|  | static HRESULT WINAPI IDirectPlayLobby2WImpl_CreateCompoundAddress | 
|  | ( LPDIRECTPLAYLOBBY2 iface, | 
|  | LPCDPCOMPOUNDADDRESSELEMENT lpElements, | 
|  | DWORD dwElementCount, | 
|  | LPVOID lpAddress, | 
|  | LPDWORD lpdwAddressSize ) | 
|  | { | 
|  | return DPL_CreateCompoundAddress( lpElements, dwElementCount, lpAddress, lpdwAddressSize, FALSE ); | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IDirectPlayLobby2AImpl_CreateCompoundAddress | 
|  | ( LPDIRECTPLAYLOBBY2A iface, | 
|  | LPCDPCOMPOUNDADDRESSELEMENT lpElements, | 
|  | DWORD dwElementCount, | 
|  | LPVOID lpAddress, | 
|  | LPDWORD lpdwAddressSize ) | 
|  | { | 
|  | return DPL_CreateCompoundAddress( lpElements, dwElementCount, lpAddress, lpdwAddressSize, TRUE ); | 
|  | } | 
|  |  | 
|  | HRESULT DPL_CreateCompoundAddress | 
|  | ( LPCDPCOMPOUNDADDRESSELEMENT lpElements, | 
|  | DWORD dwElementCount, | 
|  | LPVOID lpAddress, | 
|  | LPDWORD lpdwAddressSize, | 
|  | BOOL bAnsiInterface ) | 
|  | { | 
|  | DWORD dwSizeRequired = 0; | 
|  | DWORD dwElements; | 
|  | LPCDPCOMPOUNDADDRESSELEMENT lpOrigElements = lpElements; | 
|  |  | 
|  | TRACE("(%p,0x%08x,%p,%p)\n", lpElements, dwElementCount, lpAddress, lpdwAddressSize ); | 
|  |  | 
|  | /* Parameter check */ | 
|  | if( ( lpElements == NULL ) || | 
|  | ( dwElementCount == 0 )   /* FIXME: Not sure if this is a failure case */ | 
|  | ) | 
|  | { | 
|  | return DPERR_INVALIDPARAMS; | 
|  | } | 
|  |  | 
|  | /* Add the total size chunk */ | 
|  | dwSizeRequired += sizeof( DPADDRESS ) + sizeof( DWORD ); | 
|  |  | 
|  | /* Calculate the size of the buffer required */ | 
|  | for ( dwElements = dwElementCount; dwElements > 0; --dwElements, ++lpElements ) | 
|  | { | 
|  | if ( ( IsEqualGUID( &lpElements->guidDataType, &DPAID_ServiceProvider ) ) || | 
|  | ( IsEqualGUID( &lpElements->guidDataType, &DPAID_LobbyProvider ) ) | 
|  | ) | 
|  | { | 
|  | dwSizeRequired += sizeof( DPADDRESS ) + sizeof( GUID ); | 
|  | } | 
|  | else if ( ( IsEqualGUID( &lpElements->guidDataType, &DPAID_Phone ) ) || | 
|  | ( IsEqualGUID( &lpElements->guidDataType, &DPAID_Modem ) ) || | 
|  | ( IsEqualGUID( &lpElements->guidDataType, &DPAID_INet ) ) | 
|  | ) | 
|  | { | 
|  | if( !bAnsiInterface ) | 
|  | { | 
|  | ERR( "Ansi GUIDs used for unicode interface\n" ); | 
|  | return DPERR_INVALIDFLAGS; | 
|  | } | 
|  |  | 
|  | dwSizeRequired += sizeof( DPADDRESS ) + lpElements->dwDataSize; | 
|  | } | 
|  | else if ( ( IsEqualGUID( &lpElements->guidDataType, &DPAID_PhoneW ) ) || | 
|  | ( IsEqualGUID( &lpElements->guidDataType, &DPAID_ModemW ) ) || | 
|  | ( IsEqualGUID( &lpElements->guidDataType, &DPAID_INetW ) ) | 
|  | ) | 
|  | { | 
|  | if( bAnsiInterface ) | 
|  | { | 
|  | ERR( "Unicode GUIDs used for ansi interface\n" ); | 
|  | return DPERR_INVALIDFLAGS; | 
|  | } | 
|  |  | 
|  | FIXME( "Right size for unicode interface?\n" ); | 
|  | dwSizeRequired += sizeof( DPADDRESS ) + lpElements->dwDataSize * sizeof( WCHAR ); | 
|  | } | 
|  | else if ( IsEqualGUID( &lpElements->guidDataType, &DPAID_INetPort ) ) | 
|  | { | 
|  | dwSizeRequired += sizeof( DPADDRESS ) + sizeof( WORD ); | 
|  | } | 
|  | else if ( IsEqualGUID( &lpElements->guidDataType, &DPAID_ComPort ) ) | 
|  | { | 
|  | FIXME( "Right size for unicode interface?\n" ); | 
|  | dwSizeRequired += sizeof( DPADDRESS ) + sizeof( DPCOMPORTADDRESS ); /* FIXME: Right size? */ | 
|  | } | 
|  | else | 
|  | { | 
|  | ERR( "Unknown GUID %s\n", debugstr_guid(&lpElements->guidDataType) ); | 
|  | return DPERR_INVALIDFLAGS; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* The user wants to know how big a buffer to allocate for us */ | 
|  | if( ( lpAddress == NULL ) || | 
|  | ( *lpdwAddressSize < dwSizeRequired ) | 
|  | ) | 
|  | { | 
|  | *lpdwAddressSize = dwSizeRequired; | 
|  | return DPERR_BUFFERTOOSMALL; | 
|  | } | 
|  |  | 
|  | /* Add the total size chunk */ | 
|  | { | 
|  | LPDPADDRESS lpdpAddress = lpAddress; | 
|  |  | 
|  | lpdpAddress->guidDataType = DPAID_TotalSize; | 
|  | lpdpAddress->dwDataSize = sizeof( DWORD ); | 
|  | lpAddress = (char *) lpAddress + sizeof( DPADDRESS ); | 
|  |  | 
|  | *(LPDWORD)lpAddress = dwSizeRequired; | 
|  | lpAddress = (char *) lpAddress + sizeof( DWORD ); | 
|  | } | 
|  |  | 
|  | /* Calculate the size of the buffer required */ | 
|  | for( dwElements = dwElementCount, lpElements = lpOrigElements; | 
|  | dwElements > 0; | 
|  | --dwElements, ++lpElements ) | 
|  | { | 
|  | if ( ( IsEqualGUID( &lpElements->guidDataType, &DPAID_ServiceProvider ) ) || | 
|  | ( IsEqualGUID( &lpElements->guidDataType, &DPAID_LobbyProvider ) ) | 
|  | ) | 
|  | { | 
|  | LPDPADDRESS lpdpAddress = lpAddress; | 
|  |  | 
|  | lpdpAddress->guidDataType = lpElements->guidDataType; | 
|  | lpdpAddress->dwDataSize = sizeof( GUID ); | 
|  | lpAddress = (char *) lpAddress + sizeof( DPADDRESS ); | 
|  |  | 
|  | CopyMemory( lpAddress, lpElements->lpData, sizeof( GUID ) ); | 
|  | lpAddress = (char *) lpAddress + sizeof( GUID ); | 
|  | } | 
|  | else if ( ( IsEqualGUID( &lpElements->guidDataType, &DPAID_Phone ) ) || | 
|  | ( IsEqualGUID( &lpElements->guidDataType, &DPAID_Modem ) ) || | 
|  | ( IsEqualGUID( &lpElements->guidDataType, &DPAID_INet ) ) | 
|  | ) | 
|  | { | 
|  | LPDPADDRESS lpdpAddress = lpAddress; | 
|  |  | 
|  | lpdpAddress->guidDataType = lpElements->guidDataType; | 
|  | lpdpAddress->dwDataSize = lpElements->dwDataSize; | 
|  | lpAddress = (char *) lpAddress + sizeof( DPADDRESS ); | 
|  |  | 
|  | lstrcpynA( lpAddress, lpElements->lpData, lpElements->dwDataSize ); | 
|  | lpAddress = (char *) lpAddress + lpElements->dwDataSize; | 
|  | } | 
|  | else if ( ( IsEqualGUID( &lpElements->guidDataType, &DPAID_PhoneW ) ) || | 
|  | ( IsEqualGUID( &lpElements->guidDataType, &DPAID_ModemW ) ) || | 
|  | ( IsEqualGUID( &lpElements->guidDataType, &DPAID_INetW ) ) | 
|  | ) | 
|  | { | 
|  | LPDPADDRESS lpdpAddress = lpAddress; | 
|  |  | 
|  | lpdpAddress->guidDataType = lpElements->guidDataType; | 
|  | lpdpAddress->dwDataSize = lpElements->dwDataSize; | 
|  | lpAddress = (char *) lpAddress + sizeof( DPADDRESS ); | 
|  |  | 
|  | lstrcpynW( lpAddress, lpElements->lpData, lpElements->dwDataSize ); | 
|  | lpAddress = (char *) lpAddress + lpElements->dwDataSize * sizeof( WCHAR ); | 
|  | } | 
|  | else if ( IsEqualGUID( &lpElements->guidDataType, &DPAID_INetPort ) ) | 
|  | { | 
|  | LPDPADDRESS lpdpAddress = lpAddress; | 
|  |  | 
|  | lpdpAddress->guidDataType = lpElements->guidDataType; | 
|  | lpdpAddress->dwDataSize = lpElements->dwDataSize; | 
|  | lpAddress = (char *) lpAddress + sizeof( DPADDRESS ); | 
|  |  | 
|  | *((LPWORD)lpAddress) = *((LPWORD)lpElements->lpData); | 
|  | lpAddress = (char *) lpAddress + sizeof( WORD ); | 
|  | } | 
|  | else if ( IsEqualGUID( &lpElements->guidDataType, &DPAID_ComPort ) ) | 
|  | { | 
|  | LPDPADDRESS lpdpAddress = lpAddress; | 
|  |  | 
|  | lpdpAddress->guidDataType = lpElements->guidDataType; | 
|  | lpdpAddress->dwDataSize = lpElements->dwDataSize; | 
|  | lpAddress = (char *) lpAddress + sizeof( DPADDRESS ); | 
|  |  | 
|  | CopyMemory( lpAddress, lpElements->lpData, sizeof( DPADDRESS ) ); | 
|  | lpAddress = (char *) lpAddress + sizeof( DPADDRESS ); | 
|  | } | 
|  | } | 
|  |  | 
|  | return DP_OK; | 
|  | } | 
|  |  | 
|  | /* DPL 3 methods */ | 
|  |  | 
|  | static HRESULT WINAPI IDirectPlayLobby3WImpl_ConnectEx | 
|  | ( LPDIRECTPLAYLOBBY3 iface, DWORD dwFlags, REFIID riid, | 
|  | LPVOID* lplpDP, IUnknown* pUnk ) | 
|  | { | 
|  | IDirectPlayLobbyAImpl *This = (IDirectPlayLobbyAImpl *)iface ; | 
|  | return DPL_ConnectEx( This, dwFlags, riid, lplpDP, pUnk ); | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IDirectPlayLobby3AImpl_ConnectEx | 
|  | ( LPDIRECTPLAYLOBBY3A iface, DWORD dwFlags, REFIID riid, | 
|  | LPVOID* lplpDP, IUnknown* pUnk ) | 
|  | { | 
|  | IDirectPlayLobbyAImpl *This = (IDirectPlayLobbyAImpl *)iface ; | 
|  | return DPL_ConnectEx( This, dwFlags, riid, lplpDP, pUnk ); | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IDirectPlayLobby3WImpl_RegisterApplication | 
|  | ( LPDIRECTPLAYLOBBY3 iface, DWORD dwFlags, LPDPAPPLICATIONDESC lpAppDesc ) | 
|  | { | 
|  | FIXME(":stub\n"); | 
|  | return DP_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IDirectPlayLobby3AImpl_RegisterApplication | 
|  | ( LPDIRECTPLAYLOBBY3A iface, DWORD dwFlags, LPDPAPPLICATIONDESC lpAppDesc ) | 
|  | { | 
|  | FIXME(":stub\n"); | 
|  | return DP_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IDirectPlayLobby3WImpl_UnregisterApplication | 
|  | ( LPDIRECTPLAYLOBBY3 iface, DWORD dwFlags, REFGUID lpAppDesc ) | 
|  | { | 
|  | FIXME(":stub\n"); | 
|  | return DP_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IDirectPlayLobby3AImpl_UnregisterApplication | 
|  | ( LPDIRECTPLAYLOBBY3A iface, DWORD dwFlags, REFGUID lpAppDesc ) | 
|  | { | 
|  | FIXME(":stub\n"); | 
|  | return DP_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IDirectPlayLobby3WImpl_WaitForConnectionSettings | 
|  | ( LPDIRECTPLAYLOBBY3 iface, DWORD dwFlags ) | 
|  | { | 
|  | HRESULT hr         = DP_OK; | 
|  | BOOL    bStartWait = (dwFlags & DPLWAIT_CANCEL) ? FALSE : TRUE; | 
|  |  | 
|  | TRACE( "(%p)->(0x%08x)\n", iface, dwFlags ); | 
|  |  | 
|  | if( DPLAYX_WaitForConnectionSettings( bStartWait ) ) | 
|  | { | 
|  | /* FIXME: What is the correct error return code? */ | 
|  | hr = DPERR_NOTLOBBIED; | 
|  | } | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IDirectPlayLobby3AImpl_WaitForConnectionSettings | 
|  | ( LPDIRECTPLAYLOBBY3A iface, DWORD dwFlags ) | 
|  | { | 
|  | HRESULT hr         = DP_OK; | 
|  | BOOL    bStartWait = (dwFlags & DPLWAIT_CANCEL) ? FALSE : TRUE; | 
|  |  | 
|  | TRACE( "(%p)->(0x%08x)\n", iface, dwFlags ); | 
|  |  | 
|  | if( DPLAYX_WaitForConnectionSettings( bStartWait ) ) | 
|  | { | 
|  | /* FIXME: What is the correct error return code? */ | 
|  | hr = DPERR_NOTLOBBIED; | 
|  | } | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Virtual Table definitions for DPL{1,2,3}{A,W} */ | 
|  |  | 
|  | /* Note: Hack so we can reuse the old functions without compiler warnings */ | 
|  | #if !defined(__STRICT_ANSI__) && defined(__GNUC__) | 
|  | # define XCAST(fun)     (typeof(directPlayLobbyAVT.fun)) | 
|  | #else | 
|  | # define XCAST(fun)     (void*) | 
|  | #endif | 
|  |  | 
|  | /* Direct Play Lobby 1 (ascii) Virtual Table for methods */ | 
|  | /* All lobby 1 methods are exactly the same except QueryInterface */ | 
|  | static const IDirectPlayLobbyVtbl directPlayLobbyAVT = | 
|  | { | 
|  |  | 
|  | XCAST(QueryInterface)DPL_QueryInterface, | 
|  | XCAST(AddRef)DPL_AddRef, | 
|  | XCAST(Release)DPL_Release, | 
|  |  | 
|  | IDirectPlayLobbyAImpl_Connect, | 
|  | IDirectPlayLobbyAImpl_CreateAddress, | 
|  | IDirectPlayLobbyAImpl_EnumAddress, | 
|  | IDirectPlayLobbyAImpl_EnumAddressTypes, | 
|  | IDirectPlayLobbyAImpl_EnumLocalApplications, | 
|  | IDirectPlayLobbyAImpl_GetConnectionSettings, | 
|  | IDirectPlayLobbyAImpl_ReceiveLobbyMessage, | 
|  | IDirectPlayLobbyAImpl_RunApplication, | 
|  | IDirectPlayLobbyAImpl_SendLobbyMessage, | 
|  | IDirectPlayLobbyAImpl_SetConnectionSettings, | 
|  | IDirectPlayLobbyAImpl_SetLobbyMessageEvent | 
|  | }; | 
|  | #undef XCAST | 
|  |  | 
|  |  | 
|  | /* Note: Hack so we can reuse the old functions without compiler warnings */ | 
|  | #if !defined(__STRICT_ANSI__) && defined(__GNUC__) | 
|  | # define XCAST(fun)     (typeof(directPlayLobbyWVT.fun)) | 
|  | #else | 
|  | # define XCAST(fun)     (void*) | 
|  | #endif | 
|  |  | 
|  | /* Direct Play Lobby 1 (unicode) Virtual Table for methods */ | 
|  | static const IDirectPlayLobbyVtbl directPlayLobbyWVT = | 
|  | { | 
|  |  | 
|  | XCAST(QueryInterface)DPL_QueryInterface, | 
|  | XCAST(AddRef)DPL_AddRef, | 
|  | XCAST(Release)DPL_Release, | 
|  |  | 
|  | IDirectPlayLobbyWImpl_Connect, | 
|  | IDirectPlayLobbyWImpl_CreateAddress, | 
|  | IDirectPlayLobbyWImpl_EnumAddress, | 
|  | IDirectPlayLobbyWImpl_EnumAddressTypes, | 
|  | IDirectPlayLobbyWImpl_EnumLocalApplications, | 
|  | IDirectPlayLobbyWImpl_GetConnectionSettings, | 
|  | IDirectPlayLobbyWImpl_ReceiveLobbyMessage, | 
|  | IDirectPlayLobbyWImpl_RunApplication, | 
|  | IDirectPlayLobbyWImpl_SendLobbyMessage, | 
|  | IDirectPlayLobbyWImpl_SetConnectionSettings, | 
|  | IDirectPlayLobbyWImpl_SetLobbyMessageEvent | 
|  | }; | 
|  | #undef XCAST | 
|  |  | 
|  | /* Note: Hack so we can reuse the old functions without compiler warnings */ | 
|  | #if !defined(__STRICT_ANSI__) && defined(__GNUC__) | 
|  | # define XCAST(fun)     (typeof(directPlayLobby2AVT.fun)) | 
|  | #else | 
|  | # define XCAST(fun)     (void*) | 
|  | #endif | 
|  |  | 
|  | /* Direct Play Lobby 2 (ascii) Virtual Table for methods */ | 
|  | static const IDirectPlayLobby2Vtbl directPlayLobby2AVT = | 
|  | { | 
|  |  | 
|  | XCAST(QueryInterface)DPL_QueryInterface, | 
|  | XCAST(AddRef)DPL_AddRef, | 
|  | XCAST(Release)DPL_Release, | 
|  |  | 
|  | XCAST(Connect)IDirectPlayLobbyAImpl_Connect, | 
|  | XCAST(CreateAddress)IDirectPlayLobbyAImpl_CreateAddress, | 
|  | XCAST(EnumAddress)IDirectPlayLobbyAImpl_EnumAddress, | 
|  | XCAST(EnumAddressTypes)IDirectPlayLobbyAImpl_EnumAddressTypes, | 
|  | XCAST(EnumLocalApplications)IDirectPlayLobbyAImpl_EnumLocalApplications, | 
|  | XCAST(GetConnectionSettings)IDirectPlayLobbyAImpl_GetConnectionSettings, | 
|  | XCAST(ReceiveLobbyMessage)IDirectPlayLobbyAImpl_ReceiveLobbyMessage, | 
|  | XCAST(RunApplication)IDirectPlayLobbyAImpl_RunApplication, | 
|  | XCAST(SendLobbyMessage)IDirectPlayLobbyAImpl_SendLobbyMessage, | 
|  | XCAST(SetConnectionSettings)IDirectPlayLobbyAImpl_SetConnectionSettings, | 
|  | XCAST(SetLobbyMessageEvent)IDirectPlayLobbyAImpl_SetLobbyMessageEvent, | 
|  |  | 
|  | IDirectPlayLobby2AImpl_CreateCompoundAddress | 
|  | }; | 
|  | #undef XCAST | 
|  |  | 
|  | /* Note: Hack so we can reuse the old functions without compiler warnings */ | 
|  | #if !defined(__STRICT_ANSI__) && defined(__GNUC__) | 
|  | # define XCAST(fun)     (typeof(directPlayLobby2WVT.fun)) | 
|  | #else | 
|  | # define XCAST(fun)     (void*) | 
|  | #endif | 
|  |  | 
|  | /* Direct Play Lobby 2 (unicode) Virtual Table for methods */ | 
|  | static const IDirectPlayLobby2Vtbl directPlayLobby2WVT = | 
|  | { | 
|  |  | 
|  | XCAST(QueryInterface)DPL_QueryInterface, | 
|  | XCAST(AddRef)DPL_AddRef, | 
|  | XCAST(Release)DPL_Release, | 
|  |  | 
|  | XCAST(Connect)IDirectPlayLobbyWImpl_Connect, | 
|  | XCAST(CreateAddress)IDirectPlayLobbyWImpl_CreateAddress, | 
|  | XCAST(EnumAddress)IDirectPlayLobbyWImpl_EnumAddress, | 
|  | XCAST(EnumAddressTypes)IDirectPlayLobbyWImpl_EnumAddressTypes, | 
|  | XCAST(EnumLocalApplications)IDirectPlayLobbyWImpl_EnumLocalApplications, | 
|  | XCAST(GetConnectionSettings)IDirectPlayLobbyWImpl_GetConnectionSettings, | 
|  | XCAST(ReceiveLobbyMessage)IDirectPlayLobbyWImpl_ReceiveLobbyMessage, | 
|  | XCAST(RunApplication)IDirectPlayLobbyWImpl_RunApplication, | 
|  | XCAST(SendLobbyMessage)IDirectPlayLobbyWImpl_SendLobbyMessage, | 
|  | XCAST(SetConnectionSettings)IDirectPlayLobbyWImpl_SetConnectionSettings, | 
|  | XCAST(SetLobbyMessageEvent)IDirectPlayLobbyWImpl_SetLobbyMessageEvent, | 
|  |  | 
|  | IDirectPlayLobby2WImpl_CreateCompoundAddress | 
|  | }; | 
|  | #undef XCAST | 
|  |  | 
|  | /* Direct Play Lobby 3 (ascii) Virtual Table for methods */ | 
|  |  | 
|  | /* Note: Hack so we can reuse the old functions without compiler warnings */ | 
|  | #if !defined(__STRICT_ANSI__) && defined(__GNUC__) | 
|  | # define XCAST(fun)     (typeof(directPlayLobby3AVT.fun)) | 
|  | #else | 
|  | # define XCAST(fun)     (void*) | 
|  | #endif | 
|  |  | 
|  | static const IDirectPlayLobby3Vtbl directPlayLobby3AVT = | 
|  | { | 
|  | XCAST(QueryInterface)DPL_QueryInterface, | 
|  | XCAST(AddRef)DPL_AddRef, | 
|  | XCAST(Release)DPL_Release, | 
|  |  | 
|  | XCAST(Connect)IDirectPlayLobbyAImpl_Connect, | 
|  | XCAST(CreateAddress)IDirectPlayLobbyAImpl_CreateAddress, | 
|  | XCAST(EnumAddress)IDirectPlayLobbyAImpl_EnumAddress, | 
|  | XCAST(EnumAddressTypes)IDirectPlayLobbyAImpl_EnumAddressTypes, | 
|  | XCAST(EnumLocalApplications)IDirectPlayLobbyAImpl_EnumLocalApplications, | 
|  | XCAST(GetConnectionSettings)IDirectPlayLobbyAImpl_GetConnectionSettings, | 
|  | XCAST(ReceiveLobbyMessage)IDirectPlayLobbyAImpl_ReceiveLobbyMessage, | 
|  | XCAST(RunApplication)IDirectPlayLobbyAImpl_RunApplication, | 
|  | XCAST(SendLobbyMessage)IDirectPlayLobbyAImpl_SendLobbyMessage, | 
|  | XCAST(SetConnectionSettings)IDirectPlayLobbyAImpl_SetConnectionSettings, | 
|  | XCAST(SetLobbyMessageEvent)IDirectPlayLobbyAImpl_SetLobbyMessageEvent, | 
|  |  | 
|  | XCAST(CreateCompoundAddress)IDirectPlayLobby2AImpl_CreateCompoundAddress, | 
|  |  | 
|  | IDirectPlayLobby3AImpl_ConnectEx, | 
|  | IDirectPlayLobby3AImpl_RegisterApplication, | 
|  | IDirectPlayLobby3AImpl_UnregisterApplication, | 
|  | IDirectPlayLobby3AImpl_WaitForConnectionSettings | 
|  | }; | 
|  | #undef XCAST | 
|  |  | 
|  | /* Direct Play Lobby 3 (unicode) Virtual Table for methods */ | 
|  |  | 
|  | /* Note: Hack so we can reuse the old functions without compiler warnings */ | 
|  | #if !defined(__STRICT_ANSI__) && defined(__GNUC__) | 
|  | # define XCAST(fun)     (typeof(directPlayLobby3WVT.fun)) | 
|  | #else | 
|  | # define XCAST(fun)     (void*) | 
|  | #endif | 
|  |  | 
|  | static const IDirectPlayLobby3Vtbl directPlayLobby3WVT = | 
|  | { | 
|  | XCAST(QueryInterface)DPL_QueryInterface, | 
|  | XCAST(AddRef)DPL_AddRef, | 
|  | XCAST(Release)DPL_Release, | 
|  |  | 
|  | XCAST(Connect)IDirectPlayLobbyWImpl_Connect, | 
|  | XCAST(CreateAddress)IDirectPlayLobbyWImpl_CreateAddress, | 
|  | XCAST(EnumAddress)IDirectPlayLobbyWImpl_EnumAddress, | 
|  | XCAST(EnumAddressTypes)IDirectPlayLobbyWImpl_EnumAddressTypes, | 
|  | XCAST(EnumLocalApplications)IDirectPlayLobbyWImpl_EnumLocalApplications, | 
|  | XCAST(GetConnectionSettings)IDirectPlayLobbyWImpl_GetConnectionSettings, | 
|  | XCAST(ReceiveLobbyMessage)IDirectPlayLobbyWImpl_ReceiveLobbyMessage, | 
|  | XCAST(RunApplication)IDirectPlayLobbyWImpl_RunApplication, | 
|  | XCAST(SendLobbyMessage)IDirectPlayLobbyWImpl_SendLobbyMessage, | 
|  | XCAST(SetConnectionSettings)IDirectPlayLobbyWImpl_SetConnectionSettings, | 
|  | XCAST(SetLobbyMessageEvent)IDirectPlayLobbyWImpl_SetLobbyMessageEvent, | 
|  |  | 
|  | XCAST(CreateCompoundAddress)IDirectPlayLobby2WImpl_CreateCompoundAddress, | 
|  |  | 
|  | IDirectPlayLobby3WImpl_ConnectEx, | 
|  | IDirectPlayLobby3WImpl_RegisterApplication, | 
|  | IDirectPlayLobby3WImpl_UnregisterApplication, | 
|  | IDirectPlayLobby3WImpl_WaitForConnectionSettings | 
|  | }; | 
|  | #undef XCAST | 
|  |  | 
|  |  | 
|  | /********************************************************* | 
|  | * | 
|  | * Direct Play Lobby Interface Implementation | 
|  | * | 
|  | *********************************************************/ | 
|  |  | 
|  | /*************************************************************************** | 
|  | *  DirectPlayLobbyCreateA   (DPLAYX.4) | 
|  | * | 
|  | */ | 
|  | HRESULT WINAPI DirectPlayLobbyCreateA( LPGUID lpGUIDDSP, | 
|  | LPDIRECTPLAYLOBBYA *lplpDPL, | 
|  | IUnknown *lpUnk, | 
|  | LPVOID lpData, | 
|  | DWORD dwDataSize ) | 
|  | { | 
|  | TRACE("lpGUIDDSP=%p lplpDPL=%p lpUnk=%p lpData=%p dwDataSize=%08x\n", | 
|  | lpGUIDDSP,lplpDPL,lpUnk,lpData,dwDataSize); | 
|  |  | 
|  | /* Parameter Check: lpGUIDSP, lpUnk & lpData must be NULL. dwDataSize must | 
|  | * equal 0. These fields are mostly for future expansion. | 
|  | */ | 
|  | if ( lpGUIDDSP || lpData || dwDataSize ) | 
|  | { | 
|  | *lplpDPL = NULL; | 
|  | return DPERR_INVALIDPARAMS; | 
|  | } | 
|  |  | 
|  | if( lpUnk ) | 
|  | { | 
|  | *lplpDPL = NULL; | 
|  | ERR("Bad parameters!\n" ); | 
|  | return CLASS_E_NOAGGREGATION; | 
|  | } | 
|  |  | 
|  | return DPL_CreateInterface( &IID_IDirectPlayLobbyA, (void**)lplpDPL ); | 
|  | } | 
|  |  | 
|  | /*************************************************************************** | 
|  | *  DirectPlayLobbyCreateW   (DPLAYX.5) | 
|  | * | 
|  | */ | 
|  | HRESULT WINAPI DirectPlayLobbyCreateW( LPGUID lpGUIDDSP, | 
|  | LPDIRECTPLAYLOBBY *lplpDPL, | 
|  | IUnknown *lpUnk, | 
|  | LPVOID lpData, | 
|  | DWORD dwDataSize ) | 
|  | { | 
|  | TRACE("lpGUIDDSP=%p lplpDPL=%p lpUnk=%p lpData=%p dwDataSize=%08x\n", | 
|  | lpGUIDDSP,lplpDPL,lpUnk,lpData,dwDataSize); | 
|  |  | 
|  | /* Parameter Check: lpGUIDSP, lpUnk & lpData must be NULL. dwDataSize must | 
|  | * equal 0. These fields are mostly for future expansion. | 
|  | */ | 
|  | if ( lpGUIDDSP || lpData || dwDataSize ) | 
|  | { | 
|  | *lplpDPL = NULL; | 
|  | ERR("Bad parameters!\n" ); | 
|  | return DPERR_INVALIDPARAMS; | 
|  | } | 
|  |  | 
|  | if( lpUnk ) | 
|  | { | 
|  | *lplpDPL = NULL; | 
|  | ERR("Bad parameters!\n" ); | 
|  | return CLASS_E_NOAGGREGATION; | 
|  | } | 
|  |  | 
|  | return DPL_CreateInterface( &IID_IDirectPlayLobby, (void**)lplpDPL ); | 
|  | } |