// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. // // Copyright (c) Microsoft Corporation. All rights reserved #pragma once #define STRICT_TYPED_ITEMIDS // in case you do IDList stuff you want this on for better type saftey #define UNICODE 1 #include #include // for WM_COMMAND handling macros #include // shell stuff #include // QISearch, easy way to implement QI #include #include #include #include #pragma comment(lib, "shlwapi.lib") // link to this #pragma comment(lib, "comctl32.lib") // link to this #pragma comment(lib, "propsys.lib") // link to this // set up common controls v6 the easy way #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") __inline HRESULT ResultFromKnownLastError() { const DWORD err = GetLastError(); return err == ERROR_SUCCESS ? E_FAIL : HRESULT_FROM_WIN32(err); } // map Win32 APIs that follow the return BOOL/set last error protocol // into HRESULT // // example: MoveFileEx() __inline HRESULT ResultFromWin32Bool(BOOL b) { return b ? S_OK : ResultFromKnownLastError(); } #if (NTDDI_VERSION >= NTDDI_VISTA) __inline HRESULT ShellExecuteItem(HWND hwnd, PCWSTR pszVerb, IShellItem *psi) { // how to activate a shell item, use ShellExecute(). PIDLIST_ABSOLUTE pidl; HRESULT hr = SHGetIDListFromObject(psi, &pidl); if (SUCCEEDED(hr)) { SHELLEXECUTEINFO ei = { sizeof(ei) }; ei.fMask = SEE_MASK_INVOKEIDLIST; ei.hwnd = hwnd; ei.nShow = SW_NORMAL; ei.lpIDList = pidl; ei.lpVerb = pszVerb; hr = ResultFromWin32Bool(ShellExecuteEx(&ei)); CoTaskMemFree(pidl); } return hr; } __inline HRESULT GetItemFromView(IFolderView2 *pfv, int iItem, REFIID riid, void **ppv) { *ppv = NULL; HRESULT hr = S_OK; if (iItem == -1) { hr = pfv->GetSelectedItem(-1, &iItem); // Returns S_FALSE if none selected } if (S_OK == hr) { hr = pfv->GetItem(iItem, riid, ppv); } else { hr = E_FAIL; } return hr; } // set the icon for your window using WM_SETICON from one of the set of stock system icons // caller must call ClearDialogIcon() to free the HICON that is created __inline void SetDialogIcon(HWND hdlg, SHSTOCKICONID siid) { SHSTOCKICONINFO sii = {sizeof(sii)}; if (SUCCEEDED(SHGetStockIconInfo(siid, SHGFI_ICON | SHGFI_SMALLICON, &sii))) { SendMessage(hdlg, WM_SETICON, ICON_SMALL, (LPARAM) sii.hIcon); } if (SUCCEEDED(SHGetStockIconInfo(siid, SHGFI_ICON | SHGFI_LARGEICON, &sii))) { SendMessage(hdlg, WM_SETICON, ICON_BIG, (LPARAM) sii.hIcon); } } #endif // free the HICON that was set using SetDialogIcon() __inline void ClearDialogIcon(HWND hdlg) { DestroyIcon((HICON)SendMessage(hdlg, WM_GETICON, ICON_SMALL, 0)); DestroyIcon((HICON)SendMessage(hdlg, WM_GETICON, ICON_BIG, 0)); } __inline HRESULT SetItemImageImageInStaticControl(HWND hwndStatic, IShellItem *psi) { HBITMAP hbmp = NULL; HRESULT hr = S_OK; if (psi) { IShellItemImageFactory *psiif; hr = psi->QueryInterface(IID_PPV_ARGS(&psiif)); if (SUCCEEDED(hr)) { RECT rc; GetWindowRect(hwndStatic, &rc); const UINT dxdy = min(rc.right - rc.left, rc.bottom - rc.top); // make it square const SIZE size = { dxdy, dxdy }; hr = psiif->GetImage(size, SIIGBF_RESIZETOFIT, &hbmp); psiif->Release(); } } if (SUCCEEDED(hr)) { HGDIOBJ hgdiOld = (HGDIOBJ) SendMessage(hwndStatic, STM_SETIMAGE, (WPARAM) IMAGE_BITMAP, (LPARAM) hbmp); if (hgdiOld) { DeleteObject(hgdiOld); // if there was an old one clean it up } } return hr; } __inline HRESULT SHILCloneFull(PCUIDLIST_ABSOLUTE pidl, PIDLIST_ABSOLUTE *ppidl) { *ppidl = ILCloneFull(pidl); return *ppidl ? S_OK : E_OUTOFMEMORY; } __inline HRESULT SHILClone(PCUIDLIST_RELATIVE pidl, PIDLIST_RELATIVE *ppidl) { *ppidl = ILClone(pidl); return *ppidl ? S_OK : E_OUTOFMEMORY; } __inline HRESULT SHILCombine(PCIDLIST_ABSOLUTE pidl1, PCUIDLIST_RELATIVE pidl2, PIDLIST_ABSOLUTE *ppidl) { *ppidl = ILCombine(pidl1, pidl2); return *ppidl ? S_OK : E_OUTOFMEMORY; } __inline HRESULT GetItemAt(IShellItemArray *psia, DWORD i, REFIID riid, void **ppv) { *ppv = NULL; IShellItem *psi = NULL; // avoid error C4701 HRESULT hr = psia ? psia->GetItemAt(i, &psi) : E_NOINTERFACE; if (SUCCEEDED(hr)) { hr = psi->QueryInterface(riid, ppv); psi->Release(); } return hr; } #define MAP_ENTRY(x) {L#x, x} __inline HRESULT ShellAttributesToString(SFGAOF sfgaof, PWSTR *ppsz) { *ppsz = NULL; static const struct { PCWSTR pszName; SFGAOF sfgaof; } c_rgItemAttributes[] = { // note, SFGAO_HASSUBFOLDER is too expesnive to compute // and has been excluded from this list MAP_ENTRY(SFGAO_STREAM), MAP_ENTRY(SFGAO_FOLDER), MAP_ENTRY(SFGAO_FILESYSTEM), MAP_ENTRY(SFGAO_FILESYSANCESTOR), MAP_ENTRY(SFGAO_STORAGE), MAP_ENTRY(SFGAO_STORAGEANCESTOR), MAP_ENTRY(SFGAO_LINK), MAP_ENTRY(SFGAO_CANCOPY), MAP_ENTRY(SFGAO_CANMOVE), MAP_ENTRY(SFGAO_CANLINK), MAP_ENTRY(SFGAO_CANRENAME), MAP_ENTRY(SFGAO_CANDELETE), MAP_ENTRY(SFGAO_HASPROPSHEET), MAP_ENTRY(SFGAO_DROPTARGET), MAP_ENTRY(SFGAO_ENCRYPTED), MAP_ENTRY(SFGAO_ISSLOW), MAP_ENTRY(SFGAO_GHOSTED), MAP_ENTRY(SFGAO_SHARE), MAP_ENTRY(SFGAO_READONLY), MAP_ENTRY(SFGAO_HIDDEN), MAP_ENTRY(SFGAO_REMOVABLE), MAP_ENTRY(SFGAO_COMPRESSED), MAP_ENTRY(SFGAO_BROWSABLE), MAP_ENTRY(SFGAO_NONENUMERATED), MAP_ENTRY(SFGAO_NEWCONTENT), }; WCHAR sz[512] = {}; PWSTR psz = sz; size_t cch = ARRAYSIZE(sz); StringCchPrintfEx(psz, cch, &psz, &cch, 0, L"0x%08X", sfgaof); for (int i = 0; i < ARRAYSIZE(c_rgItemAttributes); i++) { if (c_rgItemAttributes[i].sfgaof & sfgaof) { StringCchPrintfEx(psz, cch, &psz, &cch, 0, L", %s", c_rgItemAttributes[i].pszName); } } return SHStrDup(sz, ppsz); } template void SafeRelease(T **ppT) { if (*ppT) { (*ppT)->Release(); *ppT = NULL; } } // assign an interface pointer, release old, capture ref to new, can be used to set to zero too template HRESULT SetInterface(T **ppT, IUnknown *punk) { SafeRelease(ppT); return punk ? punk->QueryInterface(ppT) : E_NOINTERFACE; } // remote COM methods are dispatched in the context of an exception handler that consumes // all SEH exceptions including crahses and C++ exceptions. this is undesirable as it // means programs will continue to run after such an exception has been thrown, // leaving the process in a inconsistent state. // // this applies to COM methods like IDropTarget::Drop() // // this code turns off that behavior __inline void DisableComExceptionHandling() { IGlobalOptions *pGlobalOptions; HRESULT hr = CoCreateInstance(CLSID_GlobalOptions, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pGlobalOptions)); if (SUCCEEDED(hr)) { #if (NTDDI_VERSION >= NTDDI_WIN7) hr = pGlobalOptions->Set(COMGLB_EXCEPTION_HANDLING, COMGLB_EXCEPTION_DONOT_HANDLE_ANY); #else hr = pGlobalOptions->Set(COMGLB_EXCEPTION_HANDLING, COMGLB_EXCEPTION_DONOT_HANDLE); #endif pGlobalOptions->Release(); } } __inline void GetWindowRectInClient(HWND hwnd, RECT *prc) { GetWindowRect(hwnd, prc); MapWindowPoints(GetDesktopWindow(), GetParent(hwnd), (POINT*)prc, 2); } // retrieve the HINSTANCE for the current DLL or EXE using this symbol that // the linker provides for every module, avoids the need for a global HINSTANCE variable // and provides access to this value for static libraries EXTERN_C IMAGE_DOS_HEADER __ImageBase; __inline HINSTANCE GetModuleHINSTANCE() { return (HINSTANCE)&__ImageBase; }