|
|
#include "priv.h"
#include "hnfblock.h"
#include <trayp.h>
#include "desktop.h"
#include "shbrows2.h"
#include "resource.h"
#include "onetree.h"
#include "apithk.h"
#include <regitemp.h>
#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 ":<hMem>:<hProcess>"
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 ":<hmem>:<hprocess>" 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}[,<path>]
// /ROOT,/IDLIST,:<hmem>:<hprocess>
// /ROOT,<path>
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 { // <path>
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; }
|