|
|
#include "shellprv.h"
#include "util.h"
#include "idlcomm.h"
#include <uxtheme.h>
#include <tmschema.h>
// shdocvw and browseui share brutil and menubands need it too
// unfortunately shell32 isnt set up quite like shdocvw and browseui so
// these have to be hacked in a little
#define MAX_BROWSER_WINDOW_TITLE 128
#define g_fRunningOnNT TRUE
#define InitClipboardFormats IDLData_InitializeClipboardFormats
#define g_cfFileDescA g_cfFileGroupDescriptorA
#define g_cfFileDescW g_cfFileGroupDescriptorW
#define g_cfURL g_cfShellURL
#define PVAREMPTY ((VARIANT*)&c_vaEmpty)
#define NO_MLUI_IN_SHELL32
#include "..\inc\brutil.cpp"
const VARIANT c_vaEmpty = {0};
HRESULT QueryService_SID_IBandProxy(IUnknown * punkParent, REFIID riid, IBandProxy ** ppbp, void **ppvObj) { HRESULT hr = E_FAIL;
if (ppbp) { if (NULL == (*ppbp)) hr = IUnknown_QueryService(punkParent, SID_IBandProxy, IID_PPV_ARG(IBandProxy, ppbp));
if (*ppbp && ppvObj) hr = (*ppbp)->QueryInterface(riid, ppvObj); // They already have the object.
}
return hr; }
HRESULT CreateIBandProxyAndSetSite(IUnknown * punkParent, REFIID riid, IBandProxy ** ppbp, void **ppvObj) { ASSERT(ppbp);
HRESULT hr = CoCreateInstance(CLSID_BandProxy, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IBandProxy, ppbp)); if (SUCCEEDED(hr)) { // Set the site
ASSERT(*ppbp); (*ppbp)->SetSite(punkParent);
if (ppvObj) hr = (*ppbp)->QueryInterface(riid, ppvObj); } else { if (ppvObj) *ppvObj = NULL; } return hr; }
typedef struct tagINIPAIR { DWORD dwFlags; LPCTSTR pszSection; } INIPAIR;
const INIPAIR c_aIniPairs[] = { EICH_KINET, TEXT("Software\\Microsoft\\Internet Explorer"), EICH_KINETMAIN, TEXT("Software\\Microsoft\\Internet Explorer\\Main"), EICH_KWIN, TEXT("Software\\Microsoft\\Windows\\CurrentVersion"), EICH_KWINEXPLORER, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"), EICH_KWINEXPLSMICO, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\SmallIcons"), EICH_KWINPOLICY, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies"), EICH_SSAVETASKBAR, TEXT("SaveTaskbar"), EICH_SWINDOWMETRICS, TEXT("WindowMetrics"), EICH_SSHELLMENU, TEXT("ShellMenu"), EICH_SPOLICY, TEXT("Policy"), EICH_SWINDOWS, TEXT("Windows"), };
DWORD SHIsExplorerIniChange(WPARAM wParam, LPARAM lParam) { DWORD dwFlags = 0;
if (lParam == 0) { if (wParam == 0) { dwFlags = EICH_UNKNOWN; } } else { //
// In the wacky world of browseui, UNICODE-ANSI doesn't vary from
// window to window. Instead, on NT browseui registers all windows
// UNICODE, while on 9x user browseui registers all windows ANSI.
//
LPCTSTR pszSection = (LPCWSTR)lParam;
for (int i = 0; !dwFlags && i < ARRAYSIZE(c_aIniPairs); i++) { if (StrCmpI(pszSection, c_aIniPairs[i].pszSection) == 0) { dwFlags = c_aIniPairs[i].dwFlags; } } }
return dwFlags; }
ULONG RegisterNotify(HWND hwnd, UINT nMsg, LPCITEMIDLIST pidl, DWORD dwEvents, UINT uFlags, BOOL fRecursive) { SHChangeNotifyEntry fsne;
uFlags |= SHCNRF_NewDelivery;
fsne.fRecursive = fRecursive; fsne.pidl = pidl; return SHChangeNotifyRegister(hwnd, uFlags, dwEvents, nMsg, 1, &fsne); }
BOOL GetInfoTipEx(IShellFolder* psf, DWORD dwFlags, LPCITEMIDLIST pidl, LPTSTR pszText, int cchTextMax) { BOOL fRet = FALSE;
*pszText = 0; // empty for failure
if (pidl) { IQueryInfo *pqi; if (SUCCEEDED(psf->GetUIObjectOf(NULL, 1, &pidl, IID_X_PPV_ARG(IQueryInfo, NULL, &pqi)))) { WCHAR *pwszTip; pqi->GetInfoTip(dwFlags, &pwszTip); if (pwszTip) { fRet = TRUE; SHUnicodeToTChar(pwszTip, pszText, cchTextMax); SHFree(pwszTip); } pqi->Release(); } } return fRet; }
BOOL GetInfoTip(IShellFolder* psf, LPCITEMIDLIST pidl, LPTSTR pszText, int cchTextMax) { return GetInfoTipEx(psf, 0, pidl, pszText, cchTextMax); }
// does filename based lookup to see if a file is browsable or not.
// this is probably vulnerable to ::$DATA stuff so DO NOT use it for deciding whether to
// shellexecute or something.
// right now all its used for is if a menu should cascade on the file.
BOOL IsBrowsableShellExt(LPCITEMIDLIST pidl) { DWORD cb; LPCTSTR pszExt; TCHAR szFile[MAX_PATH]; TCHAR szProgID[80]; // From ..\shell32\fstreex.c
TCHAR szCLSID[GUIDSTR_MAX], szCATID[GUIDSTR_MAX]; TCHAR szKey[GUIDSTR_MAX * 4]; HKEY hkeyProgID = NULL; BOOL fRet = FALSE;
for (;;) { // Make sure we have a file extension
if ( !SHGetPathFromIDList(pidl, szFile) || ((pszExt = PathFindExtension(szFile)) == NULL) || (pszExt[0] != TEXT('.')) ) { break; }
// Get the ProgID.
cb = sizeof(szProgID); if ( (SHGetValue(HKEY_CLASSES_ROOT, pszExt, NULL, NULL, szProgID, &cb) != ERROR_SUCCESS) || (RegOpenKeyEx(HKEY_CLASSES_ROOT, szProgID, 0, KEY_READ, &hkeyProgID) != ERROR_SUCCESS) ) { break; }
// From the ProgID, get the CLSID.
cb = sizeof(szCLSID); if (SHGetValue(hkeyProgID, TEXT("CLSID"), NULL, NULL, szCLSID, &cb) != ERROR_SUCCESS) break;
// Construct the registry key that detects if
// a CLSID is a member of a CATID.
SHStringFromGUID(CATID_BrowsableShellExt, szCATID, ARRAYSIZE(szCATID)); wnsprintf(szKey, ARRAYSIZE(szKey), TEXT("CLSID\\%s\\Implemented Categories\\%s"), szCLSID, szCATID);
// See if it's there.
cb = 0; if (SHGetValue(HKEY_CLASSES_ROOT, szKey, NULL, NULL, NULL, &cb) != ERROR_SUCCESS) break;
fRet = TRUE; break; }
if (hkeyProgID != NULL) RegCloseKey(hkeyProgID);
return fRet; }
void OpenFolderPidl(LPCITEMIDLIST pidl) { SHELLEXECUTEINFO shei = { 0 };
shei.cbSize = sizeof(shei); shei.fMask = SEE_MASK_INVOKEIDLIST; shei.nShow = SW_SHOWNORMAL; shei.lpIDList = (LPITEMIDLIST)pidl; // callers are responsible -- this is called only from sftbar in response to invokecommand
ShellExecuteEx(&shei); }
// As perf, share IShellLink implementations between bands and ask
// the bandsite for an implementation. Don't rely on the bandsite
// because you never know who will host us in the future. (And bandsite
// can change to not have us hosted at save/load time. Ex: it doesn't
// set our site before loading us from the stream, which sounds buggy.)
//
HRESULT SavePidlAsLink(IUnknown* punkSite, IStream *pstm, LPCITEMIDLIST pidl) { HRESULT hr = E_FAIL; IShellLinkA* psl;
if (punkSite) hr = IUnknown_QueryService(punkSite, IID_IBandSite, IID_PPV_ARG(IShellLinkA, &psl)); if (FAILED(hr)) hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellLinkA, &psl)); if (SUCCEEDED(hr)) { IPersistStream *pps; hr = psl->QueryInterface(IID_PPV_ARG(IPersistStream, &pps)); if (EVAL(SUCCEEDED(hr))) { ASSERT(pidl); psl->SetIDList(pidl);
hr = pps->Save(pstm, FALSE); pps->Release(); } psl->Release(); } return hr; }
HRESULT LoadPidlAsLink(IUnknown* punkSite, IStream *pstm, LPITEMIDLIST *ppidl) { IShellLinkA* psl; HRESULT hr = IUnknown_QueryService(punkSite, IID_IBandSite, IID_PPV_ARG(IShellLinkA, &psl)); if (FAILED(hr)) hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellLinkA, &psl)); if (SUCCEEDED(hr)) { IPersistStream *pps; hr = psl->QueryInterface(IID_PPV_ARG(IPersistStream, &pps)); if (EVAL(SUCCEEDED(hr))) { // link responsible for loading correctly
hr = pps->Load(pstm); if (EVAL(SUCCEEDED(hr))) { hr = psl->GetIDList(ppidl);
// Don't make me resolve the link because it's soo slow because
// it often loads 80k of networking dlls.
if (!EVAL(SUCCEEDED(hr))) { hr = psl->Resolve(NULL, SLR_NOUPDATE | SLR_NO_UI); if (EVAL(SUCCEEDED(hr))) hr = psl->GetIDList(ppidl); }
hr = *ppidl ? S_OK : E_FAIL; } pps->Release(); } psl->Release(); } return hr; }
// Review chrisny: this can be moved into an object easily to handle generic droptarget, dropcursor
// , autoscrool, etc. . .
void _DragEnter(HWND hwndTarget, const POINTL ptStart, IDataObject *pdtObject) { RECT rc; POINT pt;
GetWindowRect(hwndTarget, &rc);
//
// If hwndTarget is RTL mirrored, then measure the
// the client point from the visual right edge
// (near edge in RTL mirrored windows). [samera]
//
if (IS_WINDOW_RTL_MIRRORED(hwndTarget)) pt.x = rc.right - ptStart.x; else pt.x = ptStart.x - rc.left;
pt.y = ptStart.y - rc.top; DAD_DragEnterEx2(hwndTarget, pt, pdtObject); return; }
void _DragMove(HWND hwndTarget, const POINTL ptStart) { RECT rc; POINT pt;
GetWindowRect(hwndTarget, &rc);
//
// If hwndTarget is RTL mirrored, then measure the
// the client point from the visual right edge
// (near edge in RTL mirrored windows). [samera]
//
if (IS_WINDOW_RTL_MIRRORED(hwndTarget)) pt.x = rc.right - ptStart.x; else pt.x = ptStart.x - rc.left;
pt.y = ptStart.y - rc.top; DAD_DragMove(pt); return; }
// Can we browse or navigate to this pidl? If not, need
BOOL ILIsBrowsable(LPCITEMIDLIST pidl, BOOL *pfIsFolder) { if (!pidl) return FALSE; DWORD dwAttributes = SFGAO_FOLDER | SFGAO_BROWSABLE; HRESULT hr = IEGetAttributesOf(pidl, &dwAttributes);
if (pfIsFolder && SUCCEEDED(hr)) *pfIsFolder = dwAttributes & SFGAO_FOLDER;
return SUCCEEDED(hr) && (dwAttributes & (SFGAO_FOLDER | SFGAO_BROWSABLE)); }
// gets a target pidl given a name space item. typically this is a .lnk or .url file
//
// in:
// psf shell folder for item
// pidl item relative to psf, single level
//
// in/out
// pdwAttribs [optional] attributes mask to filter on (returned).
// must be initalized
//
//
// returns
// *ppidl the target pidl
// *pdwAttribs [optional] attributes of the source object
STDAPI SHGetNavigateTarget(IShellFolder *psf, LPCITEMIDLIST pidl, LPITEMIDLIST *ppidl, DWORD *pdwAttribs) { ASSERT(IS_VALID_CODE_PTR(psf, IShellFolder)); ASSERT(IS_VALID_PIDL(pidl)); ASSERT(NULL == pdwAttribs || IS_VALID_WRITE_PTR(pdwAttribs, DWORD)); ASSERT(ILFindLastID(pidl) == pidl); // must be single level PIDL
*ppidl = NULL; // assume failure
DWORD dwAttribs = SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_LINK | SFGAO_BROWSABLE;
if (pdwAttribs) dwAttribs |= *pdwAttribs;
HRESULT hr = psf->GetAttributesOf(1, &pidl, &dwAttribs); if (SUCCEEDED(hr)) { // first try the most efficient way
IShellLinkA *psl; // "A" so this works on Win95
hr = psf->GetUIObjectOf(NULL, 1, &pidl, IID_X_PPV_ARG(IShellLinkA, NULL, &psl)); if (SUCCEEDED(hr)) { hr = psl->GetIDList(ppidl); psl->Release(); }
// this is for .lnk and .url files that don't register properly
if (FAILED(hr) && (dwAttribs & (SFGAO_FILESYSTEM | SFGAO_LINK)) == (SFGAO_FILESYSTEM | SFGAO_LINK)) { TCHAR szPath[MAX_PATH];
hr = GetPathForItem(psf, pidl, szPath, NULL); if (SUCCEEDED(hr)) hr = GetLinkTargetIDList(szPath, NULL, 0, ppidl); }
// .doc or .html. return the pidl for this.
// (fully qualify against the folder pidl)
if (FAILED(hr) && (dwAttribs & SFGAO_BROWSABLE)) { LPITEMIDLIST pidlFolder; hr = SHGetIDListFromUnk(psf, &pidlFolder); if (SUCCEEDED(hr)) { *ppidl = ILCombine(pidlFolder, pidl); // navigate to this thing...
hr = *ppidl ? S_OK : E_OUTOFMEMORY; ILFree(pidlFolder); } }
// Callers of SHGetNavigateTarget assume that the returned pidl
// is navigatable (SFGAO_FOLDER or SFGAO_BROWSER), which isn't
// the case for a link (it could be a link to an exe).
//
if (SUCCEEDED(hr) && !ILIsBrowsable(*ppidl, NULL)) { ILFree(*ppidl); *ppidl = NULL; hr = E_FAIL; }
if (SUCCEEDED(hr) && pdwAttribs) *pdwAttribs = dwAttribs; } return hr; }
STDAPI SHNavigateToFavorite(IShellFolder* psf, LPCITEMIDLIST pidl, IUnknown* punkSite, DWORD dwFlags) { HRESULT hr = S_FALSE;
TCHAR szPath[MAX_PATH];
// Can we navigate to this favorite?
BOOL fNavigateDone = SUCCEEDED(GetPathForItem(psf, pidl, szPath, NULL)) && SUCCEEDED(NavFrameWithFile(szPath, punkSite)); if (fNavigateDone) return S_OK;
LPITEMIDLIST pidlGoto;
ASSERT(!(dwFlags & (SBSP_NEWBROWSER | SBSP_SAMEBROWSER))); if (SUCCEEDED(SHGetNavigateTarget(psf, pidl, &pidlGoto, NULL))) { IShellBrowser* psb; if (SUCCEEDED(IUnknown_QueryService(punkSite, SID_STopLevelBrowser, IID_PPV_ARG(IShellBrowser, &psb)))) { hr = psb->BrowseObject(pidlGoto, dwFlags | SBSP_SAMEBROWSER); psb->Release(); } ILFree(pidlGoto); } return hr; }
STDAPI SHGetTopBrowserWindow(IUnknown* punk, HWND* phwnd) { IOleWindow* pOleWindow; HRESULT hr = IUnknown_QueryService(punk, SID_STopLevelBrowser, IID_PPV_ARG(IOleWindow, &pOleWindow)); if (SUCCEEDED(hr)) { hr = pOleWindow->GetWindow(phwnd); pOleWindow->Release(); } return hr; }
void SHOutlineRect(HDC hdc, const RECT* prc, COLORREF cr) { RECT rc; COLORREF clrSave = SetBkColor(hdc, cr); //top
rc.left = prc->left; rc.top = prc->top; rc.right = prc->right; rc.bottom = prc->top + 1; ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
//left
rc.left = prc->left; rc.top = prc->top; rc.right = prc->left + 1; rc.bottom = prc->bottom; ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
//right
rc.left = prc->right - 1; rc.top = prc->top; rc.right = prc->right; rc.bottom = prc->bottom; ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
// bottom
rc.left = prc->left; rc.top = prc->bottom - 1; rc.right = prc->right; rc.bottom = prc->bottom; ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
SetBkColor(hdc, clrSave); }
STDAPI NavigateToPIDL(IWebBrowser2* pwb, LPCITEMIDLIST pidl) { ASSERT(pwb); ASSERT(pidl);
VARIANT varThePidl; HRESULT hr = InitVariantFromIDList(&varThePidl, pidl); if (SUCCEEDED(hr)) { hr = pwb->Navigate2(&varThePidl, PVAREMPTY, PVAREMPTY, PVAREMPTY, PVAREMPTY); VariantClear(&varThePidl); // Needed to free the copy of the PIDL in varThePidl.
} return hr; }
HRESULT Channels_OpenBrowser(IWebBrowser2 **ppwb, BOOL fInPlace) { HRESULT hr; IWebBrowser2* pwb;
if (fInPlace) { ASSERT(ppwb && *ppwb != NULL); pwb = *ppwb; hr = S_OK; } else { hr = CoCreateInstance(CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER, IID_PPV_ARG(IWebBrowser2, &pwb)); } if (SUCCEEDED(hr)) { // Don't special case full-screen mode for channels post IE4. Use the
// browser's full screen setting.
//
//BOOL fTheater = SHRegGetBoolUSValue(TEXT("Software\\Microsoft\\Internet Explorer\\Channels"),
BOOL fTheater = SHRegGetBoolUSValue(TEXT("Software\\Microsoft\\Internet Explorer\\Main"), TEXT("FullScreen"), FALSE, FALSE); pwb->put_TheaterMode( fTheater ? VARIANT_TRUE : VARIANT_FALSE); pwb->put_Visible(VARIANT_TRUE);
if (!SHRestricted2(REST_NoChannelUI, NULL, 0)) { SA_BSTRGUID strGuid; VARIANT vaGuid;
InitFakeBSTR(&strGuid, CLSID_FavBand);
vaGuid.vt = VT_BSTR; vaGuid.bstrVal = strGuid.wsz;
pwb->ShowBrowserBar(&vaGuid, PVAREMPTY, PVAREMPTY); } // don't release, we're going to return pwb.
} if (ppwb) *ppwb = pwb; else if (pwb) pwb->Release(); return hr; }
//
// Just like TB_GETBUTTONSIZE except that theme borders are subtracted out.
//
LRESULT TB_GetButtonSizeWithoutThemeBorder(HWND hwndTB, HTHEME hThemeParent) { LRESULT lButtonSize = SendMessage(hwndTB, TB_GETBUTTONSIZE, 0, 0L); if (hThemeParent) { HTHEME hTheme = OpenThemeData(hwndTB, L"Toolbar"); if (hTheme) { RECT rc = { 0, 0, 0, 0 }; if (SUCCEEDED(GetThemeBackgroundExtent(hTheme, NULL, TP_BUTTON, TS_NORMAL, &rc, &rc))) { lButtonSize = MAKELONG(LOWORD(lButtonSize) - RECTWIDTH(rc), HIWORD(lButtonSize) - RECTHEIGHT(rc)); } CloseThemeData(hTheme); } } return lButtonSize; }
#ifdef DEBUG
extern "C" void DumpMsg(LPCTSTR pszLabel, MSG * pmsg) { ASSERT(IS_VALID_STRING_PTR(pszLabel, -1)); ASSERT(pmsg);
switch (pmsg->message) { case WM_LBUTTONDOWN: TraceMsg(TF_ALWAYS, "%s: msg = WM_LBUTTONDOWN hwnd = %#08lx x = %d y = %d", pszLabel, pmsg->hwnd, pmsg->pt.x, pmsg->pt.y); TraceMsg(TF_ALWAYS, " keys = %#04lx x = %d y = %d", pmsg->wParam, LOWORD(pmsg->lParam), HIWORD(pmsg->lParam)); break;
case WM_LBUTTONUP: TraceMsg(TF_ALWAYS, "%s: msg = WM_LBUTTONUP hwnd = %#08lx x = %d y = %d", pszLabel, pmsg->hwnd, pmsg->pt.x, pmsg->pt.y); TraceMsg(TF_ALWAYS, " keys = %#04lx x = %d y = %d", pmsg->wParam, LOWORD(pmsg->lParam), HIWORD(pmsg->lParam)); break;
case WM_KEYDOWN: case WM_SYSKEYDOWN: case WM_KEYUP: case WM_SYSKEYUP: BLOCK { LPTSTR pcsz = TEXT("(unknown)"); switch (pmsg->message) { STRING_CASE(WM_KEYDOWN); STRING_CASE(WM_SYSKEYDOWN); STRING_CASE(WM_KEYUP); STRING_CASE(WM_SYSKEYUP); }
TraceMsg(TF_ALWAYS, "%s: msg = %s hwnd = %#08lx", pszLabel, pcsz, pmsg->hwnd); TraceMsg(TF_ALWAYS, " vk = %#04lx count = %u flags = %#04lx", pmsg->wParam, LOWORD(pmsg->lParam), HIWORD(pmsg->lParam)); } break;
case WM_CHAR: case WM_SYSCHAR: BLOCK { LPTSTR pcsz = TEXT("(unknown)"); switch (pmsg->message) { STRING_CASE(WM_CHAR); STRING_CASE(WM_SYSCHAR); }
TraceMsg(TF_ALWAYS, "%s: msg = %s hwnd = %#08lx", pszLabel, pcsz, pmsg->hwnd); TraceMsg(TF_ALWAYS, " char = '%c' count = %u flags = %#04lx", pmsg->wParam, LOWORD(pmsg->lParam), HIWORD(pmsg->lParam)); } break;
case WM_MOUSEMOVE: #if 0
TraceMsg(TF_ALWAYS, "%s: msg = WM_MOUSEMOVE hwnd = %#08lx x=%d y=%d", pszLabel, pmsg->hwnd, LOWORD(pmsg->lParam), HIWORD(pmsg->lParam)); #endif
break;
case WM_TIMER: #if 0
TraceMsg(TF_ALWAYS, "%s: msg = WM_TIMER hwnd = %#08lx x = %d y = %d", pszLabel, pmsg->hwnd, pmsg->pt.x, pmsg->pt.y); TraceMsg(TF_ALWAYS, " id = %#08lx", pmsg->wParam); #endif
break;
case WM_MENUSELECT: TraceMsg(TF_ALWAYS, "%s: msg = WM_MENUSELECT hwnd = %#08lx x = %d y = %d", pszLabel, pmsg->hwnd, pmsg->pt.x, pmsg->pt.y); TraceMsg(TF_ALWAYS, " uItem = %#04lx flags = %#04lx hmenu = %#08lx", GET_WM_MENUSELECT_CMD(pmsg->wParam, pmsg->lParam), GET_WM_MENUSELECT_FLAGS(pmsg->wParam, pmsg->lParam), GET_WM_MENUSELECT_HMENU(pmsg->wParam, pmsg->lParam)); break;
default: if (WM_USER > pmsg->message) { TraceMsg(TF_ALWAYS, "%s: msg = %#04lx hwnd=%#04lx wP=%#08lx lP=%#08lx", pszLabel, pmsg->message, pmsg->hwnd, pmsg->wParam, pmsg->lParam); } break; } } #endif
|