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.

1308 lines
37 KiB

  1. //*** uemapp.cpp -- application side of event monitor
  2. // DESCRIPTION
  3. // event generators, actions, helpers, etc.
  4. #include "priv.h"
  5. #include <trayp.h>
  6. #include "sccls.h"
  7. #include "uemapp.h"
  8. #include "uacount.h"
  9. #include "regdb.h"
  10. #include "uareg.h"
  11. #include "resource.h"
  12. #define MAX(a, b) (((a) > (b)) ? (a) : (b))
  13. #define BIT_ASSIGN(dwBits, dwMasks, dwVals) \
  14. (((dwBits) & ~(dwMasks)) | (dwVals))
  15. #define DM_UEMTRACE 0
  16. #define DM_UEMTRACE2 0 // verbose
  17. #define DM_IDLEDETECT 0 // TF_CUSTOM2
  18. #define DM_EVTMON TF_UEM
  19. int SHSearchInt(int *psrc, int cnt, int val);
  20. int UEMIIDToInd(const GUID *pguidGrp);
  21. void UEMEnableTimer(UINT uTimeout);
  22. //*** event firers {
  23. //CASSERT(UEMIND_SHELL == 0 && UEMIND_BROWSER == 1);
  24. HRESULT GetUEMLogger(int iCmd, CEMDBLog **p);
  25. CEMDBLog *g_uempDbLog[UEMIND_NSTANDARD + UEMIND_NINSTR];
  26. DWORD g_uemdwFlags /*=0*/; // UAF_* and UAAF_*
  27. // Turning this so that it's a Flat 12hours. You have to explicitly set the SessionTime=0
  28. // in the registry to debug.
  29. #ifdef DEBUG_UEM_TIMEOUTS
  30. #define UAS_SESSTIME UAT_MINUTE1
  31. #else
  32. #define UAS_SESSTIME UAT_HOUR12
  33. #endif
  34. #define UAS_SESSMIN 0
  35. #define UAS_SESSMAX ... none for now ...
  36. DWORD g_dSessTime = UAS_SESSTIME; // session time threshhold
  37. #define UAS_IDLETIME UAT_HOUR12
  38. #define UAS_IDLEMIN 0
  39. #define UAS_IDLEMAX ... none for now ...
  40. DWORD g_dIdleTime = UAS_IDLETIME; // idle time threshhold
  41. #define UAS_CLEANSESS 16
  42. DWORD g_dCleanSess = UAS_CLEANSESS; // cleanup session count threshhold
  43. void UEMSpecial(int iTab, int iGrp, int eCmd, WPARAM wParam, LPARAM lParam)
  44. {
  45. CEMDBLog *pDbLog = NULL;
  46. if (iGrp < ARRAYSIZE(g_uempDbLog))
  47. pDbLog = g_uempDbLog[iGrp];
  48. if (!pDbLog)
  49. {
  50. ASSERT(0);
  51. TraceMsg(TF_ERROR, "uemt: pDbLog not initialized iTab=%d iGrp=%d eCmd=%d wParam=0x%x lParam=0x%x", iTab, iGrp, eCmd, wParam, lParam);
  52. return;
  53. }
  54. switch (eCmd) {
  55. case UEME_DBTRACEA:
  56. TraceMsg(DM_UEMTRACE, "uemt: e=runtrace s=%hs(0x%x)", (int)lParam, (int)lParam);
  57. break;
  58. case UEME_DBTRACEW:
  59. TraceMsg(DM_UEMTRACE, "uemt: e=runtrace s=%ls(0x%x)", (int)lParam, (int)lParam);
  60. break;
  61. #ifdef DEBUG
  62. case UEME_DBSLEEP:
  63. Sleep((DWORD)lParam);
  64. break;
  65. #endif
  66. // UEME_DONE*
  67. case UEME_DONECANCEL:
  68. TraceMsg(DM_UEMTRACE, "uemt: e=donecancel lP=%x", (int)lParam);
  69. break;
  70. // UEME_ERROR*
  71. case UEME_ERRORA:
  72. TraceMsg(DM_UEMTRACE, "uemt: e=errora id=%hs(0x%x)", (LPSTR)lParam, (int)lParam);
  73. break;
  74. case UEME_ERRORW:
  75. TraceMsg(DM_UEMTRACE, "uemt: e=errorw id=%ls(0x%x)", (LPWSTR)lParam, (int)lParam);
  76. break;
  77. case UEME_CTLSESSION:
  78. ASSERT(lParam == -1); // eventually, UAQ_*
  79. pDbLog->SetSession(UAQ_SESSION, (BOOL)wParam);
  80. #ifdef UAAF_INSTR
  81. // might be safer to copy UA.sess rather than inc UA2.sess in parallel?
  82. if (g_uemdwFlags & UAAF_INSTR)
  83. {
  84. if (EVAL(g_uempDbLog[iGrp + UEMIND_NINSTR]))
  85. g_uempDbLog[iGrp + UEMIND_NINSTR]->SetSession(UAQ_SESSION, (BOOL)wParam);
  86. }
  87. #endif
  88. break;
  89. default:
  90. TraceMsg(DM_UEMTRACE, "uemt: e=0x%x(%d) lP=0x%x(%d)", eCmd, eCmd, (int)lParam, (int)lParam);
  91. break;
  92. }
  93. return;
  94. }
  95. #ifdef DEBUG // {
  96. int DBShellMenuValTab[] =
  97. {
  98. 0x8, // UEMC_FILERUN
  99. 401, // IDM_FILERUN
  100. };
  101. TCHAR * DBShellMenuStrTab[] =
  102. {
  103. TEXT("run"),
  104. TEXT("run"),
  105. };
  106. int DBBrowserMenuValTab[] = {
  107. 0x106,
  108. };
  109. TCHAR * DBBrowserMenuStrTab[] = {
  110. TEXT("properties"),
  111. };
  112. int DBBrowserTbarValTab[] = {
  113. 0x124, 0x122,
  114. };
  115. TCHAR * DBBrowserTbarStrTab[] = {
  116. TEXT("stop"),
  117. TEXT("home"),
  118. };
  119. // Function used only in this file, and only in debug,
  120. // so no point in adding to shlwapi
  121. LPTSTR SHSearchMapIntStr(const int *src, const LPTSTR *dst, int cnt, int val)
  122. {
  123. for (; cnt > 0; cnt--, src++, dst++) {
  124. if (*src == val)
  125. return *dst;
  126. }
  127. return (LPTSTR)-1;
  128. }
  129. #endif // }
  130. #define TABDAT(ueme, dope, u1, u2, u3, u4) ueme,
  131. int UemeValTab[] = {
  132. #include "uemedat.h"
  133. };
  134. #undef TABDAT
  135. #define TABDAT(ueme, dope, u1, u2, u3, u4) TEXT(# ueme),
  136. TCHAR *UemeStrTab[] = {
  137. #include "uemedat.h"
  138. };
  139. #undef TABDAT
  140. #define TABDAT(ueme, dope, u1, u2, u3, u4) dope,
  141. char *UemeDopeTab[] = {
  142. #include "uemedat.h"
  143. };
  144. #undef TABDAT
  145. BOOL UEMEncodePidl(IShellFolder *psf, LPITEMIDLIST pidlItem,
  146. LPTSTR pszBuf, DWORD cchBuf, int* piIndexStart, int* pcsidl);
  147. #define MAX_EVENT_NAME 32
  148. //***
  149. // NOTES
  150. // todo: could put more encoding instrs in dope vector (e.g. %pidl, %tstr)
  151. // for now there are only a couple so we hard-code them
  152. void UEMEncode(int iTab, WCHAR *pwszEvent, size_t cchEvent, WCHAR *pwszEncoded, size_t cchEncoded, int iGrp, int eCmd, WPARAM wParam, LPARAM lParam)
  153. {
  154. #ifdef DEBUG
  155. TCHAR *pdb2;
  156. #endif
  157. int i, csIdl;
  158. TCHAR szBufTmp[MAX_URL_STRING];
  159. TCHAR wszEvent[MAX_PATH];
  160. ASSERT(pwszEvent[0] == 0);
  161. ASSERT(pwszEncoded == 0 || pwszEncoded[0] == 0);
  162. if (iTab == -1 || iTab >= ARRAYSIZE(UemeStrTab))
  163. {
  164. StringCchCopy(pwszEvent, cchEvent, TEXT("UEM?_?"));
  165. }
  166. else
  167. {
  168. StringCchCopy(pwszEvent, cchEvent, UemeStrTab[iTab]);
  169. ASSERT(lstrlen(pwszEvent) < MAX_EVENT_NAME);
  170. if (pwszEncoded) {
  171. switch (eCmd) {
  172. case UEME_RUNPIDL:
  173. if (UEMEncodePidl((IShellFolder *)wParam, (LPITEMIDLIST)lParam, szBufTmp, SIZECHARS(szBufTmp), &i, &csIdl)) {
  174. StringCchPrintf(pwszEncoded, cchEncoded, TEXT("%s:%%csidl%d%%%s"), pwszEvent, csIdl, szBufTmp + i);
  175. }
  176. else {
  177. StringCchPrintf(pwszEncoded, cchEncoded, TEXT("%s:%s"), pwszEvent, szBufTmp);
  178. }
  179. break;
  180. case UEME_RUNPATHA:
  181. ASSERT(lstrcmp(pwszEvent, TEXT("UEME_RUNPATHA")) == 0);
  182. ASSERT(pwszEvent[12] == TEXT('A'));
  183. pwszEvent[12] = 0; // nuke the 'A'/'W'
  184. SHAnsiToTChar((PSTR)lParam, wszEvent, ARRAYSIZE(wszEvent));
  185. if (wParam != -1) {
  186. StringCchPrintf(pwszEncoded, cchEncoded, TEXT("%s:%%csidl%d%%%s"), pwszEvent, wParam, wszEvent);
  187. }
  188. else {
  189. StringCchPrintf(pwszEncoded, cchEncoded, TEXT("%s:%s"), pwszEvent, wszEvent);
  190. }
  191. break;
  192. case UEME_RUNPATHW:
  193. ASSERT(lstrcmp(pwszEvent, TEXT("UEME_RUNPATHW")) == 0);
  194. ASSERT(pwszEvent[12] == TEXT('W'));
  195. pwszEvent[12] = 0; // nuke the 'A'/'W'
  196. if (wParam != -1) {
  197. StringCchPrintf(pwszEncoded, cchEncoded, TEXT("%s:%%csidl%d%%%ls"), pwszEvent, wParam, (WCHAR *)lParam);
  198. }
  199. else {
  200. StringCchPrintf(pwszEncoded, cchEncoded, TEXT("%s:%ls"), pwszEvent, (WCHAR *)lParam);
  201. }
  202. break;
  203. case UEME_RUNCPLA:
  204. ASSERT(lstrcmp(pwszEvent, TEXT("UEME_RUNCPLA")) == 0);
  205. ASSERT(pwszEvent[11] == TEXT('A'));
  206. pwszEvent[11] = 0; // nuke the 'A'/'W'
  207. SHAnsiToTChar((PSTR)lParam, wszEvent, ARRAYSIZE(wszEvent));
  208. StringCchPrintf(pwszEncoded, cchEncoded, TEXT("%s:%s"), pwszEvent, wszEvent);
  209. break;
  210. case UEME_RUNCPLW:
  211. ASSERT(lstrcmp(pwszEvent, TEXT("UEME_RUNCPLW")) == 0);
  212. ASSERT(pwszEvent[11] == TEXT('W'));
  213. pwszEvent[11] = 0; // nuke the 'A'/'W'
  214. StringCchPrintf(pwszEncoded, cchEncoded, TEXT("%s:%ls"), pwszEvent, (WCHAR *)lParam);
  215. break;
  216. default:
  217. StringCchPrintf(pwszEncoded, cchEncoded, TEXT("%s:0x%x,%x"), pwszEvent, (DWORD)wParam, (DWORD)lParam);
  218. break;
  219. }
  220. }
  221. }
  222. #ifdef DEBUG
  223. pdb2 = (TCHAR *)-1;
  224. switch (eCmd) {
  225. case UEME_UIMENU:
  226. switch (iGrp) {
  227. case UEMIND_SHELL:
  228. pdb2 = SHSearchMapIntStr(DBShellMenuValTab, DBShellMenuStrTab, ARRAYSIZE(DBShellMenuValTab), (int)lParam);
  229. break;
  230. case UEMIND_BROWSER:
  231. pdb2 = SHSearchMapIntStr(DBBrowserMenuValTab, DBBrowserMenuStrTab, ARRAYSIZE(DBBrowserMenuValTab), (int)lParam);
  232. break;
  233. default:
  234. break;
  235. }
  236. break;
  237. case UEME_UITOOLBAR:
  238. ASSERT(iGrp == UEMIND_BROWSER);
  239. pdb2 = SHSearchMapIntStr(DBBrowserTbarValTab, DBBrowserTbarStrTab, ARRAYSIZE(DBBrowserTbarValTab), (int)lParam);
  240. break;
  241. default:
  242. break;
  243. }
  244. if (pdb2 != (TCHAR *)-1) {
  245. if (pwszEncoded)
  246. StringCchPrintf(pwszEncoded, cchEncoded, TEXT("%s:%s"), pwszEvent, pdb2);
  247. }
  248. #endif
  249. }
  250. STDAPI _UEMGetDisplayName(IShellFolder *psf, LPCITEMIDLIST pidl, UINT shgdnf, LPTSTR pszOut, DWORD cchOut)
  251. {
  252. HRESULT hr;
  253. if (psf)
  254. {
  255. ASSERT(pidl == ILFindLastID(pidl));
  256. STRRET str;
  257. hr = psf->GetDisplayNameOf(pidl, shgdnf, &str);
  258. if (SUCCEEDED(hr))
  259. hr = StrRetToBuf(&str, pidl, pszOut, cchOut);
  260. }
  261. else
  262. hr = SHGetNameAndFlags(pidl, shgdnf, pszOut, cchOut, NULL);
  263. return hr;
  264. }
  265. //*** FoldCSIDL -- folder special CSIDLs to keep start menu happy
  266. //
  267. #define FoldCSIDL(csidl) \
  268. ((csidl) == CSIDL_COMMON_PROGRAMS ? CSIDL_PROGRAMS : (csidl))
  269. //*** UemEncodePidl -- encode pidl into csidl and relative path
  270. //
  271. BOOL UEMEncodePidl(IShellFolder *psf, LPITEMIDLIST pidlItem,
  272. LPTSTR pszBuf, DWORD cchBuf, int* piIndexStart, int* pcsidl)
  273. {
  274. static UINT csidlTab[] = { CSIDL_PROGRAMS, CSIDL_COMMON_PROGRAMS, CSIDL_FAVORITES, -1 };
  275. UINT *pcsidlCur;
  276. int i;
  277. TCHAR szFolderPath[MAX_PATH];
  278. _UEMGetDisplayName(psf, pidlItem, SHGDN_FORPARSING, pszBuf, cchBuf);
  279. for (pcsidlCur = csidlTab; *pcsidlCur != (UINT)-1; pcsidlCur++)
  280. {
  281. // perf: assume shell32 caches this (it does)
  282. if (SHGetSpecialFolderPath(NULL, szFolderPath, *pcsidlCur, FALSE))
  283. {
  284. i = PathCommonPrefix(szFolderPath, pszBuf, NULL);
  285. if (i != 0 && i == lstrlen(szFolderPath))
  286. {
  287. *pcsidl = FoldCSIDL(*pcsidlCur);
  288. *piIndexStart = i;
  289. return TRUE;
  290. }
  291. }
  292. }
  293. return FALSE;
  294. }
  295. //*** UEMEvalMsg -- fire event
  296. // ENTRY/EXIT
  297. // pguidGrp 'owner' of event. e.g. shell, browser, joe-app, etc.
  298. // eCmd command. one of UEME_* (standard) or UEME_USER+xxx (custom).
  299. // wP, lP args.
  300. // NOTES
  301. // - pri=1 gotta filter events for privacy issues (esp. Ger). not sure if
  302. // we should add a param saying 'usage' of event or just infer it from the
  303. // event.
  304. // - pri=? gotta encrypt the data we log
  305. // - pri=? change to UemEvalMsg(eCmd, wParam, lParam)
  306. //
  307. void UEMEvalMsg(const GUID *pguidGrp, int eCmd, WPARAM wParam, LPARAM lParam)
  308. {
  309. HRESULT hr;
  310. hr = UEMFireEvent(pguidGrp, eCmd, UEMF_XEVENT, wParam, lParam);
  311. return;
  312. }
  313. STDAPI_(BOOL) UEMGetInfo(const GUID *pguidGrp, int eCmd, WPARAM wParam, LPARAM lParam, LPUEMINFO pui)
  314. {
  315. HRESULT hr;
  316. hr = UEMQueryEvent(pguidGrp, eCmd, wParam, lParam, pui);
  317. return SUCCEEDED(hr);
  318. }
  319. class CUserAssist : public IUserAssist
  320. {
  321. public:
  322. //*** IUnknown
  323. virtual STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppv);
  324. virtual STDMETHODIMP_(ULONG) AddRef(void);
  325. virtual STDMETHODIMP_(ULONG) Release(void);
  326. //*** IUserAssist
  327. virtual STDMETHODIMP FireEvent(const GUID *pguidGrp, int eCmd, DWORD dwFlags, WPARAM wParam, LPARAM lParam);
  328. virtual STDMETHODIMP QueryEvent(const GUID *pguidGrp, int eCmd, WPARAM wParam, LPARAM lParam, LPUEMINFO pui);
  329. virtual STDMETHODIMP SetEvent(const GUID *pguidGrp, int eCmd, WPARAM wParam, LPARAM lParam, LPUEMINFO pui);
  330. protected:
  331. CUserAssist();
  332. HRESULT Initialize();
  333. virtual ~CUserAssist();
  334. friend HRESULT CUserAssist_CI2(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi);
  335. friend void CUserAssist_CleanUp(DWORD dwReason, void *lpvReserved);
  336. friend HRESULT UEMRegisterNotify(UEMCallback pfnUEMCB, void *param);
  337. HRESULT _InitLock();
  338. HRESULT _Lock();
  339. HRESULT _Unlock();
  340. void FireNotify(const GUID *pguidGrp, int eCmd)
  341. {
  342. // Assume that we have the lock
  343. if (_pfnNotifyCB)
  344. _pfnNotifyCB(_param, pguidGrp, eCmd);
  345. }
  346. HRESULT RegisterNotify(UEMCallback pfnUEMCB, void *param)
  347. {
  348. HRESULT hr;
  349. int cTries = 0;
  350. do
  351. {
  352. cTries++;
  353. hr = _Lock();
  354. if (SUCCEEDED(hr))
  355. {
  356. _pfnNotifyCB = pfnUEMCB;
  357. _param = param;
  358. _Unlock();
  359. }
  360. else
  361. {
  362. ::Sleep(100); // wait some for the lock to get freed up
  363. }
  364. }
  365. while (FAILED(hr) && cTries < 20);
  366. return hr;
  367. }
  368. private:
  369. LONG _cRef;
  370. HANDLE _hLock;
  371. UEMCallback _pfnNotifyCB;
  372. void *_param;
  373. };
  374. #define SZ_UALOCK TEXT("_SHuassist.mtx")
  375. void DoLog(CEMDBLog *pDbLog, TCHAR *pszBuf1, TCHAR *pszBuf2)
  376. {
  377. if (pDbLog && *pszBuf1) {
  378. pDbLog->IncCount(pszBuf1);
  379. if (*pszBuf2) {
  380. //ASSERT(iGrp == UEMIND_BROWSER); // not req'd but currently true
  381. pDbLog->IncCount(pszBuf2);
  382. }
  383. }
  384. return;
  385. }
  386. HRESULT CUserAssist::FireEvent(const GUID *pguidGrp, int eCmd, DWORD dwFlags, WPARAM wParam, LPARAM lParam)
  387. {
  388. TCHAR szBuf1[32]; // "UEME_xxx"
  389. TCHAR szBuf2[MAX_URL_STRING]; // "UEME_xxx:0x%x,%x"
  390. int iGrp;
  391. CEMDBLog *pDbLog;
  392. int i, iTab;
  393. char ch;
  394. char *pszDope;
  395. ASSERT(this != 0);
  396. // If called for instrumentation (NOT event monitor) and instrumentation not enabled
  397. // we should exit!
  398. if ((UEMF_INSTRUMENT == (dwFlags & UEMF_MASK)) && (!(g_uemdwFlags & UAAF_INSTR)))
  399. return E_FAIL;
  400. if (g_uemdwFlags & UAAF_NOLOG)
  401. return E_FAIL;
  402. if (eCmd & UEME_FBROWSER) {
  403. ASSERT(0);
  404. ASSERT(IsEqualIID(*pguidGrp, UEMIID_NIL));
  405. pguidGrp = &UEMIID_BROWSER;
  406. eCmd &= ~UEME_FBROWSER;
  407. }
  408. iGrp = UEMIIDToInd(pguidGrp);
  409. pDbLog = g_uempDbLog[iGrp];
  410. TraceMsg(DM_UEMTRACE2, "uemt: eCmd=0x%x wP=0x%x lP=0x%x(%d)", eCmd, wParam, (int)lParam, (int)lParam);
  411. szBuf1[0] = szBuf2[0] = 0;
  412. iTab = SHSearchInt(UemeValTab, ARRAYSIZE(UemeValTab), eCmd);
  413. if (iTab == -1) {
  414. ASSERT(0);
  415. return E_FAIL;
  416. }
  417. pszDope = UemeDopeTab[iTab];
  418. while (ch = *pszDope++) {
  419. switch (ch) {
  420. case 'e':
  421. i = *pszDope++ - '0';
  422. if (i >= 2)
  423. {
  424. UEMEncode(iTab, szBuf1, ARRAYSIZE(szBuf1), szBuf2, ARRAYSIZE(szBuf2), iGrp, eCmd, wParam, lParam);
  425. }
  426. else
  427. {
  428. UEMEncode(iTab, szBuf1, ARRAYSIZE(szBuf1), NULL, 0, iGrp, eCmd, wParam, lParam);
  429. }
  430. TraceMsg(DM_UEMTRACE, "uemt: %s %s (0x%x %x %x)", szBuf1, szBuf2, eCmd, wParam, lParam);
  431. break;
  432. case 'f':
  433. // make sure we don't cause ourselves trouble in future
  434. // EM only gives us a couple of DWORDs, so we need s.t. like:
  435. // bits(UEMIND_*)+bits(wParam)+bits(lParam) <= bits(DWORD)
  436. // for now we allow 0/-1 in hiword, if/when we use EM we'll
  437. // need to clean that up.
  438. break;
  439. case 'l':
  440. if (SUCCEEDED(_Lock())) {
  441. if (dwFlags & UEMF_EVENTMON)
  442. DoLog(pDbLog, szBuf1, szBuf2);
  443. #ifdef UAAF_INSTR
  444. if ((g_uemdwFlags & UAAF_INSTR) && (dwFlags & UEMF_INSTRUMENT))
  445. DoLog(g_uempDbLog[iGrp + UEMIND_NINSTR], szBuf1, szBuf2);
  446. #endif
  447. FireNotify(pguidGrp, eCmd);
  448. _Unlock();
  449. }
  450. break;
  451. case 'x':
  452. TraceMsg(DM_UEMTRACE, "uemt: NYI");
  453. goto Lnodope;
  454. #ifdef DEBUG
  455. case '!':
  456. ASSERT(0);
  457. break;
  458. #endif
  459. case '@':
  460. if (SUCCEEDED(_Lock())) {
  461. UEMSpecial(iTab, iGrp, eCmd, wParam, lParam);
  462. FireNotify(pguidGrp, eCmd);
  463. _Unlock();
  464. }
  465. break;
  466. }
  467. }
  468. Lnodope:
  469. return S_OK;
  470. }
  471. HRESULT CUserAssist::QueryEvent(const GUID *pguidGrp, int eCmd, WPARAM wParam, LPARAM lParam, LPUEMINFO pui)
  472. {
  473. int iGrp;
  474. CEMDBLog *pDbLog;
  475. TCHAR szBuf1[32]; // "UEME_xxx"
  476. TCHAR szBuf2[MAX_URL_STRING]; // "UEME_xxx:0x%x,%x"
  477. ASSERT(this != 0);
  478. if (g_uemdwFlags & UAAF_NOLOG)
  479. return E_FAIL;
  480. ASSERT(eCmd == UEME_RUNPIDL
  481. || eCmd == UEME_RUNPATH || eCmd == UEME_RUNWMCMD); // others NYI
  482. ASSERT(pui->cbSize == SIZEOF(*pui));
  483. // pui->dwVersion?
  484. iGrp = UEMIIDToInd(pguidGrp);
  485. pDbLog = g_uempDbLog[iGrp];
  486. TraceMsg(DM_UEMTRACE2, "uemgi: eCmd=0x%x wP=0x%x lP=0x%x(%d)", eCmd, wParam, (int)lParam, (int)lParam);
  487. szBuf1[0] = szBuf2[0] = 0;
  488. int iTab = SHSearchInt(UemeValTab, ARRAYSIZE(UemeValTab), eCmd);
  489. UEMEncode(iTab, szBuf1, ARRAYSIZE(szBuf1), szBuf2, ARRAYSIZE(szBuf2), iGrp, eCmd, wParam, lParam);
  490. int cHit;
  491. //if (SUCCEEDED(_Lock()))
  492. cHit = pDbLog->GetCount(szBuf2);
  493. //_Unlock();
  494. TraceMsg(DM_UEMTRACE, "uemgi: cHit=%d psz=%s", cHit, szBuf2);
  495. if (pui->dwMask & UEIM_HIT)
  496. {
  497. pui->cHit = cHit;
  498. }
  499. if (pui->dwMask & UEIM_FILETIME)
  500. {
  501. pui->ftExecute = pDbLog->GetFileTime(szBuf2);
  502. }
  503. return S_OK;
  504. }
  505. HRESULT CUserAssist::SetEvent(const GUID *pguidGrp, int eCmd, WPARAM wParam, LPARAM lParam, LPUEMINFO pui)
  506. {
  507. int iGrp;
  508. CEMDBLog *pDbLog;
  509. TCHAR szBuf1[32]; // "UEME_xxx"
  510. TCHAR szBuf2[MAX_URL_STRING]; // "UEME_xxx:0x%x,%x"
  511. ASSERT(this != 0);
  512. if (g_uemdwFlags & UAAF_NOLOG)
  513. return E_FAIL;
  514. ASSERT(pui->cbSize == SIZEOF(*pui));
  515. // pui->dwVersion?
  516. iGrp = UEMIIDToInd(pguidGrp);
  517. pDbLog = g_uempDbLog[iGrp];
  518. TraceMsg(DM_UEMTRACE2, "uemgi: eCmd=0x%x wP=0x%x lP=0x%x(%d)", eCmd, wParam, (int)lParam, (int)lParam);
  519. szBuf1[0] = szBuf2[0] = 0;
  520. int iTab = SHSearchInt(UemeValTab, ARRAYSIZE(UemeValTab), eCmd);
  521. UEMEncode(iTab, szBuf1, ARRAYSIZE(szBuf1), szBuf2, ARRAYSIZE(szBuf2), iGrp, eCmd, wParam, lParam);
  522. pui->dwMask &= UEIM_HIT | UEIM_FILETIME; // what we support
  523. if (pui->dwMask && SUCCEEDED(_Lock())) {
  524. if (pui->dwMask & UEIM_HIT) {
  525. pDbLog->SetCount(szBuf2, pui->cHit);
  526. }
  527. if (pui->dwMask & UEIM_FILETIME) {
  528. pDbLog->SetFileTime(szBuf2, &pui->ftExecute);
  529. }
  530. _Unlock();
  531. }
  532. return S_OK;
  533. }
  534. //*** CUserAssist::CCI,ctor/dtor/init {
  535. IUnknown *g_uempUaSingleton;
  536. //*** CUserAssist_CreateInstance -- manage *singleton* instance
  537. //
  538. HRESULT CUserAssist_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
  539. {
  540. HRESULT hr = E_FAIL;
  541. if (g_uempUaSingleton == 0) {
  542. IUnknown *pua;
  543. hr = CUserAssist_CI2(pUnkOuter, &pua, poi);
  544. if (pua)
  545. {
  546. ENTERCRITICAL;
  547. if (g_uempUaSingleton == 0)
  548. {
  549. // Now the global owns the ref.
  550. g_uempUaSingleton = pua; // xfer refcnt
  551. pua = NULL;
  552. }
  553. LEAVECRITICAL;
  554. if (pua)
  555. {
  556. // somebody beat us.
  557. // free up the 2nd one we just created, and use new one
  558. TraceMsg(DM_UEMTRACE, "sl.cua_ci: undo race");
  559. pua->Release();
  560. }
  561. // Now, the caller gets it's own ref.
  562. g_uempUaSingleton->AddRef();
  563. TraceMsg(DM_UEMTRACE, "sl.cua_ci: create pua=0x%x g_uempUaSingleton=%x", pua, g_uempUaSingleton);
  564. }
  565. }
  566. else {
  567. g_uempUaSingleton->AddRef();
  568. }
  569. TraceMsg(DM_UEMTRACE, "sl.cua_ci: ret g_uempUaSingleton=0x%x", g_uempUaSingleton);
  570. *ppunk = g_uempUaSingleton;
  571. return *ppunk ? S_OK : hr;
  572. }
  573. //*** CUserAssist_CI2 -- *always* create instance
  574. //
  575. HRESULT CUserAssist_CI2(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
  576. {
  577. CUserAssist * p = new CUserAssist();
  578. if (p && FAILED(p->Initialize())) {
  579. delete p;
  580. p = NULL;
  581. }
  582. if (p) {
  583. *ppunk = SAFECAST(p, IUserAssist*);
  584. return S_OK;
  585. }
  586. *ppunk = NULL;
  587. return E_OUTOFMEMORY;
  588. }
  589. extern "C"
  590. HRESULT UEMRegisterNotify(UEMCallback pfnUEMCB, void *param)
  591. {
  592. HRESULT hr = E_UNEXPECTED;
  593. if (g_uempUaSingleton)
  594. {
  595. CUserAssist *pua = reinterpret_cast<CUserAssist *>(g_uempUaSingleton);
  596. hr = pua->RegisterNotify(pfnUEMCB, param);
  597. }
  598. return hr;
  599. }
  600. extern void GetUEMSettings();
  601. DWORD g_dwSessionStart; // When did this session start?
  602. #if defined(_M_IX86) && (_MSC_VER < 1200)
  603. #pragma optimize("", off)
  604. #define BUG_OPTIMIZE // restore, see below
  605. #endif
  606. //***
  607. HRESULT CUserAssist::Initialize()
  608. {
  609. HRESULT hr = S_OK;
  610. ASSERT(UEMIND_SHELL == 0 && UEMIND_BROWSER == 1);
  611. hr = _InitLock();
  612. // get standard loggers
  613. if (SUCCEEDED(hr))
  614. hr = GetUEMLogger(UEMIND_SHELL, &g_uempDbLog[UEMIND_SHELL]);
  615. if (SUCCEEDED(hr))
  616. hr = GetUEMLogger(UEMIND_BROWSER, &g_uempDbLog[UEMIND_BROWSER]);
  617. GetUEMSettings();
  618. #define UAXF_XSETTINGS (UAXF_NOPURGE|UAXF_BACKUP|UAXF_NOENCRYPT)
  619. if (g_uempDbLog[UEMIND_SHELL])
  620. {
  621. g_uempDbLog[UEMIND_SHELL]->_SetFlags(UAXF_XSETTINGS, g_uemdwFlags & UAXF_XSETTINGS);
  622. // n.b. just for shell (browser no need, instr no decay)
  623. g_uempDbLog[UEMIND_SHELL]->GarbageCollect(FALSE);
  624. }
  625. if (g_uempDbLog[UEMIND_BROWSER])
  626. {
  627. g_uempDbLog[UEMIND_BROWSER]->_SetFlags(UAXF_XSETTINGS, g_uemdwFlags & UAXF_XSETTINGS);
  628. g_uempDbLog[UEMIND_BROWSER]->GarbageCollect(FALSE);
  629. }
  630. #ifdef UAAF_INSTR
  631. if (g_uemdwFlags & UAAF_INSTR) {
  632. if (SUCCEEDED(hr))
  633. hr = GetUEMLogger(UEMIND_SHELL2, &g_uempDbLog[UEMIND_SHELL2]);
  634. if (SUCCEEDED(hr))
  635. hr = GetUEMLogger(UEMIND_BROWSER2, &g_uempDbLog[UEMIND_BROWSER2]);
  636. if (g_uempDbLog[UEMIND_SHELL2]) {
  637. g_uempDbLog[UEMIND_SHELL2]->_SetFlags(UAXF_XSETTINGS, g_uemdwFlags & UAXF_XSETTINGS);
  638. g_uempDbLog[UEMIND_SHELL2]->_SetFlags(UAXF_NODECAY, UAXF_NODECAY);
  639. }
  640. if (g_uempDbLog[UEMIND_BROWSER2]) {
  641. g_uempDbLog[UEMIND_BROWSER2]->_SetFlags(UAXF_XSETTINGS, g_uemdwFlags & UAXF_XSETTINGS);
  642. g_uempDbLog[UEMIND_BROWSER2]->_SetFlags(UAXF_NODECAY, UAXF_NODECAY);
  643. }
  644. }
  645. #endif
  646. g_dwSessionStart = GetTickCount();
  647. UEMEnableTimer(UATTOMSEC(g_dIdleTime));
  648. return hr;
  649. }
  650. #ifdef BUG_OPTIMIZE
  651. #pragma optimize("", on)
  652. #undef BUG_OPTIMIZE
  653. #endif
  654. void CEMDBLog_CleanUp();
  655. //*** CUserAssist_CleanUp -- free up the world (on DLL_PROCESS_DETACH)
  656. // NOTES
  657. // a bit hoaky right now since our UEMLog object isn't really refcnt'ed
  658. void CUserAssist_CleanUp(DWORD dwReason, void *lpvReserved)
  659. {
  660. int i;
  661. IUnknown *pUa;
  662. ASSERT(dwReason == DLL_PROCESS_DETACH);
  663. if (lpvReserved != 0) {
  664. // on process termination, *don't* nuke us since:
  665. // - safety: other DLLs in our process may still be using us, and
  666. // they'll blow up when they reference us if we're freed
  667. // - leaks: process termination will free us up when all is done,
  668. // so there's no worry about a leak
  669. TraceMsg(DM_UEMTRACE, "bui.cua_cu: skip cleanup (end process/non-FreeLibrary)");
  670. return;
  671. }
  672. // otherwise, on FreeLibrary, *do* nuke us since:
  673. // - safety: our refcnt is 0, so nobody is using us any more
  674. // - leaks: multiple Load/FreeLibrary calls will cause a leak if we
  675. // don't free ourselves here
  676. //ENTERCRITICAL;
  677. TraceMsg(DM_UEMTRACE, "bui.cua_cu: cleaning up");
  678. UEMEnableTimer(0);
  679. // free cache (and make sure we'll GPF if we party on it further)
  680. for (i = 0; i < UEMIND_NSTANDARD + UEMIND_NINSTR; i++) {
  681. // UEMIND_SHELL, UEMIND_BROWSER, UEMIND_SHELL2, UEMIND_BROWSER2
  682. InterlockedExchangePointer((void**) &g_uempDbLog[i], (LPVOID) -1);
  683. }
  684. // free 'real' guy
  685. CEMDBLog_CleanUp();
  686. // free THIS
  687. if (pUa = (IUnknown *)InterlockedExchangePointer((void**) &g_uempUaSingleton, (LPVOID) -1)) {
  688. delete SAFECAST(pUa, CUserAssist *);
  689. }
  690. //LEAVECRITICAL;
  691. }
  692. DWORD Reg_GetFlags(DWORD dwInit, HKEY hk, LPCTSTR pszSubkey, LPCTSTR const pszNameTab[], DWORD *dwMaskTab, int cTab)
  693. {
  694. int i;
  695. DWORD dwMasks, dwVals;
  696. dwMasks = dwVals = 0;
  697. for (i = 0; i < cTab; i++) {
  698. DWORD dwData, cbSize = SIZEOF(dwData);
  699. if (SHGetValue(hk, pszSubkey, pszNameTab[i], NULL, &dwData, &cbSize) == ERROR_SUCCESS) {
  700. TraceMsg(DM_UEMTRACE, "ua: regkey %s\\%s=0x%x", pszSubkey, pszNameTab[i], dwData);
  701. dwMasks |= dwMaskTab[i];
  702. if (dwData)
  703. dwVals |= dwMaskTab[i];
  704. }
  705. }
  706. dwInit = BIT_ASSIGN(dwInit, dwMasks, dwVals);
  707. TraceMsg(DM_UEMTRACE, "ua.grs: ret 0x%x", dwInit);
  708. return dwInit;
  709. }
  710. void Reg_GetVals(HKEY hk, LPCTSTR pszSubkey, LPCTSTR const pszNameTab[], DWORD **dwValTab, int cTab)
  711. {
  712. for (int i = 0; i < cTab; i++) {
  713. DWORD dwData, cbSize = SIZEOF(dwData);
  714. if (SHGetValue(hk, pszSubkey, pszNameTab[i], NULL, &dwData, &cbSize) == ERROR_SUCCESS) {
  715. TraceMsg(DM_UEMTRACE, "ua: regkey %s/%s=0x%x", pszSubkey, pszNameTab[i], dwData);
  716. *dwValTab[i] = dwData;
  717. }
  718. }
  719. }
  720. void GetUEMSettings()
  721. {
  722. HKEY hk = SHGetShellKey(SHELLKEY_HKCU_EXPLORER, NULL, FALSE);
  723. if (hk)
  724. {
  725. static const LPCTSTR pszName1Tab[] = {
  726. SZ_NOPURGE , SZ_BACKUP , SZ_NOLOG , SZ_INSTRUMENT, SZ_NOENCRYPT,
  727. };
  728. static DWORD dwMask1Tab[] = {
  729. UAXF_NOPURGE, UAXF_BACKUP, UAAF_NOLOG, UAAF_INSTR , UAXF_NOENCRYPT,
  730. };
  731. static const LPCTSTR pszName2Tab[] = { SZ_SESSTIME, SZ_IDLETIME , SZ_CLEANTIME, };
  732. static DWORD *dwVal2Tab[] = { &g_dSessTime, &g_dIdleTime, &g_dCleanSess,};
  733. g_uemdwFlags = Reg_GetFlags(g_uemdwFlags, hk, SZ_UASSIST TEXT("\\") SZ_SETTINGS, pszName1Tab, dwMask1Tab, ARRAYSIZE(pszName1Tab));
  734. TraceMsg(DM_UEMTRACE, "ua: g_uemdwFlags=0x%x", g_uemdwFlags);
  735. Reg_GetVals(hk, SZ_UASSIST TEXT("\\") SZ_SETTINGS, pszName2Tab, dwVal2Tab, ARRAYSIZE(pszName2Tab));
  736. if (!((int)UAS_SESSMIN <= (int)g_dSessTime /*&& g_dSessTime<=UAS_SESSMAX*/))
  737. g_dSessTime = UAS_SESSTIME;
  738. if (!((int)UAS_IDLEMIN <= (int)g_dIdleTime /*&& g_dIdleTime<=UAS_IDLEMAX*/))
  739. g_dIdleTime = UAS_IDLETIME;
  740. RegCloseKey(hk);
  741. }
  742. if (SHRestricted2(REST_NoUserAssist, NULL, 0)) {
  743. TraceMsg(DM_WARNING, "ua: restrict off!");
  744. g_uemdwFlags |= UAAF_NOLOG;
  745. g_uemdwFlags &= ~UAAF_INSTR; // paranoia (UAAF_NOLOG should be enuf)
  746. }
  747. #ifdef DEBUG
  748. if (g_uemdwFlags & UAAF_NOLOG)
  749. TraceMsg(DM_WARNING, "ua: logging off!");
  750. #endif
  751. return;
  752. }
  753. CUserAssist::CUserAssist() : _cRef(1)
  754. {
  755. return;
  756. }
  757. //***
  758. // NOTES
  759. // n.b. we're only called on DLL_PROCESS_DETACH (refcnt never really
  760. // goes to 0).
  761. CUserAssist::~CUserAssist()
  762. {
  763. if (_hLock)
  764. CloseHandle(_hLock);
  765. #if 1 // 981022 breadcrumbs for stress failure (see if we're double freed)
  766. //memcpy((BYTE *)_hLock, "CUAd", 4);
  767. _hLock = (void *)0x77777777;
  768. #endif
  769. return;
  770. }
  771. // }
  772. //*** CUserAssist::IUnknown::* {
  773. ULONG CUserAssist::AddRef()
  774. {
  775. ULONG cRef = InterlockedIncrement(&_cRef);
  776. TraceMsg(DM_UEMTRACE2, "cua.ar: _cRef=%d", cRef);
  777. return cRef;
  778. }
  779. ULONG CUserAssist::Release()
  780. {
  781. ASSERT( 0 != _cRef );
  782. ULONG cRef = InterlockedDecrement(&_cRef);
  783. if ( 0 == cRef )
  784. {
  785. delete this;
  786. }
  787. TraceMsg(DM_UEMTRACE2, "cua.r: cRef=%d", cRef);
  788. return cRef;
  789. }
  790. HRESULT CUserAssist::QueryInterface(REFIID riid, void **ppvObj)
  791. {
  792. static const QITAB qit[] = {
  793. QITABENT(CUserAssist, IUserAssist), // IID_IUserAssist
  794. { 0 },
  795. };
  796. return QISearch(this, qit, riid, ppvObj);
  797. }
  798. // }
  799. //*** locking stuff {
  800. HRESULT CUserAssist::_InitLock()
  801. {
  802. HRESULT hr = S_OK;
  803. if ((_hLock = CreateMutex(NULL, FALSE, SZ_UALOCK)) == NULL) {
  804. TraceMsg(TF_ERROR, "cua.i: no mutex");
  805. hr = E_FAIL;
  806. }
  807. return hr;
  808. }
  809. #define LOCK_TIMEOUT 0 // immediate timeout, should be rare
  810. HRESULT CUserAssist::_Lock()
  811. {
  812. DWORD dwRes;
  813. dwRes = WaitForSingleObject(_hLock, LOCK_TIMEOUT);
  814. switch (dwRes) {
  815. case WAIT_ABANDONED:
  816. return S_FALSE;
  817. case WAIT_OBJECT_0:
  818. return S_OK;
  819. case WAIT_TIMEOUT:
  820. TraceMsg(DM_UEMTRACE, "cua.l: locked (timeout)");
  821. return E_FAIL;
  822. }
  823. /*NOTREACHED*/
  824. return E_FAIL;
  825. }
  826. HRESULT CUserAssist::_Unlock()
  827. {
  828. ReleaseMutex(_hLock);
  829. return S_OK;
  830. }
  831. // }
  832. //*** timer stuff {
  833. DWORD_PTR g_idTimer;
  834. BOOL g_fIdle /*=FALSE*/;
  835. #if !(_WIN32_WINNT >= 0x0500) // {
  836. #define GetLastInputInfo UEMGetLastInputInfo
  837. typedef struct {
  838. UINT cbSize;
  839. DWORD dwTime;
  840. } LASTINPUTINFO;
  841. DWORD g_dwTime; // prev GetTickCount
  842. int g_csKeys; // prev GetKeyboardState
  843. int g_csCursor; // prev GetCursorPos
  844. BOOL (*g_pfnGLII)(LASTINPUTINFO *plii); // 'real' version
  845. //*** memsum -- checksum bytes
  846. //
  847. int memsum(void *pv, int n)
  848. {
  849. unsigned char *pb = (unsigned char *)pv;
  850. int sum = 0;
  851. while (n-- > 0)
  852. sum += *pb++;
  853. return sum;
  854. }
  855. //*** UEMGetLastInputInfo -- simulate (sort of...) GetLastInputInfo
  856. // DESCRIPTION
  857. // we fake it big time. our detection of 'currently non-idle' is pretty
  858. // good, but the the actual *time* we were idle is pretty iffy. each time
  859. // we're called defines a checkpoint. any time the new checkpoint differs
  860. // from the old one, we update our (approx) idle start point.
  861. BOOL UEMGetLastInputInfo(LASTINPUTINFO *plii)
  862. {
  863. int csCursor, csKeys;
  864. POINT ptCursor;
  865. BYTE ksKeys[256]; // per GetKeyboardState spec
  866. if (g_dwTime == 0) {
  867. // 1st time here...
  868. g_dwTime = GetTickCount();
  869. g_csCursor = g_csKeys = -1;
  870. // GetProcAddress only accepts ANSI.
  871. *(FARPROC *)&g_pfnGLII = GetProcAddress(GetModuleHandle(TEXT("user32.dll")),
  872. "GetLastInputInfo");
  873. TraceMsg(DM_UEMTRACE, "bui.glii: init g_dwTime=%d pfn=0x%x", g_dwTime, g_pfnGLII);
  874. }
  875. #if 1 // 980313 adp: off until we can test it!
  876. // 1st try the easy (and exact) way...
  877. if (g_pfnGLII)
  878. return (*g_pfnGLII)(plii);
  879. #endif
  880. // now the hard (and approximate) way...
  881. csCursor = csKeys = -1;
  882. if (GetCursorPos(&ptCursor))
  883. csCursor = memsum(&ptCursor, SIZEOF(ptCursor));
  884. if (GetKeyboardState(ksKeys))
  885. csKeys = memsum(ksKeys, SIZEOF(ksKeys));
  886. if (csCursor != g_csCursor || csKeys != g_csKeys
  887. || (csCursor == -1 && csKeys == -1)) {
  888. TraceMsg(DM_UEMTRACE, "bui.glli: !idle cur=0x%x cur'=%x keys=%x keys'=%x gtc(old)=%x",
  889. g_csCursor, csCursor, g_csKeys, csKeys, g_dwTime);
  890. g_dwTime = GetTickCount();
  891. g_csCursor = csCursor;
  892. g_csKeys = csKeys;
  893. }
  894. plii->dwTime = g_dwTime;
  895. TraceMsg(DM_UEMTRACE, "bui.uastp: !nt5, simulate GLII()=%d", plii->dwTime);
  896. return TRUE;
  897. }
  898. #endif // }
  899. LRESULT UEMSendTrayMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
  900. {
  901. //
  902. // We may be sending a function pointer, so make sure the target window
  903. // is in our address space.
  904. //
  905. // We need to revalidate that g_hwndTray really is the
  906. // tray window, because Explorer may have crashed, and then the
  907. // window handle got recycled into our process, and so we send
  908. // a random message to a window that isn't what we think it is.
  909. // (raymondc)
  910. //
  911. HWND hwndTray;
  912. DWORD dwPid;
  913. LRESULT lres;
  914. hwndTray = GetTrayWindow();
  915. if (IsWindow(hwndTray) &&
  916. GetWindowThreadProcessId(hwndTray, &dwPid) &&
  917. dwPid == GetCurrentProcessId()) {
  918. lres = SendMessage(hwndTray, uMsg, wParam, lParam);
  919. } else {
  920. lres = 0;
  921. }
  922. return lres;
  923. }
  924. //***
  925. //
  926. // UEMTimerProc
  927. //
  928. // Periodically checks if the user has gone idle.
  929. //
  930. // Rules for session increment:
  931. //
  932. // No session lasts longer than g_dIdleTime units.
  933. //
  934. // If the user remains idle for a long time, keep bumping the
  935. // "start of session" timer so time spent idle does not count towards
  936. // the new session.
  937. //
  938. void CALLBACK UEMTimerProc(HWND hwnd, UINT uMsg, UINT idEvt, DWORD dwNow)
  939. {
  940. #ifdef DEBUG
  941. static long iDepth; // make sure we don't get 2 ticks
  942. #endif
  943. UINT dwIdleTime; // mSec
  944. LASTINPUTINFO lii;
  945. ASSERT(iDepth == 0);
  946. ASSERT(InterlockedIncrement(&iDepth) > 0);
  947. UEMEnableTimer(0);
  948. dwIdleTime = UATTOMSEC(g_dIdleTime); // convert to mSec's (again...)
  949. lii.cbSize = SIZEOF(lii);
  950. if (GetLastInputInfo(&lii)) {
  951. DWORD dwNow = GetTickCount();
  952. TraceMsg(DM_IDLEDETECT, "UEM.tp: now-start=%d, now-last=%d",
  953. dwNow - g_dwSessionStart, dwNow - lii.dwTime);
  954. if (!g_fIdle && dwNow - g_dwSessionStart >= dwIdleTime)
  955. {
  956. g_fIdle = TRUE;
  957. g_dwSessionStart = dwNow;
  958. TraceMsg(DM_IDLEDETECT, "UEM.tp: IncrementSession");
  959. UEMFireEvent(&UEMIID_SHELL, UEME_CTLSESSION, UEMF_XEVENT, TRUE, -1);
  960. UEMFireEvent(&UEMIID_BROWSER, UEME_CTLSESSION, UEMF_XEVENT, TRUE, -1);
  961. UEMSendTrayMessage(TM_REFRESH, 0, 0); // RefreshStartMenu
  962. }
  963. //
  964. // Get out of idle mode if the user has done anything since
  965. // the session started. And mark the session as having started
  966. // at the point the user did something.
  967. //
  968. if (dwNow - lii.dwTime < dwNow - g_dwSessionStart) {
  969. TraceMsg(DM_IDLEDETECT, "UEM.tp: not idle; starting new session");
  970. g_dwSessionStart = lii.dwTime;
  971. g_fIdle = FALSE;
  972. }
  973. //
  974. // Now decide how much longer before the next interesting event.
  975. //
  976. DWORD dwWait = g_fIdle ? dwIdleTime : dwIdleTime - (dwNow - g_dwSessionStart);
  977. TraceMsg(DM_UEMTRACE, "UEM.tp: sleep=%d", dwWait);
  978. UEMEnableTimer(dwWait);
  979. }
  980. //else timer left disabled
  981. ASSERT(InterlockedDecrement(&iDepth) == 0);
  982. return;
  983. }
  984. //*** UEMEnableTimer -- turn timer on/off
  985. // ENTRY
  986. // uTimeout delay in mSec; 0 means disable
  987. void UEMEnableTimer(UINT uTimeout)
  988. {
  989. #if !(_WIN32_WINNT >= 0x0500)
  990. static BOOL fVirg = TRUE; // 1st time thru?
  991. if (fVirg) {
  992. LASTINPUTINFO lii;
  993. fVirg = FALSE;
  994. lii.cbSize = SIZEOF(lii);
  995. GetLastInputInfo(&lii); // prime it in case it's simulated
  996. }
  997. #endif
  998. if (uTimeout) {
  999. // ASSERT(!g_idTimer); // race window can hit this assert spuriously
  1000. g_idTimer = UEMSendTrayMessage(TM_SETTIMER, uTimeout, (LPARAM)UEMTimerProc);
  1001. }
  1002. else if (g_idTimer) {
  1003. UEMSendTrayMessage(TM_KILLTIMER, 0, g_idTimer);
  1004. g_idTimer = 0;
  1005. }
  1006. return;
  1007. }
  1008. // }
  1009. // }
  1010. //*** utils {
  1011. //*** FAST_IsEqualIID -- fast compare
  1012. // (cast to 'int' so don't get overloaded ==)
  1013. #define FAST_IsEqualIID(piid1, piid2) ((int) (piid1) == (int) (piid2))
  1014. //***
  1015. // ENTRY/EXIT
  1016. // iGuid (return) index of GUID in table, o.w. -1 if not found
  1017. // NOTES
  1018. // move to shlwapi if this is needed some place other than here.
  1019. int SHSearchIID(IID **pguidTab, int cnt, IID *pguidVal)
  1020. {
  1021. IID **pguid;
  1022. BOOL fInt;
  1023. pguid = pguidTab;
  1024. fInt = (pguidVal == 0 || pguidVal == (IID *)-1);
  1025. for (; cnt > 0; cnt--, pguid++) {
  1026. if (fInt) {
  1027. if (*pguid == pguidVal)
  1028. goto Lfound;
  1029. }
  1030. else if (IsEqualIID(**pguid, *pguidVal)) {
  1031. Lfound:
  1032. return (int)(pguid - pguidTab);
  1033. }
  1034. }
  1035. return -1;
  1036. }
  1037. int SHSearchInt(int *psrc, int cnt, int val)
  1038. {
  1039. int *pcur;
  1040. pcur = psrc;
  1041. for (; cnt > 0; cnt--, pcur++) {
  1042. if (*pcur == val)
  1043. return (int)(pcur - psrc);
  1044. }
  1045. return -1;
  1046. }
  1047. int UEMIIDToInd(const GUID *pguidGrp)
  1048. {
  1049. int iGrp;
  1050. if (IsEqualIID(*pguidGrp, UEMIID_BROWSER))
  1051. iGrp = UEMIND_BROWSER;
  1052. else if (IsEqualIID(*pguidGrp, UEMIID_SHELL))
  1053. iGrp = UEMIND_SHELL;
  1054. else
  1055. {
  1056. ASSERT(IsEqualIID(*pguidGrp, UEMIID_NIL));
  1057. iGrp = UEMIND_SHELL;
  1058. }
  1059. return iGrp;
  1060. }
  1061. // }