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.

985 lines
26 KiB

  1. #include "ctlspriv.h"
  2. #include <memory.h>
  3. #define MRU_ORDERDIRTY 0x1000
  4. #define DM_MRULAZY DM_TRACE
  5. #define MAX_CHAR 126
  6. #define BASE_CHAR TEXT('a')
  7. typedef struct tagMRUDATA
  8. {
  9. UINT fFlags;
  10. UINT uMax;
  11. LPVOID lpfnCompare;
  12. HKEY hKey;
  13. #ifdef DEBUG
  14. TCHAR szSubKey[32];
  15. #endif
  16. LPTSTR cOrder;
  17. } MRUDATA, *PMRUDATA;
  18. #define c_szMRU TEXT("MRUList")
  19. #define NTHSTRING(p, n) (*((LPTSTR *)((LPBYTE)p+sizeof(MRUDATA))+n))
  20. #define NTHDATA(p, n) (*((LPBYTE *)((LPBYTE)p+sizeof(MRUDATA))+n))
  21. #define NUM_OVERHEAD 3
  22. #ifdef VSTF
  23. /*----------------------------------------------------------
  24. Purpose: Validate the MRU structure
  25. */
  26. BOOL IsValidPMRUDATA(PMRUDATA pmru)
  27. {
  28. return (IS_VALID_WRITE_PTR(pmru, MRUDATA) &&
  29. (NULL == pmru->lpfnCompare || IS_VALID_CODE_PTR(pmru->lpfnCompare, void)));
  30. }
  31. #endif // VSTF
  32. //----------------------------------------------------------------------------
  33. // Internal memcmp - saves loading crt's, cdecl so we can use
  34. // as MRUCMPDATAPROC
  35. int CDECL _mymemcmp(const void *pBuf1, const void *pBuf2, size_t cb)
  36. {
  37. // Take advantage of the intrinsic version from crtfree.h
  38. return memcmp(pBuf1, pBuf2, cb);
  39. }
  40. // Use this macro to get the original size of the data.
  41. #define DATASIZE(p) (*((LPDWORD)p))
  42. // And this to get a pointer to the original data.
  43. #define DATAPDATA(p) (p+sizeof(DWORD))
  44. //----------------------------------------------------------------------------
  45. // For binary data we stick the size of the data at the begining and store the
  46. // whole thing in one go.
  47. BOOL MRUIsSameData(PMRUDATA pMRU, BYTE* pVal, const void *lpData, UINT cbData)
  48. {
  49. int cbUseSize;
  50. MRUCMPDATAPROC lpfnCompare;
  51. ASSERT(IS_VALID_STRUCT_PTR(pMRU, MRUDATA));
  52. lpfnCompare = pMRU->lpfnCompare;
  53. ASSERT(IS_VALID_CODE_PTR(lpfnCompare, MRUCMPDATAPROC));
  54. // if there's something other than a mem compare,
  55. // don't require the sizes to be equal in order for the
  56. // data to be equivalent.
  57. if (pMRU->lpfnCompare == _mymemcmp)
  58. {
  59. if (DATASIZE(pVal) != cbData)
  60. return FALSE;
  61. cbUseSize = cbData;
  62. }
  63. else
  64. cbUseSize = min(DATASIZE(pVal), cbData);
  65. return ((*lpfnCompare)(lpData, DATAPDATA(pVal), cbUseSize) == 0);
  66. }
  67. //----------------------------------------------------------------------------
  68. HANDLE WINAPI CreateMRUListLazy(LPMRUINFO lpmi, const void *lpData, UINT cbData, LPINT lpiSlot)
  69. {
  70. PTSTR pOrder, pNewOrder, pTemp;
  71. LPBYTE pVal;
  72. LONG cbVal;
  73. DWORD dwDisposition;
  74. DWORD dwType;
  75. PMRUDATA pMRU = NULL;
  76. HKEY hkeySubKey = NULL;
  77. TCHAR szTemp[2];
  78. UINT uMax = lpmi->uMax;
  79. HKEY hKey = lpmi->hKey;
  80. LPCTSTR lpszSubKey = lpmi->lpszSubKey;
  81. MRUCMPPROC lpfnCompare = lpmi->lpfnCompare;
  82. int cb;
  83. #ifdef DEBUG
  84. DWORD dwStart = GetTickCount();
  85. #endif
  86. if (!lpfnCompare)
  87. {
  88. lpfnCompare = (lpmi->fFlags & MRU_BINARY) ? (MRUCMPPROC)_mymemcmp :
  89. ((lpmi->fFlags & MRU_ANSI) ? (MRUCMPPROC)lstrcmpiA :
  90. (MRUCMPPROC)lstrcmpi);
  91. }
  92. // limit to 126 so that we don't use extended chars
  93. if (uMax > MAX_CHAR-BASE_CHAR)
  94. uMax = MAX_CHAR-BASE_CHAR;
  95. if (RegCreateKeyEx(hKey, lpszSubKey, 0L, (LPTSTR)c_szShell, REG_OPTION_NON_VOLATILE,
  96. KEY_READ | KEY_WRITE, NULL, &hkeySubKey, &dwDisposition) != ERROR_SUCCESS)
  97. {
  98. goto Error1;
  99. }
  100. pOrder = (PTSTR)Alloc((uMax + 1) * sizeof(TCHAR));
  101. if (!pOrder)
  102. {
  103. goto Error1;
  104. }
  105. cbVal = ((LONG)uMax + 1) * sizeof(TCHAR);
  106. if (RegQueryValueEx(hkeySubKey, (LPTSTR)c_szMRU, NULL, &dwType, (LPBYTE)pOrder, &cbVal) != ERROR_SUCCESS)
  107. {
  108. // if not already in the registry, then start fresh
  109. *pOrder = 0;
  110. }
  111. // Uppercase is not allowed
  112. CharLower(pOrder);
  113. // We allocate room for the MRUDATA structure, plus the order list,
  114. // and the list of strings.
  115. cb = (lpmi->fFlags & MRU_BINARY) ? sizeof(LPBYTE) : sizeof(LPTSTR);
  116. pMRU = (PMRUDATA)Alloc(sizeof(MRUDATA)+(uMax*cb));
  117. if (!pMRU)
  118. {
  119. goto Error2;
  120. }
  121. // Allocate space for the order list
  122. pMRU->cOrder = (LPTSTR)Alloc((uMax+1)*sizeof(TCHAR));
  123. if (!pMRU->cOrder)
  124. {
  125. Free(pMRU);
  126. pMRU = NULL;
  127. goto Error2;
  128. }
  129. pMRU->fFlags = lpmi->fFlags;
  130. pMRU->uMax = uMax;
  131. pMRU->lpfnCompare = lpfnCompare;
  132. pMRU->hKey = hkeySubKey;
  133. #ifdef DEBUG
  134. StringCchCopy(pMRU->szSubKey, ARRAYSIZE(pMRU->szSubKey), lpszSubKey);
  135. #endif
  136. // Traverse through the MRU list, adding strings to the end of the
  137. // list.
  138. szTemp[1] = TEXT('\0');
  139. for (pTemp = pOrder, pNewOrder = pMRU->cOrder; ; ++pTemp)
  140. {
  141. // Stop when we get to the end of the list.
  142. szTemp[0] = *pTemp;
  143. if (!szTemp[0])
  144. {
  145. break;
  146. }
  147. if (lpmi->fFlags & MRU_BINARY)
  148. {
  149. // Check if in range and if we have already used this letter.
  150. if ((UINT)(szTemp[0]-BASE_CHAR)>=uMax || NTHDATA(pMRU, szTemp[0]-BASE_CHAR))
  151. {
  152. continue;
  153. }
  154. // Get the value from the registry
  155. cbVal = 0;
  156. // first find the size
  157. if ((RegQueryValueEx(hkeySubKey, szTemp, NULL, &dwType, NULL, &cbVal)
  158. != ERROR_SUCCESS) || (dwType != REG_BINARY))
  159. {
  160. continue;
  161. }
  162. // Binary data has the size at the begining so we'll need a little extra room.
  163. pVal = (LPBYTE)Alloc(cbVal + sizeof(DWORD));
  164. if (!pVal)
  165. {
  166. // REARCHITECT perhaps sort of error is in order.
  167. continue;
  168. }
  169. // now really get it
  170. DATASIZE(pVal) = cbVal;
  171. if (RegQueryValueEx(hkeySubKey, szTemp, NULL, &dwType, pVal+sizeof(DWORD),
  172. (LPDWORD)pVal) != ERROR_SUCCESS)
  173. {
  174. continue;
  175. }
  176. // Note that blank elements ARE allowed in the list.
  177. NTHDATA(pMRU, szTemp[0]-BASE_CHAR) = pVal;
  178. *pNewOrder++ = szTemp[0];
  179. //
  180. // OPTIMIZATION
  181. // If lpData and lpiSlot are specified, we stop the enumeratation
  182. // when we find the item.
  183. //
  184. if (lpData && lpiSlot)
  185. {
  186. // Check if we have the specified one or not.
  187. if (MRUIsSameData(pMRU, pVal, lpData, cbData))
  188. {
  189. // Found it.
  190. *lpiSlot = (INT) (pNewOrder - pMRU->cOrder);
  191. TraceMsg(DM_MRULAZY, "CreateMRUListLazy found it. Copying %s", pTemp);
  192. pMRU->fFlags |= MRU_LAZY;
  193. //
  194. // Copy the rest of slot. Notice that we don't load
  195. // data for those slot.
  196. //
  197. for (pTemp++; *pTemp; pTemp++)
  198. {
  199. *pNewOrder++ = *pTemp;
  200. }
  201. break;
  202. }
  203. }
  204. }
  205. else
  206. {
  207. // Check if in range and if we have already used this letter.
  208. if ((UINT)(szTemp[0]-BASE_CHAR)>=uMax || NTHSTRING(pMRU, szTemp[0]-BASE_CHAR))
  209. {
  210. continue;
  211. }
  212. // Get the value from the registry
  213. cbVal = 0;
  214. // first find the size
  215. if ((RegQueryValueEx(hkeySubKey, szTemp, NULL, &dwType, NULL, &cbVal)
  216. != ERROR_SUCCESS) || (dwType != REG_SZ))
  217. {
  218. continue;
  219. }
  220. cbVal *= sizeof(TCHAR);
  221. pVal = (LPBYTE)Alloc(cbVal);
  222. if (!pVal)
  223. {
  224. // REARCHITECT perhaps sort of error is in order.
  225. continue;
  226. }
  227. // now really get it
  228. if (RegQueryValueEx(hkeySubKey, szTemp, NULL, &dwType, (LPBYTE)pVal, &cbVal) != ERROR_SUCCESS)
  229. {
  230. continue;
  231. }
  232. // Note that blank elements are not allowed in the list.
  233. if (*((LPTSTR)pVal))
  234. {
  235. NTHSTRING(pMRU, szTemp[0]-BASE_CHAR) = (LPTSTR)pVal;
  236. *pNewOrder++ = szTemp[0];
  237. }
  238. else
  239. {
  240. Free(pVal);
  241. pVal = NULL;
  242. }
  243. }
  244. }
  245. /* NULL terminate the order list so we can tell how many strings there
  246. * are.
  247. */
  248. *pNewOrder = TEXT('\0');
  249. if (lpData && lpiSlot)
  250. {
  251. TraceMsg(DM_MRULAZY, "CreateMRUListLazy. End of loop. %s", pMRU->cOrder);
  252. // If we failed to find, put -1 in it.
  253. if (!(pMRU->fFlags & MRU_LAZY))
  254. {
  255. *lpiSlot = -1;
  256. }
  257. }
  258. /* Actually, this is success rather than an error.
  259. */
  260. goto Error2;
  261. Error2:
  262. if (pOrder)
  263. {
  264. Free((HLOCAL)pOrder);
  265. pOrder = NULL;
  266. }
  267. Error1:
  268. if (!pMRU && hkeySubKey)
  269. RegCloseKey(hkeySubKey);
  270. return((HANDLE)pMRU);
  271. }
  272. HANDLE WINAPI CreateMRUList(LPMRUINFO lpmi)
  273. {
  274. return CreateMRUListLazy(lpmi, NULL, 0, NULL);
  275. }
  276. //
  277. // ANSI thunk
  278. //
  279. HANDLE WINAPI CreateMRUListLazyA(LPMRUINFOA lpmi, const void *lpData, UINT cbData, LPINT lpiSlot)
  280. {
  281. MRUINFOW MRUInfoW;
  282. HANDLE hMRU;
  283. MRUInfoW.cbSize = sizeof (MRUINFOW);
  284. MRUInfoW.uMax = lpmi->uMax;
  285. MRUInfoW.fFlags = lpmi->fFlags;
  286. MRUInfoW.hKey = lpmi->hKey;
  287. MRUInfoW.lpszSubKey = ProduceWFromA(CP_ACP, lpmi->lpszSubKey);
  288. MRUInfoW.lpfnCompare = (MRUCMPPROCW)lpmi->lpfnCompare;
  289. MRUInfoW.fFlags |= MRU_ANSI;
  290. hMRU = CreateMRUListLazy(&MRUInfoW, lpData, cbData, lpiSlot);
  291. FreeProducedString((LPWSTR)MRUInfoW.lpszSubKey);
  292. return hMRU;
  293. }
  294. HANDLE WINAPI CreateMRUListA(LPMRUINFOA lpmi)
  295. {
  296. return CreateMRUListLazyA(lpmi, NULL, 0, NULL);
  297. }
  298. //----------------------------------------------------------------------------
  299. STDAPI_(void) FreeMRUList(HANDLE hMRU)
  300. {
  301. int i;
  302. LPVOID *pTemp;
  303. PMRUDATA pMRU = (PMRUDATA)hMRU;
  304. ASSERT(IS_VALID_STRUCT_PTR(pMRU, MRUDATA));
  305. if (pMRU)
  306. {
  307. pTemp = (pMRU->fFlags & MRU_BINARY) ?
  308. &NTHDATA(pMRU, 0) : (LPBYTE *)&NTHSTRING(pMRU, 0);
  309. if (pMRU->fFlags & MRU_ORDERDIRTY)
  310. {
  311. RegSetValueEx(pMRU->hKey, c_szMRU, 0L, REG_SZ, (CONST BYTE *)pMRU->cOrder,
  312. sizeof(TCHAR) * (lstrlen(pMRU->cOrder) + 1));
  313. }
  314. for (i=pMRU->uMax-1; i>=0; --i, ++pTemp)
  315. {
  316. if (*pTemp)
  317. {
  318. if (pMRU->fFlags & MRU_BINARY)
  319. {
  320. Free((LPBYTE)*pTemp);
  321. *pTemp = NULL;
  322. }
  323. else
  324. Str_SetPtr((LPTSTR *)pTemp, NULL);
  325. }
  326. }
  327. RegCloseKey(pMRU->hKey);
  328. Free(pMRU->cOrder);
  329. Free((HLOCAL)pMRU);
  330. }
  331. }
  332. /* Add a string to an MRU list.
  333. */
  334. STDAPI_(int) AddMRUString(HANDLE hMRU, LPCTSTR szString)
  335. {
  336. /* The extra +1 is so that the list is NULL terminated.
  337. */
  338. TCHAR cFirst;
  339. int iSlot = -1;
  340. LPTSTR lpTemp;
  341. LPTSTR * pTemp;
  342. int i;
  343. UINT uMax;
  344. MRUCMPPROC lpfnCompare;
  345. BOOL fShouldWrite;
  346. PMRUDATA pMRU = (PMRUDATA)hMRU;
  347. #ifdef DEBUG
  348. DWORD dwStart = GetTickCount();
  349. #endif
  350. ASSERT(IS_VALID_STRUCT_PTR(pMRU, MRUDATA));
  351. if (hMRU == NULL)
  352. return(-1); // Error
  353. fShouldWrite = !(pMRU->fFlags & MRU_CACHEWRITE);
  354. uMax = pMRU->uMax;
  355. lpfnCompare = (MRUCMPPROC)pMRU->lpfnCompare;
  356. /* Check if the string already exists in the list.
  357. */
  358. for (i=0, pTemp=&NTHSTRING(pMRU, 0); (UINT)i<uMax; ++i, ++pTemp)
  359. {
  360. if (*pTemp)
  361. {
  362. int iResult;
  363. if (pMRU->fFlags & MRU_ANSI)
  364. {
  365. LPSTR lpStringA, lpTempA;
  366. lpStringA = ProduceAFromW (CP_ACP, szString);
  367. lpTempA = ProduceAFromW (CP_ACP, (LPWSTR)*pTemp);
  368. iResult = (*lpfnCompare)((const void *)lpStringA, (const void *)lpTempA);
  369. FreeProducedString (lpStringA);
  370. FreeProducedString (lpTempA);
  371. }
  372. else
  373. {
  374. iResult = (*lpfnCompare)((const void *)szString, (const void *)*pTemp);
  375. }
  376. if (!iResult)
  377. {
  378. // found it, so don't do the write out
  379. cFirst = i + BASE_CHAR;
  380. iSlot = i;
  381. goto FoundEntry;
  382. }
  383. }
  384. }
  385. /* Attempt to find an unused entry. Count up the used entries at the
  386. * same time.
  387. */
  388. for (i=0, pTemp=&NTHSTRING(pMRU, 0); ; ++i, ++pTemp)
  389. {
  390. if ((UINT)i >= uMax) // If we got to the end of the list.
  391. {
  392. // use the entry at the end of the cOrder list
  393. cFirst = pMRU->cOrder[uMax-1];
  394. pTemp = &NTHSTRING(pMRU, cFirst-BASE_CHAR);
  395. break;
  396. }
  397. // Is the entry not used?
  398. if (!*pTemp)
  399. {
  400. // yes
  401. cFirst = i+BASE_CHAR;
  402. break;
  403. }
  404. }
  405. if (Str_SetPtr(pTemp, szString))
  406. {
  407. TCHAR szTemp[2];
  408. iSlot = (int)(cFirst-BASE_CHAR);
  409. szTemp[0] = cFirst;
  410. szTemp[1] = TEXT('\0');
  411. RegSetValueEx(pMRU->hKey, szTemp, 0L, REG_SZ, (CONST BYTE *)szString,
  412. sizeof(TCHAR) * (lstrlen(szString) + 1));
  413. fShouldWrite = TRUE;
  414. }
  415. else
  416. {
  417. /* Since iSlot == -1, we will remove the reference to cFirst
  418. * below.
  419. */
  420. }
  421. FoundEntry:
  422. /* Remove any previous reference to cFirst.
  423. */
  424. lpTemp = StrChr(pMRU->cOrder, cFirst);
  425. if (lpTemp)
  426. {
  427. StringCchCopy(lpTemp, lstrlen(lpTemp), lpTemp+1);
  428. }
  429. if (iSlot != -1)
  430. {
  431. // shift everything over and put cFirst at the front
  432. hmemcpy(pMRU->cOrder+1, pMRU->cOrder, pMRU->uMax*sizeof(TCHAR));
  433. pMRU->cOrder[0] = cFirst;
  434. }
  435. if (fShouldWrite)
  436. {
  437. RegSetValueEx(pMRU->hKey, c_szMRU, 0L, REG_SZ, (CONST BYTE *)pMRU->cOrder,
  438. sizeof(TCHAR) * (lstrlen(pMRU->cOrder) + 1));
  439. pMRU->fFlags &= ~MRU_ORDERDIRTY;
  440. } else
  441. pMRU->fFlags |= MRU_ORDERDIRTY;
  442. #ifdef DEBUG
  443. // DebugMsg(DM_TRACE, TEXT("AddMRU: %d msec"), LOWORD(GetTickCount()-dwStart));
  444. #endif
  445. return(iSlot);
  446. }
  447. //
  448. // ANSI thunk
  449. //
  450. STDAPI_(int) AddMRUStringA(HANDLE hMRU, LPCSTR szString)
  451. {
  452. LPWSTR lpStringW;
  453. INT iResult;
  454. lpStringW = ProduceWFromA(CP_ACP, szString);
  455. iResult = AddMRUString(hMRU, lpStringW);
  456. FreeProducedString (lpStringW);
  457. return iResult;
  458. }
  459. /* Remove a string from an MRU list.
  460. */
  461. STDAPI_(int) DelMRUString(HANDLE hMRU, int nItem)
  462. {
  463. BOOL bRet = FALSE;
  464. LPTSTR lpTemp;
  465. PMRUDATA pMRU = (PMRUDATA)hMRU;
  466. ASSERT(IS_VALID_STRUCT_PTR(pMRU, MRUDATA));
  467. if (pMRU)
  468. {
  469. //
  470. // Make sure the index value is within the length of
  471. // the string so we don't pick up some random value.
  472. //
  473. if (!InRange(nItem, 0, pMRU->uMax) || nItem >= lstrlen(pMRU->cOrder))
  474. return FALSE;
  475. // Be easy -- just remove the entry from the cOrder list
  476. lpTemp = &pMRU->cOrder[nItem];
  477. if (lpTemp)
  478. {
  479. int iSlot = *lpTemp - BASE_CHAR;
  480. if (iSlot >= 0 && iSlot < MAX_CHAR - BASE_CHAR)
  481. {
  482. Str_SetPtr(&NTHSTRING(pMRU, iSlot), NULL);
  483. }
  484. StringCchCopy(lpTemp, lstrlen(lpTemp), lpTemp+1);
  485. if (!(pMRU->fFlags & MRU_CACHEWRITE))
  486. {
  487. RegSetValueEx(pMRU->hKey, c_szMRU, 0L, REG_SZ, (CONST BYTE *)pMRU->cOrder,
  488. sizeof(TCHAR) * (lstrlen(pMRU->cOrder) + 1));
  489. pMRU->fFlags &= ~MRU_ORDERDIRTY;
  490. }
  491. else
  492. {
  493. pMRU->fFlags |= MRU_ORDERDIRTY;
  494. }
  495. bRet = TRUE;
  496. }
  497. }
  498. return bRet;
  499. }
  500. //----------------------------------------------------------------------------
  501. // Add data to an MRU list.
  502. STDAPI_(int) AddMRUData(HANDLE hMRU, const void *lpData, UINT cbData)
  503. {
  504. TCHAR cFirst;
  505. int iSlot = -1;
  506. LPTSTR lpTemp;
  507. LPBYTE *ppData;
  508. int i;
  509. UINT uMax;
  510. MRUCMPDATAPROC lpfnCompare;
  511. PMRUDATA pMRU = (PMRUDATA)hMRU;
  512. BOOL fShouldWrite;
  513. #ifdef DEBUG
  514. DWORD dwStart = GetTickCount();
  515. #endif
  516. ASSERT(IS_VALID_STRUCT_PTR(pMRU, MRUDATA));
  517. if (hMRU == NULL)
  518. return(-1); // Error
  519. fShouldWrite = !(pMRU->fFlags & MRU_CACHEWRITE);
  520. uMax = pMRU->uMax;
  521. lpfnCompare = (MRUCMPDATAPROC)pMRU->lpfnCompare;
  522. // Check if the data already exists in the list.
  523. for (i=0, ppData=&NTHDATA(pMRU, 0); (UINT)i<uMax; ++i, ++ppData)
  524. {
  525. if (*ppData && MRUIsSameData(pMRU, *ppData, lpData, cbData))
  526. {
  527. // found it, so don't do the write out
  528. cFirst = i + BASE_CHAR;
  529. iSlot = i;
  530. goto FoundEntry;
  531. }
  532. }
  533. //
  534. // When created "lazy", we are not supposed to add a new item.
  535. //
  536. if (pMRU->fFlags & MRU_LAZY)
  537. {
  538. ASSERT(0);
  539. return -1;
  540. }
  541. // Attempt to find an unused entry. Count up the used entries at the
  542. // same time.
  543. for (i=0, ppData=&NTHDATA(pMRU, 0); ; ++i, ++ppData)
  544. {
  545. if ((UINT)i >= uMax)
  546. // If we got to the end of the list.
  547. {
  548. // use the entry at the end of the cOrder list
  549. cFirst = pMRU->cOrder[uMax-1];
  550. ppData = &NTHDATA(pMRU, cFirst-BASE_CHAR);
  551. break;
  552. }
  553. if (!*ppData)
  554. // If the entry is not used.
  555. {
  556. cFirst = i+BASE_CHAR;
  557. break;
  558. }
  559. }
  560. *ppData = ReAlloc(*ppData, cbData+sizeof(DWORD));
  561. if (*ppData)
  562. {
  563. TCHAR szTemp[2];
  564. *((LPDWORD)(*ppData)) = cbData;
  565. hmemcpy(DATAPDATA(*ppData), lpData, cbData);
  566. iSlot = (int)(cFirst-BASE_CHAR);
  567. szTemp[0] = cFirst;
  568. szTemp[1] = TEXT('\0');
  569. RegSetValueEx(pMRU->hKey, szTemp, 0L, REG_BINARY, (LPVOID)lpData, cbData);
  570. fShouldWrite = TRUE;
  571. }
  572. else
  573. {
  574. // Since iSlot == -1, we will remove the reference to cFirst
  575. // below.
  576. }
  577. FoundEntry:
  578. // Remove any previous reference to cFirst.
  579. lpTemp = StrChr(pMRU->cOrder, cFirst);
  580. if (lpTemp)
  581. {
  582. StringCchCopy(lpTemp, lstrlen(lpTemp), lpTemp+1);
  583. }
  584. if (iSlot != -1)
  585. {
  586. // shift everything over and put cFirst at the front
  587. hmemcpy(pMRU->cOrder+1, pMRU->cOrder, pMRU->uMax*sizeof(TCHAR));
  588. pMRU->cOrder[0] = cFirst;
  589. }
  590. if (fShouldWrite)
  591. {
  592. RegSetValueEx(pMRU->hKey, c_szMRU, 0L, REG_SZ, (CONST BYTE *)pMRU->cOrder,
  593. sizeof(TCHAR) * (lstrlen(pMRU->cOrder) + 1));
  594. pMRU->fFlags &= ~MRU_ORDERDIRTY;
  595. } else
  596. pMRU->fFlags |= MRU_ORDERDIRTY;
  597. #ifdef DEBUG
  598. // DebugMsg(DM_TRACE, TEXT("AddMRU: %d msec"), LOWORD(GetTickCount()-dwStart));
  599. #endif
  600. return(iSlot);
  601. }
  602. //----------------------------------------------------------------------------
  603. // Find data in an MRU list.
  604. // Returns the slot number.
  605. STDAPI_(int) FindMRUData(HANDLE hMRU, const void *lpData, UINT cbData, LPINT lpiSlot)
  606. {
  607. TCHAR cFirst;
  608. int iSlot = -1;
  609. LPTSTR lpTemp;
  610. LPBYTE *ppData;
  611. int i;
  612. UINT uMax;
  613. PMRUDATA pMRU = (PMRUDATA)hMRU;
  614. #ifdef DEBUG
  615. DWORD dwStart = GetTickCount();
  616. #endif
  617. ASSERT(IS_VALID_STRUCT_PTR(pMRU, MRUDATA));
  618. if (hMRU == NULL)
  619. return(-1); // Error state.
  620. // Can't call this API when it's created lazily.
  621. if (pMRU->fFlags & MRU_LAZY)
  622. {
  623. ASSERT(0);
  624. return -1;
  625. }
  626. uMax = pMRU->uMax;
  627. /* Find the item in the list.
  628. */
  629. for (i=0, ppData=&NTHDATA(pMRU, 0); (UINT)i<uMax; ++i, ++ppData)
  630. {
  631. if (!*ppData)
  632. continue;
  633. if (MRUIsSameData(pMRU, *ppData, lpData, cbData))
  634. {
  635. // So i now has the slot number in it.
  636. if (lpiSlot != NULL)
  637. *lpiSlot = i;
  638. // Now convert the slot number into an index number
  639. cFirst = i + BASE_CHAR;
  640. lpTemp = StrChr(pMRU->cOrder, cFirst);
  641. ASSERT(lpTemp);
  642. return((lpTemp == NULL)? -1 : (int)(lpTemp - (LPTSTR)pMRU->cOrder));
  643. }
  644. }
  645. return -1;
  646. }
  647. /* Find a string in an MRU list.
  648. */
  649. STDAPI_(int) FindMRUString(HANDLE hMRU, LPCTSTR szString, LPINT lpiSlot)
  650. {
  651. /* The extra +1 is so that the list is NULL terminated.
  652. */
  653. TCHAR cFirst;
  654. int iSlot = -1;
  655. LPTSTR lpTemp;
  656. LPTSTR *pTemp;
  657. int i;
  658. UINT uMax;
  659. MRUCMPPROC lpfnCompare;
  660. PMRUDATA pMRU = (PMRUDATA)hMRU;
  661. #ifdef DEBUG
  662. DWORD dwStart = GetTickCount();
  663. #endif
  664. ASSERT(IS_VALID_STRUCT_PTR(pMRU, MRUDATA));
  665. if (hMRU == NULL)
  666. return(-1); // Error state.
  667. uMax = pMRU->uMax;
  668. lpfnCompare = (MRUCMPPROC)pMRU->lpfnCompare;
  669. /* Find the item in the list.
  670. */
  671. for (i=0, pTemp=&NTHSTRING(pMRU, 0); (UINT)i<uMax; ++i, ++pTemp)
  672. {
  673. if (*pTemp)
  674. {
  675. int iResult;
  676. if (pMRU->fFlags & MRU_ANSI)
  677. {
  678. LPSTR lpStringA, lpTempA;
  679. lpStringA = ProduceAFromW (CP_ACP, szString);
  680. lpTempA = ProduceAFromW (CP_ACP, (LPWSTR)*pTemp);
  681. iResult = (*lpfnCompare)((const void *)lpStringA, (const void *)lpTempA);
  682. FreeProducedString (lpStringA);
  683. FreeProducedString (lpTempA);
  684. }
  685. else
  686. {
  687. iResult = (*lpfnCompare)((CONST VOID *)szString, (CONST VOID *)*pTemp);
  688. }
  689. if (!iResult)
  690. {
  691. // So i now has the slot number in it.
  692. if (lpiSlot != NULL)
  693. *lpiSlot = i;
  694. // Now convert the slot number into an index number
  695. cFirst = i + BASE_CHAR;
  696. lpTemp = StrChr(pMRU->cOrder, cFirst);
  697. return((lpTemp == NULL)? -1 : (int)(lpTemp - (LPTSTR)pMRU->cOrder));
  698. }
  699. }
  700. }
  701. return(-1);
  702. }
  703. //
  704. // ANSI thunk
  705. //
  706. int WINAPI FindMRUStringA(HANDLE hMRU, LPCSTR szString, LPINT lpiSlot)
  707. {
  708. LPWSTR lpStringW;
  709. INT iResult;
  710. lpStringW = ProduceWFromA(CP_ACP, szString);
  711. iResult = FindMRUString(hMRU, lpStringW, lpiSlot);
  712. FreeProducedString (lpStringW);
  713. return iResult;
  714. }
  715. /* If lpszString is NULL, then this returns the number of MRU items or less than
  716. * 0 on error.
  717. * if nItem < 0, we'll return the number of items currently in the MRU.
  718. * Otherwise, fill in as much of the buffer as possible (uLen includes the
  719. * terminating NULL) and return the actual length of the string (including the
  720. * terminating NULL) or less than 0 on error.
  721. */
  722. STDAPI_(int) EnumMRUList(HANDLE hMRU, int nItem, LPVOID lpData, UINT uLen)
  723. {
  724. PMRUDATA pMRU = (PMRUDATA)hMRU;
  725. int nItems = -1;
  726. LPTSTR pTemp;
  727. LPBYTE pData;
  728. ASSERT(IS_VALID_STRUCT_PTR(pMRU, MRUDATA));
  729. if (pMRU)
  730. {
  731. nItems = lstrlen(pMRU->cOrder);
  732. if (nItem < 0 || !lpData)
  733. return nItems;
  734. if (nItem < nItems)
  735. {
  736. if (pMRU->fFlags & MRU_BINARY)
  737. {
  738. pData = NTHDATA(pMRU, pMRU->cOrder[nItem]-BASE_CHAR);
  739. if (!pData)
  740. return -1;
  741. uLen = min((UINT)DATASIZE(pData), uLen);
  742. hmemcpy(lpData, DATAPDATA(pData), uLen);
  743. nItems = uLen;
  744. }
  745. else
  746. {
  747. pTemp = NTHSTRING(pMRU, pMRU->cOrder[nItem]-BASE_CHAR);
  748. if (pTemp)
  749. {
  750. StringCchCopy((LPTSTR)lpData, uLen, pTemp);
  751. nItems = lstrlen(pTemp);
  752. }
  753. else
  754. {
  755. nItems = -1;
  756. }
  757. }
  758. }
  759. else
  760. {
  761. // revert to error condition
  762. nItems = -1;
  763. }
  764. }
  765. return nItems;
  766. }
  767. STDAPI_(int) EnumMRUListA(HANDLE hMRU, int nItem, LPVOID lpData, UINT uLen)
  768. {
  769. int iResult = -1;
  770. PMRUDATA pMRU = (PMRUDATA)hMRU;
  771. ASSERT(IS_VALID_STRUCT_PTR(pMRU, MRUDATA));
  772. if (pMRU)
  773. {
  774. LPVOID lpDataW;
  775. BOOL bAllocatedMemory = FALSE;
  776. //
  777. // we need a temp buffer if the data is a string.
  778. // but if it is binary, then we trust the callers buffer.
  779. //
  780. if (!(pMRU->fFlags & MRU_BINARY) && uLen && lpData)
  781. {
  782. lpDataW = LocalAlloc(LPTR, uLen * sizeof(TCHAR));
  783. if (!lpDataW)
  784. return -1;
  785. bAllocatedMemory = TRUE;
  786. }
  787. else
  788. lpDataW = lpData;
  789. // call the real thing
  790. iResult = EnumMRUList(hMRU, nItem, lpDataW, uLen);
  791. //
  792. // if the buffer was a string that we allocated
  793. // then we need to thunk the string into the callers buffer
  794. //
  795. if (!(pMRU->fFlags & MRU_BINARY) && lpData && uLen && (iResult != -1))
  796. {
  797. WideCharToMultiByte(CP_ACP, 0, (LPWSTR)lpDataW, -1,
  798. (LPSTR)lpData, uLen, NULL, NULL);
  799. }
  800. if (bAllocatedMemory)
  801. LocalFree(lpDataW);
  802. }
  803. return iResult;
  804. }