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.

301 lines
8.2 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: N C C O M . C P P
  7. //
  8. // Contents: Helper functions for doing COM things
  9. //
  10. // Notes:
  11. //
  12. //----------------------------------------------------------------------------
  13. #include <pch.h>
  14. #pragma hdrstop
  15. #include "nccom.h"
  16. #include "ncbase.h"
  17. #include "trace.h"
  18. //+---------------------------------------------------------------------------
  19. //
  20. // Function: HrMyWaitForMultipleHandles
  21. //
  22. // Purpose: Waits for specified handles to be signaled or for a specified
  23. // timeout period to elapse, pumping messages in the meantime.
  24. // For use by apartment-threaded object that have to block,
  25. // but are on a system that doesn't support
  26. // CoWaitForMultipleHandles.
  27. //
  28. // Arguments:
  29. // [in] dwFlags Wait options. Values are taken from the
  30. // COWAIT_FLAGS enumeration.
  31. //
  32. // [in] dwTimeout Timeout period, in milliseconds.
  33. //
  34. // [in] cHandles Number of elements in the pHandles array.
  35. //
  36. // [in] pHandles Array of Win32 handles.
  37. //
  38. // [out] lpdwIndex Index to the event that was signalled
  39. //
  40. // Returns: S_OK The required handle or handles were signaled.
  41. // RPC_S_CALLPENDING The timeout period elapsed before the required
  42. // handle or handles were signaled.
  43. // RPC_E_NO_SYNC No handles were specified.
  44. //
  45. // Notes: This code was basically stolen from the implementation
  46. // of CoWaitForMultipleHandles and KB article Q136885.
  47. // It is meant to look and work exactly like
  48. // CoWaitForMultipleHandles, which exists on nt5 but not
  49. // on Millennium
  50. // See KB article Q136885 for more info.
  51. //
  52. HRESULT HrMyWaitForMultipleHandles(DWORD dwFlags,
  53. DWORD dwTimeout,
  54. ULONG cHandles,
  55. LPHANDLE pHandles,
  56. LPDWORD lpdwIndex)
  57. {
  58. HRESULT hr;
  59. DWORD dwSignaled;
  60. HANDLE hTimer = NULL;
  61. ULONG cNewHandles = 0;
  62. LPHANDLE pNewHandles = NULL;
  63. hr = S_OK;
  64. dwSignaled = 0;
  65. if ((pHandles == NULL) || (lpdwIndex == NULL))
  66. {
  67. hr = E_INVALIDARG;
  68. goto Cleanup;
  69. }
  70. if ((dwFlags & ~(COWAIT_WAITALL | COWAIT_ALERTABLE)) != 0)
  71. {
  72. hr = E_INVALIDARG;
  73. goto Cleanup;
  74. }
  75. // If nothing to do, return
  76. if (0 == cHandles)
  77. {
  78. hr = RPC_E_NO_SYNC;
  79. goto Cleanup;
  80. }
  81. {
  82. if (INFINITE != dwTimeout)
  83. {
  84. // Create a waitable timer to implement the timeout.
  85. hTimer = CreateWaitableTimer(NULL, TRUE, NULL);
  86. if (NULL == hTimer)
  87. {
  88. hr = HrFromLastWin32Error();
  89. TraceError("HrMyWaitForMultipleHandles(): "
  90. "Failed to create waitable timer",
  91. hr);
  92. goto Cleanup;
  93. }
  94. // We need to add the waitable timer to the list of things to wait
  95. // on. So we allocate a new array, copy the handles passed in into
  96. // it, and add the timer as the last handle.
  97. cNewHandles = cHandles+1;
  98. pNewHandles = new HANDLE[cNewHandles];
  99. if (NULL == pNewHandles)
  100. {
  101. hr = E_OUTOFMEMORY;
  102. TraceError("HrMyWaitForMultipleHandles(): "
  103. "Failed to allocate new handle array",
  104. hr);
  105. goto Cleanup;
  106. }
  107. for (ULONG i = 0; i < cHandles; i++)
  108. {
  109. pNewHandles[i] = pHandles[i];
  110. }
  111. pNewHandles[cHandles] = hTimer;
  112. }
  113. else
  114. {
  115. pNewHandles = pHandles;
  116. cNewHandles = cHandles;
  117. }
  118. DWORD dwWaitFlags;
  119. DWORD dwMessageSignal;
  120. dwWaitFlags = (dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0;
  121. dwWaitFlags |= (dwFlags & COWAIT_ALERTABLE) ? MWMO_ALERTABLE : 0;
  122. dwMessageSignal = WAIT_OBJECT_0 + cNewHandles;
  123. if (INFINITE != dwTimeout)
  124. {
  125. // About to enter the wait - set the waitable timer. Have to first
  126. // convert the timeout, given in milliseconds to 100 nanosecond
  127. // units.
  128. LARGE_INTEGER liTimeout;
  129. liTimeout.QuadPart = Int32x32To64(((LONG)dwTimeout * -1), 10000);
  130. if (!SetWaitableTimer(hTimer, &liTimeout, 0, NULL, NULL, FALSE))
  131. {
  132. hr = HrFromLastWin32Error();
  133. TraceError("HrMyWaitForMultipleHandles(): "
  134. "Failed to set waitable timer",
  135. hr);
  136. goto Cleanup;
  137. }
  138. }
  139. while (TRUE)
  140. {
  141. // CAUTION: the messages that MsgWaitForMultipleObjectsEx will
  142. // wake up for (the QS_* flags) MUST be a subset of the messages
  143. // that PeekMessage will process (PM_QS_*), or the CPU can be
  144. // pegged.
  145. //
  146. dwSignaled = ::MsgWaitForMultipleObjectsEx(cNewHandles,
  147. pNewHandles,
  148. INFINITE,
  149. QS_ALLINPUT,
  150. dwWaitFlags);
  151. #pragma warning(push)
  152. #pragma warning(disable:4296)
  153. if ((dwSignaled >= WAIT_OBJECT_0) &&
  154. (dwSignaled < dwMessageSignal))
  155. {
  156. // One (or all) of our handles was signalled
  157. //
  158. dwSignaled -= WAIT_OBJECT_0;
  159. if ((cNewHandles > cHandles) && (dwSignaled == cHandles) )
  160. {
  161. // The timer was signaled - this is a timeout. Fix up
  162. // the error code.
  163. hr = RPC_S_CALLPENDING;
  164. dwSignaled = WAIT_TIMEOUT;
  165. }
  166. break;
  167. }
  168. #pragma warning(pop)
  169. else if (dwMessageSignal == dwSignaled)
  170. {
  171. MSG msg;
  172. // There is a window message available. Dispatch it.
  173. //
  174. while (PeekMessage(&msg,
  175. NULL,
  176. NULL,
  177. NULL,
  178. PM_REMOVE))
  179. {
  180. ::TranslateMessage(&msg);
  181. ::DispatchMessage(&msg);
  182. }
  183. }
  184. else
  185. {
  186. Assert(FImplies(WAIT_IO_COMPLETION == dwSignaled,
  187. dwFlags & COWAIT_ALERTABLE));
  188. hr = HrFromLastWin32Error();
  189. break;
  190. }
  191. }
  192. }
  193. Cleanup:
  194. if (hTimer)
  195. {
  196. CancelWaitableTimer(hTimer);
  197. CloseHandle(hTimer);
  198. }
  199. if (pNewHandles && (pNewHandles != pHandles))
  200. {
  201. delete [] pNewHandles;
  202. cNewHandles = 0;
  203. }
  204. if (lpdwIndex)
  205. {
  206. *lpdwIndex = dwSignaled;
  207. }
  208. TraceError("MyWaitForMultipleHandles", hr);
  209. return hr;
  210. }
  211. //+---------------------------------------------------------------------------
  212. //
  213. // Function: FSupportsInterface
  214. //
  215. // Purpose: Returns TRUE if the specified object implements the given
  216. // interface, FALSE otherwise.
  217. //
  218. // Arguments:
  219. // [in] punk IUnknown * of object to query for a particular
  220. // interface.
  221. //
  222. // [in] piid IID for the interface of interest
  223. //
  224. //
  225. // Returns:
  226. // TRUE The specified interface is supported
  227. //
  228. // FALSE The specified interface is not suppored
  229. //
  230. BOOL
  231. FSupportsInterface(IUnknown * punk, REFIID piid)
  232. {
  233. Assert(punk);
  234. HRESULT hr;
  235. BOOL fResult;
  236. IUnknown * punkTemp;
  237. fResult = FALSE;
  238. punkTemp = NULL;
  239. hr = punk->QueryInterface(piid, (LPVOID*)&punkTemp);
  240. if (SUCCEEDED(hr))
  241. {
  242. Assert(punkTemp);
  243. fResult = TRUE;
  244. punkTemp->Release();
  245. }
  246. if (hr != E_NOINTERFACE)
  247. {
  248. TraceError("FSupportsInterface, QI", hr);
  249. }
  250. return fResult;
  251. }