00001 /* 00002 * Copyright 2003, 2004, 2005 Martin Fuchs 00003 * 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Lesser General Public 00006 * License as published by the Free Software Foundation; either 00007 * version 2.1 of the License, or (at your option) any later version. 00008 * 00009 * This library is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 * Lesser General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU Lesser General Public 00015 * License along with this library; if not, write to the Free Software 00016 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00017 */ 00018 00019 00020 // 00021 // Explorer clone 00022 // 00023 // shellclasses.cpp 00024 // 00025 // C++ wrapper classes for COM interfaces and shell objects 00026 // 00027 // Martin Fuchs, 20.07.2003 00028 // 00029 00030 00031 #include <precomp.h> 00032 00033 00034 #ifdef _MS_VER 00035 #pragma comment(lib, "shell32") // link to shell32.dll 00036 #endif 00037 00038 00039 // work around GCC's wide string constant bug 00040 #ifdef __GNUC__ 00041 const LPCTSTR sCFSTR_SHELLIDLIST = TEXT("Shell IDList Array"); 00042 #endif 00043 00044 00045 // helper functions for string copying 00046 00047 /*LPSTR strcpyn(LPSTR dest, LPCSTR source, size_t count) 00048 { 00049 LPCSTR s; 00050 LPSTR d = dest; 00051 00052 for(s=source; count&&(*d++=*s++); ) 00053 count--; 00054 00055 return dest; 00056 } 00057 00058 LPWSTR wcscpyn(LPWSTR dest, LPCWSTR source, size_t count) 00059 { 00060 LPCWSTR s; 00061 LPWSTR d = dest; 00062 00063 for(s=source; count&&(*d++=*s++); ) 00064 count--; 00065 00066 return dest; 00067 }*/ 00068 00069 00070 String COMException::toString() const 00071 { 00072 TCHAR msg[4*BUFFER_LEN]; 00073 #ifdef __STDC_WANT_SECURE_LIB__ 00074 int l = 4*BUFFER_LEN; 00075 #endif 00076 LPTSTR p = msg; 00077 00078 int n = _stprintf_s2(p, l, TEXT("%s\nContext: %s"), super::ErrorMessage(), (LPCTSTR)_context.toString()); 00079 p += n; 00080 #ifdef __STDC_WANT_SECURE_LIB__ 00081 l -= n; 00082 #endif 00083 00084 if (_file) 00085 p += _stprintf_s2(p, l, TEXT("\nLocation: %hs:%d"), _file, _line); 00086 00087 return msg; 00088 } 00089 00090 00091 /// Exception Handler for COM exceptions 00092 00093 void HandleException(COMException& e, HWND hwnd) 00094 { 00095 String msg = e.toString(); 00096 00097 SetLastError(0); 00098 00099 if (hwnd && !IsWindowVisible(hwnd)) 00100 hwnd = 0; 00101 00102 MessageBox(hwnd, msg, TEXT("ShellClasses Exception"), MB_ICONHAND|MB_OK); 00103 00104 // If displaying the error message box _with_ parent was not successfull, display it now without a parent window. 00105 if (GetLastError() == ERROR_INVALID_WINDOW_HANDLE) 00106 MessageBox(0, msg, TEXT("ShellClasses Exception"), MB_ICONHAND|MB_OK); 00107 } 00108 00109 00110 // common IMalloc object 00111 00112 CommonShellMalloc ShellMalloc::s_cmn_shell_malloc; 00113 00114 00115 // common desktop object 00116 00117 ShellFolder& GetDesktopFolder() 00118 { 00119 static CommonDesktop s_desktop; 00120 00121 // initialize s_desktop 00122 s_desktop.init(); 00123 00124 return s_desktop; 00125 } 00126 00127 00128 void CommonDesktop::init() 00129 { 00130 CONTEXT("CommonDesktop::init()"); 00131 00132 if (!_desktop) 00133 _desktop = new ShellFolder; 00134 } 00135 00136 CommonDesktop::~CommonDesktop() 00137 { 00138 if (_desktop) 00139 delete _desktop; 00140 } 00141 00142 00143 HRESULT path_from_pidlA(IShellFolder* folder, LPCITEMIDLIST pidl, LPSTR buffer, int len) 00144 { 00145 CONTEXT("path_from_pidlA()"); 00146 00147 StrRetA str; 00148 00149 HRESULT hr = folder->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &str); 00150 00151 if (SUCCEEDED(hr)) 00152 str.GetString(pidl->mkid, buffer, len); 00153 else 00154 buffer[0] = '\0'; 00155 00156 return hr; 00157 } 00158 00159 HRESULT path_from_pidlW(IShellFolder* folder, LPCITEMIDLIST pidl, LPWSTR buffer, int len) 00160 { 00161 CONTEXT("path_from_pidlW()"); 00162 00163 StrRetW str; 00164 00165 HRESULT hr = folder->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &str); 00166 00167 if (SUCCEEDED(hr)) 00168 str.GetString(pidl->mkid, buffer, len); 00169 else 00170 buffer[0] = '\0'; 00171 00172 return hr; 00173 } 00174 00175 HRESULT name_from_pidl(IShellFolder* folder, LPCITEMIDLIST pidl, LPTSTR buffer, int len, SHGDNF flags) 00176 { 00177 CONTEXT("name_from_pidl()"); 00178 00179 StrRet str; 00180 00181 HRESULT hr = folder->GetDisplayNameOf(pidl, flags, &str); 00182 00183 if (SUCCEEDED(hr)) 00184 str.GetString(pidl->mkid, buffer, len); 00185 else 00186 buffer[0] = '\0'; 00187 00188 return hr; 00189 } 00190 00191 00192 #ifndef _NO_COMUTIL 00193 00194 ShellFolder::ShellFolder() 00195 { 00196 CONTEXT("ShellFolder::ShellFolder()"); 00197 00198 IShellFolder* desktop; 00199 00200 CHECKERROR(SHGetDesktopFolder(&desktop)); 00201 00202 super::Attach(desktop); 00203 desktop->AddRef(); 00204 } 00205 00206 ShellFolder::ShellFolder(IShellFolder* p) 00207 : super(p) 00208 { 00209 CONTEXT("ShellFolder::ShellFolder(IShellFolder*)"); 00210 00211 p->AddRef(); 00212 } 00213 00214 ShellFolder::ShellFolder(IShellFolder* parent, LPCITEMIDLIST pidl) 00215 { 00216 CONTEXT("ShellFolder::ShellFolder(IShellFolder*, LPCITEMIDLIST)"); 00217 00218 IShellFolder* ptr; 00219 00220 if (!pidl) 00221 CHECKERROR(E_INVALIDARG); 00222 00223 if (pidl && pidl->mkid.cb) 00224 CHECKERROR(parent->BindToObject(pidl, 0, IID_IShellFolder, (LPVOID*)&ptr)); 00225 else 00226 ptr = parent; 00227 00228 super::Attach(ptr); 00229 ptr->AddRef(); 00230 } 00231 00232 ShellFolder::ShellFolder(LPCITEMIDLIST pidl) 00233 { 00234 CONTEXT("ShellFolder::ShellFolder(LPCITEMIDLIST)"); 00235 00236 IShellFolder* ptr; 00237 IShellFolder* parent = GetDesktopFolder(); 00238 00239 if (pidl && pidl->mkid.cb) 00240 CHECKERROR(parent->BindToObject(pidl, 0, IID_IShellFolder, (LPVOID*)&ptr)); 00241 else 00242 ptr = parent; 00243 00244 super::Attach(ptr); 00245 ptr->AddRef(); 00246 } 00247 00248 void ShellFolder::attach(IShellFolder* parent, LPCITEMIDLIST pidl) 00249 { 00250 CONTEXT("ShellFolder::attach(IShellFolder*, LPCITEMIDLIST)"); 00251 00252 IShellFolder* ptr; 00253 00254 if (pidl && pidl->mkid.cb) 00255 CHECKERROR(parent->BindToObject(pidl, 0, IID_IShellFolder, (LPVOID*)&ptr)); 00256 else 00257 ptr = parent; 00258 00259 super::Attach(ptr); 00260 ptr->AddRef(); 00261 } 00262 00263 #else // _com_ptr not available -> use SIfacePtr 00264 00265 ShellFolder::ShellFolder() 00266 { 00267 CONTEXT("ShellFolder::ShellFolder()"); 00268 00269 CHECKERROR(SHGetDesktopFolder(&_p)); 00270 00271 _p->AddRef(); 00272 } 00273 00274 ShellFolder::ShellFolder(IShellFolder* p) 00275 : super(p) 00276 { 00277 CONTEXT("ShellFolder::ShellFolder(IShellFolder*)"); 00278 00279 _p->AddRef(); 00280 } 00281 00282 ShellFolder::ShellFolder(IShellFolder* parent, LPCITEMIDLIST pidl) 00283 { 00284 CONTEXT("ShellFolder::ShellFolder(IShellFolder*, LPCITEMIDLIST)"); 00285 00286 if (pidl && pidl->mkid.cb) 00287 CHECKERROR(parent->BindToObject(pidl, 0, IID_IShellFolder, (LPVOID*)&_p)); 00288 else 00289 _p = GetDesktopFolder(); 00290 00291 _p->AddRef(); 00292 } 00293 00294 ShellFolder::ShellFolder(LPCITEMIDLIST pidl) 00295 { 00296 CONTEXT("ShellFolder::ShellFolder(LPCITEMIDLIST)"); 00297 00298 if (pidl && pidl->mkid.cb) 00299 CHECKERROR(GetDesktopFolder()->BindToObject(pidl, 0, IID_IShellFolder, (LPVOID*)&_p)); 00300 else 00301 _p = GetDesktopFolder(); 00302 00303 _p->AddRef(); 00304 } 00305 00306 void ShellFolder::attach(IShellFolder* parent, LPCITEMIDLIST pidl) 00307 { 00308 CONTEXT("ShellFolder::ShellFolder(IShellFolder*, LPCITEMIDLIST)"); 00309 00310 IShellFolder* h = _p; 00311 00312 CHECKERROR(parent->BindToObject(pidl, 0, IID_IShellFolder, (LPVOID*)&_p)); 00313 00314 _p->AddRef(); 00315 h->Release(); 00316 } 00317 00318 #endif 00319 00320 String ShellFolder::get_name(LPCITEMIDLIST pidl, SHGDNF flags) const 00321 { 00322 CONTEXT("ShellFolder::get_name()"); 00323 00324 TCHAR buffer[MAX_PATH]; 00325 StrRet strret; 00326 00327 HRESULT hr = ((IShellFolder*)*const_cast<ShellFolder*>(this))->GetDisplayNameOf(pidl, flags, &strret); 00328 00329 if (hr == S_OK) 00330 strret.GetString(pidl->mkid, buffer, COUNTOF(buffer)); 00331 else { 00332 CHECKERROR(hr); 00333 *buffer = TEXT('\0'); 00334 } 00335 00336 return buffer; 00337 } 00338 00339 00340 void ShellPath::split(ShellPath& parent, ShellPath& obj) const 00341 { 00342 SHITEMID *piid, *piidLast; 00343 int size = 0; 00344 00345 // find last item-id and calculate total size of pidl 00346 for(piid=piidLast=&_p->mkid; piid->cb; ) { 00347 piidLast = piid; 00348 size += (piid->cb); 00349 piid = (SHITEMID*)((LPBYTE)piid + (piid->cb)); 00350 } 00351 00352 // copy parent folder portion 00353 size -= piidLast->cb; // don't count "object" item-id 00354 00355 if (size > 0) 00356 parent.assign(_p, size); 00357 00358 // copy "object" portion 00359 obj.assign((ITEMIDLIST*)piidLast, piidLast->cb); 00360 } 00361 00362 void ShellPath::GetUIObjectOf(REFIID riid, LPVOID* ppvOut, HWND hWnd, ShellFolder& sf) 00363 { 00364 CONTEXT("ShellPath::GetUIObjectOf()"); 00365 00366 ShellPath parent, obj; 00367 00368 split(parent, obj); 00369 00370 LPCITEMIDLIST idl = obj; 00371 00372 if (parent && parent->mkid.cb) 00373 // use the IShellFolder of the parent 00374 CHECKERROR(ShellFolder((IShellFolder*)sf,parent)->GetUIObjectOf(hWnd, 1, &idl, riid, 0, ppvOut)); 00375 else // else use desktop folder 00376 CHECKERROR(sf->GetUIObjectOf(hWnd, 1, &idl, riid, 0, ppvOut)); 00377 } 00378 00379 #if 0 // ILCombine() was missing in previous versions of MinGW and is not exported from shell32.dll on Windows 2000. 00380 00381 // convert an item id list from relative to absolute (=relative to the desktop) format 00382 ShellPath ShellPath::create_absolute_pidl(LPCITEMIDLIST parent_pidl) const 00383 { 00384 CONTEXT("ShellPath::create_absolute_pidl()"); 00385 00386 return ILCombine(parent_pidl, _p); 00387 00388 /* seems to work only for NT upwards 00389 // create a new item id list with _p append behind parent_pidl 00390 int l1 = ILGetSize(parent_pidl) - sizeof(USHORT/ SHITEMID::cb /); 00391 int l2 = ILGetSize(_p); 00392 00393 LPITEMIDLIST p = (LPITEMIDLIST) _malloc->Alloc(l1+l2); 00394 00395 memcpy(p, parent_pidl, l1); 00396 memcpy((LPBYTE)p+l1, _p, l2); 00397 00398 return p; 00399 */ 00400 } 00401 00402 #else 00403 00404 ShellPath ShellPath::create_absolute_pidl(LPCITEMIDLIST parent_pidl) const 00405 { 00406 CONTEXT("ShellPath::create_absolute_pidl()"); 00407 00408 static DynamicFct<LPITEMIDLIST(WINAPI*)(LPCITEMIDLIST, LPCITEMIDLIST)> ILCombine(TEXT("SHELL32"), 25); 00409 00410 if (ILCombine) 00411 return (*ILCombine)(parent_pidl, _p); 00412 00413 // create a new item id list with _p append behind parent_pidl 00414 int l1 = ILGetSize(parent_pidl) - sizeof(USHORT/*SHITEMID::cb*/); 00415 int l2 = ILGetSize(_p); 00416 00417 LPITEMIDLIST p = (LPITEMIDLIST) _malloc->Alloc(l1+l2); 00418 00419 memcpy(p, parent_pidl, l1); 00420 memcpy((LPBYTE)p+l1, _p, l2); 00421 00422 return p; 00423 } 00424 00425 #endif 00426 00427 // local implementation of ILGetSize() to replace missing export on Windows 2000 00428 UINT ILGetSize_local(LPCITEMIDLIST pidl) 00429 { 00430 if (!pidl) 00431 return 0; 00432 00433 int l = sizeof(USHORT/*SHITEMID::cb*/); 00434 00435 while(pidl->mkid.cb) { 00436 l += pidl->mkid.cb; 00437 pidl = LPCITEMIDLIST((LPBYTE)pidl+pidl->mkid.cb); 00438 } 00439 00440 return l; 00441 } 00442 00443 00444 #ifndef _SHFOLDER_H_ 00445 #define CSIDL_FLAG_CREATE 0x8000 00446 #endif 00447 00448 /// file system path of special folder 00449 SpecialFolderFSPath::SpecialFolderFSPath(int folder, HWND hwnd) 00450 { 00451 _fullpath[0] = '\0'; 00452 00453 #ifdef UNICODE 00454 static DynamicFct<BOOL (__stdcall*)(HWND hwnd, LPTSTR pszPath, int csidl, BOOL fCreate)> s_pSHGetSpecialFolderPath(TEXT("shell32"), "SHGetSpecialFolderPathW"); 00455 #else 00456 static DynamicFct<BOOL (__stdcall*)(HWND hwnd, LPTSTR pszPath, int csidl, BOOL fCreate)> s_pSHGetSpecialFolderPath(TEXT("shell32"), "SHGetSpecialFolderPathA"); 00457 #endif 00458 if (*s_pSHGetSpecialFolderPath) 00459 (*s_pSHGetSpecialFolderPath)(hwnd, _fullpath, folder, TRUE); 00460 else { 00461 // SHGetSpecialFolderPath() is not compatible to WIN95/NT4 00462 #ifdef UNICODE 00463 static DynamicFct<HRESULT (__stdcall*)(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPTSTR pszPath)> s_pSHGetFolderPath_shell32(TEXT("shell32"), "SHGetFolderPathW"); 00464 #else 00465 static DynamicFct<HRESULT (__stdcall*)(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPTSTR pszPath)> s_pSHGetFolderPath_shell32(TEXT("shell32"), "SHGetFolderPathA"); 00466 #endif 00467 if (*s_pSHGetFolderPath_shell32) 00468 (*s_pSHGetFolderPath_shell32)(hwnd, folder|CSIDL_FLAG_CREATE, 0, 0, _fullpath); 00469 else { 00470 // SHGetFolderPath() is only present in shfolder.dll on some platforms. 00471 #ifdef UNICODE 00472 static DynamicLoadLibFct<HRESULT (__stdcall*)(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPTSTR pszPath)> s_pSHGetFolderPath_shfolder(TEXT("shfolder"), "SHGetFolderPathW"); 00473 #else 00474 static DynamicLoadLibFct<HRESULT (__stdcall*)(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPTSTR pszPath)> s_pSHGetFolderPath_shfolder(TEXT("shfolder"), "SHGetFolderPathA"); 00475 #endif 00476 if (*s_pSHGetFolderPath_shfolder) 00477 (*s_pSHGetFolderPath_shfolder)(hwnd, folder|CSIDL_FLAG_CREATE, 0, 0, _fullpath); 00478 } 00479 } 00480 } 00481 00482 00483 void CtxMenuInterfaces::reset() 00484 { 00485 _pctxmenu2 = NULL; 00486 00487 #ifndef __MINGW32__ // IContextMenu3 missing in MinGW (as of 6.2.2005) 00488 _pctxmenu3 = NULL; 00489 #endif 00490 } 00491 00492 bool CtxMenuInterfaces::HandleMenuMsg(UINT nmsg, WPARAM wparam, LPARAM lparam) 00493 { 00494 #ifndef __MINGW32__ // IContextMenu3 missing in MinGW (as of 6.2.2005) 00495 if (_pctxmenu3) { 00496 if (SUCCEEDED(_pctxmenu3->HandleMenuMsg(nmsg, wparam, lparam))) 00497 return true; 00498 } 00499 #endif 00500 00501 if (_pctxmenu2) 00502 if (SUCCEEDED(_pctxmenu2->HandleMenuMsg(nmsg, wparam, lparam))) 00503 return true; 00504 00505 return false; 00506 } 00507 00508 IContextMenu* CtxMenuInterfaces::query_interfaces(IContextMenu* pcm1) 00509 { 00510 IContextMenu* pcm = NULL; 00511 00512 reset(); 00513 00514 // Get the higher version context menu interfaces. 00515 #ifndef __MINGW32__ // IContextMenu3 missing in MinGW (as of 6.2.2005) 00516 if (pcm1->QueryInterface(IID_IContextMenu3, (void**)&pcm) == NOERROR) 00517 _pctxmenu3 = (LPCONTEXTMENU3)pcm; 00518 else 00519 #endif 00520 if (pcm1->QueryInterface(IID_IContextMenu2, (void**)&pcm) == NOERROR) 00521 _pctxmenu2 = (LPCONTEXTMENU2)pcm; 00522 00523 if (pcm) { 00524 pcm1->Release(); 00525 return pcm; 00526 } else 00527 return pcm1; 00528 } 00529 00530 00531 HRESULT ShellFolderContextMenu(IShellFolder* shell_folder, HWND hwndParent, int cidl, 00532 LPCITEMIDLIST* apidl, int x, int y, CtxMenuInterfaces& cm_ifs) 00533 { 00534 IContextMenu* pcm; 00535 00536 HRESULT hr = shell_folder->GetUIObjectOf(hwndParent, cidl, apidl, IID_IContextMenu, NULL, (LPVOID*)&pcm); 00537 // HRESULT hr = CDefFolderMenu_Create2(dir?dir->_pidl:DesktopFolder(), hwndParent, 1, &pidl, shell_folder, NULL, 0, NULL, &pcm); 00538 00539 if (SUCCEEDED(hr)) { 00540 pcm = cm_ifs.query_interfaces(pcm); 00541 00542 HMENU hmenu = CreatePopupMenu(); 00543 00544 if (hmenu) { 00545 hr = pcm->QueryContextMenu(hmenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, CMF_NORMAL|CMF_EXPLORE); 00546 00547 if (SUCCEEDED(hr)) { 00548 UINT idCmd = TrackPopupMenu(hmenu, TPM_LEFTALIGN|TPM_RETURNCMD|TPM_RIGHTBUTTON, x, y, 0, hwndParent, NULL); 00549 00550 cm_ifs.reset(); 00551 00552 if (idCmd) { 00553 CMINVOKECOMMANDINFO cmi; 00554 00555 cmi.cbSize = sizeof(CMINVOKECOMMANDINFO); 00556 cmi.fMask = 0; 00557 cmi.hwnd = hwndParent; 00558 cmi.lpVerb = (LPCSTR)(INT_PTR)(idCmd - FCIDM_SHVIEWFIRST); 00559 cmi.lpParameters = NULL; 00560 cmi.lpDirectory = NULL; 00561 cmi.nShow = SW_SHOWNORMAL; 00562 cmi.dwHotKey = 0; 00563 cmi.hIcon = 0; 00564 00565 hr = pcm->InvokeCommand(&cmi); 00566 } 00567 } else 00568 cm_ifs.reset(); 00569 DestroyMenu(hmenu); 00570 } 00571 00572 pcm->Release(); 00573 } 00574 00575 return hr; 00576 }
ROS Explorer Source Code Documentation
generated on 02.01.2013 by ![]() |