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.

444 lines
13 KiB

  1. /*++
  2. Copyright (c) 1990-1998, Microsoft Corporation All rights reserved.
  3. Module Name:
  4. filemru.cpp
  5. Abstract:
  6. This module contains the functions for implementing file mru
  7. in file open and file save dialog boxes
  8. Revision History:
  9. 01/22/98 arulk created
  10. --*/
  11. // precompiled headers
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. #include "cdids.h"
  15. #include "filemru.h"
  16. #ifndef ASSERT
  17. #define ASSERT Assert
  18. #endif
  19. #define REGSTR_PATH_FILEMRU TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\OpenSaveMRU\\")
  20. #define REGSTR_PATH_LASTVISITED TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\LastVisitedMRU\\")
  21. HANDLE CreateMRU(LPCTSTR pszExt, int nMax)
  22. {
  23. TCHAR szRegPath[256];
  24. MRUINFO mi = {
  25. sizeof(MRUINFO),
  26. nMax,
  27. MRU_CACHEWRITE,
  28. HKEY_CURRENT_USER,
  29. szRegPath,
  30. NULL // NOTE: use default string compare
  31. };
  32. //Get the Registry path for the given file type MRU
  33. EVAL(SUCCEEDED(StringCchCopy(szRegPath, ARRAYSIZE(szRegPath), REGSTR_PATH_FILEMRU)));
  34. EVAL(SUCCEEDED(StringCchCat(szRegPath, ARRAYSIZE(szRegPath), pszExt ? pszExt : TEXT("*"))));
  35. //Call the comctl32 mru implementation to load the MRU from
  36. //the registry
  37. return CreateMRUList(&mi);
  38. }
  39. BOOL GetMRUEntry(HANDLE hMRU, int iIndex, LPTSTR lpString, UINT cbSize)
  40. {
  41. //Check for valid parameters
  42. if(!lpString || !cbSize || !hMRU)
  43. {
  44. return FALSE;
  45. }
  46. //Check for valid index
  47. if (iIndex < 0 || iIndex > EnumMRUList(hMRU, -1, NULL, 0))
  48. {
  49. return FALSE;
  50. }
  51. if ((EnumMRUList(hMRU, iIndex, lpString, cbSize) > 0 ))
  52. {
  53. return TRUE;
  54. }
  55. return FALSE;
  56. }
  57. typedef struct {
  58. HANDLE mru;
  59. LPTSTR psz;
  60. } EXTMRU, *PEXTMRU;
  61. STDAPI_(int) _FreeExtMru(void * pvItem, void * pvData)
  62. {
  63. PEXTMRU pem = (PEXTMRU) pvItem;
  64. if (pem)
  65. {
  66. ASSERT(pem->psz);
  67. ASSERT(pem->mru);
  68. LocalFree(pem->psz);
  69. FreeMRUList(pem->mru);
  70. LocalFree(pem);
  71. return TRUE;
  72. }
  73. return FALSE;
  74. }
  75. STDAPI_(int) _ExtMruFindExt(void * pvFind, void * pvItem, LPARAM pvParam)
  76. {
  77. ASSERT(pvFind && pvItem);
  78. return StrCmp(((PEXTMRU)pvItem)->psz, (LPCTSTR)pvFind);
  79. }
  80. PEXTMRU _AllocExtMru(LPCTSTR pszExt, int nMax)
  81. {
  82. PEXTMRU pem = (PEXTMRU) LocalAlloc(LPTR, SIZEOF(EXTMRU));
  83. if (pem)
  84. {
  85. pem->psz = StrDup(pszExt);
  86. pem->mru = CreateMRU (pszExt, nMax);
  87. if (pem->psz && pem->mru)
  88. return pem;
  89. _FreeExtMru(pem, NULL);
  90. }
  91. return NULL;
  92. }
  93. HDPA _CreateExtMruDpa(LPCTSTR pszFilter, int nMax, int *pcItems)
  94. {
  95. //Convert the filter string of form *.c;*.cpp;*.h into form
  96. // *.c\0*.cpp\0*.h\0. Also count the file types
  97. LPTSTR pszFree = StrDup(pszFilter);
  98. *pcItems = 0;
  99. if (pszFree)
  100. {
  101. HDPA hdpa = DPA_Create(4);
  102. if (hdpa)
  103. {
  104. LPTSTR pszNext = pszFree;
  105. int cItems = 0;
  106. LPTSTR pszSemi;
  107. do
  108. {
  109. pszSemi = StrChr(pszNext, CHAR_SEMICOLON);
  110. if (pszSemi)
  111. *pszSemi = CHAR_NULL;
  112. LPTSTR pszExt = PathFindExtension(pszNext);
  113. if (*pszExt)
  114. {
  115. // walk past the dot...
  116. pszExt++;
  117. // make sure this extension isnt already in the dpa
  118. if (-1 == DPA_Search(hdpa, pszExt, 0, _ExtMruFindExt, NULL, 0))
  119. {
  120. PEXTMRU pem = _AllocExtMru(pszExt, nMax);
  121. if (!pem)
  122. break;
  123. DPA_SetPtr(hdpa, cItems++, (void *)pem);
  124. }
  125. }
  126. // we only have a next if there was more than one...
  127. if (pszSemi)
  128. pszNext = pszSemi + 1;
  129. } while (pszSemi);
  130. *pcItems = cItems;
  131. }
  132. LocalFree(pszFree);
  133. return hdpa;
  134. }
  135. return NULL;
  136. }
  137. BOOL LoadMRU(LPCTSTR pszFilter, HWND hwndCombo, int nMax)
  138. {
  139. //Check if valid filter string is passed
  140. if (!pszFilter || !pszFilter[0] || nMax <= 0)
  141. {
  142. return FALSE;
  143. }
  144. //First reset the hwndCombo
  145. SendMessage(hwndCombo, CB_RESETCONTENT, (WPARAM)0L, (LPARAM)0L);
  146. int cDPAItems;
  147. HDPA hdpa = _CreateExtMruDpa(pszFilter, nMax, &cDPAItems);
  148. if (hdpa)
  149. {
  150. TCHAR szFile[MAX_PATH];
  151. //Set the comboboxex item values
  152. COMBOBOXEXITEM cbexItem = {0};
  153. cbexItem.mask = CBEIF_TEXT; // This combobox displays only text
  154. cbexItem.iItem = -1; // Always insert the item at the end
  155. cbexItem.pszText = szFile; // This buffer contains the string
  156. cbexItem.cchTextMax = ARRAYSIZE(szFile); // Size of the buffer
  157. //Now load the hwndcombo with file list from MRU.
  158. //We use a kind of round robin algorithm for filling
  159. //the mru. We start with first MRU and try to fill the combobox
  160. //with one string from each mru. Until we have filled the required
  161. //strings or we have exhausted all strings in the mrus
  162. for (int j = 0; nMax > 0; j++)
  163. {
  164. //Variable used for checking whether we are able to load atlease one string
  165. //during the loop
  166. BOOL fCouldLoadAtleastOne = FALSE;
  167. for (int i = 0; i < cDPAItems && nMax > 0; i++)
  168. {
  169. PEXTMRU pem = (PEXTMRU)DPA_FastGetPtr(hdpa, i);
  170. if (pem && GetMRUEntry(pem->mru, j, szFile, SIZECHARS(szFile)))
  171. {
  172. SendMessage(hwndCombo, CBEM_INSERTITEM, (WPARAM)0, (LPARAM)(void *)&cbexItem);
  173. nMax--;
  174. fCouldLoadAtleastOne = TRUE;
  175. }
  176. }
  177. //Check for possible infinite loop
  178. if(!fCouldLoadAtleastOne)
  179. {
  180. //We couldn't load string from any of the MRU's so there's no point
  181. //in continuing this loop further. This is the max number of strings
  182. // we can load for this user, for this filter type.
  183. break;
  184. }
  185. }
  186. DPA_DestroyCallback(hdpa, _FreeExtMru, NULL);
  187. }
  188. return TRUE;
  189. }
  190. //This function adds the selected file into the MRU of the appropriate file MRU's
  191. //This functions also takes care of MultiFile Select case in which the file selected
  192. //will c:\winnt\file1.c\0file2.c\0file3.c\0. Refer GetOpenFileName documentation for
  193. // how the multifile is returned.
  194. BOOL AddToMRU(LPOPENFILENAME lpOFN)
  195. {
  196. TCHAR szDir[MAX_PATH];
  197. TCHAR szFile[MAX_PATH];
  198. LPTSTR lpFile;
  199. LPTSTR lpExt;
  200. BOOL fAddToStar = TRUE;
  201. HANDLE hMRUStar;
  202. //Check if we have valid file name
  203. if (!lpOFN->lpstrFile)
  204. return FALSE;
  205. hMRUStar = CreateMRU(szStar, 10); //File MRU For *.* file extension
  206. //Copy the Directory for the selected file
  207. ASSERT(0 < lpOFN->nFileOffset && lpOFN->nFileOffset <= ARRAYSIZE(szDir)); // Entire path passed in isn't longer than MAX_PATH, so this should be true.
  208. StringCchCopy(szDir, lpOFN->nFileOffset, lpOFN->lpstrFile); // This will truncate intentionally - we are only copying the directory from the full path.
  209. //point to the first file
  210. lpFile = lpOFN->lpstrFile + lpOFN->nFileOffset;
  211. do
  212. {
  213. // PERF: if there are multiple files of the same extension type,
  214. // don't keep re-creating the mru.
  215. lpExt = PathFindExtension(lpFile);
  216. if (lpExt && *lpExt)
  217. {
  218. lpExt += 1; // Remove dot
  219. }
  220. HANDLE hMRU = CreateMRU(lpExt, 10);
  221. if (hMRU)
  222. {
  223. if (PathCombine(szFile, szDir, lpFile))
  224. {
  225. AddMRUString(hMRU, szFile);
  226. if((lstrcmpi(lpExt, szStar)) && hMRUStar)
  227. {
  228. //Add to the *.* file mru also
  229. AddMRUString(hMRUStar, szFile);
  230. }
  231. }
  232. FreeMRUList(hMRU);
  233. }
  234. lpFile = lpFile + lstrlen(lpFile) + 1;
  235. } while (((lpOFN->Flags & OFN_ALLOWMULTISELECT)) && (*lpFile != CHAR_NULL));
  236. //Free the * file mru
  237. if (hMRUStar)
  238. {
  239. FreeMRUList(hMRUStar);
  240. }
  241. return TRUE;
  242. }
  243. ////////////////////////////////////////////////////////////////////////////
  244. //
  245. // Last Visited MRU Implementation
  246. // All Strings stored in the registry are stored in unicode format.
  247. //
  248. ////////////////////////////////////////////////////////////////////////////
  249. ////////////////////////////////////////////////////////////////////////////
  250. // CreateLastVisitedItem
  251. ////////////////////////////////////////////////////////////////////////////
  252. LPBYTE CreateLastVisitedItem(LPCWSTR wszModule, LPCWSTR wszPath, DWORD *pcbOut)
  253. {
  254. LPBYTE pitem = NULL;
  255. DWORD cbLen1, cbLen2;
  256. cbLen1 = CbFromCchW(lstrlenW(wszModule)+1);
  257. cbLen2 = CbFromCchW(lstrlenW(wszPath)+1);
  258. pitem = (LPBYTE) LocalAlloc(LPTR, cbLen1+cbLen2);
  259. if (pitem)
  260. {
  261. memcpy(pitem, wszModule, cbLen1);
  262. memcpy(pitem+cbLen1, wszPath, cbLen2);
  263. *pcbOut = cbLen1+cbLen2;
  264. }
  265. return pitem;
  266. }
  267. int cdecl LastVisitedCompareProc(const void *p1, const void *p2, size_t cb)
  268. {
  269. return StrCmpIW((LPWSTR)p1,(LPWSTR)p2);
  270. }
  271. ////////////////////////////////////////////////////////////////////////////
  272. // Store all the strings in the registry as unicode strings
  273. ////////////////////////////////////////////////////////////////////////////
  274. BOOL AddToLastVisitedMRU(LPCTSTR pszFile, int nFileOffset)
  275. {
  276. BOOL bRet = FALSE;
  277. if (!PathIsTemporary(pszFile))
  278. {
  279. MRUDATAINFO mi =
  280. {
  281. SIZEOF(MRUDATAINFO),
  282. MAX_MRU,
  283. MRU_BINARY | MRU_CACHEWRITE,
  284. HKEY_CURRENT_USER,
  285. REGSTR_PATH_LASTVISITED,
  286. LastVisitedCompareProc
  287. };
  288. HANDLE hMRU = CreateMRUList((MRUINFO *)&mi);
  289. if (hMRU)
  290. {
  291. WCHAR wszDir[MAX_PATH];
  292. WCHAR wszModulePath[MAX_PATH];
  293. //Get the module name
  294. GetModuleFileNameWrapW(GetModuleHandle(NULL), wszModulePath, ARRAYSIZE(wszModulePath));
  295. WCHAR* pszModuleName = PathFindFileNameW(wszModulePath);
  296. int i = FindMRUData(hMRU, (void *)pszModuleName, CbFromCchW(lstrlenW(pszModuleName)+1), NULL);
  297. if (i >= 0)
  298. {
  299. DelMRUString(hMRU, i);
  300. }
  301. //Get the directory from file.
  302. ASSERT(0 < nFileOffset && nFileOffset <= ARRAYSIZE(wszDir));
  303. StringCchCopy(wszDir, nFileOffset, pszFile); // This will truncate intentionally - we are only copying the directory from the path.
  304. DWORD cbSize;
  305. LPBYTE pitem = CreateLastVisitedItem(pszModuleName, wszDir, &cbSize);
  306. if (pitem)
  307. {
  308. AddMRUData(hMRU, pitem, cbSize);
  309. bRet = TRUE;
  310. LocalFree(pitem);
  311. }
  312. FreeMRUList(hMRU);
  313. }
  314. }
  315. return bRet;
  316. }
  317. BOOL GetPathFromLastVisitedMRU(LPTSTR pszDir, DWORD cchDir)
  318. {
  319. BOOL bRet = FALSE;
  320. MRUDATAINFO mi =
  321. {
  322. SIZEOF(MRUDATAINFO),
  323. MAX_MRU,
  324. MRU_BINARY | MRU_CACHEWRITE,
  325. HKEY_CURRENT_USER,
  326. REGSTR_PATH_LASTVISITED,
  327. LastVisitedCompareProc
  328. };
  329. pszDir[0] = 0;
  330. HANDLE hMRU = CreateMRUList((MRUINFO *)&mi);
  331. if (hMRU)
  332. {
  333. WCHAR wszModulePath[MAX_PATH];
  334. //Get the module name
  335. GetModuleFileNameWrapW(GetModuleHandle(NULL), wszModulePath, ARRAYSIZE(wszModulePath));
  336. WCHAR* pszModuleName = PathFindFileNameW(wszModulePath);
  337. int i = FindMRUData(hMRU, pszModuleName, CbFromCchW(lstrlenW(pszModuleName) + 1), NULL);
  338. if (i >= 0)
  339. {
  340. BYTE buf[CbFromCchW(2*MAX_PATH)];
  341. if (-1 != EnumMRUList(hMRU, i, buf, SIZEOF(buf)))
  342. {
  343. LPWSTR psz = (LPWSTR)((LPBYTE)buf + CbFromCchW(lstrlenW((LPWSTR)buf) +1));
  344. SHUnicodeToTChar(psz, pszDir, cchDir);
  345. bRet = TRUE;
  346. }
  347. }
  348. FreeMRUList(hMRU);
  349. }
  350. return bRet;
  351. }