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

Windows Kernel

Development Platform:

Visual C++

  1. /*
  2. NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE 
  3. This file is #include'd in browseui and shdocvw util.cpp. these are too small
  4. to add an extra dependency, so they're just shared. ideally, these should move
  5. to shlwapi or comctl32 or some lib or ...
  6. NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE 
  7. */
  8. #include "ccstock2.h"
  9. #include "mluisupp.h"
  10. STDAPI_(BOOL) IsBrowseNewProcess()
  11. {
  12.     return SHRegGetBoolUSValue(REGSTR_PATH_EXPLORER TEXT("\BrowseNewProcess"), TEXT("BrowseNewProcess"), FALSE, FALSE);
  13. }
  14. // Should we run browser in a new process?
  15. STDAPI_(BOOL) IsBrowseNewProcessAndExplorer()
  16. {
  17.     if (GetModuleHandle(TEXT("EXPLORER.EXE")))
  18.         return IsBrowseNewProcess();
  19.     return FALSE;   // Not in shell process so ignore browse new process flag
  20. }
  21. HRESULT _NavigateFrame(IUnknown *punkFrame, LPCTSTR pszPath, BOOL fIsInternetShortcut)
  22. {
  23.     HRESULT hr = E_OUTOFMEMORY;
  24.     BSTR bstr = SysAllocStringT(pszPath);
  25.     if (bstr)
  26.     {
  27.         if (fIsInternetShortcut)
  28.         {
  29.             IOleCommandTarget *pcmdt;
  30.             hr = IUnknown_QueryService(punkFrame, SID_SHlinkFrame, IID_PPV_ARG(IOleCommandTarget, &pcmdt));
  31.             if (SUCCEEDED(hr))
  32.             {
  33.                 VARIANT varShortCutPath = {0};
  34.                 VARIANT varFlag = {0};
  35.                 varFlag.vt = VT_BOOL;
  36.                 varFlag.boolVal = VARIANT_TRUE;
  37.                 varShortCutPath.vt = VT_BSTR;
  38.                 varShortCutPath.bstrVal = bstr;
  39.                 hr = pcmdt->Exec(&CGID_Explorer, SBCMDID_IESHORTCUT, 0, &varShortCutPath, &varFlag);                
  40.                 pcmdt->Release();
  41.             }
  42.         }
  43.         else
  44.         {
  45.             IWebBrowser2 *pwb;
  46.             hr = IUnknown_QueryService(punkFrame, SID_SHlinkFrame, IID_PPV_ARG(IWebBrowser2, &pwb));
  47.             if (SUCCEEDED(hr))
  48.             {
  49.                 hr = pwb->Navigate(bstr, PVAREMPTY, PVAREMPTY, PVAREMPTY, PVAREMPTY);
  50.                 hr = pwb->put_Visible(VARIANT_TRUE);
  51.                 pwb->Release();
  52.             }
  53.         }
  54.         SysFreeString(bstr);
  55.     }
  56.     return hr;
  57. }
  58. //
  59. // Take a path or an URL and create a shorcut to navigare to it
  60. //
  61. STDAPI IENavigateIEProcess(LPCTSTR pszPath, BOOL fIsInternetShortcut)
  62. {
  63.     IUnknown *punk;
  64.     HRESULT hr = CoCreateInstance(CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER, IID_PPV_ARG(IUnknown, &punk));
  65.     if (SUCCEEDED(hr))
  66.     {
  67.         hr = _NavigateFrame(punk, pszPath, fIsInternetShortcut);
  68.         punk->Release();
  69.     }
  70.     
  71.     return hr;
  72. }
  73.         
  74. // If this is an internet shortcut (.url file), we want it to
  75. // navigate using using the file name so the frame frame
  76. // can read data beyond out of that file. this includes frame set
  77. // navigation and data that script on the page may have stored.
  78. /*
  79.     Purpose : This function takes a path to a file. if that file is a .URL we try
  80.     to navigate with that file name. this is because .URL files have extra data stored
  81.     in them that we want to let script on the page get to. the exec we send here
  82.     lets the frame know the .URL file that this came from
  83.     Parameters : file name of .URL file (maybe) : In param
  84.     pUnk :       Pointer to Object from which you can get the IOleCommandTarget
  85.   returns:
  86.     TRUE    handled
  87.     FALSE   not handled, file might not be a .URL
  88. */
  89. STDAPI NavFrameWithFile(LPCTSTR pszPath, IUnknown *punk)
  90. {
  91.     HRESULT hr = E_FAIL;
  92.     LPTSTR pszExt = PathFindExtension(pszPath);
  93.     // HACK: we hard code .URL. this should be a property of the file type
  94.     if (0 == StrCmpI(pszExt, TEXT(".url")))
  95.     {
  96. #ifdef BROWSENEWPROCESS_STRICT // "Nav in new process" has become "Launch in new process", so this is no longer needed
  97.         if (IsBrowseNewProcessAndExplorer())
  98.             hr = IENavigateIEProcess(pszPath, TRUE);
  99.         else
  100. #endif
  101.             hr = _NavigateFrame(punk, pszPath, TRUE);
  102.     }
  103.     return hr;
  104. }
  105. // get the win32 file system name (path) for the item
  106. // and optional attributes
  107. //
  108. // pdwAttrib may be NULL
  109. // in/out:
  110. //      pdwAttrib   may be NULL, attributes to query on the item
  111. STDAPI GetPathForItem(IShellFolder *psf, LPCITEMIDLIST pidl, LPTSTR pszPath, DWORD *pdwAttrib)
  112. {
  113.     HRESULT hres = E_FAIL;
  114.     DWORD dwAttrib;
  115.     if (pdwAttrib == NULL)
  116.     {
  117.         pdwAttrib = &dwAttrib;
  118.         dwAttrib = SFGAO_FILESYSTEM;
  119.     }
  120.     else
  121.         *pdwAttrib |= SFGAO_FILESYSTEM;
  122.     if (SUCCEEDED(psf->GetAttributesOf(1, &pidl, pdwAttrib)) &&
  123.         (*pdwAttrib & SFGAO_FILESYSTEM))
  124.     {
  125.         STRRET str;
  126.         hres = psf->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &str);
  127.         if (SUCCEEDED(hres))
  128.             StrRetToStrN(pszPath, MAX_PATH, &str, pidl);
  129.     }
  130.     return hres;
  131. }
  132. STDAPI EditBox_TranslateAcceleratorST(LPMSG lpmsg)
  133. {
  134.     switch (lpmsg->message) {
  135.     case WM_KEYUP:      // eat these (if we process corresponding WM_KEYDOWN)
  136.     case WM_KEYDOWN:    // process these
  137.         if (lpmsg->wParam != VK_TAB)
  138.         {
  139.             // all keydown messages except for the tab key should go straight to
  140.             // the edit control -- unless the Ctrl key is down, in which case there
  141.             // are 9 messages that should go straight to the edit control
  142. #ifdef DEBUG
  143.             if (lpmsg->wParam == VK_CONTROL)
  144.                 return S_FALSE;
  145. #endif
  146.             if (GetKeyState(VK_CONTROL) & 0x80000000)
  147.             {
  148.                 switch (lpmsg->wParam)
  149.                 {
  150.                 case VK_RIGHT:
  151.                 case VK_LEFT:
  152.                 case VK_UP:
  153.                 case VK_DOWN:
  154.                 case VK_HOME:
  155.                 case VK_END:
  156.                 case VK_F4:
  157.                 case VK_INSERT:
  158.                 case VK_DELETE:
  159.                 case 'C':
  160.                 case 'X':
  161.                 case 'V':
  162.                 case 'A':
  163.                 case 'Z':
  164.                     // these Ctrl+key messages are used by the edit control
  165.                     // send 'em straight there
  166.                     break;
  167.                 default:
  168.                     return(S_FALSE);
  169.                 }
  170.             }
  171.             else
  172.             {
  173.                 switch(lpmsg->wParam)
  174.                 {
  175.                 case VK_F5: // for refresh
  176.                 case VK_F6: // for cycle focus
  177.                     return(S_FALSE);
  178.                 }
  179.             }
  180.             // Note that we return S_OK.
  181.             goto TranslateDispatch;
  182.         }
  183.         break;
  184.     case WM_CHAR:
  185. TranslateDispatch:
  186.         TranslateMessage(lpmsg);
  187.         DispatchMessage(lpmsg);
  188.         return(S_OK);
  189.     }
  190.     return S_FALSE;
  191. }
  192. // BUGBUG: dupe with shell32 util.cpp function
  193. // like OLE GetClassFile(), but it only works on ProgIDCLSID type registration
  194. // not real doc files or pattern matched files
  195. //
  196. STDAPI _CLSIDFromExtension(LPCTSTR pszExt, CLSID *pclsid)
  197. {
  198.     TCHAR szProgID[80];
  199.     DWORD cb = SIZEOF(szProgID);
  200.     if (SHGetValue(HKEY_CLASSES_ROOT, pszExt, NULL, NULL, szProgID, &cb) == ERROR_SUCCESS)
  201.     {
  202.         TCHAR szCLSID[80];
  203.         StrCatBuff(szProgID, TEXT("\CLSID"), ARRAYSIZE(szProgID));
  204.         cb = SIZEOF(szCLSID);
  205.         if (SHGetValue(HKEY_CLASSES_ROOT, szProgID, NULL, NULL, szCLSID, &cb) == ERROR_SUCCESS)
  206.         {
  207.             return GUIDFromString(szCLSID, pclsid) ? S_OK : E_FAIL;
  208.         }
  209.     }
  210.     return E_FAIL;
  211. }
  212. #if 0 // not used yet
  213. // IShellLink is #defined to IShellLinkA or IShellLinkW depending on compile flags,
  214. // bug Win95 did not support IShellLinkW.  So call this function instead and you
  215. // get the correct results regardless of what platform you are running on.
  216. // REVIEW: In fact, we probably want these for ALL IShellLink functions...
  217. //
  218. LWSTDAPI IShellLink_GetPathA(IUnknown *punk, LPSTR pszBuf, UINT cchBuf, DWORD dwFlags)
  219. {
  220.     HRESULT hres = E_INVALIDARG;
  221.     
  222.     RIPMSG(cchBuf && pszBuf && IS_VALID_WRITE_BUFFER(pszBuf, char, cchBuf), "IShellLink_GetPathA: callre passed bad pszBuf/cchBuf");
  223.     DEBUGWhackPathBufferA(pszBuf, cchBuf);
  224.     if (cchBuf && pszBuf)
  225.     {
  226.         // In case of gross failure, NULL output buffer
  227.         *pszBuf = 0;
  228.         IShellLinkA * pslA;
  229.         hres = punk->QueryInterface(IID_IShellLinkA, (void**)&pslA);
  230.         if (SUCCEEDED(hres))
  231.         {
  232.             hres = pslA->GetPath(pszBuf, cchBuf, NULL, dwFlags);
  233.             pslA->Release();
  234.         }
  235.         else if (FAILED(hres))
  236.         {
  237. #ifdef UNICODE
  238.             IShellLinkW *pslW;
  239.             hres = punk->QueryInterface(IID_IShellLinkW, (void**)&pslW);
  240.             if (SUCCEEDED(hres))
  241.             {
  242.                 WCHAR wszPath[MAX_BUF];
  243.                 LPWSTR pwszBuf = wszPath;
  244.                 UINT cch = ARRAYSIZE(wszPath);
  245.                 // Our stack buffer is too small, allocate one of the output buffer size
  246.                 if (cchBuf > cch)
  247.                 {
  248.                     LPWSTR pwsz = LocalAlloc(LPTR, cchBuf * sizeof(WCHAR));
  249.                     if (pwsz)
  250.                     {
  251.                         pwszBuf = pwsz;
  252.                         cch = cchBuf;
  253.                     }
  254.                 }
  255.                 hres = pslW->GetPath(pwszBuf, cch, NULL, dwFlags);
  256.                 if (SUCCEEDED(hres))
  257.                 {
  258.                     SHUnicodeToAnsi(pwszBuf, pszBuf, cchBuf);
  259.                 }
  260.                 pslW->Release();
  261.             }
  262. #endif
  263.         }
  264.     }
  265.     return hres;
  266. }
  267. LWSTDAPI IShellLink_GetPathW(IUnknown *punk, LPWSTR pwszBuf, UINT cchBuf, DWORD dwFlags)
  268. {
  269.     HRESULT hres = E_INVALIDARG;
  270.     
  271.     RIPMSG(cchBuf && pwszBuf && IS_VALID_WRITE_BUFFER(pwszBuf, WCHAR, cchBuf), "IShellLink_GetPathW: caller passed bad pwszBuf/cchBuf");
  272.     DEBUGWhackPathBufferW(pwszBuf, cchBuf);
  273.     if (cchBuf && pwszBuf)
  274.     {
  275.         // In case of gross failure, NULL output buffer
  276.         *pwszBuf = 0;
  277. #ifdef UNICODE
  278.         IShellLinkW * pslW;
  279.         hres = punk->QueryInterface(IID_IShellLinkW, (void**)&pslW);
  280.         if (SUCCEEDED(hres))
  281.         {
  282.             hres = pslW->GetPath(pszBuf, cchBuf, NULL, dwFlags);
  283.             pslW->Release();
  284.         }
  285.         else if (FAILED(hres))
  286. #endif
  287.         {
  288.             IShellLinkA *pslA;
  289.             hres = punk->QueryInterface(IID_IShellLinkA, (void**)&pslA);
  290.             if (SUCCEEDED(hres))
  291.             {
  292.                 char szPath[MAX_BUF];
  293.                 LPSTR pszBuf = szPath;
  294.                 UINT cch = ARRAYSIZE(szPath);
  295.                 // Our stack buffer is too small, allocate one of the output buffer size
  296.                 if (cchBuf > cch)
  297.                 {
  298.                     LPSTR psz = LocalAlloc(LPTR, cchBuf * sizeof(char));
  299.                     if (psz)
  300.                     {
  301.                         pszBuf = psz;
  302.                         cch = cchBuf;
  303.                     }
  304.                 }
  305.                 hres = pslA->GetPath(pszBuf, cch, NULL, dwFlags);
  306.                 if (SUCCEEDED(hres))
  307.                 {
  308.                     SHAnsiToUnicode(pszBuf, pwszBuf, cchBuf);
  309.                 }
  310.                 pslA->Release();
  311.             }
  312.         }
  313.     }
  314.     return hres;
  315. }
  316. #endif // 0
  317. HRESULT IShellLinkAorW_GetPath(IShellLinkA *pslA, LPTSTR pszBuf, UINT cchBuf, 
  318. DWORD dwFlags)
  319. {
  320.     HRESULT hres = E_FAIL;
  321. // If we store the string unicode, we could be losing file information by asking
  322. // through A version. Be unicode friendly and use the W version if it exists
  323. //
  324. #ifdef UNICODE
  325.     IShellLinkW *pslW;
  326.     hres = pslA->QueryInterface(IID_IShellLinkW, (void**)&pslW);
  327.     if (SUCCEEDED(hres))
  328.     {
  329.         hres = pslW->GetPath(pszBuf, cchBuf, NULL, dwFlags);
  330.         pslW->Release();
  331.     }
  332. #endif
  333.     if (FAILED(hres))
  334.     {
  335.         char szBuf[MAX_URL_STRING];  // BOGUS, but this is a common size used, perhaps we should LocalAlloc...
  336.         cchBuf = ARRAYSIZE(szBuf);
  337.         hres = pslA->GetPath(szBuf, cchBuf, NULL, dwFlags);
  338.         SHAnsiToTChar(szBuf, pszBuf, cchBuf);
  339.     }
  340.     return hres;
  341. }
  342. STDAPI GetLinkTargetIDList(LPCTSTR pszPath, LPTSTR pszTarget, DWORD cchTarget, LPITEMIDLIST *ppidl)
  343. {
  344.     IShellLinkA *psl;
  345.     CLSID clsid;
  346.     HRESULT hres;
  347.     *ppidl = NULL;  // assume failure
  348.     // BUGBUG: we really should call GetClassFile() but this could
  349.     // slow this down a lot... so chicken out and just look in the registry
  350.     if (FAILED(_CLSIDFromExtension(PathFindExtension(pszPath), &clsid)))
  351.         clsid = CLSID_ShellLink;        // assume it's a shell link
  352.     hres = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkA, (void **)&psl);
  353.     if (SUCCEEDED(hres))
  354.     {
  355.         IPersistFile *ppf;
  356.         hres = psl->QueryInterface(IID_IPersistFile, (void **)&ppf);
  357.         if (SUCCEEDED(hres))
  358.         {
  359.             WCHAR wszPath[MAX_PATH];
  360.             SHTCharToUnicode(pszPath, wszPath, ARRAYSIZE(wszPath));
  361.             hres = ppf->Load(wszPath, 0);
  362.             if (SUCCEEDED(hres))
  363.             {
  364.                 psl->GetIDList(ppidl);
  365.                 if (*ppidl == NULL)
  366.                     hres = E_FAIL;  // NULL pidl is valid, but
  367.                                     // lets not return that to clients
  368.                 if (pszTarget)
  369.                 {
  370.                     IShellLinkAorW_GetPath(psl, pszTarget, cchTarget, 0);
  371.                 }
  372.             }
  373.             ppf->Release();
  374.         }
  375.         psl->Release();
  376.     }
  377.     // pszPath might == pszTarget so don't null out on entry always
  378.     if (FAILED(hres) && pszTarget)
  379.         *pszTarget = 0;
  380.     return hres;
  381. }
  382. STDAPI_(void) PathToDisplayNameW(LPCTSTR pszPath, LPTSTR pszDisplayName, UINT cchDisplayName)
  383. {
  384.     SHFILEINFO sfi;
  385.     if (SHGetFileInfo(pszPath, 0, &sfi, SIZEOF(sfi), SHGFI_DISPLAYNAME))
  386.     {
  387.         StrCpyN(pszDisplayName, sfi.szDisplayName, cchDisplayName);
  388.     }
  389.     else
  390.     {
  391.         StrCpyN(pszDisplayName, PathFindFileName(pszPath), cchDisplayName);
  392.         PathRemoveExtension(pszDisplayName);
  393.     }
  394. }
  395. STDAPI_(void) PathToDisplayNameA(LPSTR pszPathA, LPSTR pszDisplayNameA, int cchDisplayName)
  396. {
  397.     SHFILEINFOA sfi;
  398.     if (SHGetFileInfoA(pszPathA, 0, &sfi, SIZEOF(sfi), SHGFI_DISPLAYNAME))
  399.     {
  400.         StrCpyNA(pszDisplayNameA, sfi.szDisplayName, cchDisplayName);
  401.     }
  402.     else
  403.     {
  404.         pszPathA = PathFindFileNameA(pszPathA);
  405.         StrCpyNA(pszDisplayNameA, pszPathA, cchDisplayName);
  406.         PathRemoveExtensionA(pszDisplayNameA);
  407.     }
  408. }
  409. // this looks for the file descriptor format to get the display name of a data object
  410. STDAPI DataObj_GetNameFromFileDescriptor(IDataObject *pdtobj, LPWSTR pszDisplayName, UINT cch)
  411. {
  412.     HRESULT hres = E_FAIL;
  413.     STGMEDIUM mediumFGD;
  414.     InitClipboardFormats();
  415.     FILEGROUPDESCRIPTORW * pfgd = (FILEGROUPDESCRIPTORW *)DataObj_GetDataOfType(pdtobj, g_cfFileDescW, &mediumFGD);
  416.     if (pfgd)
  417.     {
  418.         if (pfgd->cItems > 0)
  419.         {
  420.             LPFILEDESCRIPTORW pfd = &(pfgd->fgd[0]);
  421.             SHUnicodeToTChar(pfd->cFileName, pszDisplayName, cch);
  422.             hres = S_OK;
  423.         }
  424.         ReleaseStgMediumHGLOBAL(&mediumFGD);
  425.     }
  426.     else
  427.     {
  428.         FILEGROUPDESCRIPTORA * pfgd = (FILEGROUPDESCRIPTORA *)DataObj_GetDataOfType(pdtobj, g_cfFileDescA, &mediumFGD);
  429.         if (pfgd)
  430.         {
  431.             if (pfgd->cItems > 0)
  432.             {
  433.                 LPFILEDESCRIPTORA pfd = &(pfgd->fgd[0]);
  434.                 SHAnsiToTChar(pfd->cFileName, pszDisplayName, cch);
  435.                 hres = S_OK;
  436.             }
  437.             ReleaseStgMediumHGLOBAL(&mediumFGD);
  438.         }
  439.     }
  440.     return hres;
  441. }
  442. STDAPI SHPidlFromDataObject2(IDataObject *pdtobj, LPITEMIDLIST * ppidl)
  443. {
  444.     HRESULT hres = E_FAIL;
  445.     STGMEDIUM medium;
  446.     InitClipboardFormats();
  447.     void *pdata = DataObj_GetDataOfType(pdtobj, g_cfHIDA, &medium);
  448.     if (pdata)
  449.     {
  450.         *ppidl = IDA_ILClone((LPIDA)pdata, 0);
  451.         if (*ppidl)
  452.             hres = S_OK;
  453.         else
  454.             hres = E_OUTOFMEMORY;
  455.         ReleaseStgMediumHGLOBAL(&medium);
  456.     }
  457.     return hres;
  458. }
  459. STDAPI SHPidlFromDataObject(IDataObject *pdtobj, LPITEMIDLIST *ppidl,
  460.                            LPWSTR pszDisplayNameW, DWORD cchDisplayName)
  461. {
  462.     FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  463.     STGMEDIUM medium;
  464.     *ppidl = NULL;
  465.     HRESULT hres = pdtobj->GetData(&fmte, &medium);
  466.     if (hres == S_OK)
  467.     {
  468.         // This string is also used to store an URL in case it's an URL file
  469.         TCHAR szPath[MAX_URL_STRING];
  470.         hres = E_FAIL;
  471.         if (DragQueryFile((HDROP)medium.hGlobal, 0, szPath, ARRAYSIZE(szPath)))
  472.         {
  473.             SHFILEINFO sfi;
  474.             SHGetFileInfo(szPath, 0, &sfi, SIZEOF(sfi), SHGFI_ATTRIBUTES | SHGFI_DISPLAYNAME);
  475.             if (pszDisplayNameW)
  476.                 SHTCharToUnicode(sfi.szDisplayName, pszDisplayNameW, MAX_PATH);
  477.             if (sfi.dwAttributes & SFGAO_LINK)
  478.                 hres = GetLinkTargetIDList(szPath, szPath, ARRAYSIZE(szPath), ppidl);
  479.             if (FAILED(hres))
  480.                 hres = IECreateFromPath(szPath, ppidl);
  481.         }
  482.         ReleaseStgMedium(&medium);
  483.     }
  484.     else
  485.     {
  486.         hres = SHPidlFromDataObject2(pdtobj, ppidl);
  487.         if (FAILED(hres))
  488.         {
  489.             void *pdata = DataObj_GetDataOfType(pdtobj, g_cfURL, &medium);
  490.             if (pdata)
  491.             {
  492.                 LPSTR pszPath = (LPSTR)pdata;
  493.                 if (pszDisplayNameW) {
  494.                     if (FAILED(DataObj_GetNameFromFileDescriptor(pdtobj, pszDisplayNameW, cchDisplayName))) {
  495.                         CHAR szDisplayNameA[MAX_URL_STRING];
  496.                         ASSERT(cchDisplayName < MAX_URL_STRING);
  497.                         SHUnicodeToAnsi(pszDisplayNameW, szDisplayNameA, cchDisplayName);
  498.                         PathToDisplayNameA(pszPath, szDisplayNameA, cchDisplayName);
  499.                     }
  500.                 }
  501.                 hres = IECreateFromPathA(pszPath, ppidl);
  502.                 ReleaseStgMediumHGLOBAL(&medium);
  503.             }
  504.         }
  505.     }
  506.     return hres;
  507. }
  508. // BharatS - Perhaps all the stuff below here should be moved to shlwapi after beta 2 ?
  509. typedef struct _broadcastmsgparams
  510. {
  511.     BOOL fSendMessage; // If true - we call SendMessageTimeout
  512.     UINT uTimeout; // Only Matters if fSendMessage is set
  513.     UINT uMsg;
  514.     WPARAM wParam;
  515.     LPARAM lParam;
  516. } BROADCAST_MSG_PARAMS;
  517. BOOL CALLBACK EnumShellIEWindowsProc(  
  518.     HWND hwnd,      // handle to parent window
  519.     LPARAM lParam   // application-defined value - this has the info needed for posting/sending the message 
  520. )
  521. {
  522.     BROADCAST_MSG_PARAMS *pParams = (BROADCAST_MSG_PARAMS *)lParam;
  523.     BOOL fRet = TRUE;
  524.     if(IsExplorerWindow(hwnd) || IsFolderWindow(hwnd))
  525.     {
  526.         if(pParams->fSendMessage)
  527.         {
  528.             UINT  uTimeout = (pParams->uTimeout < 4000) ? pParams->uTimeout : 4000;
  529.             LRESULT lResult;
  530.             DWORD_PTR dwpResult;
  531.             if (g_fRunningOnNT)
  532.             {
  533.                 lResult = SendMessageTimeout(hwnd, pParams->uMsg, pParams->wParam, pParams->lParam, SMTO_ABORTIFHUNG | SMTO_NORMAL, uTimeout, &dwpResult);
  534.             }
  535.             else
  536.             {           
  537.                 lResult = SendMessageTimeoutA(hwnd, pParams->uMsg, pParams->wParam, pParams->lParam, SMTO_ABORTIFHUNG | SMTO_NORMAL, uTimeout, &dwpResult);
  538.             }
  539.             fRet = BOOLIFY(lResult);
  540.         }
  541.         else
  542.         {
  543.             fRet = PostMessage(hwnd, pParams->uMsg, pParams->wParam, pParams->lParam);
  544.         }
  545.     }
  546.     return fRet;
  547. }
  548. // PostShellIEBroadcastMessage is commented out since it is not used currentl
  549. /*
  550. STDAPI_(LRESULT)  PostShellIEBroadcastMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
  551. {   
  552.     BROADCAST_MSG_PARAMS MsgParam;
  553.     MsgParam.uMsg = uMsg;
  554.     MsgParam.wParam = wParam;
  555.     MsgParam.lParam = lParam;
  556.     MsgParam.fSendMessage = FALSE;
  557.     
  558.     return EnumWindows((WNDENUMPROC )EnumShellIEWindowsProc, (LPARAM)&MsgParam);
  559. }
  560. */
  561. //
  562. // We can be hung if we use sendMessage, and you can not use pointers with asynchronous
  563. // calls such as PostMessage or SendNotifyMessage.  So we resort to using a timeout.
  564. // This function should be used to broadcast notification messages, such as WM_SETTINGCHANGE, 
  565. // that pass pointers. (stevepro)
  566. //
  567. STDAPI_(LRESULT) SendShellIEBroadcastMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, UINT uTimeout)
  568. {
  569.     // Note that each this timeout is applied to each window that we broadcast to 
  570.     BROADCAST_MSG_PARAMS MsgParam;
  571.     MsgParam.uMsg = uMsg;
  572.     MsgParam.wParam = wParam;
  573. #ifdef UNICODE
  574.     CHAR szSection[MAX_PATH];
  575.     
  576.     if (!g_fRunningOnNT && (uMsg == WM_WININICHANGE) && (0 != lParam))
  577.     {
  578.         SHUnicodeToAnsi((LPCWSTR)lParam, szSection, ARRAYSIZE(szSection));
  579.         lParam = (LPARAM)szSection;
  580.     }
  581. #endif
  582.     MsgParam.lParam = lParam;
  583.     MsgParam.fSendMessage = TRUE;
  584.     MsgParam.uTimeout = uTimeout;
  585.     return EnumWindows((WNDENUMPROC )EnumShellIEWindowsProc, (LPARAM)&MsgParam);
  586. }
  587. // Return the parent psf and relative pidl given a pidl.
  588. STDAPI IEBindToParentFolder(LPCITEMIDLIST pidl, IShellFolder** ppsfParent, LPCITEMIDLIST *ppidlChild)
  589. {
  590.     HRESULT hres;
  591.     //
  592.     //  if this is a rooted pidl and it is just the root
  593.     //  then we can bind to the target pidl of the root instead
  594.     //
  595.     if (ILIsRooted(pidl) && ILIsEmpty(_ILNext(pidl)))
  596.         pidl = ILRootedFindIDList(pidl);
  597.         
  598.     LPITEMIDLIST pidlParent = ILCloneParent(pidl);
  599.     
  600.     if (pidlParent)
  601.     {
  602.         hres = IEBindToObject(pidlParent, ppsfParent);
  603.         ILFree(pidlParent);
  604.     }
  605.     else
  606.         hres = E_OUTOFMEMORY;
  607.     if (ppidlChild)
  608.         *ppidlChild = ILFindLastID(pidl);
  609.     return hres;
  610. }
  611. STDAPI GetDataObjectForPidl(LPCITEMIDLIST pidl, IDataObject ** ppdtobj)
  612. {
  613.     HRESULT hres = E_FAIL;
  614.     if (pidl)
  615.     {
  616.         IShellFolder *psfParent;
  617.         LPCITEMIDLIST pidlChild;
  618.         hres = IEBindToParentFolder(pidl, &psfParent, &pidlChild);
  619.         if (SUCCEEDED(hres))
  620.         {
  621.             hres = psfParent->GetUIObjectOf(NULL, 1, &pidlChild, IID_IDataObject, NULL, (void**)ppdtobj);
  622.             psfParent->Release();
  623.         }
  624.     }
  625.     return hres;
  626. }
  627. // Is this pidl a Folder/Directory in the File System?
  628. STDAPI_(BOOL) ILIsFileSysFolder(LPCITEMIDLIST pidl)
  629. {
  630.     if (!pidl)
  631.         return FALSE;
  632.     DWORD dwAttributes = SFGAO_FOLDER | SFGAO_FILESYSTEM;
  633.     HRESULT hr = IEGetAttributesOf(pidl, &dwAttributes);
  634.     return SUCCEEDED(hr) && ((dwAttributes & (SFGAO_FOLDER | SFGAO_FILESYSTEM)) == (SFGAO_FOLDER | SFGAO_FILESYSTEM));
  635. }
  636. // HACKHACK HACKHACK
  637. // the following functions are to work around the menu
  638. // munging that happens in the shlwapi wrappers... when we're
  639. // manipulating menus which are tracked by the system, the
  640. // menu munging code in our shlwapi wrappers (necessary
  641. // for xcp plugUI) trashes them since the system doesn't
  642. // understand munged menus... hence the work arounds below.
  643. // note that many of these functions are copies of the shlwapi
  644. // *WrapW functions (minus the munging).
  645. #undef LoadMenuW
  646. // from winuser.h
  647. EXTERN_C WINUSERAPI HMENU WINAPI LoadMenuW(HINSTANCE hInstance, LPCWSTR lpMenuName);
  648. STDAPI_(HMENU)
  649. LoadMenu_PrivateNoMungeW(HINSTANCE hInstance, LPCWSTR lpMenuName)
  650. {
  651.     ASSERT(HIWORD64(lpMenuName) == 0);
  652.     if (g_fRunningOnNT)
  653.     {
  654.         return LoadMenuW(hInstance, lpMenuName);
  655.     }
  656.     return LoadMenuA(hInstance, (LPCSTR) lpMenuName);
  657. }
  658. #define CP_ATOM         0xFFFFFFFF          /* not a string at all */
  659. #undef InsertMenuW
  660. // from winuser.h
  661. EXTERN_C WINUSERAPI BOOL WINAPI InsertMenuW(IN HMENU hMenu, IN UINT uPosition, IN UINT uFlags, IN UINT_PTR uIDNewItem, IN LPCWSTR lpNewItem);
  662. STDAPI_(BOOL)
  663. InsertMenu_PrivateNoMungeW(HMENU       hMenu,
  664.                            UINT        uPosition,
  665.                            UINT        uFlags,
  666.                            UINT_PTR    uIDNewItem,
  667.                            LPCWSTR     lpNewItem)
  668. {
  669.     if (g_fRunningOnNT)
  670.     {
  671.         return InsertMenuW(hMenu, uPosition, uFlags, uIDNewItem, lpNewItem);
  672.     }
  673.     char szMenuItem[CCH_MENUMAX];
  674.     SHUnicodeToAnsiCP((uFlags & MFT_NONSTRING) ? CP_ATOM : CP_ACP,
  675.                       lpNewItem,
  676.                       szMenuItem,
  677.                       ARRAYSIZE(szMenuItem));
  678.     return InsertMenuA(hMenu, uPosition, uFlags, uIDNewItem, szMenuItem);
  679. }
  680. STDAPI_(HMENU)
  681. LoadMenuPopup_PrivateNoMungeW(UINT id)
  682. {
  683.     HINSTANCE hinst;
  684.     hinst = MLLoadShellLangResources();
  685.     HMENU hMenuSub = NULL;
  686.     HMENU hMenu = LoadMenu_PrivateNoMungeW(hinst, MAKEINTRESOURCEW(id));
  687.     if (hMenu)
  688.     {
  689.         hMenuSub = GetSubMenu(hMenu, 0);
  690.         if (hMenuSub)
  691.         {
  692.             RemoveMenu(hMenu, 0, MF_BYPOSITION);
  693.         }
  694.         // note this calls the shlwapi wrapper (that handles
  695.         // destroying munged menus) but it looks like
  696.         // it's safe to do so.
  697.         DestroyMenu(hMenu);
  698.     }
  699.     MLFreeLibrary(hinst);
  700.     return hMenuSub;
  701. }
  702. // determine if a path is just a filespec (contains no path parts)
  703. //
  704. // REVIEW: we may want to count the # of elements, and make sure
  705. // there are no illegal chars, but that is probably another routing
  706. // PathIsValid()
  707. //
  708. // in:
  709. //      lpszPath    path to look at
  710. // returns:
  711. //      TRUE        no ":" or "" chars in this path
  712. //      FALSE       there are path chars in there
  713. //
  714. //
  715. BOOL PathIsFilePathA(LPCSTR lpszPath)
  716. {
  717. #ifdef UNIX
  718.     if (lpszPath[0] == '/')
  719. #else
  720.     if ((lpszPath[0] == '\') || (lpszPath[1] == ':'))
  721. #endif
  722.         return TRUE;
  723.     return IsFileUrl(lpszPath);
  724. }
  725. //
  726. // PrepareURLForDisplay
  727. //
  728. //     Decodes without stripping file:// prefix
  729. //
  730. STDAPI_(BOOL) PrepareURLForDisplayA(LPCSTR psz, LPSTR pszOut, LPDWORD pcchOut)
  731. {
  732.     if (PathIsFilePathA(psz))
  733.     {
  734.         if (IsFileUrl(psz))
  735.             return SUCCEEDED(PathCreateFromUrlA(psz, pszOut, pcchOut, 0));
  736.         StrCpyNA(pszOut, psz, *pcchOut);
  737.         *pcchOut = lstrlenA(pszOut);
  738.         return TRUE;
  739.     }
  740.     return SUCCEEDED(UrlUnescapeA((LPSTR)psz, pszOut, pcchOut, 0));
  741. }
  742. #undef InsertMenuW
  743. #undef LoadMenuW
  744. // from w95wraps.h
  745. #define InsertMenuW                 InsertMenuWrapW
  746. #define LoadMenuW                   LoadMenuWrapW
  747. STDAPI SHTitleFromPidl(LPCITEMIDLIST pidl, LPTSTR psz, DWORD cch, BOOL fFullPath)
  748. {
  749.     // Tries to get a system-displayable string from a pidl.
  750.     // (On Win9x and NT4, User32 doesn't support font-linking,
  751.     // so we can't display non-system language strings as window
  752.     // titles or menu items.  In those cases, we call this function
  753.     // to grab the path/URL instead, which will likely be system-
  754.     // displayable).
  755.     UINT uType;
  756.     *psz = NULL;
  757.     TCHAR szName[MAX_URL_STRING];
  758.     if (fFullPath)
  759.         uType = SHGDN_FORPARSING;
  760.     else
  761.         uType = SHGDN_NORMAL;
  762.     uType |= SHGDN_FORADDRESSBAR; 
  763.     DWORD dwAttrib = SFGAO_LINK;
  764.     HRESULT hr = IEGetNameAndFlags(pidl, uType, szName, SIZECHARS(szName), &dwAttrib);
  765.     if (SUCCEEDED(hr))
  766.     {
  767.         if ((uType & SHGDN_FORPARSING) && (dwAttrib & SFGAO_LINK))
  768.         {
  769.             // folder shortcut special case
  770.             IShellLinkA *psl;  // Use A version for W95.
  771.             if (SUCCEEDED(SHGetUIObjectFromFullPIDL(pidl, NULL, IID_PPV_ARG(IShellLinkA, &psl))))
  772.             {
  773.                 LPITEMIDLIST pidlTarget;
  774.                 if (SUCCEEDED(psl->GetIDList(&pidlTarget)) && pidlTarget)
  775.                 {
  776.                     hr = IEGetNameAndFlags(pidlTarget, uType, szName, SIZECHARS(szName), NULL);
  777.                     ILFree(pidlTarget);
  778.                 }
  779.             }
  780.         }
  781.     }
  782.     else
  783.     {
  784.         // didn't work, try the reverse
  785.         uType ^= SHGDN_FORPARSING;  // flip the for parsing bit
  786.         hr = IEGetNameAndFlags(pidl, uType, szName, SIZECHARS(szName), NULL);
  787.         // some old namespaces get confused by all our funny bits...
  788.         if (FAILED(hr))
  789.         {
  790.             hr = IEGetNameAndFlags(pidl, SHGDN_NORMAL, szName, SIZECHARS(szName), NULL);
  791.         }
  792.     }
  793.     if (SUCCEEDED(hr))
  794.     {
  795.         SHRemoveURLTurd(szName);
  796.         // HTTP URLs are not escaped because they come from the
  797.         // user or web page which is required to create correctly
  798.         // escaped URLs.  FTP creates then via results from the
  799.         // FTP session, so their pieces (username, password, path)
  800.         // need to be escaped when put in URL form.  However,
  801.         // we are going to put that URL into the Caption Bar, and
  802.         // and we want to unescape it because it's assumed to be
  803.         // a DBCS name.  All of this is done because unescaped URLs
  804.         // are pretty. (NT #1272882)
  805.         if (URL_SCHEME_FTP == GetUrlScheme(szName))
  806.         {
  807.             CHAR szUrlTemp[MAX_BROWSER_WINDOW_TITLE];
  808.             CHAR szUnEscaped[MAX_BROWSER_WINDOW_TITLE];
  809.             DWORD cchSizeTemp = ARRAYSIZE(szUnEscaped);
  810.             // This this thunking crap is necessary.  Unescaping won't
  811.             // gell into DBCS chars unless it's in ansi.
  812.             SHTCharToAnsi(szName, szUrlTemp, ARRAYSIZE(szUrlTemp));
  813.             PrepareURLForDisplayA(szUrlTemp, szUnEscaped, &cchSizeTemp);
  814.             SHAnsiToTChar(szUnEscaped, psz, cch);
  815.         }
  816.         else
  817.         {
  818.             StrCpyN(psz, szName, cch);
  819.         }
  820.     }
  821.     return hr;
  822. }
  823. BOOL IsSpecialUrl(LPCWSTR pchURL)
  824. {
  825.     UINT      uProt;
  826.     uProt = GetUrlSchemeW(pchURL);
  827.     return (URL_SCHEME_JAVASCRIPT == uProt || 
  828.             URL_SCHEME_VBSCRIPT == uProt ||
  829.             URL_SCHEME_ABOUT == uProt);
  830. }
  831. //encode any incoming %1 so that people can't spoof our domain security code
  832. HRESULT WrapSpecialUrl(BSTR * pbstrUrl)
  833. {
  834.     HRESULT     hr = S_OK;
  835.     TCHAR      *pchSafeUrl = NULL;
  836.     TCHAR      *pch;
  837.     TCHAR       achUrl[4096];
  838.     DWORD       dwSize;
  839.     BSTR        bstrURL = *pbstrUrl;
  840.     int         cSize;
  841.     if (IsSpecialUrl(bstrURL))
  842.     {
  843.         //
  844.         // If this is javascript:, vbscript: or about:, append the
  845.         // url of this document so that on the other side we can
  846.         // decide whether or not to allow script execution.
  847.         //
  848.         // QFE 2735 (Georgi XDomain): [alanau]
  849.         //
  850.         // If the special URL contains an %00 sequence, then it will be converted to a Null char when
  851.         // encoded.  This will effectively truncate the Security ID.  For now, simply disallow this
  852.         // sequence, and display a "Permission Denied" script error.
  853.         //
  854.         if (StrStrW(bstrURL, L"%00"))
  855.         {
  856.             hr = E_ACCESSDENIED;
  857.             goto Cleanup;
  858.         }
  859.         // Copy the URL so we can munge it.
  860.         //
  861.         cSize = SysStringLen(bstrURL) + 1;
  862.         pchSafeUrl = new TCHAR[cSize];
  863.         if (!pchSafeUrl)
  864.         {
  865.             hr = E_OUTOFMEMORY;
  866.             goto Cleanup;
  867.         } 
  868.         StrCpyN(pchSafeUrl, bstrURL, cSize);
  869.         // someone could put in a string like this:
  870.         //     %2501 OR %252501 OR %25252501
  871.         // which, depending on the number of decoding steps, will bypass security
  872.         // so, just keep decoding while there are %s and the string is getting shorter
  873.         int nPreviousLen = 0;
  874.         while ( (nPreviousLen != lstrlen(pchSafeUrl)) && (StrChrW(pchSafeUrl, L'%')))
  875.         {
  876.             nPreviousLen = lstrlen(pchSafeUrl);
  877.             int nNumPercents;
  878.             int nNumPrevPercents = 0;
  879.             // Reduce the URL
  880.             //
  881.             for (;;)
  882.             {
  883.                 // Count the % signs.
  884.                 //
  885.                 nNumPercents = 0;
  886.                 pch = pchSafeUrl;
  887.                 while (pch = StrChrW(pch, L'%'))
  888.                 {
  889.                     pch++;
  890.                     nNumPercents++;
  891.                 }
  892.                 // If the number of % signs has changed, we've reduced the URL one iteration.
  893.                 //
  894.                 if (nNumPercents != nNumPrevPercents)
  895.                 {
  896.                     // Encode the URL 
  897.                     hr = THR(CoInternetParseUrl(pchSafeUrl, 
  898.                         PARSE_ENCODE, 
  899.                         0, 
  900.                         achUrl, 
  901.                         ARRAYSIZE(achUrl), 
  902.                         &dwSize,
  903.                         0));
  904.                     StrCpyN(pchSafeUrl, achUrl, cSize);
  905.                     nNumPrevPercents = nNumPercents;
  906.                 }
  907.                 else
  908.                 {
  909.                     // The URL is fully reduced.  Break out of loop.
  910.                     //
  911.                     break;
  912.                 }
  913.             }
  914.         }
  915.         // Now scan for '1' characters.
  916.         //
  917.         if (StrChrW(pchSafeUrl, L'1'))
  918.         {
  919.             // If there are '1' characters, we can't guarantee the safety.  Put up "Permission Denied".
  920.             //
  921.             hr = E_ACCESSDENIED;
  922.             goto Cleanup;
  923.         }
  924.         SysFreeString(*pbstrUrl);
  925.         *pbstrUrl = SysAllocString(pchSafeUrl);
  926.         if (!*pbstrUrl)
  927.         {
  928.             hr = E_OUTOFMEMORY;
  929.             goto Cleanup;
  930.         }
  931.     }
  932. Cleanup:
  933.     delete [] pchSafeUrl;
  934.     return hr;
  935. }
  936. HRESULT WrapSpecialUrlFlat(LPWSTR pszUrl, DWORD cchUrl)
  937. {
  938.     HRESULT     hr = S_OK;
  939.     if (IsSpecialUrl(pszUrl))
  940.     {
  941.         //
  942.         // If this is javascript:, vbscript: or about:, append the
  943.         // url of this document so that on the other side we can
  944.         // decide whether or not to allow script execution.
  945.         //
  946.         // QFE 2735 (Georgi XDomain): [alanau]
  947.         //
  948.         // If the special URL contains an %00 sequence, then it will be converted to a Null char when
  949.         // encoded.  This will effectively truncate the Security ID.  For now, simply disallow this
  950.         // sequence, and display a "Permission Denied" script error.
  951.         //
  952.         if (StrStrW(pszUrl, L"%00"))
  953.         {
  954.             hr = E_ACCESSDENIED;
  955.         }
  956.         else
  957.         {
  958.             // munge the url in place
  959.             //
  960.             // someone could put in a string like this:
  961.             //     %2501 OR %252501 OR %25252501
  962.             // which, depending on the number of decoding steps, will bypass security
  963.             // so, just keep decoding while there are %s and the string is getting shorter
  964.             int nPreviousLen = 0;
  965.             while ( (nPreviousLen != lstrlen(pszUrl)) && (StrChrW(pszUrl, L'%')))
  966.             {
  967.                 nPreviousLen = lstrlen(pszUrl);
  968.                 int nNumPercents;
  969.                 int nNumPrevPercents = 0;
  970.                 // Reduce the URL
  971.                 //
  972.                 for (;;)
  973.                 {
  974.                     // Count the % signs.
  975.                     //
  976.                     nNumPercents = 0;
  977.                     WCHAR *pch = pszUrl;
  978.                     while (pch = StrChrW(pch, L'%'))
  979.                     {
  980.                         pch++;
  981.                         nNumPercents++;
  982.                     }
  983.                     // If the number of % signs has changed, we've reduced the URL one iteration.
  984.                     //
  985.                     if (nNumPercents != nNumPrevPercents)
  986.                     {
  987.                         WCHAR szBuf[MAX_URL_STRING];
  988.                         DWORD dwSize;
  989.                         // Encode the URL 
  990.                         hr = THR(CoInternetParseUrl(pszUrl, 
  991.                             PARSE_ENCODE, 
  992.                             0,
  993.                             szBuf,
  994.                             ARRAYSIZE(szBuf),
  995.                             &dwSize,
  996.                             0));
  997.                         StrCpyN(pszUrl, szBuf, cchUrl);
  998.                         nNumPrevPercents = nNumPercents;
  999.                     }
  1000.                     else
  1001.                     {
  1002.                         // The URL is fully reduced.  Break out of loop.
  1003.                         //
  1004.                         break;
  1005.                     }
  1006.                 }
  1007.             }
  1008.             // Now scan for '1' characters.
  1009.             //
  1010.             if (StrChrW(pszUrl, L'1'))
  1011.             {
  1012.                 // If there are '1' characters, we can't guarantee the safety.  Put up "Permission Denied".
  1013.                 //
  1014.                 hr = E_ACCESSDENIED;
  1015.             }
  1016.         }
  1017.     }
  1018.     return hr;
  1019. }
  1020. //
  1021. //      GetUIVersion()
  1022. //
  1023. //  returns the version of shell32
  1024. //  3 == win95 gold / NT4
  1025. //  4 == IE4 Integ / win98
  1026. //  5 == win2k
  1027. //
  1028. STDAPI_(UINT) GetUIVersion()
  1029. {
  1030.     static UINT s_uiShell32 = 0;
  1031.     if (s_uiShell32 == 0)
  1032.     {
  1033.         HINSTANCE hinst = GetModuleHandle(TEXT("SHELL32.DLL"));
  1034.         if (hinst)
  1035.         {
  1036.             DLLGETVERSIONPROC pfnGetVersion = (DLLGETVERSIONPROC)GetProcAddress(hinst, "DllGetVersion");
  1037.             DLLVERSIONINFO dllinfo;
  1038.             dllinfo.cbSize = sizeof(DLLVERSIONINFO);
  1039.             if (pfnGetVersion && pfnGetVersion(&dllinfo) == NOERROR)
  1040.                 s_uiShell32 = dllinfo.dwMajorVersion;
  1041.             else
  1042.                 s_uiShell32 = 3;
  1043.         }
  1044.     }
  1045.     return s_uiShell32;
  1046. }
  1047. STDAPI GetBrowserFrameOptions(IUnknown *punkFolder, IN BROWSERFRAMEOPTIONS dwMask, OUT BROWSERFRAMEOPTIONS * pdwOptions)
  1048. {
  1049.     HRESULT hr = E_INVALIDARG;
  1050.     *pdwOptions = BFO_NONE;
  1051.     if (punkFolder)
  1052.     {
  1053.         IBrowserFrameOptions *pbfo;
  1054.         hr = punkFolder->QueryInterface(IID_PPV_ARG(IBrowserFrameOptions, &pbfo));
  1055.         if (SUCCEEDED(hr))
  1056.         {
  1057.             hr = pbfo->GetFrameOptions(dwMask, pdwOptions);
  1058.             pbfo->Release();
  1059.         }
  1060.     }
  1061.     return hr;
  1062. }
  1063. STDAPI GetBrowserFrameOptionsPidl(IN LPCITEMIDLIST pidl, IN BROWSERFRAMEOPTIONS dwMask, OUT BROWSERFRAMEOPTIONS * pdwOptions)
  1064. {
  1065.     HRESULT hr = E_INVALIDARG;
  1066.     *pdwOptions = BFO_NONE;
  1067.     if (pidl)
  1068.     {
  1069.         IBrowserFrameOptions *pbfo;
  1070.         hr = IEBindToObjectEx(pidl, NULL, IID_PPV_ARG(IBrowserFrameOptions, &pbfo));
  1071.         if (SUCCEEDED(hr))
  1072.         {
  1073.             hr = pbfo->GetFrameOptions(dwMask, pdwOptions);
  1074.             pbfo->Release();
  1075.         }
  1076.     }
  1077.     return hr;
  1078. }
  1079. // Return TRUE only if all the bits in dwMask are set.
  1080. STDAPI_(BOOL) IsBrowserFrameOptionsSet(IN IShellFolder * psf, IN BROWSERFRAMEOPTIONS dwMask)
  1081. {
  1082.     BOOL fSet = FALSE;
  1083.     BROWSERFRAMEOPTIONS dwOptions = 0;
  1084.     if (SUCCEEDED(GetBrowserFrameOptions(psf, dwMask, &dwOptions)) &&
  1085.         (dwOptions == dwMask))
  1086.     {
  1087.         fSet = TRUE;
  1088.     }
  1089.     return fSet;
  1090. }
  1091. // Return TRUE only if all the bits in dwMask are set.
  1092. STDAPI_(BOOL) IsBrowserFrameOptionsPidlSet(IN LPCITEMIDLIST pidl, IN BROWSERFRAMEOPTIONS dwMask)
  1093. {
  1094.     BOOL fSet = FALSE;
  1095.     BROWSERFRAMEOPTIONS dwOptions = 0;
  1096.     if (SUCCEEDED(GetBrowserFrameOptionsPidl(pidl, dwMask, &dwOptions)) &&
  1097.         (dwOptions == dwMask))
  1098.     {
  1099.         fSet = TRUE;
  1100.     }
  1101.     return fSet;
  1102. }
  1103. STDAPI_(BOOL) IsFTPFolder(IShellFolder * psf)
  1104. {
  1105.     BOOL fIsFTPFolder = FALSE;
  1106.     CLSID clsid;
  1107.     if (psf && SUCCEEDED(IUnknown_GetClassID(psf, &clsid)))
  1108.     {
  1109.         // Is this an FTP Folder?
  1110.         if (IsEqualIID(clsid, CLSID_FtpFolder))
  1111.             fIsFTPFolder = TRUE;
  1112.         else
  1113.         {
  1114.             // Not directly, but let's see if it is an Folder Shortcut to
  1115.             // an FTP Folder
  1116.             if (IsEqualIID(clsid, CLSID_FolderShortcut))
  1117.             {
  1118.                 IShellLinkA * psl = NULL;
  1119.                 HRESULT hr = psf->QueryInterface(IID_IShellLinkA, (void **) &psl);
  1120.                 if (SUCCEEDED(hr))
  1121.                 {
  1122.                     LPITEMIDLIST pidl;
  1123.                     hr = psl->GetIDList(&pidl);
  1124.                     if (SUCCEEDED(hr))
  1125.                     {
  1126.                         IShellFolder * psfTarget;
  1127.                         hr = IEBindToObject(pidl, &psfTarget);
  1128.                         if (SUCCEEDED(hr))
  1129.                         {
  1130.                             if (SUCCEEDED(IUnknown_GetClassID(psfTarget, &clsid)) &&
  1131.                                 IsEqualIID(clsid, CLSID_FtpFolder))
  1132.                             {
  1133.                                 fIsFTPFolder = TRUE;
  1134.                             }
  1135.                             psfTarget->Release();
  1136.                         }
  1137.                         ILFree(pidl);
  1138.                     }
  1139.                     psl->Release();
  1140.                 }
  1141.             }
  1142.         }
  1143.     }
  1144.     return fIsFTPFolder;
  1145. }