|
|
/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
DirectPlayEnumOrder.cpp
Abstract:
Certain applications (Midtown Madness) expects the DPLAY providers to enumerate in a specific order.
History:
04/25/2000 robkenny
--*/
#include "precomp.h"
#include "CharVector.h"
#include <Dplay.h>
IMPLEMENT_SHIM_BEGIN(DirectPlayEnumOrder) #include "ShimHookMacro.h"
APIHOOK_ENUM_BEGIN APIHOOK_ENUM_ENTRY_DIRECTX_COMSERVER() APIHOOK_ENUM_END
IMPLEMENT_DIRECTX_COMSERVER_HOOKS()
// A class that makes it easy to store DPlay::EnumConnections information.
class DPlayConnectionsInfo { public: BOOL m_beenUsed; GUID m_lpguidSP; LPVOID m_lpConnection; DWORD m_dwConnectionSize; DPNAME m_lpName; DWORD m_dwFlags; LPVOID m_lpContext;
// Construct our object, saveing all these values.
DPlayConnectionsInfo( LPCGUID lpguidSP, LPVOID lpConnection, DWORD dwConnectionSize, LPCDPNAME lpName, DWORD dwFlags, LPVOID lpContext ) { m_beenUsed = FALSE; m_lpguidSP = *lpguidSP; m_lpConnection = malloc(dwConnectionSize);
memcpy(m_lpConnection, lpConnection, dwConnectionSize);
m_dwConnectionSize = dwConnectionSize; m_lpName = *lpName; m_lpName.lpszShortNameA = StringDuplicateA(lpName->lpszShortNameA); m_dwFlags = dwFlags; m_lpContext = lpContext; }
// Free our allocated space, and erase values.
void Erase() { free(m_lpConnection); free(m_lpName.lpszShortNameA); m_lpConnection = NULL; m_dwConnectionSize = 0; m_lpName.lpszShortNameA = NULL; m_dwFlags = 0; m_lpContext = 0; }
// Do we match this GUID?
BOOL operator == (const GUID & guidSP) { return IsEqualGUID(guidSP, m_lpguidSP); }
// Call the callback routine with this saved information
void CallEnumRoutine(LPDPENUMCONNECTIONSCALLBACK lpEnumCallback) { lpEnumCallback( &m_lpguidSP, m_lpConnection, m_dwConnectionSize, &m_lpName, m_dwFlags, m_lpContext );
m_beenUsed = TRUE; }
};
// A list of DPlay connections
class DPlayConnectionsInfoVector : public VectorT<DPlayConnectionsInfo> { static DPlayConnectionsInfoVector * g_DPlayConnectionsInfoVector;
public:
// Get us a pointer to the one and only DPlayConnectionsInfoVector
static DPlayConnectionsInfoVector * GetVector() { if (g_DPlayConnectionsInfoVector == NULL) g_DPlayConnectionsInfoVector = new DPlayConnectionsInfoVector; return g_DPlayConnectionsInfoVector; };
// Deconstruct the elements, then Erase the list
void FreeAndErase() { for (int i = 0; i < Size(); ++i) { DPlayConnectionsInfo & deleteMe = Get(i); deleteMe.Erase(); } Erase(); }
// Find an entry that matches this GUID
DPlayConnectionsInfo * Find(const GUID & guidSP) { const int size = Size(); #if DBG
DPFN( eDbgLevelInfo, "Find GUID(%08x-%08x-%08x-%08x) Size(%d).", guidSP.Data1, guidSP.Data2, guidSP.Data3, guidSP.Data4, size); #endif
for (int i = 0; i < size; ++i) { DPlayConnectionsInfo & dpci = Get(i); #if DBG
DPFN( eDbgLevelInfo, " Compare[%02d] = GUID(%08x-%08x-%08x-%08x) (%s).", i, dpci.m_lpguidSP.Data1, dpci.m_lpguidSP.Data2, dpci.m_lpguidSP.Data3, dpci.m_lpguidSP.Data4, dpci.m_lpName.lpszShortNameA); #endif
if (dpci == guidSP) { #if DBG
DPFN( eDbgLevelInfo, "FOUND(%s).", dpci.m_lpName.lpszShortNameA); #endif
return &dpci; } } #if DBG
DPFN( eDbgLevelInfo, "NOT FOUND."); #endif
return NULL; }
// Lookup the GUID and if found, call the callback routine.
void CallEnumRoutine(const GUID & guidSP, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback) { #if DBG
DPFN( eDbgLevelInfo, "CallEnumRoutine(%08x) Find GUID(%08x-%08x-%08x-%08x).", lpEnumCallback, guidSP.Data1, guidSP.Data2, guidSP.Data3, guidSP.Data4); #endif
DPlayConnectionsInfo * dpci = DPlayConnectionsInfoVector::GetVector()->Find(guidSP); if (dpci) { dpci->CallEnumRoutine(lpEnumCallback); } } };
// The global list of DPlay Connections
DPlayConnectionsInfoVector * DPlayConnectionsInfoVector::g_DPlayConnectionsInfoVector = NULL;
/*++
Our private callback for IDirectPlay4::EnumConnections. We simply save all the connections in our private list for later use.
--*/
BOOL FAR PASCAL EnumConnectionsCallback( LPCGUID lpguidSP, LPVOID lpConnection, DWORD dwConnectionSize, LPCDPNAME lpName, DWORD dwFlags, LPVOID lpContext ) { // Only add it to the list if it is not already there
// App calls EnumConnections from inside Enum callback routine.
if (!DPlayConnectionsInfoVector::GetVector()->Find(*lpguidSP)) { #if DBG
LOGN( eDbgLevelError, "EnumConnectionsCallback Add(%d) (%s).", DPlayConnectionsInfoVector::GetVector()->Size(), lpName->lpszShortName ); #endif
// Store the info for later
DPlayConnectionsInfo dpci(lpguidSP, lpConnection, dwConnectionSize, lpName, dwFlags, lpContext);
DPlayConnectionsInfoVector::GetVector()->Append(dpci); } #if DBG
else { DPFN( eDbgLevelInfo, "EnumConnectionsCallback Already in the list(%s).", lpName->lpszShortName ); } #endif
return TRUE; }
/*++
Win9x Direct play enumerates hosts in this order: DPSPGUID_IPX, DPSPGUID_TCPIP, DPSPGUID_MODEM, DPSPGUID_SERIAL,
IXP, TCP, Modem, Serial. Have EnumConnections call our callback routine to gather the host list, sort it, then call the app's callback routine.
--*/
HRESULT COMHOOK(IDirectPlay4A, EnumConnections)( PVOID pThis, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags ) { #if DBG
DPFN( eDbgLevelInfo, "======================================"); DPFN( eDbgLevelInfo, "COMHOOK IDirectPlay4A EnumConnections" ); #endif
HRESULT hResult = DPERR_CONNECTIONLOST;
typedef HRESULT (*_pfn_IDirectPlay4_EnumConnections)( PVOID pThis, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags);
_pfn_IDirectPlay4A_EnumConnections EnumConnections = ORIGINAL_COM( IDirectPlay4A, EnumConnections, pThis);
if (EnumConnections) { static bool alreadyHere = false; if (!alreadyHere) { alreadyHere = true;
#if DBG
LOGN( eDbgLevelError, "EnumConnections(%08x)\n", EnumConnections ); #endif
// Enumerate connections to our own routine.
hResult = EnumConnections(pThis, lpguidApplication, EnumConnectionsCallback, lpContext, dwFlags); #if DBG
LOGN( eDbgLevelError, "Done EnumConnections Start calling app Size(%d).", DPlayConnectionsInfoVector::GetVector()->Size()); #endif
// Call the application's callback routine with the GUID in the order it expects
if (hResult == DP_OK) { DPlayConnectionsInfoVector::GetVector()->CallEnumRoutine(DPSPGUID_IPX, lpEnumCallback); DPlayConnectionsInfoVector::GetVector()->CallEnumRoutine(DPSPGUID_TCPIP, lpEnumCallback); DPlayConnectionsInfoVector::GetVector()->CallEnumRoutine(DPSPGUID_MODEM, lpEnumCallback); DPlayConnectionsInfoVector::GetVector()->CallEnumRoutine(DPSPGUID_SERIAL, lpEnumCallback);
// Now loop over the list and enum any remaining providers
for (int i = 0; i < DPlayConnectionsInfoVector::GetVector()->Size(); ++i) { DPlayConnectionsInfo & dpci = DPlayConnectionsInfoVector::GetVector()->Get(i); if (!dpci.m_beenUsed) { dpci.CallEnumRoutine(lpEnumCallback); dpci.m_beenUsed = TRUE; } } }
alreadyHere = false; } #if DBG
else { DPFN( eDbgLevelInfo, "EnumConnections Recursive." ); } #endif
} // All done with the list, clean up.
DPlayConnectionsInfoVector::GetVector()->FreeAndErase();
return hResult; }
/*++
Do the same thing for DirectPlay3
--*/
HRESULT COMHOOK(IDirectPlay3A, EnumConnections)( PVOID pThis, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags ) { #if DBG
DPFN( eDbgLevelInfo, "======================================"); DPFN( eDbgLevelInfo, "COMHOOK IDirectPlay3A EnumConnections" ); #endif
HRESULT hResult = DPERR_CONNECTIONLOST;
typedef HRESULT (*_pfn_IDirectPlay3A_EnumConnections)( PVOID pThis, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags);
_pfn_IDirectPlay3A_EnumConnections EnumConnections = ORIGINAL_COM( IDirectPlay3A, EnumConnections, pThis);
if (EnumConnections) { static bool alreadyHere = false; if (!alreadyHere) { alreadyHere = true;
#if DBG
LOGN( eDbgLevelError, "EnumConnections(%08x).", EnumConnections ); #endif
// Enumerate connections to our own routine.
hResult = EnumConnections(pThis, lpguidApplication, EnumConnectionsCallback, lpContext, dwFlags); #if DBG
LOGN( eDbgLevelError, "Done EnumConnections Start calling app Size(%d).", DPlayConnectionsInfoVector::GetVector()->Size()); #endif
// Call the application's callback routine with the GUID in the order it expects
if (hResult == DP_OK) { DPlayConnectionsInfoVector::GetVector()->CallEnumRoutine(DPSPGUID_IPX, lpEnumCallback); DPlayConnectionsInfoVector::GetVector()->CallEnumRoutine(DPSPGUID_TCPIP, lpEnumCallback); DPlayConnectionsInfoVector::GetVector()->CallEnumRoutine(DPSPGUID_MODEM, lpEnumCallback); DPlayConnectionsInfoVector::GetVector()->CallEnumRoutine(DPSPGUID_SERIAL, lpEnumCallback);
// Now loop over the list and enum any remaining providers
for (int i = 0; i < DPlayConnectionsInfoVector::GetVector()->Size(); ++i) { DPlayConnectionsInfo & dpci = DPlayConnectionsInfoVector::GetVector()->Get(i); if (!dpci.m_beenUsed) { dpci.CallEnumRoutine(lpEnumCallback); dpci.m_beenUsed = TRUE; } } }
alreadyHere = false; } #if DBG
else { DPFN( eDbgLevelInfo, "EnumConnections Recursive." ); } #endif
} // All done with the list, clean up.
DPlayConnectionsInfoVector::GetVector()->FreeAndErase();
return hResult; }
/*++
Register hooked functions
--*/
HOOK_BEGIN
APIHOOK_ENTRY_DIRECTX_COMSERVER()
COMHOOK_ENTRY(DirectPlay, IDirectPlay4A, EnumConnections, 35) COMHOOK_ENTRY(DirectPlay, IDirectPlay3A, EnumConnections, 35)
HOOK_END
IMPLEMENT_SHIM_END
|