| /* 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 ); |
| } |