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

385 lines
9.4 KiB

  1. //*** CUACount -- user-assistance counter w/ decay
  2. // NOTES
  3. // todo: scavenging to clean out registry. but see caveats in UAC_CDEF.
  4. #include "priv.h"
  5. #include "uacount.h"
  6. #include "uareg.h"
  7. #define DM_UEMTRACE TF_UEM
  8. #define MAX(a, b) (((a) > (b)) ? (a) : (b))
  9. //*** UAC_CDEFAULT -- initial _cCnt for entry (we *always* show items)
  10. // NOTES
  11. // eventually we might want to scavenge all entries, decaying them down
  12. // and deleting any that decay to 0. note however that this will cause
  13. // them to look like they have a default count of 1 (see CUAC::Init), so
  14. // they'll suddenly appear on the menus again.
  15. #define UAC_CDEFAULT 0 // initial _cCnt for entry
  16. #define SID_SDEFAULT SID_SNOWREAD // initial _sidMru for new entry
  17. //***
  18. // NOTES
  19. // it's getting to the point that we should disallow stack-alloc'ed
  20. // guys and instead count on new() to 0-init us.
  21. CUACount::CUACount()
  22. {
  23. // Since this is created on the stack, we don't get the benefits of the
  24. // Heap allocator's zero initialization...
  25. ZeroMemory(_GetRawData(), _GetRawCount());
  26. _fInited = FALSE; // need to call Initialize
  27. #if XXX_VERSIONED
  28. _cbSize = -1;
  29. #endif
  30. #if XXX_DELETE
  31. _fInherited = FALSE;
  32. #endif
  33. _fDirty = FALSE;
  34. _fNoDecay = _fNoPurge = FALSE;
  35. return;
  36. }
  37. #ifdef DEBUG
  38. BOOL CUACount::DBIsInit()
  39. {
  40. #if XXX_VERSIONED
  41. ASSERT((_cbSize == SIZEOF(SUACount)) == BOOLIFY(_fInited));
  42. #endif
  43. return _fInited;
  44. }
  45. #endif
  46. HRESULT CUACount::Initialize(IUASession *puas)
  47. {
  48. _puas = puas;
  49. if (!_fInited) {
  50. _fInited = TRUE;
  51. #if XXX_VERSIONED
  52. // todo: _cbSize -1 means no entry, < SIZEOF means version upgrade
  53. _cbSize = SIZEOF(SUACount);
  54. #endif
  55. // hardcode the SZ_CUACount_ctor values here
  56. _cCnt = UAC_CDEFAULT; // all items start out visible
  57. _sidMruDisk = SID_SNOWREAD; // ... and non-aged
  58. }
  59. _sidMru = _sidMruDisk;
  60. if (ISSID_SSPECIAL(_sidMruDisk)) {
  61. _sidMru = _ExpandSpecial(_sidMruDisk);
  62. if (_sidMruDisk == SID_SNOWINIT) {
  63. _sidMruDisk = _sidMru;
  64. _fDirty = TRUE;
  65. }
  66. else if (_sidMruDisk == SID_SNOWREAD) {
  67. _sidMruDisk = _sidMru;
  68. ASSERT(!_fDirty);
  69. }
  70. }
  71. return S_OK;
  72. }
  73. HRESULT CUACount::LoadFrom(PFNNRW3 pfnIO, PNRWINFO pRwi)
  74. {
  75. HRESULT hr;
  76. hr = (*pfnIO->_pfnRead)(_GetRawData(), _GetRawCount(), pRwi);
  77. if (SUCCEEDED(hr))
  78. _fInited = TRUE;
  79. return hr;
  80. }
  81. HRESULT CUACount::SaveTo(BOOL fForce, PFNNRW3 pfnIO, PNRWINFO pRwi)
  82. {
  83. HRESULT hr;
  84. hr = S_FALSE;
  85. if (fForce || _fDirty) {
  86. if (!ISSID_SSPECIAL(_sidMruDisk))
  87. _sidMruDisk = _sidMru;
  88. #if XXX_DELETE
  89. if (_cCnt == 0 && !_fNoPurge && pfnIO->_pfnDelete)
  90. hr = (*pfnIO->_pfnDelete)(_GetRawData(), _GetRawCount(), pRwi);
  91. else
  92. #endif
  93. hr = (*pfnIO->_pfnWrite)(_GetRawData(), _GetRawCount(), pRwi);
  94. // ASSERT(SUCCEEDED(hr)); // this legitimately happens (low memory, access denied)
  95. _fDirty = FALSE;
  96. }
  97. return hr;
  98. }
  99. //*** GetCount -- get count info (w/ lazy decay)
  100. //
  101. int CUACount::GetCount()
  102. {
  103. ASSERT(DBIsInit());
  104. int cCnt = _DecayCount(FALSE);
  105. return cCnt;
  106. }
  107. void CUACount::IncCount()
  108. {
  109. AddCount(1);
  110. return;
  111. }
  112. void CUACount::AddCount(int i)
  113. {
  114. ASSERT(DBIsInit());
  115. _DecayCount(TRUE);
  116. _cCnt += i;
  117. if (_cCnt == 0 && i > 0) {
  118. // nt5:173048
  119. // handle wrap
  120. // should never happen, but what the heck
  121. // do *not* remove this assert, if we ever let people do DecCount
  122. // we'll need to rethink it...
  123. ASSERT(0); // 'impossible'
  124. _cCnt++;
  125. }
  126. // 981029 new incr algorithm per ie5 PM
  127. // UAC_MINCOUNT: initial inc starts at 6
  128. // _fNoDecay: but, UAssist2 doesn't do this
  129. if (_cCnt < UAC_MINCOUNT && !_fNoDecay)
  130. _cCnt = UAC_MINCOUNT;
  131. return;
  132. }
  133. //***
  134. // NOTES
  135. // should we update the timestamp? maybe add a fMru param?
  136. void CUACount::SetCount(int cCnt)
  137. {
  138. ASSERT(DBIsInit());
  139. _cCnt = cCnt;
  140. return;
  141. }
  142. void CUACount::SetFileTime(const FILETIME *pft)
  143. {
  144. ASSERT(DBIsInit());
  145. _ftExecuteTime = *pft;
  146. return;
  147. }
  148. #if XXX_DELETE
  149. #define BTOM(b, m) ((b) ? (m) : 0)
  150. DWORD CUACount::_SetFlags(DWORD dwMask, DWORD dwFlags)
  151. {
  152. // standard guys
  153. if (dwMask & UAXF_NOPURGE)
  154. _fNoPurge = BOOLIFY(dwFlags & UAXF_NOPURGE);
  155. #if 0
  156. if (dwMask & UAXF_BACKUP)
  157. _fBackup = BOOLIFY(dwFlags & UAXF_BACKUP);
  158. #endif
  159. if (dwMask & UAXF_NODECAY)
  160. _fNoDecay = BOOLIFY(dwFlags & UAXF_NODECAY);
  161. // my guys
  162. if (dwMask & UACF_INHERITED)
  163. _fInherited = BOOLIFY(dwFlags & UACF_INHERITED);
  164. return 0 // n.b. see continuation line(s)!!!
  165. #if XXX_DELETE
  166. | BTOM(_fInherited, UACF_INHERITED)
  167. #endif
  168. | BTOM(_fNoPurge, UAXF_NOPURGE)
  169. | BTOM(_fNoDecay, UAXF_NODECAY)
  170. ;
  171. }
  172. #endif
  173. //*** PCTOF -- p% of n (w/o floating point!)
  174. //
  175. #define PCTOF(n, p) (((n) * (p)) / 100)
  176. //*** _DecayCount -- decay (and propagate) count
  177. // ENTRY/EXIT
  178. // fWrite TRUE if want to update object and timestamp, o.w. FALSE
  179. // cNew (return) new count
  180. // DESCRIPTION
  181. // on a read, we do the decay but don't update the object. on the write
  182. // we decay and update.
  183. // NOTES
  184. // todo: if/when we make cCnt a vector, we can propagate stuff here.
  185. // this would allow us to usually inc a single small-granularity elt,
  186. // and propagate to the large-gran elts only when we really need them.
  187. // perf: we could make the table 'cumulative', then we wouldn't have
  188. // to do as much computation. not worth the trouble...
  189. int CUACount::_DecayCount(BOOL fWrite)
  190. {
  191. int cCnt;
  192. cCnt = _cCnt;
  193. if (cCnt > 0 || fWrite) {
  194. UINT sidNow;
  195. sidNow = _puas->GetSessionId();
  196. if (!_fNoDecay) {
  197. // from mso-9 spec
  198. // last used 'timTab' sessions ago => dec by >-of abs, pct
  199. // n.b. this table is non-cumulative
  200. static const int timTab[] = { 3, 6, 9, 12, 17, 23, 29, 31, -1, };
  201. static const int absTab[] = { 1, 1, 1, 2, 3, 4, 5, 0, 0, };
  202. static const int pctTab[] = { 0, 0, 0, 25, 25, 50, 75, 100, 100, };
  203. UINT sidMru;
  204. int dt;
  205. int i;
  206. sidMru = _sidMru;
  207. ASSERT(!ISSID_SSPECIAL(_sidMru));
  208. ASSERT(sidMru != SID_SDEFAULT);
  209. if (sidMru != SID_SDEFAULT) {
  210. dt = sidNow - sidMru;
  211. // iterate fwd not bkwd so bail early in common case
  212. for (i = 0; i < ARRAYSIZE(timTab); i++) {
  213. if ((UINT)dt < (UINT)timTab[i])
  214. break;
  215. cCnt -= MAX(absTab[i], PCTOF(cCnt, pctTab[i]));
  216. // don't go negative!
  217. // gotta check *each* time thru loop (o.w. PCT is bogus)
  218. cCnt = MAX(0, cCnt);
  219. }
  220. }
  221. }
  222. if (cCnt != _cCnt)
  223. TraceMsg(DM_UEMTRACE, "uac.dc: decay %d->%d", _cCnt, cCnt);
  224. if (fWrite) {
  225. _sidMru = sidNow;
  226. _cCnt = cCnt;
  227. }
  228. #if XXX_DELETE
  229. if (cCnt == 0 && !_fInherited) {
  230. // if we decay down to 0, mark so it will be deleted
  231. TraceMsg(DM_UEMTRACE, "uac.dc: decay %d->%d => mark dirty pRaw=0x%x", _cCnt, cCnt, _GetRawData());
  232. _cCnt = 0;
  233. _fDirty = TRUE;
  234. }
  235. #endif
  236. }
  237. return cCnt;
  238. }
  239. //***
  240. // NOTES
  241. // perf: currently all special guys return sidNow so no 'switch' necessary
  242. UINT CUACount::_ExpandSpecial(UINT sidMru)
  243. {
  244. UINT sidNow;
  245. if (EVAL(ISSID_SSPECIAL(sidMru))) {
  246. ASSERT(_puas);
  247. sidNow = _puas->GetSessionId(); // perf: multiple calls
  248. switch (sidMru) {
  249. case SID_SNOWALWAYS:
  250. return sidNow;
  251. //break;
  252. case SID_SNOWREAD:
  253. case SID_SNOWINIT:
  254. return sidNow;
  255. //break;
  256. #ifdef DEBUG
  257. default:
  258. ASSERT(0);
  259. break;
  260. #endif
  261. }
  262. }
  263. return sidMru;
  264. }
  265. // Return the encoded filetime. This is read from the registry or
  266. // generated from UpdateFileTime.
  267. FILETIME CUACount::GetFileTime()
  268. {
  269. return _ftExecuteTime;
  270. }
  271. // Updates the internal filetime information. This info
  272. // will be later persisted to the registry.
  273. void CUACount::UpdateFileTime()
  274. {
  275. SYSTEMTIME st;
  276. // Get the current system time.
  277. GetSystemTime(&st);
  278. // This is done for ARP. They use filetimes, not the system time
  279. // for the calculation of the last execute time.
  280. SystemTimeToFileTime(&st, &_ftExecuteTime);
  281. }
  282. // {
  283. //*** UATIME --
  284. //*** FTToUATime -- convert FILETIME to UATIME
  285. // DESCRIPTION
  286. // UATIME granularity is (approximately) 1 minute. the math works out
  287. // roughly as follows:
  288. // filetime granularity is 100 nanosec
  289. // 1 ft = 10^-7 sec
  290. // highword is 2^32 ft = 2^32 * 10^-7 sec
  291. // 1 sec = hiw / (2^32 * 10^-7)
  292. // 1 min = hiw * 60 / (2^32 * 10^-7)
  293. // = hiw * 60 / (1G * 10^-7)
  294. // ~= hiw * 60 / ~429
  295. // = hiw / 7.15
  296. // ~= hiw / 8 approx
  297. // the exact granularity is:
  298. // ...
  299. #define FTToUATime(pft) ((DWORD)(*(_int64 *)(pft) >> 29)) // 1 minute (approx)
  300. //*** GetUaTime -- convert systemtime (or 'now') to UATIME
  301. //
  302. UATIME GetUaTime(LPSYSTEMTIME pst)
  303. {
  304. FILETIME ft;
  305. UATIME uat;
  306. if (pst == NULL)
  307. {
  308. GetSystemTimeAsFileTime(&ft);
  309. }
  310. else
  311. {
  312. SystemTimeToFileTime(pst, &ft);
  313. }
  314. uat = FTToUATime(&ft); // minutes
  315. return uat;
  316. }
  317. // }