#include "priv.h" #include "hnfblock.h" #include #include "desktop.h" #include "shbrows2.h" #include "resource.h" #include "onetree.h" #include "apithk.h" #include #include "mluisupp.h" //forward declaration of private function BOOL _private_ParseField(LPCTSTR pszData, int n, LPTSTR szBuf, int iBufLen); BOOL _RootsEqual(HANDLE hCR, DWORD dwProcId, LPCITEMIDLIST pidlRoot) { BOOL bSame = FALSE; if (hCR) { LPITEMIDLIST pidl = (LPITEMIDLIST)SHLockShared(hCR, dwProcId); if (pidl) { bSame = ILIsEqualRoot(pidlRoot, pidl); SHUnlockShared(pidl); } } return bSame; } // NOTE: this export is new to IE5, so it can move to browseui // along with the rest of this proxy desktop code BOOL SHOnCWMCommandLine(LPARAM lParam) { HNFBLOCK hnf = (HNFBLOCK)lParam; IETHREADPARAM *piei = ConvertHNFBLOCKtoNFI(hnf); if (piei) return SHOpenFolderWindow(piei); // bad params passed, normal failure case return FALSE; } //--------------------------------------------------------------------------- // This proxy desktop window procedure is used when we are run and we // are not the shell. We are a hidden window which will simply respond // to messages like the ones that create threads for folder windows. // This window procedure will close after all of the open windows // associated with it go away. class CProxyDesktop { private: static LRESULT CALLBACK ProxyWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); friend CProxyDesktop *CreateProxyDesktop(IETHREADPARAM *piei); friend BOOL SHCreateFromDesktop(PNEWFOLDERINFO pfi); CProxyDesktop() {}; ~CProxyDesktop(); HWND _hwnd; LPITEMIDLIST _pidlRoot; }; CProxyDesktop::~CProxyDesktop() { ILFree(_pidlRoot); } LRESULT CALLBACK CProxyDesktop::ProxyWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { CProxyDesktop *pproxy = (CProxyDesktop *)GetWindowPtr0(hwnd); switch (msg) { case WM_CREATE: pproxy = (CProxyDesktop *)((CREATESTRUCT *)lParam)->lpCreateParams; SetWindowPtr0(hwnd, pproxy); pproxy->_hwnd = hwnd; return 0; // success case WM_DESTROY: if (pproxy) pproxy->_hwnd = NULL; return 0; case CWM_COMMANDLINE: SHOnCWMCommandLine(lParam); break; case CWM_COMPAREROOT: return _RootsEqual((HANDLE)lParam, (DWORD)wParam, pproxy->_pidlRoot); default: return DefWindowProcWrap(hwnd, msg, wParam, lParam); } return 0; } CProxyDesktop *CreateProxyDesktop(IETHREADPARAM *piei) { CProxyDesktop *pproxy = new CProxyDesktop(); if (pproxy) { WNDCLASS wc = {0}; wc.lpfnWndProc = CProxyDesktop::ProxyWndProc; wc.cbWndExtra = SIZEOF(CProxyDesktop *); wc.hInstance = HINST_THISDLL; wc.hbrBackground = (HBRUSH)(COLOR_DESKTOP + 1); wc.lpszClassName = DESKTOPPROXYCLASS; SHRegisterClass(&wc); if (CreateWindowEx(WS_EX_TOOLWINDOW, DESKTOPPROXYCLASS, DESKTOPPROXYCLASS, WS_POPUP, 0, 0, 0, 0, NULL, NULL, HINST_THISDLL, pproxy)) { if (ILIsRooted(piei->pidl)) { pproxy->_pidlRoot = ILCloneFirst(piei->pidl); if (pproxy->_pidlRoot == NULL) { DestroyWindow(pproxy->_hwnd); pproxy = NULL; } } } else { delete pproxy; pproxy = NULL; } } return pproxy; } // REVIEW: maybe just check (hwnd == GetShellWindow()) STDAPI_(BOOL) IsDesktopWindow(HWND hwnd) { TCHAR szName[80]; GetClassName(hwnd, szName, ARRAYSIZE(szName)); if (!lstrcmp(szName, DESKTOPCLASS)) { GetWindowText(hwnd, szName, ARRAYSIZE(szName)); return !lstrcmp(szName, PROGMAN); } return FALSE; } typedef struct { HWND hwndDesktop; HANDLE hCR; DWORD dwProcId; HWND hwndResult; } FRDSTRUCT; BOOL CALLBACK FindRootEnumProc(HWND hwnd, LPARAM lParam) { FRDSTRUCT *pfrds = (FRDSTRUCT *)lParam; TCHAR szClassName[40]; GetClassName(hwnd, szClassName, ARRAYSIZE(szClassName)); if (lstrcmpi(szClassName, DESKTOPPROXYCLASS) == 0) { ASSERT(hwnd != pfrds->hwndDesktop); if (SendMessage(hwnd, CWM_COMPAREROOT, (WPARAM)pfrds->dwProcId, (LPARAM)pfrds->hCR)) { // Found it, so stop enumerating pfrds->hwndResult = hwnd; return FALSE; } } return TRUE; } BOOL RunSeparateDesktop() { DWORD bSeparate = FALSE; if (SHRestricted(REST_SEPARATEDESKTOPPROCESS)) bSeparate = TRUE; else { SHELLSTATE ss; SHGetSetSettings(&ss, SSF_SEPPROCESS, FALSE); bSeparate = ss.fSepProcess; if (!bSeparate) { DWORD cbData = SIZEOF(bSeparate); SHGetValue(HKEY_CURRENT_USER, REGSTR_PATH_EXPLORER, TEXT("DesktopProcess"), NULL, &bSeparate, &cbData); } } return bSeparate; } // if we need to force some legacy rootet explorers into their own process, implement this. //#define _RootRunSeparateProcess(pidlRoot) ILIsRooted(pidlRoot) OLD BEHAVIOR #define _RootRunSeparateProcess(pidlRoot) FALSE HWND FindRootedDesktop(LPCITEMIDLIST pidlRoot) { HWND hwndDesktop = GetShellWindow(); // This is the "normal" desktop if (!RunSeparateDesktop() && !_RootRunSeparateProcess(pidlRoot) && hwndDesktop) { ASSERT(IsDesktopWindow(hwndDesktop)); return hwndDesktop; } FRDSTRUCT frds; frds.hwndDesktop = hwndDesktop; frds.hwndResult = NULL; // Initalize to no matching rooted expl frds.dwProcId = GetCurrentProcessId(); frds.hCR = SHAllocShared(pidlRoot, ILGetSize(pidlRoot), frds.dwProcId); if (frds.hCR) { EnumWindows(FindRootEnumProc, (LPARAM)&frds); SHFreeShared(frds.hCR, frds.dwProcId); } return frds.hwndResult; } UINT _GetProcessHotkey(void) { STARTUPINFO si = {SIZEOF(si)}; GetStartupInfo(&si); return (UINT)(DWORD_PTR)si.hStdInput; } void FolderInfoToIEThreadParam(PNEWFOLDERINFO pfi, IETHREADPARAM *piei) { piei->uFlags = pfi->uFlags; piei->nCmdShow = pfi->nShow; piei->wHotkey = _GetProcessHotkey(); ASSERT(pfi->pszRoot == NULL); // explorer always converts to a PIDL for us // we no longer support rooted explorers this way // it should have been filtered out above us. ASSERT(!pfi->pidlRoot); ASSERT(!(pfi->uFlags & (COF_ROOTCLASS | COF_NEWROOT))); ASSERT(IsEqualGUID(pfi->clsid, CLSID_NULL)); if (pfi->pidl) { piei->pidl = ILClone(pfi->pidl); } // COF_PARSEPATH means that we should defer the parsing of the pszPath else if (!(pfi->uFlags & COF_PARSEPATH) && pfi->pszPath && pfi->pszPath[0]) { // maybe should use IECreateFromPath?? // or maybe we should parse relative to the root?? piei->pidl = ILCreateFromPathA(pfi->pszPath); } } // IE4 Integrated delay loads CreateFromDesktop from SHDOCVW.DLL // So we need to keep this function here. Forward to the correct // implementation in SHELL32 (if integrated) or SHDOC41 (if not) BOOL SHCreateFromDesktop(PNEWFOLDERINFO pfi) { IETHREADPARAM *piei = SHCreateIETHREADPARAM(NULL, 0, NULL, NULL); if (piei) { // ASSUMING UNICODE COMPILE! LPCTSTR pszPath = NULL; HWND hwndDesktop; if (pfi->uFlags & COF_PARSEPATH) { ASSERT(!pfi->pidl); pszPath = (LPCTSTR) pfi->pszPath; } FolderInfoToIEThreadParam(pfi, piei); if (pfi->uFlags & COF_SEPARATEPROCESS) { hwndDesktop = NULL; // Assume no desktop process exists } else { hwndDesktop = FindRootedDesktop(piei->pidl); } if (hwndDesktop) { DWORD dwProcId; DWORD dwThreadId = GetWindowThreadProcessId(hwndDesktop, &dwProcId); AllowSetForegroundWindow(dwProcId); HNFBLOCK hBlock = ConvertNFItoHNFBLOCK(piei, pszPath, dwProcId); if (hBlock) { PostMessage(hwndDesktop, CWM_COMMANDLINE, 0, (LPARAM)hBlock); HANDLE hExplorer = OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, dwProcId ); if ( hExplorer ) { // wait for input idle 10 seconds. WaitForInputIdle( hExplorer, 10000 ); CloseHandle( hExplorer ); } } } else { HRESULT hrInit = SHCoInitialize(); CProxyDesktop *pproxy = CreateProxyDesktop(piei); if (pproxy) { // CRefThread controls this processes reference count. browser windows use this // to keep this process (window) around and this also lets thrid parties hold // references to our process, MSN uses this for example LONG cRefMsgLoop; IUnknown *punkRefMsgLoop; if (SUCCEEDED(SHCreateThreadRef(&cRefMsgLoop, &punkRefMsgLoop))) { SHSetInstanceExplorer(punkRefMsgLoop); // we needed to wait for this for the CoInit() if (pszPath) piei->pidl = ILCreateFromPath(pszPath); SHOpenFolderWindow(piei); piei = NULL; // OpenFolderWindow() takes ownership of this punkRefMsgLoop->Release(); // we now depend on the browser window to keep our msg loop } MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { if (cRefMsgLoop == 0) break; // no more refs on this thread, done TranslateMessage(&msg); DispatchMessage(&msg); } delete pproxy; } SHCoUninitialize(hrInit); } if (piei) SHDestroyIETHREADPARAM(piei); } return TRUE; // no one pays attention to this } HNFBLOCK ConvertNFItoHNFBLOCK(IETHREADPARAM* pInfo, LPCTSTR pszPath, DWORD dwProcId) { UINT uSize; UINT uPidl; UINT uPidlSelect; UINT uPidlRoot; UINT upszPath; PNEWFOLDERBLOCK pnfb; LPBYTE lpb; HNFBLOCK hBlock; LPVOID pidlRootOrMonitor = NULL; // pidlRoot or &hMonitor uSize = SIZEOF(NEWFOLDERBLOCK); if (pInfo->pidl) { uPidl = ILGetSize(pInfo->pidl); uSize += uPidl; } if (pInfo->pidlSelect) { uPidlSelect = ILGetSize(pInfo->pidlSelect); uSize += uPidlSelect; } if (pInfo->uFlags & COF_HASHMONITOR) { pidlRootOrMonitor = &pInfo->pidlRoot; uPidlRoot = sizeof(HMONITOR); uSize += uPidlRoot; } else if (pInfo->pidlRoot) { pidlRootOrMonitor = pInfo->pidlRoot; uPidlRoot = ILGetSize(pInfo->pidlRoot); uSize += uPidlRoot; } if (pszPath) { upszPath = CbFromCch(lstrlen(pszPath) + 1); uSize += upszPath; } hBlock = (HNFBLOCK)SHAllocShared(NULL, uSize, dwProcId); if (hBlock == NULL) return NULL; pnfb = (PNEWFOLDERBLOCK)SHLockShared(hBlock, dwProcId); if (pnfb == NULL) { SHFreeShared(hBlock, dwProcId); return NULL; } pnfb->dwSize = uSize; pnfb->uFlags = pInfo->uFlags; pnfb->nShow = pInfo->nCmdShow; pnfb->dwHwndCaller= PtrToInt(pInfo->hwndCaller); pnfb->dwHotKey = pInfo->wHotkey; pnfb->clsid = pInfo->clsid; pnfb->clsidInProc = pInfo->clsidInProc; pnfb->oidl = 0; pnfb->oidlSelect = 0; pnfb->oidlRoot = 0; pnfb->opszPath = 0; lpb = (LPBYTE)(pnfb+1); // Point just past the structure if (pInfo->pidl) { memcpy(lpb,pInfo->pidl,uPidl); pnfb->oidl = (int)(lpb-(LPBYTE)pnfb); lpb += uPidl; } if (pInfo->pidlSelect) { memcpy(lpb,pInfo->pidlSelect,uPidlSelect); pnfb->oidlSelect = (int)(lpb-(LPBYTE)pnfb); lpb += uPidlSelect; } if (pidlRootOrMonitor) { memcpy(lpb, pidlRootOrMonitor, uPidlRoot); pnfb->oidlRoot = (int)(lpb-(LPBYTE)pnfb); lpb += uPidlRoot; } if (pszPath) { memcpy(lpb, pszPath, upszPath); pnfb->opszPath = (int)(lpb-(LPBYTE)pnfb); lpb += upszPath; } SHUnlockShared(pnfb); return hBlock; } IETHREADPARAM* ConvertHNFBLOCKtoNFI(HNFBLOCK hBlock) { BOOL fFailure = FALSE; IETHREADPARAM* piei = NULL; if (hBlock) { DWORD dwProcId = GetCurrentProcessId(); PNEWFOLDERBLOCK pnfb = (PNEWFOLDERBLOCK)SHLockShared(hBlock, dwProcId); if (pnfb) { if (pnfb->dwSize >= SIZEOF(NEWFOLDERBLOCK)) { piei = SHCreateIETHREADPARAM(NULL, pnfb->nShow, NULL, NULL); if (piei) { LPITEMIDLIST pidl = NULL; piei->uFlags = pnfb->uFlags; piei->hwndCaller = IntToPtr_(HWND, pnfb->dwHwndCaller); piei->wHotkey = pnfb->dwHotKey; piei->clsid = pnfb->clsid; piei->clsidInProc = pnfb->clsidInProc; if (pnfb->oidlSelect) piei->pidlSelect = ILClone((LPITEMIDLIST)((LPBYTE)pnfb+pnfb->oidlSelect)); if (pnfb->oidlRoot) { LPITEMIDLIST pidlRoot = (LPITEMIDLIST)((LPBYTE)pnfb+pnfb->oidlRoot); if (pnfb->uFlags & COF_HASHMONITOR) { piei->pidlRoot = (LPITEMIDLIST)*(UNALIGNED HMONITOR *)pidlRoot; } else { piei->pidlRoot = ILClone(pidl); } } if (pnfb->oidl) pidl = ILClone((LPITEMIDLIST)((LPBYTE)pnfb+pnfb->oidl)); if (pidl) { piei->pidl = pidl; } // we pass this string through because msn fails the cocreateinstane of // their desktop if another one is up and running, so we can't convert // this from path to pidl except in the current process context if (pnfb->opszPath) { LPTSTR pszPath = (LPTSTR)((LPBYTE)pnfb+pnfb->opszPath); HRESULT hr = E_FAIL; if (ILIsRooted(pidl)) { // let the root handle the parsing. IShellFolder *psf; if (SUCCEEDED(IEBindToObject(pidl, &psf))) { hr = IShellFolder_ParseDisplayName(psf, NULL, NULL, pszPath, NULL, &(piei->pidl), NULL); psf->Release(); } } else IECreateFromPath(pszPath, &(piei->pidl)); // APP COMPAT: these two specific return result codes are the two we ignored for win95. // APP COMPAT: MSN 1.3 Classic accidentally on purpose returns one of these... if ( !piei->pidl ) { // failed, report the error to the user ... (will only fail for paths) ASSERT( !PathIsURL( pszPath)) if (! (piei->uFlags & COF_NOTUSERDRIVEN) && ( hr != E_OUTOFMEMORY ) && ( hr != HRESULT_FROM_WIN32( ERROR_CANCELLED ))) { MLShellMessageBox( NULL, MAKEINTRESOURCE( IDS_NOTADIR ), MAKEINTRESOURCE( IDS_CABINET ), MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND, pszPath); } fFailure = TRUE; } } } } SHUnlockShared(pnfb); } SHFreeShared(hBlock, dwProcId); } // if we really failed somewhere, return NULL if (fFailure) { SHDestroyIETHREADPARAM(piei); piei = NULL; } return piei; } // Check the registry for a shell root under this CLSID. BOOL GetRootFromRootClass(LPCTSTR pszGUID, LPTSTR pszPath, int cchPath) { BOOL bRet; TCHAR szClass[MAX_PATH]; if (SUCCEEDED(StringCchPrintf(szClass, ARRAYSIZE(szClass), TEXT("CLSID\\%s\\ShellExplorerRoot"), pszGUID))) { // REVIEW: Do we need SRRF_RM_NORMAL? Is there a reason we wouldn't // want this to succeed in either safe or safe network boot modes? DWORD cbPath = cchPath * sizeof(TCHAR); bRet = ERROR_SUCCESS == SHRegGetValue(HKEY_CLASSES_ROOT, szClass, NULL, SRRF_RT_REG_SZ | SRRF_RM_NORMAL, NULL, pszPath, &cbPath); } else { bRet = FALSE; } return bRet; } // format is "::" LPITEMIDLIST IDListFromCmdLine(LPCTSTR pszCmdLine, int i) { LPITEMIDLIST pidl = NULL; TCHAR szField[80]; if (_private_ParseField(pszCmdLine, i, szField, ARRAYSIZE(szField)) && szField[0] == TEXT(':')) { // Convert the string of format "::" into a pointer HANDLE hMem = LongToHandle(StrToLong(szField + 1)); LPTSTR pszNextColon = StrChr(szField + 1, TEXT(':')); if (pszNextColon) { DWORD dwProcId = (DWORD)StrToLong(pszNextColon + 1); LPITEMIDLIST pidlGlobal = (LPITEMIDLIST) SHLockShared(hMem, dwProcId); if (pidlGlobal) { pidl = ILClone(pidlGlobal); SHUnlockShared(pidlGlobal); SHFreeShared(hMem, dwProcId); } } } return pidl; } #define MYDOCS_CLSIDW L"{450d8fba-ad25-11d0-98a8-0800361b1103}" // CLSID_MyDocuments LPITEMIDLIST MyDocsIDList(void) { LPITEMIDLIST pidl = NULL; IShellFolder *psf; HRESULT hres = SHGetDesktopFolder(&psf); if (SUCCEEDED(hres)) { hres = psf->ParseDisplayName(NULL, NULL, L"::" MYDOCS_CLSIDW, NULL, &pidl, NULL); psf->Release(); } // Win95/NT4 case, go for the real MyDocs folder if (FAILED(hres)) { hres = SHGetSpecialFolderLocation(NULL, CSIDL_PERSONAL, &pidl); } return SUCCEEDED(hres) ? pidl : NULL; } BOOL SHExplorerParseCmdLine(PNEWFOLDERINFO pfi) { int i; TCHAR szField[MAX_PATH]; LPCTSTR pszCmdLine = GetCommandLine(); pszCmdLine = PathGetArgs(pszCmdLine); // empty command line -> explorer My Docs if (*pszCmdLine == 0) { pfi->uFlags = COF_CREATENEWWINDOW | COF_EXPLORE; // try MyDocs first? pfi->pidl = MyDocsIDList(); if (pfi->pidl == NULL) { TCHAR szPath[MAX_PATH]; GetWindowsDirectory(szPath, ARRAYSIZE(szPath)); PathStripToRoot(szPath); pfi->pidl = ILCreateFromPath(szPath); } return BOOLFROMPTR(pfi->pidl); } // Arguments must be separated by '=' or ',' for (i = 1; _private_ParseField(pszCmdLine, i, szField, ARRAYSIZE(szField)); i++) { if (lstrcmpi(szField, TEXT("/N")) == 0) { pfi->uFlags |= COF_CREATENEWWINDOW | COF_NOFINDWINDOW; } else if (lstrcmpi(szField, TEXT("/S")) == 0) { pfi->uFlags |= COF_USEOPENSETTINGS; } else if (lstrcmpi(szField, TEXT("/E")) == 0) { pfi->uFlags |= COF_EXPLORE; } else if (lstrcmpi(szField, TEXT("/ROOT")) == 0) { LPITEMIDLIST pidlRoot = NULL; CLSID *pclsidRoot = NULL; CLSID clsid; RIPMSG(!pfi->pidl, "SHExplorerParseCommandLine: (/ROOT) caller passed bad params"); // of the form: // /ROOT,{clsid}[,] // /ROOT,/IDLIST,:: // /ROOT, if (!_private_ParseField(pszCmdLine, ++i, szField, ARRAYSIZE(szField))) return FALSE; // {clsid} if (GUIDFromString(szField, &clsid)) { TCHAR szGUID[GUIDSTR_MAX]; StringCchCopy(szGUID, ARRAYSIZE(szGUID), szField); // {clsid} case, if not path compute from the registry if (!_private_ParseField(pszCmdLine, ++i, szField, ARRAYSIZE(szField))) { // path must come from the registry now if (!GetRootFromRootClass(szGUID, szField, ARRAYSIZE(szField))) { return FALSE; // bad command line } } IECreateFromPath(szField, &pidlRoot); pclsidRoot = &clsid; } else if (lstrcmpi(szField, TEXT("/IDLIST")) == 0) { // /IDLIST pidlRoot = IDListFromCmdLine(pszCmdLine, ++i); } else { // IECreateFromPath(szField, &pidlRoot); } // fix up bad cmd line "explorer.exe /root," case if (pidlRoot == NULL) { HRESULT hr = SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pfi->pidlRoot); if (FAILED(hr)) { pfi->pidlRoot = NULL; } } if (pidlRoot) { pfi->pidl = ILRootedCreateIDList(pclsidRoot, pidlRoot); ILFree(pidlRoot); } } else if (lstrcmpi(szField, TEXT("/INPROC")) == 0) { // Parse and skip the next arg or 2 if (!_private_ParseField(pszCmdLine, ++i, szField, ARRAYSIZE(szField))) { return FALSE; } // The next arg must be a GUID if (!GUIDFromString(szField, &pfi->clsidInProc)) { return FALSE; } pfi->uFlags |= COF_INPROC; } else if (lstrcmpi(szField, TEXT("/SELECT")) == 0) { pfi->uFlags |= COF_SELECT; } else if (lstrcmpi(szField, TEXT("/NOUI")) == 0) { pfi->uFlags |= COF_NOUI; } else if (lstrcmpi(szField, TEXT("-embedding")) == 0) { pfi->uFlags |= COF_AUTOMATION; } else if (lstrcmpi(szField, TEXT("/IDLIST")) == 0) { LPITEMIDLIST pidl = IDListFromCmdLine(pszCmdLine, ++i); if (pidl) { if (pfi->pidl) { // again, this is kind of bogus (see comment below). If we already have a // pidl, free it and use the new one. ILFree(pfi->pidl); } pfi->pidl = pidl; } else if (pfi->pidl == NULL) { // if we didn't have a pidl before and we dont have one now, we are in trouble, so get out return FALSE; } } else if (lstrcmpi(szField, TEXT("/SEPARATE")) == 0) { pfi->uFlags |= COF_SEPARATEPROCESS; } else { LPITEMIDLIST pidl = ILCreateFromPath(szField); if (!pidl) { // // LEGACY - if this is unparseable, then guess it is relative path // this catches "explorer ." as opening the current directory // TCHAR szDir[MAX_PATH]; TCHAR szCombined[MAX_PATH]; DWORD lenDir = GetCurrentDirectory(ARRAYSIZE(szDir), szDir); if (lenDir > 0 && lenDir < ARRAYSIZE(szDir) && NULL != PathCombine(szCombined, szDir, szField)) { pidl = ILCreateFromPath(szCombined); } } // this is kind of bogus: we have traditionally passed both the idlist (/idlist,:580:1612) and the path // (C:\Winnt\Profiles\reinerf\Desktop) as the default command string to explorer (see HKCR\Folder\shell // \open\command). Since we have both a /idlist and a path, we have always used the latter so that is what // we continue to do here. if (pfi->pidl) { ILFree(pfi->pidl); // free the /idlist pidl and use the one from the path } pfi->pidl = pidl; if (pidl) { pfi->uFlags |= COF_NOTRANSLATE; // pidl is abosolute from the desktop } else { pfi->pszPath = (LPSTR) StrDup(szField); if (pfi->pszPath) { pfi->uFlags |= COF_PARSEPATH; } } } } return TRUE; } #define ISSEP(c) ((c) == TEXT('=') || (c) == TEXT(',')) #define ISWHITE(c) ((c) == TEXT(' ') || (c) == TEXT('\t') || (c) == TEXT('\n') || (c) == TEXT('\r')) #define ISNOISE(c) ((c) == TEXT('"')) #define QUOTE TEXT('"') #define COMMA TEXT(',') #define SPACE TEXT(' ') #define EQUAL TEXT('=') /* BOOL ParseField(szData,n,szBuf,iBufLen) * * Given a line from SETUP.INF, will extract the nth field from the string * fields are assumed separated by comma's. Leading and trailing spaces * are removed. * * ENTRY: * * szData : pointer to line from SETUP.INF * n : field to extract. ( 1 based ) * 0 is field before a '=' sign * szDataStr : pointer to buffer to hold extracted field * iBufLen : size of buffer to receive extracted field. * * EXIT: returns TRUE if successful, FALSE if failure. * * Copied from shell32\util.cpp * note that this is now used to parse the Explorer command line * --ccooney */ BOOL _private_ParseField(LPCTSTR pszData, int n, LPTSTR szBuf, int iBufLen) { BOOL fQuote = FALSE; LPCTSTR pszInf = pszData; LPTSTR ptr; int iLen = 1; if (!pszData || !szBuf) return FALSE; /* * find the first separator */ while (*pszInf && !ISSEP(*pszInf)) { if (*pszInf == QUOTE) fQuote = !fQuote; pszInf = CharNext(pszInf); } if (n == 0 && *pszInf != TEXT('=')) return FALSE; if (n > 0 && *pszInf == TEXT('=') && !fQuote) // Change pszData to point to first field pszData = ++pszInf; // Ok for DBCS /* * locate the nth comma, that is not inside of quotes */ fQuote = FALSE; while (n > 1) { while (*pszData) { if (!fQuote && ISSEP(*pszData)) break; if (*pszData == QUOTE) fQuote = !fQuote; pszData = CharNext(pszData); } if (!*pszData) { szBuf[0] = 0; // make szBuf empty return FALSE; } pszData = CharNext(pszData); // we could do ++ here since we got here // after finding comma or equal n--; } /* * now copy the field to szBuf */ while (ISWHITE(*pszData)) pszData = CharNext(pszData); // we could do ++ here since white space can // NOT be a lead byte fQuote = FALSE; ptr = szBuf; // fill output buffer with this while (*pszData) { if (*pszData == QUOTE) { // // If we're in quotes already, maybe this // is a double quote as in: "He said ""Hello"" to me" // if (fQuote && *(pszData+1) == QUOTE) // Yep, double-quoting - QUOTE is non-DBCS { if (iLen < iBufLen) { *ptr++ = QUOTE; ++iLen; } pszData++; // now skip past 1st quote } else fQuote = !fQuote; } else if (!fQuote && ISSEP(*pszData)) break; else { if ( iLen < iBufLen ) { *ptr++ = *pszData; // Thank you, Dave ++iLen; } if ( IsDBCSLeadByte(*pszData) && (iLen < iBufLen) ) { *ptr++ = pszData[1]; ++iLen; } } pszData = CharNext(pszData); } /* * remove trailing spaces */ while (ptr > szBuf) { ptr = CharPrev(szBuf, ptr); if (!ISWHITE(*ptr)) { ptr = CharNext(ptr); break; } } *ptr = 0; return TRUE; }