Leaked source code of windows server 2003
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.

523 lines
14 KiB

  1. #include "shellprv.h"
  2. #pragma hdrstop
  3. #include <shguidp.h>
  4. #include "uevttmr.h"
  5. // 1. Use dpa callback system to delete the entire hdpa array
  6. EXTERN_C const TCHAR c_szUserEventWindow[] = TEXT("UserEventWindow");
  7. // *** IUnknown methods ***
  8. STDMETHODIMP CUserEventTimer::QueryInterface (REFIID riid, LPVOID * ppvObj)
  9. {
  10. static const QITAB qit[] =
  11. {
  12. QITABENT(CUserEventTimer, IUserEventTimer),
  13. { 0 },
  14. };
  15. return QISearch(this, qit, riid, ppvObj);
  16. }
  17. STDMETHODIMP_(ULONG) CUserEventTimer::AddRef()
  18. {
  19. return InterlockedIncrement(&m_cRef);
  20. }
  21. STDMETHODIMP_(ULONG) CUserEventTimer::Release()
  22. {
  23. ASSERT( 0 != m_cRef );
  24. ULONG cRef = InterlockedDecrement(&m_cRef);
  25. if ( 0 == cRef )
  26. {
  27. delete this;
  28. }
  29. return cRef;
  30. }
  31. // *** Constructor and Destructor ***
  32. CUserEventTimer::CUserEventTimer() : m_cRef(1)
  33. {
  34. }
  35. CUserEventTimer::~CUserEventTimer()
  36. {
  37. _Destroy();
  38. }
  39. // *** IUserEventTimer methods ***
  40. HRESULT CUserEventTimer::SetUserEventTimer(
  41. HWND hWnd,
  42. UINT uCallbackMessage,
  43. UINT uTimerElapse,
  44. IUserEventTimerCallback * pUserEventTimerCallback,
  45. ULONG * puUserEventTimerID
  46. )
  47. {
  48. RIP(puUserEventTimerID != NULL);
  49. HRESULT hr;
  50. // Argument Validation
  51. if (!m_hWnd)
  52. hr = E_FAIL;
  53. else if (!_dpaUserEventInfo)
  54. hr = E_OUTOFMEMORY;
  55. else if (!hWnd && !pUserEventTimerCallback)
  56. hr = E_INVALIDARG;
  57. else if (!puUserEventTimerID || uTimerElapse <= 0)
  58. hr = E_INVALIDARG;
  59. else if (hWnd)
  60. {
  61. int nIndex = _GetTimerDetailsIndex(hWnd, *puUserEventTimerID);
  62. if (nIndex >= 0)
  63. hr = _ResetUserEventTimer(hWnd, uCallbackMessage, uTimerElapse, nIndex);
  64. else
  65. hr = _SetUserEventTimer(hWnd, uCallbackMessage, uTimerElapse, pUserEventTimerCallback, puUserEventTimerID);
  66. }
  67. else
  68. {
  69. ASSERT(pUserEventTimerCallback != NULL);
  70. hr = _SetUserEventTimer(hWnd, uCallbackMessage, uTimerElapse, pUserEventTimerCallback, puUserEventTimerID);
  71. }
  72. return hr;
  73. }
  74. HRESULT CUserEventTimer::InitTimerTickInterval(UINT uTimerTickIntervalMs)
  75. {
  76. // If there is more than one registered client to the user event timer,
  77. // then we cannot change the timer tick interval
  78. if (_dpaUserEventInfo.GetPtrCount() > 0)
  79. return E_FAIL;
  80. if (uTimerTickIntervalMs > 0)
  81. m_uTimerTickInterval = uTimerTickIntervalMs;
  82. else
  83. m_uTimerTickInterval = TIMER_ELAPSE;
  84. return S_OK;
  85. }
  86. HRESULT CUserEventTimer::_SetUserEventTimer(
  87. HWND hWnd,
  88. UINT uCallbackMessage,
  89. UINT uTimerElapse,
  90. IUserEventTimerCallback * pUserEventTimerCallback,
  91. ULONG * puUserEventTimerID
  92. )
  93. {
  94. ASSERT(puUserEventTimerID);
  95. ASSERT(m_uTimerTickInterval > 0);
  96. HRESULT hr = E_OUTOFMEMORY;
  97. USEREVENTINFO * pUserEventInfo = new USEREVENTINFO;
  98. if (pUserEventInfo)
  99. {
  100. pUserEventInfo->hWnd = hWnd;
  101. if (hWnd)
  102. {
  103. pUserEventInfo->uCallbackMessage = uCallbackMessage;
  104. pUserEventInfo->uUserEventTimerID = *puUserEventTimerID;
  105. }
  106. else
  107. {
  108. pUserEventInfo->pUserEventTimerCallback = pUserEventTimerCallback;
  109. }
  110. // Timer ID cannot be zero..
  111. if (!pUserEventInfo->uUserEventTimerID)
  112. {
  113. ULONG uTimerID = _GetNextInternalTimerID(hWnd);
  114. if (uTimerID != -1)
  115. pUserEventInfo->uUserEventTimerID = uTimerID;
  116. }
  117. int nRetInsert = -1;
  118. if (pUserEventInfo->uUserEventTimerID)
  119. {
  120. pUserEventInfo->uTimerElapse = uTimerElapse;
  121. pUserEventInfo->uIntervalCountdown = _CalcNumIntervals(uTimerElapse);
  122. pUserEventInfo->bFirstTime = TRUE;
  123. nRetInsert = _dpaUserEventInfo.AppendPtr(pUserEventInfo);
  124. if (nRetInsert != -1)
  125. {
  126. *puUserEventTimerID = pUserEventInfo->uUserEventTimerID;
  127. if (!_uUserTimerID)
  128. {
  129. _uUserTimerID = SetTimer(m_hWnd, TIMER_ID, m_uTimerTickInterval, NULL);
  130. }
  131. if (!_uUserTimerID)
  132. {
  133. _dpaUserEventInfo.DeletePtr(_dpaUserEventInfo.GetPtrCount()-1);
  134. }
  135. }
  136. }
  137. hr = S_OK;
  138. if (nRetInsert == -1 || _uUserTimerID == 0)
  139. {
  140. *puUserEventTimerID = 0;
  141. delete (pUserEventInfo);
  142. hr = E_FAIL;
  143. }
  144. else if (NULL == hWnd)
  145. {
  146. IUnknown_SetSite(pUserEventTimerCallback, this);
  147. pUserEventTimerCallback->AddRef();
  148. }
  149. }
  150. if (SUCCEEDED(hr))
  151. {
  152. if (!m_dwUserStartTime && _dpaUserEventInfo.GetPtrCount() == 1)
  153. m_dwUserStartTime = GetTickCount();
  154. }
  155. return hr;
  156. }
  157. HRESULT CUserEventTimer::_ResetUserEventTimer(
  158. HWND hWnd,
  159. UINT uCallbackMessage,
  160. UINT uTimerElapse,
  161. int nIndex
  162. )
  163. {
  164. ASSERT(m_hWnd != NULL);
  165. ASSERT(_dpaUserEventInfo != NULL);
  166. ASSERT(hWnd != NULL);
  167. ASSERT(nIndex >= 0);
  168. USEREVENTINFO * pUserEventInfo = _dpaUserEventInfo.GetPtr(nIndex);
  169. ASSERT(pUserEventInfo);
  170. ASSERT(pUserEventInfo->hWnd == hWnd);
  171. pUserEventInfo->uTimerElapse = uTimerElapse;
  172. pUserEventInfo->uIntervalCountdown = _CalcNumIntervals(uTimerElapse);
  173. pUserEventInfo->bFirstTime = TRUE;
  174. return S_OK;
  175. }
  176. int DeleteCB(USEREVENTINFO * lpData1, LPVOID lpData2)
  177. {
  178. USEREVENTINFO * pUserEventInfo = lpData1;
  179. ASSERT(pUserEventInfo);
  180. #ifdef DEBUG
  181. BOOL bErrorCheck = (lpData2 ? (*(BOOL *)lpData2) : FALSE);
  182. if (bErrorCheck)
  183. TraceMsg(TF_WARNING, "CUserEventTimer::s_DeleteCB App hasnt killed timer hwnd = %u, timerID = %u",
  184. pUserEventInfo->hWnd, pUserEventInfo->uUserEventTimerID);
  185. #endif
  186. IUserEventTimerCallback * pUserEventTimerCallback =
  187. (pUserEventInfo->hWnd == NULL) ? pUserEventInfo->pUserEventTimerCallback : NULL;
  188. ASSERT(pUserEventInfo->hWnd || pUserEventTimerCallback);
  189. if (pUserEventTimerCallback)
  190. {
  191. IUnknown_SetSite(pUserEventTimerCallback, NULL);
  192. pUserEventTimerCallback->Release();
  193. }
  194. // Dangerous to delete pUserEventInfo here, but this function is called as the
  195. // DPA DestroyCallback, as well as from KillUserEventTimer
  196. // In KillUserEventTimer, we remove the event from the dpa, while in the callback,
  197. // we dont need to explicitly remove the event from the queue...
  198. delete pUserEventInfo;
  199. return TRUE;
  200. }
  201. HRESULT CUserEventTimer::GetUserEventTimerElapsed(
  202. HWND hWnd,
  203. ULONG uUserEventTimerID,
  204. UINT * puTimerElapsed)
  205. {
  206. HRESULT hr = E_FAIL;
  207. if (!puTimerElapsed || !hWnd || !m_hWnd || !_dpaUserEventInfo)
  208. return hr;
  209. int nIndex = _GetTimerDetailsIndex(hWnd, uUserEventTimerID);
  210. if (nIndex >= 0)
  211. {
  212. USEREVENTINFO * pUserEventInfo = _dpaUserEventInfo.GetPtr(nIndex);
  213. *puTimerElapsed = _CalcMilliSeconds(
  214. _CalcNumIntervals(pUserEventInfo->uTimerElapse) - pUserEventInfo->uIntervalCountdown
  215. );
  216. hr = S_OK;
  217. }
  218. else
  219. *puTimerElapsed = 0;
  220. return hr;
  221. }
  222. HRESULT CUserEventTimer::KillUserEventTimer(HWND hWnd, ULONG uUserEventTimerID)
  223. {
  224. HRESULT hr = E_FAIL;
  225. if (!m_hWnd || !_dpaUserEventInfo)
  226. return hr;
  227. int nIndex = _GetTimerDetailsIndex(hWnd, uUserEventTimerID);
  228. if (nIndex >= 0)
  229. {
  230. DeleteCB(_dpaUserEventInfo.GetPtr(nIndex), NULL);
  231. _dpaUserEventInfo.DeletePtr(nIndex);
  232. _KillIntervalTimer();
  233. hr = S_OK;
  234. }
  235. else
  236. {
  237. hr = E_FAIL;
  238. }
  239. if (0 == _dpaUserEventInfo.GetPtrCount())
  240. m_dwUserStartTime = 0;
  241. return hr;
  242. }
  243. // Private helpers
  244. HRESULT CUserEventTimer::Init()
  245. {
  246. if (!_CreateWindow())
  247. return E_FAIL;
  248. if (!_dpaUserEventInfo.Create(4))
  249. return E_OUTOFMEMORY;
  250. m_uTimerTickInterval = TIMER_ELAPSE;
  251. ASSERT(!_uUserTimerID);
  252. ASSERT(!m_dwUserStartTime);
  253. return S_OK;
  254. }
  255. BOOL CUserEventTimer::_CreateWindow()
  256. {
  257. if (!m_hWnd)
  258. {
  259. WNDCLASSEX wc;
  260. DWORD dwExStyle = WS_EX_STATICEDGE;
  261. ZeroMemory(&wc, sizeof(wc));
  262. wc.cbSize = sizeof(WNDCLASSEX);
  263. if (!GetClassInfoEx(HINST_THISDLL, c_szUserEventWindow, &wc))
  264. {
  265. wc.lpszClassName = c_szUserEventWindow;
  266. wc.style = CS_DBLCLKS;
  267. wc.lpfnWndProc = s_WndProc;
  268. wc.hInstance = HINST_THISDLL;
  269. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  270. wc.hbrBackground = (HBRUSH)(COLOR_3DFACE+1);
  271. wc.cbWndExtra = sizeof(CUserEventTimer *);
  272. if (!RegisterClassEx(&wc))
  273. {
  274. return FALSE;
  275. }
  276. }
  277. m_hWnd = CreateWindowEx(dwExStyle, c_szUserEventWindow,
  278. NULL, WS_POPUP, 0, 0, 0, 0,
  279. HWND_MESSAGE, NULL, HINST_THISDLL, (void *)this);
  280. if (!m_hWnd)
  281. return FALSE;
  282. }
  283. return TRUE;
  284. }
  285. void CUserEventTimer::_Destroy()
  286. {
  287. if (_dpaUserEventInfo)
  288. {
  289. BOOL bErrorCheck = TRUE;
  290. _dpaUserEventInfo.DestroyCallback(DeleteCB, &bErrorCheck);
  291. }
  292. _KillIntervalTimer();
  293. DestroyWindow(m_hWnd);
  294. }
  295. void CUserEventTimer::_KillIntervalTimer()
  296. {
  297. if (_uUserTimerID)
  298. {
  299. if (_dpaUserEventInfo && _dpaUserEventInfo.GetPtrCount() == 0)
  300. {
  301. KillTimer(m_hWnd, _uUserTimerID);
  302. _uUserTimerID = 0;
  303. }
  304. }
  305. }
  306. ULONG CUserEventTimer::_GetNextInternalTimerID(HWND hWnd)
  307. {
  308. ULONG uStartTimerID = MIN_TIMER_ID;
  309. for (; uStartTimerID <= MAX_TIMER_ID; uStartTimerID++)
  310. {
  311. if (!_IsAssignedTimerID(hWnd, uStartTimerID))
  312. break;
  313. }
  314. if (uStartTimerID > MAX_TIMER_ID)
  315. uStartTimerID = -1;
  316. return uStartTimerID;
  317. }
  318. int CUserEventTimer::_GetTimerDetailsIndex(HWND hWnd, ULONG uUserEventTimerID)
  319. {
  320. if (!_dpaUserEventInfo || !uUserEventTimerID)
  321. return -1;
  322. for (int i = _dpaUserEventInfo.GetPtrCount()-1; i >= 0; i--)
  323. {
  324. USEREVENTINFO * pUserEventInfo = _dpaUserEventInfo.GetPtr(i);
  325. ASSERT(pUserEventInfo);
  326. if (pUserEventInfo->hWnd == hWnd && pUserEventInfo->uUserEventTimerID == uUserEventTimerID)
  327. {
  328. return i;
  329. }
  330. }
  331. return -1;
  332. }
  333. LRESULT CALLBACK CUserEventTimer::s_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  334. {
  335. CUserEventTimer *puet = (CUserEventTimer *)GetWindowLongPtr(hwnd, 0);
  336. if (WM_CREATE == uMsg)
  337. {
  338. CREATESTRUCT *pcs = (CREATESTRUCT *)lParam;
  339. puet = (CUserEventTimer *)pcs->lpCreateParams;
  340. puet->m_hWnd = hwnd;
  341. SetWindowLongPtr(hwnd, 0, (LONG_PTR)puet);
  342. }
  343. return puet ? puet->v_WndProc(uMsg, wParam, lParam) : DefWindowProc(hwnd, uMsg, wParam, lParam);
  344. }
  345. LRESULT CUserEventTimer::v_WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
  346. {
  347. switch (uMsg)
  348. {
  349. case WM_TIMER:
  350. ASSERT(wParam == TIMER_ID);
  351. _OnTimer();
  352. return 0;
  353. default:
  354. return (DefWindowProc(m_hWnd, uMsg, wParam, lParam));
  355. }
  356. }
  357. void CUserEventTimer::_OnTimer()
  358. {
  359. ASSERT(m_hWnd);
  360. if (_dpaUserEventInfo)
  361. {
  362. LONG uTimerDifference = -1;
  363. LASTINPUTINFO lii = {0};
  364. lii.cbSize = sizeof(LASTINPUTINFO);
  365. if (GetLastInputInfo(&lii))
  366. {
  367. if (lii.dwTime < m_dwUserStartTime)
  368. uTimerDifference = 0;
  369. else
  370. uTimerDifference = lii.dwTime - m_dwUserStartTime;
  371. }
  372. LONG uMinTimerDifferenceThreshold = (LONG) (m_uTimerTickInterval * (float)(1-MIN_TIMER_THRESHOLD));
  373. LONG uMaxTimerDifferenceThreshold = (LONG) (m_uTimerTickInterval * (float)(1+MAX_TIMER_THRESHOLD));
  374. for (int i = _dpaUserEventInfo.GetPtrCount()-1; i >= 0; i--)
  375. {
  376. USEREVENTINFO * pUserEventInfo = _dpaUserEventInfo.GetPtr(i);
  377. ASSERT(pUserEventInfo);
  378. if (uTimerDifference != 0)
  379. {
  380. if ( (uTimerDifference == -1) ||
  381. (pUserEventInfo->bFirstTime && uTimerDifference > uMinTimerDifferenceThreshold &&
  382. uTimerDifference <= uMaxTimerDifferenceThreshold) ||
  383. (!pUserEventInfo->bFirstTime && uTimerDifference <= uMaxTimerDifferenceThreshold)
  384. )
  385. {
  386. pUserEventInfo->uIntervalCountdown --;
  387. if (pUserEventInfo->uIntervalCountdown == 0)
  388. {
  389. // Reset the countdown
  390. pUserEventInfo->uIntervalCountdown = _CalcNumIntervals(pUserEventInfo->uTimerElapse);
  391. if (pUserEventInfo->hWnd)
  392. {
  393. PostMessage(pUserEventInfo->hWnd,
  394. pUserEventInfo->uCallbackMessage,
  395. (WPARAM) pUserEventInfo->uTimerElapse,
  396. (LPARAM) pUserEventInfo->uUserEventTimerID);
  397. }
  398. else
  399. {
  400. pUserEventInfo->pUserEventTimerCallback->UserEventTimerProc(
  401. pUserEventInfo->uUserEventTimerID,
  402. pUserEventInfo->uTimerElapse);
  403. }
  404. }
  405. }
  406. }
  407. pUserEventInfo->bFirstTime = FALSE;
  408. }
  409. m_dwUserStartTime = GetTickCount();
  410. }
  411. }
  412. STDAPI CUserEventTimer_CreateInstance(IUnknown* punkOuter, REFIID riid, void **ppv)
  413. {
  414. HRESULT hr = E_OUTOFMEMORY;
  415. CUserEventTimer * pUserEventTimer = new CUserEventTimer();
  416. if (!pUserEventTimer || FAILED(hr = pUserEventTimer->Init()))
  417. {
  418. *ppv = NULL;
  419. }
  420. else
  421. {
  422. hr = pUserEventTimer->QueryInterface(riid, ppv);
  423. pUserEventTimer->Release(); // Already have a ref count from new
  424. }
  425. return hr;
  426. }