/* Direct Play 3 and Direct Play Lobby 2 Implementation * * Copyright 1998 - Peter Hunnisett * * * */ #include "interfaces.h" #include "heap.h" #include "winerror.h" #include "debug.h" #include "winnt.h" #include "winreg.h" #include "compobj.h" #include "dplay.h" #include "thread.h" #define IsEqualGUID(rguid1, rguid2) (!memcmp(rguid1, rguid2, sizeof(GUID))) #define IsEqualIID(riid1, riid2) IsEqualGUID(riid1, riid2) #define IsEqualCLSID(rclsid1, rclsid2) IsEqualGUID(rclsid1, rclsid2) struct IDirectPlayLobby { LPDIRECTPLAYLOBBY_VTABLE lpVtbl; ULONG ref; LPDPLCONNECTION lpSession; }; struct IDirectPlayLobby2 { LPDIRECTPLAYLOBBY2_VTABLE lpVtbl; ULONG ref; LPDPLCONNECTION lpSession; }; /* Forward declarations of virtual tables */ static DIRECTPLAYLOBBY_VTABLE directPlayLobbyAVT; static DIRECTPLAYLOBBY_VTABLE directPlayLobbyWVT; static DIRECTPLAYLOBBY2_VTABLE directPlayLobby2AVT; static DIRECTPLAYLOBBY2_VTABLE directPlayLobby2WVT; struct IDirectPlay2 { LPDIRECTPLAY2_VTABLE lpVtbl; ULONG ref; }; struct IDirectPlay3 { LPDIRECTPLAY3_VTABLE lpVtbl; ULONG ref; }; static DIRECTPLAY2_VTABLE directPlay2AVT; static DIRECTPLAY2_VTABLE directPlay2WVT; static DIRECTPLAY3_VTABLE directPlay3AVT; static DIRECTPLAY3_VTABLE directPlay3WVT; /* Routine to delete the entire DPLCONNECTION tree. Works for both unicode and ascii. */ void deleteDPConnection( LPDPLCONNECTION* ptrToDelete ) { /* This is most definitely wrong. We're not even keeping dwCurrentPlayers over this */ LPDPLCONNECTION toDelete = *ptrToDelete; FIXME( dplay, "incomplete.\n" ); if( !toDelete ) return; /* Clear out DPSESSIONDESC2 */ if( toDelete->lpSessionDesc ) { if( toDelete->lpSessionDesc->sess.lpszSessionName ) HeapFree( GetProcessHeap(), 0, toDelete->lpSessionDesc->sess.lpszSessionName ); if( toDelete->lpSessionDesc->pass.lpszPassword ) HeapFree( GetProcessHeap(), 0, toDelete->lpSessionDesc->pass.lpszPassword ); if( toDelete->lpSessionDesc ); HeapFree( GetProcessHeap(), 0, toDelete->lpSessionDesc ); } /* Clear out LPDPNAME */ if( toDelete->lpPlayerName ) { if( toDelete->lpPlayerName->psn.lpszShortName ) HeapFree( GetProcessHeap(), 0, toDelete->lpPlayerName->psn.lpszShortName ); if( toDelete->lpPlayerName->pln.lpszLongName ) HeapFree( GetProcessHeap(), 0, toDelete->lpPlayerName->pln.lpszLongName ); if( toDelete->lpPlayerName ) HeapFree( GetProcessHeap(), 0, toDelete->lpPlayerName ); } /* Clear out lpAddress. TO DO...Once we actually copy it. */ /* Clear out DPLCONNECTION */ HeapFree( GetProcessHeap(), 0, toDelete ); toDelete = NULL; } #if 0 /* Routine which copies and allocates all the store required for the DPLCONNECTION struct. */ void rebuildDPConnectionW( LPDPLCONNECTION dest, LPDPLCONNECTION src ) { /* Need to delete everything that already exists first */ FIXME( dplay, "function is incomplete.\n" ); if( !src ) { /* Nothing to copy...hmmm...*/ ERR( dplay, "nothing to copy\n" ); return; } /* Copy DPLCONNECTION struct. If dest isn't NULL then we have a DPLCONNECTION struct but that's it */ if( dest == NULL ) { dest = HeapAlloc( GetProcessHeap(), 0, sizeof( *src ) ); } memcpy( dest, src, sizeof( *src ) ); /* Copy LPDPSESSIONDESC2 struct */ if( src->lpSessionDesc ) { dest->lpSessionDesc = HeapAlloc( GetProcessHeap(), 0, sizeof( *(src->lpSessionDesc) ) ); memcpy( dest->lpSessionDesc, src->lpSessionDesc, sizeof( *(src->lpSessionDesc) ) ); if( src->lpSessionDesc ) { /* Hmmm...do we have to assume the system heap? */ dest->lpSessionDesc->sess.lpszSessionName = HEAP_strdupW( GetProcessHeap(), 0, src->lpSessionDesc->sess.lpszSessionName ); } if( src->lpSessionDesc->pass.lpszPassword ) { dest->lpSessionDesc->pass.lpszPassword = HEAP_strdupW( GetProcessHeap(), 0, src->lpSessionDesc->pass.lpszPassword ); } dest->lpSessionDesc->dwReserved1 = src->lpSessionDesc->dwReserved2 = 0; } /* Copy DPNAME struct */ if( src->lpPlayerName ) { dest->lpPlayerName = HeapAlloc( GetProcessHeap(), 0, sizeof( *(src->lpPlayerName) ) ); memcpy( dest->lpPlayerName, src->lpPlayerName, sizeof( *(src->lpPlayerName) ) ); if( src->lpPlayerName->psn.lpszShortName ) { dest->lpPlayerName->psn.lpszShortName = HEAP_strdupW( GetProcessHeap(), 0, src->lpPlayerName->psn.lpszShortName ); } if( src->lpPlayerName->pln.lpszLongName ) { dest->lpPlayerName->pln.lpszLongName = HEAP_strdupW( GetProcessHeap(), 0, src->lpPlayerName->pln.lpszLongName ); } } /* Copy Address of Service Provider -TBD */ if( src->lpAddress ) { /* What do we do here? */ } } #endif /* Routine called when starting up the server thread */ DWORD DPLobby_Spawn_Server( LPVOID startData ) { DPSESSIONDESC2* lpSession = (DPSESSIONDESC2*) startData; DWORD sessionDwFlags = lpSession->dwFlags; TRACE( dplay, "spawing thread for lpConn=%p dwFlags=%08lx\n", lpSession, sessionDwFlags ); FIXME( dplay, "thread needs something to do\n" ); /*for(;;)*/ { /* Check out the connection flags to determine what to do. Ensure we have no leftover bits in this structure */ if( sessionDwFlags & DPSESSION_CLIENTSERVER ) { /* This indicates that the application which is requesting the creation * of this session is going to be the server (application/player) */ if( sessionDwFlags & DPSESSION_SECURESERVER ) { sessionDwFlags &= ~DPSESSION_SECURESERVER; } sessionDwFlags &= ~DPSESSION_CLIENTSERVER; } if( sessionDwFlags & DPSESSION_JOINDISABLED ) { sessionDwFlags &= ~DPSESSION_JOINDISABLED; } if( sessionDwFlags & DPSESSION_KEEPALIVE ) { sessionDwFlags &= ~DPSESSION_KEEPALIVE; } if( sessionDwFlags & DPSESSION_MIGRATEHOST ) { sessionDwFlags &= ~DPSESSION_MIGRATEHOST; } if( sessionDwFlags & DPSESSION_MULTICASTSERVER ) { sessionDwFlags &= ~DPSESSION_MULTICASTSERVER; } if( sessionDwFlags & DPSESSION_NEWPLAYERSDISABLED ) { sessionDwFlags &= ~DPSESSION_NEWPLAYERSDISABLED; } if( sessionDwFlags & DPSESSION_NODATAMESSAGES ) { sessionDwFlags &= ~DPSESSION_NODATAMESSAGES; } if( sessionDwFlags & DPSESSION_NOMESSAGEID ) { sessionDwFlags &= ~DPSESSION_NOMESSAGEID; } if( sessionDwFlags & DPSESSION_PASSWORDREQUIRED ) { sessionDwFlags &= ~DPSESSION_PASSWORDREQUIRED; } } ExitThread(0); return 0; } /********************************************************* * * Direct Play and Direct Play Lobby Interface Implementation * *********************************************************/ /* 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. * * As you can see, this interface doesn't qualify but will most likely * be good enough for the time being. */ static HRESULT WINAPI IDirectPlayLobbyA_QueryInterface ( LPDIRECTPLAYLOBBYA this, REFIID riid, LPVOID* ppvObj ) { return DPERR_OUTOFMEMORY; } static HRESULT WINAPI IDirectPlayLobbyW_QueryInterface ( LPDIRECTPLAYLOBBY this, REFIID riid, LPVOID* ppvObj ) { return DPERR_OUTOFMEMORY; } static HRESULT WINAPI IDirectPlayLobby2A_QueryInterface ( LPDIRECTPLAYLOBBY2A this, REFIID riid, LPVOID* ppvObj ) { /* Compare riids. We know this object is a direct play lobby 2A object. If we are asking about the same type of interface we're fine. */ if( IsEqualGUID( &IID_IUnknown, riid ) || IsEqualGUID( &IID_IDirectPlayLobby2A, riid ) ) { this->lpVtbl->fnAddRef( this ); *ppvObj = this; return S_OK; } /* They're requesting a unicode version of the interface */ else if( IsEqualGUID( &IID_IDirectPlayLobby2, riid ) ) { LPDIRECTPLAYLOBBY2 lpDpL = (LPDIRECTPLAYLOBBY2)(*ppvObj); lpDpL = (LPDIRECTPLAYLOBBY2)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( IDirectPlayLobby2 ) ); if( !lpDpL ) { return E_NOINTERFACE; } lpDpL->lpVtbl = &directPlayLobby2WVT; lpDpL->ref = 1; return S_OK; } /* Unexpected interface request! */ *ppvObj = NULL; return E_NOINTERFACE; }; static HRESULT WINAPI IDirectPlayLobby2W_QueryInterface ( LPDIRECTPLAYLOBBY2 this, REFIID riid, LPVOID* ppvObj ) { /* Compare riids. We know this object is a direct play lobby 2 object. If we are asking about the same type of interface we're fine. */ if( IsEqualGUID( &IID_IUnknown, riid ) || IsEqualGUID( &IID_IDirectPlayLobby2, riid ) ) { this->lpVtbl->fnAddRef( this ); *ppvObj = this; return S_OK; } else if( IsEqualGUID( &IID_IDirectPlayLobby2A, riid ) ) { LPDIRECTPLAYLOBBY2A lpDpL = (LPDIRECTPLAYLOBBY2A)(*ppvObj); lpDpL = (LPDIRECTPLAYLOBBY2A)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( IDirectPlayLobby2A ) ); if( !lpDpL ) { return E_NOINTERFACE; } lpDpL->lpVtbl = &directPlayLobby2AVT; lpDpL->ref = 1; return S_OK; } /* Unexpected interface request! */ *ppvObj = NULL; return E_NOINTERFACE; }; /* * Simple procedure. Just increment the reference count to this * structure and return the new reference count. */ static ULONG WINAPI IDirectPlayLobbyA_AddRef ( LPDIRECTPLAYLOBBYA this ) { ++(this->ref); TRACE( dplay,"ref count now %lu\n", this->ref ); return (this->ref); } static ULONG WINAPI IDirectPlayLobbyW_AddRef ( LPDIRECTPLAYLOBBY this ) { return IDirectPlayLobbyA_AddRef( (LPDIRECTPLAYLOBBY) this ); } static ULONG WINAPI IDirectPlayLobby2A_AddRef ( LPDIRECTPLAYLOBBY2A this ) { return IDirectPlayLobbyA_AddRef( (LPDIRECTPLAYLOBBY) this ); }; static ULONG WINAPI IDirectPlayLobby2W_AddRef ( LPDIRECTPLAYLOBBY2 this ) { return IDirectPlayLobbyA_AddRef( (LPDIRECTPLAYLOBBY) this ); }; /* * 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 IDirectPlayLobbyA_Release ( LPDIRECTPLAYLOBBYA this ) { TRACE( dplay, "ref count decremeneted from %lu\n", this->ref ); this->ref--; /* Deallocate if this is the last reference to the object */ if( !(this->ref) ) { deleteDPConnection( &(this->lpSession) ); HeapFree( GetProcessHeap(), 0, this ); return S_OK; } return this->ref; } static ULONG WINAPI IDirectPlayLobbyW_Release ( LPDIRECTPLAYLOBBY this ) { return IDirectPlayLobbyA_Release( (LPDIRECTPLAYLOBBYA) this ); } static ULONG WINAPI IDirectPlayLobby2A_Release ( LPDIRECTPLAYLOBBY2A this ) { return IDirectPlayLobbyA_Release( (LPDIRECTPLAYLOBBYA) this ); }; static ULONG WINAPI IDirectPlayLobby2W_Release ( LPDIRECTPLAYLOBBY2 this ) { return IDirectPlayLobbyA_Release( (LPDIRECTPLAYLOBBYA) this ); }; /******************************************************************** * * Connects an application to the session specified by the DPLCONNECTION * structure currently stored with the DirectPlayLobby object. * * Returns a IDirectPlay interface. * */ static HRESULT WINAPI IDirectPlayLobbyA_Connect ( LPDIRECTPLAYLOBBYA this, DWORD dwFlags, LPDIRECTPLAY* lplpDP, IUnknown* pUnk) { FIXME( dplay, ": dwFlags=%08lx %p %p stub\n", dwFlags, lplpDP, pUnk ); return DPERR_OUTOFMEMORY; }; static HRESULT WINAPI IDirectPlayLobby2A_Connect ( LPDIRECTPLAYLOBBY2A this, DWORD dwFlags, LPDIRECTPLAY* lplpDP, IUnknown* pUnk) { return IDirectPlayLobbyA_Connect( (LPDIRECTPLAYLOBBYA)this, dwFlags, lplpDP, pUnk ); }; static HRESULT WINAPI IDirectPlayLobbyW_Connect ( LPDIRECTPLAYLOBBY this, DWORD dwFlags, LPDIRECTPLAY* lplpDP, IUnknown* pUnk) { LPDIRECTPLAY2A directPlay2A; LPDIRECTPLAY2 directPlay2W; HRESULT createRC; FIXME( dplay, ": dwFlags=%08lx %p %p stub\n", dwFlags, lplpDP, pUnk ); #if 0 /* See dpbuild_4301.txt */ /* Create the direct play 2 W interface */ if( ( ( createRC = DirectPlayCreate( NULL, &directPlay2A, pUnk ) ) != DP_OK ) || ( ( createRC = directPlay2A->lpVtbl->fnQueryInterface ( directPlay2A, IID_IDirectPlay2, &directPlay2W ) ) != DP_OK ) ) { ERR( dplay, "error creating Direct Play 2 (W) interface. Return Code = %d.\n", createRC ); return createRC; } /* All the stuff below this is WRONG! */ if( this->lpSession->dwFlags == DPLCONNECTION_CREATESESSION ) { DWORD threadIdSink; /* Spawn a thread to deal with all of this and to handle the incomming requests */ threadIdSink = CreateThread( NULL, 0, &DPLobby_Spawn_Server, (LPVOID)this->lpSession->lpConn->lpSessionDesc, 0, &threadIdSink ); } else if ( this->lpSession->dwFlags == DPLCONNECTION_JOINSESSION ) { /* Let's search for a matching session */ FIXME( dplay, "joining session not yet supported.\n"); return DPERR_OUTOFMEMORY; } else /* Unknown type of connection request */ { ERR( dplay, ": Unknown connection request lpConn->dwFlags=%08lx\n", lpConn->dwFlags ); return DPERR_OUTOFMEMORY; } /* This does the work of the following methods... IDirectPlay3::InitializeConnection, IDirectPlay3::EnumSessions, IDirectPlay3::Open */ #endif return DP_OK; }; static HRESULT WINAPI IDirectPlayLobby2W_Connect ( LPDIRECTPLAYLOBBY2 this, DWORD dwFlags, LPDIRECTPLAY* lplpDP, IUnknown* pUnk) { return IDirectPlayLobbyW_Connect( (LPDIRECTPLAYLOBBY)this, dwFlags, 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. * */ static HRESULT WINAPI IDirectPlayLobbyA_CreateAddress ( LPDIRECTPLAYLOBBY this, REFGUID guidSP, REFGUID guidDataType, LPCVOID lpData, DWORD dwDataSize, LPVOID lpAddress, LPDWORD lpdwAddressSize ) { FIXME( dplay, ":stub\n"); return DPERR_OUTOFMEMORY; }; static HRESULT WINAPI IDirectPlayLobby2A_CreateAddress ( LPDIRECTPLAYLOBBY2A this, REFGUID guidSP, REFGUID guidDataType, LPCVOID lpData, DWORD dwDataSize, LPVOID lpAddress, LPDWORD lpdwAddressSize ) { return IDirectPlayLobbyA_CreateAddress( (LPDIRECTPLAYLOBBY)this, guidSP, guidDataType, lpData, dwDataSize, lpAddress, lpdwAddressSize ); }; static HRESULT WINAPI IDirectPlayLobbyW_CreateAddress ( LPDIRECTPLAYLOBBY this, REFGUID guidSP, REFGUID guidDataType, LPCVOID lpData, DWORD dwDataSize, LPVOID lpAddress, LPDWORD lpdwAddressSize ) { FIXME( dplay, ":stub\n"); return DPERR_OUTOFMEMORY; }; static HRESULT WINAPI IDirectPlayLobby2W_CreateAddress ( LPDIRECTPLAYLOBBY2 this, REFGUID guidSP, REFGUID guidDataType, LPCVOID lpData, DWORD dwDataSize, LPVOID lpAddress, LPDWORD lpdwAddressSize ) { return IDirectPlayLobbyW_CreateAddress( (LPDIRECTPLAYLOBBY)this, guidSP, guidDataType, lpData, dwDataSize, lpAddress, lpdwAddressSize ); }; /******************************************************************** * * Parses out chunks from the DirectPlay Address buffer by calling the * given callback function, with lpContext, for each of the chunks. * */ static HRESULT WINAPI IDirectPlayLobbyA_EnumAddress ( LPDIRECTPLAYLOBBYA this, LPDPENUMADDRESSCALLBACK lpEnumAddressCallback, LPCVOID lpAddress, DWORD dwAddressSize, LPVOID lpContext ) { FIXME( dplay, ":stub\n"); return DPERR_OUTOFMEMORY; }; static HRESULT WINAPI IDirectPlayLobby2A_EnumAddress ( LPDIRECTPLAYLOBBY2A this, LPDPENUMADDRESSCALLBACK lpEnumAddressCallback, LPCVOID lpAddress, DWORD dwAddressSize, LPVOID lpContext ) { return IDirectPlayLobbyA_EnumAddress( (LPDIRECTPLAYLOBBYA)this, lpEnumAddressCallback, lpAddress, dwAddressSize, lpContext ); }; static HRESULT WINAPI IDirectPlayLobbyW_EnumAddress ( LPDIRECTPLAYLOBBY this, LPDPENUMADDRESSCALLBACK lpEnumAddressCallback, LPCVOID lpAddress, DWORD dwAddressSize, LPVOID lpContext ) { FIXME( dplay, ":stub\n"); return DPERR_OUTOFMEMORY; }; static HRESULT WINAPI IDirectPlayLobby2W_EnumAddress ( LPDIRECTPLAYLOBBY2 this, LPDPENUMADDRESSCALLBACK lpEnumAddressCallback, LPCVOID lpAddress, DWORD dwAddressSize, LPVOID lpContext ) { return IDirectPlayLobbyW_EnumAddress( (LPDIRECTPLAYLOBBY)this, lpEnumAddressCallback, lpAddress, dwAddressSize, lpContext ); }; /******************************************************************** * * Enumerates all the address types that a given service provider needs to * build the DirectPlay Address. * */ static HRESULT WINAPI IDirectPlayLobbyA_EnumAddressTypes ( LPDIRECTPLAYLOBBYA this, LPDPLENUMADDRESSTYPESCALLBACK lpEnumAddressTypeCallback, REFGUID guidSP, LPVOID lpContext, DWORD dwFlags ) { FIXME( dplay, ":stub\n"); return DPERR_OUTOFMEMORY; }; static HRESULT WINAPI IDirectPlayLobby2A_EnumAddressTypes ( LPDIRECTPLAYLOBBY2A this, LPDPLENUMADDRESSTYPESCALLBACK lpEnumAddressTypeCallback, REFGUID guidSP, LPVOID lpContext, DWORD dwFlags ) { return IDirectPlayLobbyA_EnumAddressTypes( (LPDIRECTPLAYLOBBYA)this, lpEnumAddressTypeCallback, guidSP, lpContext, dwFlags ); }; static HRESULT WINAPI IDirectPlayLobbyW_EnumAddressTypes ( LPDIRECTPLAYLOBBY this, LPDPLENUMADDRESSTYPESCALLBACK lpEnumAddressTypeCallback, REFGUID guidSP, LPVOID lpContext, DWORD dwFlags ) { FIXME( dplay, ":stub\n"); return DPERR_OUTOFMEMORY; }; static HRESULT WINAPI IDirectPlayLobby2W_EnumAddressTypes ( LPDIRECTPLAYLOBBY2 this, LPDPLENUMADDRESSTYPESCALLBACK lpEnumAddressTypeCallback, REFGUID guidSP, LPVOID lpContext, DWORD dwFlags ) { return IDirectPlayLobbyW_EnumAddressTypes( (LPDIRECTPLAYLOBBY)this, lpEnumAddressTypeCallback, guidSP, lpContext, dwFlags ); }; /******************************************************************** * * Enumerates what applications are registered with DirectPlay by * invoking the callback function with lpContext. * */ static HRESULT WINAPI IDirectPlayLobbyW_EnumLocalApplications ( LPDIRECTPLAYLOBBY this, LPDPLENUMLOCALAPPLICATIONSCALLBACK a, LPVOID lpContext, DWORD dwFlags ) { FIXME( dplay, ":stub\n"); return DPERR_OUTOFMEMORY; }; static HRESULT WINAPI IDirectPlayLobby2W_EnumLocalApplications ( LPDIRECTPLAYLOBBY2 this, LPDPLENUMLOCALAPPLICATIONSCALLBACK a, LPVOID lpContext, DWORD dwFlags ) { return IDirectPlayLobbyW_EnumLocalApplications( (LPDIRECTPLAYLOBBY)this, a, lpContext, dwFlags ); }; static HRESULT WINAPI IDirectPlayLobbyA_EnumLocalApplications ( LPDIRECTPLAYLOBBYA this, LPDPLENUMLOCALAPPLICATIONSCALLBACK a, LPVOID lpContext, DWORD dwFlags ) { FIXME( dplay, ":stub\n"); return DPERR_OUTOFMEMORY; }; static HRESULT WINAPI IDirectPlayLobby2A_EnumLocalApplications ( LPDIRECTPLAYLOBBY2A this, LPDPLENUMLOCALAPPLICATIONSCALLBACK a, LPVOID lpContext, DWORD dwFlags ) { return IDirectPlayLobbyA_EnumLocalApplications( (LPDIRECTPLAYLOBBYA)this, a, lpContext, dwFlags ); }; /******************************************************************** * * 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 IDirectPlayLobbyA_GetConnectionSettings ( LPDIRECTPLAYLOBBYA this, DWORD dwAppID, LPVOID lpData, LPDWORD lpdwDataSize ) { FIXME( dplay, ": semi stub %p %08lx %p %p \n", this, dwAppID, lpData, lpdwDataSize ); /* Application is requesting us to give the required size */ if ( !lpData ) { /* Let's check the size of the buffer that the application has allocated */ if( *lpdwDataSize >= sizeof( DPLCONNECTION ) ) { return DP_OK; } else { *lpdwDataSize = sizeof( DPLCONNECTION ); return DPERR_BUFFERTOOSMALL; } } /* Fill in the fields - let them just use the ptrs */ if( ((LPDPLCONNECTION)lpData)->lpSessionDesc ) { } memcpy( lpData, this->lpSession, sizeof( *(this->lpSession) ) ); return DP_OK; } static HRESULT WINAPI IDirectPlayLobby2A_GetConnectionSettings ( LPDIRECTPLAYLOBBY2A this, DWORD dwAppID, LPVOID lpData, LPDWORD lpdwDataSize ) { return IDirectPlayLobbyA_GetConnectionSettings( (LPDIRECTPLAYLOBBYA)this, dwAppID, lpData, lpdwDataSize ); } static HRESULT WINAPI IDirectPlayLobbyW_GetConnectionSettings ( LPDIRECTPLAYLOBBY this, DWORD dwAppID, LPVOID lpData, LPDWORD lpdwDataSize ) { FIXME( dplay, ":semi stub %p %08lx %p %p \n", this, dwAppID, lpData, lpdwDataSize ); /* Application is requesting us to give the required size */ if ( !lpData ) { /* Let's check the size of the buffer that the application has allocated */ if( *lpdwDataSize >= sizeof( DPLCONNECTION ) ) { return DP_OK; } else { *lpdwDataSize = sizeof( DPLCONNECTION ); return DPERR_BUFFERTOOSMALL; } } /* Fill in the fields - let them just use the ptrs */ memcpy( lpData, this->lpSession, sizeof( *(this->lpSession) ) ); return DP_OK; }; static HRESULT WINAPI IDirectPlayLobby2W_GetConnectionSettings ( LPDIRECTPLAYLOBBY2 this, DWORD dwAppID, LPVOID lpData, LPDWORD lpdwDataSize ) { return IDirectPlayLobbyW_GetConnectionSettings( (LPDIRECTPLAYLOBBY)this, dwAppID, lpData, lpdwDataSize ); } /******************************************************************** * * Retrieves the message sent between a lobby client and a DirectPlay * application. All messages are queued until received. * */ static HRESULT WINAPI IDirectPlayLobbyA_ReceiveLobbyMessage ( LPDIRECTPLAYLOBBYA this, DWORD dwFlags, DWORD dwAppID, LPDWORD lpdwMessageFlags, LPVOID lpData, LPDWORD lpdwDataSize ) { FIXME( dplay, ":stub %p %08lx %08lx %p %p %p\n", this, dwFlags, dwAppID, lpdwMessageFlags, lpData, lpdwDataSize ); return DPERR_OUTOFMEMORY; }; static HRESULT WINAPI IDirectPlayLobby2A_ReceiveLobbyMessage ( LPDIRECTPLAYLOBBY2A this, DWORD dwFlags, DWORD dwAppID, LPDWORD lpdwMessageFlags, LPVOID lpData, LPDWORD lpdwDataSize ) { return IDirectPlayLobbyA_ReceiveLobbyMessage( (LPDIRECTPLAYLOBBYA)this, dwFlags, dwAppID, lpdwMessageFlags, lpData, lpdwDataSize ); }; static HRESULT WINAPI IDirectPlayLobbyW_ReceiveLobbyMessage ( LPDIRECTPLAYLOBBY this, DWORD dwFlags, DWORD dwAppID, LPDWORD lpdwMessageFlags, LPVOID lpData, LPDWORD lpdwDataSize ) { FIXME( dplay, ":stub %p %08lx %08lx %p %p %p\n", this, dwFlags, dwAppID, lpdwMessageFlags, lpData, lpdwDataSize ); return DPERR_OUTOFMEMORY; }; static HRESULT WINAPI IDirectPlayLobby2W_ReceiveLobbyMessage ( LPDIRECTPLAYLOBBY2 this, DWORD dwFlags, DWORD dwAppID, LPDWORD lpdwMessageFlags, LPVOID lpData, LPDWORD lpdwDataSize ) { return IDirectPlayLobbyW_ReceiveLobbyMessage( (LPDIRECTPLAYLOBBY)this, dwFlags, dwAppID, lpdwMessageFlags, lpData, lpdwDataSize ); }; /******************************************************************** * * Starts an application and passes to it all the information to * connect to a session. * */ static HRESULT WINAPI IDirectPlayLobbyA_RunApplication ( LPDIRECTPLAYLOBBYA this, DWORD dwFlags, LPDWORD lpdwAppID, LPDPLCONNECTION lpConn, HANDLE32 hReceiveEvent ) { FIXME( dplay, ":stub\n"); return DPERR_OUTOFMEMORY; }; static HRESULT WINAPI IDirectPlayLobby2A_RunApplication ( LPDIRECTPLAYLOBBY2A this, DWORD dwFlags, LPDWORD lpdwAppID, LPDPLCONNECTION lpConn, HANDLE32 hReceiveEvent ) { return IDirectPlayLobbyA_RunApplication( (LPDIRECTPLAYLOBBYA)this, dwFlags, lpdwAppID, lpConn, hReceiveEvent ); }; static HRESULT WINAPI IDirectPlayLobbyW_RunApplication ( LPDIRECTPLAYLOBBY this, DWORD dwFlags, LPDWORD lpdwAppID, LPDPLCONNECTION lpConn, HANDLE32 hReceiveEvent ) { FIXME( dplay, ":stub\n"); return DPERR_OUTOFMEMORY; }; static HRESULT WINAPI IDirectPlayLobby2W_RunApplication ( LPDIRECTPLAYLOBBY2 this, DWORD dwFlags, LPDWORD lpdwAppID, LPDPLCONNECTION lpConn, HANDLE32 hReceiveEvent ) { return IDirectPlayLobbyW_RunApplication( (LPDIRECTPLAYLOBBY)this, dwFlags, lpdwAppID, lpConn, hReceiveEvent ); }; /******************************************************************** * * Sends a message between the application and the lobby client. * All messages are queued until received. * */ static HRESULT WINAPI IDirectPlayLobbyA_SendLobbyMessage ( LPDIRECTPLAYLOBBYA this, DWORD dwFlags, DWORD dwAppID, LPVOID lpData, DWORD dwDataSize ) { FIXME( dplay, ":stub\n"); return DPERR_OUTOFMEMORY; }; static HRESULT WINAPI IDirectPlayLobby2A_SendLobbyMessage ( LPDIRECTPLAYLOBBY2A this, DWORD dwFlags, DWORD dwAppID, LPVOID lpData, DWORD dwDataSize ) { return IDirectPlayLobbyA_SendLobbyMessage( (LPDIRECTPLAYLOBBYA)this, dwFlags, dwAppID, lpData, dwDataSize ); }; static HRESULT WINAPI IDirectPlayLobbyW_SendLobbyMessage ( LPDIRECTPLAYLOBBY this, DWORD dwFlags, DWORD dwAppID, LPVOID lpData, DWORD dwDataSize ) { FIXME( dplay, ":stub\n"); return DPERR_OUTOFMEMORY; }; static HRESULT WINAPI IDirectPlayLobby2W_SendLobbyMessage ( LPDIRECTPLAYLOBBY2 this, DWORD dwFlags, DWORD dwAppID, LPVOID lpData, DWORD dwDataSize ) { return IDirectPlayLobbyW_SendLobbyMessage( (LPDIRECTPLAYLOBBY)this, dwFlags, dwAppID, lpData, dwDataSize ); }; /******************************************************************** * * Modifies the DPLCONNECTION structure to contain all information * needed to start and connect an application. * */ static HRESULT WINAPI IDirectPlayLobbyW_SetConnectionSettings ( LPDIRECTPLAYLOBBY this, DWORD dwFlags, DWORD dwAppID, LPDPLCONNECTION lpConn ) { FIXME( dplay, ": this=%p, dwFlags=%08lx, dwAppId=%08lx, lpConn=%p: semi stub\n", this, dwFlags, dwAppID, lpConn ); /* Paramater check */ if( dwFlags || !this || !lpConn ) { ERR( dplay, "invalid parameters.\n"); return DPERR_INVALIDPARAMS; } /* See if there is a connection associated with this request. * dwAppID == 0 indicates that this request isn't associated with a connection. */ if( dwAppID ) { FIXME( dplay, ": Connection dwAppID=%08lx given. Not implemented yet.\n", dwAppID ); /* Need to add a check for this application Id...*/ return DPERR_NOTLOBBIED; } if( lpConn->dwSize != sizeof(DPLCONNECTION) ) { ERR( dplay, ": old/new DPLCONNECTION type? Size=%08lx vs. expected=%ul bytes\n", lpConn->dwSize, sizeof( DPLCONNECTION ) ); return DPERR_INVALIDPARAMS; } /* Need to investigate the lpConn->lpSessionDesc to figure out * what type of session we need to join/create. */ if( (!lpConn->lpSessionDesc ) || ( lpConn->lpSessionDesc->dwSize != sizeof( DPSESSIONDESC2 ) ) ) { ERR( dplay, "DPSESSIONDESC passed in? Size=%08lx vs. expected=%ul bytes\n", lpConn->lpSessionDesc->dwSize, sizeof( DPSESSIONDESC2 ) ); return DPERR_INVALIDPARAMS; } /* Need to actually store the stuff here */ return DPERR_OUTOFMEMORY; }; static HRESULT WINAPI IDirectPlayLobby2W_SetConnectionSettings ( LPDIRECTPLAYLOBBY2 this, DWORD dwFlags, DWORD dwAppID, LPDPLCONNECTION lpConn ) { return IDirectPlayLobbyW_SetConnectionSettings( (LPDIRECTPLAYLOBBY)this, dwFlags, dwAppID, lpConn ); } static HRESULT WINAPI IDirectPlayLobbyA_SetConnectionSettings ( LPDIRECTPLAYLOBBYA this, DWORD dwFlags, DWORD dwAppID, LPDPLCONNECTION lpConn ) { FIXME( dplay, ": this=%p, dwFlags=%08lx, dwAppId=%08lx, lpConn=%p: stub\n", this, dwFlags, dwAppID, lpConn ); return DPERR_OUTOFMEMORY; } static HRESULT WINAPI IDirectPlayLobby2A_SetConnectionSettings ( LPDIRECTPLAYLOBBY2A this, DWORD dwFlags, DWORD dwAppID, LPDPLCONNECTION lpConn ) { return IDirectPlayLobbyA_SetConnectionSettings( (LPDIRECTPLAYLOBBYA)this, dwFlags, dwAppID, lpConn ); }; /******************************************************************** * * Registers an event that will be set when a lobby message is received. * */ static HRESULT WINAPI IDirectPlayLobbyA_SetLobbyMessageEvent ( LPDIRECTPLAYLOBBYA this, DWORD dwFlags, DWORD dwAppID, HANDLE32 hReceiveEvent ) { FIXME( dplay, ":stub\n"); return DPERR_OUTOFMEMORY; }; static HRESULT WINAPI IDirectPlayLobby2A_SetLobbyMessageEvent ( LPDIRECTPLAYLOBBY2A this, DWORD dwFlags, DWORD dwAppID, HANDLE32 hReceiveEvent ) { return IDirectPlayLobbyA_SetLobbyMessageEvent( (LPDIRECTPLAYLOBBYA)this, dwFlags, dwAppID, hReceiveEvent ); }; static HRESULT WINAPI IDirectPlayLobbyW_SetLobbyMessageEvent ( LPDIRECTPLAYLOBBY this, DWORD dwFlags, DWORD dwAppID, HANDLE32 hReceiveEvent ) { FIXME( dplay, ":stub\n"); return DPERR_OUTOFMEMORY; }; static HRESULT WINAPI IDirectPlayLobby2W_SetLobbyMessageEvent ( LPDIRECTPLAYLOBBY2 this, DWORD dwFlags, DWORD dwAppID, HANDLE32 hReceiveEvent ) { return IDirectPlayLobbyW_SetLobbyMessageEvent( (LPDIRECTPLAYLOBBY)this, dwFlags, dwAppID, hReceiveEvent ); }; /******************************************************************** * * Registers an event that will be set when a lobby message is received. * */ static HRESULT WINAPI IDirectPlayLobby2W_CreateCompoundAddress ( LPDIRECTPLAYLOBBY2 this, LPCDPCOMPOUNDADDRESSELEMENT lpElements, DWORD dwElementCount, LPVOID lpAddress, LPDWORD lpdwAddressSize ) { FIXME( dplay, ":stub\n"); return DPERR_OUTOFMEMORY; }; static HRESULT WINAPI IDirectPlayLobby2A_CreateCompoundAddress ( LPDIRECTPLAYLOBBY2A this, LPCDPCOMPOUNDADDRESSELEMENT lpElements, DWORD dwElementCount, LPVOID lpAddress, LPDWORD lpdwAddressSize ) { FIXME( dplay, ":stub\n"); return DPERR_OUTOFMEMORY; }; /* Direct Play Lobby 1 (ascii) Virtual Table for methods */ static struct tagLPDIRECTPLAYLOBBY_VTABLE directPlayLobbyAVT = { IDirectPlayLobbyA_QueryInterface, IDirectPlayLobbyA_AddRef, IDirectPlayLobbyA_Release, IDirectPlayLobbyA_Connect, IDirectPlayLobbyA_CreateAddress, IDirectPlayLobbyA_EnumAddress, IDirectPlayLobbyA_EnumAddressTypes, IDirectPlayLobbyA_EnumLocalApplications, IDirectPlayLobbyA_GetConnectionSettings, IDirectPlayLobbyA_ReceiveLobbyMessage, IDirectPlayLobbyA_RunApplication, IDirectPlayLobbyA_SendLobbyMessage, IDirectPlayLobbyA_SetConnectionSettings, IDirectPlayLobbyA_SetLobbyMessageEvent }; /* Direct Play Lobby 1 (unicode) Virtual Table for methods */ static struct tagLPDIRECTPLAYLOBBY_VTABLE directPlayLobbyWVT = { IDirectPlayLobbyW_QueryInterface, IDirectPlayLobbyW_AddRef, IDirectPlayLobbyW_Release, IDirectPlayLobbyW_Connect, IDirectPlayLobbyW_CreateAddress, IDirectPlayLobbyW_EnumAddress, IDirectPlayLobbyW_EnumAddressTypes, IDirectPlayLobbyW_EnumLocalApplications, IDirectPlayLobbyW_GetConnectionSettings, IDirectPlayLobbyW_ReceiveLobbyMessage, IDirectPlayLobbyW_RunApplication, IDirectPlayLobbyW_SendLobbyMessage, IDirectPlayLobbyW_SetConnectionSettings, IDirectPlayLobbyW_SetLobbyMessageEvent }; /* Direct Play Lobby 2 (ascii) Virtual Table for methods */ static struct tagLPDIRECTPLAYLOBBY2_VTABLE directPlayLobby2AVT = { IDirectPlayLobby2A_QueryInterface, IDirectPlayLobby2A_AddRef, IDirectPlayLobby2A_Release, IDirectPlayLobby2A_Connect, IDirectPlayLobby2A_CreateAddress, IDirectPlayLobby2A_EnumAddress, IDirectPlayLobby2A_EnumAddressTypes, IDirectPlayLobby2A_EnumLocalApplications, IDirectPlayLobby2A_GetConnectionSettings, IDirectPlayLobby2A_ReceiveLobbyMessage, IDirectPlayLobby2A_RunApplication, IDirectPlayLobby2A_SendLobbyMessage, IDirectPlayLobby2A_SetConnectionSettings, IDirectPlayLobby2A_SetLobbyMessageEvent, IDirectPlayLobby2A_CreateCompoundAddress }; /* Direct Play Lobby 2 (unicode) Virtual Table for methods */ static struct tagLPDIRECTPLAYLOBBY2_VTABLE directPlayLobby2WVT = { IDirectPlayLobby2W_QueryInterface, IDirectPlayLobby2W_AddRef, IDirectPlayLobby2W_Release, IDirectPlayLobby2W_Connect, IDirectPlayLobby2W_CreateAddress, IDirectPlayLobby2W_EnumAddress, IDirectPlayLobby2W_EnumAddressTypes, IDirectPlayLobby2W_EnumLocalApplications, IDirectPlayLobby2W_GetConnectionSettings, IDirectPlayLobby2W_ReceiveLobbyMessage, IDirectPlayLobby2W_RunApplication, IDirectPlayLobby2W_SendLobbyMessage, IDirectPlayLobby2W_SetConnectionSettings, IDirectPlayLobby2W_SetLobbyMessageEvent, IDirectPlayLobby2W_CreateCompoundAddress }; /*************************************************************************** * DirectPlayLobbyCreateA (DPLAYX.4) * */ HRESULT WINAPI DirectPlayLobbyCreateA( LPGUID lpGUIDDSP, LPDIRECTPLAYLOBBYA *lplpDPL, IUnknown *lpUnk, LPVOID lpData, DWORD dwDataSize ) { TRACE(dplay,"lpGUIDDSP=%p lplpDPL=%p lpUnk=%p lpData=%p dwDataSize=%08lx\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 || lpUnk || lpData || dwDataSize ) { *lplpDPL = NULL; return DPERR_INVALIDPARAMS; } /* Yes...really we should bre returning a lobby 1 object */ *lplpDPL = (LPDIRECTPLAYLOBBYA)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( IDirectPlayLobbyA ) ); if( ! (*lplpDPL) ) { return DPERR_OUTOFMEMORY; } (*lplpDPL)->lpVtbl = &directPlayLobbyAVT; (*lplpDPL)->ref = 1; (*lplpDPL)->lpSession = (LPDPLCONNECTION)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( DPLCONNECTION ) ); (*lplpDPL)->lpSession->dwSize = sizeof( DPLCONNECTION ); (*lplpDPL)->lpSession->lpSessionDesc = (LPDPSESSIONDESC2)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( DPSESSIONDESC2 ) ); (*lplpDPL)->lpSession->lpSessionDesc->dwSize = sizeof( DPSESSIONDESC2 ); return DP_OK; } /*************************************************************************** * DirectPlayLobbyCreateW (DPLAYX.5) * */ HRESULT WINAPI DirectPlayLobbyCreateW( LPGUID lpGUIDDSP, LPDIRECTPLAYLOBBY *lplpDPL, IUnknown *lpUnk, LPVOID lpData, DWORD dwDataSize ) { TRACE(dplay,"lpGUIDDSP=%p lplpDPL=%p lpUnk=%p lpData=%p dwDataSize=%08lx\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 || lpUnk || lpData || dwDataSize ) { *lplpDPL = NULL; ERR( dplay, "Bad parameters!\n" ); return DPERR_INVALIDPARAMS; } /* Yes...really we should bre returning a lobby 1 object */ *lplpDPL = (LPDIRECTPLAYLOBBY)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( IDirectPlayLobby ) ); if( !*lplpDPL) { return DPERR_OUTOFMEMORY; } (*lplpDPL)->lpVtbl = &directPlayLobbyWVT; (*lplpDPL)->ref = 1; (*lplpDPL)->lpSession = (LPDPLCONNECTION)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( DPLCONNECTION ) ); (*lplpDPL)->lpSession->dwSize = sizeof( DPLCONNECTION ); (*lplpDPL)->lpSession->lpSessionDesc = (LPDPSESSIONDESC2)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( DPSESSIONDESC2 ) ); (*lplpDPL)->lpSession->lpSessionDesc->dwSize = sizeof( DPSESSIONDESC2 ); return DP_OK; } /*************************************************************************** * DirectPlayEnumerateA (DPLAYX.2) * * The pointer to the structure lpContext will be filled with the * appropriate data for each service offered by the OS. These services are * not necessarily available on this particular machine but are defined * as simple service providers under the "Service Providers" registry key. * This structure is then passed to lpEnumCallback for each of the different * services. * * This API is useful only for applications written using DirectX3 or * worse. It is superceeded by IDirectPlay3::EnumConnections which also * gives information on the actual connections. * * defn of a service provider: * A dynamic-link library used by DirectPlay to communicate over a network. * The service provider contains all the network-specific code required * to send and receive messages. Online services and network operators can * supply service providers to use specialized hardware, protocols, communications * media, and network resources. * * TODO: Allocate string buffer space from the heap (length from reg) * Pass real device driver numbers... * Get the GUID properly... */ HRESULT WINAPI DirectPlayEnumerateA( LPDPENUMDPCALLBACKA lpEnumCallback, LPVOID lpContext ) { HKEY hkResult; LPCSTR searchSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers"; LPSTR guidDataSubKey = "Guid"; LPSTR majVerDataSubKey = "dwReserved1"; DWORD dwIndex, sizeOfSubKeyName=50; char subKeyName[51]; TRACE( dplay, ": lpEnumCallback=%p lpContext=%p\n", lpEnumCallback, lpContext ); if( !lpEnumCallback || !*lpEnumCallback ) { return DPERR_INVALIDPARAMS; } /* Need to loop over the service providers in the registry */ if( RegOpenKeyEx32A( HKEY_LOCAL_MACHINE, searchSubKey, 0, KEY_ENUMERATE_SUB_KEYS, &hkResult ) != ERROR_SUCCESS ) { /* Hmmm. Does this mean that there are no service providers? */ ERR(dplay, ": no service providers?\n"); return DP_OK; } /* Traverse all the service providers we have available */ for( dwIndex=0; RegEnumKey32A( hkResult, dwIndex, subKeyName, sizeOfSubKeyName ) != ERROR_NO_MORE_ITEMS; ++dwIndex ) { HKEY hkServiceProvider; GUID serviceProviderGUID; DWORD returnTypeGUID, returnTypeReserved1, sizeOfReturnBuffer=50; char returnBuffer[51]; DWORD majVersionNum, minVersionNum; LPWSTR lpWGUIDString; TRACE( dplay, " this time through: %s\n", subKeyName ); /* Get a handle for this particular service provider */ if( RegOpenKeyEx32A( hkResult, subKeyName, 0, KEY_QUERY_VALUE, &hkServiceProvider ) != ERROR_SUCCESS ) { ERR( dplay, ": what the heck is going on?\n" ); continue; } /* Get the GUID, Device major number and device minor number * from the registry. */ if( RegQueryValueEx32A( hkServiceProvider, guidDataSubKey, NULL, &returnTypeGUID, returnBuffer, &sizeOfReturnBuffer ) != ERROR_SUCCESS ) { ERR( dplay, ": missing GUID registry data members\n" ); continue; } /* FIXME: Check return types to ensure we're interpreting data right */ lpWGUIDString = HEAP_strdupAtoW( GetProcessHeap(), 0, returnBuffer ); CLSIDFromString32( (LPCOLESTR32)lpWGUIDString, &serviceProviderGUID ); HeapFree( GetProcessHeap(), 0, lpWGUIDString ); sizeOfReturnBuffer = 50; if( RegQueryValueEx32A( hkServiceProvider, majVerDataSubKey, NULL, &returnTypeReserved1, returnBuffer, &sizeOfReturnBuffer ) != ERROR_SUCCESS ) { ERR( dplay, ": missing dwReserved1 registry data members\n") ; continue; } /* FIXME: This couldn't possibly be right...*/ majVersionNum = GET_DWORD( returnBuffer ); /* The enumeration will return FALSE if we are not to continue */ if( !lpEnumCallback( &serviceProviderGUID , subKeyName, majVersionNum, (DWORD)0, lpContext ) ) { WARN( dplay, "lpEnumCallback returning FALSE\n" ); break; } } return DP_OK; }; /*************************************************************************** * DirectPlayEnumerateW (DPLAYX.3) * */ HRESULT WINAPI DirectPlayEnumerateW( LPDPENUMDPCALLBACKW lpEnumCallback, LPVOID lpContext ) { FIXME( dplay, ":stub\n"); return DPERR_OUTOFMEMORY; }; /*************************************************************************** * DirectPlayCreate (DPLAYX.1) (DPLAY.1) * */ HRESULT WINAPI DirectPlayCreate ( LPGUID lpGUID, LPDIRECTPLAY2 *lplpDP, IUnknown *pUnk) { FIXME( dplay, ":stub\n"); return DPERR_OUTOFMEMORY; TRACE(dplay,"\n" ); if( pUnk != NULL ) { /* Hmmm...wonder what this means! */ ERR(dplay, "What does a NULL here mean?\n" ); return DPERR_OUTOFMEMORY; } *lplpDP = (LPDIRECTPLAY)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( **lplpDP ) ); if( !*lplpDP ) { return DPERR_OUTOFMEMORY; } (*lplpDP)->lpVtbl = &directPlay2AVT; (*lplpDP)->ref = 1; return DP_OK; };