Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

437 lines
12 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. DirectPlayEnumOrder.cpp
  5. Abstract:
  6. Certain applications (Midtown Madness) expects the DPLAY providers to enumerate in a specific order.
  7. History:
  8. 04/25/2000 robkenny
  9. --*/
  10. #include "precomp.h"
  11. #include "CharVector.h"
  12. #include <Dplay.h>
  13. IMPLEMENT_SHIM_BEGIN(DirectPlayEnumOrder)
  14. #include "ShimHookMacro.h"
  15. APIHOOK_ENUM_BEGIN
  16. APIHOOK_ENUM_ENTRY_DIRECTX_COMSERVER()
  17. APIHOOK_ENUM_END
  18. IMPLEMENT_DIRECTX_COMSERVER_HOOKS()
  19. // A class that makes it easy to store DPlay::EnumConnections information.
  20. class DPlayConnectionsInfo
  21. {
  22. public:
  23. BOOL m_beenUsed;
  24. GUID m_lpguidSP;
  25. LPVOID m_lpConnection;
  26. DWORD m_dwConnectionSize;
  27. DPNAME m_lpName;
  28. DWORD m_dwFlags;
  29. LPVOID m_lpContext;
  30. // Construct our object, saveing all these values.
  31. DPlayConnectionsInfo(
  32. LPCGUID lpguidSP,
  33. LPVOID lpConnection,
  34. DWORD dwConnectionSize,
  35. LPCDPNAME lpName,
  36. DWORD dwFlags,
  37. LPVOID lpContext
  38. )
  39. {
  40. m_beenUsed = FALSE;
  41. m_lpguidSP = *lpguidSP;
  42. m_lpConnection = malloc(dwConnectionSize);
  43. memcpy(m_lpConnection, lpConnection, dwConnectionSize);
  44. m_dwConnectionSize = dwConnectionSize;
  45. m_lpName = *lpName;
  46. m_lpName.lpszShortNameA = StringDuplicateA(lpName->lpszShortNameA);
  47. m_dwFlags = dwFlags;
  48. m_lpContext = lpContext;
  49. }
  50. // Free our allocated space, and erase values.
  51. void Erase()
  52. {
  53. free(m_lpConnection);
  54. free(m_lpName.lpszShortNameA);
  55. m_lpConnection = NULL;
  56. m_dwConnectionSize = 0;
  57. m_lpName.lpszShortNameA = NULL;
  58. m_dwFlags = 0;
  59. m_lpContext = 0;
  60. }
  61. // Do we match this GUID?
  62. BOOL operator == (const GUID & guidSP)
  63. {
  64. return IsEqualGUID(guidSP, m_lpguidSP);
  65. }
  66. // Call the callback routine with this saved information
  67. void CallEnumRoutine(LPDPENUMCONNECTIONSCALLBACK lpEnumCallback)
  68. {
  69. lpEnumCallback(
  70. &m_lpguidSP,
  71. m_lpConnection,
  72. m_dwConnectionSize,
  73. &m_lpName,
  74. m_dwFlags,
  75. m_lpContext
  76. );
  77. m_beenUsed = TRUE;
  78. }
  79. };
  80. // A list of DPlay connections
  81. class DPlayConnectionsInfoVector : public VectorT<DPlayConnectionsInfo>
  82. {
  83. static DPlayConnectionsInfoVector * g_DPlayConnectionsInfoVector;
  84. public:
  85. // Get us a pointer to the one and only DPlayConnectionsInfoVector
  86. static DPlayConnectionsInfoVector * GetVector()
  87. {
  88. if (g_DPlayConnectionsInfoVector == NULL)
  89. g_DPlayConnectionsInfoVector = new DPlayConnectionsInfoVector;
  90. return g_DPlayConnectionsInfoVector;
  91. };
  92. // Deconstruct the elements, then Erase the list
  93. void FreeAndErase()
  94. {
  95. for (int i = 0; i < Size(); ++i)
  96. {
  97. DPlayConnectionsInfo & deleteMe = Get(i);
  98. deleteMe.Erase();
  99. }
  100. Erase();
  101. }
  102. // Find an entry that matches this GUID
  103. DPlayConnectionsInfo * Find(const GUID & guidSP)
  104. {
  105. const int size = Size();
  106. #if DBG
  107. DPFN(
  108. eDbgLevelInfo,
  109. "Find GUID(%08x-%08x-%08x-%08x) Size(%d).",
  110. guidSP.Data1,
  111. guidSP.Data2,
  112. guidSP.Data3,
  113. guidSP.Data4,
  114. size);
  115. #endif
  116. for (int i = 0; i < size; ++i)
  117. {
  118. DPlayConnectionsInfo & dpci = Get(i);
  119. #if DBG
  120. DPFN(
  121. eDbgLevelInfo,
  122. " Compare[%02d] = GUID(%08x-%08x-%08x-%08x) (%s).",
  123. i,
  124. dpci.m_lpguidSP.Data1,
  125. dpci.m_lpguidSP.Data2,
  126. dpci.m_lpguidSP.Data3,
  127. dpci.m_lpguidSP.Data4,
  128. dpci.m_lpName.lpszShortNameA);
  129. #endif
  130. if (dpci == guidSP)
  131. {
  132. #if DBG
  133. DPFN(
  134. eDbgLevelInfo,
  135. "FOUND(%s).",
  136. dpci.m_lpName.lpszShortNameA);
  137. #endif
  138. return &dpci;
  139. }
  140. }
  141. #if DBG
  142. DPFN(
  143. eDbgLevelInfo,
  144. "NOT FOUND.");
  145. #endif
  146. return NULL;
  147. }
  148. // Lookup the GUID and if found, call the callback routine.
  149. void CallEnumRoutine(const GUID & guidSP, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback)
  150. {
  151. #if DBG
  152. DPFN(
  153. eDbgLevelInfo,
  154. "CallEnumRoutine(%08x) Find GUID(%08x-%08x-%08x-%08x).",
  155. lpEnumCallback,
  156. guidSP.Data1,
  157. guidSP.Data2,
  158. guidSP.Data3,
  159. guidSP.Data4);
  160. #endif
  161. DPlayConnectionsInfo * dpci = DPlayConnectionsInfoVector::GetVector()->Find(guidSP);
  162. if (dpci)
  163. {
  164. dpci->CallEnumRoutine(lpEnumCallback);
  165. }
  166. }
  167. };
  168. // The global list of DPlay Connections
  169. DPlayConnectionsInfoVector * DPlayConnectionsInfoVector::g_DPlayConnectionsInfoVector = NULL;
  170. /*++
  171. Our private callback for IDirectPlay4::EnumConnections. We simply save all
  172. the connections in our private list for later use.
  173. --*/
  174. BOOL FAR PASCAL EnumConnectionsCallback(
  175. LPCGUID lpguidSP,
  176. LPVOID lpConnection,
  177. DWORD dwConnectionSize,
  178. LPCDPNAME lpName,
  179. DWORD dwFlags,
  180. LPVOID lpContext
  181. )
  182. {
  183. // Only add it to the list if it is not already there
  184. // App calls EnumConnections from inside Enum callback routine.
  185. if (!DPlayConnectionsInfoVector::GetVector()->Find(*lpguidSP))
  186. {
  187. #if DBG
  188. LOGN(
  189. eDbgLevelError,
  190. "EnumConnectionsCallback Add(%d) (%s).",
  191. DPlayConnectionsInfoVector::GetVector()->Size(),
  192. lpName->lpszShortName );
  193. #endif
  194. // Store the info for later
  195. DPlayConnectionsInfo dpci(lpguidSP, lpConnection, dwConnectionSize, lpName, dwFlags, lpContext);
  196. DPlayConnectionsInfoVector::GetVector()->Append(dpci);
  197. }
  198. #if DBG
  199. else
  200. {
  201. DPFN(
  202. eDbgLevelInfo,
  203. "EnumConnectionsCallback Already in the list(%s).",
  204. lpName->lpszShortName );
  205. }
  206. #endif
  207. return TRUE;
  208. }
  209. /*++
  210. Win9x Direct play enumerates hosts in this order:
  211. DPSPGUID_IPX,
  212. DPSPGUID_TCPIP,
  213. DPSPGUID_MODEM,
  214. DPSPGUID_SERIAL,
  215. IXP, TCP, Modem, Serial. Have EnumConnections call our callback
  216. routine to gather the host list, sort it, then call the app's callback routine.
  217. --*/
  218. HRESULT
  219. COMHOOK(IDirectPlay4A, EnumConnections)(
  220. PVOID pThis,
  221. LPCGUID lpguidApplication,
  222. LPDPENUMCONNECTIONSCALLBACK lpEnumCallback,
  223. LPVOID lpContext,
  224. DWORD dwFlags
  225. )
  226. {
  227. #if DBG
  228. DPFN( eDbgLevelInfo, "======================================");
  229. DPFN( eDbgLevelInfo, "COMHOOK IDirectPlay4A EnumConnections" );
  230. #endif
  231. HRESULT hResult = DPERR_CONNECTIONLOST;
  232. typedef HRESULT (*_pfn_IDirectPlay4_EnumConnections)( PVOID pThis, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags);
  233. _pfn_IDirectPlay4A_EnumConnections EnumConnections = ORIGINAL_COM(
  234. IDirectPlay4A,
  235. EnumConnections,
  236. pThis);
  237. if (EnumConnections)
  238. {
  239. static bool alreadyHere = false;
  240. if (!alreadyHere)
  241. {
  242. alreadyHere = true;
  243. #if DBG
  244. LOGN( eDbgLevelError, "EnumConnections(%08x)\n", EnumConnections );
  245. #endif
  246. // Enumerate connections to our own routine.
  247. hResult = EnumConnections(pThis, lpguidApplication, EnumConnectionsCallback, lpContext, dwFlags);
  248. #if DBG
  249. LOGN( eDbgLevelError,
  250. "Done EnumConnections Start calling app Size(%d).",
  251. DPlayConnectionsInfoVector::GetVector()->Size());
  252. #endif
  253. // Call the application's callback routine with the GUID in the order it expects
  254. if (hResult == DP_OK)
  255. {
  256. DPlayConnectionsInfoVector::GetVector()->CallEnumRoutine(DPSPGUID_IPX, lpEnumCallback);
  257. DPlayConnectionsInfoVector::GetVector()->CallEnumRoutine(DPSPGUID_TCPIP, lpEnumCallback);
  258. DPlayConnectionsInfoVector::GetVector()->CallEnumRoutine(DPSPGUID_MODEM, lpEnumCallback);
  259. DPlayConnectionsInfoVector::GetVector()->CallEnumRoutine(DPSPGUID_SERIAL, lpEnumCallback);
  260. // Now loop over the list and enum any remaining providers
  261. for (int i = 0; i < DPlayConnectionsInfoVector::GetVector()->Size(); ++i)
  262. {
  263. DPlayConnectionsInfo & dpci = DPlayConnectionsInfoVector::GetVector()->Get(i);
  264. if (!dpci.m_beenUsed)
  265. {
  266. dpci.CallEnumRoutine(lpEnumCallback);
  267. dpci.m_beenUsed = TRUE;
  268. }
  269. }
  270. }
  271. alreadyHere = false;
  272. }
  273. #if DBG
  274. else
  275. {
  276. DPFN( eDbgLevelInfo, "EnumConnections Recursive." );
  277. }
  278. #endif
  279. }
  280. // All done with the list, clean up.
  281. DPlayConnectionsInfoVector::GetVector()->FreeAndErase();
  282. return hResult;
  283. }
  284. /*++
  285. Do the same thing for DirectPlay3
  286. --*/
  287. HRESULT
  288. COMHOOK(IDirectPlay3A, EnumConnections)(
  289. PVOID pThis,
  290. LPCGUID lpguidApplication,
  291. LPDPENUMCONNECTIONSCALLBACK lpEnumCallback,
  292. LPVOID lpContext,
  293. DWORD dwFlags
  294. )
  295. {
  296. #if DBG
  297. DPFN( eDbgLevelInfo, "======================================");
  298. DPFN( eDbgLevelInfo, "COMHOOK IDirectPlay3A EnumConnections" );
  299. #endif
  300. HRESULT hResult = DPERR_CONNECTIONLOST;
  301. typedef HRESULT (*_pfn_IDirectPlay3A_EnumConnections)( PVOID pThis, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags);
  302. _pfn_IDirectPlay3A_EnumConnections EnumConnections = ORIGINAL_COM(
  303. IDirectPlay3A,
  304. EnumConnections,
  305. pThis);
  306. if (EnumConnections)
  307. {
  308. static bool alreadyHere = false;
  309. if (!alreadyHere)
  310. {
  311. alreadyHere = true;
  312. #if DBG
  313. LOGN( eDbgLevelError, "EnumConnections(%08x).", EnumConnections );
  314. #endif
  315. // Enumerate connections to our own routine.
  316. hResult = EnumConnections(pThis, lpguidApplication, EnumConnectionsCallback, lpContext, dwFlags);
  317. #if DBG
  318. LOGN( eDbgLevelError,
  319. "Done EnumConnections Start calling app Size(%d).",
  320. DPlayConnectionsInfoVector::GetVector()->Size());
  321. #endif
  322. // Call the application's callback routine with the GUID in the order it expects
  323. if (hResult == DP_OK)
  324. {
  325. DPlayConnectionsInfoVector::GetVector()->CallEnumRoutine(DPSPGUID_IPX, lpEnumCallback);
  326. DPlayConnectionsInfoVector::GetVector()->CallEnumRoutine(DPSPGUID_TCPIP, lpEnumCallback);
  327. DPlayConnectionsInfoVector::GetVector()->CallEnumRoutine(DPSPGUID_MODEM, lpEnumCallback);
  328. DPlayConnectionsInfoVector::GetVector()->CallEnumRoutine(DPSPGUID_SERIAL, lpEnumCallback);
  329. // Now loop over the list and enum any remaining providers
  330. for (int i = 0; i < DPlayConnectionsInfoVector::GetVector()->Size(); ++i)
  331. {
  332. DPlayConnectionsInfo & dpci = DPlayConnectionsInfoVector::GetVector()->Get(i);
  333. if (!dpci.m_beenUsed)
  334. {
  335. dpci.CallEnumRoutine(lpEnumCallback);
  336. dpci.m_beenUsed = TRUE;
  337. }
  338. }
  339. }
  340. alreadyHere = false;
  341. }
  342. #if DBG
  343. else
  344. {
  345. DPFN( eDbgLevelInfo, "EnumConnections Recursive." );
  346. }
  347. #endif
  348. }
  349. // All done with the list, clean up.
  350. DPlayConnectionsInfoVector::GetVector()->FreeAndErase();
  351. return hResult;
  352. }
  353. /*++
  354. Register hooked functions
  355. --*/
  356. HOOK_BEGIN
  357. APIHOOK_ENTRY_DIRECTX_COMSERVER()
  358. COMHOOK_ENTRY(DirectPlay, IDirectPlay4A, EnumConnections, 35)
  359. COMHOOK_ENTRY(DirectPlay, IDirectPlay3A, EnumConnections, 35)
  360. HOOK_END
  361. IMPLEMENT_SHIM_END