util.cpp
上传用户:xhy777
上传日期:2007-02-14
资源大小:24088k
文件大小:146k
源码类别:

系统编程

开发平台:

Visual C++

  1.                 if (dwPathLen>dwMaxPathLen)
  2.                 {
  3.                     DWORD   dwOverFlow = dwPathLen - dwMaxPathLen + dwElipsisLen;
  4.                     wnsprintfA(rgchPathForDisplay, ARRAYSIZE(rgchPathForDisplay), "/%s%s", rgchElipsis, rgchUrlPath+dwOverFlow);
  5.                     dwPathLen = dwMaxPathLen;
  6.                 }
  7.                 else
  8.                     StrCpyNA(rgchPathForDisplay, rgchUrlPath, ARRAYSIZE(rgchPathForDisplay));
  9.                 WCHAR   rgwchScheme[INTERNET_MAX_SCHEME_LENGTH];
  10.                 WCHAR   rgwchHostForDisplay[INTERNET_MAX_HOST_NAME_LENGTH];
  11.                 WCHAR   rgwchPathForDisplay[MAX_PATH];
  12.                 WCHAR   rgwchUrlPath[MAX_PATH];
  13.                 SHAnsiToUnicodeCP(dwCodePage, rgchScheme, rgwchScheme, ARRAYSIZE(rgwchScheme));
  14.                 SHAnsiToUnicodeCP(dwCodePage, rgchHostForDisplay, rgwchHostForDisplay, ARRAYSIZE(rgwchHostForDisplay));
  15.                 SHAnsiToUnicodeCP(dwCodePage, rgchPathForDisplay, rgwchPathForDisplay, ARRAYSIZE(rgwchPathForDisplay));
  16.                 SHAnsiToUnicodeCP(dwCodePage, rgchUrlPath, rgwchUrlPath, ARRAYSIZE(rgwchUrlPath));
  17.                 
  18.                 if (fSeperate)
  19.                 {
  20.                     // Format string as "X from Y"
  21.                     WCHAR   rgwchTemplate[dwMaxTemplateLen];
  22.                     WCHAR  *pwzFileName = PathFindFileNameW(rgwchPathForDisplay);
  23.                     DWORD   dwCount;
  24.                     //
  25.                     // remove cache decoration goop to map ie5setup[1].exe to ie5setup.exe
  26.                     //
  27.                     PathUndecorateW(pwzFileName);
  28.                     ZeroMemory(rgwchTemplate, sizeof(rgwchTemplate));
  29.                     dwCount = MLLoadString(IDS_TARGETFILE, rgwchTemplate, ARRAYSIZE(rgwchTemplate));
  30.                     if (dwCount > 0)
  31.                     {
  32.                         if (urlComp.nScheme == INTERNET_SCHEME_FILE)
  33.                         {
  34.                             StrCpyNW(rgwchHostForDisplay, rgwchUrlPath, ARRAYSIZE(rgwchPathForDisplay));
  35.                             PathRemoveFileSpecW(rgwchHostForDisplay);
  36.                         }
  37.                         if (dwPathLen+lstrlenW(rgwchTemplate)+dwHostLen <= cchBuf)
  38.                         {
  39.                             _FormatMessage(rgwchTemplate, pwzFriendly, cchBuf, pwzFileName, rgwchHostForDisplay);
  40.                             hrRC = S_OK;
  41.                         }
  42.                     }
  43.                 }
  44.                 else    // !fSeperate
  45.                 {
  46.                     if (3+dwPathLen+dwHostLen+dwSchemeLen < cchBuf)
  47.                     {
  48.                         wnsprintf(pwzFriendly, cchBuf, TEXT("%ws://%ws%ws"), rgwchScheme, rgwchHostForDisplay, rgwchPathForDisplay);
  49.                         hrRC = S_OK;
  50.                     }
  51.                 }
  52.             }
  53.         }
  54.         LocalFree(pszURL);
  55.     }
  56.     
  57.     return(hrRC);
  58. }
  59. BOOL __cdecl _FormatMessage(LPCWSTR szTemplate, LPWSTR szBuf, UINT cchBuf, ...)
  60. {
  61.     BOOL fRet;
  62.     va_list ArgList;
  63.     va_start(ArgList, cchBuf);
  64.     fRet = FormatMessage(FORMAT_MESSAGE_FROM_STRING, szTemplate, 0, 0, szBuf, cchBuf, &ArgList);
  65.     va_end(ArgList);
  66.     return fRet;
  67. }
  68. // Navigate to a given Url (wszUrl) using IE. Returns an error if IE does not exist.
  69. // fNewWindow = TRUE ==> A new window is compulsory
  70. // fNewWindow = FALSE ==> Do not launch a new window if one already is open.
  71. HRESULT NavToUrlUsingIEW(LPCWSTR wszUrl, BOOL fNewWindow)
  72. {
  73.     HRESULT hr = S_OK;
  74.     if (!EVAL(wszUrl))
  75.         return E_INVALIDARG;
  76.     if(IsIEDefaultBrowser() && !fNewWindow)
  77.     {
  78.         // ShellExecute navigates to the Url using the same browser window,
  79.         // if one is already open.
  80.         SHELLEXECUTEINFOW sei = {0};
  81.         sei.cbSize = sizeof(sei);
  82.         sei.lpFile = wszUrl;
  83.         sei.nShow  = SW_SHOWNORMAL;
  84.         ShellExecuteExW(&sei);
  85.     }
  86.     else
  87.     {
  88.         IWebBrowser2 *pwb2;
  89. #ifndef UNIX
  90.         hr = CoCreateInstance(CLSID_InternetExplorer, NULL,
  91.                               CLSCTX_LOCAL_SERVER, IID_IWebBrowser2, (LPVOID*)&pwb2);
  92. #else
  93.         hr = CoCreateInternetExplorer( IID_IWebBrowser2,
  94.                                        CLSCTX_LOCAL_SERVER,
  95.                                        (LPVOID*) &pwb2 );
  96. #endif
  97.         if(SUCCEEDED(hr))
  98.         {
  99.             SA_BSTR sstrURL;
  100.             StrCpyNW(sstrURL.wsz, wszUrl, ARRAYSIZE(sstrURL.wsz));
  101.             sstrURL.cb = lstrlenW(sstrURL.wsz) * SIZEOF(WCHAR);
  102.             VARIANT varURL;
  103.             varURL.vt = VT_BSTR;
  104.             varURL.bstrVal = sstrURL.wsz;
  105.             VARIANT varFlags;
  106.             varFlags.vt = VT_I4;
  107.             varFlags.lVal = 0;
  108.             hr = pwb2->Navigate2(&varURL, &varFlags, PVAREMPTY, PVAREMPTY, PVAREMPTY);
  109.             ASSERT(SUCCEEDED(hr)); // mikesh sez there's no way for Navigate2 to fail
  110.             hr = pwb2->put_Visible( TRUE );
  111.             pwb2->Release();
  112.         }
  113.     }
  114.     return hr;
  115. }
  116. HRESULT NavToUrlUsingIEA(LPCSTR szUrl, BOOL fNewWindow)
  117. {
  118.     WCHAR   wszUrl[INTERNET_MAX_URL_LENGTH];
  119.     AnsiToUnicode(szUrl, wszUrl, ARRAYSIZE(wszUrl));
  120.     return NavToUrlUsingIEW(wszUrl, fNewWindow);
  121. }
  122. STDAPI_(BSTR) SysAllocStringA(LPCSTR pszAnsiStr)
  123. {
  124.     OLECHAR *bstrOut = NULL;
  125.     LPWSTR pwzTemp;
  126.     UINT cchSize = (lstrlenA(pszAnsiStr) + 2);  // Count of characters
  127.     if (!pszAnsiStr)
  128.         return NULL;    // What the hell do you expect?
  129.     pwzTemp = (LPWSTR) LocalAlloc(LPTR, cchSize * sizeof(WCHAR));
  130.     if (pwzTemp)
  131.     {
  132.         SHAnsiToUnicode(pszAnsiStr, pwzTemp, cchSize);
  133.         bstrOut = SysAllocString(pwzTemp);
  134.         LocalFree(pwzTemp);
  135.     }
  136.     return bstrOut;
  137. }
  138. // MultiByteToWideChar doesn't truncate if the buffer is too small.
  139. // these utils do.
  140. // returns:
  141. //      # of chars converted (WIDE chars) into out buffer (pwstr)
  142. int _AnsiToUnicode(UINT uiCP, LPCSTR pstr, LPWSTR pwstr, int cch)
  143. {
  144.     int cchDst = 0;
  145.     ASSERT(IS_VALID_STRING_PTRA(pstr, -1));
  146.     ASSERT(NULL == pwstr || IS_VALID_WRITE_BUFFER(pwstr, WCHAR, cch));
  147.     if (cch && pwstr)
  148.         pwstr[0] = 0;
  149.     switch (uiCP)
  150.     {
  151.         case 1200:                      // UCS-2 (Unicode)
  152.             uiCP = 65001;
  153.             // fall through
  154.         case 50000:                     // "User Defined"
  155.         case 65000:                     // UTF-7
  156.         case 65001:                     // UTF-8
  157.         {
  158.             INT cchSrc, cchSrcOriginal;
  159.             cchSrc = cchSrcOriginal = lstrlenA(pstr) + 1;
  160.             cchDst = cch;
  161.             if (SUCCEEDED(ConvertINetMultiByteToUnicode(NULL, uiCP, pstr,
  162.                 &cchSrc, pwstr, &cchDst)) &&
  163.                 cchSrc < cchSrcOriginal)
  164.             {
  165.                 LPWSTR pwsz = (LPWSTR)LocalAlloc(LPTR, cchDst * SIZEOF(WCHAR));
  166.                 if (pwsz)
  167.                 {
  168.                     if (SUCCEEDED(ConvertINetMultiByteToUnicode( NULL, uiCP, pstr,
  169.                         &cchSrcOriginal, pwsz, &cchDst )))
  170.                     {
  171.                         StrCpyNW( pwstr, pwsz, cch );
  172.                         cchDst = cch;
  173.                     }
  174.                     LocalFree(pwsz);
  175.                 }
  176.             }
  177.             break;
  178.         }
  179.         default:
  180.             cchDst = MultiByteToWideChar(uiCP, 0, pstr, -1, pwstr, cch);
  181.             if (!cchDst) {
  182.                 // failed.
  183.                 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
  184.                     int cchNeeded = MultiByteToWideChar(uiCP, 0, pstr, -1, NULL, 0);
  185.                     if (cchNeeded) {
  186.                         LPWSTR pwsz = (LPWSTR)LocalAlloc(LPTR, cchNeeded * SIZEOF(WCHAR));
  187.                         if (pwsz) {
  188.                             cchDst = MultiByteToWideChar(uiCP, 0, pstr, -1, pwsz, cchNeeded);
  189.                             if (cchDst) {
  190.                                 StrCpyNW(pwstr, pwsz, cch);
  191.                                 cchDst = cch;
  192.                             }
  193.                             LocalFree(pwsz);
  194.                         }
  195.                     }
  196.                 }
  197.             }
  198.             break;
  199.     }
  200.     return cchDst;
  201. }
  202. #ifndef POSTPOSTSPLIT
  203. HRESULT ContextMenu_GetCommandStringVerb(IContextMenu *pcm, UINT idCmd, LPTSTR pszVerb, int cchVerb)
  204. {
  205.     HRESULT hres = E_FAIL;
  206.     // Try the WCHAR string first on NT systems
  207.     if (g_fRunningOnNT)
  208.     {
  209.         hres = pcm->GetCommandString(idCmd, GCS_VERBW, NULL, (LPSTR)pszVerb, cchVerb);
  210.     }
  211.     // Try the ANSI string next
  212.     if (FAILED(hres))
  213.     {
  214.         char szVerbAnsi[80];
  215.         hres = pcm->GetCommandString(idCmd, GCS_VERBA, NULL, szVerbAnsi, ARRAYSIZE(szVerbAnsi));
  216.         SHAnsiToTChar(szVerbAnsi, pszVerb, cchVerb);
  217.     }
  218.     return hres;
  219. }
  220. #endif
  221. UINT    g_cfURL = 0;
  222. UINT    g_cfFileDescA = 0;
  223. UINT    g_cfFileContents = 0;
  224. UINT    g_cfPreferedEffect = 0;
  225. #ifndef POSTPOSTSPLIT
  226. UINT    g_cfHIDA = 0;
  227. UINT    g_cfFileDescW = 0;
  228. #endif
  229. void InitClipboardFormats()
  230. {
  231.     if (g_cfURL == 0)
  232.     {
  233.         g_cfURL = RegisterClipboardFormat(CFSTR_SHELLURL);
  234.         g_cfFileDescA = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORA);
  235.         g_cfFileContents = RegisterClipboardFormat(CFSTR_FILECONTENTS);
  236.         g_cfPreferedEffect = RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT);
  237. #ifndef POSTPOSTSPLIT
  238.         g_cfHIDA = RegisterClipboardFormat(CFSTR_SHELLIDLIST);
  239.         g_cfFileDescW = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW);
  240. #endif
  241.     }
  242. }
  243. // BUGBUG [raymondc] use SHGlobalCounter
  244. // We need to use a cross process browser count.
  245. // We use a named semaphore.
  246. //
  247. EXTERN_C HANDLE g_hSemBrowserCount = NULL;
  248. #define SESSION_COUNT_SEMAPHORE_NAME "_ie_sessioncount"
  249. HANDLE GetSessionCountSemaphoreHandle()
  250. {
  251.     if (!g_hSemBrowserCount)
  252.     {
  253.         //
  254.         // Use the "A" version so it works on W95 w/o a wrapper.
  255.         //
  256.         // Too afraid to use CreateAllAccessSecurityAttributes because
  257.         // who knows what'll happen when two people with different
  258.         // security attributes try to access the same winlist...
  259.         g_hSemBrowserCount = CreateSemaphoreA(NULL, 0, 0x7FFFFFFF, SESSION_COUNT_SEMAPHORE_NAME);
  260.         if (!g_hSemBrowserCount)
  261.         {
  262.             ASSERT(GetLastError() == ERROR_ALREADY_EXISTS);
  263.             g_hSemBrowserCount = OpenSemaphoreA(SEMAPHORE_ALL_ACCESS,
  264.                                  FALSE, SESSION_COUNT_SEMAPHORE_NAME);
  265.         }
  266.     }
  267.     return g_hSemBrowserCount;
  268. }
  269. LONG GetSessionCount()
  270. {
  271.     LONG lPrevCount = 0x7FFFFFFF;
  272.     HANDLE hSem = GetSessionCountSemaphoreHandle();
  273.     ASSERT(hSem);
  274.     if(hSem)
  275.     {
  276.         ReleaseSemaphore(hSem, 1, &lPrevCount);
  277.         WaitForSingleObject(hSem, 0);
  278.     }
  279.     return lPrevCount;
  280. }
  281. LONG IncrementSessionCount()
  282. {
  283.     LONG lPrevCount = 0x7FFFFFFF;
  284.     HANDLE hSem = GetSessionCountSemaphoreHandle();
  285.     ASSERT(hSem);
  286.     if(hSem)
  287.     {
  288.         ReleaseSemaphore(hSem, 1, &lPrevCount);
  289.     }
  290.     return lPrevCount;
  291. }
  292. LONG DecrementSessionCount()
  293. {
  294.     LONG lPrevCount = 0x7FFFFFFF;
  295.     HANDLE hSem = GetSessionCountSemaphoreHandle();
  296.     ASSERT(hSem);
  297.     if(hSem)
  298.     {
  299.         ReleaseSemaphore(hSem, 1, &lPrevCount); // increment first to make sure deadlock
  300.                                                  // never occurs
  301.         ASSERT(lPrevCount > 0);
  302.         if(lPrevCount > 0)
  303.         {
  304.             WaitForSingleObject(hSem, 0);
  305.             WaitForSingleObject(hSem, 0);
  306.             lPrevCount--;
  307.         }
  308.         else
  309.         {
  310.             // Oops - Looks like a bug !
  311.             // Just return it back to normal and leave
  312.             WaitForSingleObject(hSem, 0);
  313.         }
  314.     }
  315.     return lPrevCount;
  316. }
  317. //
  318. // The following is the message that autodial monitors expect to receive
  319. // when it's a good time to hang up
  320. //
  321. #define WM_IEXPLORER_EXITING    (WM_USER + 103)
  322. long SetQueryNetSessionCount(enum SessionOp Op)
  323. {
  324.     long lCount = 0;
  325.     
  326.     switch(Op) {
  327.         case SESSION_QUERY:
  328.             lCount = GetSessionCount();
  329.             TraceMsg(DM_SESSIONCOUNT, "SetQueryNetSessionCount SessionCount=%d (query)", lCount);
  330.             break;
  331.         case SESSION_INCREMENT_NODEFAULTBROWSERCHECK:
  332.         case SESSION_INCREMENT:
  333.             lCount = IncrementSessionCount();
  334.             TraceMsg(DM_SESSIONCOUNT, "SetQueryNetSessionCount SessionCount=%d (incr)", lCount);
  335.             
  336.             if ((PLATFORM_INTEGRATED == WhichPlatform()))
  337.             {
  338.                 // Weird name here... But in integrated mode we make every new browser window
  339.                 // look like a new session wrt how we use the cache. Basically this is the way things appear to the
  340.                 // user. This effects the way we look for new pages vs doing an if modified
  341.                 // since.  The ie3/ie4 switch says "look for new pages on each session start"
  342.                 // but wininet folks implemented this as a end session name. Woops.
  343.                 // Note that things like authentication etc aren't reset by this, but rather
  344.                 // only when all browsers are closed via the INTERNET_OPTION_END_BROWSER_SESSION option.
  345.                 InternetSetOption(NULL, INTERNET_OPTION_RESET_URLCACHE_SESSION, NULL, 0);
  346.             }
  347.             if (!lCount && (Op == SESSION_INCREMENT))
  348.             {
  349.                 // this forces a reload of the title
  350.                 DetectAndFixAssociations();
  351.             }
  352.             break;
  353.         case SESSION_DECREMENT:
  354.             lCount = DecrementSessionCount();
  355.             TraceMsg(DM_SESSIONCOUNT, "SetQueryNetSessionCount SessionCount=%d (decr)", lCount);
  356.             if(!lCount) {
  357.                 // if we've closed all the net browsers, we need to flush the cache
  358.                 InternetSetOption(NULL, INTERNET_OPTION_END_BROWSER_SESSION, NULL, 0);
  359.                 InternetSetOption(NULL, INTERNET_OPTION_RESET_URLCACHE_SESSION, NULL, 0);
  360.                 // flush the Java VM cache too (if the Java VM is loaded in this process
  361.                 // and we're in integrated mode)
  362.                 if (WhichPlatform() == PLATFORM_INTEGRATED)
  363.                 {
  364.                     HMODULE hmod = GetModuleHandle(TEXT("msjava.dll"));
  365.                     if (hmod)
  366.                     {
  367.                         typedef HRESULT (*PFNNOTIFYBROWSERSHUTDOWN)(LPVOID);
  368.                         FARPROC fp = GetProcAddress(hmod, "NotifyBrowserShutdown");
  369.                         if (fp)
  370.                         {
  371.                             HRESULT hr = ((PFNNOTIFYBROWSERSHUTDOWN)fp)(NULL);
  372.                             ASSERT(SUCCEEDED(hr));
  373.                         }
  374.                     }
  375.                 }
  376.                 // Inform dial monitor that it's a good time to hang up
  377.                 HWND hwndMonitorWnd = FindWindow(TEXT("MS_AutodialMonitor"),NULL);
  378.                 if (hwndMonitorWnd) {
  379.                     PostMessage(hwndMonitorWnd,WM_IEXPLORER_EXITING,0,0);
  380.                 }
  381.                 hwndMonitorWnd = FindWindow(TEXT("MS_WebcheckMonitor"),NULL);
  382.                 if (hwndMonitorWnd) {
  383.                     PostMessage(hwndMonitorWnd,WM_IEXPLORER_EXITING,0,0);
  384.                 }
  385.                 // reset offline mode on all platforms except Win2K.
  386.                 OSVERSIONINFOA vi;
  387.                 vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
  388.                 GetVersionExA(&vi);
  389.                 if( vi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS ||
  390.                     vi.dwMajorVersion < 5)
  391.                 {
  392.                     // wininet is loaded - tell it to go online
  393.                     INTERNET_CONNECTED_INFO ci;
  394.                     memset(&ci, 0, sizeof(ci));
  395.                     ci.dwConnectedState = INTERNET_STATE_CONNECTED;
  396.                     InternetSetOption(NULL, INTERNET_OPTION_CONNECTED_STATE, &ci, sizeof(ci));
  397.                 }
  398.             }
  399.             break;
  400.     }
  401.     return lCount;
  402. }
  403. #ifdef DEBUG
  404. //---------------------------------------------------------------------------
  405. // Copy the exception info so we can get debug info for Raised exceptions
  406. // which don't go through the debugger.
  407. void _CopyExceptionInfo(LPEXCEPTION_POINTERS pep)
  408. {
  409.     PEXCEPTION_RECORD per;
  410.     per = pep->ExceptionRecord;
  411.     TraceMsg(DM_ERROR, "Exception %x at %#08x.", per->ExceptionCode, per->ExceptionAddress);
  412.     if (per->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
  413.     {
  414.         // If the first param is 1 then this was a write.
  415.         // If the first param is 0 then this was a read.
  416.         if (per->ExceptionInformation[0])
  417.         {
  418.             TraceMsg(DM_ERROR, "Invalid write to %#08x.", per->ExceptionInformation[1]);
  419.         }
  420.         else
  421.         {
  422.             TraceMsg(DM_ERROR, "Invalid read of %#08x.", per->ExceptionInformation[1]);
  423.         }
  424.     }
  425. }
  426. #else
  427. #define _CopyExceptionInfo(x) TRUE
  428. #endif
  429. int WELCallback(LPVOID p, LPVOID pData)
  430. {
  431.     STATURL* pstat = (STATURL*)p;
  432.     if (pstat->pwcsUrl) {
  433.         OleFree(pstat->pwcsUrl);
  434.     }
  435.     return 1;
  436. }
  437. int CALLBACK WELCompare(LPVOID p1, LPVOID p2, LPARAM lParam)
  438. {
  439.     HDSA hdsa = (HDSA)lParam;
  440.     // Sundown: coercion to long because parameter is an index
  441.     STATURL* pstat1 = (STATURL*)DSA_GetItemPtr(hdsa, PtrToLong(p1));
  442.     STATURL* pstat2 = (STATURL*)DSA_GetItemPtr(hdsa, PtrToLong(p2));
  443.     if (pstat1 && pstat2) {
  444.         return CompareFileTime(&pstat2->ftLastVisited, &pstat1->ftLastVisited);
  445.     }
  446.     ASSERT(0);
  447.     return 0;
  448. }
  449. #define MACRO_STR(x) #x
  450. #define VERSION_HEADER_STR "Microsoft Internet Explorer 5.0 Error Log -- " 
  451.                            MACRO_STR(VER_MAJOR_PRODUCTVER) "." 
  452.                            MACRO_STR(VER_MINOR_PRODUCTVER) "." 
  453.                            MACRO_STR(VER_PRODUCTBUILD) "." 
  454.                            MACRO_STR(VER_PRODUCTBUILD_QFE) "rn"
  455. void IEWriteErrorLog(const EXCEPTION_RECORD* pexr)
  456. {
  457.     HANDLE hfile = INVALID_HANDLE_VALUE;
  458.     _try
  459.     {
  460.         //
  461.         // Post a message to the MTTF tool if running
  462.         //
  463.         PostMTTFMessage(MTTF_CRASHTRAPPED);
  464.         TCHAR szWindows[MAX_PATH];
  465.         GetWindowsDirectory(szWindows, ARRAYSIZE(szWindows));
  466.         PathAppend(szWindows, TEXT("IE4 Error Log.txt"));
  467.         HANDLE hfile = CreateFile(szWindows, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  468.         if(hfile != INVALID_HANDLE_VALUE)
  469.         {
  470.             const static CHAR c_szCRLF[] = "rn";
  471.             DWORD cbWritten;
  472.             CHAR szBuf[MAX_URL_STRING];
  473.             // Write the title and product version.
  474.             WriteFile(hfile, VERSION_HEADER_STR, lstrlenA(VERSION_HEADER_STR), &cbWritten, NULL);
  475.             // Write the current time.
  476.             SYSTEMTIME st;
  477.             FILETIME ft;
  478.             GetSystemTime(&st);
  479.             SystemTimeToFileTime(&st, &ft);
  480.             SHFormatDateTimeA(&ft, NULL, szBuf, SIZECHARS(szBuf));
  481.             const static CHAR c_szCurrentTime[] = "CurrentTime: ";
  482.             WriteFile(hfile, c_szCurrentTime, SIZEOF(c_szCurrentTime)-1, &cbWritten, NULL);
  483.             WriteFile(hfile, szBuf, lstrlenA(szBuf), &cbWritten, NULL);
  484.             WriteFile(hfile, c_szCRLF, SIZEOF(c_szCRLF)-1, &cbWritten, NULL);
  485.             if (pexr) {
  486.                 const static CHAR c_szExcCode[] = "Exception Info: Code=%x Flags=%x Address=%xrn";
  487.                 const static CHAR c_szExcParam[] = "Exception Param:";
  488.                 wnsprintfA(szBuf, ARRAYSIZE(szBuf), c_szExcCode, pexr->ExceptionCode, pexr->ExceptionFlags, pexr->ExceptionAddress);
  489.                 WriteFile(hfile, szBuf, lstrlenA(szBuf), &cbWritten, NULL);
  490.                 if (pexr->NumberParameters) {
  491.                     WriteFile(hfile, c_szExcParam, SIZEOF(c_szExcParam)-1, &cbWritten, NULL);
  492.                     for (UINT iParam=0; iParam<pexr->NumberParameters; iParam++) {
  493.                         wnsprintfA(szBuf, ARRAYSIZE(szBuf), " %x", pexr->ExceptionInformation[iParam]);
  494.                         WriteFile(hfile, szBuf, lstrlenA(szBuf), &cbWritten, NULL);
  495.                     }
  496.                 }
  497.                 WriteFile(hfile, c_szCRLF, SIZEOF(c_szCRLF)-1, &cbWritten, NULL);
  498.                 WriteFile(hfile, c_szCRLF, SIZEOF(c_szCRLF)-1, &cbWritten, NULL);
  499.             }
  500.             IUrlHistoryStg* pUrlHistStg;
  501.             HRESULT hres = CoCreateInstance(CLSID_CUrlHistory, NULL, CLSCTX_INPROC_SERVER,
  502.                 IID_IUrlHistoryStg, (void **)&pUrlHistStg);
  503.             if (SUCCEEDED(hres)) {
  504.                 IEnumSTATURL* penum;
  505.                 hres = pUrlHistStg->EnumUrls(&penum);
  506.                 if (SUCCEEDED(hres)) {
  507.                     // Allocate DSA for an array of STATURL
  508.                     HDSA hdsa = DSA_Create(SIZEOF(STATURL), 32);
  509.                     if (hdsa) {
  510.                         // Allocate DPA for sorting
  511.                         HDPA hdpa = DPA_Create(32);
  512.                         if (hdpa) {
  513.                             STATURL stat;
  514.                             stat.cbSize = SIZEOF(stat.cbSize);
  515.                             while(penum->Next(1, &stat, NULL)==S_OK && stat.pwcsUrl) {
  516.                                 DSA_AppendItem(hdsa, &stat);
  517.                                 DPA_AppendPtr(hdpa, (LPVOID)(DSA_GetItemCount(hdsa)-1));
  518.                             }
  519.                             DPA_Sort(hdpa, WELCompare, (LPARAM)hdsa);
  520.                             for (int i=0; i<10 && i<DPA_GetPtrCount(hdpa) ; i++) {
  521.                                 // Sundown: typecast to long is OK
  522.                                 STATURL* pstat = (STATURL*)DSA_GetItemPtr(hdsa, PtrToLong(DPA_GetPtr(hdpa, i)));
  523.                                 if (pstat && pstat->pwcsUrl) {
  524.                                     SHFormatDateTimeA(&pstat->ftLastVisited, NULL, szBuf, SIZECHARS(szBuf));
  525.                                     WriteFile(hfile, szBuf, lstrlenA(szBuf), &cbWritten, NULL);
  526.                                     const static TCHAR c_szColumn[] = TEXT(" -- ");
  527.                                     WriteFile(hfile, c_szColumn, SIZEOF(c_szColumn)-1, &cbWritten, NULL);
  528.                                     WideCharToMultiByte(CP_ACP, 0, pstat->pwcsUrl, -1,
  529.                                                         szBuf, ARRAYSIZE(szBuf), NULL, NULL);
  530.                                     WriteFile(hfile, szBuf, lstrlenA(szBuf), &cbWritten, NULL);
  531.                                     WriteFile(hfile, c_szCRLF, SIZEOF(c_szCRLF)-1, &cbWritten, NULL);
  532.                                 } else {
  533.                                     ASSERT(0);
  534.                                 }
  535.                             }
  536.                             DPA_Destroy(hdpa);
  537.                         }
  538.                         DSA_DestroyCallback(hdsa, WELCallback, NULL);
  539.                     }
  540.                     penum->Release();
  541.                 } else {
  542.                     ASSERT(0);
  543.                 }
  544.                 pUrlHistStg->Release();
  545.             } else {
  546.                 ASSERT(0);
  547.             }
  548.             CloseHandle( hfile );
  549.             hfile = INVALID_HANDLE_VALUE;
  550.         }
  551.     }
  552.     _except((SetErrorMode(SEM_NOGPFAULTERRORBOX),
  553.             _CopyExceptionInfo(GetExceptionInformation()),
  554.             UnhandledExceptionFilter(GetExceptionInformation())
  555.             ))
  556.     {
  557.         // We hit an exception while handling an exception.
  558.         // Do nothing; we have already displayed the error dialog box.
  559.         if(hfile != INVALID_HANDLE_VALUE) {
  560.             CloseHandle(hfile);
  561.         }
  562.     }
  563.     __endexcept
  564. }
  565. int CDECL MRUILIsEqual(const void *pidl1, const void *pidl2, size_t cb)
  566. {
  567.     // First cheap hack to see if they are 100 percent equal for performance
  568.     int iCmp = memcmp(pidl1, pidl2, cb);
  569.     if (iCmp == 0)
  570.         return 0;
  571.     if (ILIsEqual((LPITEMIDLIST)pidl1, (LPITEMIDLIST)pidl2))
  572.         return 0;
  573.     return iCmp;
  574. }
  575. IStream* SHGetViewStream(LPCITEMIDLIST pidl, DWORD grfMode, LPCTSTR pszName, LPCTSTR pszStreamMRU, LPCTSTR pszStreams)
  576. {
  577.     IStream *pstm = NULL;
  578.     HANDLE hmru;
  579.     int iFoundSlot = -1;
  580.     UINT cbPidl;
  581.     static DWORD s_dwMRUSize = 0;
  582.     DWORD dwSize = sizeof(s_dwMRUSize);
  583.     if ((0 == s_dwMRUSize) &&
  584.         (ERROR_SUCCESS != SHGetValue(HKEY_CURRENT_USER, pszStreamMRU, TEXT("MRU Size"), NULL, (LPVOID) &s_dwMRUSize, &dwSize)))
  585.     {
  586.         s_dwMRUSize = 200;          // The default.
  587.     }
  588.     MRUINFO mi = {
  589.         SIZEOF(MRUINFO),
  590.         s_dwMRUSize,                     // we store this many view streams
  591.         MRU_BINARY,
  592.         HKEY_CURRENT_USER,
  593.         pszStreamMRU,
  594.         (MRUCMPPROC)MRUILIsEqual,
  595.     };
  596.     ASSERT(pidl);
  597.     // should be checked by caller - if this is not true we'll flush the
  598.     // MRU cache with internet pidls!  FTP and other URL Shell Extension PIDLs
  599.     // that act like a folder and need similar persistence and fine.  This
  600.     // is especially true because recently the cache size was increased from
  601.     // 30 or so to 200.
  602.     ASSERT(ILIsEqual(pidl, c_pidlURLRoot) || !IsBrowserFrameOptionsPidlSet(pidl, BFO_BROWSER_PERSIST_SETTINGS));
  603.     cbPidl = ILGetSize(pidl);
  604.     // Now lets try to save away the other information associated with view.
  605.     hmru = CreateMRUListLazyEx(&mi, pidl, cbPidl, &iFoundSlot);
  606.     if (!hmru)
  607.         return NULL;
  608.     // Did we find the item?
  609.     if (iFoundSlot < 0 && ((grfMode & (STGM_READ|STGM_WRITE|STGM_READWRITE)) == STGM_READ))
  610.     {
  611.         // Do not  create the stream if it does not exist and we are
  612.         // only reading
  613.     }
  614.     else
  615.     {
  616.         HKEY hkCabStreams;
  617.         TCHAR szRegPath[MAX_PATH];
  618.         StrCpyN(szRegPath, REGSTR_PATH_EXPLORER TEXT("\"), ARRAYSIZE(szRegPath));
  619.         StrCatBuff(szRegPath, pszStreams, ARRAYSIZE(szRegPath));
  620.         // Note that we always create the key here, since we have
  621.         // already checked whether we are just reading and the MRU
  622.         // thing does not exist
  623.         if (RegCreateKey(HKEY_CURRENT_USER, szRegPath, &hkCabStreams) == ERROR_SUCCESS)
  624.         {
  625.             HKEY hkValues;
  626.             TCHAR szValue[32], szSubVal[64];
  627.             wnsprintf(szValue, ARRAYSIZE(szValue), TEXT("%d"), AddMRUDataEx(hmru, pidl, cbPidl));
  628.             if (iFoundSlot < 0 && RegOpenKey(hkCabStreams, szValue, &hkValues) == ERROR_SUCCESS)
  629.             {
  630.                 // This means that we have created a new MRU
  631.                 // item for this PIDL, so clear out any
  632.                 // information residing at this slot
  633.                 // Note that we do not just delete the key,
  634.                 // since that could fail if it has any sub-keys
  635.                 DWORD dwType, dwSize = ARRAYSIZE(szSubVal);
  636.                 while (RegEnumValue(hkValues, 0, szSubVal, &dwSize, NULL, &dwType, NULL, NULL) == ERROR_SUCCESS)
  637.                 {
  638.                     if (RegDeleteValue(hkValues, szSubVal) != ERROR_SUCCESS)
  639.                     {
  640.                         break;
  641.                     }
  642.                 }
  643.                 RegCloseKey(hkValues);
  644.             }
  645.             pstm = OpenRegStream(hkCabStreams, szValue, pszName, grfMode);
  646.             RegCloseKey(hkCabStreams);
  647.         }
  648.     }
  649.     FreeMRUListEx(hmru);
  650.     return pstm;
  651. }
  652. #define c_szExploreClass TEXT("ExploreWClass")
  653. #define c_szIExploreClass TEXT("IEFrame")
  654. #ifdef IE3CLASSNAME
  655. #define c_szCabinetClass TEXT("IEFrame")
  656. #else
  657. #define c_szCabinetClass TEXT("CabinetWClass")
  658. #endif
  659. BOOL IsNamedWindow(HWND hwnd, LPCTSTR pszClass)
  660. {
  661.     TCHAR szClass[32];
  662.     GetClassName(hwnd, szClass, ARRAYSIZE(szClass));
  663.     return StrCmp(szClass, pszClass) == 0;
  664. }
  665. BOOL IsTrayWindow(HWND hwnd)
  666. {
  667.     return IsNamedWindow(hwnd, TEXT(WNDCLASS_TRAYNOTIFY));
  668. }
  669. BOOL IsExplorerWindow(HWND hwnd)
  670. {
  671.     return IsNamedWindow(hwnd, c_szExploreClass);
  672. }
  673. BOOL IsFolderWindow(HWND hwnd)
  674. {
  675.     TCHAR szClass[32];
  676.     GetClassName(hwnd, szClass, ARRAYSIZE(szClass));
  677.     return (StrCmp(szClass, c_szCabinetClass) == 0) || (StrCmp(szClass, c_szIExploreClass) == 0);
  678. }
  679. HRESULT _SendOrPostDispatchMessage(HWND hwnd, WPARAM wParam, LPARAM lParam, BOOL fPostMessage, BOOL fCheckFirst)
  680. {
  681.     HRESULT hr = HRESULT_FROM_WIN32(ERROR_BUSY);
  682.     DWORD idProcess;
  683.     // in case of wParam = DSID_NAVIGATEIEBROWSER, lParam is LocalAlloced structure
  684.     // so we better make sure we are in process 'coz otherwise will fault
  685.     GetWindowThreadProcessId(hwnd, &idProcess);
  686.     if (idProcess == GetCurrentProcessId() && IsWindowEnabled(hwnd) && IsWindowVisible(hwnd))
  687.     {
  688.         if (!fPostMessage || fCheckFirst)
  689.         {
  690.             //  sync or we are querying the windows readiness
  691.             ULONG_PTR result;
  692.             if (SendMessageTimeoutA(hwnd, WMC_DISPATCH, (fCheckFirst ? DSID_NOACTION : wParam),
  693.                 lParam, SMTO_ABORTIFHUNG, 400, &result))
  694.                 hr = (HRESULT) result;
  695.         }
  696.         //  handle the post only if the window was ready
  697.         if (fPostMessage && (!fCheckFirst || SUCCEEDED(hr)))
  698.             hr = (PostMessage(hwnd, WMC_DISPATCH, wParam, lParam) ? S_OK : E_FAIL);
  699.     }
  700.     return hr;
  701. }
  702. //---------------------------------------------------------------------------
  703. HRESULT FindBrowserWindowOfClass(LPCTSTR pszClass, WPARAM wParam, LPARAM lParam, BOOL fPostMessage, HWND* phwnd)
  704. {
  705.     //If there is no window, assume the user is in the process of shutting down IE, and return E_FAIL
  706.     //Otherwise, if there is at least one window, start cycling through the windows until you find
  707.     //one that's not busy, and give it our message.  If all are busy, return
  708.     //HRESULT_FROM_WIN32(ERROR_BUSY)
  709.     HWND hwnd = NULL;
  710.     HRESULT hr = E_FAIL;
  711.     while (FAILED(hr)
  712.         && (hwnd = FindWindowEx(NULL, hwnd, pszClass, NULL)) != NULL)
  713.     {
  714.         hr = _SendOrPostDispatchMessage(hwnd, wParam, lParam, fPostMessage, fPostMessage);
  715.     }
  716.     *phwnd = hwnd;
  717.     return hr;
  718. }
  719. //This common function gets called when the DDE engine doesn't seem to care in which window something
  720. //happens.  It returns in which window that something happened.  0 means all windows are busy.
  721. //
  722. //phwnd: a pointer the hwnd to which to send the message.  <= 0 means any window will do.
  723. //       this is also an out parameter that specifies in which window it happened.
  724. //fPostMessage: when doing navigations, we have to do a PostMessage instead of a SendMessageTimeout
  725. //       or a CoCreateInstance later on in CDocObjectHost::_BindFileMoniker will fail.  So when
  726. //       this function is called from CDDEAuto_Navigate, we make this flag TRUE
  727. HRESULT CDDEAuto_Common(WPARAM wParam, LPARAM lParam, HWND *phwnd, BOOL fPostMessage)
  728. {
  729.     HRESULT hr = HRESULT_FROM_WIN32(ERROR_BUSY);
  730.     HWND hwnd;
  731.     //if we're told to go to a specific window
  732.     if (phwnd && (*phwnd != (HWND)-1))
  733.     {
  734.         hr = _SendOrPostDispatchMessage(*phwnd, wParam, lParam, fPostMessage, FALSE);
  735.     }
  736.     if (HRESULT_FROM_WIN32(ERROR_BUSY) == hr)
  737.     {
  738.         hr = FindBrowserWindowOfClass(c_szIExploreClass, wParam, lParam, fPostMessage, &hwnd);
  739.         if (!hwnd)
  740.             hr = FindBrowserWindowOfClass(c_szCabinetClass, wParam, lParam, fPostMessage, &hwnd);
  741.         if (phwnd)
  742.             *phwnd = hwnd;
  743.     }
  744.     return hr;
  745. }
  746. //
  747. //  Before changing the behavior of this function look at itemmenu.cpp in
  748. //  cdfview.
  749. //
  750. HRESULT CDDEAuto_Navigate(BSTR str, HWND *phwnd, long) //the long is for lTransID, which is currently
  751.                                                        //turned off
  752. {
  753.     DDENAVIGATESTRUCT *pddens = NULL;
  754.     HRESULT hres = E_FAIL;
  755.     if (phwnd == NULL)
  756.         return E_INVALIDARG;
  757.     pddens = new DDENAVIGATESTRUCT;
  758.     if (!pddens)
  759.         hres = E_OUTOFMEMORY;
  760.     else
  761.     {
  762.         pddens->wszUrl = StrDupW(str);
  763.         if (!pddens->wszUrl)
  764.             hres = E_OUTOFMEMORY;
  765.         else
  766.         {
  767.             // Don't do the navigate if *phwnd == 0, in that case we want to either
  768.             // create a new window or activate an existing one that already is viewing
  769.             // this URL.
  770.             
  771.             if (*phwnd != NULL)
  772.             {
  773.                 BOOL fForceWindowReuse = FALSE;
  774.                 BSTR bstrUrl = NULL;
  775.                 // If there is even a single window with a location 
  776.                 // you are basically assured that you cannot force a 
  777.                 // reuse of windows. essentially
  778.                // case 1 : only iexplore -nohome windows implies we want to force reuse
  779.                // case 2 : only windows that have a location - we don't want to force reuse
  780.                //          just follow user's preference
  781.                // case 3: mix of iexplore -nohome windows and windows with location. we don't
  782.                //         know what state we are in - don't force reuse
  783.                 hres = CDDEAuto_get_LocationURL(&bstrUrl, *phwnd);
  784.                 if(FAILED(hres) ||
  785.                    (!bstrUrl)   ||
  786.                    (SUCCEEDED(hres) && (*bstrUrl == L'')))
  787.                 {
  788.                     fForceWindowReuse = TRUE;
  789.                 }
  790.                 if(bstrUrl)
  791.                     SysFreeString(bstrUrl);
  792.                     
  793.                 if( !(GetAsyncKeyState(VK_SHIFT) < 0)
  794.                     && (fForceWindowReuse || SHRegGetBoolUSValue(REGSTR_PATH_MAIN, TEXT("AllowWindowReuse"), FALSE, TRUE)))
  795.                 {
  796.                     hres = CDDEAuto_Common(DSID_NAVIGATEIEBROWSER, (LPARAM)pddens, phwnd, FALSE);
  797.                 }
  798.             }
  799.             
  800.             if (SUCCEEDED(hres) && (*phwnd != 0) && (*phwnd != (HWND)-1))
  801.             {
  802.                 // We found an existing browser window and successfully sent the
  803.                 // navigate message to it. Make the window foreground.
  804.                 SetForegroundWindow(*phwnd);
  805.                 if (IsIconic(*phwnd))
  806.                     ShowWindowAsync(*phwnd,SW_RESTORE);
  807.             }
  808.             //
  809.             // If we are using whatever window and all the browser windows are busy
  810.             // (*phwnd == 0), or if there's no browser window opened (*phwnd == -1)
  811.             // or we are asked to create a new one, then take the official OLE automation
  812.             // route to start a new window.
  813.             //
  814.             if ((*phwnd == 0) ||
  815.                 (*phwnd == (HWND)-1))
  816.             {
  817.                 //BUGBUG: this route doesn't give us the ability to return the hwnd of the window
  818.                 //in which the navigation took place (while we could - it's too hard and not worth it)
  819.                 LPITEMIDLIST pidlNew;
  820.                 TCHAR szURL[MAX_URL_STRING];
  821.                 OleStrToStrN(szURL, ARRAYSIZE(szURL), str, (UINT)-1);
  822.                 hres = IECreateFromPath(szURL, &pidlNew);
  823.                 if (SUCCEEDED(hres))
  824.                 {
  825.                     // See if there is already a browser viewing this URL, if so just
  826.                     // make him foreground otherwise create a new browser.
  827.                     if ((hres = WinList_FindFolderWindow(pidlNew, NULL, phwnd, NULL)) == S_OK)
  828.                     {
  829.                         ILFree(pidlNew);
  830.                         SetForegroundWindow(*phwnd);
  831.                         ShowWindow(*phwnd, SW_SHOWNORMAL);
  832.                     }
  833.                     else
  834.                     {
  835.                         SHOpenNewFrame(pidlNew, NULL, 0, 0);
  836.                     }
  837.                 }
  838.             }
  839.         }
  840.         // It will be set to NULL if we don't need to free it.
  841.         if (pddens)
  842.         {
  843.             if (pddens->wszUrl)
  844.             {
  845.                 LocalFree(pddens->wszUrl);
  846.             }
  847.             delete pddens;
  848.         }    
  849.     }
  850.     return hres;
  851. }
  852. HRESULT CDDEAuto_get_LocationURL(BSTR * pstr, HWND hwnd)
  853. {
  854.     return CDDEAuto_Common(DSID_GETLOCATIONURL, (LPARAM)pstr, &hwnd, FALSE);
  855. }
  856. HRESULT CDDEAuto_get_LocationTitle(BSTR * pstr, HWND hwnd)
  857. {
  858.     return CDDEAuto_Common(DSID_GETLOCATIONTITLE, (LPARAM)pstr, &hwnd, FALSE);
  859. }
  860. HRESULT CDDEAuto_get_HWND(long * phwnd)
  861. {
  862.     return CDDEAuto_Common(DSID_GETHWND, (LPARAM)phwnd, NULL, FALSE);
  863. }
  864. HRESULT CDDEAuto_Exit()
  865. {
  866.     return CDDEAuto_Common(DSID_EXIT, (LPARAM)NULL, NULL, FALSE);
  867. }
  868. #ifndef POSTPOSTSPLIT
  869. #define DXTRACK 1
  870. void FrameTrack(HDC hdc, LPRECT prc, UINT uFlags)
  871. {
  872.     COLORREF clrSave, clr;
  873.     RECT    rc;
  874.     // upperleft
  875.     switch (uFlags)
  876.     {
  877.     case TRACKHOT:
  878.         clr = GetSysColor(COLOR_BTNHILIGHT);
  879.         break;
  880.     case TRACKNOCHILD:
  881.     case TRACKEXPAND:
  882.         clr = GetSysColor(COLOR_BTNSHADOW);
  883.         break;
  884.     default:
  885.         ASSERT(FALSE);
  886.         clr = GetSysColor(COLOR_BTNSHADOW);
  887.         break;
  888.     }
  889.     clrSave = SetBkColor(hdc, clr);
  890.     rc = *prc;
  891.     rc.bottom = rc.top + DXTRACK;
  892.     ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
  893.     rc.bottom = prc->bottom;
  894.     rc.right = rc.left + DXTRACK;
  895.     rc.top = prc->top + DXTRACK;
  896.     ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
  897.     // lowerright
  898.     switch (uFlags)
  899.     {
  900.     case TRACKHOT:
  901.         clr = GetSysColor(COLOR_BTNSHADOW);
  902.         break;
  903.     case TRACKNOCHILD:
  904.     case TRACKEXPAND:
  905.         clr = GetSysColor(COLOR_BTNHILIGHT);
  906.         break;
  907.     default:
  908.         ASSERT(FALSE);
  909.         break;
  910.     }
  911.     SetBkColor(hdc, clr);
  912.     if (uFlags & (TRACKHOT | TRACKNOCHILD))
  913.     {
  914.         rc.right = prc->right;
  915.         rc.top = rc.bottom - DXTRACK;
  916.         rc.left = prc->left;
  917.         ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
  918.     }
  919.     rc.right = prc->right;
  920.     rc.left = prc->right - DXTRACK;
  921.     rc.top = prc->top;
  922.     rc.bottom = prc->bottom;
  923.     ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
  924.     SetBkColor(hdc, clrSave);
  925.     return;
  926. }
  927. #endif
  928. #undef new // Hack!! Need to remove this (edwardp)
  929. class CDelagateMalloc : public IMalloc
  930. {
  931. public:
  932.     // IUnknown
  933.     virtual STDMETHODIMP QueryInterface(REFIID,void **);
  934.     virtual STDMETHODIMP_(ULONG) AddRef(void);
  935.     virtual STDMETHODIMP_(ULONG) Release(void);
  936.     // IMalloc
  937.     virtual STDMETHODIMP_(LPVOID)   Alloc(SIZE_T cb);
  938.     virtual STDMETHODIMP_(LPVOID)   Realloc(void *pv, SIZE_T cb);
  939.     virtual STDMETHODIMP_(void)     Free(void *pv);
  940.     virtual STDMETHODIMP_(SIZE_T)    GetSize(void *pv);
  941.     virtual STDMETHODIMP_(int)      DidAlloc(void *pv);
  942.     virtual STDMETHODIMP_(void)     HeapMinimize();
  943. private:
  944.     CDelagateMalloc(void *pv, SIZE_T cbSize, WORD wOuter);
  945.     ~CDelagateMalloc();
  946.     void* operator new(size_t cbClass, SIZE_T cbSize);
  947.     friend HRESULT CDelegateMalloc_Create(void *pv, SIZE_T cbSize, WORD wOuter, IMalloc **ppmalloc);
  948. protected:
  949.     LONG _cRef;
  950.     WORD _wOuter;           // delegate item outer signature
  951.     WORD _wUnused;          // to allign
  952. #ifdef DEBUG
  953.     UINT _cAllocs;
  954. #endif
  955.     SIZE_T _cb;
  956.     BYTE _data[EMPTY_SIZE];
  957. };
  958. void* CDelagateMalloc::operator new(size_t cbClass, SIZE_T cbSize)
  959. {
  960.     return ::operator new(cbClass + cbSize);
  961. }
  962. CDelagateMalloc::CDelagateMalloc(void *pv, SIZE_T cbSize, WORD wOuter)
  963. {
  964.     _cRef = 1;
  965.     _wOuter = wOuter;
  966.     _cb = cbSize;
  967.     memcpy(_data, pv, _cb);
  968. }
  969. CDelagateMalloc::~CDelagateMalloc()
  970. {
  971.     // This isn't something we need to worry about and it causes way
  972.     // too much noise. -BryanSt
  973. //    DEBUG_CODE( TraceMsg(DM_TRACE, "DelegateMalloc destroyed with %d allocs performed", _cAllocs); )
  974. }
  975. HRESULT CDelagateMalloc::QueryInterface(REFIID riid, void **ppvObj)
  976. {
  977.     if (IsEqualIID(riid, IID_IMalloc) || IsEqualIID(riid, IID_IUnknown))
  978.     {
  979.         *ppvObj = SAFECAST(this, IMalloc *);
  980.     }
  981.     else
  982.     {
  983.         *ppvObj = NULL;
  984.         return E_NOINTERFACE;
  985.     }
  986.     AddRef();
  987.     return S_OK;
  988. }
  989. ULONG CDelagateMalloc::AddRef()
  990. {
  991.     return InterlockedIncrement(&_cRef);
  992. }
  993. ULONG CDelagateMalloc::Release()
  994. {
  995.     if (InterlockedDecrement(&_cRef))
  996.         return _cRef;
  997.     delete this;
  998.     return 0;
  999. }
  1000. void *CDelagateMalloc::Alloc(SIZE_T cb)
  1001. {
  1002.     WORD cbActualSize = (WORD)(
  1003.                         SIZEOF(DELEGATEITEMID) - 1 +    // header (-1 sizeof(rgb[0])
  1004.                         cb +                            // inner
  1005.                         _cb);                           // outer data
  1006.     PDELEGATEITEMID pidl = (PDELEGATEITEMID)SHAlloc(cbActualSize + 2);  // +2 for pidl term
  1007.     if (pidl)
  1008.     {
  1009.         pidl->cbSize = cbActualSize;
  1010.         pidl->wOuter = _wOuter;
  1011.         pidl->cbInner = (WORD)cb;
  1012.         memcpy(&pidl->rgb[cb], _data, _cb);
  1013.         *(WORD *)&(((BYTE *)pidl)[cbActualSize]) = 0;
  1014. #ifdef DEBUG
  1015.         _cAllocs++;
  1016. #endif
  1017.     }
  1018.     return pidl;
  1019. }
  1020. void *CDelagateMalloc::Realloc(void *pv, SIZE_T cb)
  1021. {
  1022.     return NULL;
  1023. }
  1024. void CDelagateMalloc::Free(void *pv)
  1025. {
  1026.     SHFree(pv);
  1027. }
  1028. SIZE_T CDelagateMalloc::GetSize(void *pv)
  1029. {
  1030.     return (SIZE_T)-1;
  1031. }
  1032. int CDelagateMalloc::DidAlloc(void *pv)
  1033. {
  1034.     return -1;
  1035. }
  1036. void CDelagateMalloc::HeapMinimize()
  1037. {
  1038. }
  1039. STDAPI CDelegateMalloc_Create(void *pv, SIZE_T cbSize, WORD wOuter, IMalloc **ppmalloc)
  1040. {
  1041.     CDelagateMalloc *pdm = new(cbSize) CDelagateMalloc(pv, cbSize, wOuter);
  1042.     if (pdm)
  1043.     {
  1044.         HRESULT hres = pdm->QueryInterface(IID_IMalloc, (void **)ppmalloc);
  1045.         pdm->Release();
  1046.         return hres;
  1047.     }
  1048.     return E_OUTOFMEMORY;
  1049. }
  1050. //+-------------------------------------------------------------------------
  1051. // This function scans the head of an html document for the desired element
  1052. // with a particular attribute.  If a match is found, the first occurance
  1053. // of that element is returned in punkDesired and S_OK is returned.
  1054. // Otherwise, E_FAIL is returned.
  1055. //
  1056. // Example:  Find the first meta element with name="ProgID":
  1057. //
  1058. //   SearchForElementInHead(pHTMLDoc, OLESTR("Name"), OLESTR("ProgId"),
  1059. //           IID_IHTMLMetaElement, (IUnknown**)&pMetaElement);
  1060. //
  1061. //--------------------------------------------------------------------------
  1062. HRESULT SearchForElementInHead
  1063. (
  1064.     IHTMLDocument2* pHTMLDocument,  // [in] document to search
  1065.     LPOLESTR        pszAttribName,  // [in] attribute to check for
  1066.     LPOLESTR        pszAttrib,      // [in] value the attribute must have
  1067.     REFIID          iidDesired,     // [in] element interface to return
  1068.     IUnknown**      ppunkDesired    // [out] returned interface
  1069. )
  1070. {
  1071.     ASSERT(NULL != pHTMLDocument);
  1072.     ASSERT(NULL != pszAttribName);
  1073.     ASSERT(NULL != pszAttrib);
  1074.     ASSERT(NULL != ppunkDesired);
  1075.     HRESULT hr = E_FAIL;
  1076.     *ppunkDesired = NULL;
  1077.     BSTR bstrAttribName = SysAllocString(pszAttribName);
  1078.     if (NULL == bstrAttribName)
  1079.     {
  1080.         return E_OUTOFMEMORY;
  1081.     }
  1082.     //
  1083.     // First get all document elements.  Note that this is very fast in
  1084.     // ie5 because the collection directly accesses the internal tree.
  1085.     //
  1086.     IHTMLElementCollection * pAllCollection;
  1087.     if (SUCCEEDED(pHTMLDocument->get_all(&pAllCollection)))
  1088.     {
  1089.         IUnknown* punk;
  1090.         IHTMLBodyElement* pBodyElement;
  1091.         IHTMLFrameSetElement* pFrameSetElement;
  1092.         IDispatch* pDispItem;
  1093.         //
  1094.         // Now we scan the document for the desired tags.  Since we're only
  1095.         // searching the head, and since Trident always creates a body tag
  1096.         // (unless there is a frameset), we can stop looking when we hit the
  1097.         // body or frameset.
  1098.         //
  1099.         // Note, the alternative of using pAllCollection->tags to return the
  1100.         // collection of desired tags is likely more expensive because it will
  1101.         // walk the whole tree (unless Trident optimizes this).
  1102.         //
  1103.         long lItemCnt;
  1104.         VARIANT vEmpty;
  1105.         V_VT(&vEmpty) = VT_EMPTY;
  1106.         VARIANT vIndex;
  1107.         V_VT(&vIndex) = VT_I4;
  1108.         EVAL(SUCCEEDED(pAllCollection->get_length(&lItemCnt)));
  1109.         for (long lItem = 0; lItem < lItemCnt; lItem++)
  1110.         {
  1111.             V_I4(&vIndex) = lItem;
  1112.             if (S_OK == pAllCollection->item(vIndex, vEmpty, &pDispItem))
  1113.             {
  1114.                 //
  1115.                 // First see if it's the desired element type
  1116.                 //
  1117.                 if (SUCCEEDED(pDispItem->QueryInterface(iidDesired,
  1118.                                                     (void **)&punk)))
  1119.                 {
  1120.                     //
  1121.                     // Next see if it has the desired attribute
  1122.                     //
  1123.                     IHTMLElement* pElement;
  1124.                     if (SUCCEEDED(pDispItem->QueryInterface(IID_IHTMLElement, (void **)&pElement)))
  1125.                     {
  1126.                         VARIANT varAttrib;
  1127.                         V_VT(&varAttrib) = VT_EMPTY;
  1128.                         if (SUCCEEDED(pElement->getAttribute(bstrAttribName, FALSE, &varAttrib)) &&
  1129.                             (V_VT(&varAttrib) == VT_BSTR) && varAttrib.bstrVal &&
  1130.                             (StrCmpIW(varAttrib.bstrVal, pszAttrib) == 0) )
  1131.                         {
  1132.                             // Found it!
  1133.                             *ppunkDesired = punk;
  1134.                             punk = NULL;
  1135.                             hr = S_OK;
  1136.                             // Terminate the search;
  1137.                             lItem = lItemCnt;
  1138.                         }
  1139.                         pElement->Release();
  1140.                         VariantClear(&varAttrib);
  1141.                     }
  1142.                     if (punk)
  1143.                         punk->Release();
  1144.                 }
  1145.                 //
  1146.                 // Next check for the body tag
  1147.                 //
  1148.                 else if (SUCCEEDED(pDispItem->QueryInterface(IID_IHTMLBodyElement,
  1149.                                                     (void **)&pBodyElement)) )
  1150.                 {
  1151.                     // Found a body tag, so terminate the search
  1152.                     lItem = lItemCnt;
  1153.                     pBodyElement->Release();
  1154.                 }
  1155.                 //
  1156.                 // Finally, check for a frameset tag
  1157.                 //
  1158.                 else if (SUCCEEDED(pDispItem->QueryInterface(IID_IHTMLFrameSetElement,
  1159.                                                     (void **)&pFrameSetElement)) )
  1160.                 {
  1161.                     // Found a frameset tag, so terminate the search
  1162.                     lItem = lItemCnt;
  1163.                     pFrameSetElement->Release();
  1164.                 }
  1165.                 pDispItem->Release();
  1166.             }
  1167.         }
  1168.         // Make sure that these don't have to be cleared (should not have been modified)
  1169.         ASSERT(vEmpty.vt == VT_EMPTY);
  1170.         ASSERT(vIndex.vt == VT_I4);
  1171.         pAllCollection->Release();
  1172.     }
  1173.     SysFreeString(bstrAttribName);
  1174.     return hr;
  1175. }
  1176. //+-------------------------------------------------------------------
  1177. //     JITCoCreateInstance
  1178. //
  1179. //  This function makes sure that the Option pack which
  1180. //  has this class id is installed.
  1181. //  It attempts to make sure that the Option pack corresponding
  1182. //  to the current IE Build.
  1183. //  If the feature does get installed correctly, it will
  1184. //  attempt to CoCreate the specified CLSID
  1185. //
  1186. //+------------------------------------------------------------------
  1187. HRESULT
  1188. JITCoCreateInstance(
  1189.     REFCLSID rclsid,
  1190.     LPUNKNOWN pUnkOuter,
  1191.     DWORD dwClsContext,
  1192.     REFIID riid,
  1193.     LPVOID FAR* ppv,
  1194.     HWND hwndParent,
  1195.     DWORD dwJitFlags
  1196. )
  1197. {
  1198.     uCLSSPEC ucs;
  1199.     QUERYCONTEXT qc = { 0 };
  1200.     HRESULT hr;
  1201.     ucs.tyspec = TYSPEC_CLSID;
  1202.     ucs.tagged_union.clsid = rclsid;
  1203.     ASSERT((dwJitFlags & ~(FIEF_FLAG_FORCE_JITUI | FIEF_FLAG_PEEK)) == 0);
  1204.     hr = FaultInIEFeature(hwndParent, &ucs, &qc, dwJitFlags);
  1205.     if (SUCCEEDED(hr))
  1206.     {
  1207.         hr = CoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, ppv);
  1208.     }
  1209.     return hr;
  1210. }
  1211. BOOL IsFeaturePotentiallyAvailable(REFCLSID rclsid)
  1212. {
  1213.     uCLSSPEC ucs;
  1214.     QUERYCONTEXT qc = { 0 };
  1215.     ucs.tyspec = TYSPEC_CLSID;
  1216.     ucs.tagged_union.clsid = rclsid;
  1217.     return (FaultInIEFeature(NULL, &ucs, &qc, FIEF_FLAG_FORCE_JITUI | FIEF_FLAG_PEEK) != E_ACCESSDENIED);
  1218. }
  1219. BOOL CreateFromDesktop(PNEWFOLDERINFO pfi)
  1220. {
  1221.     //
  1222.     //  BUGBUGHACKHACK - we need to handle differences in the way we parse the command line
  1223.     //  on IE4 integrated.  we should not be called by anybody but IE4's Explorer.exe
  1224.     //
  1225.     ASSERT(GetUIVersion() == 4);
  1226.     if (!pfi->pidl) 
  1227.     {
  1228.         if ((pfi->uFlags & (COF_ROOTCLASS | COF_NEWROOT)) || pfi->pidlRoot)
  1229.         {
  1230.             pfi->pidl = ILRootedCreateIDList(pfi->uFlags & COF_ROOTCLASS ? &pfi->clsid : NULL, pfi->pidlRoot);
  1231.             pfi->uFlags &= ~(COF_ROOTCLASS | COF_NEWROOT);
  1232.             ILFree(pfi->pidlRoot);
  1233.             pfi->pidlRoot = NULL;
  1234.             pfi->clsid = CLSID_NULL;
  1235.         }
  1236.         else if (!PathIsURLA(pfi->pszPath))
  1237.         {
  1238.            CHAR szTemp[MAX_PATH];
  1239.            GetCurrentDirectoryA(ARRAYSIZE(szTemp), szTemp);
  1240.            PathCombineA(szTemp, szTemp, pfi->pszPath);
  1241.            Str_SetPtrA(&(pfi->pszPath), szTemp);
  1242.         } 
  1243.     }
  1244.     ASSERT(!(pfi->uFlags & (COF_ROOTCLASS | COF_NEWROOT)));
  1245.     
  1246.     return SHCreateFromDesktop(pfi);
  1247. }
  1248. //***   IsVK_TABCycler -- is key a TAB-equivalent
  1249. // ENTRY/EXIT
  1250. //  dir     0 if not a TAB, non-0 if a TAB
  1251. // NOTES
  1252. //  NYI: -1 for shift+tab, 1 for tab
  1253. //
  1254. int IsVK_TABCycler(MSG *pMsg)
  1255. {
  1256.     if (!pMsg)
  1257.         return 0;
  1258.     if (pMsg->message != WM_KEYDOWN)
  1259.         return 0;
  1260.     if (! (pMsg->wParam == VK_TAB || pMsg->wParam == VK_F6))
  1261.         return 0;
  1262.     return (GetKeyState(VK_SHIFT) < 0) ? -1 : 1;
  1263. }
  1264. #ifdef DEBUG
  1265. //
  1266. // This function fully fills the input buffer, trashing stuff so we fault
  1267. // when the size is wrong :-)
  1268. //
  1269. // We should hopefully catch people passing buffers that are too small here by
  1270. // having a reproable stack corruption.
  1271. //
  1272. #define CH_BADCHARA          ((CHAR)0xCC)
  1273. #define CH_BADCHARW          ((WCHAR)0xCCCC)
  1274. #ifdef UNICODE
  1275. #define CH_BADCHAR          CH_BADCHARW
  1276. #else // UNICODE
  1277. #define CH_BADCHAR          CH_BADCHARA
  1278. #endif // UNICODE
  1279. void DebugFillInputString(LPTSTR pszBuffer, DWORD cchSize)
  1280. {
  1281.     while (cchSize--)
  1282.     {
  1283.         pszBuffer[0] = CH_BADCHAR;
  1284.         pszBuffer++;
  1285.     }
  1286. }
  1287. void DebugFillInputStringA(LPSTR pszBuffer, DWORD cchSize)
  1288. {
  1289.     while (cchSize--)
  1290.     {
  1291.         pszBuffer[0] = CH_BADCHARA;
  1292.         pszBuffer++;
  1293.     }
  1294. }
  1295. #endif // DEBUG
  1296. // Review chrisny:  this can be moved into an object easily to handle generic droptarget, dropcursor
  1297. // , autoscrool, etc. . .
  1298. void _DragEnter(HWND hwndTarget, const POINTL ptStart, IDataObject *pdtObject)
  1299. {
  1300.     RECT    rc;
  1301.     POINT   pt;
  1302.     GetWindowRect(hwndTarget, &rc);
  1303.     if (IS_WINDOW_RTL_MIRRORED(hwndTarget))
  1304.         pt.x = rc.right - ptStart.x;
  1305.     else
  1306.         pt.x = ptStart.x - rc.left;
  1307.     pt.y = ptStart.y - rc.top;
  1308.     DAD_DragEnterEx2(hwndTarget, pt, pdtObject);
  1309.     return;
  1310. }
  1311. void _DragMove(HWND hwndTarget, const POINTL ptStart)
  1312. {
  1313.     RECT rc;
  1314.     POINT pt;
  1315.     GetWindowRect(hwndTarget, &rc);
  1316.     if (IS_WINDOW_RTL_MIRRORED(hwndTarget))
  1317.         pt.x = rc.right - ptStart.x;
  1318.     else
  1319.         pt.x = ptStart.x - rc.left;
  1320.     pt.y = ptStart.y - rc.top;
  1321.     DAD_DragMove(pt);
  1322.     return;
  1323. }
  1324. STDAPI_(IBindCtx *) CreateBindCtxForUI(IUnknown * punkSite)
  1325. {
  1326.     IBindCtx * pbc = NULL;
  1327.     if (EVAL(punkSite && SUCCEEDED(CreateBindCtx(0, &pbc))))
  1328.     {
  1329.         if (FAILED(pbc->RegisterObjectParam(STR_DISPLAY_UI_DURING_BINDING, punkSite)))
  1330.         {
  1331.             // It failed damn nagit.
  1332.             ATOMICRELEASE(pbc);
  1333.         }
  1334.     }
  1335.     return pbc;
  1336. }
  1337. //
  1338. // Return the location of the internet cache
  1339. // HRESULT GetCacheLocation(
  1340. // dwSize          no. of chars in pszCacheLocation
  1341. STDAPI GetCacheLocation(LPTSTR pszCacheLocation, DWORD dwSize)
  1342. {
  1343.     HRESULT hr = S_OK;
  1344.     DWORD dwLastErr;
  1345.     LPINTERNET_CACHE_CONFIG_INFO lpCCI = NULL;  // init to suppress bogus C4701 warning
  1346.     DWORD dwCCISize = sizeof(INTERNET_CACHE_CONFIG_INFO);
  1347.     BOOL fOnceErrored = FALSE;
  1348.     while (TRUE)
  1349.     {
  1350.         if ((lpCCI = (LPINTERNET_CACHE_CONFIG_INFO) LocalAlloc(LPTR,
  1351.                                                         dwCCISize)) == NULL)
  1352.         {
  1353.             hr = E_OUTOFMEMORY;
  1354.             goto cleanup;
  1355.         }
  1356.         if (!GetUrlCacheConfigInfo(lpCCI, &dwCCISize,
  1357.                                             CACHE_CONFIG_CONTENT_PATHS_FC))
  1358.         {
  1359.             if ((dwLastErr = GetLastError()) != ERROR_INSUFFICIENT_BUFFER  ||
  1360.                 fOnceErrored)
  1361.             {
  1362.                 hr = HRESULT_FROM_WIN32(dwLastErr);
  1363.                 goto cleanup;
  1364.             }
  1365.             //
  1366.             // We have insufficient buffer size; reallocate a buffer with the
  1367.             //      new dwCCISize set by GetUrlCacheConfigInfo
  1368.             // Set fOnceErrored to TRUE so that we don't loop indefinitely
  1369.             //
  1370.             fOnceErrored = TRUE;
  1371.         }
  1372.         else
  1373.         {
  1374.             LPTSTR pszPath = lpCCI->CachePaths[0].CachePath;
  1375.             INT iLen;
  1376.             PathRemoveBackslash(pszPath);
  1377.             iLen = lstrlen(pszPath) + 1;        // + 1 is for the null char
  1378.             if ((DWORD) iLen < dwSize)
  1379.             {
  1380.                 StrCpyN(pszCacheLocation, pszPath, iLen);
  1381.             }
  1382.             else
  1383.             {
  1384.                 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  1385.             }
  1386.             break;
  1387.         }
  1388.         LocalFree(lpCCI);
  1389.         lpCCI = NULL;
  1390.     }
  1391. cleanup:
  1392.     if (lpCCI != NULL)
  1393.     {
  1394.         LocalFree(lpCCI);
  1395.     }
  1396.     return hr;
  1397. }
  1398. STDAPI_(UINT) GetWheelMsg()
  1399. {
  1400.     static UINT s_msgMSWheel = 0;
  1401.     if (s_msgMSWheel == 0)
  1402.         s_msgMSWheel = RegisterWindowMessage(TEXT("MSWHEEL_ROLLMSG"));
  1403.     return s_msgMSWheel;
  1404. }
  1405. STDAPI StringToStrRet(LPCTSTR pString, STRRET *pstrret)
  1406. {
  1407.     HRESULT hr = SHStrDup(pString, &pstrret->pOleStr);
  1408.     if (SUCCEEDED(hr))
  1409.     {
  1410.         pstrret->uType = STRRET_WSTR;
  1411.     }
  1412.     return hr;
  1413. }
  1414. // these two functions are duplicated from browseui
  1415. HINSTANCE GetComctl32Hinst()
  1416. {
  1417.     static HINSTANCE s_hinst = NULL;
  1418.     if (!s_hinst)
  1419.         s_hinst = GetModuleHandle(TEXT("comctl32.dll"));
  1420.     return s_hinst;
  1421. }
  1422. // since we don't define the proper WINVER we do this ourselves
  1423. #ifndef IDC_HAND
  1424. #define IDC_HAND            MAKEINTRESOURCE(32649)
  1425. #endif
  1426. STDAPI_(HCURSOR) LoadHandCursor(DWORD dwRes)
  1427. {
  1428.     if (g_bRunOnNT5 || g_bRunOnMemphis)
  1429.     {
  1430.         HCURSOR hcur = LoadCursor(NULL, IDC_HAND);  // from USER, system supplied
  1431.         if (hcur)
  1432.             return hcur;
  1433.     }
  1434.     return LoadCursor(GetComctl32Hinst(), IDC_HAND_INTERNAL);
  1435. }
  1436. //+-------------------------------------------------------------------------
  1437. // Returns true if this type of url may not be available when offline unless
  1438. // it is cached by wininet
  1439. //--------------------------------------------------------------------------
  1440. BOOL MayBeUnavailableOffline(LPTSTR pszUrl)
  1441. {
  1442.     BOOL fRet = FALSE;
  1443.     URL_COMPONENTS uc = {0};
  1444.     uc.dwStructSize = sizeof(uc);
  1445.     if (SUCCEEDED(InternetCrackUrl(pszUrl, 0, 0, &uc)))
  1446.     {
  1447.         fRet = uc.nScheme == INTERNET_SCHEME_HTTP ||
  1448.             uc.nScheme == INTERNET_SCHEME_HTTPS ||
  1449.             uc.nScheme == INTERNET_SCHEME_FTP ||
  1450.             uc.nScheme == INTERNET_SCHEME_GOPHER;
  1451.     }
  1452.     return fRet;
  1453. }
  1454. //+-------------------------------------------------------------------------
  1455. // If the folder is a link, the associated URL is returned.
  1456. //--------------------------------------------------------------------------
  1457. HRESULT GetNavTargetName(IShellFolder* psf, LPCITEMIDLIST pidl, LPTSTR pszUrl, UINT cMaxChars)
  1458. {
  1459.     LPITEMIDLIST pidlTarget;
  1460.     HRESULT hr = SHGetNavigateTarget(psf, pidl, &pidlTarget, NULL);
  1461.     if (SUCCEEDED(hr))
  1462.     {
  1463.         // Get the URL
  1464.         hr = IEGetNameAndFlags(pidlTarget, SHGDN_FORADDRESSBAR, pszUrl, cMaxChars, NULL);
  1465.         ILFree(pidlTarget);
  1466.     }
  1467.     else
  1468.         *pszUrl = 0;
  1469.     return hr;
  1470. }
  1471. //+-------------------------------------------------------------------------
  1472. // Returns info about whether this item is available offline. Returns E_FAIL
  1473. // if the item is not a link.
  1474. // if we navigate to this item
  1475. //  (true if we're online, items in the cache or otherwise available)
  1476. // if item is a sticky cache entry
  1477. //--------------------------------------------------------------------------
  1478. // BUGBUG: this should use an interface to bind to this information abstractly
  1479. // psf->GetUIObjectOf(IID_IAvailablility, ...);
  1480. HRESULT GetLinkInfo(IShellFolder* psf, LPCITEMIDLIST pidlItem, BOOL* pfAvailable, BOOL* pfSticky)
  1481. {
  1482.     if (pfAvailable)
  1483.         *pfAvailable = TRUE;
  1484.     if (pfSticky)
  1485.         *pfSticky = FALSE;
  1486.     //
  1487.     // See if it is a link. If it is not, then it can't be in the wininet cache and can't
  1488.     // be pinned (sticky cache entry) or greyed (unavailable when offline)
  1489.     //
  1490.     WCHAR szUrl[MAX_URL_STRING];
  1491.     DWORD dwFlags = 0;
  1492.     HRESULT hr = GetNavTargetName(psf, pidlItem, szUrl, ARRAYSIZE(szUrl));
  1493.     if (SUCCEEDED(hr))
  1494.     {
  1495.         CHAR szUrlAnsi[MAX_URL_STRING];
  1496.         //
  1497.         // Get the cache info for this item.  Note that we use GetUrlCacheEntryInfoEx instead
  1498.         // of GetUrlCacheEntryInfo because it follows any redirects that occured.  This wacky
  1499.         // api uses a variable length buffer, so we have to guess the size and retry if the
  1500.         // call fails.
  1501.         //
  1502.         BOOL fInCache = FALSE;
  1503.         WCHAR szBuf[512];
  1504.         LPINTERNET_CACHE_ENTRY_INFOA pCE = (LPINTERNET_CACHE_ENTRY_INFOA)szBuf;
  1505.         DWORD dwEntrySize = ARRAYSIZE(szBuf);
  1506.         SHTCharToAnsi(szUrl, szUrlAnsi, ARRAYSIZE(szUrlAnsi));
  1507.         if (!(fInCache = GetUrlCacheEntryInfoExA(szUrlAnsi, pCE, &dwEntrySize, NULL, NULL, NULL, 0)))
  1508.         {
  1509.             if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  1510.             {
  1511.                 // We guessed too small for the buffer so allocate the correct size & retry
  1512.                 pCE = (LPINTERNET_CACHE_ENTRY_INFOA)LocalAlloc(LPTR, dwEntrySize);
  1513.                 if (pCE)
  1514.                 {
  1515.                     fInCache = GetUrlCacheEntryInfoExA(szUrlAnsi, pCE, &dwEntrySize, NULL, NULL, NULL, 0);
  1516.                 }
  1517.             }
  1518.         }
  1519.         //
  1520.         // If we are offline, see if the item is in the cache.
  1521.         //
  1522.         if (pfAvailable && SHIsGlobalOffline() && MayBeUnavailableOffline(szUrl) && !fInCache)
  1523.         {
  1524.             // Not available
  1525.             *pfAvailable = FALSE;
  1526.         }
  1527.         //
  1528.         // See if it's a sticky cache entry
  1529.         //
  1530.         if (pCE)
  1531.         {
  1532.             if (pfSticky && fInCache && (pCE->CacheEntryType & STICKY_CACHE_ENTRY))
  1533.             {
  1534.                 *pfSticky = TRUE;
  1535.             }
  1536.             if ((TCHAR*)pCE != szBuf)
  1537.             {
  1538.                 LocalFree(pCE);
  1539.             }
  1540.         }
  1541.     }
  1542.     return hr;
  1543. }
  1544. //
  1545. // Get the avg char width given an hwnd
  1546. //
  1547. int GetAvgCharWidth(HWND hwnd)
  1548. {
  1549.     ASSERT(hwnd);
  1550.     int nWidth = 0;
  1551.     HFONT hfont = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0);
  1552.     if (hfont)
  1553.     {
  1554.         HDC hdc = GetDC(NULL);
  1555.         if(hdc)
  1556.         {
  1557.             HFONT hfontOld = (HFONT)SelectObject(hdc, hfont);
  1558.             TEXTMETRIC tm;
  1559.             if (GetTextMetrics(hdc, &tm))
  1560.                 nWidth = tm.tmAveCharWidth;
  1561.             SelectObject(hdc, hfontOld);
  1562.             ReleaseDC(NULL, hdc);
  1563.         }
  1564.     }
  1565.     return nWidth;
  1566. }
  1567. //
  1568. // Converts all "&" into "&&" so that they show up
  1569. // in menus
  1570. //
  1571. void FixAmpersands(LPWSTR pszToFix, UINT cchMax)
  1572. {
  1573.     ASSERT(pszToFix && cchMax > 0);
  1574.     WCHAR szBuf[MAX_URL_STRING];
  1575.     LPWSTR pszBuf = szBuf;
  1576.     LPWSTR pszSrc = pszToFix;
  1577.     UINT cch = 0;
  1578.     while (*pszSrc && cch < ARRAYSIZE(szBuf)-2)
  1579.     {
  1580.         if (*pszSrc == '&')
  1581.         {
  1582.             *pszBuf++ = '&';
  1583.             ++cch;
  1584.         }
  1585.         *pszBuf++ = *pszSrc++;
  1586.         ++cch;
  1587.     }
  1588.     *pszBuf = 0;
  1589.     StrCpyN(pszToFix, szBuf, cchMax);
  1590. }
  1591. // EVIL: return an aliased pointer to the pidl in this variant (that is why it is const)
  1592. // see VariantToIDList
  1593. STDAPI_(LPCITEMIDLIST) VariantToConstIDList(const VARIANT *pv)
  1594. {
  1595.     if (pv == NULL)
  1596.         return NULL;
  1597.     LPCITEMIDLIST pidl = NULL;
  1598.     if (pv->vt == (VT_BYREF | VT_VARIANT) && pv->pvarVal)
  1599.         pv = pv->pvarVal;
  1600.     switch (pv->vt)
  1601.     {
  1602.     case VT_UINT_PTR:
  1603.         // HACK in process case, avoid the use of this if possible
  1604.         pidl = (LPCITEMIDLIST)pv->byref;
  1605.         ASSERT(pidl);
  1606.         break;
  1607.     case VT_ARRAY | VT_UI1:
  1608.         pidl = (LPCITEMIDLIST)pv->parray->pvData;   // alias: PIDL encoded
  1609.         break;
  1610.     }
  1611.     return pidl;
  1612. }
  1613. STDAPI_(LPITEMIDLIST) VariantToIDList(const VARIANT *pv)
  1614. {
  1615.     LPITEMIDLIST pidl = NULL;
  1616.     if (pv)
  1617.     {
  1618.         if (pv->vt == (VT_BYREF | VT_VARIANT) && pv->pvarVal)
  1619.             pv = pv->pvarVal;
  1620.         switch (pv->vt)
  1621.         {
  1622.         case VT_I2:
  1623.             pidl = SHCloneSpecialIDList(NULL, pv->iVal, TRUE);
  1624.             break;
  1625.         case VT_I4:
  1626.             pidl = SHCloneSpecialIDList(NULL, pv->lVal, TRUE);
  1627.             break;
  1628.         case VT_BSTR:
  1629.             pidl = ILCreateFromPath(pv->bstrVal);
  1630.             break;
  1631.         case VT_ARRAY | VT_UI1:
  1632.             pidl = ILClone((LPCITEMIDLIST)pv->parray->pvData);
  1633.             break;
  1634.         default:
  1635.             LPCITEMIDLIST pidlToCopy = VariantToConstIDList(pv);
  1636.             if (pidlToCopy)
  1637.                 pidl = ILClone(pidlToCopy);
  1638.             break;
  1639.         }
  1640.     }
  1641.     return pidl;
  1642. }
  1643. STDAPI VariantToBuffer(const VARIANT* pvar, void *pv, UINT cb)
  1644. {
  1645.     if (pvar && pvar->vt == (VT_ARRAY | VT_UI1))
  1646.     {
  1647.         memcpy(pv, pvar->parray->pvData, cb);
  1648.         return TRUE;
  1649.     }
  1650.     return FALSE;
  1651. }
  1652. STDAPI VariantToGUID(VARIANT *pvar, GUID *pguid)
  1653. {
  1654.     return VariantToBuffer(pvar, pguid, sizeof(*pguid));
  1655. }
  1656. STDAPI InitVariantFromBuffer(VARIANT *pvar, const void *pv, UINT cb)
  1657. {
  1658.     HRESULT hres;
  1659.     SAFEARRAY *psa = SafeArrayCreateVector(VT_UI1, 0, cb);   // create a one-dimensional safe array
  1660.     if (psa) 
  1661.     {
  1662.         memcpy(psa->pvData, pv, cb);
  1663.         memset(pvar, 0, sizeof(*pvar));  // VariantInit()
  1664.         pvar->vt = VT_ARRAY | VT_UI1;
  1665.         pvar->parray = psa;
  1666.         hres = S_OK;
  1667.     }
  1668.     else
  1669.         hres = E_OUTOFMEMORY;
  1670.     return hres;
  1671. }
  1672. STDAPI_(BOOL) InitVariantFromIDList(VARIANT* pvar, LPCITEMIDLIST pidl)
  1673. {
  1674.     return SUCCEEDED(InitVariantFromBuffer(pvar, pidl, ILGetSize(pidl)));
  1675. }
  1676. STDAPI_(BOOL) InitVariantFromGUID(VARIANT *pvar, GUID *pguid)
  1677. {
  1678.     return SUCCEEDED(InitVariantFromBuffer(pvar, pguid, SIZEOF(*pguid)));
  1679. }
  1680. // EVIL: if you know the VARIANT will be passed in process only you can
  1681. // use this. note code above that decodes this properly
  1682. //
  1683. // the lifetime of the pidl must equal that of the VARIANT
  1684. STDAPI_(void) InitVariantFromIDListInProc(VARIANT *pvar, LPCITEMIDLIST pidl)
  1685. {
  1686.     memset(pvar, 0, sizeof(*pvar));  // VariantInit()
  1687.     pvar->vt = VT_UINT_PTR;
  1688.     pvar->byref = (PVOID)pidl;
  1689. }
  1690. #define SZ_REGKEY_INETCPL_POLICIES   TEXT("Software\Policies\Microsoft\Internet Explorer\Control Panel")
  1691. BOOL IsInetcplRestricted(LPWSTR pszCommand)
  1692. {
  1693.     BOOL fDisabled;
  1694.     DWORD dwData;
  1695.     DWORD dwSize = sizeof(dwData);
  1696.     DWORD dwType;
  1697.     if (ERROR_SUCCESS == SHRegGetUSValue(
  1698.                             SZ_REGKEY_INETCPL_POLICIES,
  1699.                             pszCommand,
  1700.                             &dwType,
  1701.                             (LPVOID)&dwData,
  1702.                             &dwSize,
  1703.                             FALSE,
  1704.                             NULL,
  1705.                             0))
  1706.     {
  1707.         fDisabled = dwData;
  1708.     }
  1709.     else
  1710.     {
  1711.         // If the value is missing from the registry, then
  1712.         // assume the feature is enabled
  1713.         fDisabled = FALSE;
  1714.     }
  1715.     return fDisabled;
  1716. }
  1717. BOOL HasExtendedChar(LPCWSTR pszQuery)
  1718. {
  1719.     BOOL fNonAscii = FALSE;
  1720.     for (LPCWSTR psz = pszQuery; *psz; psz++)
  1721.     {
  1722.         if (*psz > 0x7f)
  1723.         {
  1724.             fNonAscii = TRUE;
  1725.             break;
  1726.         }
  1727.     }
  1728.     return fNonAscii;
  1729. }
  1730. void ConvertToUtf8Escaped(LPWSTR pszUrl, int cch)
  1731. {
  1732.     // Convert to utf8
  1733.     char szBuf[MAX_URL_STRING];
  1734.     SHUnicodeToAnsiCP(CP_UTF8, pszUrl, szBuf, ARRAYSIZE(szBuf));
  1735.     // Escape the string into the original buffer
  1736.     LPSTR pchIn; 
  1737.     LPWSTR pchOut = pszUrl;
  1738.     WCHAR ch;
  1739.     static const WCHAR hex[] = L"0123456789ABCDEF";
  1740.     for (pchIn = szBuf; *pchIn && cch > 3; pchIn++)
  1741.     {
  1742.         ch = *pchIn;
  1743.         if (ch > 0x7f)
  1744.         {
  1745.             cch -= 3;
  1746.             *pchOut++ = L'%';
  1747.             *pchOut++ = hex[(ch >> 4) & 15];
  1748.             *pchOut++ = hex[ch & 15];
  1749.         }
  1750.         else
  1751.         {
  1752.             --cch;
  1753.             *pchOut++ = *pchIn;
  1754.         }
  1755.     }
  1756.     *pchOut = L'';
  1757. }
  1758. HRESULT IExtractIcon_GetIconLocation(
  1759.     IUnknown *punk,
  1760.     IN  UINT   uInFlags,
  1761.     OUT LPTSTR pszIconFile,
  1762.     IN  UINT   cchIconFile,
  1763.     OUT PINT   pniIcon,
  1764.     OUT PUINT  puOutFlags)
  1765. {
  1766.     ASSERT(punk);
  1767.     HRESULT hr;
  1768.     
  1769.     if (g_fRunningOnNT)
  1770.     {
  1771.         IExtractIcon *pxi;
  1772.         hr = punk->QueryInterface(IID_IExtractIcon, (void **)&pxi);
  1773.         if (SUCCEEDED(hr))
  1774.         {
  1775.             hr = pxi->GetIconLocation(uInFlags, pszIconFile, cchIconFile, pniIcon, puOutFlags);
  1776.             pxi->Release();
  1777.         }
  1778.     }
  1779.     else
  1780.     {
  1781.         IExtractIconA *pxi;
  1782.         hr = punk->QueryInterface(IID_IExtractIconA, (void **)&pxi);
  1783.         if (SUCCEEDED(hr))
  1784.         {
  1785.             CHAR sz[MAX_PATH];
  1786.             hr = pxi->GetIconLocation(uInFlags, sz, SIZECHARS(sz), pniIcon, puOutFlags);
  1787.             if (SUCCEEDED(hr))
  1788.                 SHAnsiToTChar(sz, pszIconFile, cchIconFile);
  1789.             pxi->Release();
  1790.         }
  1791.     }
  1792.     return hr;
  1793. }
  1794.         
  1795. HRESULT IExtractIcon_Extract(
  1796.     IUnknown *punk,
  1797.     IN  LPCTSTR pszIconFile,
  1798.     IN  UINT    iIcon,
  1799.     OUT HICON * phiconLarge,
  1800.     OUT HICON * phiconSmall,
  1801.     IN  UINT    ucIconSize)
  1802. {
  1803.     ASSERT(punk);
  1804.     HRESULT hr;
  1805.     
  1806.     if (g_fRunningOnNT)
  1807.     {
  1808.         IExtractIcon *pxi;
  1809.         hr = punk->QueryInterface(IID_IExtractIcon, (void **)&pxi);
  1810.         if (SUCCEEDED(hr))
  1811.         {
  1812.             hr = pxi->Extract(pszIconFile, iIcon, phiconLarge, phiconSmall, ucIconSize);
  1813.             pxi->Release();
  1814.         }
  1815.     }
  1816.     else
  1817.     {
  1818.         IExtractIconA *pxi;
  1819.         hr = punk->QueryInterface(IID_IExtractIconA, (void **)&pxi);
  1820.         if (SUCCEEDED(hr))
  1821.         {
  1822.             CHAR sz[MAX_PATH];
  1823.             SHTCharToAnsi(pszIconFile, sz, SIZECHARS(sz));
  1824.             hr = pxi->Extract(sz, iIcon, phiconLarge, phiconSmall, ucIconSize);
  1825.             pxi->Release();
  1826.         }
  1827.     }
  1828.     return hr;
  1829. }
  1830. typedef EXECUTION_STATE (__stdcall *PFNSTES) (EXECUTION_STATE);
  1831. EXECUTION_STATE _SetThreadExecutionState(EXECUTION_STATE esFlags)
  1832. {
  1833.     static PFNSTES _pfnSetThreadExecutionState = (PFNSTES)0xffffffff;
  1834.     
  1835.     if(_pfnSetThreadExecutionState == (PFNSTES)0xffffffff)
  1836.         _pfnSetThreadExecutionState = (PFNSTES)GetProcAddress(GetModuleHandleA("kernel32.dll"), "SetThreadExecutionState");
  1837.     if(_pfnSetThreadExecutionState != (PFNSTES)NULL)
  1838.         return(_pfnSetThreadExecutionState(esFlags));
  1839.     else
  1840.         return((EXECUTION_STATE)NULL);
  1841. }
  1842. HRESULT SHPathPrepareForWriteWrap(HWND hwnd, IUnknown *punkEnableModless, LPCTSTR pszPath, UINT wFunc, DWORD dwFlags)
  1843. {
  1844.     HRESULT hr;
  1845.     if (g_bRunOnNT5)
  1846.     {
  1847.         // NT5's version of the API is better.
  1848.         hr = _SHPathPrepareForWriteW(hwnd, punkEnableModless, pszPath, dwFlags);
  1849.     }
  1850.     else
  1851.     {
  1852.         hr = SHCheckDiskForMedia(hwnd, punkEnableModless, pszPath, wFunc);
  1853.     }
  1854.     return hr;
  1855. }
  1856. void GetPathOtherFormA(LPSTR lpszPath, LPSTR lpszNewPath, DWORD dwSize)
  1857. {
  1858.     BOOL bQuotes = FALSE;
  1859.     LPSTR szStart = lpszPath;
  1860.     LPSTR szEnd = NULL;
  1861.     LPSTR szNewStart = lpszNewPath;
  1862.     ZeroMemory(lpszNewPath, dwSize);
  1863.     // Cull out the starting and ending " because GetShortPathName does not
  1864.     // like it.
  1865.     if (*lpszPath == '"')
  1866.     {
  1867.         bQuotes = TRUE;
  1868.         szStart = lpszPath + 1;
  1869.         szEnd   = lpszPath + lstrlenA(lpszPath) - 1; // Point to the last "
  1870.         *szEnd  = '';
  1871.         szNewStart = lpszNewPath + 1;  // So that we can insert the " in it.
  1872.         dwSize = dwSize - 2;  // for the two double quotes to be added.
  1873.     }
  1874.     if (GetShortPathNameA(szStart, szNewStart, dwSize) != 0)
  1875.     {
  1876.         if (StrCmpIA(szStart, szNewStart) == 0)
  1877.         {   // The original Path is a SFN. So NewPath needs to be LFN.
  1878.             GetLongPathNameA((LPCSTR)szStart, szNewStart, dwSize);
  1879.         }
  1880.     }
  1881.                                              
  1882.     // Now add the " to the NewPath so that it is in the expected form
  1883.     if (bQuotes)
  1884.     {
  1885.         int len = 0;
  1886.         // Fix the Original path.
  1887.         *szEnd = '"';
  1888.         // Fix the New path.
  1889.         *lpszNewPath = '"';        // Insert " in the beginning.
  1890.         len = lstrlenA(lpszNewPath);
  1891.         *(lpszNewPath + len) = '"'; // Add the " in the end.
  1892.         *(lpszNewPath + len + 1) = ''; // Terminate the string.
  1893.     }
  1894.     return;
  1895. }
  1896. int GetUrlSchemeFromPidl(LPCITEMIDLIST pidl)
  1897. {
  1898.     ASSERT(pidl);
  1899.     ASSERT(IsURLChild(pidl, FALSE));
  1900.     int nRet = URL_SCHEME_INVALID;
  1901.     WCHAR szUrl[MAX_URL_STRING];
  1902.     if (SUCCEEDED(IEGetNameAndFlags(pidl, SHGDN_FORPARSING, szUrl,
  1903.                                     ARRAYSIZE(szUrl), NULL)))
  1904.     {
  1905.         nRet = GetUrlScheme(szUrl);
  1906.     }
  1907.     return nRet;
  1908. }
  1909. //
  1910. // Check if it is safe to create a shortcut for the given url.  Used by add
  1911. // to favorites code.
  1912. //
  1913. BOOL IEIsLinkSafe(HWND hwnd, LPCITEMIDLIST pidl, ILS_ACTION ilsFlag)
  1914. {
  1915.     ASSERT(pidl);
  1916.     BOOL fRet = TRUE;
  1917.     if (IsURLChild(pidl, FALSE))
  1918.     {
  1919.         int nScheme = GetUrlSchemeFromPidl(pidl);
  1920.         if (URL_SCHEME_JAVASCRIPT == nScheme || URL_SCHEME_VBSCRIPT == nScheme)
  1921.         {
  1922.             WCHAR szTitle[MAX_PATH];
  1923.             WCHAR szText[MAX_PATH];
  1924.             MLLoadString(IDS_SECURITYALERT, szTitle, ARRAYSIZE(szTitle));
  1925.             MLLoadString(IDS_ADDTOFAV_WARNING + ilsFlag, szText,
  1926.                          ARRAYSIZE(szText));
  1927.             fRet = (IDYES == MLShellMessageBox(hwnd, szText, szTitle, MB_YESNO |
  1928.                                                MB_ICONWARNING | MB_APPLMODAL |
  1929.                                                MB_DEFBUTTON2));
  1930.         }
  1931.     }
  1932.     return fRet;
  1933. }
  1934. BOOL AccessAllowed(LPCWSTR pwszURL1, LPCWSTR pwszURL2)
  1935. {
  1936.     BOOL fRet = FALSE;
  1937.     IInternetSecurityManager *pSecMgr = NULL;
  1938.     if (pwszURL1 && pwszURL2 && SUCCEEDED(CoCreateInstance(CLSID_InternetSecurityManager, 
  1939.                                    NULL, 
  1940.                                    CLSCTX_INPROC_SERVER,
  1941.                                    IID_IInternetSecurityManager, 
  1942.                                    (void **)&pSecMgr)))
  1943.     {
  1944.         BYTE reqSid[MAX_SIZE_SECURITY_ID], docSid[MAX_SIZE_SECURITY_ID];
  1945.         DWORD cbReqSid = ARRAYSIZE(reqSid);
  1946.         DWORD cbDocSid = ARRAYSIZE(docSid);
  1947.         if (   SUCCEEDED(pSecMgr->GetSecurityId(pwszURL1, reqSid, &cbReqSid, 0))
  1948.             && SUCCEEDED(pSecMgr->GetSecurityId(pwszURL2, docSid, &cbDocSid, 0))
  1949.             && (cbReqSid == cbDocSid)
  1950.             && (memcmp(reqSid, docSid, cbReqSid) == 0))                    
  1951.         {
  1952.             fRet = TRUE;
  1953.         }
  1954.         pSecMgr->Release();
  1955.     }
  1956.     return fRet;
  1957. }