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.

1017 lines
26 KiB

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