windows-nt/Source/XPSP1/NT/windows/appcompat/shims/layer/directplayenumorder.cpp
2020-09-26 16:20:57 +08:00

438 lines
12 KiB
C++

/*++
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