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.

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