uemapp.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 41k
Category:

Windows Kernel

Development Platform:

Visual C++

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