fsassoc.c
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 43k
Category:

Windows Kernel

Development Platform:

Visual C++

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