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

Windows Kernel

Development Platform:

Visual C++

  1. #include "priv.h"
  2. #include <multimon.h>
  3. #include "hnfblock.h"
  4. #include <trayp.h>
  5. #include "desktop.h"
  6. #include "shbrows2.h"
  7. #include "resource.h"
  8. #include "onetree.h"
  9. #include "apithk.h"
  10. #include <regitemp.h>
  11. #include "mluisupp.h"
  12. BOOL _RootsEqual(HANDLE hCR, DWORD dwProcId, LPCITEMIDLIST pidlRoot)
  13. {
  14.     BOOL bSame = FALSE;
  15.     if (hCR)
  16.     {
  17.         LPITEMIDLIST pidl = (LPITEMIDLIST)SHLockShared(hCR, dwProcId);
  18.         if (pidl)
  19.         {
  20.             bSame = ILIsEqualRoot(pidlRoot, pidl);
  21.             SHUnlockShared(pidl);
  22.         }
  23.     }
  24.     return bSame;
  25. }
  26. // NOTE: this export is new to IE5, so it can move to browseui
  27. // along with the rest of this proxy desktop code
  28. BOOL SHOnCWMCommandLine(LPARAM lParam)
  29. {
  30.     HNFBLOCK hnf = (HNFBLOCK)lParam;
  31.     IETHREADPARAM *piei = ConvertHNFBLOCKtoNFI(hnf);
  32.     if (piei)
  33.         return SHOpenFolderWindow(piei);
  34.     // bad params passed, normal failure case
  35.     return FALSE;
  36. }
  37. //---------------------------------------------------------------------------
  38. // This proxy desktop window procedure is used when we are run and we
  39. // are not the shell.  We are a hidden window which will simply respond
  40. // to messages like the ones that create threads for folder windows.
  41. // This window procedure will close after all of the open windows
  42. // associated with it go away.
  43. class CProxyDesktop
  44. {
  45. private:
  46.     static LRESULT CALLBACK ProxyWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
  47.     friend CProxyDesktop *CreateProxyDesktop(IETHREADPARAM *piei);
  48.     friend BOOL SHCreateFromDesktop(PNEWFOLDERINFO pfi);
  49.     CProxyDesktop() {};
  50.     ~CProxyDesktop();
  51.     HWND            _hwnd;
  52.     LPITEMIDLIST    _pidlRoot;
  53. };
  54. CProxyDesktop::~CProxyDesktop()
  55. {
  56.     ILFree(_pidlRoot);
  57. }
  58. LRESULT CALLBACK CProxyDesktop::ProxyWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  59. {
  60.     CProxyDesktop *pproxy = (CProxyDesktop *)GetWindowPtr0(hwnd);
  61.     switch (msg)
  62.     {
  63.     case WM_CREATE:
  64.         pproxy = (CProxyDesktop *)((CREATESTRUCT *)lParam)->lpCreateParams;
  65.         SetWindowPtr0(hwnd, pproxy);
  66.         pproxy->_hwnd = hwnd;
  67.         return 0;   // success
  68.     case WM_DESTROY:
  69.         if (pproxy)
  70.             pproxy->_hwnd = NULL;
  71.         return 0;
  72.     case CWM_COMMANDLINE:
  73.         SHOnCWMCommandLine(lParam);
  74.         break;
  75.     case CWM_COMPAREROOT:
  76.         return _RootsEqual((HANDLE)lParam, (DWORD)wParam, pproxy->_pidlRoot);
  77.     default:
  78.         return DefWindowProcWrap(hwnd, msg, wParam, lParam);
  79.     }
  80.     return 0;
  81. }
  82. CProxyDesktop *CreateProxyDesktop(IETHREADPARAM *piei)
  83. {
  84.     CProxyDesktop *pproxy = new CProxyDesktop();
  85.     if (pproxy)
  86.     {
  87.         WNDCLASS wc = {0};
  88.         wc.lpfnWndProc = CProxyDesktop::ProxyWndProc;
  89.         wc.cbWndExtra = SIZEOF(CProxyDesktop *);
  90.         wc.hInstance = HINST_THISDLL;
  91.         wc.hbrBackground = (HBRUSH)(COLOR_DESKTOP + 1);
  92.         wc.lpszClassName = DESKTOPPROXYCLASS;
  93.         SHRegisterClass(&wc);
  94.         if (CreateWindowEx(WS_EX_TOOLWINDOW, DESKTOPPROXYCLASS, DESKTOPPROXYCLASS,
  95.             WS_POPUP, 0, 0, 0, 0, NULL, NULL, HINST_THISDLL, pproxy))
  96.         {
  97.             if (ILIsRooted(piei->pidl))
  98.             {
  99.                 pproxy->_pidlRoot = ILCloneFirst(piei->pidl);
  100.                 if (pproxy->_pidlRoot == NULL)
  101.                 {
  102.                     DestroyWindow(pproxy->_hwnd);
  103.                     pproxy = NULL;
  104.                 }
  105.             }
  106.         }
  107.         else
  108.         {
  109.             delete pproxy;
  110.             pproxy = NULL;
  111.         }
  112.     }
  113.     return pproxy;
  114. }
  115. // REVIEW: maybe just check (hwnd == GetShellWindow())
  116. STDAPI_(BOOL) IsDesktopWindow(HWND hwnd)
  117. {
  118.     TCHAR szName[80];
  119.     GetClassName(hwnd, szName, ARRAYSIZE(szName));
  120.     if (!lstrcmp(szName, DESKTOPCLASS))
  121.     {
  122.         GetWindowText(hwnd, szName, ARRAYSIZE(szName));
  123.         return !lstrcmp(szName, PROGMAN);
  124.     }
  125.     return FALSE;
  126. }
  127. typedef struct
  128. {
  129.     HWND hwndDesktop;
  130.     HANDLE hCR;
  131.     DWORD dwProcId;
  132.     HWND hwndResult;
  133. } FRDSTRUCT;
  134. BOOL CALLBACK FindRootEnumProc(HWND hwnd, LPARAM lParam)
  135. {
  136.     FRDSTRUCT *pfrds = (FRDSTRUCT *)lParam;
  137.     TCHAR szClassName[40];
  138.     GetClassName(hwnd, szClassName, ARRAYSIZE(szClassName));
  139.     if (lstrcmpi(szClassName, DESKTOPPROXYCLASS) == 0)
  140.     {
  141.         ASSERT(hwnd != pfrds->hwndDesktop);
  142.         if (SendMessage(hwnd, CWM_COMPAREROOT, (WPARAM)pfrds->dwProcId, (LPARAM)pfrds->hCR))
  143.         {
  144.             // Found it, so stop enumerating
  145.             pfrds->hwndResult = hwnd;
  146.             return FALSE;
  147.         }
  148.     }
  149.     return TRUE;
  150. }
  151. BOOL RunSeparateDesktop()
  152. {
  153.     DWORD bSeparate = FALSE;
  154.     if (SHRestricted(REST_SEPARATEDESKTOPPROCESS))
  155.         bSeparate = TRUE;
  156.     else
  157.     {
  158.         SHELLSTATE ss;
  159.         SHGetSetSettings(&ss, SSF_SEPPROCESS, FALSE);
  160.         bSeparate = ss.fSepProcess;
  161.         if (!bSeparate)
  162.         {
  163.             DWORD cbData = SIZEOF(bSeparate);
  164.             SHGetValue(HKEY_CURRENT_USER, REGSTR_PATH_EXPLORER, TEXT("DesktopProcess"), NULL, &bSeparate, &cbData);
  165.         }
  166.     }
  167.     return bSeparate;
  168. }
  169. //  if we need to force some legacy rootet explorers into their own process, implement this.
  170. //#define _RootRunSeparateProcess(pidlRoot)  ILIsRooted(pidlRoot)  OLD BEHAVIOR
  171. #define _RootRunSeparateProcess(pidlRoot)  FALSE
  172. HWND FindRootedDesktop(LPCITEMIDLIST pidlRoot)
  173. {
  174.     HWND hwndDesktop = GetShellWindow();    // This is the "normal" desktop
  175.     if (!RunSeparateDesktop() && !_RootRunSeparateProcess(pidlRoot) && hwndDesktop)
  176.     {
  177.         ASSERT(IsDesktopWindow(hwndDesktop));
  178.         return hwndDesktop;
  179.     }
  180.     FRDSTRUCT frds;
  181.     frds.hwndDesktop = hwndDesktop;
  182.     frds.hwndResult = NULL;     // Initalize to no matching rooted expl
  183.     frds.dwProcId = GetCurrentProcessId();
  184.     frds.hCR = SHAllocShared(pidlRoot, ILGetSize(pidlRoot), frds.dwProcId);
  185.     if (frds.hCR)
  186.     {
  187.         EnumWindows(FindRootEnumProc, (LPARAM)&frds);
  188.         SHFreeShared(frds.hCR, frds.dwProcId);
  189.     }
  190.     return frds.hwndResult;
  191. }
  192. UINT _GetProcessHotkey(void)
  193. {
  194.     STARTUPINFO si = {SIZEOF(si)};
  195.     GetStartupInfo(&si);
  196.     return (UINT)(DWORD_PTR)si.hStdInput;
  197. }
  198. void FolderInfoToIEThreadParam(PNEWFOLDERINFO pfi, IETHREADPARAM *piei)
  199. {
  200.     piei->uFlags = pfi->uFlags;
  201.     piei->nCmdShow = pfi->nShow;
  202.     piei->wHotkey = _GetProcessHotkey();
  203.     
  204.     ASSERT(pfi->pszRoot == NULL);       // explorer always converts to a PIDL for us
  205.     //  we no longer support rooted explorers this way
  206.     //  it should have been filtered out above us.
  207.     ASSERT(!pfi->pidlRoot);
  208.     ASSERT(!(pfi->uFlags & (COF_ROOTCLASS | COF_NEWROOT)));
  209.     ASSERT(IsEqualGUID(pfi->clsid, CLSID_NULL));
  210.     if (pfi->pidl) 
  211.     {
  212.         piei->pidl = ILClone(pfi->pidl);
  213.     } 
  214.     //  COF_PARSEPATH means that we should defer the parsing of the pszPath
  215.     else if (!(pfi->uFlags & COF_PARSEPATH) && pfi->pszPath && pfi->pszPath[0])
  216.     {
  217.         //  maybe should use IECreateFromPath??
  218.         //  or maybe we should parse relative to the root??
  219.         piei->pidl = ILCreateFromPathA(pfi->pszPath);
  220.     }
  221. }
  222. // IE4 Integrated delay loads CreateFromDesktop from SHDOCVW.DLL
  223. // So we need to keep this function here. Forward to the correct
  224. // implementation in SHELL32 (if integrated) or SHDOC41 (if not)
  225. BOOL SHCreateFromDesktop(PNEWFOLDERINFO pfi)
  226. {
  227.     IETHREADPARAM *piei = SHCreateIETHREADPARAM(NULL, 0, NULL, NULL);
  228.     if (piei)
  229.     {
  230.         //  ASSUMING UNICODE COMPILE!
  231.         LPCTSTR pszPath = NULL;
  232.         
  233.         if (pfi->uFlags & COF_PARSEPATH)
  234.         {
  235.             ASSERT(!pfi->pidl);
  236.             pszPath = (LPCTSTR) pfi->pszPath;
  237.         }
  238.         FolderInfoToIEThreadParam(pfi, piei);
  239.         HWND hwndDesktop = FindRootedDesktop(piei->pidl);
  240.         if (hwndDesktop)
  241.         {
  242.             DWORD dwProcId;
  243.             DWORD dwThreadId = GetWindowThreadProcessId(hwndDesktop, &dwProcId);
  244.             AllowSetForegroundWindow(dwProcId);
  245.             HNFBLOCK hBlock = ConvertNFItoHNFBLOCK(piei, pszPath, dwProcId);
  246.             if (hBlock)
  247.             {
  248.                 PostMessage(hwndDesktop, CWM_COMMANDLINE, 0, (LPARAM)hBlock);
  249.                 HANDLE hExplorer = OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, dwProcId );
  250.                 if ( hExplorer )
  251.                 {
  252.                     // wait for input idle 10 seconds.
  253.                     WaitForInputIdle( hExplorer, 10000 );
  254.                     CloseHandle( hExplorer );
  255.                 }
  256.             }
  257.         }
  258.         else
  259.         {
  260.             CoInitialize(0);
  261.             CProxyDesktop *pproxy = CreateProxyDesktop(piei);
  262.             if (pproxy)
  263.             {
  264.                 // CRefThread controls this processes reference count. browser windows use this
  265.                 // to keep this process (window) around and this also lets thrid parties hold 
  266.                 // references to our process, MSN uses this for example
  267.                 LONG cRefMsgLoop;
  268.                 IUnknown *punkRefMsgLoop;
  269.                 if (SUCCEEDED(SHCreateThreadRef(&cRefMsgLoop, &punkRefMsgLoop)))
  270.                 {
  271.                     SHSetInstanceExplorer(punkRefMsgLoop);
  272.                     //  we needed to wait for this for the CoInit()
  273.                     if (pszPath)
  274.                         piei->pidl = ILCreateFromPath(pszPath);
  275.                     SHOpenFolderWindow(piei);
  276.                     piei = NULL;                // OpenFolderWindow() takes ownership of this
  277.                     punkRefMsgLoop->Release();  // we now depend on the browser window to keep our msg loop
  278.                 }
  279.                 MSG msg;
  280.                 while (GetMessage(&msg, NULL, 0, 0))
  281.                 {
  282.                     if (cRefMsgLoop == 0)
  283.                         break; // no more refs on this thread, done
  284.                     TranslateMessage(&msg);
  285.                     DispatchMessage(&msg);
  286.                 }
  287.                 delete pproxy;
  288.             }
  289.             CoUninitialize();
  290.         }
  291.         if (piei)
  292.             SHDestroyIETHREADPARAM(piei);
  293.     }
  294.     return TRUE;        // no one pays attention to this
  295. }
  296.         
  297. HNFBLOCK ConvertNFItoHNFBLOCK(IETHREADPARAM* pInfo, LPCTSTR pszPath, DWORD dwProcId)
  298. {
  299.     UINT    uSize;
  300.     UINT    uPidl;
  301.     UINT    uPidlSelect;
  302.     UINT    uPidlRoot;
  303.     UINT    upszPath;
  304.     PNEWFOLDERBLOCK pnfb;
  305.     LPBYTE  lpb;
  306.     HNFBLOCK hBlock;
  307.     LPVOID pidlRootOrMonitor = NULL; // pidlRoot or &hMonitor
  308.     uSize = SIZEOF(NEWFOLDERBLOCK);
  309.     if (pInfo->pidl)
  310.     {
  311.         uPidl = ILGetSize(pInfo->pidl);
  312.         uSize += uPidl;
  313.     }
  314.     if (pInfo->pidlSelect)
  315.     {
  316.         uPidlSelect = ILGetSize(pInfo->pidlSelect);
  317.         uSize += uPidlSelect;
  318.     }
  319.     if (pInfo->uFlags & COF_HASHMONITOR)
  320.     {
  321.         pidlRootOrMonitor = &pInfo->pidlRoot;
  322.         uPidlRoot = sizeof(HMONITOR);
  323.         uSize += uPidlRoot;
  324.     }
  325.     else if (pInfo->pidlRoot)
  326.     {
  327.         pidlRootOrMonitor = pInfo->pidlRoot;
  328.         uPidlRoot = ILGetSize(pInfo->pidlRoot);
  329.         uSize += uPidlRoot;
  330.     }
  331.     if (pszPath) {
  332.         upszPath = CbFromCch(lstrlen(pszPath) + 1);
  333.         uSize += upszPath;
  334.     }
  335.     hBlock = (HNFBLOCK)SHAllocShared(NULL, uSize, dwProcId);
  336.     if (hBlock == NULL)
  337.         return NULL;
  338.     pnfb = (PNEWFOLDERBLOCK)SHLockShared(hBlock, dwProcId);
  339.     if (pnfb == NULL)
  340.     {
  341.         SHFreeShared(hBlock, dwProcId);
  342.         return NULL;
  343.     }
  344.     pnfb->dwSize      = uSize;
  345.     pnfb->uFlags      = pInfo->uFlags;
  346.     pnfb->nShow       = pInfo->nCmdShow;
  347.     pnfb->hwndCaller  = pInfo->hwndCaller;
  348.     pnfb->dwHotKey    = pInfo->wHotkey;
  349.     pnfb->clsid       = pInfo->clsid;
  350.     pnfb->clsidInProc = pInfo->clsidInProc;
  351.     pnfb->oidl        = 0;
  352.     pnfb->oidlSelect  = 0;
  353.     pnfb->oidlRoot    = 0;
  354.     pnfb->opszPath    = 0;
  355.     lpb = (LPBYTE)(pnfb+1);     // Point just past the structure
  356.     if (pInfo->pidl)
  357.     {
  358.         memcpy(lpb,pInfo->pidl,uPidl);
  359.         pnfb->oidl = (int)(lpb-(LPBYTE)pnfb);
  360.         lpb += uPidl;
  361.     }
  362.     if (pInfo->pidlSelect)
  363.     {
  364.         memcpy(lpb,pInfo->pidlSelect,uPidlSelect);
  365.         pnfb->oidlSelect = (int)(lpb-(LPBYTE)pnfb);
  366.         lpb += uPidlSelect;
  367.     }
  368.     if (pidlRootOrMonitor)
  369.     {
  370.         memcpy(lpb, pidlRootOrMonitor, uPidlRoot);
  371.         pnfb->oidlRoot = (int)(lpb-(LPBYTE)pnfb);
  372.         lpb += uPidlRoot;
  373.     }
  374.     if (pszPath)
  375.     {
  376.         memcpy(lpb, pszPath, upszPath);
  377.         pnfb->opszPath = (int)(lpb-(LPBYTE)pnfb);
  378.         lpb += upszPath;
  379.     }
  380.     SHUnlockShared(pnfb);
  381.     return hBlock;
  382. }
  383. IETHREADPARAM* ConvertHNFBLOCKtoNFI(HNFBLOCK hBlock)
  384. {
  385.     BOOL fFailure = FALSE;
  386.     IETHREADPARAM* piei = NULL;
  387.     if (hBlock)
  388.     {
  389.         DWORD dwProcId = GetCurrentProcessId();
  390.         PNEWFOLDERBLOCK pnfb = (PNEWFOLDERBLOCK)SHLockShared(hBlock, dwProcId);
  391.         if (pnfb)
  392.         {
  393.             if (pnfb->dwSize >= SIZEOF(NEWFOLDERBLOCK))
  394.             {
  395.                 piei = SHCreateIETHREADPARAM(NULL, pnfb->nShow, NULL, NULL);
  396.                 if (piei)
  397.                 {
  398.                     LPITEMIDLIST pidl = NULL;
  399.                     piei->uFlags      = pnfb->uFlags;
  400.                     piei->hwndCaller  = pnfb->hwndCaller;
  401.                     piei->wHotkey     = pnfb->dwHotKey;
  402.                     piei->clsid       = pnfb->clsid;
  403.                     piei->clsidInProc = pnfb->clsidInProc;
  404.                     if (pnfb->oidlSelect)
  405.                         piei->pidlSelect = ILClone((LPITEMIDLIST)((LPBYTE)pnfb+pnfb->oidlSelect));
  406.                     if (pnfb->oidlRoot)
  407.                     {
  408.                         LPITEMIDLIST pidlRoot = (LPITEMIDLIST)((LPBYTE)pnfb+pnfb->oidlRoot);
  409.                         if (pnfb->uFlags & COF_HASHMONITOR)
  410.                         {
  411.                             piei->pidlRoot = (LPITEMIDLIST)*(UNALIGNED HMONITOR *)pidlRoot;
  412.                         }
  413.                         else
  414.                         {
  415.                             piei->pidlRoot = ILClone(pidl);
  416.                         }
  417.                     }
  418.                     if (pnfb->oidl)
  419.                         pidl = ILClone((LPITEMIDLIST)((LPBYTE)pnfb+pnfb->oidl));
  420.                     if (pidl) 
  421.                     {
  422.                         piei->pidl = pidl;
  423.                     } 
  424.                     
  425.                     // we pass this string through because msn fails the cocreateinstane of
  426.                     // their desktop if another one is up and running, so we can't convert
  427.                     // this from path to pidl except in the current process context
  428.                     if (pnfb->opszPath) 
  429.                     {
  430.                         LPTSTR pszPath = (LPTSTR)((LPBYTE)pnfb+pnfb->opszPath);
  431.                         HRESULT hr = E_FAIL;
  432.                         
  433.                         if (ILIsRooted(pidl))
  434.                         {
  435.                             //  let the root handle the parsing.
  436.                             IShellFolder *psf;
  437.                             if (SUCCEEDED(IEBindToObject(pidl, &psf)))
  438.                             {
  439.                                 hr = IShellFolder_ParseDisplayName(psf, NULL, NULL, pszPath, NULL, &(piei->pidl), NULL);
  440.                                 psf->Release();
  441.                             }
  442.                         }
  443.                         else
  444.                             IECreateFromPath(pszPath, &(piei->pidl));
  445.                         // APP COMPAT: these two specific return result codes are the two we ignored for win95.
  446.                         // APP COMPAT: MSN 1.3 Classic accidentally on purpose returns one of these...
  447.                         if ( !piei->pidl )
  448.                         {
  449.                             // failed, report the error to the user ... (will only fail for paths)
  450.                             ASSERT( !PathIsURL( pszPath))
  451.                             if (! (piei->uFlags & COF_NOTUSERDRIVEN) && ( hr != E_OUTOFMEMORY ) && ( hr != HRESULT_FROM_WIN32( ERROR_CANCELLED )))
  452.                             {
  453.                                 MLShellMessageBox(
  454.                                                   NULL,
  455.                                                   MAKEINTRESOURCE( IDS_NOTADIR ),
  456.                                                   MAKEINTRESOURCE( IDS_CABINET ),
  457.                                                   MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND,
  458.                                                   pszPath);
  459.                             }
  460.                             fFailure = TRUE;
  461.                         }
  462.                     }
  463.                 }
  464.             }
  465.             SHUnlockShared(pnfb);
  466.         }
  467.         SHFreeShared(hBlock, dwProcId);
  468.     }
  469.     // if we really failed somewhere, return NULL
  470.     if (fFailure)
  471.     {
  472.         SHDestroyIETHREADPARAM(piei);
  473.         piei = NULL;
  474.     }
  475.     return piei;
  476. }
  477. // Check the registry for a shell root under this CLSID.
  478. BOOL GetRootFromRootClass(LPCTSTR pszGUID, LPTSTR pszPath, int cchPath)
  479. {
  480.     TCHAR szClass[MAX_PATH];
  481.     wnsprintf(szClass, ARRAYSIZE(szClass), TEXT("CLSID\%s\ShellExplorerRoot"), pszGUID);
  482.     DWORD cbPath = cchPath * sizeof(TCHAR);
  483.     return SHGetValueGoodBoot(HKEY_CLASSES_ROOT, szClass, NULL, NULL, (BYTE *)pszPath, &cbPath) == ERROR_SUCCESS;
  484. }
  485. // format is ":<hMem>:<hProcess>"
  486. LPITEMIDLIST IDListFromCmdLine(LPCTSTR pszCmdLine, int i)
  487. {
  488.     LPITEMIDLIST pidl = NULL;
  489.     TCHAR szField[80];
  490.     if (ParseField(pszCmdLine, i, szField, ARRAYSIZE(szField)) && szField[0] == TEXT(':'))
  491.     {
  492.         // Convert the string of format ":<hmem>:<hprocess>" into a pointer
  493.         HANDLE hMem = (HANDLE)StrToLong(szField + 1);
  494.         LPTSTR pszNextColon = StrChr(szField + 1, TEXT(':'));
  495.         if (pszNextColon)
  496.         {
  497.             DWORD dwProcId = (DWORD)StrToLong(pszNextColon + 1);
  498.             LPITEMIDLIST pidlGlobal = (LPITEMIDLIST) SHLockShared(hMem, dwProcId);
  499.             if (pidlGlobal)
  500.             {
  501.                 if (!IsBadReadPtr(pidlGlobal, 1))
  502.                     pidl = ILClone(pidlGlobal);
  503.                 SHUnlockShared(pidlGlobal);
  504.                 SHFreeShared(hMem, dwProcId);
  505.             }
  506.         }
  507.     }
  508.     return pidl;
  509. }
  510. #define MYDOCS_CLSID TEXT("{450d8fba-ad25-11d0-98a8-0800361b1103}") // CLSID_MyDocuments
  511. LPITEMIDLIST MyDocsIDList(void)
  512. {
  513.     LPITEMIDLIST pidl = NULL;
  514.     IShellFolder *psf;
  515.     HRESULT hres = SHGetDesktopFolder(&psf);
  516.     if (SUCCEEDED(hres))
  517.     {
  518.         WCHAR wszName[128];
  519.         wszName[0] = wszName[1] = TEXT(':');
  520.         SHTCharToUnicode(MYDOCS_CLSID, wszName + 2, ARRAYSIZE(wszName) - 2);
  521.         hres = psf->ParseDisplayName(NULL, NULL, wszName, NULL, &pidl, NULL);
  522.         psf->Release();
  523.     }
  524.     // Win95/NT4 case, go for the real MyDocs folder
  525.     if (FAILED(hres))
  526.     {
  527.         hres = SHGetSpecialFolderLocation(NULL, CSIDL_PERSONAL, &pidl);
  528.     }
  529.     return SUCCEEDED(hres) ? pidl : NULL;
  530. }
  531. BOOL SHExplorerParseCmdLine(PNEWFOLDERINFO pfi)
  532. {
  533.     int i;
  534.     TCHAR szField[MAX_PATH];
  535.     LPCTSTR pszCmdLine = GetCommandLine();
  536.     pszCmdLine = PathGetArgs(pszCmdLine);
  537.     // empty command line -> explorer My Docs
  538.     if (*pszCmdLine == 0)
  539.     {
  540.         pfi->uFlags = COF_CREATENEWWINDOW | COF_EXPLORE;
  541.         // try MyDocs first?
  542.         pfi->pidl = MyDocsIDList();
  543.         if (pfi->pidl == NULL)
  544.         {
  545.             TCHAR szPath[MAX_PATH];
  546.             GetWindowsDirectory(szPath, ARRAYSIZE(szPath));
  547.             PathStripToRoot(szPath);
  548.             pfi->pidl = ILCreateFromPath(szPath);
  549.         }
  550.         return BOOLFROMPTR(pfi->pidl);
  551.     }
  552.     // Arguments must be separated by '=' or ','
  553.     for (i = 1; ParseField(pszCmdLine, i, szField, ARRAYSIZE(szField)); i++)
  554.     {
  555.         if (lstrcmpi(szField, TEXT("/N")) == 0)
  556.         {
  557.             pfi->uFlags |= COF_CREATENEWWINDOW | COF_NOFINDWINDOW;
  558.         }
  559.         else if (lstrcmpi(szField, TEXT("/S")) == 0)
  560.         {
  561.             pfi->uFlags |= COF_USEOPENSETTINGS;
  562.         }
  563.         else if (lstrcmpi(szField, TEXT("/E")) == 0)
  564.         {
  565.             pfi->uFlags |= COF_EXPLORE;
  566.         }
  567.         else if (lstrcmpi(szField, TEXT("/ROOT")) == 0)
  568.         {
  569.             LPITEMIDLIST pidlRoot = NULL;
  570.             CLSID *pclsidRoot = NULL;
  571.             CLSID clsid;
  572.             RIPMSG(!pfi->pidl, "SHExplorerParseCommandLine: (/ROOT) caller passed bad params");
  573.             // of the form:
  574.             //     /ROOT,{clsid}[,<path>]
  575.             //     /ROOT,/IDLIST,:<hmem>:<hprocess>
  576.             //     /ROOT,<path>
  577.             if (!ParseField(pszCmdLine, ++i, szField, ARRAYSIZE(szField)))
  578.                 return FALSE;
  579.             // {clsid}
  580.             if (GUIDFromString(szField, &clsid))
  581.             {
  582.                 TCHAR szGUID[GUIDSTR_MAX];
  583.                 StrCpyN(szGUID, szField, SIZECHARS(szGUID));
  584.                 // {clsid} case, if not path compute from the registry
  585.                 if (!ParseField(pszCmdLine, ++i, szField, ARRAYSIZE(szField)))
  586.                 {
  587.                     // path must come from the registry now
  588.                     if (!GetRootFromRootClass(szGUID, szField, ARRAYSIZE(szField)))
  589.                     {
  590.                         return FALSE;   // bad command line
  591.                     }
  592.                 }
  593.                 IECreateFromPath(szField, &pidlRoot);
  594.                 pclsidRoot = &clsid;
  595.             }
  596.             else if (lstrcmpi(szField, TEXT("/IDLIST")) == 0)
  597.             {
  598.                 // /IDLIST
  599.                 pidlRoot = IDListFromCmdLine(pszCmdLine, ++i);
  600.             }
  601.             else
  602.             {
  603.                 // <path>
  604.                 IECreateFromPath(szField, &pidlRoot);
  605.             }
  606.             // fix up bad cmd line "explorer.exe /root," case
  607.             if (pidlRoot == NULL)
  608.                 SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pfi->pidlRoot);
  609.             if (pidlRoot)
  610.             {
  611.                 pfi->pidl = ILRootedCreateIDList(pclsidRoot, pidlRoot);
  612.                 ILFree(pidlRoot);
  613.             }
  614.         }
  615.         else if (lstrcmpi(szField, TEXT("/INPROC")) == 0)
  616.         {
  617.             // Parse and skip the next arg or 2
  618.             if (!ParseField(pszCmdLine, ++i, szField, ARRAYSIZE(szField)))
  619.             {
  620.                 return FALSE;
  621.             }
  622.             // The next arg must be a GUID
  623.             if (!GUIDFromString(szField, &pfi->clsidInProc))
  624.             {
  625.                 return FALSE;
  626.             }
  627.             pfi->uFlags |= COF_INPROC;
  628.         }
  629.         else if (lstrcmpi(szField, TEXT("/SELECT")) == 0)
  630.         {
  631.             pfi->uFlags |= COF_SELECT;
  632.         }
  633.         else if (lstrcmpi(szField, TEXT("/NOUI")) == 0)
  634.         {
  635.             pfi->uFlags |= COF_NOUI;
  636.         }
  637.         else if (lstrcmpi(szField, TEXT("-embedding")) == 0)
  638.         {
  639.             pfi->uFlags |= COF_AUTOMATION;
  640.         }
  641.         else  if (lstrcmpi(szField, TEXT("/IDLIST")) == 0)
  642.         {
  643.             LPITEMIDLIST pidl = IDListFromCmdLine(pszCmdLine, ++i);
  644.             if (pidl)
  645.             {
  646.                 if (pfi->pidl)
  647.                 {
  648.                     // again, this is kind of bogus (see comment below). If we already have a
  649.                     // pidl, free it and use the new one.
  650.                     ILFree(pfi->pidl);
  651.                 }
  652.                 pfi->pidl = pidl;
  653.             }
  654.             else if (pfi->pidl == NULL)
  655.             {
  656.                 // if we didn't have a pidl before and we dont have one now, we are screwed, so bail
  657.                 return FALSE;
  658.             }
  659.         }
  660.         else
  661.         {
  662.             LPITEMIDLIST pidl = ILCreateFromPath(szField);
  663.             if (!pidl)
  664.             {
  665.                 //
  666.                 //  LEGACY - if this is unparseable, then guess it is relative path
  667.                 //  this catches "explorer ." as opening the current directory
  668.                 //
  669.                 TCHAR szDir[MAX_PATH];
  670.                 TCHAR szCombined[MAX_PATH];
  671.                 GetCurrentDirectory(SIZECHARS(szDir), szDir);
  672.                 PathCombine(szCombined, szDir, szField);
  673.                 pidl = ILCreateFromPath(szCombined);
  674.             }
  675.             // this is kind of bogus: we have traditionally passed both the idlist (/idlist,:580:1612) and the path
  676.             // (C:WinntProfilesreinerfDesktop) as the default command string to explorer (see HKCRFoldershell
  677.             // opencommand). Since we have both a /idlist and a path, we have always used the latter so that is what
  678.             // we continue to do here.
  679.             if (pfi->pidl)
  680.             {
  681.                 // free the /idlist pidl and use the one from the path
  682.                 ILFree(pfi->pidl);
  683.             }
  684.             if (pidl)  
  685.             {
  686.                 pfi->pidl = pidl;
  687.                 pfi->uFlags |= COF_NOTRANSLATE;     // pidl is abosolute from the desktop
  688.             }
  689.             else
  690.             {
  691.                 pfi->pszPath = (LPSTR) StrDup(szField);
  692.                 if (pfi->pszPath)
  693.                 {
  694.                     pfi->uFlags |= COF_PARSEPATH;
  695.                 }
  696.             }
  697.         }
  698.     }
  699.     return TRUE;
  700. }