Something went wrong. Try again.
Reactos
Something went wrong. Try again.
13 kB · 569 lines
C++
at master
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570/* * Copyright 2003, 2004, 2005 Martin Fuchs * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
// // Explorer clone // // shellclasses.cpp // // C++ wrapper classes for COM interfaces and shell objects // // Martin Fuchs, 20.07.2003 //
#include <precomp.h>
#ifdef _MS_VER#pragma comment(lib, "shell32") // link to shell32.dll#endif
// work around GCC's wide string constant bug#ifdef __GNUC__const LPCTSTR sCFSTR_SHELLIDLIST = TEXT("Shell IDList Array");#endif
// helper functions for string copying
/*LPSTR strcpyn(LPSTR dest, LPCSTR source, size_t count){ LPCSTR s; LPSTR d = dest;
for(s=source; count&&(*d++=*s++); ) count--;
return dest;}
LPWSTR wcscpyn(LPWSTR dest, LPCWSTR source, size_t count){ LPCWSTR s; LPWSTR d = dest;
for(s=source; count&&(*d++=*s++); ) count--;
return dest;}*/
String COMException::toString() const{ TCHAR msg[4*BUFFER_LEN];#ifdef __STDC_WANT_SECURE_LIB__ int l = 4*BUFFER_LEN;#endif LPTSTR p = msg;
int n = _stprintf_s2(p, l, TEXT("%s\nContext: %s"), super::ErrorMessage(), (LPCTSTR)_context.toString()); p += n;#ifdef __STDC_WANT_SECURE_LIB__ l -= n;#endif
if (_file) p += _stprintf_s2(p, l, TEXT("\nLocation: %hs:%d"), _file, _line);
return msg;}
/// Exception Handler for COM exceptions
void HandleException(COMException& e, HWND hwnd){ String msg = e.toString();
SetLastError(0);
if (hwnd && !IsWindowVisible(hwnd)) hwnd = 0;
MessageBox(hwnd, msg, TEXT("ShellClasses Exception"), MB_ICONHAND|MB_OK);
// If displaying the error message box _with_ parent was not successfull, display it now without a parent window. if (GetLastError() == ERROR_INVALID_WINDOW_HANDLE) MessageBox(0, msg, TEXT("ShellClasses Exception"), MB_ICONHAND|MB_OK);}
// common IMalloc object
CommonShellMalloc ShellMalloc::s_cmn_shell_malloc;
// common desktop object
ShellFolder& GetDesktopFolder(){ static CommonDesktop s_desktop;
// initialize s_desktop s_desktop.init();
return s_desktop;}
void CommonDesktop::init(){ CONTEXT("CommonDesktop::init()");
if (!_desktop) _desktop = new ShellFolder;}
CommonDesktop::~CommonDesktop(){ if (_desktop) delete _desktop;}
HRESULT path_from_pidlA(IShellFolder* folder, LPCITEMIDLIST pidl, LPSTR buffer, int len){ CONTEXT("path_from_pidlA()");
StrRetA str;
HRESULT hr = folder->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &str);
if (SUCCEEDED(hr)) str.GetString(pidl->mkid, buffer, len); else buffer[0] = '\0';
return hr;}
HRESULT path_from_pidlW(IShellFolder* folder, LPCITEMIDLIST pidl, LPWSTR buffer, int len){ CONTEXT("path_from_pidlW()");
StrRetW str;
HRESULT hr = folder->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &str);
if (SUCCEEDED(hr)) str.GetString(pidl->mkid, buffer, len); else buffer[0] = '\0';
return hr;}
HRESULT name_from_pidl(IShellFolder* folder, LPCITEMIDLIST pidl, LPTSTR buffer, int len, SHGDNF flags){ CONTEXT("name_from_pidl()");
StrRet str;
HRESULT hr = folder->GetDisplayNameOf(pidl, flags, &str);
if (SUCCEEDED(hr)) str.GetString(pidl->mkid, buffer, len); else buffer[0] = '\0';
return hr;}
#ifndef _NO_COMUTIL
ShellFolder::ShellFolder(){ CONTEXT("ShellFolder::ShellFolder()");
IShellFolder* desktop;
CHECKERROR(SHGetDesktopFolder(&desktop));
super::Attach(desktop); desktop->AddRef();}
ShellFolder::ShellFolder(IShellFolder* p) : super(p){ CONTEXT("ShellFolder::ShellFolder(IShellFolder*)");
p->AddRef();}
ShellFolder::ShellFolder(IShellFolder* parent, LPCITEMIDLIST pidl){ CONTEXT("ShellFolder::ShellFolder(IShellFolder*, LPCITEMIDLIST)");
IShellFolder* ptr;
if (!pidl) CHECKERROR(E_INVALIDARG);
if (pidl && pidl->mkid.cb) CHECKERROR(parent->BindToObject(pidl, 0, IID_IShellFolder, (LPVOID*)&ptr)); else ptr = parent;
super::Attach(ptr); ptr->AddRef();}
ShellFolder::ShellFolder(LPCITEMIDLIST pidl){ CONTEXT("ShellFolder::ShellFolder(LPCITEMIDLIST)");
IShellFolder* ptr; IShellFolder* parent = GetDesktopFolder();
if (pidl && pidl->mkid.cb) CHECKERROR(parent->BindToObject(pidl, 0, IID_IShellFolder, (LPVOID*)&ptr)); else ptr = parent;
super::Attach(ptr); ptr->AddRef();}
void ShellFolder::attach(IShellFolder* parent, LPCITEMIDLIST pidl){ CONTEXT("ShellFolder::attach(IShellFolder*, LPCITEMIDLIST)");
IShellFolder* ptr;
if (pidl && pidl->mkid.cb) CHECKERROR(parent->BindToObject(pidl, 0, IID_IShellFolder, (LPVOID*)&ptr)); else ptr = parent;
super::Attach(ptr); ptr->AddRef();}
#else // _com_ptr not available -> use SIfacePtr
ShellFolder::ShellFolder(){ CONTEXT("ShellFolder::ShellFolder()");
CHECKERROR(SHGetDesktopFolder(&_p));
_p->AddRef();}
ShellFolder::ShellFolder(IShellFolder* p) : super(p){ CONTEXT("ShellFolder::ShellFolder(IShellFolder*)");
_p->AddRef();}
ShellFolder::ShellFolder(IShellFolder* parent, LPCITEMIDLIST pidl){ CONTEXT("ShellFolder::ShellFolder(IShellFolder*, LPCITEMIDLIST)");
if (pidl && pidl->mkid.cb) CHECKERROR(parent->BindToObject(pidl, 0, IID_IShellFolder, (LPVOID*)&_p)); else _p = GetDesktopFolder();
_p->AddRef();}
ShellFolder::ShellFolder(LPCITEMIDLIST pidl){ CONTEXT("ShellFolder::ShellFolder(LPCITEMIDLIST)");
if (pidl && pidl->mkid.cb) CHECKERROR(GetDesktopFolder()->BindToObject(pidl, 0, IID_IShellFolder, (LPVOID*)&_p)); else _p = GetDesktopFolder();
_p->AddRef();}
void ShellFolder::attach(IShellFolder* parent, LPCITEMIDLIST pidl){ CONTEXT("ShellFolder::ShellFolder(IShellFolder*, LPCITEMIDLIST)");
IShellFolder* h = _p;
CHECKERROR(parent->BindToObject(pidl, 0, IID_IShellFolder, (LPVOID*)&_p));
_p->AddRef(); h->Release();}
#endif
String ShellFolder::get_name(LPCITEMIDLIST pidl, SHGDNF flags) const{ CONTEXT("ShellFolder::get_name()");
TCHAR buffer[MAX_PATH]; StrRet strret;
HRESULT hr = ((IShellFolder*)*const_cast<ShellFolder*>(this))->GetDisplayNameOf(pidl, flags, &strret);
if (hr == S_OK) strret.GetString(pidl->mkid, buffer, COUNTOF(buffer)); else { CHECKERROR(hr); *buffer = TEXT('\0'); }
return buffer;}
void ShellPath::split(ShellPath& parent, ShellPath& obj) const{ SHITEMID *piid, *piidLast; int size = 0;
// find last item-id and calculate total size of pidl for(piid=piidLast=&_p->mkid; piid->cb; ) { piidLast = piid; size += (piid->cb); piid = (SHITEMID*)((LPBYTE)piid + (piid->cb)); }
// copy parent folder portion size -= piidLast->cb; // don't count "object" item-id
if (size > 0) parent.assign(_p, size);
// copy "object" portion obj.assign((ITEMIDLIST*)piidLast, piidLast->cb);}
void ShellPath::GetUIObjectOf(REFIID riid, LPVOID* ppvOut, HWND hWnd, ShellFolder& sf){ CONTEXT("ShellPath::GetUIObjectOf()");
ShellPath parent, obj;
split(parent, obj);
LPCITEMIDLIST idl = obj;
if (parent && parent->mkid.cb) // use the IShellFolder of the parent CHECKERROR(ShellFolder((IShellFolder*)sf,parent)->GetUIObjectOf(hWnd, 1, &idl, riid, 0, ppvOut)); else // else use desktop folder CHECKERROR(sf->GetUIObjectOf(hWnd, 1, &idl, riid, 0, ppvOut));}
#if 0 // ILCombine() was missing in previous versions of MinGW and is not exported from shell32.dll on Windows 2000.
// convert an item id list from relative to absolute (=relative to the desktop) formatShellPath ShellPath::create_absolute_pidl(LPCITEMIDLIST parent_pidl) const{ CONTEXT("ShellPath::create_absolute_pidl()");
return ILCombine(parent_pidl, _p);
/* seems to work only for NT upwards // create a new item id list with _p append behind parent_pidl int l1 = ILGetSize(parent_pidl) - sizeof(USHORT/ SHITEMID::cb /); int l2 = ILGetSize(_p);
LPITEMIDLIST p = (LPITEMIDLIST) _malloc->Alloc(l1+l2);
memcpy(p, parent_pidl, l1); memcpy((LPBYTE)p+l1, _p, l2);
return p;*/}
#else
ShellPath ShellPath::create_absolute_pidl(LPCITEMIDLIST parent_pidl) const{ CONTEXT("ShellPath::create_absolute_pidl()");
static DynamicFct<LPITEMIDLIST(WINAPI*)(LPCITEMIDLIST, LPCITEMIDLIST)> ILCombine(TEXT("SHELL32"), 25);
if (ILCombine) return (*ILCombine)(parent_pidl, _p);
// create a new item id list with _p append behind parent_pidl int l1 = ILGetSize(parent_pidl) - sizeof(USHORT/*SHITEMID::cb*/); int l2 = ILGetSize(_p);
LPITEMIDLIST p = (LPITEMIDLIST) _malloc->Alloc(l1+l2);
memcpy(p, parent_pidl, l1); memcpy((LPBYTE)p+l1, _p, l2);
return p;}
#endif
// local implementation of ILGetSize() to replace missing export on Windows 2000UINT ILGetSize_local(LPCITEMIDLIST pidl){ if (!pidl) return 0;
int l = sizeof(USHORT/*SHITEMID::cb*/);
while(pidl->mkid.cb) { l += pidl->mkid.cb; pidl = LPCITEMIDLIST((LPBYTE)pidl+pidl->mkid.cb); }
return l;}
#ifndef _SHFOLDER_H_#define CSIDL_FLAG_CREATE 0x8000#endif
/// file system path of special folderSpecialFolderFSPath::SpecialFolderFSPath(int folder, HWND hwnd){ _fullpath[0] = '\0';
#ifdef UNICODE static DynamicFct<BOOL (__stdcall*)(HWND hwnd, LPTSTR pszPath, int csidl, BOOL fCreate)> s_pSHGetSpecialFolderPath(TEXT("shell32"), "SHGetSpecialFolderPathW");#else static DynamicFct<BOOL (__stdcall*)(HWND hwnd, LPTSTR pszPath, int csidl, BOOL fCreate)> s_pSHGetSpecialFolderPath(TEXT("shell32"), "SHGetSpecialFolderPathA");#endif if (*s_pSHGetSpecialFolderPath) (*s_pSHGetSpecialFolderPath)(hwnd, _fullpath, folder, TRUE); else { // SHGetSpecialFolderPath() is not compatible to WIN95/NT4#ifdef UNICODE static DynamicFct<HRESULT (__stdcall*)(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPTSTR pszPath)> s_pSHGetFolderPath_shell32(TEXT("shell32"), "SHGetFolderPathW");#else static DynamicFct<HRESULT (__stdcall*)(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPTSTR pszPath)> s_pSHGetFolderPath_shell32(TEXT("shell32"), "SHGetFolderPathA");#endif if (*s_pSHGetFolderPath_shell32) (*s_pSHGetFolderPath_shell32)(hwnd, folder|CSIDL_FLAG_CREATE, 0, 0, _fullpath); else { // SHGetFolderPath() is only present in shfolder.dll on some platforms.#ifdef UNICODE static DynamicLoadLibFct<HRESULT (__stdcall*)(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPTSTR pszPath)> s_pSHGetFolderPath_shfolder(TEXT("shfolder"), "SHGetFolderPathW");#else static DynamicLoadLibFct<HRESULT (__stdcall*)(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPTSTR pszPath)> s_pSHGetFolderPath_shfolder(TEXT("shfolder"), "SHGetFolderPathA");#endif if (*s_pSHGetFolderPath_shfolder) (*s_pSHGetFolderPath_shfolder)(hwnd, folder|CSIDL_FLAG_CREATE, 0, 0, _fullpath); } }}
void CtxMenuInterfaces::reset(){ _pctxmenu2 = NULL; _pctxmenu3 = NULL;}
bool CtxMenuInterfaces::HandleMenuMsg(UINT nmsg, WPARAM wparam, LPARAM lparam){ if (_pctxmenu3) { if (SUCCEEDED(_pctxmenu3->HandleMenuMsg(nmsg, wparam, lparam))) return true; }
if (_pctxmenu2) if (SUCCEEDED(_pctxmenu2->HandleMenuMsg(nmsg, wparam, lparam))) return true;
return false;}
IContextMenu* CtxMenuInterfaces::query_interfaces(IContextMenu* pcm1){ IContextMenu* pcm = NULL;
reset();
// Get the higher version context menu interfaces. if (pcm1->QueryInterface(IID_IContextMenu3, (void**)&pcm) == NOERROR) _pctxmenu3 = (LPCONTEXTMENU3)pcm; else if (pcm1->QueryInterface(IID_IContextMenu2, (void**)&pcm) == NOERROR) _pctxmenu2 = (LPCONTEXTMENU2)pcm;
if (pcm) { pcm1->Release(); return pcm; } else return pcm1;}
HRESULT ShellFolderContextMenu(IShellFolder* shell_folder, HWND hwndParent, int cidl, LPCITEMIDLIST* apidl, int x, int y, CtxMenuInterfaces& cm_ifs){ IContextMenu* pcm;
HRESULT hr = shell_folder->GetUIObjectOf(hwndParent, cidl, apidl, IID_IContextMenu, NULL, (LPVOID*)&pcm);// HRESULT hr = CDefFolderMenu_Create2(dir?dir->_pidl:DesktopFolder(), hwndParent, 1, &pidl, shell_folder, NULL, 0, NULL, &pcm);
if (SUCCEEDED(hr)) { pcm = cm_ifs.query_interfaces(pcm);
HMENU hmenu = CreatePopupMenu();
if (hmenu) { hr = pcm->QueryContextMenu(hmenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, CMF_NORMAL|CMF_EXPLORE);
if (SUCCEEDED(hr)) { UINT idCmd = TrackPopupMenu(hmenu, TPM_LEFTALIGN|TPM_RETURNCMD|TPM_RIGHTBUTTON, x, y, 0, hwndParent, NULL);
cm_ifs.reset();
if (idCmd) { CMINVOKECOMMANDINFO cmi;
cmi.cbSize = sizeof(CMINVOKECOMMANDINFO); cmi.fMask = 0; cmi.hwnd = hwndParent; cmi.lpVerb = (LPCSTR)(INT_PTR)(idCmd - FCIDM_SHVIEWFIRST); cmi.lpParameters = NULL; cmi.lpDirectory = NULL; cmi.nShow = SW_SHOWNORMAL; cmi.dwHotKey = 0; cmi.hIcon = 0;
hr = pcm->InvokeCommand(&cmi); } } else cm_ifs.reset(); DestroyMenu(hmenu); }
pcm->Release(); }
return hr;}