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.

524 lines
17 KiB

  1. /*++
  2. Copyright (c) 1990-1998, Microsoft Corporation All rights reserved.
  3. Module Name:
  4. util.cpp
  5. Abstract:
  6. This module implements utility functions for the common dialog.
  7. Author:
  8. Arul Kumaravel (arulk@microsoft.com)
  9. History:
  10. Mar-07-2001 - Lazar Ivanov (LazarI)
  11. reimplemented ThunkDevNamesW2A & ThunkDevNamesA2W
  12. --*/
  13. // precompiled headers
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. #include "cdids.h"
  17. #include "fileopen.h"
  18. #include "filenew.h"
  19. #include "util.h"
  20. // crtfree.h is located in shell\inc and it defines new and delete
  21. // operators to do LocalAlloc and LocalFree, so you don't have to
  22. // link to MSVCRT in order to get those. i tried to remove this code
  23. // and link to MSVCRT, but there are some ugly written code here
  24. // which relies on the new operator to zero initialize the returned
  25. // memory block so the class don't bother to initialize its members
  26. // in the constructor. as i said this is quite ugly, but nothing i can
  27. // do about this at the moment.
  28. //
  29. // LazarI - 2/21/2001
  30. //
  31. #define DECL_CRTFREE
  32. #include <crtfree.h>
  33. #ifndef ASSERT
  34. #define ASSERT Assert
  35. #endif
  36. #define EVAL(x) x
  37. #define USE_AUTOCOMPETE_DEFAULT TRUE
  38. #define SZ_REGKEY_USEAUTOCOMPLETE TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoComplete")
  39. #define SZ_REGVALUE_FILEDLGAUTOCOMPLETE TEXT("AutoComplete In File Dialog")
  40. #define BOOL_NOT_SET 0x00000005
  41. #define SZ_REGVALUE_AUTOCOMPLETE_TAB TEXT("Always Use Tab")
  42. /****************************************************\
  43. FUNCTION: AutoComplete
  44. DESCRIPTION:
  45. This function will have AutoComplete take over
  46. an editbox to help autocomplete DOS paths.
  47. \****************************************************/
  48. HRESULT AutoComplete(HWND hwndEdit, ICurrentWorkingDirectory ** ppcwd, DWORD dwFlags)
  49. {
  50. HRESULT hr = S_OK;
  51. IUnknown * punkACLISF;
  52. static BOOL fUseAutoComplete = -10; // Not inited.
  53. if (-10 == fUseAutoComplete)
  54. fUseAutoComplete = (SHRegGetBoolUSValue(SZ_REGKEY_USEAUTOCOMPLETE, SZ_REGVALUE_FILEDLGAUTOCOMPLETE, FALSE, USE_AUTOCOMPETE_DEFAULT));
  55. // WARNING: If you want to disable AutoComplete by default,
  56. // turn USE_AUTOCOMPETE_DEFAULT to FALSE
  57. if (fUseAutoComplete)
  58. {
  59. Assert(!dwFlags); // Not yet used.
  60. hr = SHCoCreateInstance(NULL, &CLSID_ACListISF, NULL, IID_PPV_ARG(IUnknown, &punkACLISF));
  61. if (SUCCEEDED(hr))
  62. {
  63. IAutoComplete2 * pac;
  64. // Create the AutoComplete Object
  65. hr = SHCoCreateInstance(NULL, &CLSID_AutoComplete, NULL, IID_PPV_ARG(IAutoComplete2, &pac));
  66. if (SUCCEEDED(hr))
  67. {
  68. DWORD dwOptions = 0;
  69. hr = pac->Init(hwndEdit, punkACLISF, NULL, NULL);
  70. // Set the autocomplete options
  71. if (SHRegGetBoolUSValue(REGSTR_PATH_AUTOCOMPLETE, REGSTR_VAL_USEAUTOAPPEND, FALSE, /*default:*/FALSE))
  72. {
  73. dwOptions |= ACO_AUTOAPPEND;
  74. }
  75. if (SHRegGetBoolUSValue(REGSTR_PATH_AUTOCOMPLETE, REGSTR_VAL_USEAUTOSUGGEST, FALSE, /*default:*/TRUE))
  76. {
  77. dwOptions |= ACO_AUTOSUGGEST;
  78. }
  79. // Windows uses the TAB key to move between controls in a dialog. UNIX and other
  80. // operating systems that use AutoComplete have traditionally used the TAB key to
  81. // iterate thru the AutoComplete possibilities. We need to default to disable the
  82. // TAB key (ACO_USETAB) unless the caller specifically wants it. We will also
  83. // turn it on
  84. static BOOL s_fAlwaysUseTab = BOOL_NOT_SET;
  85. if (BOOL_NOT_SET == s_fAlwaysUseTab)
  86. s_fAlwaysUseTab = SHRegGetBoolUSValue(SZ_REGKEY_USEAUTOCOMPLETE, SZ_REGVALUE_AUTOCOMPLETE_TAB, FALSE, FALSE);
  87. if (s_fAlwaysUseTab)
  88. dwOptions |= ACO_USETAB;
  89. EVAL(SUCCEEDED(pac->SetOptions(dwOptions)));
  90. pac->Release();
  91. }
  92. if (ppcwd)
  93. {
  94. punkACLISF->QueryInterface(IID_PPV_ARG(ICurrentWorkingDirectory, ppcwd));
  95. }
  96. punkACLISF->Release();
  97. }
  98. }
  99. return hr;
  100. }
  101. ////////////////////////////////////////////////////////////////////////////
  102. //
  103. // Common Dialog Administrator Restrictions
  104. //
  105. ////////////////////////////////////////////////////////////////////////////
  106. const SHRESTRICTIONITEMS c_rgRestItems[] =
  107. {
  108. {REST_NOBACKBUTTON, L"Comdlg32", L"NoBackButton"},
  109. {REST_NOFILEMRU , L"Comdlg32", L"NoFileMru"},
  110. {REST_NOPLACESBAR, L"Comdlg32", L"NoPlacesBar"},
  111. {0, NULL, NULL},
  112. };
  113. #define NUMRESTRICTIONS ARRAYSIZE(c_rgRestItems)
  114. DWORD g_rgRestItemValues[NUMRESTRICTIONS - 1 ] = { -1 };
  115. DWORD IsRestricted(COMMDLG_RESTRICTIONS rest)
  116. {
  117. static BOOL bFirstTime = TRUE;
  118. if (bFirstTime)
  119. {
  120. memset((LPBYTE)g_rgRestItemValues, (BYTE)-1, sizeof(g_rgRestItemValues));
  121. bFirstTime = FALSE;
  122. }
  123. return SHRestrictionLookup(rest, NULL, c_rgRestItems, g_rgRestItemValues);
  124. }
  125. #define MODULE_NAME_SIZE 128
  126. #define MODULE_VERSION_SIZE 15
  127. typedef struct tagAPPCOMPAT
  128. {
  129. LPCTSTR pszModule;
  130. LPCTSTR pszVersion;
  131. DWORD dwFlags;
  132. } APPCOMPAT, FAR* LPAPPCOMPAT;
  133. DWORD CDGetAppCompatFlags()
  134. {
  135. static BOOL bInitialized = FALSE;
  136. static DWORD dwCachedFlags = 0;
  137. static const APPCOMPAT aAppCompat[] =
  138. { //Mathcad
  139. {TEXT("MCAD.EXE"), TEXT("6.00b"), CDACF_MATHCAD},
  140. //Picture Publisher
  141. {TEXT("PP70.EXE"),NULL, CDACF_NT40TOOLBAR},
  142. {TEXT("PP80.EXE"),NULL, CDACF_NT40TOOLBAR},
  143. //Code Wright
  144. {TEXT("CW32.exe"),TEXT("5.1"), CDACF_NT40TOOLBAR},
  145. //Designer.exe
  146. {TEXT("ds70.exe"),NULL, CDACF_FILETITLE}
  147. };
  148. if (!bInitialized)
  149. {
  150. TCHAR szModulePath[MODULE_NAME_SIZE];
  151. TCHAR* pszModuleName;
  152. DWORD dwHandle;
  153. int i;
  154. GetModuleFileName(GetModuleHandle(NULL), szModulePath, ARRAYSIZE(szModulePath));
  155. pszModuleName = PathFindFileName(szModulePath);
  156. if (pszModuleName)
  157. {
  158. for (i=0; i < ARRAYSIZE(aAppCompat); i++)
  159. {
  160. if (lstrcmpi(aAppCompat[i].pszModule, pszModuleName) == 0)
  161. {
  162. if (aAppCompat[i].pszVersion == NULL)
  163. {
  164. dwCachedFlags = aAppCompat[i].dwFlags;
  165. }
  166. else
  167. {
  168. CHAR chBuffer[3072]; // hopefully this is enough... lotus smart center needs 3000
  169. TCHAR* pszVersion = NULL;
  170. UINT cb;
  171. // get module version here!
  172. cb = GetFileVersionInfoSize(szModulePath, &dwHandle);
  173. if (cb <= ARRAYSIZE(chBuffer) &&
  174. GetFileVersionInfo(szModulePath, dwHandle, ARRAYSIZE(chBuffer), (LPVOID)chBuffer) &&
  175. VerQueryValue((LPVOID)chBuffer, TEXT("\\StringFileInfo\\040904E4\\ProductVersion"), (void **) &pszVersion, &cb))
  176. {
  177. DebugMsg(0x0004, TEXT("product: %s\n version: %s"), pszModuleName, pszVersion);
  178. if (lstrcmpi(pszVersion, aAppCompat[i].pszVersion) == 0)
  179. {
  180. dwCachedFlags = aAppCompat[i].dwFlags;
  181. break;
  182. }
  183. }
  184. }
  185. }
  186. }
  187. }
  188. bInitialized = TRUE;
  189. }
  190. return dwCachedFlags;
  191. }
  192. BOOL ILIsFTP(LPCITEMIDLIST pidl)
  193. {
  194. IShellFolder * psf;
  195. BOOL fIsFTPFolder = FALSE;
  196. if (SUCCEEDED(CDBindToObject(NULL, IID_X_PPV_ARG(IShellFolder, pidl, &psf))))
  197. {
  198. CLSID clsid;
  199. if (SUCCEEDED(IUnknown_GetClassID(psf, &clsid)) &&
  200. (IsEqualIID(clsid, CLSID_FtpFolder)))
  201. {
  202. fIsFTPFolder = TRUE;
  203. }
  204. psf->Release();
  205. }
  206. return fIsFTPFolder;
  207. }
  208. #ifdef __cplusplus
  209. extern "C" {
  210. #endif
  211. // this is weak.
  212. // a long time ago somebody changed all the FindResources to call FindResourceEx, specifying
  213. // a language. thatd be cool except FindResource already has logic to get the right language.
  214. // whatever was busted should have probably been fixed some other way.
  215. // not only that but it's broken because MUI needs to fall back to US if it can't get the resource
  216. // from the MUI language-specific files.
  217. // thus force a fallback to US. really everything should be rewritten to be normal like every other
  218. // DLL but there's a lot of weird TLS stuff that would break and its risky for this late in XP.
  219. HRSRC FindResourceExFallback(HMODULE hModule, LPCTSTR lpType, LPCTSTR lpName, WORD wLanguage)
  220. {
  221. HRSRC hrsrc = FindResourceEx(hModule, lpType, lpName, wLanguage);
  222. if (!hrsrc)
  223. {
  224. LANGID langid = GetSystemDefaultUILanguage();
  225. if (langid && (langid != wLanguage))
  226. {
  227. hrsrc = FindResourceEx(hModule, lpType, lpName, langid);
  228. }
  229. }
  230. return hrsrc;
  231. }
  232. // Win32Error2HRESULT: converts Win32 error to HRESULT
  233. inline HRESULT Win32Error2HRESULT(DWORD dwError = GetLastError())
  234. {
  235. return (ERROR_SUCCESS == dwError) ? E_FAIL : HRESULT_FROM_WIN32(dwError);
  236. }
  237. /*++
  238. Routine Name:
  239. ThunkDevNamesA2W
  240. Routine Description:
  241. Converts ANSI DEVNAMES structure to UNICODE
  242. on failure we don't release *phDevNamesW
  243. Arguments:
  244. hDevNamesA - [in] handle to ANSI DEVNAMES
  245. phDevNamesW - [in, out] handle to UNICODE DEVNAMES
  246. Return Value:
  247. S_OK if succeded and OLE error otherwise
  248. History:
  249. Lazar Ivanov (LazarI), Mar-07-2001 - created.
  250. --*/
  251. HRESULT
  252. ThunkDevNamesA2W(
  253. IN HGLOBAL hDevNamesA,
  254. IN OUT HGLOBAL *phDevNamesW
  255. )
  256. {
  257. HRESULT hr = E_FAIL;
  258. if (hDevNamesA && phDevNamesW)
  259. {
  260. LPDEVNAMES pDNA = (LPDEVNAMES )GlobalLock(hDevNamesA);
  261. if (pDNA)
  262. {
  263. // calculate the input string pointers
  264. LPSTR pszDriver = reinterpret_cast<LPSTR>(pDNA) + pDNA->wDriverOffset;
  265. LPSTR pszDevice = reinterpret_cast<LPSTR>(pDNA) + pDNA->wDeviceOffset;
  266. LPSTR pszOutput = reinterpret_cast<LPSTR>(pDNA) + pDNA->wOutputOffset;
  267. // calculate the lengths of the ANSI strings
  268. SIZE_T iDriverLenW = MultiByteToWideChar(CP_ACP, 0, pszDriver, -1, NULL, 0);
  269. SIZE_T iDeviceLenW = MultiByteToWideChar(CP_ACP, 0, pszDevice, -1, NULL, 0);
  270. SIZE_T iOutputLenW = MultiByteToWideChar(CP_ACP, 0, pszOutput, -1, NULL, 0);
  271. // calculate the output buffer length
  272. SIZE_T iBytesTotal = sizeof(DEVNAMES) + sizeof(WCHAR) *
  273. ((iDriverLenW + 1) + (iDeviceLenW + 1) + (iOutputLenW + 1) + DN_PADDINGCHARS);
  274. HGLOBAL hDevNamesW = (*phDevNamesW) ?
  275. GlobalReAlloc(*phDevNamesW, iBytesTotal, GHND) :
  276. GlobalAlloc(GHND, iBytesTotal);
  277. if (hDevNamesW)
  278. {
  279. // thunk DEVNAMES...
  280. LPDEVNAMES pDNW = (LPDEVNAMES )GlobalLock(hDevNamesW);
  281. if (pDNW)
  282. {
  283. // calculate the offsets
  284. // note: the offsets are in chars not bytes!!
  285. pDNW->wDriverOffset = sizeof(DEVNAMES) / sizeof(WCHAR);
  286. pDNW->wDeviceOffset = pDNW->wDriverOffset + iDriverLenW + 1;
  287. pDNW->wOutputOffset = pDNW->wDeviceOffset + iDeviceLenW + 1;
  288. pDNW->wDefault = pDNA->wDefault;
  289. // calculate the output string pointers
  290. LPWSTR pwszDriver = reinterpret_cast<LPWSTR>(pDNW) + pDNW->wDriverOffset;
  291. LPWSTR pwszDevice = reinterpret_cast<LPWSTR>(pDNW) + pDNW->wDeviceOffset;
  292. LPWSTR pwszOutput = reinterpret_cast<LPWSTR>(pDNW) + pDNW->wOutputOffset;
  293. // convert from ansi to uniciode
  294. MultiByteToWideChar(CP_ACP, 0, pszDriver, -1, pwszDriver, iDriverLenW + 1);
  295. MultiByteToWideChar(CP_ACP, 0, pszDevice, -1, pwszDevice, iDeviceLenW + 1);
  296. MultiByteToWideChar(CP_ACP, 0, pszOutput, -1, pwszOutput, iOutputLenW + 1);
  297. // unlock hDevNamesW
  298. GlobalUnlock(hDevNamesW);
  299. // declare success
  300. *phDevNamesW = hDevNamesW;
  301. hr = S_OK;
  302. }
  303. else
  304. {
  305. // GlobalLock failed
  306. hr = Win32Error2HRESULT(GetLastError());
  307. GlobalFree(hDevNamesW);
  308. }
  309. }
  310. else
  311. {
  312. // GlobalAlloc failed
  313. hr = E_OUTOFMEMORY;
  314. }
  315. // unlock hDevNamesA
  316. GlobalUnlock(hDevNamesA);
  317. }
  318. else
  319. {
  320. // GlobalLock failed
  321. hr = Win32Error2HRESULT(GetLastError());
  322. }
  323. }
  324. else
  325. {
  326. // some of the arguments are invalid (NULL)
  327. hr = E_INVALIDARG;
  328. }
  329. return hr;
  330. }
  331. /*++
  332. Routine Name:
  333. ThunkDevNamesW2A
  334. Routine Description:
  335. Converts UNICODE DEVNAMES structure to ANSI
  336. on failure we don't release *phDevNamesA
  337. Arguments:
  338. hDevNamesW - [in] handle to UNICODE DEVNAMES
  339. phDevNamesA - [in, out] handle to ANSI DEVNAMES
  340. Return Value:
  341. S_OK if succeded and OLE error otherwise
  342. History:
  343. Lazar Ivanov (LazarI), Mar-07-2001 - created.
  344. --*/
  345. HRESULT
  346. ThunkDevNamesW2A(
  347. IN HGLOBAL hDevNamesW,
  348. IN OUT HGLOBAL *phDevNamesA
  349. )
  350. {
  351. HRESULT hr = E_FAIL;
  352. if (hDevNamesW && phDevNamesA)
  353. {
  354. LPDEVNAMES pDNW = (LPDEVNAMES)GlobalLock(hDevNamesW);
  355. if (pDNW)
  356. {
  357. // calculate the input string pointers
  358. LPWSTR pwszDriver = reinterpret_cast<LPWSTR>(pDNW) + pDNW->wDriverOffset;
  359. LPWSTR pwszDevice = reinterpret_cast<LPWSTR>(pDNW) + pDNW->wDeviceOffset;
  360. LPWSTR pwszOutput = reinterpret_cast<LPWSTR>(pDNW) + pDNW->wOutputOffset;
  361. // calculate the lengths of the ANSI strings
  362. SIZE_T iDriverLenA = WideCharToMultiByte(CP_ACP, 0, pwszDriver, -1, NULL, 0, NULL, NULL);
  363. SIZE_T iDeviceLenA = WideCharToMultiByte(CP_ACP, 0, pwszDevice, -1, NULL, 0, NULL, NULL);
  364. SIZE_T iOutputLenA = WideCharToMultiByte(CP_ACP, 0, pwszOutput, -1, NULL, 0, NULL, NULL);
  365. // calculate the output buffer length
  366. SIZE_T iBytesTotal = sizeof(DEVNAMES) + sizeof(CHAR) *
  367. ((iDriverLenA + 1) + (iDeviceLenA + 1) + (iOutputLenA + 1) + DN_PADDINGCHARS);
  368. HGLOBAL hDevNamesA = (*phDevNamesA) ?
  369. GlobalReAlloc(*phDevNamesA, iBytesTotal, GHND) :
  370. GlobalAlloc(GHND, iBytesTotal);
  371. if (hDevNamesA)
  372. {
  373. // thunk DEVNAMES...
  374. LPDEVNAMES pDNA = (LPDEVNAMES )GlobalLock(hDevNamesA);
  375. if (pDNA)
  376. {
  377. // calculate the offsets
  378. // note: the offsets are in chars not bytes!!
  379. pDNA->wDriverOffset = sizeof(DEVNAMES) / sizeof(CHAR);
  380. pDNA->wDeviceOffset = pDNA->wDriverOffset + iDriverLenA + 1;
  381. pDNA->wOutputOffset = pDNA->wDeviceOffset + iDeviceLenA + 1;
  382. pDNA->wDefault = pDNW->wDefault;
  383. // calculate the output string pointers
  384. LPSTR pszDriver = reinterpret_cast<LPSTR>(pDNA) + pDNA->wDriverOffset;
  385. LPSTR pszDevice = reinterpret_cast<LPSTR>(pDNA) + pDNA->wDeviceOffset;
  386. LPSTR pszOutput = reinterpret_cast<LPSTR>(pDNA) + pDNA->wOutputOffset;
  387. // convert from uniciode to ansi
  388. WideCharToMultiByte(CP_ACP, 0, pwszDriver, -1, pszDriver, iDriverLenA + 1, NULL, NULL);
  389. WideCharToMultiByte(CP_ACP, 0, pwszDevice, -1, pszDevice, iDeviceLenA + 1, NULL, NULL);
  390. WideCharToMultiByte(CP_ACP, 0, pwszOutput, -1, pszOutput, iOutputLenA + 1, NULL, NULL);
  391. // unlock hDevNamesA
  392. GlobalUnlock(hDevNamesA);
  393. // declare success
  394. *phDevNamesA = hDevNamesA;
  395. hr = S_OK;
  396. }
  397. else
  398. {
  399. // GlobalLock failed
  400. hr = Win32Error2HRESULT(GetLastError());
  401. GlobalFree(hDevNamesW);
  402. }
  403. }
  404. else
  405. {
  406. // GlobalAlloc failed
  407. hr = E_OUTOFMEMORY;
  408. }
  409. // unlock hDevNamesW
  410. GlobalUnlock(hDevNamesW);
  411. }
  412. else
  413. {
  414. // GlobalLock failed
  415. hr = Win32Error2HRESULT(GetLastError());
  416. }
  417. }
  418. else
  419. {
  420. // some of the arguments are invalid (NULL)
  421. hr = E_INVALIDARG;
  422. }
  423. return hr;
  424. }
  425. #ifdef __cplusplus
  426. }; // extern "C"
  427. #endif