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.

1441 lines
42 KiB

  1. /* Look for BUILDBUILD to find build hacks. */
  2. /* BUILDBUILD: My hacks to get this to build. */
  3. #pragma warning(disable:4001) /* "single line comment" warning */
  4. #include "project.h"
  5. #pragma hdrstop
  6. #include "urlshell.h"
  7. #include <windowsx.h>
  8. #include <mluisupp.h>
  9. #undef NO_HELP
  10. #include <help.h>
  11. #pragma pack(1)
  12. //#include <newexe.h> // newexe.h is broken with pack()!!!
  13. #pragma pack()
  14. #ifdef STRICT
  15. #undef STRICT
  16. #endif
  17. #define NO_SHELL_HEAP_ALLOCATOR //Kludge to get around new mem heaps in nt
  18. #define NO_MULTIMON // BUILDBUILD (scotth): no multimon stub functions
  19. #define NO_SHELL_VALIDATION
  20. #include <newexe.h> // BUILDBUILD: added this from shellprv.h
  21. #include "resource.h" // BUILDBUILD: use local resource IDs
  22. #ifdef RegQueryValue
  23. #undef RegQueryValue
  24. #endif
  25. #define RegQueryValue(hkey, pszSubkey, pvValue, pcbSize) SHGetValue(hkey, pszSubkey, NULL, NULL, pvValue, pcbSize)
  26. // BUILDBUILD: add from shsemip.h
  27. #define SIZEOF(a) sizeof(a)
  28. // BUILDBUILD: was from cstrings.h
  29. extern CCHAR c_szNULL[];
  30. #include "openas.h"
  31. #undef HINST_THISDLL
  32. #define HINST_THISDLL (GetThisModulesHandle())
  33. #undef ASSERTNONCRITICAL
  34. #define ASSERTNONCRITICAL ASSERT(! AccessIsExclusive());
  35. #define MZMAGIC ((WORD)'M'+((WORD)'Z'<<8))
  36. #define LEMAGIC ((WORD)'L'+((WORD)'E'<<8))
  37. #define FCC(c0,c1,c2,c3) ((DWORD)(c0)|((DWORD)(c1)<<8)|((DWORD)(c2)<<16)|((DWORD)(c3)<<24))
  38. #define COM_FILE FCC('.', 'c', 'o', 'm')
  39. #define BAT_FILE FCC('.', 'b', 'a', 't')
  40. #define EXE_FILE FCC('.', 'e', 'x', 'e')
  41. #define hinstCabinet GetThisModulesHandle()
  42. BOOL GetClassDescription(HKEY hkClasses, LPCSTR pszClass, LPSTR szDisplayName, int cbDisplayName, UINT uFlags);
  43. /* needed because the NT shell only understands unicode for these
  44. * functions...
  45. */
  46. /* define the local versions */
  47. extern BOOL lPathIsExeA(LPCSTR);
  48. extern int lShell_GetCachedImageIndexA(LPCSTR, int, UINT);
  49. extern BOOL lPathYetAnotherMakeUniqueNameA(LPSTR,LPCSTR,LPCSTR,LPCSTR);
  50. extern LONG lRegDeleteKeyA(HKEY, LPCSTR);
  51. /***********************************************************
  52. * Needed because under NT, deleting a subkey will fail.
  53. *
  54. * Stolen from the SDK:
  55. * Windows 95: The RegDeleteKey function deletes a key and
  56. * all its descendents.
  57. * Windows NT: The RegDeleteKey function deletes the specified
  58. * key. This function cannot delete a key that has
  59. * subkeys.
  60. **********************************************************/
  61. // On Win95, RegDeleteKey deletes the key and all subkeys. On NT, RegDeleteKey
  62. // fails if there are any subkeys. On NT, we'll make shell code that assumes
  63. // the Win95 behavior work by mapping SHRegDeleteKey to a helper function that
  64. // does the recursive delete.
  65. // The reason we do it here, instead of calling the shell is so that we don't
  66. // have any bogus dynalinks for the X86 version, which must also run on W95.
  67. LONG ShRegDeleteKey(HKEY hKey, LPCSTR lpSubKey)
  68. {
  69. LONG lResult;
  70. HKEY hkSubKey;
  71. DWORD dwIndex;
  72. char szSubKeyName[MAX_PATH + 1];
  73. DWORD cchSubKeyName = ARRAYSIZE(szSubKeyName);
  74. char szClass[MAX_PATH];
  75. DWORD cbClass = ARRAYSIZE(szClass);
  76. DWORD dwDummy1, dwDummy2, dwDummy3, dwDummy4, dwDummy5, dwDummy6;
  77. FILETIME ft;
  78. // Open the subkey so we can enumerate any children
  79. lResult = RegOpenKeyExA(hKey, lpSubKey, 0, KEY_ALL_ACCESS, &hkSubKey);
  80. if (ERROR_SUCCESS == lResult)
  81. {
  82. // I can't just call RegEnumKey with an ever-increasing index, because
  83. // I'm deleting the subkeys as I go, which alters the indices of the
  84. // remaining subkeys in an implementation-dependent way. In order to
  85. // be safe, I have to count backwards while deleting the subkeys.
  86. // Find out how many subkeys there are
  87. lResult = RegQueryInfoKey(hkSubKey,
  88. szClass,
  89. &cbClass,
  90. NULL,
  91. &dwIndex, // The # of subkeys -- all we need
  92. &dwDummy1,
  93. &dwDummy2,
  94. &dwDummy3,
  95. &dwDummy4,
  96. &dwDummy5,
  97. &dwDummy6,
  98. &ft);
  99. if (ERROR_SUCCESS == lResult)
  100. {
  101. // dwIndex is now the count of subkeys, but it needs to be
  102. // zero-based for RegEnumKey, so I'll pre-decrement, rather
  103. // than post-decrement.
  104. while (ERROR_SUCCESS == RegEnumKey(hkSubKey, --dwIndex, szSubKeyName, cchSubKeyName))
  105. {
  106. ShRegDeleteKey(hkSubKey, szSubKeyName);
  107. }
  108. }
  109. // APPCOMPAT
  110. // Issue with shellprv. For some reason someone commented out the definition of SHRegCloseKey
  111. // SHRegCloseKey is not in Win95. Doing an undef here puts it back to RegCloseKey
  112. // Works now on both NT and Win95
  113. //
  114. #undef RegCloseKey
  115. RegCloseKey(hkSubKey);
  116. lResult = RegDeleteKey(hKey, lpSubKey);
  117. }
  118. return lResult;
  119. }
  120. LONG lRegDeleteKeyA(HKEY hKey, LPCSTR lpSubKey)
  121. {
  122. if (RUNNING_NT)
  123. return(ShRegDeleteKey(hKey, lpSubKey));
  124. else
  125. return(RegDeleteKey(hKey, lpSubKey));
  126. }
  127. // in:
  128. // pszPath directory to do this into or full dest path
  129. // if pszShort is NULL
  130. // pszShort file name (short version) if NULL assumes
  131. // pszPath is both path and spec
  132. // pszFileSpec file name (long version)
  133. //
  134. // out:
  135. // pszUniqueName
  136. //
  137. // returns:
  138. // TRUE success, name can be used
  139. BOOL lPathYetAnotherMakeUniqueNameA(LPSTR pszUniqueName,
  140. LPCSTR pszPath,
  141. LPCSTR pszShort,
  142. LPCSTR pszFileSpec)
  143. {
  144. if (RUNNING_NT)
  145. {
  146. LPSTR lpPath,lpShort,lpFileSpec;
  147. WCHAR tmpBuf[MAX_PATH];
  148. WCHAR tmpPath[MAX_PATH];
  149. WCHAR tmpShort[MAX_PATH];
  150. WCHAR tmpFileSpec[MAX_PATH];
  151. BOOL retVal;
  152. if((lpPath = (LPSTR)pszPath)!= NULL)
  153. {
  154. lpPath = (LPSTR)tmpPath;
  155. MultiByteToWideChar(CP_ACP, 0, pszPath, -1, (LPWSTR)lpPath,
  156. ARRAYSIZE(tmpPath));
  157. }
  158. if((lpShort = (LPSTR)pszShort)!= NULL)
  159. {
  160. lpShort = (LPSTR)tmpShort;
  161. MultiByteToWideChar(CP_ACP, 0, pszShort, -1, (LPWSTR)lpShort,
  162. ARRAYSIZE(tmpShort));
  163. }
  164. if((lpFileSpec = (LPSTR)pszFileSpec)!= NULL)
  165. {
  166. lpFileSpec = (LPSTR)tmpFileSpec;
  167. MultiByteToWideChar(CP_ACP, 0, pszFileSpec, -1, (LPWSTR)lpFileSpec,
  168. ARRAYSIZE(tmpFileSpec));
  169. }
  170. MultiByteToWideChar(CP_ACP, 0, pszUniqueName, -1, tmpBuf,
  171. ARRAYSIZE(tmpBuf));
  172. retVal = PathYetAnotherMakeUniqueName(tmpBuf, (LPWSTR)lpPath,
  173. (LPWSTR)lpShort, (LPWSTR)lpFileSpec); // (LPWSTR) so it builds, but works downlevel
  174. if(retVal)
  175. WideCharToMultiByte(CP_ACP, 0, tmpBuf, -1,
  176. pszUniqueName, ARRAYSIZE(tmpBuf),
  177. NULL, NULL);
  178. return(retVal);
  179. }
  180. else
  181. return(PathYetAnotherMakeUniqueName((LPWSTR)pszUniqueName, (LPWSTR)pszPath,
  182. (LPWSTR)pszShort, (LPWSTR)pszFileSpec)); // (LPWSTR) so it builds, but works downlevel
  183. }
  184. ////////////////////////////////////////////////////////////////
  185. //
  186. // in:
  187. // pszIconPath file to get icon from (eg. cabinet.exe)
  188. // iIconIndex icon index in pszIconPath to get
  189. // uIconFlags GIL_ values indicating simulate doc icon, etc.
  190. int lShell_GetCachedImageIndexA(LPCSTR pszIconPath, int iIconIndex, UINT uIconFlags)
  191. {
  192. if (RUNNING_NT)
  193. {
  194. WCHAR uPath[MAX_PATH];
  195. MultiByteToWideChar(CP_ACP, 0, pszIconPath, -1, uPath,
  196. ARRAYSIZE(uPath));
  197. return Shell_GetCachedImageIndex(uPath, iIconIndex, uIconFlags);
  198. }
  199. else
  200. return Shell_GetCachedImageIndex((LPWSTR)pszIconPath, iIconIndex, uIconFlags); // (LPWSTR) so it builds, but works downlevel
  201. }
  202. // determine if a path is a program by looking at the extension
  203. //
  204. BOOL lPathIsExeA(LPCSTR szFile)
  205. {
  206. if (RUNNING_NT)
  207. {
  208. WCHAR uPath[MAX_PATH];
  209. MultiByteToWideChar(CP_ACP, 0, szFile, -1, uPath,
  210. ARRAYSIZE(uPath));
  211. return (PathIsExe(uPath));
  212. }
  213. else
  214. return PathIsExe((LPWSTR)szFile); // (LPWSTR) so it builds, but works downlevel
  215. }
  216. /*
  217. * BUILDBUILD: Replacements for shell32.dll critical section functions for
  218. * shell32.dll!hash.c.
  219. */
  220. void Shell_EnterCriticalSection(void)
  221. {
  222. BeginExclusiveAccess();
  223. return;
  224. }
  225. void Shell_LeaveCriticalSection(void)
  226. {
  227. EndExclusiveAccess();
  228. return;
  229. }
  230. #define DATA_SEG_READ_ONLY ".text"
  231. #pragma data_seg(DATA_SEG_READ_ONLY)
  232. /*
  233. * They meant to use const char arrays here, rather than char
  234. * const arrays. Arrays are implicitly const. But this is how these array are
  235. * declared in shell32.dll!cstrings.h.
  236. */
  237. char const c_szPercentOne[] = "%1";
  238. char const c_szPercentl[] = "%l";
  239. char const c_szPercentL[] = "%L";
  240. char const c_szRunDll[] = "rundll32.exe";
  241. char const c_szShellOpenCmd[] = "shell\\open\\command";
  242. char const c_szShellOpenDDEExec[] = "shell\\open\\ddeexec";
  243. char const c_szSlashCommand[] = "\\command";
  244. char const c_szSlashDDEExec[] = "\\ddeexec";
  245. char const c_szStar[] = "*";
  246. #pragma data_seg()
  247. char g_szFileTypeName[32] = " "; // First char is blank such that can append...
  248. /* BUILDBUILD: LVUtil_GetLParam() swiped from shell32.dll!lvutil.c. */
  249. //
  250. // Note that it returns NULL, if iItem is -1.
  251. //
  252. LPARAM PASCAL LVUtil_GetLParam(HWND hwndLV, int i)
  253. {
  254. LV_ITEM item;
  255. item.mask = LVIF_PARAM;
  256. item.iItem = i;
  257. item.iSubItem = 0;
  258. item.lParam = 0;
  259. if (i != -1)
  260. {
  261. ListView_GetItem(hwndLV, &item);
  262. }
  263. return item.lParam;
  264. }
  265. /* BUILDBUILD: App_IsLFNAware() swiped from shell32.dll!shlexec.c. */
  266. //----------------------------------------------------------------------------
  267. #define PEMAGIC ((WORD)'P'+((WORD)'E'<<8))
  268. #if 0
  269. /* BUILDBUILD: NEMAGIC is defined in newexe.h, #included for GetExeType(). */
  270. #define NEMAGIC ((WORD)'N'+((WORD)'E'<<8))
  271. #endif
  272. //----------------------------------------------------------------------------
  273. // Returns TRUE is app is LFN aware.
  274. // NB This simply assumes all Win4.0 and all Win32 apps are LFN aware.
  275. BOOL App_IsLFNAware(LPCSTR pszFile)
  276. {
  277. DWORD dw;
  278. ASSERT(pszFile);
  279. ASSERT(*pszFile);
  280. // Assume Win 4.0 apps and Win32 apps are LFN aware.
  281. dw = GetExeType(pszFile);
  282. // DebugMsg(DM_TRACE, "s.aila: %s %s %x", lpszFile, szFile, dw);
  283. if ((LOWORD(dw) == PEMAGIC) || ((LOWORD(dw) == NEMAGIC) && (HIWORD(dw) >= 0x0400)))
  284. {
  285. return TRUE;
  286. }
  287. else
  288. {
  289. return FALSE;
  290. }
  291. }
  292. /* BUILDBUILD: SendMessageD() swiped from shell32.dll!init.c. */
  293. #ifdef DEBUG
  294. LRESULT
  295. WINAPI
  296. SendMessageD(
  297. HWND hWnd,
  298. UINT Msg,
  299. WPARAM wParam,
  300. LPARAM lParam)
  301. {
  302. ASSERTNONCRITICAL;
  303. return SendMessageA(hWnd, Msg, wParam, lParam);
  304. }
  305. #endif // DEBUG
  306. /* BUILDBUILD: HasExtension() swiped from shell32.dll!extract.c. */
  307. DWORD HasExtension(LPCSTR pszPath)
  308. {
  309. LPCSTR p = PathFindExtension(pszPath);
  310. if (*p == '.')
  311. return *((UNALIGNED DWORD *)p) | 0x20202000; // make lower case
  312. else
  313. return 0;
  314. }
  315. /* BUILDBUILD: GetExeType() swiped from shell32.dll!extract.c. */
  316. /****************************************************************************
  317. * GetExeType - get the EXE type of the passed file (DOS, Win16, Win32)
  318. *
  319. * returns:
  320. * 0 = not a exe of any type.
  321. *
  322. * if a windows app
  323. * LOWORD = NE or PE
  324. * HIWORD = windows version 3.0, 3.5, 4.0
  325. *
  326. * if a DOS app (or a .com or batch file)
  327. * LOWORD = MZ
  328. * HIWORD = 0
  329. *
  330. * if a Win32 console app
  331. * LOWORD = PE
  332. * HIWORD = 0
  333. *
  334. * APPCOMPAT this is so similar to the Win32 API GetBinaryType() too bad Win95
  335. * kernel does not support it.
  336. *
  337. ****************************************************************************/
  338. DWORD WINAPI GetExeType(LPCSTR szFile)
  339. {
  340. HANDLE fh;
  341. DWORD dw;
  342. struct exe_hdr exehdr;
  343. struct new_exe newexe;
  344. FILETIME ftAccess;
  345. DWORD dwRead;
  346. //
  347. // check for special extensions, and fail quick
  348. //
  349. switch (HasExtension(szFile))
  350. {
  351. case COM_FILE:
  352. case BAT_FILE:
  353. return MAKELONG(MZMAGIC, 0); // DOS exe
  354. case EXE_FILE: // we need to open it.
  355. break;
  356. default:
  357. return 0; // not a exe, or if it is we dont care
  358. }
  359. newexe.ne_expver = 0;
  360. fh = CreateFile(szFile, GENERIC_READ | FILE_WRITE_ATTRIBUTES,
  361. FILE_SHARE_READ | FILE_SHARE_WRITE,
  362. 0, OPEN_EXISTING, 0, 0);
  363. if (fh == INVALID_HANDLE_VALUE)
  364. {
  365. return 0;
  366. }
  367. // preserve the access time
  368. if (GetFileTime(fh, NULL, &ftAccess, NULL))
  369. SetFileTime(fh, NULL, &ftAccess, NULL);
  370. if (!ReadFile(fh, &exehdr, sizeof(exehdr), &dwRead, NULL) ||
  371. (dwRead != sizeof(exehdr)))
  372. goto error;
  373. if (exehdr.e_magic != EMAGIC)
  374. goto error;
  375. SetFilePointer(fh, exehdr.e_lfanew, NULL, FILE_BEGIN);
  376. ReadFile(fh,&newexe, sizeof(newexe), &dwRead, NULL);
  377. if (newexe.ne_magic == PEMAGIC)
  378. {
  379. // read the SubsystemVersion
  380. SetFilePointer(fh, exehdr.e_lfanew+18*4, NULL, FILE_BEGIN);
  381. ReadFile(fh,&dw,4, &dwRead, NULL);
  382. newexe.ne_expver = LOBYTE(LOWORD(dw)) << 8 | LOBYTE(HIWORD(dw));
  383. // read the Subsystem
  384. SetFilePointer(fh, exehdr.e_lfanew+23*4, NULL, FILE_BEGIN);
  385. ReadFile(fh,&dw,4, &dwRead, NULL);
  386. // if it is not a Win32 GUI app return a version of 0
  387. if (LOWORD(dw) != 2) // IMAGE_SUBSYSTEM_WINDOWS_GUI
  388. newexe.ne_expver = 0;
  389. goto exit;
  390. }
  391. else if (newexe.ne_magic == LEMAGIC)
  392. {
  393. newexe.ne_magic = MZMAGIC; // just a DOS exe
  394. newexe.ne_expver = 0;
  395. }
  396. else if (newexe.ne_magic == NEMAGIC)
  397. {
  398. //
  399. // we found a 'NE' it still might not be a windows
  400. // app, it could be.....
  401. //
  402. // a OS/2 app ne_exetyp==NE_OS2
  403. // a DOS4 app ne_exetyp==NE_DOS4
  404. // a VxD ne_exetyp==DEV386
  405. //
  406. // only treat it as a Windows app if the exetype
  407. // is NE_WINDOWS or NE_UNKNOWN
  408. //
  409. if (newexe.ne_exetyp != NE_WINDOWS && newexe.ne_exetyp != NE_UNKNOWN)
  410. {
  411. newexe.ne_magic = MZMAGIC; // just a DOS exe
  412. newexe.ne_expver = 0;
  413. }
  414. //
  415. // if could also have a bogus expected windows version
  416. // (treat 0 as invalid)
  417. //
  418. if (newexe.ne_expver == 0)
  419. {
  420. newexe.ne_magic = MZMAGIC; // just a DOS exe
  421. newexe.ne_expver = 0;
  422. }
  423. }
  424. else // if (newexe.ne_magic != NEMAGIC)
  425. {
  426. newexe.ne_magic = MZMAGIC; // just a DOS exe
  427. newexe.ne_expver = 0;
  428. }
  429. exit:
  430. CloseHandle(fh);
  431. return MAKELONG(newexe.ne_magic, newexe.ne_expver);
  432. error:
  433. CloseHandle(fh);
  434. return 0;
  435. }
  436. /******************************************************************************
  437. Original Shell32.dll code starts here.
  438. ******************************************************************************/
  439. #if 0
  440. /* BUILDBUILD: Remove old headers. */
  441. #include "..\..\inc\help.h"
  442. #include "views.h"
  443. #include "ids.h"
  444. #include "lvutil.h"
  445. #endif
  446. // REARCHITECT: duplicate strings as in cstrings.c
  447. #pragma data_seg(".text", "CODE")
  448. char const c_szSSlashS[] = "%s\\%s";
  449. #pragma data_seg()
  450. extern char g_szFileTypeName[]; // used to build type name...
  451. extern BOOL App_IsLFNAware(LPCSTR pszFile);
  452. void _GenerateAssociateNotify(LPSTR pszExt)
  453. {
  454. char szFakePath[MAX_PATH];
  455. LPITEMIDLIST pidl;
  456. //
  457. // This is a real hack, but for now we generate an idlist that looks
  458. // something like: C:\*.ext which is the extension for the IDList.
  459. // We use the simple IDList as to not hit the disk...
  460. //
  461. // All I do is make an ANSI string, and then jam the unicode
  462. // version into the skinny-char buffer. Saves on stack.
  463. if (RUNNING_NT)
  464. {
  465. char tmpBuf[20];
  466. lstrcpy(tmpBuf, "c:\\");
  467. lstrcat(tmpBuf, c_szStar);
  468. lstrcat(tmpBuf, pszExt);
  469. MultiByteToWideChar(CP_ACP, 0, tmpBuf, -1, (LPWSTR)szFakePath,
  470. sizeof(szFakePath)/sizeof(WCHAR));
  471. }
  472. else
  473. {
  474. PathBuildRoot(szFakePath, 2); // (c:\)
  475. lstrcat(szFakePath, c_szStar);
  476. lstrcat(szFakePath, pszExt);
  477. }
  478. pidl = SHSimpleIDListFromPath((LPWSTR)szFakePath); // (LPWSTR) so it builds, but works downlevel
  479. // Now call off to the notify function.
  480. SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, pidl, NULL);
  481. ILFree(pidl);
  482. }
  483. // Given a class key returns the shell\open\command string in szValue
  484. // and the number of chars copied in cbMaxValue. cbMaxValue should
  485. // be initialised to the max siz eof szValue.
  486. void GetCmdLine(LPCSTR szKey, LPSTR szValue, LONG cbValue)
  487. {
  488. char szTemp[MAX_PATH+40]; // Leave room for both extension plus junk on at end...
  489. wsprintf(szTemp, c_szSSlashS, szKey, c_szShellOpenCmd);
  490. szValue[0] = 0;
  491. RegQueryValue(HKEY_CLASSES_ROOT, szTemp, szValue, &cbValue);
  492. }
  493. // uFlags GCD_ flags from GetClassDescription uFlags
  494. void FillListWithClasses(HWND hwnd, BOOL fComboBox, UINT uFlags)
  495. {
  496. int i;
  497. char szClass[CCH_KEYMAX];
  498. char szDisplayName[CCH_KEYMAX];
  499. LONG lcb;
  500. SendMessage(hwnd, fComboBox ? CB_RESETCONTENT : LB_RESETCONTENT, 0, 0L);
  501. if (uFlags & GCD_MUSTHAVEEXTASSOC)
  502. {
  503. char szExt[CCH_KEYMAX];
  504. // The caller stated that they only want those classes that
  505. // have have at least one extension associated with it.
  506. //
  507. for (i = 0; RegEnumKey(HKEY_CLASSES_ROOT, i, szClass, sizeof(szClass)) == ERROR_SUCCESS; i++)
  508. {
  509. // Is this an extension
  510. if (szClass[0] != '.')
  511. continue; // go process the next one...
  512. // Get the class name
  513. lstrcpy(szExt, szClass);
  514. lcb = sizeof(szClass);
  515. if ((RegQueryValue(HKEY_CLASSES_ROOT, szExt, szClass, &lcb) != ERROR_SUCCESS) || (lcb == 0))
  516. continue; // Again we are not interested.
  517. // use uFlags passed in to filter
  518. if (GetClassDescription(HKEY_CLASSES_ROOT, szClass, szDisplayName, sizeof(szDisplayName), uFlags))
  519. {
  520. int iItem;
  521. // Now make sure it is not already in the list...
  522. if ((int)SendMessage(hwnd, fComboBox ? CB_FINDSTRINGEXACT : LB_FINDSTRINGEXACT,
  523. (WPARAM)-1, (LPARAM)(LPSTR)szDisplayName) >= 0)
  524. continue; // allready in the list.
  525. // sorted
  526. iItem = (int)SendMessage(hwnd, fComboBox ? CB_ADDSTRING : LB_ADDSTRING,
  527. 0, (LPARAM)(LPSTR)szDisplayName);
  528. if (iItem >= 0)
  529. SendMessage(hwnd, fComboBox ? CB_SETITEMDATA : LB_SETITEMDATA, iItem, (LPARAM)AddHashItem(NULL, szClass));
  530. }
  531. }
  532. }
  533. else
  534. {
  535. for (i = 0; RegEnumKey(HKEY_CLASSES_ROOT, i, szClass, sizeof(szClass)) == ERROR_SUCCESS; i++)
  536. {
  537. // use uFlags passed in to filter
  538. if (GetClassDescription(HKEY_CLASSES_ROOT, szClass, szDisplayName, sizeof(szDisplayName), uFlags))
  539. {
  540. // sorted
  541. int iItem = (int)SendMessage(hwnd, fComboBox ? CB_ADDSTRING : LB_ADDSTRING,
  542. 0, (LPARAM)(LPSTR)szDisplayName);
  543. if (iItem >= 0)
  544. SendMessage(hwnd, fComboBox ? CB_SETITEMDATA : LB_SETITEMDATA, iItem, (LPARAM)AddHashItem(NULL, szClass));
  545. }
  546. }
  547. }
  548. }
  549. // get the displayable name for file types "classes"
  550. //
  551. //
  552. // uFlags:
  553. // GCD_MUSTHAVEOPENCMD only returns things with open verbs
  554. // GCD_ADDEXETODISPNAME append the name of the ext that is in the open cmd
  555. // (GCD_MUSTHAVEOPENCMD)
  556. // GCD_ALLOWPSUDEOCLASSES return psudeo classes, those with stuff haning
  557. // off the .ext key
  558. BOOL GetClassDescription(HKEY hkClasses, LPCSTR pszClass, LPSTR szDisplayName, int cbDisplayName, UINT uFlags)
  559. {
  560. char szExe[MAX_PATH];
  561. char szClass[CCH_KEYMAX];
  562. LPSTR pszExeFile;
  563. LONG lcb;
  564. // Skip things that aren't classes (extensions).
  565. if (pszClass[0] == '.')
  566. {
  567. if (uFlags & GCD_ALLOWPSUDEOCLASSES)
  568. {
  569. lcb = sizeof(szClass);
  570. if ((RegQueryValue(hkClasses, pszClass, szClass, &lcb) != ERROR_SUCCESS) || (lcb == 0))
  571. {
  572. // look for .ext\shel\open\command directly (hard wired association)
  573. // if this extenstion does not name a real class
  574. GetCmdLine(pszClass, szExe, sizeof(szExe));
  575. if (szExe[0]) {
  576. lstrcpyn(szDisplayName, PathFindFileName(szExe), cbDisplayName);
  577. return TRUE;
  578. }
  579. return FALSE;
  580. }
  581. pszClass = szClass;
  582. }
  583. else
  584. {
  585. return FALSE; // don't return psudeo class
  586. }
  587. }
  588. // REVIEW: we should really special case the OLE junk here. if pszClass is
  589. // CLSID, Interface, TypeLib, etc we should skip it
  590. // REVIEW: we really need to verify that some extension points at this type to verfy
  591. // that it is valid. perhaps the existance of a "shell" key is enough.
  592. // get the classes displayable name
  593. lcb = cbDisplayName;
  594. if (RegQueryValue(hkClasses, pszClass, szDisplayName, &lcb) != ERROR_SUCCESS || (lcb < 2))
  595. return FALSE;
  596. if (uFlags & GCD_MUSTHAVEOPENCMD)
  597. {
  598. // verify that it has an open command
  599. GetCmdLine(pszClass, szExe, sizeof(szExe));
  600. if (!szExe[0])
  601. return FALSE;
  602. // WARNING: currently this is dead functionallity
  603. if (uFlags & GCD_ADDEXETODISPNAME)
  604. {
  605. PathRemoveArgs(szExe);
  606. // eliminate per instance type things (programs, pif, etc)
  607. // Skip things that aren't relevant ot the shell.
  608. if (szExe[0] == '%')
  609. return FALSE;
  610. // skip things with per-instance type associations
  611. pszExeFile = PathFindFileName(szExe);
  612. if (lstrlen(szDisplayName) + lstrlen(pszExeFile) + 2 < cbDisplayName)
  613. {
  614. #pragma data_seg(".text", "CODE")
  615. wsprintf(szDisplayName + lstrlen(szDisplayName), " (%s)", pszExeFile);
  616. #pragma data_seg()
  617. }
  618. }
  619. }
  620. return TRUE;
  621. }
  622. void DeleteListAttoms(HWND hwnd, BOOL fComboBox)
  623. {
  624. int cItems;
  625. PHASHITEM phiClass;
  626. int iGetDataMsg;
  627. iGetDataMsg = fComboBox ? CB_GETITEMDATA : LB_GETITEMDATA;
  628. cItems = (int)SendMessage(hwnd, fComboBox ? CB_GETCOUNT : LB_GETCOUNT, 0, 0) - 1;
  629. /* clean out them atoms except for "(none)".
  630. */
  631. for (; cItems >= 0; cItems--)
  632. {
  633. phiClass = (PHASHITEM)SendMessage(hwnd, iGetDataMsg, cItems, 0L);
  634. if (phiClass != (PHASHITEM)LB_ERR && phiClass)
  635. DeleteHashItem(NULL, phiClass);
  636. }
  637. }
  638. // BEGIN new stuff
  639. typedef struct { // oad
  640. // params
  641. HWND hwnd;
  642. POPENASINFO poainfo;
  643. // local data
  644. int idDlg;
  645. HWND hDlg;
  646. HWND hwndList;
  647. LPSTR lpszExt;
  648. LPCSTR lpcszClass;
  649. HRESULT hr;
  650. char szTypeName[CCH_KEYMAX]; // type name
  651. char szDescription[CCH_KEYMAX]; // type description
  652. } OPENAS_DATA, *POPENAS_DATA;
  653. typedef struct {
  654. UINT bHasQuote; // Did we find a quote around param? "%1"
  655. char szApp[MAX_PATH+2]; // May need room for quotes
  656. } APPINFO;
  657. #define HASQUOTE_NO 0
  658. #define HASQUOTE_MAYBE 1
  659. #define HASQUOTE_YES 3
  660. BOOL QuotesAroundArg(PCSTR pcszCmdLine)
  661. {
  662. BOOL bQuotes = FALSE;
  663. PCSTR pcsz;
  664. /* Is there a %1, %l, or %L on the command line? */
  665. if ((pcsz = StrStr(pcszCmdLine, c_szPercentOne)) != NULL ||
  666. (pcsz = StrStr(pcszCmdLine, c_szPercentl)) != NULL ||
  667. (pcsz = StrStr(pcszCmdLine, c_szPercentL)) != NULL)
  668. {
  669. /* Yes. Is it preceded by double quotes? */
  670. if (*(pcsz - 1) == '"')
  671. /* Yes. */
  672. bQuotes = TRUE;
  673. }
  674. return(bQuotes);
  675. }
  676. void FillListWithApps(HWND hwndList)
  677. {
  678. int i, iMax;
  679. char szClass[CCH_KEYMAX];
  680. char szKey[CCH_KEYMAX];
  681. char szValue[MAX_PATH];
  682. APPINFO *paiLast;
  683. LV_ITEM item;
  684. int iLast;
  685. BOOL fLastExists = FALSE;
  686. for (i = 0; RegEnumKey(HKEY_CLASSES_ROOT, i, szClass, sizeof(szClass)) == ERROR_SUCCESS; i++)
  687. {
  688. LONG lTmp;
  689. wsprintf(szKey, c_szSSlashS, szClass, c_szShellOpenCmd);
  690. lTmp = sizeof(szValue);
  691. if (RegQueryValue(HKEY_CLASSES_ROOT, szKey, szValue, &lTmp) == ERROR_SUCCESS)
  692. {
  693. // filter out stuff we know is bogus
  694. // strings that start with: %1, "%1"
  695. // strings that contain: rundll
  696. //
  697. if ((szValue[0] != '%') &&
  698. ((szValue[0] != '"') || (szValue[1] != '%')) &&
  699. (StrStr(szValue, c_szRunDll) == NULL))
  700. {
  701. APPINFO *pai = (APPINFO *)LocalAlloc(LPTR, sizeof(APPINFO));
  702. if (pai)
  703. {
  704. if (QuotesAroundArg(szValue))
  705. pai->bHasQuote = HASQUOTE_YES;
  706. else
  707. {
  708. char szDDEExecValue[MAX_PATH];
  709. wsprintf(szKey, c_szSSlashS, szClass,
  710. c_szShellOpenDDEExec);
  711. lTmp = sizeof(szDDEExecValue);
  712. if (RegQueryValue(HKEY_CLASSES_ROOT, szKey,
  713. szDDEExecValue, &lTmp)
  714. == ERROR_SUCCESS)
  715. {
  716. if (QuotesAroundArg(szDDEExecValue))
  717. pai->bHasQuote = HASQUOTE_YES;
  718. }
  719. }
  720. PathRemoveArgs(szValue);
  721. lstrcpy(pai->szApp, szValue);
  722. item.mask = LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM;
  723. item.iItem = 0x7FFF;
  724. item.iSubItem = 0;
  725. item.state = 0;
  726. item.iImage = I_IMAGECALLBACK;
  727. PathRemoveExtension(szValue);
  728. item.pszText = PathFindFileName(szValue);
  729. item.lParam = (LPARAM)pai;
  730. ListView_InsertItem(hwndList, &item);
  731. }
  732. }
  733. }
  734. }
  735. // punt dups
  736. ListView_SortItems(hwndList, NULL, 0);
  737. paiLast = NULL;
  738. // szKey will hold the lpszLast's display name
  739. for (i = 0, iMax = ListView_GetItemCount(hwndList); i < iMax; i++)
  740. {
  741. APPINFO *pai;
  742. item.mask = LVIF_TEXT | LVIF_PARAM;
  743. item.iItem = i;
  744. item.iSubItem = 0;
  745. item.pszText = szValue;
  746. item.cchTextMax = sizeof(szValue);
  747. // get the text string
  748. ListView_GetItem(hwndList, &item);
  749. pai = (APPINFO *)item.lParam;
  750. if (paiLast && (!lstrcmpi(szKey, szValue))) {
  751. int iDelete = i;
  752. // if they are different in path, delete the one that doesn't exit (or the new one if they both do)
  753. if (lstrcmpi(paiLast->szApp, pai->szApp)) {
  754. if (!fLastExists && !(fLastExists = PathFileExists(pai->szApp))) {
  755. if (paiLast->bHasQuote > pai->bHasQuote)
  756. pai->bHasQuote = paiLast->bHasQuote;
  757. iDelete = iLast;
  758. }
  759. }
  760. // Will assume that if either item has quote set that it will work...
  761. if (pai->bHasQuote > paiLast->bHasQuote)
  762. paiLast->bHasQuote =pai->bHasQuote;
  763. ListView_DeleteItem(hwndList, iDelete);
  764. i--; iMax--;
  765. // we deleted the iLast, we need to set a new iLast
  766. if (iDelete == iLast)
  767. goto NewLastExe;
  768. } else {
  769. NewLastExe:
  770. iLast = i;
  771. paiLast = pai;
  772. lstrcpy(szKey, szValue);
  773. fLastExists = TRUE;
  774. }
  775. }
  776. // Lets set the focus to first item, but not the focus as some users
  777. // have made the mistake and type in the name and hit return and it
  778. // runs the first guy in the list which in the current cases tries to
  779. // run the backup app...
  780. ListView_SetItemState(hwndList, 0, LVNI_FOCUSED, LVNI_FOCUSED | LVNI_SELECTED);
  781. SetFocus(hwndList);
  782. }
  783. void _InitOpenAsDlg(POPENAS_DATA poad)
  784. {
  785. char szFormat[200];
  786. char szFileName[MAX_PATH];
  787. char szTemp[MAX_PATH + sizeof(szFormat)];
  788. BOOL fDisableAssociate;
  789. HIMAGELIST himlLarge = NULL;
  790. HIMAGELIST himlSmall = NULL;
  791. LV_COLUMN col = {LVCF_FMT | LVCF_WIDTH, LVCFMT_LEFT};
  792. RECT rc;
  793. // Don't let the file name go beyond the width of one line...
  794. GetDlgItemText(poad->hDlg, IDD_TEXT, szFormat, sizeof(szFormat));
  795. lstrcpy(szFileName, PathFindFileName(poad->poainfo->pcszFile));
  796. GetClientRect(GetDlgItem(poad->hDlg, IDD_TEXT), &rc);
  797. PathCompactPath(NULL, szFileName, rc.right - 4 * GetSystemMetrics(SM_CXBORDER));
  798. wsprintf(szTemp, szFormat, szFileName);
  799. SetDlgItemText(poad->hDlg, IDD_TEXT, szTemp);
  800. // Don't allow associations to be made for things we consider exes...
  801. fDisableAssociate = (! (poad->poainfo->dwInFlags & OPENASINFO_FL_ALLOW_REGISTRATION) ||
  802. lPathIsExeA(poad->poainfo->pcszFile));
  803. if (poad->idDlg == DLG_OPENAS_NOTYPE) {
  804. GetDlgItemText(poad->hDlg, IDD_DESCRIPTIONTEXT, szFormat, sizeof(szFormat));
  805. wsprintf(szTemp, szFormat, poad->lpcszClass);
  806. SetDlgItemText(poad->hDlg, IDD_DESCRIPTIONTEXT, szTemp);
  807. // Default to Set the association here if we do not know what
  808. // the file is...
  809. if (!fDisableAssociate)
  810. CheckDlgButton(poad->hDlg, IDD_MAKEASSOC, TRUE);
  811. }
  812. if (fDisableAssociate)
  813. EnableWindow(GetDlgItem(poad->hDlg, IDD_MAKEASSOC), FALSE);
  814. poad->hwndList = GetDlgItem(poad->hDlg, IDD_APPLIST);
  815. Shell_GetImageLists(&himlLarge, &himlSmall);
  816. if(himlLarge != NULL)
  817. ListView_SetImageList(poad->hwndList, himlLarge, LVSIL_NORMAL);
  818. if(himlSmall != NULL)
  819. ListView_SetImageList(poad->hwndList, himlSmall, LVSIL_SMALL);
  820. SetWindowLong(poad->hwndList, GWL_EXSTYLE,
  821. GetWindowLong(poad->hwndList, GWL_EXSTYLE) | WS_EX_CLIENTEDGE);
  822. GetClientRect(poad->hwndList, &rc);
  823. col.cx = rc.right - GetSystemMetrics(SM_CXVSCROLL)
  824. - 4 * GetSystemMetrics(SM_CXEDGE);
  825. ListView_InsertColumn(poad->hwndList, 0, &col);
  826. FillListWithApps(poad->hwndList);
  827. // and initialize the OK button
  828. EnableWindow(GetDlgItem(poad->hDlg, IDOK),
  829. (ListView_GetNextItem(poad->hwndList, -1, LVNI_SELECTED) != -1));
  830. }
  831. void RunAs(POPENAS_DATA poad)
  832. {
  833. SHELLEXECUTEINFO ExecInfo;
  834. // If this run created a new type we should use it, otherwise we should
  835. // construct a command using the exe that we selected...
  836. if (*poad->lpszExt && IsDlgButtonChecked(poad->hDlg, IDD_MAKEASSOC))
  837. {
  838. FillExecInfo(ExecInfo, poad->hwnd, NULL, poad->poainfo->pcszFile, NULL, NULL, SW_NORMAL);
  839. }
  840. else
  841. {
  842. char szApp[MAX_PATH];
  843. char szQuotedFile[MAX_PATH+2];
  844. APPINFO *pai;
  845. int iItemFocus = ListView_GetNextItem(poad->hwndList, -1, LVNI_SELECTED);
  846. pai = (APPINFO *)LVUtil_GetLParam(poad->hwndList, iItemFocus);
  847. lstrcpy(szQuotedFile, poad->poainfo->pcszFile);
  848. lstrcpy(szApp, pai->szApp);
  849. PathUnquoteSpaces(szApp);
  850. // Try to intellegently quote blanks or not...
  851. if (!App_IsLFNAware(szApp))
  852. {
  853. // We better also make sure that this a short path name
  854. // pass off to the application...
  855. char tmpBuf[MAX_PATH];
  856. GetShortPathName(szQuotedFile, tmpBuf, SIZECHARS(tmpBuf));
  857. lstrcpy(szQuotedFile, tmpBuf);
  858. }
  859. else
  860. {
  861. // Either maybe or yes is we should quote
  862. if (pai->bHasQuote)
  863. PathQuoteSpaces(szQuotedFile);
  864. }
  865. FillExecInfo(ExecInfo, poad->hwnd, NULL, szApp, szQuotedFile, NULL, SW_NORMAL);
  866. }
  867. ShellExecuteEx(&ExecInfo);
  868. }
  869. void OpenAsOther(POPENAS_DATA poad)
  870. {
  871. char szText[MAX_PATH];
  872. BOOL retval;
  873. #if 0
  874. /*
  875. * BUILDBUILD: There is no IDD_COMMAND control in DLG_OPENAS or
  876. * DLG_OPENAS_NOTYPE.
  877. */
  878. GetDlgItemText(poad->hDlg, IDD_COMMAND, szText, sizeof(szText));
  879. #else
  880. *szText = '\0\0';
  881. #endif
  882. // now it will work on NT: unicode
  883. // do a file open browse
  884. if (RUNNING_NT)
  885. {
  886. WCHAR szuPath[MAX_PATH];
  887. WCHAR szuExe[16];
  888. WCHAR szuFilters[MAX_PATH];
  889. WCHAR szuTitle[80];
  890. LPWSTR psz;
  891. szuPath[0] = szuTitle[0] = szuExe[0] = szuFilters[0]= 0;
  892. MLLoadStringW(IDS_OPENAS, szuTitle, 80);
  893. MLLoadStringW(IDS_EXE, szuExe, 16);
  894. MLLoadStringW(IDS_PROGRAMSFILTER, szuFilters, MAX_PATH);
  895. /* hack up the array... */
  896. psz = szuFilters;
  897. while (*psz)
  898. {
  899. if (*psz == (WCHAR)('#'))
  900. *psz = (WCHAR)('\0');
  901. psz++;
  902. }
  903. retval = GetFileNameFromBrowse(poad->hDlg, szuPath,
  904. ARRAYSIZE(szuPath), NULL, szuExe,
  905. szuFilters, szuTitle);
  906. /* make certain we convert back to ANSI chars! */
  907. if (retval)
  908. WideCharToMultiByte(CP_ACP,0,szuPath,-1,szText,
  909. ARRAYSIZE(szuPath),NULL,NULL);
  910. }
  911. else
  912. {
  913. CHAR szExe[16];
  914. CHAR szFilters[MAX_PATH];
  915. CHAR szTitle[80];
  916. LPSTR psz;
  917. szTitle[0] = szExe[0] = szFilters[0]= 0;
  918. MLLoadStringA(IDS_OPENAS, szTitle, 80);
  919. MLLoadStringA(IDS_EXE, szExe, 16);
  920. MLLoadStringA(IDS_PROGRAMSFILTER, szFilters, MAX_PATH);
  921. /* hack up the array... */
  922. psz = szFilters;
  923. while (*psz)
  924. {
  925. if (*psz == (CHAR)('#'))
  926. *psz = (CHAR)('\0');
  927. psz++;
  928. }
  929. retval = GetFileNameFromBrowse(poad->hDlg, (LPWSTR)szText,
  930. sizeof(szText), NULL,
  931. (LPWSTR)szExe, (LPWSTR)szFilters, (LPWSTR)szTitle); // (LPWSTR) so it builds, but works downlevel
  932. }
  933. if (retval)
  934. {
  935. // then add it to the list view and select it.
  936. APPINFO *pai = (APPINFO *)LocalAlloc(LPTR, sizeof(APPINFO));
  937. if (pai)
  938. {
  939. LV_ITEM item;
  940. int i;
  941. int iItem;
  942. APPINFO *paiT;
  943. pai->bHasQuote = HASQUOTE_MAYBE;
  944. lstrcpy(pai->szApp, szText);
  945. PathQuoteSpaces(pai->szApp);
  946. item.mask = LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM;
  947. item.iItem = 0x7FFF;
  948. item.iSubItem = 0;
  949. item.state = 0;
  950. item.iImage = I_IMAGECALLBACK;
  951. PathRemoveExtension(szText);
  952. item.pszText = PathFindFileName(szText);
  953. item.lParam = (LPARAM)pai;
  954. i = ListView_InsertItem(poad->hwndList, &item);
  955. ListView_SetItemState(poad->hwndList, i, LVNI_SELECTED | LVNI_FOCUSED, LVNI_SELECTED | LVNI_FOCUSED);
  956. ListView_EnsureVisible(poad->hwndList, i, FALSE);
  957. SetFocus(poad->hwndList);
  958. // We also want to see if we find another entry in the listview for the
  959. // application. We do this such that we can see if the app supports
  960. // quotes or not.
  961. for (iItem = ListView_GetItemCount(poad->hwndList) - 1; iItem >= 0; iItem--)
  962. {
  963. if (iItem == i)
  964. continue;
  965. item.mask = LVIF_PARAM;
  966. item.iItem = iItem;
  967. item.iSubItem = 0;
  968. ListView_GetItem(poad->hwndList, &item);
  969. paiT = (APPINFO *)item.lParam;
  970. if (lstrcmpi(pai->szApp, paiT->szApp) == 0)
  971. {
  972. pai->bHasQuote = paiT->bHasQuote;
  973. break;
  974. }
  975. }
  976. }
  977. }
  978. }
  979. // return true if ok to continue
  980. BOOL OpenAsMakeAssociation(POPENAS_DATA poad)
  981. {
  982. UINT err;
  983. // See if we should make an association or not...
  984. if (!IsDlgButtonChecked(poad->hDlg, IDD_MAKEASSOC))
  985. return(TRUE);
  986. if (poad->idDlg == DLG_OPENAS_NOTYPE) {
  987. GetDlgItemText(poad->hDlg, IDD_DESCRIPTION, poad->szDescription, sizeof poad->szDescription);
  988. if (*poad->szDescription == '\0') {
  989. // Another place to make sure Ivans tests don't catch...
  990. /* BUILDBUILD: Load IDS_FILETYPENAME here. */
  991. if (lstrlen(g_szFileTypeName) <2)
  992. {
  993. MLLoadStringA(IDS_FILETYPENAME,
  994. g_szFileTypeName+1, sizeof(g_szFileTypeName)-1);
  995. }
  996. lstrcpyn(poad->szDescription, AnsiNext(poad->lpszExt),
  997. ARRAYSIZE(poad->szDescription) - lstrlen(g_szFileTypeName) -1);
  998. AnsiUpper(poad->szDescription);
  999. // Likewise we add a blank at start for appending for FOO Files..
  1000. lstrcat(poad->szDescription, g_szFileTypeName);
  1001. }
  1002. #pragma data_seg(".text", "CODE")
  1003. lstrcpyn(poad->szTypeName, poad->lpszExt+1, sizeof(poad->szTypeName)
  1004. - sizeof("_auto_file"));
  1005. lstrcat(poad->szTypeName, "_auto_file");
  1006. #pragma data_seg()
  1007. err = RegSetValueA(HKEY_CLASSES_ROOT, poad->lpszExt, REG_SZ, poad->szTypeName, 0L);
  1008. err |= RegSetValueA(HKEY_CLASSES_ROOT, poad->szTypeName, REG_SZ, poad->szDescription, 0L);
  1009. ASSERT(err == ERROR_SUCCESS);
  1010. if (err != ERROR_SUCCESS)
  1011. {
  1012. MessageBeep(MB_ICONEXCLAMATION);
  1013. return(FALSE);
  1014. }
  1015. }
  1016. if (*poad->lpszExt) {
  1017. char szTemp[MAX_PATH];
  1018. char szCommand[MAX_PATH + 10];
  1019. int iItemFocus = ListView_GetNextItem(poad->hwndList, -1, LVNI_FOCUSED);
  1020. APPINFO *pai = (APPINFO *)LVUtil_GetLParam(poad->hwndList, iItemFocus);
  1021. #pragma data_seg(".text", "CODE")
  1022. // We need to set the open commands value to empty to take care of cases
  1023. // that have something like: open=&Merge
  1024. wsprintf(szTemp, "%s\\shell\\open", poad->szTypeName);
  1025. err = RegSetValueA(HKEY_CLASSES_ROOT, szTemp, REG_SZ, c_szNULL, 0L);
  1026. lstrcat(szTemp, c_szSlashCommand);
  1027. if ((pai->bHasQuote == HASQUOTE_YES) ||
  1028. ((pai->bHasQuote == HASQUOTE_MAYBE) && App_IsLFNAware(pai->szApp)))
  1029. wsprintf(szCommand, "%s \"%%1\"", pai->szApp);
  1030. else
  1031. wsprintf(szCommand, "%s %%1", pai->szApp);
  1032. err = RegSetValueA(HKEY_CLASSES_ROOT, szTemp, REG_SZ, szCommand, 0L);
  1033. ASSERT(err == ERROR_SUCCESS);
  1034. if (err != ERROR_SUCCESS)
  1035. {
  1036. MessageBeep(MB_ICONEXCLAMATION);
  1037. return(FALSE);
  1038. }
  1039. // Need to delete any ddeexec information that might also exist...
  1040. PathRemoveFileSpec(szTemp); // Remove the command (last component)
  1041. lstrcat(szTemp, c_szSlashDDEExec);
  1042. lRegDeleteKeyA(HKEY_CLASSES_ROOT, szTemp);
  1043. #pragma data_seg()
  1044. // notify views
  1045. _GenerateAssociateNotify(poad->lpszExt);
  1046. }
  1047. return TRUE;
  1048. }
  1049. #pragma data_seg(DATASEG_READONLY)
  1050. const static DWORD aOpenAsHelpIDs[] = { // Context Help IDs
  1051. IDD_TEXT, IDH_FCAB_OPENAS_DESCRIPTION,
  1052. IDD_DESCRIPTIONTEXT, IDH_FCAB_OPENAS_DESCRIPTION,
  1053. IDD_DESCRIPTION, IDH_FCAB_OPENAS_DESCRIPTION,
  1054. IDD_APPLIST, IDH_FCAB_OPENAS_APPLIST,
  1055. IDD_MAKEASSOC, IDH_FCAB_OPENAS_MAKEASSOC,
  1056. IDD_OTHER, IDH_FCAB_OPENAS_OTHER,
  1057. 0, 0
  1058. };
  1059. #pragma data_seg()
  1060. INT_PTR CALLBACK OpenAsDlgProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam)
  1061. {
  1062. POPENAS_DATA poad = (POPENAS_DATA)GetWindowLongPtr(hDlg, DWLP_USER);
  1063. APPINFO *pai;
  1064. int iItemFocus;
  1065. switch (wMsg) {
  1066. case WM_INITDIALOG:
  1067. SetWindowLongPtr(hDlg, DWLP_USER, lParam);
  1068. poad = (POPENAS_DATA)lParam;
  1069. poad->hDlg = hDlg;
  1070. _InitOpenAsDlg(poad);
  1071. break;
  1072. case WM_HELP:
  1073. SHWinHelpOnDemandWrap((HWND)((LPHELPINFO) lParam)->hItemHandle, NULL,
  1074. HELP_WM_HELP, (DWORD_PTR)(LPSTR) aOpenAsHelpIDs);
  1075. break;
  1076. case WM_CONTEXTMENU:
  1077. if ((int)SendMessage(hDlg, WM_NCHITTEST, 0, lParam) != HTCLIENT)
  1078. return FALSE; // don't process it
  1079. SHWinHelpOnDemandWrap((HWND) wParam, NULL, HELP_CONTEXTMENU,
  1080. (DWORD_PTR)(LPVOID)aOpenAsHelpIDs);
  1081. break;
  1082. case WM_NOTIFY:
  1083. switch (((LPNMHDR)lParam)->code)
  1084. {
  1085. case LVN_GETDISPINFO:
  1086. {
  1087. #define pdi ((LV_DISPINFO *)lParam)
  1088. char szApp[MAX_PATH];
  1089. APPINFO *pai = (APPINFO *)pdi->item.lParam;
  1090. lstrcpy(szApp, pai->szApp);
  1091. PathUnquoteSpaces(szApp);
  1092. pdi->item.iImage = lShell_GetCachedImageIndexA(szApp, 0, 0);
  1093. if (pdi->item.iImage == -1)
  1094. pdi->item.iImage = II_APPLICATION;
  1095. break;
  1096. #undef pdi
  1097. }
  1098. case LVN_DELETEITEM:
  1099. LocalFree((HLOCAL)((NM_LISTVIEW *)lParam)->lParam);
  1100. break;
  1101. case LVN_ITEMCHANGED:
  1102. EnableWindow(GetDlgItem(hDlg, IDOK),
  1103. (ListView_GetNextItem(poad->hwndList, -1, LVNI_SELECTED) != -1));
  1104. break;
  1105. case NM_DBLCLK:
  1106. if (IsWindowEnabled(GetDlgItem(hDlg, IDOK)))
  1107. PostMessage(hDlg, WM_COMMAND, GET_WM_COMMAND_MPS(IDOK, hDlg, 0));
  1108. break;
  1109. }
  1110. break;
  1111. case WM_COMMAND:
  1112. ASSERT(poad);
  1113. switch (GET_WM_COMMAND_ID(wParam, lParam)) {
  1114. case IDD_OTHER:
  1115. OpenAsOther(poad);
  1116. break;
  1117. case IDOK:
  1118. /* Register association if requested. */
  1119. // The NT URL has this commented out...
  1120. if (//(poad->poainfo->dwInFlags & OPENASINFO_FL_REGISTER_EXT) &&
  1121. ! OpenAsMakeAssociation(poad))
  1122. break;
  1123. /* Copy name of associated application. */
  1124. iItemFocus = ListView_GetNextItem(poad->hwndList, -1, LVNI_SELECTED);
  1125. pai = (APPINFO *)LVUtil_GetLParam(poad->hwndList, iItemFocus);
  1126. lstrcpyn(poad->poainfo->szApp, pai->szApp, sizeof(poad->poainfo->szApp));
  1127. PathUnquoteSpaces(poad->poainfo->szApp);
  1128. /* Did we register the association? */
  1129. poad->hr = IsDlgButtonChecked(poad->hDlg, IDD_MAKEASSOC) ? S_OK : S_FALSE;
  1130. /* Exec if requested. */
  1131. if (poad->poainfo->dwInFlags & OPENASINFO_FL_EXEC)
  1132. {
  1133. RunAs(poad);
  1134. SHAddToRecentDocs(RUNNING_NT ? SHARD_PATHA : SHARD_PATH,
  1135. poad->poainfo->pcszFile);
  1136. }
  1137. EndDialog(hDlg, TRUE);
  1138. break;
  1139. case IDCANCEL:
  1140. poad->hr = E_ABORT;
  1141. EndDialog(hDlg, FALSE);
  1142. break;
  1143. }
  1144. break;
  1145. default:
  1146. return FALSE;
  1147. }
  1148. return TRUE;
  1149. }
  1150. // external API version
  1151. HRESULT MyOpenAsDialog(HWND hwnd, POPENASINFO poainfo)
  1152. {
  1153. OPENAS_DATA oad;
  1154. int idDlg;
  1155. oad.hwnd = hwnd;
  1156. oad.poainfo = poainfo;
  1157. oad.szDescription[0] = 0;
  1158. oad.szTypeName[0] = 0;
  1159. TRACE_OUT(("Enter OpenAs for %s", oad.poainfo->pcszFile));
  1160. oad.lpszExt = PathFindExtension(oad.poainfo->pcszFile);
  1161. oad.lpcszClass = poainfo->pcszClass ? poainfo->pcszClass : oad.lpszExt;
  1162. if (*oad.lpszExt) {
  1163. LONG lTmp = sizeof(oad.szTypeName);
  1164. if ((RegQueryValue(HKEY_CLASSES_ROOT, oad.lpszExt, oad.szTypeName, &lTmp) == ERROR_SUCCESS)
  1165. && (lTmp != 0) && (*oad.szTypeName)) {
  1166. idDlg = DLG_OPENAS;
  1167. } else
  1168. idDlg = DLG_OPENAS_NOTYPE;
  1169. } else {
  1170. idDlg = DLG_OPENAS;
  1171. }
  1172. oad.idDlg = idDlg;
  1173. return((DialogBoxParam(MLGetHinst(), MAKEINTRESOURCE(idDlg), hwnd,
  1174. OpenAsDlgProc, (LPARAM)(POPENAS_DATA)&oad) != -1)
  1175. ? oad.hr : E_OUTOFMEMORY);
  1176. }
  1177. #if 0
  1178. /* BUILDBUILD: Not used in url.dll. Restore if added to shell32.dll. */
  1179. void WINAPI OpenAs_RunDLL(HWND hwnd, HINSTANCE hAppInstance, LPSTR lpszCmdLine, int nCmdShow)
  1180. {
  1181. OPENASINFO oainfo;
  1182. TRACE_OUT(("OpenAs_RunDLL is called with (%s)", lpszCmdLine));
  1183. oainfo.pcszFile = lpszCmdLine;
  1184. oainfo.pcszClass = NULL;
  1185. oainfo.dwInFlags = (OPENASINFO_FL_ALLOW_REGISTRATION |
  1186. OPENASINFO_FL_REGISTER_EXT |
  1187. OPENASINFO_FL_EXEC);
  1188. MyOpenAsDialog(hwnd, &oainfo);
  1189. }
  1190. #ifdef DEBUG
  1191. //
  1192. // Type checking
  1193. //
  1194. static RUNDLLPROC lpfnRunDLL = OpenAs_RunDLL;
  1195. #endif
  1196. #endif