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.

1039 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. lstrcpyn(pMRU->szSubKey, lpszSubKey, ARRAYSIZE(pMRU->szSubKey));
  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. #ifdef UNICODE
  277. //
  278. // ANSI thunk
  279. //
  280. HANDLE WINAPI CreateMRUListLazyA(LPMRUINFOA lpmi, const void *lpData, UINT cbData, LPINT lpiSlot)
  281. {
  282. MRUINFOW MRUInfoW;
  283. HANDLE hMRU;
  284. MRUInfoW.cbSize = sizeof (MRUINFOW);
  285. MRUInfoW.uMax = lpmi->uMax;
  286. MRUInfoW.fFlags = lpmi->fFlags;
  287. MRUInfoW.hKey = lpmi->hKey;
  288. MRUInfoW.lpszSubKey = ProduceWFromA(CP_ACP, lpmi->lpszSubKey);
  289. MRUInfoW.lpfnCompare = (MRUCMPPROCW)lpmi->lpfnCompare;
  290. MRUInfoW.fFlags |= MRU_ANSI;
  291. hMRU = CreateMRUListLazy(&MRUInfoW, lpData, cbData, lpiSlot);
  292. FreeProducedString((LPWSTR)MRUInfoW.lpszSubKey);
  293. return hMRU;
  294. }
  295. HANDLE WINAPI CreateMRUListA(LPMRUINFOA lpmi)
  296. {
  297. return CreateMRUListLazyA(lpmi, NULL, 0, NULL);
  298. }
  299. #else
  300. //
  301. // Unicode stub when this code is built ANSI
  302. //
  303. HANDLE WINAPI CreateMRUListW(LPMRUINFOW lpmi)
  304. {
  305. SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
  306. return NULL;
  307. }
  308. HANDLE WINAPI CreateMRUListLazyW(LPMRUINFOW lpmi, const void *lpData, UINT cbData, LPINT lpiSlot)
  309. {
  310. SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
  311. return NULL;
  312. }
  313. #endif
  314. //----------------------------------------------------------------------------
  315. STDAPI_(void) FreeMRUList(HANDLE hMRU)
  316. {
  317. int i;
  318. LPVOID *pTemp;
  319. PMRUDATA pMRU = (PMRUDATA)hMRU;
  320. ASSERT(IS_VALID_STRUCT_PTR(pMRU, MRUDATA));
  321. if (pMRU)
  322. {
  323. pTemp = (pMRU->fFlags & MRU_BINARY) ?
  324. &NTHDATA(pMRU, 0) : (LPBYTE *)&NTHSTRING(pMRU, 0);
  325. if (pMRU->fFlags & MRU_ORDERDIRTY)
  326. {
  327. RegSetValueEx(pMRU->hKey, c_szMRU, 0L, REG_SZ, (CONST BYTE *)pMRU->cOrder,
  328. sizeof(TCHAR) * (lstrlen(pMRU->cOrder) + 1));
  329. }
  330. for (i=pMRU->uMax-1; i>=0; --i, ++pTemp)
  331. {
  332. if (*pTemp)
  333. {
  334. if (pMRU->fFlags & MRU_BINARY)
  335. {
  336. Free((LPBYTE)*pTemp);
  337. *pTemp = NULL;
  338. }
  339. else
  340. Str_SetPtr((LPTSTR *)pTemp, NULL);
  341. }
  342. }
  343. RegCloseKey(pMRU->hKey);
  344. Free(pMRU->cOrder);
  345. Free((HLOCAL)pMRU);
  346. }
  347. }
  348. /* Add a string to an MRU list.
  349. */
  350. STDAPI_(int) AddMRUString(HANDLE hMRU, LPCTSTR szString)
  351. {
  352. /* The extra +1 is so that the list is NULL terminated.
  353. */
  354. TCHAR cFirst;
  355. int iSlot = -1;
  356. LPTSTR lpTemp;
  357. LPTSTR * pTemp;
  358. int i;
  359. UINT uMax;
  360. MRUCMPPROC lpfnCompare;
  361. BOOL fShouldWrite;
  362. PMRUDATA pMRU = (PMRUDATA)hMRU;
  363. #ifdef DEBUG
  364. DWORD dwStart = GetTickCount();
  365. #endif
  366. ASSERT(IS_VALID_STRUCT_PTR(pMRU, MRUDATA));
  367. if (hMRU == NULL)
  368. return(-1); // Error
  369. fShouldWrite = !(pMRU->fFlags & MRU_CACHEWRITE);
  370. uMax = pMRU->uMax;
  371. lpfnCompare = (MRUCMPPROC)pMRU->lpfnCompare;
  372. /* Check if the string already exists in the list.
  373. */
  374. for (i=0, pTemp=&NTHSTRING(pMRU, 0); (UINT)i<uMax; ++i, ++pTemp)
  375. {
  376. if (*pTemp)
  377. {
  378. int iResult;
  379. #ifdef UNICODE
  380. if (pMRU->fFlags & MRU_ANSI)
  381. {
  382. LPSTR lpStringA, lpTempA;
  383. lpStringA = ProduceAFromW (CP_ACP, szString);
  384. lpTempA = ProduceAFromW (CP_ACP, (LPWSTR)*pTemp);
  385. iResult = (*lpfnCompare)((const void *)lpStringA, (const void *)lpTempA);
  386. FreeProducedString (lpStringA);
  387. FreeProducedString (lpTempA);
  388. }
  389. else
  390. #endif
  391. {
  392. iResult = (*lpfnCompare)((const void *)szString, (const void *)*pTemp);
  393. }
  394. if (!iResult)
  395. {
  396. // found it, so don't do the write out
  397. cFirst = i + BASE_CHAR;
  398. iSlot = i;
  399. goto FoundEntry;
  400. }
  401. }
  402. }
  403. /* Attempt to find an unused entry. Count up the used entries at the
  404. * same time.
  405. */
  406. for (i=0, pTemp=&NTHSTRING(pMRU, 0); ; ++i, ++pTemp)
  407. {
  408. if ((UINT)i >= uMax) // If we got to the end of the list.
  409. {
  410. // use the entry at the end of the cOrder list
  411. cFirst = pMRU->cOrder[uMax-1];
  412. pTemp = &NTHSTRING(pMRU, cFirst-BASE_CHAR);
  413. break;
  414. }
  415. // Is the entry not used?
  416. if (!*pTemp)
  417. {
  418. // yes
  419. cFirst = i+BASE_CHAR;
  420. break;
  421. }
  422. }
  423. if (Str_SetPtr(pTemp, szString))
  424. {
  425. TCHAR szTemp[2];
  426. iSlot = (int)(cFirst-BASE_CHAR);
  427. szTemp[0] = cFirst;
  428. szTemp[1] = TEXT('\0');
  429. RegSetValueEx(pMRU->hKey, szTemp, 0L, REG_SZ, (CONST BYTE *)szString,
  430. sizeof(TCHAR) * (lstrlen(szString) + 1));
  431. fShouldWrite = TRUE;
  432. }
  433. else
  434. {
  435. /* Since iSlot == -1, we will remove the reference to cFirst
  436. * below.
  437. */
  438. }
  439. FoundEntry:
  440. /* Remove any previous reference to cFirst.
  441. */
  442. lpTemp = StrChr(pMRU->cOrder, cFirst);
  443. if (lpTemp)
  444. {
  445. lstrcpy(lpTemp, lpTemp+1);
  446. }
  447. if (iSlot != -1)
  448. {
  449. // shift everything over and put cFirst at the front
  450. hmemcpy(pMRU->cOrder+1, pMRU->cOrder, pMRU->uMax*sizeof(TCHAR));
  451. pMRU->cOrder[0] = cFirst;
  452. }
  453. if (fShouldWrite)
  454. {
  455. RegSetValueEx(pMRU->hKey, c_szMRU, 0L, REG_SZ, (CONST BYTE *)pMRU->cOrder,
  456. sizeof(TCHAR) * (lstrlen(pMRU->cOrder) + 1));
  457. pMRU->fFlags &= ~MRU_ORDERDIRTY;
  458. } else
  459. pMRU->fFlags |= MRU_ORDERDIRTY;
  460. #ifdef DEBUG
  461. // DebugMsg(DM_TRACE, TEXT("AddMRU: %d msec"), LOWORD(GetTickCount()-dwStart));
  462. #endif
  463. return(iSlot);
  464. }
  465. #ifdef UNICODE
  466. //
  467. // ANSI thunk
  468. //
  469. STDAPI_(int) AddMRUStringA(HANDLE hMRU, LPCSTR szString)
  470. {
  471. LPWSTR lpStringW;
  472. INT iResult;
  473. lpStringW = ProduceWFromA(CP_ACP, szString);
  474. iResult = AddMRUString(hMRU, lpStringW);
  475. FreeProducedString (lpStringW);
  476. return iResult;
  477. }
  478. #else
  479. //
  480. // Unicode stub when this code is build ANSI
  481. //
  482. STDAPI_(int) AddMRUStringW(HANDLE hMRU, LPCWSTR szString)
  483. {
  484. SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
  485. return -1;
  486. }
  487. #endif
  488. /* Remove a string from an MRU list.
  489. */
  490. STDAPI_(int) DelMRUString(HANDLE hMRU, int nItem)
  491. {
  492. BOOL bRet = FALSE;
  493. LPTSTR lpTemp;
  494. PMRUDATA pMRU = (PMRUDATA)hMRU;
  495. ASSERT(IS_VALID_STRUCT_PTR(pMRU, MRUDATA));
  496. if (pMRU)
  497. {
  498. //
  499. // Make sure the index value is within the length of
  500. // the string so we don't pick up some random value.
  501. //
  502. if (!InRange(nItem, 0, pMRU->uMax) || nItem >= lstrlen(pMRU->cOrder))
  503. return FALSE;
  504. // Be easy -- just remove the entry from the cOrder list
  505. lpTemp = &pMRU->cOrder[nItem];
  506. if (lpTemp)
  507. {
  508. int iSlot = *lpTemp - BASE_CHAR;
  509. if (iSlot >= 0 && iSlot < MAX_CHAR - BASE_CHAR)
  510. Str_SetPtr(&NTHSTRING(pMRU, iSlot), NULL);
  511. lstrcpy(lpTemp, lpTemp+1);
  512. if (!(pMRU->fFlags & MRU_CACHEWRITE))
  513. {
  514. RegSetValueEx(pMRU->hKey, c_szMRU, 0L, REG_SZ, (CONST BYTE *)pMRU->cOrder,
  515. sizeof(TCHAR) * (lstrlen(pMRU->cOrder) + 1));
  516. pMRU->fFlags &= ~MRU_ORDERDIRTY;
  517. }
  518. else
  519. {
  520. pMRU->fFlags |= MRU_ORDERDIRTY;
  521. }
  522. bRet = TRUE;
  523. }
  524. }
  525. return bRet;
  526. }
  527. //----------------------------------------------------------------------------
  528. // Add data to an MRU list.
  529. STDAPI_(int) AddMRUData(HANDLE hMRU, const void *lpData, UINT cbData)
  530. {
  531. TCHAR cFirst;
  532. int iSlot = -1;
  533. LPTSTR lpTemp;
  534. LPBYTE *ppData;
  535. int i;
  536. UINT uMax;
  537. MRUCMPDATAPROC lpfnCompare;
  538. PMRUDATA pMRU = (PMRUDATA)hMRU;
  539. BOOL fShouldWrite;
  540. #ifdef DEBUG
  541. DWORD dwStart = GetTickCount();
  542. #endif
  543. ASSERT(IS_VALID_STRUCT_PTR(pMRU, MRUDATA));
  544. if (hMRU == NULL)
  545. return(-1); // Error
  546. fShouldWrite = !(pMRU->fFlags & MRU_CACHEWRITE);
  547. uMax = pMRU->uMax;
  548. lpfnCompare = (MRUCMPDATAPROC)pMRU->lpfnCompare;
  549. // Check if the data already exists in the list.
  550. for (i=0, ppData=&NTHDATA(pMRU, 0); (UINT)i<uMax; ++i, ++ppData)
  551. {
  552. if (*ppData && MRUIsSameData(pMRU, *ppData, lpData, cbData))
  553. {
  554. // found it, so don't do the write out
  555. cFirst = i + BASE_CHAR;
  556. iSlot = i;
  557. goto FoundEntry;
  558. }
  559. }
  560. //
  561. // When created "lazy", we are not supposed to add a new item.
  562. //
  563. if (pMRU->fFlags & MRU_LAZY)
  564. {
  565. ASSERT(0);
  566. return -1;
  567. }
  568. // Attempt to find an unused entry. Count up the used entries at the
  569. // same time.
  570. for (i=0, ppData=&NTHDATA(pMRU, 0); ; ++i, ++ppData)
  571. {
  572. if ((UINT)i >= uMax)
  573. // If we got to the end of the list.
  574. {
  575. // use the entry at the end of the cOrder list
  576. cFirst = pMRU->cOrder[uMax-1];
  577. ppData = &NTHDATA(pMRU, cFirst-BASE_CHAR);
  578. break;
  579. }
  580. if (!*ppData)
  581. // If the entry is not used.
  582. {
  583. cFirst = i+BASE_CHAR;
  584. break;
  585. }
  586. }
  587. *ppData = ReAlloc(*ppData, cbData+sizeof(DWORD));
  588. if (*ppData)
  589. {
  590. TCHAR szTemp[2];
  591. *((LPDWORD)(*ppData)) = cbData;
  592. hmemcpy(DATAPDATA(*ppData), lpData, cbData);
  593. iSlot = (int)(cFirst-BASE_CHAR);
  594. szTemp[0] = cFirst;
  595. szTemp[1] = TEXT('\0');
  596. RegSetValueEx(pMRU->hKey, szTemp, 0L, REG_BINARY, (LPVOID)lpData, cbData);
  597. fShouldWrite = TRUE;
  598. }
  599. else
  600. {
  601. // Since iSlot == -1, we will remove the reference to cFirst
  602. // below.
  603. }
  604. FoundEntry:
  605. // Remove any previous reference to cFirst.
  606. lpTemp = StrChr(pMRU->cOrder, cFirst);
  607. if (lpTemp)
  608. {
  609. lstrcpy(lpTemp, lpTemp+1);
  610. }
  611. if (iSlot != -1)
  612. {
  613. // shift everything over and put cFirst at the front
  614. hmemcpy(pMRU->cOrder+1, pMRU->cOrder, pMRU->uMax*sizeof(TCHAR));
  615. pMRU->cOrder[0] = cFirst;
  616. }
  617. if (fShouldWrite)
  618. {
  619. RegSetValueEx(pMRU->hKey, c_szMRU, 0L, REG_SZ, (CONST BYTE *)pMRU->cOrder,
  620. sizeof(TCHAR) * (lstrlen(pMRU->cOrder) + 1));
  621. pMRU->fFlags &= ~MRU_ORDERDIRTY;
  622. } else
  623. pMRU->fFlags |= MRU_ORDERDIRTY;
  624. #ifdef DEBUG
  625. // DebugMsg(DM_TRACE, TEXT("AddMRU: %d msec"), LOWORD(GetTickCount()-dwStart));
  626. #endif
  627. return(iSlot);
  628. }
  629. //----------------------------------------------------------------------------
  630. // Find data in an MRU list.
  631. // Returns the slot number.
  632. STDAPI_(int) FindMRUData(HANDLE hMRU, const void *lpData, UINT cbData, LPINT lpiSlot)
  633. {
  634. TCHAR cFirst;
  635. int iSlot = -1;
  636. LPTSTR lpTemp;
  637. LPBYTE *ppData;
  638. int i;
  639. UINT uMax;
  640. PMRUDATA pMRU = (PMRUDATA)hMRU;
  641. #ifdef DEBUG
  642. DWORD dwStart = GetTickCount();
  643. #endif
  644. ASSERT(IS_VALID_STRUCT_PTR(pMRU, MRUDATA));
  645. if (hMRU == NULL)
  646. return(-1); // Error state.
  647. // Can't call this API when it's created lazily.
  648. if (pMRU->fFlags & MRU_LAZY)
  649. {
  650. ASSERT(0);
  651. return -1;
  652. }
  653. uMax = pMRU->uMax;
  654. /* Find the item in the list.
  655. */
  656. for (i=0, ppData=&NTHDATA(pMRU, 0); (UINT)i<uMax; ++i, ++ppData)
  657. {
  658. if (!*ppData)
  659. continue;
  660. if (MRUIsSameData(pMRU, *ppData, lpData, cbData))
  661. {
  662. // So i now has the slot number in it.
  663. if (lpiSlot != NULL)
  664. *lpiSlot = i;
  665. // Now convert the slot number into an index number
  666. cFirst = i + BASE_CHAR;
  667. lpTemp = StrChr(pMRU->cOrder, cFirst);
  668. ASSERT(lpTemp);
  669. return((lpTemp == NULL)? -1 : (int)(lpTemp - (LPTSTR)pMRU->cOrder));
  670. }
  671. }
  672. return -1;
  673. }
  674. /* Find a string in an MRU list.
  675. */
  676. STDAPI_(int) FindMRUString(HANDLE hMRU, LPCTSTR szString, LPINT lpiSlot)
  677. {
  678. /* The extra +1 is so that the list is NULL terminated.
  679. */
  680. TCHAR cFirst;
  681. int iSlot = -1;
  682. LPTSTR lpTemp;
  683. LPTSTR *pTemp;
  684. int i;
  685. UINT uMax;
  686. MRUCMPPROC lpfnCompare;
  687. PMRUDATA pMRU = (PMRUDATA)hMRU;
  688. #ifdef DEBUG
  689. DWORD dwStart = GetTickCount();
  690. #endif
  691. ASSERT(IS_VALID_STRUCT_PTR(pMRU, MRUDATA));
  692. if (hMRU == NULL)
  693. return(-1); // Error state.
  694. uMax = pMRU->uMax;
  695. lpfnCompare = (MRUCMPPROC)pMRU->lpfnCompare;
  696. /* Find the item in the list.
  697. */
  698. for (i=0, pTemp=&NTHSTRING(pMRU, 0); (UINT)i<uMax; ++i, ++pTemp)
  699. {
  700. if (*pTemp)
  701. {
  702. int iResult;
  703. #ifdef UNICODE
  704. if (pMRU->fFlags & MRU_ANSI)
  705. {
  706. LPSTR lpStringA, lpTempA;
  707. lpStringA = ProduceAFromW (CP_ACP, szString);
  708. lpTempA = ProduceAFromW (CP_ACP, (LPWSTR)*pTemp);
  709. iResult = (*lpfnCompare)((const void *)lpStringA, (const void *)lpTempA);
  710. FreeProducedString (lpStringA);
  711. FreeProducedString (lpTempA);
  712. }
  713. else
  714. #endif
  715. {
  716. iResult = (*lpfnCompare)((CONST VOID *)szString, (CONST VOID *)*pTemp);
  717. }
  718. if (!iResult)
  719. {
  720. // So i now has the slot number in it.
  721. if (lpiSlot != NULL)
  722. *lpiSlot = i;
  723. // Now convert the slot number into an index number
  724. cFirst = i + BASE_CHAR;
  725. lpTemp = StrChr(pMRU->cOrder, cFirst);
  726. return((lpTemp == NULL)? -1 : (int)(lpTemp - (LPTSTR)pMRU->cOrder));
  727. }
  728. }
  729. }
  730. return(-1);
  731. }
  732. #ifdef UNICODE
  733. //
  734. // ANSI thunk
  735. //
  736. int WINAPI FindMRUStringA(HANDLE hMRU, LPCSTR szString, LPINT lpiSlot)
  737. {
  738. LPWSTR lpStringW;
  739. INT iResult;
  740. lpStringW = ProduceWFromA(CP_ACP, szString);
  741. iResult = FindMRUString(hMRU, lpStringW, lpiSlot);
  742. FreeProducedString (lpStringW);
  743. return iResult;
  744. }
  745. #else
  746. //
  747. // Unicode stub when build ANSI
  748. //
  749. int WINAPI FindMRUStringW(HANDLE hMRU, LPCWSTR szString, LPINT lpiSlot)
  750. {
  751. SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
  752. return -1;
  753. }
  754. #endif
  755. /* If lpszString is NULL, then this returns the number of MRU items or less than
  756. * 0 on error.
  757. * if nItem < 0, we'll return the number of items currently in the MRU.
  758. * Otherwise, fill in as much of the buffer as possible (uLen includes the
  759. * terminating NULL) and return the actual length of the string (including the
  760. * terminating NULL) or less than 0 on error.
  761. */
  762. STDAPI_(int) EnumMRUList(HANDLE hMRU, int nItem, LPVOID lpData, UINT uLen)
  763. {
  764. PMRUDATA pMRU = (PMRUDATA)hMRU;
  765. int nItems = -1;
  766. LPTSTR pTemp;
  767. LPBYTE pData;
  768. ASSERT(IS_VALID_STRUCT_PTR(pMRU, MRUDATA));
  769. if (pMRU)
  770. {
  771. nItems = lstrlen(pMRU->cOrder);
  772. if (nItem < 0 || !lpData)
  773. return nItems;
  774. if (nItem < nItems)
  775. {
  776. if (pMRU->fFlags & MRU_BINARY)
  777. {
  778. pData = NTHDATA(pMRU, pMRU->cOrder[nItem]-BASE_CHAR);
  779. if (!pData)
  780. return -1;
  781. uLen = min((UINT)DATASIZE(pData), uLen);
  782. hmemcpy(lpData, DATAPDATA(pData), uLen);
  783. nItems = uLen;
  784. }
  785. else
  786. {
  787. pTemp = NTHSTRING(pMRU, pMRU->cOrder[nItem]-BASE_CHAR);
  788. if (!pTemp)
  789. return -1;
  790. lstrcpyn((LPTSTR)lpData, pTemp, uLen);
  791. nItems = lstrlen(pTemp);
  792. }
  793. }
  794. else // revert to error condition
  795. nItems = -1;
  796. }
  797. return nItems;
  798. }
  799. #ifdef UNICODE
  800. STDAPI_(int) EnumMRUListA(HANDLE hMRU, int nItem, LPVOID lpData, UINT uLen)
  801. {
  802. int iResult = -1;
  803. PMRUDATA pMRU = (PMRUDATA)hMRU;
  804. ASSERT(IS_VALID_STRUCT_PTR(pMRU, MRUDATA));
  805. if (pMRU)
  806. {
  807. LPVOID lpDataW;
  808. BOOL bAllocatedMemory = FALSE;
  809. //
  810. // we need a temp buffer if the data is a string.
  811. // but if it is binary, then we trust the callers buffer.
  812. //
  813. if (!(pMRU->fFlags & MRU_BINARY) && uLen && lpData)
  814. {
  815. lpDataW = LocalAlloc(LPTR, uLen * sizeof(TCHAR));
  816. if (!lpDataW)
  817. return -1;
  818. bAllocatedMemory = TRUE;
  819. }
  820. else
  821. lpDataW = lpData;
  822. // call the real thing
  823. iResult = EnumMRUList(hMRU, nItem, lpDataW, uLen);
  824. //
  825. // if the buffer was a string that we allocated
  826. // then we need to thunk the string into the callers buffer
  827. //
  828. if (!(pMRU->fFlags & MRU_BINARY) && lpData && uLen && (iResult != -1))
  829. {
  830. WideCharToMultiByte(CP_ACP, 0, (LPWSTR)lpDataW, -1,
  831. (LPSTR)lpData, uLen, NULL, NULL);
  832. }
  833. if (bAllocatedMemory)
  834. LocalFree(lpDataW);
  835. }
  836. return iResult;
  837. }
  838. #else
  839. STDAPI_(int) EnumMRUListW(HANDLE hMRU, int nItem, LPVOID lpData, UINT uLen)
  840. {
  841. SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
  842. return 0;
  843. }
  844. #endif // UNICODE