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.

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