// -------------------------------------------------------------------------- // ========================================================================== // File: TDx_PlayLobby.CPP // Authors: BCB_Code_Generator v1.62, // Darren Dwyer (source code, documentation, demos, website), // Hugh Edwards (documentation, icons), // Brian Austin (some source code, documentation) // Description: This file contains the code for the TDx_PlayLobby Component // // "TDx_Play_Library v1.62" // (c) 2002 BCB-Tools.com Pty. Ltd., Sydney, Australia. // All Rights Reserved. // // Refer to the 'Licence.Txt' file for licencing & copyright information. // ========================================================================== // -------------------------------------------------------------------------- // #includes ... // -------------------------------------------------------------------------- #include #pragma hdrstop // -------------------------------------------------------------------------- #include "TDx_PlayLobby.H" // -------------------------------------------------------------------------- // external classes used by the TDx_PlayLobby component. #include "TDPLAppInfo.H" // -------------------------------------------------------------------------- // external classes used by TDx_PlayLobby methods. #include "TDPCompoundAddressElement.H" #include "TDPApplicationDesc.H" #include "TDPLConnection.H" // -------------------------------------------------------------------------- #pragma link "TDx_Library_Defns" #pragma link "TDx_Library_Functions" #pragma link "TDx_Play_Library_Defns" #pragma link "TDx_Play_Library_Functions" // -------------------------------------------------------------------------- // Object Registration... // -------------------------------------------------------------------------- #if (__BORLANDC__ >= 0x0530) // BCB Version 3+ #pragma package(smart_init) #endif // -------------------------------------------------------------------------- static inline void ValidCtrCheck(TDx_PlayLobby*) { new TDx_PlayLobby(NULL); } // -------------------------------------------------------------------------- namespace Tdx_playlobby { #if (__BORLANDC__ >= 0x0530) // BCB Version 3+ void __fastcall PACKAGE Register() #else void __fastcall Register() #endif { TComponentClass classes[1] = {__classid(TDx_PlayLobby)}; RegisterComponents("TDx_Play", classes, 0); } } // -------------------------------------------------------------------------- // Global Variables used internally by the TDx_PlayLobby component. // -------------------------------------------------------------------------- static TComponent* TDx_PlayLobby_ThreadParent = NULL; // -------------------------------------------------------------------------- // Global Functions used internally by the TDx_PlayLobby component. // -------------------------------------------------------------------------- class TDx_PlayLobby_ThreadClass : public TThread { //exactly same as SoundNotify public: __property bool HandlesModified = {write=fHandlesModified, default=true}; void __fastcall DoNothing() {}; void __fastcall Pause() { while (fRebuildingHandles) DoNothing(); SetEvent( fPauseEvent ); } void __fastcall Restart() { while (fRebuildingHandles) DoNothing(); SetEvent( fRestartEvent ); } void __fastcall TerminateImmediately() { while (fRebuildingHandles) DoNothing(); SetEvent( fTerminateEvent ); } void __fastcall RebuildHandles(); __fastcall TDx_PlayLobby_ThreadClass(); virtual __fastcall ~TDx_PlayLobby_ThreadClass(); protected: void __fastcall Execute(); void __fastcall Translate(); private: HANDLE* fHandles; TDx_PlayLobby** fHandleOwners; int fNumHandles; HANDLE fPauseEvent; HANDLE fRestartEvent; HANDLE fTerminateEvent; int fPauseIndex; int fRestartIndex; int fTerminateIndex; int fEventNum; bool fHandlesModified; bool fRebuildingHandles; }; //--------------------------------------------------------------------------- static TList* TDx_PlayLobby_ComponentList = NULL; static TDx_PlayLobby_ThreadClass* TDx_PlayLobby_Thread = NULL; //--------------------------------------------------------------------------- __fastcall TDx_PlayLobby_ThreadClass::TDx_PlayLobby_ThreadClass() : TThread(true) { //exactly same as Soundnotify fHandles = NULL; fNumHandles = 0; fEventNum = 0; fPauseEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); fPauseIndex = -1; fRestartEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); fRestartIndex = -1; fTerminateEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); fTerminateIndex = -1; fHandlesModified = true; fRebuildingHandles = false; } //--------------------------------------------------------------------------- __fastcall TDx_PlayLobby_ThreadClass::~TDx_PlayLobby_ThreadClass() { //exactly same as soundNotify if (fHandles) { delete[] fHandles; fHandles = NULL; fNumHandles = 0; } if (fTerminateEvent) { CloseHandle( fTerminateEvent ); fTerminateEvent = NULL; } if (fRestartEvent) { CloseHandle( fRestartEvent ); fRestartEvent = NULL; } if (fPauseEvent) { CloseHandle( fPauseEvent ); fPauseEvent = NULL; } } //--------------------------------------------------------------------------- void __fastcall TDx_PlayLobby_ThreadClass::Execute() {//exactly same as SoundNotify FreeOnTerminate = true; // wait for events while (true) { // rebuild handles iff required if (fHandlesModified) { fRebuildingHandles = true; RebuildHandles(); fHandlesModified = false; // do not change the order of these 2 bools fRebuildingHandles = false; // because other threads might be waiting for -this- result before changing ^one } // wait for notifications + pause, restart, terminate events fEventNum = WaitForMultipleObjects( fNumHandles+3, fHandles, FALSE, INFINITE ); // if for some reason the handles were invalid, re-try if (fEventNum==WAIT_FAILED) { fHandlesModified = true; // force a rebuild of the handles continue; } // modify the result fEventNum -= WAIT_OBJECT_0; // if it's a pause, wait for a resume or a terminate if (fEventNum == fPauseIndex) { // wait for restart / terminate event fEventNum = WaitForMultipleObjects( 2, &fHandles[fRestartIndex], FALSE, INFINITE ); } // if it's a restart, simply restart if (fEventNum == fRestartIndex) { continue; } // if it's a terminate event, exit immediately if (fEventNum == fTerminateIndex) { break; } // otherwise, the event is a notification event, send it to the user if (fEventNum < fNumHandles) { Synchronize(Translate); } } // finished } //--------------------------------------------------------------------------- void __fastcall TDx_PlayLobby_ThreadClass::RebuildHandles() { //modified slightly from soundnotify if (fHandles) { delete[] fHandles; fHandles = NULL; fNumHandles = 0; } if (fHandleOwners) { delete[] fHandleOwners; fHandleOwners = NULL; } // determine the number of handles that need to be added int num_handles = 0; for (int i=0;iCount;i++) { TDx_PlayLobby* lobby = (TDx_PlayLobby*) TDx_PlayLobby_ComponentList->Items[i]; if (lobby) if (lobby->Created) if (lobby->NumLobbies>0) num_handles += lobby->NumLobbies; } // allocate storage for handles and something to tell us who the handle refers to fHandles = new HANDLE [num_handles+3]; if (!fHandles) return; fHandleOwners = new TDx_PlayLobby* [num_handles+3]; if (!fHandleOwners) { delete[] fHandles; fHandles = NULL; return; } fNumHandles = num_handles; // add notification events to internal storage int pos = 0; for (int i=0;iCount;i++) { TDx_PlayLobby* lobby = (TDx_PlayLobby*) TDx_PlayLobby_ComponentList->Items[i]; if (lobby) if (lobby->Created) if (lobby->NumLobbies>0) for (int j=0;jNumLobbies;j++) { fHandles[pos] = lobby->LobbyEvents->Items[j]; fHandleOwners[pos] = lobby; pos++; } } // add pause, restart, terminate events fPauseIndex = fNumHandles; fHandles[fPauseIndex] = fPauseEvent; fRestartIndex = fNumHandles+1; fHandles[fRestartIndex] = fRestartEvent; fTerminateIndex = fNumHandles+2; fHandles[fTerminateIndex] = fTerminateEvent; } //--------------------------------------------------------------------------- void __fastcall TDx_PlayLobby_ThreadClass::Translate() { //modified slightly from soundnotify // if the handles were modified during the synchronize, abort immediately if (fHandlesModified) { return; } // send it to the relevant BCB event handler try { TDx_PlayLobby* lobby = (TDx_PlayLobby*) fHandleOwners[fEventNum]; if (lobby) // send to the TDx_PlayLobby::OnReceive() event (if one has been setup) if (lobby->OnReceive) lobby->OnReceive( lobby ); } // absorb anything extraordinary catch (...) {} } // -------------------------------------------------------------------------- // Extra code for Callback Handling // -------------------------------------------------------------------------- TDx_PlayLobby* TDx_PlayLobby_OnEnumAddressOwner = NULL; TDx_PlayLobby* TDx_PlayLobby_OnEnumAddressTypesOwner = NULL; TDx_PlayLobby* TDx_PlayLobby_OnEnumLocalApplicationsOwner = NULL; // -------------------------------------------------------------------------- // Constructor: TDx_PlayLobby::TDx_PlayLobby() // Description: The default constructor for the TDx_PlayLobby object. // -------------------------------------------------------------------------- __fastcall TDx_PlayLobby::TDx_PlayLobby(TComponent* Owner) : TComponent(Owner) { // Set up the IDs, Events and EventList internal variables fCreated = false; fErrorValue = DP_OK; fNumLobbies = 0; fLobbyEvents = new TList(); if (fLobbyEvents == NULL) { fErrorValue = DPERR_OUTOFMEMORY; } // create the thread iff required bool inside_ide = false; if (Screen) if (Screen->ActiveForm) if (Screen->ActiveForm->Designer) inside_ide = true; if (!inside_ide) if (TDx_PlayLobby_ThreadParent==NULL) { TDx_PlayLobby_ComponentList = new TList(); if (TDx_PlayLobby_ComponentList) { TDx_PlayLobby_Thread = new TDx_PlayLobby_ThreadClass(); if (TDx_PlayLobby_Thread) { TDx_PlayLobby_ThreadParent=this; TDx_PlayLobby_Thread->Resume(); } else { delete TDx_PlayLobby_ComponentList; TDx_PlayLobby_ComponentList = NULL; TDx_PlayLobby_ThreadParent = NULL; } } } } // -------------------------------------------------------------------------- // Destructor: TDx_PlayLobby::~TDx_PlayLobby() // Description: The destructor for the TDx_PlayLobby object. // -------------------------------------------------------------------------- __fastcall TDx_PlayLobby::~TDx_PlayLobby() { // make sure to destroy internals if (Created) Destroy(); // destroy the thread iff required if (TDx_PlayLobby_Thread != NULL) if (TDx_PlayLobby_ThreadParent==this) { TDx_PlayLobby_Thread->Pause(); // remove from list if (TDx_PlayLobby_ComponentList) if (TDx_PlayLobby_ComponentList->IndexOf(this)!=-1) TDx_PlayLobby_ComponentList->Delete( TDx_PlayLobby_ComponentList->IndexOf(this) ); // if there are any other components still alive, migrate the parent bool migrated = false; for (int i=0;iCount;i++) if (TDx_PlayLobby_ComponentList->Items[i]!=NULL) { TDx_PlayLobby_ThreadParent = (TDx_PlayLobby*) TDx_PlayLobby_ComponentList->Items[i]; migrated = true; break; } // otherwise, destroy the thread and the component list if (!migrated) { TDx_PlayLobby_Thread->TerminateImmediately(); TDx_PlayLobby_Thread = NULL; // :: DO NOT :: delete TDx_PlayLobby_Thread; delete TDx_PlayLobby_ComponentList; TDx_PlayLobby_ComponentList = NULL; TDx_PlayLobby_ThreadParent = NULL; } else // restart the thread with the new parent. { TDx_PlayLobby_Thread->HandlesModified = true; TDx_PlayLobby_Thread->Restart(); } } //clean up internal TLists for (int i=0;iCount;i++) { if (fLobbyEvents->Items[i]!=NULL) { // remove player event HANDLE handle = (HANDLE) fLobbyEvents->Items[i]; CloseHandle( handle ); } } if (fLobbyEvents) delete fLobbyEvents; } // -------------------------------------------------------------------------- // Property: Created // Description: The Created property is true if the internal // LPDIRECTPLAYLOBBY3 used in this component has been // successfully created, otherwise Created is false. // // To create the internal LPDIRECTPLAYLOBBY3, call the // TDx_PlayLobby::Create() method. // -------------------------------------------------------------------------- bool __fastcall TDx_PlayLobby::FGetCreated() { return fCreated; } // -------------------------------------------------------------------------- void __fastcall TDx_PlayLobby::FSetCreated( bool pCreated ) { fCreated = (pCreated && (fLPDIRECTPLAYLOBBY3==NULL)); } // -------------------------------------------------------------------------- // Property: ErrorValue // Description: The ErrorValue property contains the last error value // returned from a call to a TDx_PlayLobby method or fget/fset. // eg. DP_OK or DDERR_SURFACELOST or TDX_ERROR // -------------------------------------------------------------------------- HRESULT __fastcall TDx_PlayLobby::FGetErrorValue() { return fErrorValue; } // -------------------------------------------------------------------------- void __fastcall TDx_PlayLobby::FSetErrorValue( HRESULT pErrorValue ) { fErrorValue = pErrorValue; } // -------------------------------------------------------------------------- // Property: LobbyEvents // Description: The LobbyEvents property is internally by the TDx_PlayLobby // component to store events used by the // TDx_PlayLobbyThreadClass. // -------------------------------------------------------------------------- TList* __fastcall TDx_PlayLobby::FGetLobbyEvents() { return fLobbyEvents; } // -------------------------------------------------------------------------- void __fastcall TDx_PlayLobby::FSetLobbyEvents( TList* pLobbyEvents ) { fLobbyEvents = pLobbyEvents; } // -------------------------------------------------------------------------- // Property: NumLobbies // Description: The NumLobbies property is internally by TDx_PlayLobby and // TDx_PlayLobbyThreadClass. // -------------------------------------------------------------------------- int __fastcall TDx_PlayLobby::FGetNumLobbies() { return fNumLobbies; } // -------------------------------------------------------------------------- void __fastcall TDx_PlayLobby::FSetNumLobbies( int pNumLobbies ) { fNumLobbies = pNumLobbies; } // -------------------------------------------------------------------------- // Property: UseAnsiString // Description: The UseAnsiString property is defines whether the unicode or // ANSI string interface is being used. // -------------------------------------------------------------------------- bool __fastcall TDx_PlayLobby::FGetUseAnsiString() { return fUseAnsiString; } // -------------------------------------------------------------------------- void __fastcall TDx_PlayLobby::FSetUseAnsiString( bool pUseAnsiString ) { fUseAnsiString = pUseAnsiString; } // -------------------------------------------------------------------------- // Method: ConnectEx() // Description: The ConnectEx method will connect an application to a session // using the information stored in the associated TDPLConnection // component. // // The method will attempt to connect for a maximum of one // minute. // // You can check the current connection settings with // TDx_PlayLobby::GetConnectionSettings() and modify them using // TDx_PlayLobby::SetConnectionSettings(). // // Error values that can be generated are: // // DPERR_CONNECTING // DPERR_INVALIDFLAGS // DPERR_INVALIDPARAMS // Params: pFlags - // The Flags parameter defines a flag indicating how to // establish the connection. // The described effect applies when the flag is set. // // The default value of zero indicates the method will return // after connection is made or it times out. // Flags: // DPCONNECT_RETURNSTATUS - // The method will obtain the connection status and return // immediately. // // The method will return DPERR_CONNECTING immediately, // call the method periodically until DP_OK is returned. // pIID - // The IID parameter identifies which com interface to return. // // The possible values are: // // IID_IDirectPlay4A // IID_IDirectPlay4 // pDP - // The DP parameter references a TDx_Play component to be // initialized with the interface specified by the IID // parameter. // -------------------------------------------------------------------------- HRESULT __fastcall TDx_PlayLobby::ConnectEx( dword pFlags, REFIID pIID, void** pDP ) { // Original Function Definition // HRESULT ConnectEx( // DWORD dwFlags, // REFIID riid, // LPVOID* lplpDP, // IUnknown FAR *pUnk // ); // if the component internals are not already created, exit if (!fCreated) { fErrorValue = TDX_NOTCREATED; if (FOnError) FOnError( this, Name+"::ConnectEx()", "TDX_NOTCREATED", "The "+Name+" component has not been created successfully." ); return false; } // Call Original Function fErrorValue = fLPDIRECTPLAYLOBBY3->ConnectEx( (DWORD) pFlags, pIID, (LPVOID*) pDP, NULL ); // Success! return fErrorValue; } // -------------------------------------------------------------------------- // Method: Create() // Description: The Create() method is used to automatically create the // internal LPDIRECTPLAYLOBBY3 interface used in the // TDx_PlayLobby component and must be called before any methods // of the TDx_PlayLobby component will function. // -------------------------------------------------------------------------- bool __fastcall TDx_PlayLobby::Create() { // if the component internals have already been created, exit if (fCreated) { if (FOnError) FOnError( this, Name+"::Create()", "TDX_ALREADYCREATED", "The "+Name+"::Create() method was called when the component has already been created successfully." ); return false; } // Initialize DirectPlayLobby fLPDIRECTPLAYLOBBY3=NULL; CoInitialize(NULL); if (UseAnsiString) fErrorValue = CoCreateInstance( CLSID_DirectPlayLobby, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlayLobby3A, (LPVOID*)&fLPDIRECTPLAYLOBBY3); else fErrorValue = CoCreateInstance( CLSID_DirectPlayLobby, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlayLobby3, (LPVOID*)&fLPDIRECTPLAYLOBBY3); if (fErrorValue != DP_OK) { // Failure. if (FOnError) FOnError( this, Name+"::Create()", TDx_Play_Library_ErrorString(fErrorValue), TDx_Play_Library_ErrorMessage(fErrorValue) ); return false; } if (fLPDIRECTPLAYLOBBY3 != NULL) { fErrorValue = DP_OK; fCreated = true; if (FOnCreate) FOnCreate(this); } else if (FOnError) FOnError( this, Name+"::Create()", "TDX_ERROR", "The "+Name+"::Create() method failed because CoCreateInstance(...) failed." ); // return true if created return fCreated; } // -------------------------------------------------------------------------- // Method: CreateAddress() // Description: The CreateAddress method will create a TDx_Play address from // a network address specific to a service provider. // // The resulting address identifies the service provider and // includes a network address the service provider can // understand. // // TDx_PlayLobby::CreateCompoundAddress() can be used to create // addresses with more than one data chunk and is generally much // more useful. // // Error values that can be generated are: // // DPERR_BUFFERTOOSMALL // DPERR_INVALIDPARAMS // Params: pSP - // The SP parameter identifies the service provider. // pDataType - // The DataType parameter identifies the type of network address // being used. // // The predefined address types are: // // DPAID_Comport // DPAID_INet // DPAID_INetW // DPAID_INetPort // DPAID_LobbyProvider // DPAID_Modem // DPAID_ModemW // DPAID_Phone // DPAID_PhoneW // DPAID_ServiceProvider // DPAID_TotalSize // pData - // The Data parameter references the network address being used // to create the TDx_Play address. // // The data referenced and how it is interpreted depends on the // type specified in DataType. // // DPAID_ComPort // A TDPComportAddress component defining COM port settings. // // DPAID_INet // An ANSI representation of an IP or domain address. // For Example: "220.150.10.102" or "game.com". // Using an empty string ("") causes the Internet TCP/IP // connection service provider enumerate active sessions on the // specified network address or broadcast on the subnet. // The DataSize must include the terminator. // // DPAID_INetW // A unicode representation of an IP or domain address. // For Example: "220.150.10.102" or "game.com". // Using an empty string ("") causes the Internet TCP/IP // connection service provider enumerate active sessions on the // specified network address or broadcast on the subnet. // The DataSize must include the terminator. // // DPAID_INetPort // An integer specifying which port number to use for // communications. // // DPAID_LobbyProvider // A 16-byte GUID identifying the lobby provider the address // applies to. // // DPAID_Modem // A NULL terminated ANSI value specifying which modem to use. // Available modems can be determined with // TDx_Play::GetPlayerAddress(). // The DataSize must include the terminator. // // DPAID_ModemW // A NULL terminated unicode value specifying which modem to // use. // Available modems can be determined with // TDx_Play::GetPlayerAddress(). // The DataSize must include the terminator. // // DPAID_Phone // An ANSI value defining a phone number. // The modem service provider will call this number when // TDx_Play::EnumSessions() is called. // If no modem is specified, the first available modem will be // used. // The DataSize must include the terminator. // // DPAID_PhoneW // A unicode value defining a phone number. // The modem service provider will call this number when // TDx_Play::EnumSessions() is called. // If no modem is specified, the first available modem will be // used. // The DataSize must include the terminator. // // DPAID_ServiceProvider // A 16-byte GUID identifying the service provider the address // applies to. // // DPAID_TotalSize // A dword holding the size of the internal DPADDRESS structure. // pDataSize - // The DataSize parameter defines the size, in bytes, of the // network address in the Data parameter. // pAddress - // The Address parameter will reference the newly created // address if this method returns successfully. // // Set NULL to retrieve the required buffer size in the // AddressSize parameter. // pAddressSize - // The AddressSize parameter references the size, in bytes, of // the Address buffer // // Before the call, set this to the size of the Address buffer. // After the call, it will indicate how many bytes were written // to the Address buffer. // If the Address buffer was too small, this parameter will be // set to the required size and DPERR_BUFFERTOOSMALL returned. // -------------------------------------------------------------------------- bool __fastcall TDx_PlayLobby::CreateAddress( REFGUID pSP, REFGUID pDataType, const void* pData, dword pDataSize, void* pAddress, dword* pAddressSize ) { // Original Function Definition // HRESULT CreateAddress( // REFGUID guidSP, // REFGUID guidDataType, // LPCVOID lpData, // DWORD dwDataSize, // LPVOID lpAddress, // LPDWORD lpdwAddressSize // ); // if the component internals are not already created, exit if (!fCreated) { fErrorValue = TDX_NOTCREATED; if (FOnError) FOnError( this, Name+"::CreateAddress()", "TDX_NOTCREATED", "The "+Name+" component has not been created successfully." ); return false; } // Call Original Function fErrorValue = fLPDIRECTPLAYLOBBY3->CreateAddress( pSP, pDataType, (LPCVOID) pData, (DWORD) pDataSize, (LPVOID) pAddress, (LPDWORD) pAddressSize ); // Handle any Known Results if (fErrorValue!=DP_OK) { // Failure. if (FOnError) FOnError( this, Name+"::CreateAddress()", TDx_Play_Library_ErrorString(fErrorValue), TDx_Play_Library_ErrorMessage(fErrorValue) ); return false; } // Success! return true; } // -------------------------------------------------------------------------- // Method: CreateCompoundAddress() // Description: The CreateCompoundAddress method will create a TDx_Play // address from a network address specific to a service // provider. // // The resulting address is constructed from multiple data // chunks identifying the service provider and includes a // network address the service provider can understand. // // Error values that can be generated are: // // DPERR_BUFFERTOOSMALL // DPERR_INVALIDFLAGS // DPERR_INVALIDPARAMS // Params: pElements - // The Elements parameter references first // TDPCompoundAddressElement component in the array being used // to construct the TDx_Play address. // pElementCount - // The ElementCount parameter defines the number of elements in // the Elements array. // pAddress - // The Address parameter will reference the newly created // address if this method returns successfully. // // Set NULL to retrieve the required buffer size in the // AddressSize parameter. // pAddressSize - // The AddressSize parameter references the size, in bytes, of // the Address buffer // // Before the call, set this to the size of the Address buffer. // After the call, it will indicate how many bytes were written // to the Address buffer. // If the Address buffer was too small, this parameter will be // set to the required size and DPERR_BUFFERTOOSMALL returned. // -------------------------------------------------------------------------- bool __fastcall TDx_PlayLobby::CreateCompoundAddress( TDPCompoundAddressElement* pElements, dword pElementCount, void* pAddress, dword* pAddressSize ) { // Original Function Definition // HRESULT CreateCompoundAddress( // LPDPCOMPOUNDADDRESSELEMENT lpElements, // DWORD dwElementCount, // LPVOID lpAddress, // LPDWORD lpdwAddressSize // ); // if the component internals are not already created, exit if (!fCreated) { fErrorValue = TDX_NOTCREATED; if (FOnError) FOnError( this, Name+"::CreateCompoundAddress()", "TDX_NOTCREATED", "The "+Name+" component has not been created successfully." ); return false; } // Call Original Function fErrorValue = fLPDIRECTPLAYLOBBY3->CreateCompoundAddress( (pElements==NULL) ? NULL : pElements->Internal_DPCOMPOUNDADDRESSELEMENT_Ptr, (DWORD) pElementCount, (LPVOID) pAddress, (LPDWORD) pAddressSize ); // Translate Data returned from Function if (pElements!=NULL) pElements->Internal_DPCOMPOUNDADDRESSELEMENT_Update(); // Handle any Known Results if (fErrorValue!=DP_OK) { // Failure. if (FOnError) FOnError( this, Name+"::CreateCompoundAddress()", TDx_Play_Library_ErrorString(fErrorValue), TDx_Play_Library_ErrorMessage(fErrorValue) ); return false; } // Success! return true; } // -------------------------------------------------------------------------- // Method: Destroy() // Description: The Destroy() method is used to automatically destroy the // internal LPDIRECTPLAYLOBBY3 interface used in the // TDx_PlayLobby component and should be called when the // internal interface is no longer required. // // Note: This method is called by the component's destructor. // -------------------------------------------------------------------------- bool __fastcall TDx_PlayLobby::Destroy() { // if the component internals are not already created, exit if (!fCreated) { if (FOnError) FOnError( this, Name+"::Destroy()", "TDX_NOTCREATED", "The "+Name+"::Destroy() method was called before the component was created successfully." ); return false; } // exit if there is no lobby to destroy if (fLPDIRECTPLAYLOBBY3==NULL) { if (FOnError) FOnError( this, Name+"::Destroy()", "TDX_ERROR", "The "+Name+" component's internal IDirectPlayLobby interface is NULL but the TDx_PlayLobby component is expecting it to be not NULL. Aborting the Destroy()." ); return false; } // call the OnDestroy() event try { if (FOnDestroy) FOnDestroy(this); } catch (...) { fErrorValue = TDX_ERROR; if (FOnError) FOnError( this, Name+"::Destroy()", "TDX_ERROR", "An exception has occurred within "+Name+"::OnDestroy()" ); } // destroy the internal interface try { if (fLPDIRECTPLAYLOBBY3!=NULL) fLPDIRECTPLAYLOBBY3->Release(); } catch (...) { fErrorValue = TDX_ERROR; if (FOnError) FOnError( this, Name+"::Destroy()", "TDX_ERROR", "An exception has occurred within LPDIRECTPLAYLOBBY->Release(). Check that you are destroying all components in reverse order of creation." ); } // successful destruction fCreated = false; fLPDIRECTPLAYLOBBY3 = NULL; fLPDIRECTPLAYLOBBY = NULL; CoUninitialize(); return true; } // -------------------------------------------------------------------------- // Method: EnumAddress() // Description: The EnumAddress method will identify and parse data chunks // from a TDx_Play address. // // The TDx_PlayLobby::OnEnumAddress() event will be called for // each data chunk enumerated. // // Error values that can be generated are: // // DPERR_EXCEPTION // DPERR_INVALIDOBJECT // DPERR_INVALIDPARAMS // Params: pAddress - // The Address parameter references the TDx_Play address to be // parsed. // pAddressSize - // The AddressSize parameter defines the size, in bytes, of the // address being enumerated. // pContext - // The Context parameter references application defined data to // be passed to the callback function each time it is called. // -------------------------------------------------------------------------- bool __fastcall TDx_PlayLobby::EnumAddress( const void* pAddress, dword pAddressSize, void* pContext ) { // Original Function Definition // HRESULT EnumAddress( // LPDPENUMADDRESSCALLBACK lpEnumAddressCallback, // LPCVOID lpAddress, // DWORD dwAddressSize, // LPVOID lpContext // ); // if the component internals are not already created, exit if (!fCreated) { fErrorValue = TDX_NOTCREATED; if (FOnError) FOnError( this, Name+"::EnumAddress()", "TDX_NOTCREATED", "The "+Name+" component has not been created successfully." ); return false; } // Call Original Function TDx_PlayLobby_OnEnumAddressOwner = this; fErrorValue = fLPDIRECTPLAYLOBBY3->EnumAddress( Internal_EnumAddressCallback, (LPCVOID) pAddress, (DWORD) pAddressSize, (LPVOID) pContext ); TDx_PlayLobby_OnEnumAddressOwner = NULL; // Handle any Known Results if (fErrorValue!=DP_OK) { // Failure. if (FOnError) FOnError( this, Name+"::EnumAddress()", TDx_Play_Library_ErrorString(fErrorValue), TDx_Play_Library_ErrorMessage(fErrorValue) ); return false; } // Success! return true; } // -------------------------------------------------------------------------- // Method: EnumAddressTypes() // Description: The EnumAddressTypes method will enumerate the address types // the specified service provider will need when building a // TDx_Play address. // // The TDx_PlayLobby::OnEnumAddressTypes() event will be called // for each address type enumerated. // // Error values that can be generated are: // // DPERR_EXCEPTION // DPERR_INVALIDOBJECT // DPERR_INVALIDPARAMS // Params: pSP - // The SP parameter identifies the service provider whose // address types are to be enumerated. // pContext - // The Context parameter references application defined data to // be passed to the callback function each time it is called. // -------------------------------------------------------------------------- bool __fastcall TDx_PlayLobby::EnumAddressTypes( REFGUID pSP, void* pContext ) { // Original Function Definition // HRESULT EnumAddressTypes( // LPDPLENUMADDRESSTYPESCALLBACK pEnumAddressTypeCallback, // REFGUID guidSP, // LPVOID lpContext, // DWORD dwFlags // ); // if the component internals are not already created, exit if (!fCreated) { fErrorValue = TDX_NOTCREATED; if (FOnError) FOnError( this, Name+"::EnumAddressTypes()", "TDX_NOTCREATED", "The "+Name+" component has not been created successfully." ); return false; } // Call Original Function TDx_PlayLobby_OnEnumAddressTypesOwner = this; fErrorValue = fLPDIRECTPLAYLOBBY3->EnumAddressTypes( Internal_EnumAddressTypesCallback, pSP, (LPVOID) pContext, 0 ); TDx_PlayLobby_OnEnumAddressTypesOwner = NULL; // Handle any Known Results if (fErrorValue!=DP_OK) { // Failure. if (FOnError) FOnError( this, Name+"::EnumAddressTypes()", TDx_Play_Library_ErrorString(fErrorValue), TDx_Play_Library_ErrorMessage(fErrorValue) ); return false; } // Success! return true; } // -------------------------------------------------------------------------- // Method: EnumLocalApplications() // Description: The EnumLocalApplications method will enumerate any // applications that have been registered using // TDx_PlayLobby::RegisterApplication(). // // The TDx_PlayLobby::OnEnumLocalApplications() event will be // called for each application enumerated. // // Error values that can be generated are: // // DPERR_GENERIC // DPERR_INVALIDINTERFACE // DPERR_INVALIDOBJECT // DPERR_INVALIDPARAMS // DPERR_OUTOFMEMORY // Params: pContext - // The Context parameter references application defined data to // be passed to the callback function each time it is called. // -------------------------------------------------------------------------- bool __fastcall TDx_PlayLobby::EnumLocalApplications( void* pContext ) { // Original Function Definition // HRESULT EnumLocalApplications( // LPDPENUMLOCALAPPLICATIONSCALLBACK lpEnumLocalAppCallback, // LPVOID lpContext, // DWORD dwFlags // ); // if the component internals are not already created, exit if (!fCreated) { fErrorValue = TDX_NOTCREATED; if (FOnError) FOnError( this, Name+"::EnumLocalApplications()", "TDX_NOTCREATED", "The "+Name+" component has not been created successfully." ); return false; } // Call Original Function TDx_PlayLobby_OnEnumLocalApplicationsOwner = this; fErrorValue = fLPDIRECTPLAYLOBBY3->EnumLocalApplications( Internal_EnumLocalApplicationsCallback, (LPVOID) pContext, 0 ); TDx_PlayLobby_OnEnumLocalApplicationsOwner = NULL; // Handle any Known Results if (fErrorValue!=DP_OK) { // Failure. if (FOnError) FOnError( this, Name+"::EnumLocalApplications()", TDx_Play_Library_ErrorString(fErrorValue), TDx_Play_Library_ErrorMessage(fErrorValue) ); return false; } // Success! return true; } // -------------------------------------------------------------------------- // Method: GetConnectionSettings() // Description: The GetConnectionSettings method will retrieve the // TDPLConnection information associated with the lobby. // // These connection settings are used to start and connect a // specific application. // They will be identical to those passed to // TDx_PlayLobby::RunApplication() by the lobby client or set // using TDx_PlayLobby::SetConnectionSettings(). // // Error values that can be generated are: // // DPERR_BUFFERTOOSMALL // DPERR_GENERIC // DPERR_INVALIDINTERFACE // DPERR_INVALIDOBJECT // DPERR_INVALIDPARAMS // DPERR_NOTLOBBIED // DPERR_OUTOFMEMORY // Params: pAppID - // The AppID parameter identifies the application for which the // connection settings are to be retrieved. // // Only set this parameter when the method is called from a // lobby client. // Zero should be set when calling the method from an // application. // pData - // The Data parameter will reference the connection settings if // the method returns successfully. // // Set NULL to retrieve the required buffer size in the DataSize // parameter. // pDataSize - // The DataSize parameter references the size, in bytes, of the // Data buffer. // // Before the call, set this to the size of the Data buffer. // After the call, it will indicate how many bytes were written // to the Data buffer. // If the Data buffer was too small, this parameter will be set // to the required size and DPERR_BUFFERTOOSMALL returned. // -------------------------------------------------------------------------- bool __fastcall TDx_PlayLobby::GetConnectionSettings( dword pAppID, void* pData, dword* pDataSize ) { // Original Function Definition // HRESULT GetConnectionSettings( // DWORD dwAppID, // LPVOID lpData, // LPDWORD lpdwDataSize // ); // if the component internals are not already created, exit if (!fCreated) { fErrorValue = TDX_NOTCREATED; if (FOnError) FOnError( this, Name+"::GetConnectionSettings()", "TDX_NOTCREATED", "The "+Name+" component has not been created successfully." ); return false; } // Call Original Function fErrorValue = fLPDIRECTPLAYLOBBY3->GetConnectionSettings( (DWORD) pAppID, (LPVOID) pData, (LPDWORD) pDataSize ); // Handle any Known Results if (fErrorValue!=DP_OK) { // Failure. if (FOnError) FOnError( this, Name+"::GetConnectionSettings()", TDx_Play_Library_ErrorString(fErrorValue), TDx_Play_Library_ErrorMessage(fErrorValue) ); return false; } // Success! return true; } // -------------------------------------------------------------------------- // Method: Internal_EnumAddressCallback() // Description: The Internal_EnumAddressCallback method is used to process // enumeration for TDx_PlayLobby::EnumAddress(). // Params: pDataType - // The DataType parameter // pDataSize - // The DataSize parameter // pData - // The Data parameter // pContext - // The Context parameter // -------------------------------------------------------------------------- BOOL __stdcall TDx_PlayLobby::Internal_EnumAddressCallback( REFGUID pDataType, DWORD pDataSize, LPCVOID pData, LPVOID pContext ) { // Original Function Definition GUID DataType = pDataType; dword DataSize = pDataSize; const void* Data = pData; void* Context = pContext; bool fContinue = true; // Call Original Function if (TDx_PlayLobby_OnEnumAddressOwner->OnEnumAddress) TDx_PlayLobby_OnEnumAddressOwner->OnEnumAddress( TDx_PlayLobby_OnEnumAddressOwner, DataType, DataSize, Data, Context, fContinue ); // Finished! return fContinue; } // -------------------------------------------------------------------------- // Method: Internal_EnumAddressTypesCallback() // Description: The Internal_EnumAddressTypesCallback method is used to // process enumeration for TDx_PlayLobby::EnumAddressTypes(). // Params: pDataType - // The DataType parameter // pContext - // The Context parameter // pFlags - // The Flags parameter // -------------------------------------------------------------------------- BOOL __stdcall TDx_PlayLobby::Internal_EnumAddressTypesCallback( REFGUID pDataType, LPVOID pContext, DWORD pFlags ) { // Original Function Definition GUID DataType = pDataType; void* Context = pContext; dword Flags = pFlags; bool fContinue = true; // Call Original Function if (TDx_PlayLobby_OnEnumAddressTypesOwner->OnEnumAddressTypes) TDx_PlayLobby_OnEnumAddressTypesOwner->OnEnumAddressTypes( TDx_PlayLobby_OnEnumAddressTypesOwner, DataType, Context, Flags, fContinue); // Finished! return fContinue; } // -------------------------------------------------------------------------- // Method: Internal_EnumLocalApplicationsCallback() // Description: The Internal_EnumLocalApplicationsCallback method is used to // process enumeration for // TDx_PlayLobby::EnumLocalApplicationsCallback(). // Params: pAppInfo - // The AppInfo parameter // pContext - // The Context parameter // pFlags - // The Flags parameter // -------------------------------------------------------------------------- BOOL __stdcall TDx_PlayLobby::Internal_EnumLocalApplicationsCallback( LPCDPLAPPINFO pAppInfo, LPVOID pContext, DWORD pFlags ) { // Original Function Definition void* Context = pContext; dword Flags = pFlags; bool fContinue = true; /* typedef struct { DWORD dwSize; GUID guidApplication; union { LPSTR lpszAppNameA; LPWSTR lpszAppName; }; } */ TDPLAppInfo* AppInfo = new TDPLAppInfo( NULL ); if (pAppInfo != NULL) { AppInfo->Application = pAppInfo->guidApplication; if (TDx_PlayLobby_OnEnumLocalApplicationsOwner->UseAnsiString) { AnsiString temp1 = (char*) pAppInfo->lpszAppNameA; AppInfo->AppNameA = temp1; } else { AnsiString temp1 = (char*) pAppInfo->lpszAppName; AppInfo->AppName = temp1; } } else { AppInfo->Application = GUID_NULL; if (TDx_PlayLobby_OnEnumLocalApplicationsOwner->UseAnsiString) { AppInfo->AppNameA = "Null passed to callback for lpappinfo"; } else { AppInfo->AppName = ""; } } if (TDx_PlayLobby_OnEnumLocalApplicationsOwner->OnEnumLocalApplications) TDx_PlayLobby_OnEnumLocalApplicationsOwner->OnEnumLocalApplications( TDx_PlayLobby_OnEnumLocalApplicationsOwner, AppInfo, Context, Flags, fContinue); delete AppInfo; // Finished! return fContinue; } // -------------------------------------------------------------------------- // Method: ReceiveLobbyMessage() // Description: The ReceiveLobbyMessage method will retrieve messages sent // between lobby client and application. // // Error values that can be generated are: // // DPERR_APPNOTSTARTED // DPERR_BUFFERTOOSMALL // DPERR_GENERIC // DPERR_INVALIDINTERFACE // DPERR_INVALIDOBJECT // DPERR_INVALIDPARAMS // DPERR_NOMESSAGES // DPERR_OUTOFMEMORY // Params: pAppID - // The AppID parameter identifies which applications messages to // retrieve. // // Only valid when the method is being called by a lobby client. // Set zero when calling from an application. // pMessageFlags - // The MessageFlags parameter defines flags indicating the type // of message being retrieved. // The described effect applies when the flag is set. // // The default setting of zero indicates a custom message // defined by the sender. // Flags: // DPLMSG_STANDARD - // The message is a standard DirectPlay defined message. // // Processing of the message is optional. // DPLMSG_SYSTEM - // The message was generated by the system to inform the // lobby of application status changes. // pData - // The Data parameter will reference the retrieved message if // the method returns successfully. // // Set NULL to retrieve the required buffer size in the DataSize // parameter. // pDataSize - // The DataSize parameter references the size, in bytes, of the // Data buffer. // // Before the call, set this to the size of the Data buffer. // After the call, it will indicate how many bytes were written // to the Data buffer. // If the Data buffer was too small, this parameter will be set // to the required size and DPERR_BUFFERTOOSMALL returned. // -------------------------------------------------------------------------- bool __fastcall TDx_PlayLobby::ReceiveLobbyMessage( dword pAppID, dword* pMessageFlags, void* pData, dword* pDataSize ) { // Original Function Definition // HRESULT ReceiveLobbyMessage( // DWORD dwFlags, // DWORD dwAppID, // LPDWORD lpdwMessageFlags, // LPVOID lpData, // LPDWORD lpdwDataSize // ); // if the component internals are not already created, exit if (!fCreated) { fErrorValue = TDX_NOTCREATED; if (FOnError) FOnError( this, Name+"::ReceiveLobbyMessage()", "TDX_NOTCREATED", "The "+Name+" component has not been created successfully." ); return false; } // Call Original Function fErrorValue = fLPDIRECTPLAYLOBBY3->ReceiveLobbyMessage( 0, (DWORD) pAppID, (LPDWORD) pMessageFlags, (LPVOID) pData, (LPDWORD) pDataSize ); // Handle any Known Results if (fErrorValue!=DP_OK) { // Failure. if (FOnError) FOnError( this, Name+"::ReceiveLobbyMessage()", TDx_Play_Library_ErrorString(fErrorValue), TDx_Play_Library_ErrorMessage(fErrorValue) ); return false; } // Success! return true; } // -------------------------------------------------------------------------- // Method: ReceiveLobbyMessageEx() // Description: The ReceiveLobbyMessageEx method will retrieve messages sent // between lobby client and application, generating OnDPLMSG_x // events when appropriate. // // Error values that can be generated are: // // DPERR_APPNOTSTARTED // DPERR_BUFFERTOOSMALL // DPERR_GENERIC // DPERR_INVALIDINTERFACE // DPERR_INVALIDOBJECT // DPERR_INVALIDPARAMS // DPERR_NOMESSAGES // DPERR_OUTOFMEMORY // Params: pAppID - // The AppID parameter identifies which applications messages to // retrieve. // // Only valid when the method is being called by a lobby client. // Set zero when calling from an application. // -------------------------------------------------------------------------- bool __fastcall TDx_PlayLobby::ReceiveLobbyMessageEx( DWORD pAppID ) { // Original Function Definition // HRESULT ReceiveLobbyMessage( // DWORD dwFlags, // DWORD dwAppID, // LPDWORD lpdwMessageFlags, // LPVOID lpData, // LPDWORD lpdwDataSize // ); byte* fData = NULL; dword fMessageFlags = 0; dword fDataSize = 0; // loop until a single message is successfully read do { // read message from specified player if (fLPDIRECTPLAYLOBBY3!=NULL) fErrorValue = fLPDIRECTPLAYLOBBY3->ReceiveLobbyMessage( 0, (DWORD) pAppID, (LPDWORD) &fMessageFlags, (LPVOID) fData, (LPDWORD) fDataSize ); //if not enough room then resize buffer if (fErrorValue == DPERR_BUFFERTOOSMALL) { if (fData) delete fData ; fData = new byte[fDataSize]; if (fData == NULL) fErrorValue = DPERR_OUTOFMEMORY; } } while (fErrorValue == DPERR_BUFFERTOOSMALL); if ((fErrorValue == DP_OK) && // successfully read a message (fDataSize >= sizeof(DPLMSG_GENERIC))) // and it is big enough { // determine type of message LPDPMSG_GENERIC generic = (LPDPMSG_GENERIC) fData; dword msg_type = generic->dwType; //separate system and standard messages if (fMessageFlags & DPLMSG_STANDARD) { // a standard message if (OnGeneric) OnGeneric(this, pAppID, fData, fDataSize, msg_type); } else { // all system messages switch (msg_type) { case DPLSYS_GETPROPERTY: { if (OnGetProperty) { LPDPLMSG_GETPROPERTY fTemp = (LPDPLMSG_GETPROPERTY) fData; OnGetProperty(this, fTemp->dwRequestID, fTemp->guidPlayer, fTemp->guidPropertyTag); } break; } case DPLSYS_GETPROPERTYRESPONSE: { if (OnGetPropertyResponse) { LPDPLMSG_GETPROPERTYRESPONSE fTemp = (LPDPLMSG_GETPROPERTYRESPONSE) fData; OnGetPropertyResponse(this, fTemp->dwRequestID, fTemp->guidPlayer, fTemp->guidPropertyTag, fTemp->hr, fTemp->dwDataSize, fTemp->dwPropertyData);//array of dwords - use pointer! } break; } case DPLSYS_NEWSESSIONHOST: { if (OnNewSessionHost) { LPDPLMSG_NEWSESSIONHOST fTemp = (LPDPLMSG_NEWSESSIONHOST) fData; OnNewSessionHost(this, fTemp->guidInstance); } break; } case DPLSYS_SETPROPERTY: { if (OnSetProperty) { LPDPLMSG_SETPROPERTY fTemp = (LPDPLMSG_SETPROPERTY) fData; OnSetProperty(this, fTemp->dwRequestID, fTemp->guidPlayer, fTemp->guidPropertyTag, fTemp->dwDataSize, fTemp->dwPropertyData);//array of dwords - use pointer! } break; } case DPLSYS_SETPROPERTYRESPONSE: { if (OnSetPropertyResponse) { LPDPLMSG_SETPROPERTYRESPONSE fTemp = (LPDPLMSG_SETPROPERTYRESPONSE) fData; OnSetPropertyResponse(this, fTemp->dwRequestID, fTemp->guidPlayer, fTemp->guidPropertyTag, fTemp->hr); } break; } case DPLSYS_APPTERMINATED: { if (OnAppTerminated) { LPDPLMSG_SYSTEMMESSAGE fTemp = (LPDPLMSG_SYSTEMMESSAGE) fData; OnAppTerminated(this, fTemp->guidInstance); } break; } case DPLSYS_CONNECTIONSETTINGSREAD : { if (OnConnectionSettingsRead) { LPDPLMSG_SYSTEMMESSAGE fTemp = (LPDPLMSG_SYSTEMMESSAGE) fData; OnConnectionSettingsRead(this, fTemp->guidInstance); } break; } case DPLSYS_DPLAYCONNECTFAILED : { if (OnPlayConnectFailed) { LPDPLMSG_SYSTEMMESSAGE fTemp = (LPDPLMSG_SYSTEMMESSAGE) fData; OnPlayConnectFailed(this, fTemp->guidInstance); } break; } case DPLSYS_DPLAYCONNECTSUCCEEDED: { if (OnPlayConnectSucceeded) { LPDPLMSG_SYSTEMMESSAGE fTemp = (LPDPLMSG_SYSTEMMESSAGE) fData; OnPlayConnectSucceeded(this, fTemp->guidInstance); } break; } case DPLSYS_NEWCONNECTIONSETTINGS : { if (OnNewConnectionSettings) { LPDPLMSG_SYSTEMMESSAGE fTemp = (LPDPLMSG_SYSTEMMESSAGE) fData; OnNewConnectionSettings(this, fTemp->guidInstance); } break; } default : if (FOnError) FOnError( this, Name+"::ReceiveLobbyMessage()", "TDX_ERROR", "Unlisted system message found." ); } } } // Handle any Known Results if (fErrorValue!=DP_OK) { // Failure. if (FOnError) FOnError( this, Name+"::ReceiveLobbyMessage()", TDx_Play_Library_ErrorString(fErrorValue), TDx_Play_Library_ErrorMessage(fErrorValue) ); return false; } // Finished! return true; } // -------------------------------------------------------------------------- // Method: RegisterApplication() // Description: The RegisterApplication method is used to register lobby // aware applications with DirectPlay so they can be launched by // a lobby. // // Registration need only be done once and // TDx_PlayLobby::UnregisterApplication() can be used to // unregister an application when it is uninstalled. // // Error values that can be generated are: // // DPERR_INVALIDFLAGS // DPERR_INVALIDPARAMS // Params: pAppDesc - // The AppDesc parameter references a TDPApplicationDesc // component holding the values required to register the // application. // -------------------------------------------------------------------------- HRESULT __fastcall TDx_PlayLobby::RegisterApplication( TDPApplicationDesc* pAppDesc ) { // Original Function Definition // HRESULT RegisterApplication( // DWORD dwFlags, // LPDPAPPLICATIONDESC2 lpAppDesc // ); // if the component internals are not already created, exit if (!fCreated) { fErrorValue = TDX_NOTCREATED; if (FOnError) FOnError( this, Name+"::RegisterApplication()", "TDX_NOTCREATED", "The "+Name+" component has not been created successfully." ); return false; } // Call Original Function fErrorValue = fLPDIRECTPLAYLOBBY3->RegisterApplication( 0, (pAppDesc==NULL) ? NULL : pAppDesc->Internal_DPAPPLICATIONDESC2_Ptr ); // Translate Data returned from Function if (pAppDesc!=NULL) pAppDesc->Internal_DPAPPLICATIONDESC2_Update(); // Success! return fErrorValue; } // -------------------------------------------------------------------------- // Method: RunApplication() // Description: The RunApplication method allows a lobby client to start an // application, passing it all the required session connection // information. // // Once the application process has been created, the lobby // client will receive a system message indicating the // applications status. // // If the application is hosting the session, wait for a // DPLSYS_DPLAYCONNECTSUCCEEDED message before starting other // applications that wish to join the session. // // Failure to create or join a session generates a // DPLSYS_DPLAYCONNECTFAILED message and a terminating // application will generate a DPLSYS_APPTERMINATED message. // // Once the application has read the connection settings, it // sends a DPLSYS_CONNECTIONSETTINGSREAD message. Do not release // the lobby interface until this message is retrieved by either // the synchronization event or a call to // TDx_PlayLobby::ReceiveLobbyMessage() or // TDx_PlayLobby::ReceiveLobbyMessageEx(). // // Error values that can be generated are: // // DPERR_CANTCREATEPROCESS // DPERR_GENERIC // DPERR_INVALIDINTERFACE // DPERR_INVALIDOBJECT // DPERR_INVALIDPARAMS // DPERR_OUTOFMEMORY // DPERR_UNKNOWNAPPLICATION // Params: pAppID - // The AppID parameter reference the identifier assigned to the // application if the method returns successfully. // // This identifier is used by TDx_PlayLobby::SendLobbyMessage() // and TDx_PlayLobby::ReceiveLobbyMessage(). // pConn - // The Conn parameter references a TDPLConnection component // detailing which application to start and the relevant session // connection information. // -------------------------------------------------------------------------- bool __fastcall TDx_PlayLobby::RunApplication( dword* pAppID, TDPLConnection* pConn ) { // Original Function Definition // HRESULT RunApplication( // DWORD dwFlags, // LPDWORD lpdwAppID, // LPDPLCONNECTION lpConn, // HANDLE hReceiveEvent // ); // if the component internals are not already created, exit if (!fCreated) { fErrorValue = TDX_NOTCREATED; if (FOnError) FOnError( this, Name+"::RunApplication()", "TDX_NOTCREATED", "The "+Name+" component has not been created successfully." ); return false; } //create players event HANDLE fEvent = CreateEvent(NULL,FALSE,FALSE,NULL); if (fEvent == NULL) { fErrorValue = DPERR_NOMEMORY; if (FOnError) FOnError( this, Name+"::RunApplication()", TDx_Play_Library_ErrorString(fErrorValue), TDx_Play_Library_ErrorMessage(fErrorValue)); return false; } // Call Original Function fErrorValue = fLPDIRECTPLAYLOBBY3->RunApplication( 0, (LPDWORD) pAppID, (pConn==NULL) ? NULL : pConn->Internal_DPLCONNECTION_Ptr, fEvent ); // Translate Data returned from Function if (pConn!=NULL) pConn->Internal_DPLCONNECTION_Update(); // Handle any Known Results if (fErrorValue!=DP_OK) { // Failure. if (FOnError) FOnError( this, Name+"::RunApplication()", TDx_Play_Library_ErrorString(fErrorValue), TDx_Play_Library_ErrorMessage(fErrorValue) ); return false; } else { // pause existing thread if (TDx_PlayLobby_Thread) TDx_PlayLobby_Thread->Pause(); // add player event to array for message receive fLobbyEvents->Add( (void*) fEvent ); // HANDLE fNumLobbies = fNumLobbies + 1; // restart the thread if (TDx_PlayLobby_Thread) { TDx_PlayLobby_Thread->HandlesModified = true; TDx_PlayLobby_Thread->Restart(); } } // Success! return true; } // -------------------------------------------------------------------------- // Method: SendLobbyMessage() // Description: The SendLobbyMessage method will send messages between lobby // client and application. // // Error values that can be generated are: // // DPERR_APPNOTSTARTED // DPERR_BUFFERTOOLARGE // DPERR_GENERIC // DPERR_INVALIDINTERFACE // DPERR_INVALIDOBJECT // DPERR_INVALIDPARAMS // DPERR_OUTOFMEMORY // DPERR_TIMEOUT // Params: pFlags - // The Flags parameter defines flags indicating the type of // message being sent. // The described effect applies when the flag is set. // // The default setting of zero indicates an application defined // message is being sent. // Flags: // DPLMSG_STANDARD - // The message is a standard DirectPlay defined message. // pAppID - // The AppID parameter identifies the destination application // for the message. // // Set zero when the method is called from an application. // This is the identifier returned by // TDx_PlayLobby::RunApplication(). // pData - // The Data parameter references the message data to be sent. // // The standard DirectX message structures used when // DPLMSG_STANDARD is set are: // // typedef struct { // dword Type; // dword RequestID; // GUID Player; // GUID PropertyTag; // } TDPLMSG_GetProperty, FAR *LPDPLMSG_GetProperty; // // // typedef struct { // dword Type; // dword RequestID; // GUID Player; // GUID PropertyTag; // dword DataSize; // dword PropertyData[1]; // } TDPLMSG_SetProperty, FAR *LPDPLMSG_SetProperty; // // For the above structures, the following descriptions apply to // their members. // // Type // The type of system message that is being sent. // Possible values are DPLSYS_GETPROPERTY and DPLSYS_SETPROPERTY // respectivly. // A system DPLSYS_GETPROPERTYRESPONSE or // DPLSYS_SETPROPERTYRESPONSE will be triggered. // // RequestID // An application defined unique identifier used to match // requests to lobby responses. // // Player // The GUID of the player the property applies to. // Non player specific information will have this set to // GUID_NULL. // // PropertyTag // The GUID of the property being set. Standard DirectX // properties are: // // DPLPROPERTY_LobbyGuid // DPLPROPERTY_MessagesSupported // DPLPROPERTY_PlayerGuid // DPLPROPERTY_PlayerScore // // DataSize // The size of the property data. // // PropertyData // A buffer of information that is to be interpreted based on // the PropertyTag member. // pDataSize - // The DataSize parameter defines the size, in bytes, of the // Data buffer. // -------------------------------------------------------------------------- bool __fastcall TDx_PlayLobby::SendLobbyMessage( dword pFlags, dword pAppID, void* pData, dword pDataSize ) { // Original Function Definition // HRESULT SendLobbyMessage( // DWORD dwFlags, // DWORD dwAppID, // LPVOID lpData, // DWORD dwDataSize // ); // if the component internals are not already created, exit if (!fCreated) { fErrorValue = TDX_NOTCREATED; if (FOnError) FOnError( this, Name+"::SendLobbyMessage()", "TDX_NOTCREATED", "The "+Name+" component has not been created successfully." ); return false; } // Call Original Function fErrorValue = fLPDIRECTPLAYLOBBY3->SendLobbyMessage( (DWORD) pFlags, (DWORD) pAppID, (LPVOID) pData, (DWORD) pDataSize ); // Handle any Known Results if (fErrorValue!=DP_OK) { // Failure. if (FOnError) FOnError( this, Name+"::SendLobbyMessage()", TDx_Play_Library_ErrorString(fErrorValue), TDx_Play_Library_ErrorMessage(fErrorValue) ); return false; } // Success! return true; } // -------------------------------------------------------------------------- // Method: SetConnectionSettings() // Description: The SetConnectionSettings method will modify the application // start and connection information associated with the lobby. // // Error values that can be generated are: // // DPERR_GENERIC // DPERR_INVALIDINTERFACE // DPERR_INVALIDOBJECT // DPERR_INVALIDPARAMS // DPERR_OUTOFMEMORY // Params: pAppID - // The AppID parameter identifies which applications connection // settings are being changed. // // Set zero when the method is called from an application. // This is the identifier returned by // TDx_PlayLobby::RunApplication(). // pConn - // The Conn parameter references a TDPLConnection component // holding the new connection information. // -------------------------------------------------------------------------- bool __fastcall TDx_PlayLobby::SetConnectionSettings( dword pAppID, TDPLConnection* pConn ) { // Original Function Definition // HRESULT SetConnectionSettings( // DWORD dwFlags, // DWORD dwAppID, // LPDPLCONNECTION lpConn // ); // if the component internals are not already created, exit if (!fCreated) { fErrorValue = TDX_NOTCREATED; if (FOnError) FOnError( this, Name+"::SetConnectionSettings()", "TDX_NOTCREATED", "The "+Name+" component has not been created successfully." ); return false; } // Call Original Function fErrorValue = fLPDIRECTPLAYLOBBY3->SetConnectionSettings( 0, (DWORD) pAppID, (pConn==NULL) ? NULL : pConn->Internal_DPLCONNECTION_Ptr ); // Translate Data returned from Function if (pConn!=NULL) pConn->Internal_DPLCONNECTION_Update(); // Handle any Known Results if (fErrorValue!=DP_OK) { // Failure. if (FOnError) FOnError( this, Name+"::SetConnectionSettings()", TDx_Play_Library_ErrorString(fErrorValue), TDx_Play_Library_ErrorMessage(fErrorValue) ); return false; } // Success! return true; } // -------------------------------------------------------------------------- // Method: UnregisterApplication() // Description: The UnRegisterApplication method is used to deregister a // lobby aware application so the uninstall process can be // complete. // // Error values that can be generated are: // // DPERR_INVALIDFLAGS // DPERR_INVALIDPARAMS // DPERR_UNKNOWNAPPLICATION // Params: pApplication - // The Application parameter identifies which applications // registry entries to delete. // -------------------------------------------------------------------------- bool __fastcall TDx_PlayLobby::UnregisterApplication( REFGUID pApplication ) { // Original Function Definition // HRESULT UnregisterApplication( // DWORD dwFlags, // REFGUID guidApplication // ); // if the component internals are not already created, exit if (!fCreated) { fErrorValue = TDX_NOTCREATED; if (FOnError) FOnError( this, Name+"::UnregisterApplication()", "TDX_NOTCREATED", "The "+Name+" component has not been created successfully." ); return false; } // Call Original Function fErrorValue = fLPDIRECTPLAYLOBBY3->UnregisterApplication( 0, pApplication ); // Handle any Known Results if (fErrorValue!=DP_OK) { // Failure. if (FOnError) FOnError( this, Name+"::UnregisterApplication()", TDx_Play_Library_ErrorString(fErrorValue), TDx_Play_Library_ErrorMessage(fErrorValue) ); return false; } // Success! return true; } // -------------------------------------------------------------------------- // Method: WaitForConnectionSettings() // Description: The WaitForConnectionSettings method will make an application // wait for connection settings. // // When the lobby client calls TDx_PlayLobby::RunApplication(), // it will not create a new application instance, instead // sending a DPLSYS_NEWCONNECTIONSETTINGS message to the waiting // application. // // The application can then obtain the connection settings with // TDx_PlayLobby::GetConnectionSettings() and use // TDx_PlayLobby::ConnectEx() to join the session. // // Error values that can be generated are: // // DPERR_INVALIDFLAGS // DPERR_UNAVAILABLE // Params: pFlags - // The Flags parameter defines a flag indicating whether wait // mode should be activated or cancelled. // The described effect applies when the flag is set. // // The default value of zero indicates the application should be // placed in wait mode. // Flags: // DPLWAIT_CANCEL - // Take the application out of wait mode. // // This will occur automatically on receipt of a // DPLSYS_NEWCONNECTIONSETTINGS message by the // application. // -------------------------------------------------------------------------- bool __fastcall TDx_PlayLobby::WaitForConnectionSettings( dword pFlags ) { // Original Function Definition // HRESULT WaitForConnectionSettings( // DWORD dwFlags // ); // if the component internals are not already created, exit if (!fCreated) { fErrorValue = TDX_NOTCREATED; if (FOnError) FOnError( this, Name+"::WaitForConnectionSettings()", "TDX_NOTCREATED", "The "+Name+" component has not been created successfully." ); return false; } // Call Original Function fErrorValue = fLPDIRECTPLAYLOBBY3->WaitForConnectionSettings( (DWORD) pFlags ); // Handle any Known Results if (fErrorValue!=DP_OK) { // Failure. if (FOnError) FOnError( this, Name+"::WaitForConnectionSettings()", TDx_Play_Library_ErrorString(fErrorValue), TDx_Play_Library_ErrorMessage(fErrorValue) ); return false; } // Success! return true; } // -------------------------------------------------------------------------- // Internal Interface Access // -------------------------------------------------------------------------- LPDIRECTPLAYLOBBY3 __fastcall TDx_PlayLobby::FGetInternal_LPDIRECTPLAYLOBBY3() { return fLPDIRECTPLAYLOBBY3; } // -------------------------------------------------------------------------- LPDIRECTPLAYLOBBY3* __fastcall TDx_PlayLobby::FGetInternal_LPDIRECTPLAYLOBBY3_Ptr() { return &fLPDIRECTPLAYLOBBY3; } // -------------------------------------------------------------------------- void __fastcall TDx_PlayLobby::FSetInternal_LPDIRECTPLAYLOBBY3( LPDIRECTPLAYLOBBY3 pLPDIRECTPLAYLOBBY3 ) { if (!fCreated) { fLPDIRECTPLAYLOBBY3 = pLPDIRECTPLAYLOBBY3; fCreated = (fLPDIRECTPLAYLOBBY3!=NULL); } } // -------------------------------------------------------------------------- void __fastcall TDx_PlayLobby::Internal_LPDIRECTPLAYLOBBY3_Update() { fCreated = (fLPDIRECTPLAYLOBBY3!=NULL); } // -------------------------------------------------------------------------- LPDIRECTPLAYLOBBY __fastcall TDx_PlayLobby::FGetInternal_LPDIRECTPLAYLOBBY() { return fLPDIRECTPLAYLOBBY; } // -------------------------------------------------------------------------- LPDIRECTPLAYLOBBY* __fastcall TDx_PlayLobby::FGetInternal_LPDIRECTPLAYLOBBY_Ptr() { return &fLPDIRECTPLAYLOBBY; } // -------------------------------------------------------------------------- void __fastcall TDx_PlayLobby::FSetInternal_LPDIRECTPLAYLOBBY( LPDIRECTPLAYLOBBY pLPDIRECTPLAYLOBBY ) { if (!fCreated) { fLPDIRECTPLAYLOBBY = pLPDIRECTPLAYLOBBY; fCreated = (fLPDIRECTPLAYLOBBY!=NULL); } } // -------------------------------------------------------------------------- void __fastcall TDx_PlayLobby::Internal_LPDIRECTPLAYLOBBY_Update() { fCreated = (fLPDIRECTPLAYLOBBY3!=NULL); } // --------------------------------------------------------------------------