#include "shellprv.h" #pragma hdrstop #include "datautil.h" // // This function is a callback function from property sheet page extensions. // BOOL CALLBACK _AddPropSheetPage(HPROPSHEETPAGE hpage, LPARAM lParam) { PROPSHEETHEADER * ppsh = (PROPSHEETHEADER *)lParam; if (ppsh->nPages < MAX_FILE_PROP_PAGES) { ppsh->phpage[ppsh->nPages++] = hpage; return TRUE; } return FALSE; } // // This function enumerates all the property sheet page extensions for // specified class and let them add pages. // // int DCA_AppendClassSheetInfo(HDCA hdca, HKEY hkeyProgID, LPPROPSHEETHEADER ppsh, IDataObject *pdtobj) { int i, iStart = -1; for (i = 0; i < DCA_GetItemCount(hdca); i++) { IShellExtInit *psei; // These came from HKCR hence need to go through administrator approval if (DCA_ExtCreateInstance(hdca, i, &IID_IShellExtInit, &psei) == NOERROR) { IShellPropSheetExt *pspse; if (SUCCEEDED(psei->lpVtbl->Initialize(psei, NULL, pdtobj, hkeyProgID)) && SUCCEEDED(psei->lpVtbl->QueryInterface(psei, &IID_IShellPropSheetExt, &pspse))) { int nPagesSave = ppsh->nPages; HRESULT hres = pspse->lpVtbl->AddPages(pspse, _AddPropSheetPage, (LPARAM)ppsh); if (SUCCEEDED(hres) && hres != S_OK) { // Some shell extensions get confused and return S_FALSE when // they didn't add anything, unaware that S_FALSE means "Please // take the page I added and make it the default". So ignore // the return value if it is out of range. DWORD nPagesAdded = ppsh->nPages - nPagesSave; DWORD nPageWanted = hres - 1; if (nPageWanted < nPagesAdded) iStart = nPagesSave + nPageWanted; } pspse->lpVtbl->Release(pspse); } psei->lpVtbl->Release(psei); } } return iStart; } HWND FindStubForPidlClass(LPCITEMIDLIST pidl, int iClass) { HWND hwnd; if (!pidl) return NULL; for (hwnd = FindWindow(c_szStubWindowClass, NULL); hwnd; hwnd = GetWindow(hwnd, GW_HWNDNEXT)) { TCHAR szClass[80]; // find stub windows only GetClassName(hwnd, szClass, ARRAYSIZE(szClass)); if (lstrcmpi(szClass, c_szStubWindowClass) == 0) { HANDLE hClassPidl; DWORD dwProcId; DWORD_PTR dwResult; GetWindowThreadProcessId(hwnd, &dwProcId); // since a propsheet could be doing work & not pumping messages, use a timeout // we can almost just do this: hClassPidl = GetWindowLongPtr(hwnd, 0) if (!SendMessageTimeout(hwnd, STUBM_GETDATA, 0, 0, SMTO_BLOCK, 3000, &dwResult)) continue; hClassPidl = (HANDLE)dwResult; if (hClassPidl) { LPBYTE lpb = (LPBYTE)SHLockShared(hClassPidl, dwProcId); if (lpb) { int iClassFound = *(int *)lpb; if (iClassFound == iClass && ILIsEqual(pidl, (LPITEMIDLIST)(lpb + sizeof(int))) ) { SHUnlockShared(lpb); return hwnd; } SHUnlockShared(lpb); } } } } return NULL; } HANDLE _StuffStubWindow(HWND hwnd, LPITEMIDLIST pidlT, int iClass) { DWORD dwProcId; HANDLE hSharedClassPidl; UINT uidlSize; uidlSize = ILGetSize(pidlT); GetWindowThreadProcessId(hwnd, &dwProcId); hSharedClassPidl = SHAllocShared(NULL, sizeof(int) + uidlSize, dwProcId); if (hSharedClassPidl) { LPBYTE lpb = SHLockShared(hSharedClassPidl, dwProcId); if (lpb) { *((int *)lpb) = iClass; memcpy(lpb + sizeof(int), pidlT, uidlSize); SHUnlockShared(lpb); SendMessage(hwnd, STUBM_SETDATA, (WPARAM)hSharedClassPidl, 0); return hSharedClassPidl; } SHFreeShared(hSharedClassPidl, dwProcId); } return NULL; } // // Make sure we are the only stub window for this pidl/class. // // If so, saves information in the UNIQUESTUBINFO structure which keeps // track of the uniqueness key. After you are done, you must pass the // UNIQUESTUBINFO structure to FreeUniqueStub() to clean up the uniqueness // key and destroy the stub window. Returns TRUE. // // If a stub window already exists for this pidl/class, then sets focus // to the existing window that matches our uniqueness key and returns FALSE. // // In low memory conditions, plays it safe and declares the pidl/class // unique. // // // Example: // // UNIQUESTUBINFO usi; // if (EnsureUniqueStub(pidl, STUBCLASS_PROPSHEET, NULL, &usi)) { // DoStuff(usi.hwndStub, pidl); // FreeUniqueStub(&usi); // } // STDAPI_(BOOL) EnsureUniqueStub(LPITEMIDLIST pidl, int iClass, POINT* ppt, UNIQUESTUBINFO* pusi) { HWND hwndOther; ZeroMemory(pusi, sizeof(UNIQUESTUBINFO)); hwndOther = FindStubForPidlClass(pidl, iClass); if (hwndOther) { SwitchToThisWindow(GetLastActivePopup(hwndOther), TRUE); return FALSE; } else { // Tag ourselves as the unique stub for this pidl/class pusi->hwndStub = _CreateStubWindow(ppt, NULL); // If no pidl, then nothing to tag *with* // If no stub window, then nothing to attach the tag *to* // But they are both still considered success. if (pusi->hwndStub && pidl) { SHFILEINFO sfi; pusi->hClassPidl = _StuffStubWindow(pusi->hwndStub, pidl, iClass); if (SHGetFileInfo((LPCTSTR)pidl, 0, &sfi, sizeof(sfi), SHGFI_ICON | SHGFI_PIDL)) { pusi->hicoStub = sfi.hIcon; // Cannot stuff the title because the window might belong to another process SendMessage(pusi->hwndStub, STUBM_SETICONTITLE, (WPARAM)pusi->hicoStub, 0); } } return TRUE; } } STDAPI_(void) FreeUniqueStub(UNIQUESTUBINFO *pusi) { if (pusi->hwndStub) DestroyWindow(pusi->hwndStub); if (pusi->hClassPidl) SHFreeShared(pusi->hClassPidl, GetCurrentProcessId()); if (pusi->hicoStub) DestroyIcon(pusi->hicoStub); } BOOL _IsAnyDuplicatedKey(HKEY ahkeys[], UINT ckeys, HKEY hkey) { UINT ikey; for (ikey=0; ikey 0 ? ahkeys[ckeys-1] : NULL, &psh, pdtobj); // If a shell extension requested to be the default and the caller didn't // specify a preferred initial page, then let the shell extension win. if (!pStartPage && nStartPage >= 0) psh.nStartPage = nStartPage; DCA_Destroy(hdca); } // Open the property sheet, only if we have some pages. if (psh.nPages > 0) { _try { if (PropertySheet(&psh) >= 0) // IDOK or IDCANCEL (< 0 is error) fSuccess = TRUE; } _except(UnhandledExceptionFilter(GetExceptionInformation())) { DebugMsg(DM_ERROR, TEXT("PRSHT: Fault in property sheet")); } } else { ShellMessageBox(HINST_THISDLL, NULL, MAKEINTRESOURCE(IDS_NOPAGE), MAKEINTRESOURCE(IDS_DESKTOP), MB_OK|MB_ICONHAND); } // clean up the stub window and data FreeUniqueStub(&usi); return fSuccess; } #ifdef UNICODE STDAPI_(BOOL) SHOpenPropSheetA( LPCSTR pszCaption, HKEY ahkeys[], UINT ckeys, const CLSID * pclsidDef, IDataObject *pdtobj, IShellBrowser * psb, LPCSTR pszStartPage) OPTIONAL { BOOL bRet = FALSE; if (IS_VALID_STRING_PTRA(pszCaption, MAX_PATH)) { WCHAR wszCaption[MAX_PATH]; WCHAR wszStartPage[MAX_PATH]; SHAnsiToUnicode(pszCaption, wszCaption, SIZECHARS(wszCaption)); if (pszStartPage) { ASSERT(IS_VALID_STRING_PTRA(pszStartPage, MAX_PATH)); SHAnsiToUnicode(pszStartPage, wszStartPage, SIZECHARS(wszStartPage)); pszStartPage = (LPCSTR)wszStartPage; } bRet = SHOpenPropSheet(wszCaption, ahkeys, ckeys, pclsidDef, pdtobj, psb, (LPCWSTR)pszStartPage); } return bRet; } #else STDAPI_(BOOL) SHOpenPropSheetW( LPCWSTR pszCaption, HKEY ahkeys[], UINT ckeys, const CLSID * pclsidDef, IDataObject *pdtobj, IShellBrowser * psb, LPCWSTR pszStartPage) OPTIONAL { BOOL bRet = FALSE; if (IS_VALID_STRING_PTRW(pszCaption, MAX_PATH)) { char szCaption[MAX_PATH]; char szStartPage[MAX_PATH]; SHUnicodeToAnsi(pszCaption, szCaption, SIZECHARS(szCaption)); if (pszStartPage) { ASSERT(IS_VALID_STRING_PTRW(pszStartPage, MAX_PATH)); SHUnicodeToAnsi(pszStartPage, szStartPage, SIZECHARS(szStartPage)); pszStartPage = (LPCWSTR)szStartPage; } bRet = SHOpenPropSheet(szCaption, ahkeys, ckeys, pclsidDef, pdtobj, psb, (LPCSTR)pszStartPage); } return bRet; } #endif // UNICODE // // Async version of SHFormatDrive - creates a separate thread to do the // format and returns immediately. // typedef struct { HWND hwnd; UINT drive; UINT fmtID; UINT options; } FORMATTHREADINFO; STDAPI_(DWORD) _FormatThreadProc(LPVOID lpParam) { FORMATTHREADINFO* pfi = (FORMATTHREADINFO*)lpParam; LPITEMIDLIST pidl; TCHAR szDrive[4]; if (SUCCEEDED(StringCchCopy(szDrive, ARRAYSIZE(szDrive), TEXT("A:\\")))) { ASSERT(pfi->drive < 26); szDrive[0] += (TCHAR)pfi->drive; pidl = ILCreateFromPath(szDrive); if (pidl) { UNIQUESTUBINFO usi; LPPOINT ppt = NULL; RECT rcWindow; if (pfi->hwnd) { GetWindowRect(pfi->hwnd, &rcWindow); ppt = (LPPOINT)&rcWindow; } if (EnsureUniqueStub(pidl, STUBCLASS_FORMAT, ppt, &usi)) { SHFormatDrive(usi.hwndStub, pfi->drive, pfi->fmtID, pfi->options); FreeUniqueStub(&usi); } ILFree(pidl); } } LocalFree(pfi); return 0; } STDAPI_(void) SHFormatDriveAsync( HWND hwnd, UINT drive, UINT fmtID, UINT options ) { FORMATTHREADINFO* pfi = (FORMATTHREADINFO*)LocalAlloc(LPTR, sizeof(FORMATTHREADINFO)); if (pfi) { pfi->hwnd = hwnd; pfi->drive = drive; pfi->fmtID = fmtID; pfi->options = options; SHCreateThread(_FormatThreadProc, pfi, CTF_INSIST | CTF_PROCESS_REF, NULL); } }