shwizutl.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 48k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. #include "shwizard.h"
  2. #include <tchar.h>
  3. #include <shlguid.h>
  4. #include <shlwapi.h>
  5. #include <shlobj.h>
  6. #include <shguidp.h>
  7. #include <shellp.h>
  8. #define STR_SHELLCLASSINFO          TEXT(".ShellClassInfo")
  9. #define STR_HTMLINFOTIPFILE (SZ_CANBEUNICODE TEXT("HTMLInfoTipFile"))
  10. #define STR_WEBVIEWTEMPLATE_KEY     TEXT("WebViewTemplate")
  11. #define STR_PERSISTMONIKER_VERSION  TEXT("IE4")
  12. #define FILE_PROTOCOL               TEXT("file://")
  13. #define FILE_FOLDER_SETTINGS        TEXT("Folder Settings")
  14. #define FILE_FOLDER_SETTINGS_SHORT  TEXT("FldSet")
  15. #define FILE_BACKGROUND_IMAGE       TEXT("Background")
  16. #define FILE_BACKGROUND_IMAGE_SHORT TEXT("Backgrnd")
  17. #define FILE_HTMLINFOTIP            TEXT("Comment.htt")
  18. #define FILE_WEBVIEW_TEMPLATE       TEXT("Folder.htt")
  19. const WCHAR g_wchUnicodeBOFMarker = 0xfeff; // Little endian unicode Byte Order Mark.First byte:0xff, Second byte: 0xfe.
  20. // Forward declarations
  21. HRESULT ReadWebViewTemplate(LPCTSTR pszIniFile, LPCTSTR pszSection, LPTSTR pszWebViewTemplate, int cchWebViewTemplate);
  22. void DisplayPicture(LPCTSTR lpszImageFileName, HWND hwndSubclassed, LPCSTR lpszStartHtml, LPCSTR lpszEndHtml);
  23. #ifdef UNICODE
  24. DWORD SHGetIniStringUTF7(LPCWSTR pwszSection, LPCWSTR pwszKey, LPWSTR pBuf, DWORD nSize, LPCWSTR pwszFile)
  25. {
  26.     DWORD dwRet;
  27.     if (pwszKey && *pwszKey == SZ_CANBEUNICODE[0])
  28.     {
  29.         dwRet = SHGetIniString(pwszSection, pwszKey+1, pBuf, nSize, pwszFile);
  30.     }
  31.     else
  32.     {
  33.         dwRet = GetPrivateProfileString(pwszSection, pwszKey, TEXT(""), pBuf, nSize, pwszFile);
  34.     }
  35.     return dwRet;
  36. }
  37. BOOL SHSetIniStringUTF7(LPCWSTR pwszSection, LPCWSTR pwszKey, LPCWSTR pwszString, LPCWSTR pwszFile)
  38. {
  39.     BOOL bRet;
  40.     if (pwszKey && *pwszKey == SZ_CANBEUNICODE[0])
  41.     {
  42.         bRet = SHSetIniString(pwszSection, pwszKey+1, pwszString, pwszFile);
  43.     }
  44.     else
  45.     {
  46.         bRet = WritePrivateProfileString(pwszSection, pwszKey, pwszString, pwszFile);
  47.     }
  48.     return bRet;
  49. }
  50. #endif
  51. // Displays an error message box.
  52. void DisplayFolderCustomizationError(UINT nError)
  53. {
  54.     TCHAR szTitle[MAX_PATH];
  55.     LoadString(g_hAppInst, IDS_TITLE, szTitle, ARRAYSIZE(szTitle));
  56.     TCHAR szMessage[MAX_PATH];
  57.     LoadString(g_hAppInst, nError, szMessage, ARRAYSIZE(szMessage));
  58.     MessageBox(NULL, szMessage, szTitle, MB_OK | MB_SETFOREGROUND | MB_ICONSTOP);
  59. }
  60. // The pszGUID buffer should be atleast GUIDSTR_MAX chars long.
  61. void TCharStringFromGUID(const GUID& guid, TCHAR* pszGUID)
  62. {
  63.     OLECHAR wszOleGUID[GUIDSTR_MAX];
  64.     StringFromGUID2(guid, wszOleGUID, ARRAYSIZE(wszOleGUID));
  65.     SHUnicodeToTChar(wszOleGUID, pszGUID, GUIDSTR_MAX);
  66. }
  67. HRESULT EnsureFSObjectPresenceWithErrorUI(LPCTSTR pszFile, DWORD dwAccess, DWORD dwAttributes)
  68. {
  69.     HRESULT hres = E_FAIL;
  70.     if (dwAttributes & FILE_ATTRIBUTE_DIRECTORY)
  71.     {
  72.         if (PathIsDirectory(pszFile)    // A dir with the same name already exists. Good.
  73.                 || CreateDirectory(pszFile, NULL))  // We can create it now.
  74.         {
  75.             hres = S_OK;
  76.         }
  77.     }
  78.     else
  79.     {
  80.         HANDLE hFile = CreateFile(pszFile, dwAccess, 0, NULL, OPEN_ALWAYS, dwAttributes, NULL);
  81.         if (hFile != INVALID_HANDLE_VALUE)
  82.         {
  83.             CloseHandle(hFile);
  84.             hres = S_OK;
  85.         }
  86.     }
  87.     if (FAILED(hres))
  88.     {
  89.         // Report the error.
  90.         DisplayFolderCustomizationError(IDS_ACCESSERROR);
  91.     }
  92.     return hres;
  93. }
  94. void GetRelativePath(LPCTSTR pszDir, LPTSTR pszPath)
  95. {
  96.     TCHAR szTemp[MAX_PATH];
  97.     PathRelativePathTo(szTemp, pszDir, FILE_ATTRIBUTE_DIRECTORY, pszPath, 0);
  98.     PathCanonicalize(pszPath, szTemp);
  99. }
  100. HRESULT EnsureDirResourceObjectPresenceWithErrorUI(LPCTSTR pszDir, LPTSTR pszResourceObjectPath)
  101. {
  102.     BOOL    fSuccess;
  103.     
  104.     // Make sure there is FILE_FOLDER_SETTINGS folder within pszDir.
  105.     lstrcpyn(pszResourceObjectPath, pszDir, MAX_PATH);
  106.     if (IsLFNDrive(pszResourceObjectPath))
  107.     {
  108.         fSuccess = PathAppend(pszResourceObjectPath, FILE_FOLDER_SETTINGS);
  109.     }
  110.     else
  111.     {
  112.         fSuccess = PathAppend(pszResourceObjectPath, FILE_FOLDER_SETTINGS_SHORT);
  113.     }
  114.     if (!fSuccess)
  115.         return E_FAIL;
  116.     
  117.     HRESULT  hres = EnsureFSObjectPresenceWithErrorUI(pszResourceObjectPath, GENERIC_WRITE,
  118.             FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY);
  119.     if (SUCCEEDED(hres))
  120.     {
  121.         // Make sure FILE_FOLDER_SETTINGS is a super hidden folder.
  122.         if(!SetFileAttributes(pszResourceObjectPath, FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM))
  123.             hres = E_FAIL;
  124.     }
  125.     return hres;
  126. }
  127. HRESULT MakeFileLocalCopy(LPCTSTR pszSrcFilePath, LPCTSTR pszFolderPath, LPTSTR pszDestFile)
  128. {
  129.     HRESULT hres = E_FAIL;
  130.     TCHAR szTemp[MAX_PATH];
  131.     // The local-copy should go in the directory resource object.
  132.     if (SUCCEEDED(EnsureDirResourceObjectPresenceWithErrorUI(pszFolderPath, szTemp)))
  133.     {
  134.         //PathAppend can fail if the path is too deep!
  135.         if(PathAppend(szTemp, pszDestFile) &&
  136.           (lstrcmpi(pszSrcFilePath, szTemp) != 0))
  137.         {
  138.             SetFileAttributes(szTemp, FILE_ATTRIBUTE_NORMAL);   // Make sure it is writable.
  139.             if (CopyFile(pszSrcFilePath, szTemp, FALSE))
  140.             {
  141.                 lstrcpy(pszDestFile, szTemp);
  142.                 hres = S_OK;
  143.             }
  144.             else
  145.             {
  146.                 int i = GetLastError();
  147.                 // Report the error.
  148.                 DisplayFolderCustomizationError(IDS_ACCESSERROR);
  149.             }
  150.         }
  151.     }
  152.     return hres;
  153. }
  154. HRESULT UpdateLVBackgroundImageSettings(LPCTSTR pszBackgroundImage, LPCTSTR pszFolderPath, LPCTSTR pszIni)
  155. {
  156.     TCHAR szGUID[GUIDSTR_MAX];
  157.     TCharStringFromGUID(VID_FolderState, szGUID);
  158.     WritePrivateProfileString(TEXT("ExtShellFolderViews"), TEXT("Default"), NULL, pszIni);
  159.     WritePrivateProfileString(TEXT("ExtShellFolderViews"), szGUID, szGUID, pszIni);
  160.     WritePrivateProfileString(szGUID, TEXT("Attributes"), TEXT("1"), pszIni);
  161.     // Write out the relative path for the background image file in the ini file
  162.     TCHAR szRelativePath[MAX_PATH];
  163.     lstrcpyn(szRelativePath, pszBackgroundImage, ARRAYSIZE(szRelativePath));
  164.     GetRelativePath(pszFolderPath, szRelativePath);
  165.     SHSetIniString(szGUID, TEXT("IconArea_Image"), szRelativePath, pszIni);
  166.     return S_OK;
  167. }
  168. BOOL IsBackgroundImageSet()
  169. {
  170.     TCHAR szGUID[GUIDSTR_MAX];
  171.     TCharStringFromGUID(VID_FolderState, szGUID);
  172.     TCHAR szNone[MAX_PATH];
  173.     LoadString(g_hAppInst, IDS_ENTRY_NONE, szNone, ARRAYSIZE(szNone));
  174.     TCHAR szTemp[30];
  175.     return SHGetIniString(szGUID, TEXT("IconArea_Image"), szTemp, ARRAYSIZE(szTemp), g_szIniFile)
  176.             && (lstrcmpi(szTemp, szNone) != 0);
  177. }
  178. void RemoveBackgroundImage()
  179. {
  180.     TCHAR szNone[MAX_PATH];
  181.     LoadString(g_hAppInst, IDS_ENTRY_NONE, szNone, ARRAYSIZE(szNone));
  182.     UpdateChangeBitmap(szNone);
  183. }
  184. BOOL IsIconTextColorSet()
  185. {
  186.     TCHAR szGUID[GUIDSTR_MAX];
  187.     TCharStringFromGUID(VID_FolderState, szGUID);
  188.     TCHAR szTemp[30];
  189.     return GetPrivateProfileString(szGUID, TEXT("IconArea_Text"), TEXT(""),
  190.             szTemp, ARRAYSIZE(szTemp), g_szIniFile)
  191.             || GetPrivateProfileString(szGUID, TEXT("IconArea_TextBackground"), TEXT(""),
  192.             szTemp, ARRAYSIZE(szTemp), g_szIniFile);
  193. }
  194. void RestoreIconTextColor()
  195. {
  196.     TCHAR szGUID[GUIDSTR_MAX];
  197.     TCharStringFromGUID(VID_FolderState, szGUID);
  198.     WritePrivateProfileString(szGUID, TEXT("IconArea_Text"), NULL, g_szIniFile);
  199.     WritePrivateProfileString(szGUID, TEXT("IconArea_TextBackground"), NULL, g_szIniFile);
  200. }
  201. BOOL IsFolderCommentSet()
  202. {
  203.     TCHAR szTemp[30];
  204.     return SHGetIniStringUTF7(STR_SHELLCLASSINFO, STR_HTMLINFOTIPFILE, szTemp, ARRAYSIZE(szTemp), g_szIniFile) > 0;
  205. }
  206. void RemoveFolderComment()
  207. {
  208.     UpdateComment(NULL);
  209. }
  210. BOOL IsWebViewTemplateSet()
  211. {
  212.     TCHAR szVID[GUIDSTR_MAX];
  213.     TCharStringFromGUID(VID_WebView, szVID);
  214.     TCHAR szTemp[30];
  215.     return SUCCEEDED(ReadWebViewTemplate(g_szIniFile, szVID, szTemp, ARRAYSIZE(szTemp)));
  216. }
  217. void UpdateChangeBitmap(LPCTSTR pszImageFile)
  218. {
  219.     // Ensure that the INI file is present and we can get write access.
  220.     if (SUCCEEDED(EnsureFSObjectPresenceWithErrorUI(g_szIniFile, GENERIC_WRITE, FILE_ATTRIBUTE_NORMAL)))
  221.     {
  222.         TCHAR szGUID[GUIDSTR_MAX];
  223.         TCharStringFromGUID(VID_FolderState, szGUID);
  224.         TCHAR szNone[MAX_PATH];
  225.         LoadString(g_hAppInst, IDS_ENTRY_NONE, szNone, ARRAYSIZE(szNone));
  226.         TCHAR szTemp2[MAX_PATH];
  227.         SHGetIniString(szGUID, TEXT("IconArea_Image"), szTemp2, ARRAYSIZE(szTemp2), g_szIniFile);
  228.         if (!*szTemp2)
  229.             lstrcpy(szTemp2, szNone);
  230.         PathCombine(szTemp2, g_szCurFolder, szTemp2);
  231.         if (lstrcmpi(pszImageFile, szNone) == 0)    // Remove the entry for the background image file from the ini file.
  232.         {
  233.             SHSetIniString(szGUID, TEXT("IconArea_Image"), NULL, g_szIniFile);
  234.         }
  235.         else
  236.         {
  237.             TCHAR szTemp[MAX_PATH];
  238.             // Get the dest file name
  239.             if (IsLFNDrive(g_szCurFolder))
  240.             {
  241.                 lstrcpyn(szTemp, FILE_BACKGROUND_IMAGE, ARRAYSIZE(szTemp));
  242.             }
  243.             else
  244.             {
  245.                 lstrcpyn(szTemp, FILE_BACKGROUND_IMAGE_SHORT, ARRAYSIZE(szTemp));
  246.             }
  247.             TCHAR* pszExt = PathFindExtension(pszImageFile);
  248.             if (pszExt)
  249.             {
  250.                 StrCatBuff(szTemp, pszExt, ARRAYSIZE(szTemp));
  251.             }
  252.             // The local-copy of the background image should go in the directory resource object.
  253.             if (SUCCEEDED(MakeFileLocalCopy(pszImageFile, g_szCurFolder, szTemp)))
  254.             {
  255.                 // Delete the old image file if it is not the same as the new one.
  256.                 if (lstrcmpi(szTemp2, szTemp) != 0)
  257.                 {
  258.                     DeleteFile(szTemp2);
  259.                 }
  260.                 UpdateLVBackgroundImageSettings(szTemp, g_szCurFolder, g_szIniFile);
  261.             }
  262.         }
  263.         UpdateGlobalFolderInfo(UPDATE_BITMAP, szGUID);
  264.     }
  265. }
  266. const LPCTSTR c_szWebViewTemplateVersions[] =
  267. {
  268.     STR_WEBVIEWTEMPLATE_KEY TEXT(".NT5"),
  269.     TEXT("PersistMoniker"),
  270. };
  271. HRESULT RemoveWebViewTemplateSettings()
  272. {
  273.     SHFOLDERCUSTOMSETTINGS fcs = {sizeof(fcs), FCSM_WEBVIEWTEMPLATE, 0};
  274.     fcs.pszWebViewTemplate = NULL;   // template path
  275.     return SHGetSetFolderCustomSettings(&fcs, g_szCurFolder, FCS_FORCEWRITE);
  276. }
  277. HRESULT ReadWebViewTemplate(LPCTSTR pszIniFile, LPCTSTR pszSection, LPTSTR pszWebViewTemplate, int cchWebViewTemplate)
  278. {
  279.     SHFOLDERCUSTOMSETTINGS fcs = {sizeof(fcs), FCSM_WEBVIEWTEMPLATE, 0};
  280.     fcs.pszWebViewTemplate = pszWebViewTemplate;
  281.     fcs.cchWebViewTemplate = cchWebViewTemplate;
  282.     return SHGetSetFolderCustomSettings(&fcs, g_szCurFolder, FCS_READ);
  283. }
  284. HRESULT GetWebViewTemplateKeyVersion(LPCTSTR pszKey, LPTSTR pszKeyVersion, int cchKeyVersion)
  285. {
  286.     HRESULT hr = E_INVALIDARG;
  287.     if (pszKeyVersion)
  288.     {
  289.         pszKeyVersion[0] = TEXT('');
  290.         TCHAR szTemp[MAX_PATH];
  291.         wnsprintf(szTemp, ARRAYSIZE(szTemp), TEXT("%s\%s"), REG_WEBVIEW_TEMPLATES, pszKey);
  292.         HKEY hkeyTemplate;
  293.         if (pszKey && pszKey[0] && RegOpenKeyEx(HKEY_LOCAL_MACHINE, szTemp, 0, KEY_READ, &hkeyTemplate) == ERROR_SUCCESS)
  294.         {
  295.             TCHAR szTemp2[MAX_PATH];
  296.             DWORD cbTemp2 = sizeof(szTemp2);
  297.             if (RegQueryValueEx(hkeyTemplate, REG_VAL_VERSION, NULL, NULL, (LPBYTE)szTemp2, &cbTemp2) == ERROR_SUCCESS
  298.                     && StrCmpNI(szTemp2, STR_PERSISTMONIKER_VERSION, ARRAYSIZE(STR_PERSISTMONIKER_VERSION)) != 0)
  299.             {
  300.                 lstrcpyn(pszKeyVersion, szTemp2, cchKeyVersion);
  301.             }
  302.             RegCloseKey(hkeyTemplate);
  303.         }
  304.         hr = S_OK;
  305.     }
  306.     return hr;
  307. }
  308. TCHAR const c_szWebDir[] = TEXT("%WebDir%");
  309. BOOL SubstituteWebDir(LPTSTR pszFile, int cch)
  310. {
  311.     BOOL fRet = FALSE;
  312.     TCHAR szWebDirPath[MAX_PATH];
  313.     if (SUCCEEDED(SHGetWebFolderFilePath(FILE_WEBVIEW_TEMPLATE, szWebDirPath, ARRAYSIZE(szWebDirPath))))
  314.     {
  315.         PathRemoveFileSpec(szWebDirPath);
  316.         LPTSTR pszTemp = StrStrI(pszFile, szWebDirPath);
  317.         if (pszTemp)
  318.         {
  319.             StrCpy(pszTemp, c_szWebDir);
  320.             PathAppend(pszTemp, pszTemp + lstrlen(szWebDirPath));
  321.             fRet = TRUE;
  322.         }
  323.     }
  324.     return fRet;
  325. }
  326. HRESULT UpdateWebViewTemplateSettings(LPCTSTR pszKey, LPCTSTR pszWebViewTemplatePath, LPCTSTR pszPreviewBitmap, LPCTSTR pszIni)
  327. {
  328.     TCHAR szVID[GUIDSTR_MAX];
  329.     TCharStringFromGUID(VID_WebView, szVID);
  330.     TCHAR szTemp[MAX_PATH];
  331.     StrCpyN(szTemp, pszWebViewTemplatePath, ARRAYSIZE(szTemp));
  332.     TCHAR szTemp2[MAX_PATH];
  333.     GetWebViewTemplateKeyVersion(pszKey, szTemp2, ARRAYSIZE(szTemp2));
  334.     // Update the Ini file.
  335.     SHFOLDERCUSTOMSETTINGS fcs = {sizeof(fcs), FCSM_WEBVIEWTEMPLATE, 0};
  336.     fcs.pszWebViewTemplate = szTemp;
  337.     fcs.pszWebViewTemplateVersion = szTemp2;
  338.     HRESULT hres = SHGetSetFolderCustomSettings(&fcs, g_szCurFolder, FCS_FORCEWRITE);
  339.     // Update the template preview.
  340.     if (SUCCEEDED(hres) && pszPreviewBitmap && pszPreviewBitmap[0])
  341.     {
  342.         lstrcpyn(szTemp2, pszPreviewBitmap, ARRAYSIZE(szTemp2));
  343.         if (!SubstituteWebDir(szTemp2, ARRAYSIZE(szTemp2)))
  344.         {
  345.             PathUnExpandEnvStrings(pszPreviewBitmap, szTemp2, ARRAYSIZE(szTemp2));  // Encode the path with env vars
  346.         }
  347.         WritePrivateProfileString(szVID, TEXT("PersistMonikerPreview"), szTemp2, pszIni);
  348.     }
  349.     return hres;
  350. }
  351. void UpdateAddWebView()
  352. {
  353.     // Make sure FILE_FOLDER_SETTINGS is present and we can get write access.
  354.     if (SUCCEEDED(EnsureFSObjectPresenceWithErrorUI(g_szIniFile, GENERIC_WRITE, FILE_ATTRIBUTE_NORMAL)))
  355.     {
  356.         // Copy over the supporting files as well.
  357.         HRESULT hres = S_OK;
  358.         HKEY hkeyTemplate;
  359.         TCHAR szTemp[MAX_PATH], szTemp2[MAX_PATH];
  360.         wnsprintf(szTemp, ARRAYSIZE(szTemp), TEXT("%s\%s"), REG_WEBVIEW_TEMPLATES, g_szKey);
  361.         // Make sure this is a template from the registry
  362.         if (g_szKey[0] && RegOpenKeyEx(HKEY_LOCAL_MACHINE, szTemp, 0, KEY_READ, &hkeyTemplate) == ERROR_SUCCESS)
  363.         {
  364.             // Now, copy the supporting files for the template, into FILE_FOLDER_SETTINGS.
  365.             HKEY hkeySupportingFiles;
  366.             if (RegOpenKeyEx(hkeyTemplate, REG_SUPPORTINGFILES, 0, KEY_READ, &hkeySupportingFiles) == ERROR_SUCCESS)
  367.             {
  368.                 TCHAR szTemp3[50]; // 50 is a reasonable limit on a file name.
  369.                 // The local-copies of the template resources should go in the directory resource object.
  370.                 if (SUCCEEDED(EnsureDirResourceObjectPresenceWithErrorUI(g_szCurFolder, szTemp2)))
  371.                 {
  372.                     DWORD cchTemp3 = ARRAYSIZE(szTemp3), cbTemp = sizeof(szTemp);
  373.                     for (int i = 0; RegEnumValue(hkeySupportingFiles, i, szTemp3, &cchTemp3,
  374.                             NULL, NULL, (LPBYTE)szTemp, &cbTemp) == ERROR_SUCCESS;
  375.                             cchTemp3 = ARRAYSIZE(szTemp3), cbTemp = sizeof(szTemp), i++)
  376.                     {
  377.                         TCHAR szDestFilePath[MAX_PATH];
  378.                         PathCombine(szDestFilePath, szTemp2, szTemp3);
  379.                         SetFileAttributes(szDestFilePath, FILE_ATTRIBUTE_NORMAL);   // Make sure it is writable.
  380.                         if (!CopyFile(szTemp, szDestFilePath, FALSE))
  381.                         {
  382.                             // Report the error.
  383.                             DisplayFolderCustomizationError(IDS_ACCESSERROR);
  384.                             hres = E_FAIL;
  385.                             break;
  386.                         }
  387.                     }
  388.                 }
  389.                 RegCloseKey(hkeySupportingFiles);
  390.             }
  391.             RegCloseKey(hkeyTemplate);
  392.         }
  393.         if (SUCCEEDED(hres))
  394.         {
  395.             if (g_iFlagA != SYSTEM_TEMPLATE)
  396.             {
  397.                 lstrcpy(szTemp, FILE_WEBVIEW_TEMPLATE);
  398.                 hres = MakeFileLocalCopy(g_szFullHTMLFile, g_szCurFolder, szTemp);
  399.             }
  400.             if (SUCCEEDED(hres) && g_szKey[0])
  401.             {
  402.                 if (IsLFNDrive(g_szIniFile))
  403.                 {
  404.                     lstrcpyn(szTemp, FILE_PROTOCOL FILE_FOLDER_SETTINGS TEXT("\") FILE_WEBVIEW_TEMPLATE, ARRAYSIZE(szTemp));
  405.                 }
  406.                 else
  407.                 {
  408.                     lstrcpyn(szTemp, FILE_PROTOCOL FILE_FOLDER_SETTINGS_SHORT TEXT("\") FILE_WEBVIEW_TEMPLATE, ARRAYSIZE(szTemp));
  409.                 }
  410.                 hres = UpdateWebViewTemplateSettings(g_szKey, (g_iFlagA == SYSTEM_TEMPLATE) ? g_szTemplateFile : szTemp, g_szPreviewBitmapFile, g_szIniFile);
  411.             }
  412.         }
  413.         if (g_iFlagA != SYSTEM_TEMPLATE)
  414.         {
  415.             DeleteFile(g_szFullHTMLFile);   // Delete this temp file
  416.         }
  417.         if (SUCCEEDED(hres))
  418.         {
  419.             UpdateGlobalFolderInfo(UPDATE_WEB_VIEW, NULL);
  420.         }
  421.     }
  422. }
  423. void GetTemporaryTemplatePath(LPTSTR pszTemplate)
  424. {
  425.     GetTempPath(MAX_PATH, pszTemplate);
  426.     PathAppend(pszTemplate, FILE_WEBVIEW_TEMPLATE);
  427. }
  428. void ChooseShortcutColor (HWND hWnd, SHORTCUTCOLOR *sccColor)
  429. {
  430.     CHOOSECOLOR ccColors;
  431.     memset(&ccColors, 0, sizeof(CHOOSECOLOR));
  432.     ccColors.hwndOwner      = hWnd;
  433.     ccColors.lStructSize    = sizeof(CHOOSECOLOR);
  434.     ccColors.rgbResult      = sccColor->crColor;
  435.     ccColors.lpCustColors   = g_crCustomColors;
  436.     ccColors.Flags          = CC_RGBINIT | CC_SOLIDCOLOR; // | CC_PREVENTFULLOPEN;
  437.     ccColors.lCustData      = 0L;
  438.     if (ChooseColor(&ccColors))
  439.     {
  440.         sccColor->iChanged = TRUE;
  441.         sccColor->crColor = ccColors.rgbResult;
  442.         InvalidateRect(NULL, NULL, FALSE);
  443.     }
  444. }
  445. void UpdateShortcutColors (LPCTSTR szGUID)
  446. {
  447.     TCHAR szTempVal[20];
  448.     BOOL bEnsureFolderStateSettings = FALSE;
  449.     if (ShortcutColorText.iChanged)
  450.     {
  451.         wnsprintf(szTempVal, ARRAYSIZE(szTempVal), TEXT("0x%8.8X"), ShortcutColorText.crColor);
  452.         WritePrivateProfileString(szGUID, TEXT("IconArea_Text"), szTempVal, g_szIniFile);
  453.         bEnsureFolderStateSettings = TRUE;
  454.     }
  455.     if (ShortcutColorBkgnd.iChanged)
  456.     {
  457.         wnsprintf(szTempVal, ARRAYSIZE(szTempVal), TEXT("0x%8.8X"), ShortcutColorBkgnd.crColor);
  458.         WritePrivateProfileString(szGUID, TEXT("IconArea_TextBackground"), szTempVal, g_szIniFile);
  459.         bEnsureFolderStateSettings = TRUE;
  460.     }
  461.     else
  462.     {
  463.         WritePrivateProfileString(szGUID, TEXT("IconArea_TextBackground"), NULL, g_szIniFile);
  464.     }
  465.     if (bEnsureFolderStateSettings)
  466.     {
  467.         WritePrivateProfileString(TEXT("ExtShellFolderViews"), szGUID, szGUID, g_szIniFile);
  468.         WritePrivateProfileString(szGUID, TEXT("Attributes"), TEXT("1"), g_szIniFile);
  469.     }
  470. }
  471. void SetRequiredAttributes()
  472. {
  473.     SetFileAttributes(g_szIniFile, FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
  474.     // PathMakeSystemFolder() special cases the windir and system dir
  475.     PathMakeSystemFolder(g_szCurFolder);
  476. }
  477. void UpdateGlobalFolderInfo (int flag, LPCTSTR szGUID)
  478. {
  479.     SetRequiredAttributes();
  480.     if (flag == UPDATE_BITMAP && szGUID)
  481.         UpdateShortcutColors(szGUID);
  482.     else
  483.         SetFileAttributes(g_szFullHTMLFile, FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
  484.     WritePrivateProfileString(STR_SHELLCLASSINFO, TEXT("ConfirmFileOp"), TEXT("0"), g_szIniFile);
  485. }
  486. BOOL CopyTemplate()
  487. {
  488.     DWORD buffer_size = 0, bytes_processed;
  489.     HANDLE hTemplateSource, hTemplateTarget;
  490.     void *file_buffer = NULL;
  491.     if (!TemplateExists(g_szTemplateFile))
  492.     {
  493.         RestoreMasterTemplate(g_szTemplateFile);
  494.     }
  495.     hTemplateSource = CreateFile(g_szTemplateFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  496.     if (hTemplateSource == INVALID_HANDLE_VALUE)
  497.         return(FALSE);
  498.     // CreateFile() fails if the file already exists and has the RO bit set. So, first set the attribute to normal.
  499.     SetFileAttributes(g_szFullHTMLFile, FILE_ATTRIBUTE_NORMAL);
  500.     hTemplateTarget = CreateFile(g_szFullHTMLFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  501.     if (hTemplateTarget == INVALID_HANDLE_VALUE)
  502.     {
  503.         DWORD dwError = GetLastError();
  504.         CloseHandle(hTemplateSource);
  505.         return(FALSE);
  506.     }
  507.     
  508.     if ((file_buffer = malloc((buffer_size = GetFileSize(hTemplateSource, NULL)))) == (void *)NULL)
  509.     {
  510.         CloseHandle(hTemplateSource);
  511.         CloseHandle(hTemplateTarget);
  512.         return(FALSE);
  513.     }
  514.     ReadFile(hTemplateSource, file_buffer, buffer_size, &bytes_processed, NULL);
  515.     WriteFile(hTemplateTarget, file_buffer, buffer_size, &bytes_processed, NULL);
  516.     free(file_buffer);
  517.     CloseHandle(hTemplateSource);
  518.     CloseHandle(hTemplateTarget);
  519.     g_bTemplateCopied = TRUE;
  520.     return(TRUE);
  521. }
  522. BOOL TemplateExists (LPCTSTR szTemplatePath)
  523. {
  524.     return GetFileAttributes(szTemplatePath) != 0xFFFFFFFF;
  525. }
  526. void LaunchRegisteredEditor (void)
  527. {
  528.     //Launch Editor
  529.     SHELLEXECUTEINFO rgInfo;
  530.     rgInfo.cbSize = sizeof(rgInfo);
  531.     rgInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI | SEE_MASK_FLAG_DDEWAIT;
  532.     rgInfo.hwnd = NULL;
  533.     rgInfo.lpVerb = TEXT("edit");
  534.     rgInfo.lpFile = g_szFullHTMLFile;
  535.     rgInfo.lpParameters = NULL;
  536.     rgInfo.lpDirectory = NULL;
  537.     rgInfo.nShow = SW_NORMAL;
  538.     SetFileAttributes(g_szFullHTMLFile, FILE_ATTRIBUTE_NORMAL);  // Originally done for FPE, now do this for TPVs (Third Party Vendors)
  539.     if (ShellExecuteEx(&rgInfo)) {
  540.         while (MsgWaitForMultipleObjects(1, &rgInfo.hProcess, FALSE, INFINITE, QS_ALLINPUT) == (WAIT_OBJECT_0 + 1)) {
  541.             MSG msg;
  542.             while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { 
  543.                 if (msg.message == WM_PAINT)  
  544.                     DispatchMessage(&msg); 
  545.             }
  546.         }
  547.         CloseHandle(rgInfo.hProcess);
  548.     } else
  549.         LaunchNotepad();            // resort to notepad if the registered app couldn't be launched ...
  550.     SetFileAttributes(g_szFullHTMLFile, FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
  551.     SHRegisterValidateTemplate(g_szFullHTMLFile, SHRVT_REGISTER);
  552. }
  553. void LaunchNotepad (void)
  554. {
  555.     TCHAR szTemp[MAX_PATH];
  556.     LoadString(g_hAppInst, IDS_NOTEPAD, szTemp, ARRAYSIZE(szTemp));
  557.     lstrcat(szTemp, g_szFullHTMLFile);
  558.     STARTUPINFO si = {0};
  559.     PROCESS_INFORMATION pi = {0};
  560.     si.cb = sizeof(STARTUPINFO);
  561.     si.lpReserved = NULL;
  562.     si.lpReserved2 = NULL;
  563.     si.cbReserved2 = 0;
  564.     si.lpDesktop = NULL;
  565.     si.dwFlags = 0;
  566.     
  567.     CreateProcess(NULL, szTemp, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);
  568.     CloseHandle(pi.hThread);
  569.     while (MsgWaitForMultipleObjects(1, &pi.hProcess, FALSE, INFINITE, QS_ALLINPUT) == (WAIT_OBJECT_0 + 1)) {
  570.         MSG msg;
  571.         while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { 
  572.             if (msg.message == WM_PAINT)  
  573.                 DispatchMessage(&msg); 
  574.         }
  575.     }
  576.     CloseHandle(pi.hProcess);
  577. }
  578. void RestoreMasterTemplate (LPCTSTR szTemplatePath)
  579. {
  580.     HINSTANCE hInstance;
  581.     HRSRC     hRsrc;
  582.     HGLOBAL   hGlobal;
  583.     HANDLE    hTemplateTarget;
  584.     DWORD     bytes_processed;
  585.     void      *buffer;
  586.     TCHAR     szTemp[MAX_PATH];
  587.     LoadString(g_hAppInst, IDS_WEBVIEW_DLL, szTemp, ARRAYSIZE(szTemp));
  588.     hInstance = LoadLibraryEx(szTemp, NULL, LOAD_LIBRARY_AS_DATAFILE);
  589.     LoadString(g_hAppInst, IDS_FOLDER, szTemp, ARRAYSIZE(szTemp));
  590.     hRsrc = FindResource(hInstance, szTemp, RT_HTML);
  591.     hGlobal = LoadResource(hInstance, hRsrc);
  592.     buffer = LockResource(hGlobal);
  593.     hTemplateTarget = CreateFile(szTemplatePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  594.     if (hTemplateTarget == INVALID_HANDLE_VALUE)
  595.         return;
  596.     WriteFile(hTemplateTarget, buffer, SizeofResource(hInstance, hRsrc), &bytes_processed, NULL);
  597.     CloseHandle(hTemplateTarget);
  598. }
  599. #define MAX_HTML_ESCAPE_SEQUENCE 8  // longest string representation of a 16 bit integer is 65535.  So, entire composite escape string has:
  600.                                     // 2 for "&#" + maximum of 5 digits + 1 for ";" = 8 characters
  601. /*
  602.  * UnicodeToHTMLEscapeStringAnsi
  603.  *
  604.  * Takes a unicode string as the input source and translates it into an ansi string that mshtml can process.  Characters > 127 will be
  605.  * translated into an html escape sequence that has the following syntax:  "&#xxxxx;" where xxxxx is the string representation of the decimal
  606.  * integer which is the value for the unicode character.  In this manner we are able to generate HTML text which represent UNICODE characters.
  607.  */
  608. void UnicodeToHTMLEscapeStringAnsi(LPCWSTR pwszSrc, LPSTR pszDest, int cchDest)
  609. {
  610.     while (*pwszSrc && (cchDest > MAX_HTML_ESCAPE_SEQUENCE))
  611.     {
  612.         int iLen;
  613.         ULONG ul = MAKELONG(*pwszSrc, 0);
  614.         // We can optimize the common ansi characters to avoid generating the long escape sequence.  This allows us to fit
  615.         // longer paths in the buffer.
  616.         if (ul < 128)
  617.         {
  618.             *pszDest = (CHAR)*pwszSrc;
  619.             iLen = 1;
  620.         }
  621.         else
  622.         {
  623.             iLen = wsprintfA(pszDest, "&#%lu;", ul);
  624.         }
  625.         pszDest += iLen;
  626.         cchDest -= iLen;
  627.         pwszSrc++;
  628.     }
  629.     *pszDest = 0;
  630. }
  631. /************************************************************
  632.  void DisplayPicture(LPCTSTR lpszImageFileName, HWND hwndSubclassed, LPCSTR lpszStartHtml, LPCSTR lpszEndHtml):
  633.  Displays the file mentioned in hwnd, which should have been subclassed with ThumbNailSubClassWndProc.
  634.  
  635.  Parameters: lpszImageFileName: Name of the file displayed
  636.              hwndSubclassed:    Handle to the window in which the image is displayed.
  637.                                 This should have been subclassed with ThumbNailSubClassWndProc
  638.              lpszStartHtml:     The start string for the generated HTML file
  639.                 If lpszImageFileName is not NULL, it is inserted in the HTML file, after lpszStartHtml
  640.              lpszEndHtml:       The end string for the generated HTML file
  641.  Return Value : void
  642.  ************************************************************/
  643.  
  644. void DisplayPicture(LPCTSTR lpszImageFileName, HWND hwndSubclassed, LPCSTR lpszStartHtml, LPCSTR lpszEndHtml)
  645. {
  646.     TCHAR szTitle[MAX_PATH];
  647.     TCHAR szMessage[MAX_PATH];
  648.     TCHAR szTempFileName[MAX_PATH];
  649.     static unsigned int uiTempFileNo = 0;
  650.     GetTempPath(ARRAYSIZE(szMessage), szMessage);
  651.     GetLongPathName(szMessage, szTempFileName, ARRAYSIZE(szTempFileName));
  652.     wnsprintf(szTitle, ARRAYSIZE(szTitle), TEXT("shwiz%u.htm"), uiTempFileNo++ % 20);
  653.     PathAppend(szTempFileName, szTitle);
  654.     HANDLE  hFile;
  655.     hFile = CreateFile(szTempFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  656.     if (hFile == INVALID_HANDLE_VALUE)
  657.     {
  658.         // report the error ..
  659.         LoadString(g_hAppInst, IDS_TITLE, szTitle, ARRAYSIZE(szTitle));
  660.         LoadString(g_hAppInst, IDS_ERR_FILEOPEN, szMessage, ARRAYSIZE(szMessage));
  661.         MessageBox(NULL, szMessage, szTitle, MB_OK | MB_SETFOREGROUND | MB_ICONSTOP);
  662.     }
  663.     else
  664.     {
  665.         TCHAR szTemp[MAX_PATH];
  666.         if (lpszImageFileName)
  667.         {
  668.             lstrcpyn(szTemp, lpszImageFileName, ARRAYSIZE(szTemp));
  669.         }
  670.         else
  671.         {
  672.             szTemp[0] = TEXT('');
  673.         }
  674.         CHAR szTemp2[MAX_PATH];
  675. #ifdef UNICODE
  676.         UnicodeToHTMLEscapeStringAnsi(szTemp, szTemp2, ARRAYSIZE(szTemp2));
  677. #else
  678.         SHTCharToAnsi(szTemp, szTemp2, ARRAYSIZE(szTemp2));
  679. #endif
  680.         DWORD dwBytesProcessed;
  681.         WriteFile(hFile, lpszStartHtml, lstrlenA(lpszStartHtml), &dwBytesProcessed, NULL);
  682.         WriteFile(hFile, szTemp2, lstrlenA(szTemp2), &dwBytesProcessed, NULL);
  683.         WriteFile(hFile, lpszEndHtml, lstrlenA(lpszEndHtml), &dwBytesProcessed, NULL);
  684.         CloseHandle(hFile);
  685.         ShowPreview(szTempFileName, hwndSubclassed);
  686.     }
  687. }
  688. void DisplayBackground(LPCTSTR lpszImageFileName, HWND hwndSubclassed)
  689. {
  690.     // The following variables must not be Unicode since HTML files cannot be Unicode
  691.     char szStartHtml[] = "<HTML><BODY BACKGROUND="";
  692.     char szEndHtml[] = ""><BR CLEAR=ALL></BR></BODY></HTML>";
  693.     DisplayPicture(lpszImageFileName, hwndSubclassed, szStartHtml, szEndHtml);
  694. }
  695. void DisplayPreview(LPCTSTR lpszImageFileName, HWND hwndSubclassed)
  696. {
  697.     RECT rcClient;
  698.     GetClientRect(hwndSubclassed, &rcClient);
  699.     // The following variables must not be Unicode since HTML files cannot be Unicode
  700.     //bugbug - should change #c0c0c0 below to reflect user's system 3dface color
  701.     char szStartHtml[] = "<HTML><BODY style="border:none;" topmargin=0 leftmargin=0 rightmargin=0 bottommargin=0>rn<IMG src="";
  702.     char szEndHtml[] = "" style="position: absolute; left:0; top:0; width: 100%; height: 100%;">rn</BODY></HTML>";
  703.     DisplayPicture(lpszImageFileName, hwndSubclassed, szStartHtml, szEndHtml);
  704. }
  705. void InstallFileFromResource(LPCTSTR pszSource, LPCTSTR pszDestFile)
  706. {
  707.     HRSRC hRsrc;
  708.     hRsrc = FindResource(g_hAppInst, pszSource, RT_HTML);
  709.     if (hRsrc)
  710.     {
  711.         HANDLE hDestFile = CreateFile(pszDestFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 
  712.         if (hDestFile != INVALID_HANDLE_VALUE)
  713.         {
  714.             HGLOBAL hGlob = LoadResource(g_hAppInst, hRsrc);
  715.             LPVOID pTemp = LockResource(hGlob);
  716.             if (pTemp)
  717.             {
  718.                 ULONG cbWritten, cbResource = SizeofResource(g_hAppInst, hRsrc);
  719.                 WriteFile(hDestFile, pTemp, cbResource, &cbWritten, NULL);
  720.             }
  721.             CloseHandle(hDestFile);
  722.         }
  723.     }
  724. }
  725. void InstallUnknownHTML(LPTSTR pszTempFileName, int cchTempFileName, BOOL bForce)
  726. {
  727.     TCHAR szTempFileName[MAX_PATH];
  728.     if (!pszTempFileName || cchTempFileName <= 0)
  729.     {
  730.         pszTempFileName = szTempFileName;
  731.         cchTempFileName = ARRAYSIZE(szTempFileName);
  732.     }
  733.     TCHAR szUnknown[] = TEXT("unknown.htm");
  734.     GetTempPath(cchTempFileName, pszTempFileName);
  735.     PathAppend(pszTempFileName, szUnknown);
  736.     // Do this only if pszDestFile doesn't already exist or we are forced to install
  737.     if (bForce || GetFileAttributes(pszTempFileName) == 0xFFFFFFFF)
  738.     {
  739.         InstallFileFromResource(szUnknown, pszTempFileName);
  740.     }
  741. }
  742. void DisplayUnknown(HWND hwndSubclassed)
  743. {
  744.     TCHAR szTempFileName[MAX_PATH];
  745.     InstallUnknownHTML(szTempFileName, ARRAYSIZE(szTempFileName), FALSE);
  746.     ShowPreview(szTempFileName, hwndSubclassed);
  747. }
  748. // Displays a preview of an empty html in hwnd,
  749. // which should have been subclassed with ThumbNailSubClassWndProc.
  750. // Parameters: lpszImageFileName: Name of the file displayed
  751. //             hwndSubclassed:    Handle to the window in which the image is displayed.
  752. //                                This should have been subclassed with ThumbNailSubClassWndProc
  753. // Return Value : void
  754. void DisplayNone(HWND hwndSubclassed)
  755. {
  756.     // The following variables must not be Unicode since HTML files cannot be Unicode
  757.     //bugbug - should change #c0c0c0 below to reflect user's system 3dface color
  758.     char szStartHtml[] = "<HTML><BODY BGCOLOR=#C0C0C0>";
  759.     char szEndHtml[] = "</BODY></HTML>";
  760.     DisplayPicture(NULL, hwndSubclassed, szStartHtml, szEndHtml);
  761. }
  762. // Shows the preview of the HtmlFile lpszFileName in hwnd,
  763. // which should have been subclassed with ThumbNailSubClassWndProc.
  764. void ShowPreview(LPCTSTR lpszFileName, HWND hwndSubclassed)
  765. {
  766.     SendMessage(hwndSubclassed, WM_SETIMAGE, 0, (LPARAM)lpszFileName);
  767. }
  768. // Subclassing hwnd with ThumbNailSubClassWndProc. The original WndProc is saved in g_lpThumbnailWndProc
  769. void Subclass(HWND hwnd)
  770. {
  771.     if (!g_lpThumbnailWndProc)  // It is not subclassed by anyone else.
  772.     {
  773.         // Subclass hwnd
  774.         g_lpThumbnailWndProc = (WNDPROC)GetWindowLongPtr(hwnd, GWLP_WNDPROC);
  775.         if (g_lpThumbnailWndProc)
  776.         {
  777.             SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)ThumbNailSubClassWndProc);
  778.             // Initialize the subclass
  779.             SendMessage(hwnd, WM_INITSUBPROC, 0, 0);
  780.         }
  781.     }
  782. }
  783. // Resets subclassing. The original WndProc should be in g_lpThumbnailWndProc
  784. void Unsubclass(HWND hwnd)
  785. {
  786.     if (g_lpThumbnailWndProc)  // It is subclassed.
  787.     {
  788.         SendMessage(hwnd, WM_UNINITSUBPROC, 0, 0);
  789.         SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)g_lpThumbnailWndProc);
  790.         g_lpThumbnailWndProc = NULL;
  791.     }
  792. }
  793. void ExpandWebDir(LPTSTR pszFile, int cch)
  794. {
  795.     //Check if the given string has %WebDir%
  796.     LPTSTR psz = StrChr(pszFile, TEXT('%'));
  797.     if (psz)
  798.     {
  799.         if (!StrCmpNI(psz, c_szWebDir, ARRAYSIZE(c_szWebDir) - 1))
  800.         {
  801.             LPTSTR pszFileName = PathFindFileName(pszFile);
  802.             if (pszFileName && (pszFileName != psz))
  803.             {
  804.                 TCHAR szTempBuff[MAX_PATH];
  805.                 StrCpyN(szTempBuff, pszFileName, ARRAYSIZE(szTempBuff));
  806.                 SHGetWebFolderFilePath(szTempBuff, pszFile, cch);
  807.             }
  808.         }
  809.     }
  810. }
  811. // Returns: PM_NONE if g_szIniFile does not contain a WebViewTemplate
  812. //          PM_LOCAL if g_szIniFile contains a local folder.htt as the WebViewTemplate
  813. //          PM_REMOTE if g_szIniFile contains a remote template as the WebViewTemplate
  814. // If pszFileName is not NULL and cchFileName > 0, then the WebViewTemplate is returned in pszFileName and it's
  815. // PreviewBitmapFileName is returned in pszPreviewFileName
  816. int HasPersistMoniker(LPTSTR pszFileName, int cchFileName, LPTSTR pszPreviewFileName, int cchPreviewFileName)
  817. {
  818.     int iRetVal = PM_NONE;
  819.     TCHAR szTemp[MAX_PATH];
  820.     TCHAR szVID[GUIDSTR_MAX];
  821.     TCharStringFromGUID(VID_WebView, szVID);
  822.     TCHAR szFileName[MAX_PATH];
  823.     if (!pszFileName || cchFileName <= 0)
  824.     {
  825.         pszFileName = szFileName;
  826.         cchFileName = ARRAYSIZE(szFileName);
  827.     }
  828.     HRESULT hr = ReadWebViewTemplate(g_szIniFile, szVID, pszFileName, cchFileName);
  829.     if (pszPreviewFileName && cchPreviewFileName > 0)
  830.     {
  831.         GetPrivateProfileString(szVID, TEXT("PersistMonikerPreview"), TEXT(""), szTemp, ARRAYSIZE(szTemp), g_szIniFile);
  832.         ExpandEnvironmentStrings(szTemp, pszPreviewFileName, cchPreviewFileName);   // This is a path, so expand the env vars in it
  833.         ExpandWebDir(pszPreviewFileName, cchPreviewFileName);
  834.     }
  835.     if (SUCCEEDED(hr) && pszFileName[0])
  836.     {
  837.         lstrcpyn(szTemp, pszFileName, ARRAYSIZE(szTemp));
  838.         LPTSTR pszTemp = szTemp;
  839.         if (StrCmpNI(FILE_PROTOCOL, pszTemp, 7) == 0) // ARRAYSIZE(TEXT("file://"))
  840.         {
  841.             pszTemp += 7;   // ARRAYSIZE(TEXT("file://"))
  842.         }
  843.         // handle relative references...
  844.         PathCombine(pszTemp, g_szCurFolder, pszTemp);
  845.         TCHAR szTemp2[MAX_PATH];
  846.         lstrcpyn(szTemp2, g_szCurFolder, ARRAYSIZE(szTemp2));
  847.         if (IsLFNDrive(szTemp2))
  848.         {
  849.             PathAppend(szTemp2, FILE_FOLDER_SETTINGS);
  850.         }
  851.         else
  852.         {
  853.             PathAppend(szTemp2, FILE_FOLDER_SETTINGS_SHORT);
  854.         }
  855.         PathAppend(szTemp2, FILE_WEBVIEW_TEMPLATE);
  856.         if (lstrcmpi(pszTemp, szTemp2) == 0)
  857.         {
  858.             iRetVal = PM_LOCAL;
  859.             lstrcpyn(pszFileName, szTemp2, cchFileName);
  860.         }
  861.         else
  862.         {
  863.             iRetVal = PM_REMOTE;
  864.         }
  865.     }
  866.     return iRetVal;
  867. }
  868. const TCHAR c_szExploreClass[]  = TEXT("ExploreWClass");
  869. const TCHAR c_szIExploreClass[] = TEXT("IEFrame");
  870. const TCHAR c_szCabinetClass[]  = 
  871. #ifdef IE3CLASSNAME
  872.     TEXT("IEFrame");
  873. #else
  874.     TEXT("CabinetWClass");
  875. #endif
  876. const TCHAR c_szDesktopClass[]  = TEXT("Progman");
  877. BOOL IsFolderWindow(HWND hwnd)
  878. {
  879.     TCHAR szClass[32];
  880.     GetClassName(hwnd, szClass, ARRAYSIZE(szClass));
  881.     return (lstrcmp(szClass, c_szCabinetClass) == 0) || (lstrcmp(szClass, c_szIExploreClass) == 0);
  882. }
  883. BOOL IsNamedWindow(HWND hwnd, LPCTSTR pszClass)
  884. {
  885.     TCHAR szClass[32];
  886.     GetClassName(hwnd, szClass, ARRAYSIZE(szClass));
  887.     return lstrcmp(szClass, pszClass) == 0;
  888. }
  889. BOOL IsExplorerWindow(HWND hwnd)
  890. {
  891.     return IsNamedWindow(hwnd, c_szExploreClass);
  892. }
  893. BOOL IsDesktopWindow(HWND hwnd)
  894. {
  895.     return IsNamedWindow(hwnd, c_szDesktopClass);
  896. }
  897. BOOL CALLBACK Folder_UpdateWebView(HWND hwnd, LPARAM lParam)
  898. {
  899.     if (IsFolderWindow(hwnd) || IsExplorerWindow(hwnd))
  900.     {
  901.         PostMessage(hwnd, WM_COMMAND, SFVIDM_MISC_SETWEBVIEW, lParam);
  902.     }
  903.     return TRUE;
  904. }
  905. #define SHGETSETSETTINGSORDINAL 68  // shell32.dll ordinal for SHGetSetSettings
  906. typedef void (WINAPI *SHGETSETSETTINGSFN)(LPSHELLSTATE pss, DWORD dwMask, BOOL bSet);
  907. BOOL ProdWebViewOn(HWND hwndOwner)
  908. {
  909.     BOOL fRet = TRUE;
  910.     HINSTANCE hShell32 = LoadLibrary(TEXT("shell32.dll"));
  911.     SHGETSETSETTINGSFN pfn = (SHGETSETSETTINGSFN)GetProcAddress(hShell32, (LPCSTR)MAKEINTRESOURCE(SHGETSETSETTINGSORDINAL));
  912.     if (pfn)   // Webview is off. Ask if they want to turn it on.
  913.     {
  914.         SHELLSTATE  ss = {0};
  915.         pfn(&ss, 0, TRUE);   // Force a refresh
  916.         pfn(&ss, SSF_WEBVIEW, FALSE);
  917.         if (!ss.fWebView)
  918.         {
  919.             TCHAR szTitle[MAX_PATH], szMessage[MAX_PATH];
  920.             LoadString(g_hAppInst, IDS_TITLE, szTitle, ARRAYSIZE(szTitle));
  921.             LoadString(g_hAppInst, IDS_WEBVIEW_ON, szMessage, ARRAYSIZE(szMessage));
  922.             if (MessageBox(hwndOwner, szMessage, szTitle, MB_OKCANCEL | MB_SETFOREGROUND
  923.                     | MB_ICONQUESTION | MB_DEFBUTTON1) != IDOK)
  924.             {
  925.                 fRet = FALSE;
  926.             }
  927.             else
  928.             {
  929.                 ss.fWebView = TRUE;
  930.                 pfn(&ss, SSF_WEBVIEW, TRUE);
  931.                 EnumWindows(Folder_UpdateWebView, (LPARAM)TRUE);
  932.             }
  933.         }
  934.     }
  935.     return fRet;
  936. }
  937. #ifndef FCIDM_REFRESH
  938. #define FCIDM_REFRESH   0xA220
  939. #endif
  940. BOOL CALLBACK Folder_UpdateAll(HWND hwnd, LPARAM lParam)
  941. {
  942.     if (IsFolderWindow(hwnd) || IsExplorerWindow(hwnd) || IsDesktopWindow(hwnd))
  943.     {
  944.         PostMessage(hwnd, WM_COMMAND, FCIDM_REFRESH, NULL);
  945.     }
  946.     return TRUE;
  947. }
  948. void ForceShellToRefresh(void)
  949. {
  950.     SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH, g_szCurFolder, NULL);
  951.     EnumWindows(Folder_UpdateAll, NULL);
  952. }
  953. const TCHAR g_szCommentWrapBegin[] = TEXT("<body style="background:infobackground; color:infotext; margin-top:1; font:menu">n");
  954. const TCHAR g_szCommentWrapEnd[] = TEXT("</body>");
  955. HRESULT UpdateComment(LPCTSTR pszHTMLComment)
  956. {
  957.     HRESULT hr = E_FAIL;
  958.     if (pszHTMLComment && pszHTMLComment[0])
  959.     {
  960.         TCHAR szTemp[MAX_PATH];
  961.         if (SUCCEEDED(EnsureDirResourceObjectPresenceWithErrorUI(g_szCurFolder, szTemp))
  962.                 && PathAppend(szTemp, FILE_HTMLINFOTIP))
  963.         {
  964.             HANDLE hCommentFile = CreateFile(szTemp, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  965.             if (hCommentFile != INVALID_HANDLE_VALUE)
  966.             {
  967.                 DWORD cbWritten;
  968.                 DWORD cchToWrite = lstrlen(pszHTMLComment) + 1;
  969.                 BOOL bContinue = TRUE;
  970. #ifdef UNICODE
  971.                 bContinue = WriteFile(hCommentFile, (LPCSTR)&g_wchUnicodeBOFMarker, SIZEOF(g_wchUnicodeBOFMarker), &cbWritten, NULL);
  972. #endif
  973.                 if (bContinue && WriteFile(hCommentFile, (LPCVOID)g_szCommentWrapBegin, lstrlen(g_szCommentWrapBegin) * SIZEOF(TCHAR), &cbWritten, NULL)
  974.                         && WriteFile(hCommentFile, (LPCVOID)pszHTMLComment, lstrlen(pszHTMLComment) * SIZEOF(TCHAR), &cbWritten, NULL)
  975.                         && WriteFile(hCommentFile, (LPCVOID)g_szCommentWrapEnd, lstrlen(g_szCommentWrapEnd) * SIZEOF(TCHAR), &cbWritten, NULL))
  976.                 {
  977.                     if (IsLFNDrive(g_szIniFile))
  978.                     {
  979.                         lstrcpyn(szTemp, FILE_PROTOCOL FILE_FOLDER_SETTINGS TEXT("\") FILE_HTMLINFOTIP, ARRAYSIZE(szTemp));
  980.                     }
  981.                     else
  982.                     {
  983.                         lstrcpyn(szTemp, FILE_PROTOCOL FILE_FOLDER_SETTINGS_SHORT TEXT("\") FILE_HTMLINFOTIP, ARRAYSIZE(szTemp));
  984.                     }
  985.                     if (SHSetIniStringUTF7(STR_SHELLCLASSINFO, STR_HTMLINFOTIPFILE, szTemp , g_szIniFile))
  986.                     {
  987.                         hr = S_OK;
  988.                     }
  989.                 }
  990.                 CloseHandle(hCommentFile);
  991.             }
  992.         }
  993.         UpdateGlobalFolderInfo(UPDATE_COMMENT, NULL);
  994.     }
  995.     else
  996.     {   // Have to remove comment.htt & HTMLInfoTipFile from desktop.ini
  997.         TCHAR szHTMLInfoTipFile[MAX_PATH];
  998.         SHGetIniStringUTF7(STR_SHELLCLASSINFO, STR_HTMLINFOTIPFILE, szHTMLInfoTipFile, ARRAYSIZE(szHTMLInfoTipFile), g_szIniFile);
  999.         LPTSTR pszHTMLInfoTipFile = szHTMLInfoTipFile;
  1000.         if (StrCmpNI(FILE_PROTOCOL, pszHTMLInfoTipFile, 7) == 0) // ARRAYSIZE(TEXT("file://"))
  1001.         {
  1002.             pszHTMLInfoTipFile += 7;   // ARRAYSIZE(TEXT("file://"))
  1003.         }
  1004.         // handle relative references...
  1005.         PathCombine(pszHTMLInfoTipFile, g_szCurFolder, pszHTMLInfoTipFile);
  1006.         DeleteFile(pszHTMLInfoTipFile);
  1007.         SHSetIniStringUTF7(STR_SHELLCLASSINFO, STR_HTMLINFOTIPFILE, NULL, g_szIniFile);
  1008.         hr = S_OK;
  1009.     }
  1010.     return hr;
  1011. }
  1012. HRESULT GetCurrentComment(LPTSTR pszHTMLComment, int cchHTMLComment)
  1013. {
  1014.     HRESULT hr = E_FAIL;
  1015.     TCHAR szTemp[MAX_PATH];
  1016.     if (!pszHTMLComment || (cchHTMLComment <= 0))
  1017.     {
  1018.         hr = E_INVALIDARG;
  1019.     }
  1020.     else if (SHGetIniStringUTF7(STR_SHELLCLASSINFO, STR_HTMLINFOTIPFILE, szTemp, ARRAYSIZE(szTemp), g_szIniFile) > 0)
  1021.     {
  1022.         TCHAR szHTMLInfoTipFile[MAX_PATH];
  1023.         ExpandEnvironmentStrings(szTemp, szHTMLInfoTipFile, ARRAYSIZE(szHTMLInfoTipFile));   // This is a path, so expand the env vars in it
  1024.         ExpandWebDir(szHTMLInfoTipFile, ARRAYSIZE(szHTMLInfoTipFile));
  1025.         LPTSTR pszHTMLInfoTipFile = szHTMLInfoTipFile;
  1026.         if (StrCmpNI(FILE_PROTOCOL, pszHTMLInfoTipFile, 7) == 0) // ARRAYSIZE(TEXT("file://"))
  1027.         {
  1028.             pszHTMLInfoTipFile += 7;   // ARRAYSIZE(TEXT("file://"))
  1029.         }
  1030.         // handle relative references...
  1031.         PathCombine(pszHTMLInfoTipFile, g_szCurFolder, pszHTMLInfoTipFile);
  1032.         HANDLE hCommentFile = CreateFile(pszHTMLInfoTipFile, GENERIC_READ, FILE_SHARE_READ, 
  1033.                 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  1034.         if (hCommentFile != INVALID_HANDLE_VALUE)
  1035.         {
  1036.             WCHAR wch;
  1037.             DWORD cbRead = 0;
  1038.             
  1039.             if (ReadFile(hCommentFile, (LPVOID)&wch, SIZEOF(wch), &cbRead, NULL)
  1040.                     && (cbRead == SIZEOF(wch)))
  1041.             {
  1042.                 DWORD cbToRead;
  1043.                 BOOL bFoundCommentStart = FALSE;
  1044.                 if (wch == g_wchUnicodeBOFMarker)
  1045.                 {
  1046.                     cbToRead = (cchHTMLComment - 1) * SIZEOF(WCHAR);
  1047.                     LPWSTR pwsz = (LPWSTR)LocalAlloc(LPTR, cbToRead + (1 * SIZEOF(WCHAR)));
  1048.                     if (!pwsz)
  1049.                     {
  1050.                         hr = E_OUTOFMEMORY;
  1051.                     }
  1052.                     else
  1053.                     {
  1054.                         WCHAR wszTemp[ARRAYSIZE(g_szCommentWrapBegin)];
  1055.                         if (ReadFile(hCommentFile, (LPVOID)&wszTemp, (ARRAYSIZE(wszTemp) - 1) * SIZEOF(WCHAR), &cbRead, NULL)
  1056.                                 && (cbRead == (ARRAYSIZE(wszTemp) - 1) * SIZEOF(WCHAR)))
  1057.                         {
  1058.                             wszTemp[ARRAYSIZE(wszTemp) - 1] = L'';
  1059.                             WCHAR wszCommentWrapBegin[ARRAYSIZE(g_szCommentWrapBegin)];
  1060.                             SHTCharToUnicode(g_szCommentWrapBegin, wszCommentWrapBegin, ARRAYSIZE(wszCommentWrapBegin));
  1061.                             
  1062.                             if (StrCmpIW(wszTemp, wszCommentWrapBegin) != 0)
  1063.                             {
  1064.                                 //Seek to the point after the Unicode file marker
  1065.                                 SetFilePointer(hCommentFile, SIZEOF(g_wchUnicodeBOFMarker), NULL, FILE_BEGIN);
  1066.                             }
  1067.                             else
  1068.                             {
  1069.                                 bFoundCommentStart = TRUE;
  1070.                             }
  1071.                         }
  1072.                         if (ReadFile(hCommentFile, (LPVOID)pwsz, cbToRead, &cbRead, NULL))
  1073.                         {
  1074.                             int iEnd = (int)cbRead / SIZEOF(WCHAR);
  1075.                             if (bFoundCommentStart)
  1076.                             {
  1077.                                 pwsz[iEnd] = L'';
  1078.                                 WCHAR wszCommentWrapEnd[ARRAYSIZE(g_szCommentWrapEnd)];
  1079.                                 SHTCharToUnicode(g_szCommentWrapEnd, wszCommentWrapEnd, ARRAYSIZE(wszCommentWrapEnd));
  1080.                                 if (StrCmpIW(&pwsz[iEnd - lstrlen(g_szCommentWrapEnd)], wszCommentWrapEnd) == 0)
  1081.                                 {
  1082.                                     iEnd -= lstrlen(g_szCommentWrapEnd);
  1083.                                 }
  1084.                             }
  1085.                             pwsz[iEnd] = L'';
  1086.                             SHUnicodeToTChar(pwsz, pszHTMLComment, cchHTMLComment);
  1087.                             hr = S_OK;
  1088.                         }
  1089.                         LocalFree(pwsz);
  1090.                     }
  1091.                 }
  1092.                 else
  1093.                 {
  1094.                     // Anything other than the little endian unicode file is treated as ansi.
  1095.                     SetFilePointer(hCommentFile, 0L, NULL, FILE_BEGIN);   //Seek to the begining of the file again
  1096.                     cbToRead = (cchHTMLComment - 1) * SIZEOF(CHAR);
  1097.                     LPSTR psz = (LPSTR)LocalAlloc(LPTR, cbToRead + (1 * SIZEOF(CHAR)));
  1098.                     if (!psz)
  1099.                     {
  1100.                         hr = E_OUTOFMEMORY;
  1101.                     }
  1102.                     else
  1103.                     {
  1104.                         CHAR szTemp2[ARRAYSIZE(g_szCommentWrapBegin)];
  1105.                         if (ReadFile(hCommentFile, (LPVOID)&szTemp2, (ARRAYSIZE(szTemp2) - 1) * SIZEOF(CHAR), &cbRead, NULL)
  1106.                                 && (cbRead == (ARRAYSIZE(szTemp2) - 1) * SIZEOF(CHAR)))
  1107.                         {
  1108.                             szTemp2[ARRAYSIZE(szTemp2) - 1] = L'';
  1109.                             
  1110.                             CHAR szCommentWrapBegin[ARRAYSIZE(g_szCommentWrapBegin)];
  1111.                             SHTCharToAnsi(g_szCommentWrapBegin, szCommentWrapBegin, ARRAYSIZE(szCommentWrapBegin));
  1112.                             
  1113.                             if (StrCmpIA(szTemp2, szCommentWrapBegin) != 0)
  1114.                             {
  1115.                                 //Seek to the begining of the file again
  1116.                                 SetFilePointer(hCommentFile, 0L, NULL, FILE_BEGIN);
  1117.                             }
  1118.                             else
  1119.                             {
  1120.                                 bFoundCommentStart = TRUE;
  1121.                             }
  1122.                         }
  1123.                         if (ReadFile(hCommentFile, (LPVOID)psz, cbToRead, &cbRead, NULL))
  1124.                         {
  1125.                             int iEnd = (int)cbRead / SIZEOF(CHAR);
  1126.                             if (bFoundCommentStart)
  1127.                             {
  1128.                                 psz[iEnd] = L'';
  1129.                                 CHAR szCommentWrapEnd[ARRAYSIZE(g_szCommentWrapEnd)];
  1130.                                 SHTCharToAnsi(g_szCommentWrapEnd, szCommentWrapEnd, ARRAYSIZE(szCommentWrapEnd));
  1131.                                 if (StrCmpIA(&psz[iEnd - lstrlen(g_szCommentWrapEnd)], szCommentWrapEnd) == 0)
  1132.                                 {
  1133.                                     iEnd -= lstrlen(g_szCommentWrapEnd);
  1134.                                 }
  1135.                             }
  1136.                             psz[iEnd] = L'';
  1137.                             SHAnsiToTChar(psz, pszHTMLComment, cchHTMLComment);
  1138.                             hr = S_OK;
  1139.                         }
  1140.                         LocalFree(psz);
  1141.                     }
  1142.                 }
  1143.             }
  1144.             CloseHandle(hCommentFile);
  1145.         }
  1146.     }
  1147.     if (FAILED(hr) && (hr != E_INVALIDARG))
  1148.     {
  1149.         pszHTMLComment[0] = TEXT('');
  1150.         hr = S_OK;
  1151.     }
  1152.     return hr;
  1153. }