#include "priv.h" #pragma hdrstop const GUID CLSID_CDocProp = {0x3EA48300L, 0x8CF6, 0x101B, 0x84, 0xFB, 0x66, 0x6C, 0xCB, 0x9B, 0xCD, 0x32}; HRESULT CDocProp_CreateInstance(IUnknown *punkOuter, REFIID riid, void **); // Global variables UINT g_cRefDll = 0; // Reference count of this DLL. HANDLE g_hmodThisDll = NULL; // Handle to this DLL itself. STDAPI_(BOOL) DllEntry(HANDLE hDll, DWORD dwReason, LPVOID lpReserved) { switch(dwReason) { case DLL_PROCESS_ATTACH: g_hmodThisDll = hDll; DisableThreadLibraryCalls(hDll); SHFusionInitializeFromModule(hDll); break; case DLL_PROCESS_DETACH: SHFusionUninitialize(); break; } return TRUE; } typedef struct { const IClassFactoryVtbl *cf; const CLSID *pclsid; HRESULT (*pfnCreate)(IUnknown *, REFIID, void **); } OBJ_ENTRY; extern const IClassFactoryVtbl c_CFVtbl; // forward // // we always do a linear search here so put your most often used things first // const OBJ_ENTRY c_clsmap[] = { { &c_CFVtbl, &CLSID_CDocProp, CDocProp_CreateInstance}, // add more entries here { NULL, NULL, NULL} }; // static class factory (no allocs!) STDMETHODIMP CClassFactory_QueryInterface(IClassFactory *pcf, REFIID riid, void **ppvObj) { if (IsEqualIID(riid, &IID_IClassFactory) || IsEqualIID(riid, &IID_IUnknown)) { *ppvObj = (void *)pcf; } else { *ppvObj = NULL; return E_NOINTERFACE; } DllAddRef(); return NOERROR; } STDMETHODIMP_(ULONG) CClassFactory_AddRef(IClassFactory *pcf) { DllAddRef(); return 2; } STDMETHODIMP_(ULONG) CClassFactory_Release(IClassFactory *pcf) { DllRelease(); return 1; } STDMETHODIMP CClassFactory_CreateInstance(IClassFactory *pcf, IUnknown *punkOuter, REFIID riid, void **ppvObject) { OBJ_ENTRY *this = IToClass(OBJ_ENTRY, cf, pcf); return this->pfnCreate(punkOuter, riid, ppvObject); } STDMETHODIMP CClassFactory_LockServer(IClassFactory *pcf, BOOL fLock) { if (fLock) DllAddRef(); else DllRelease(); return S_OK; } const IClassFactoryVtbl c_CFVtbl = { CClassFactory_QueryInterface, CClassFactory_AddRef, CClassFactory_Release, CClassFactory_CreateInstance, CClassFactory_LockServer }; STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv) { if (IsEqualIID(riid, &IID_IClassFactory) || IsEqualIID(riid, &IID_IUnknown)) { const OBJ_ENTRY *pcls; for (pcls = c_clsmap; pcls->pclsid; pcls++) { if (IsEqualIID(rclsid, pcls->pclsid)) { *ppv = (void *)&(pcls->cf); DllAddRef(); // Class Factory keeps dll in memory return NOERROR; } } } // failure *ppv = NULL; return CLASS_E_CLASSNOTAVAILABLE;; } STDAPI_(void) DllAddRef() { InterlockedIncrement(&g_cRefDll); } STDAPI_(void) DllRelease() { InterlockedDecrement(&g_cRefDll); } STDAPI DllCanUnloadNow(void) { return g_cRefDll == 0 ? S_OK : S_FALSE; } typedef struct { IShellExtInit _ei; IShellPropSheetExt _pse; int _cRef; // reference count IDataObject * _pdtobj; // data object TCHAR _szFile[MAX_PATH]; } CDocProp; STDMETHODIMP_(UINT) CDocProp_PSE_AddRef(IShellPropSheetExt *pei) { CDocProp *this = IToClass(CDocProp, _pse, pei); return ++this->_cRef; } STDMETHODIMP_(UINT) CDocProp_PSE_Release(IShellPropSheetExt *pei) { CDocProp *this = IToClass(CDocProp, _pse, pei); if (--this->_cRef) return this->_cRef; if (this->_pdtobj) this->_pdtobj->lpVtbl->Release(this->_pdtobj); LocalFree((HLOCAL)this); DllRelease(); return 0; } STDMETHODIMP CDocProp_PSE_QueryInterface(IShellPropSheetExt *pei, REFIID riid, void **ppvOut) { CDocProp *this = IToClass(CDocProp, _pse, pei); if (IsEqualIID(riid, &IID_IShellPropSheetExt) || IsEqualIID(riid, &IID_IUnknown)) { *ppvOut = (void *)pei; } else if (IsEqualIID(riid, &IID_IShellExtInit)) { *ppvOut = (void *)&this->_ei; } else { *ppvOut = NULL; return E_NOINTERFACE; } this->_cRef++; return NOERROR; } #ifdef _ABBREVIATED_DOCPROP_ #define NUM_PAGES 1 #else //_ABBREVIATED_DOCPROP_ #define NUM_PAGES 4 #endif //_ABBREVIATED_DOCPROP_ UINT CALLBACK PSPCallback(HWND hwnd, UINT uMsg, LPPROPSHEETPAGE psp) { switch (uMsg) { case PSPCB_RELEASE: if (psp && psp->lParam) { LPALLOBJS lpallobjs = (LPALLOBJS)psp->lParam; if (0 == --lpallobjs->uPageRef) { if (lpallobjs->fOleInit) CoUninitialize(); // Free our structure so hope we don't get it again! FOfficeDestroyObjects(&lpallobjs->lpSIObj, &lpallobjs->lpDSIObj, &lpallobjs->lpUDObj); GlobalFree(lpallobjs); } } DllRelease(); break; } return 1; } STDMETHODIMP CDocProp_PSE_AddPages(IShellPropSheetExt *ppse, LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam) { CDocProp *this = IToClass(CDocProp, _pse, ppse); STGMEDIUM medium; FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; HRESULT hres = this->_pdtobj->lpVtbl->GetData(this->_pdtobj, &fmte, &medium); if (hres == S_OK && (DragQueryFile((HDROP)medium.hGlobal, (UINT)-1, NULL, 0) == 1)) { WCHAR wszPath[MAX_PATH]; TCHAR szPath[MAX_PATH]; DWORD grfStgMode; IStorage *pstg = NULL; DragQueryFile((HDROP)medium.hGlobal, 0, szPath, ARRAYSIZE(szPath)); #ifdef UNICODE lstrcpyn(wszPath, szPath, MAX_PATH); #else MultiByteToWideChar(CP_ACP, 0, szPath, -1, wszPath, ARRAYSIZE(wszPath)); #endif // Load the properties for this file grfStgMode = STGM_READWRITE | STGM_SHARE_EXCLUSIVE; #ifdef WINNT if( GetFileAttributes( szPath ) & FILE_ATTRIBUTE_OFFLINE ) { ReleaseStgMedium(&medium); return HRESULT_FROM_WIN32(ERROR_FILE_OFFLINE); } hres = StgOpenStorageEx(wszPath, grfStgMode, STGFMT_STORAGE, 0, NULL, NULL, &IID_IStorage, (void**)&pstg); #else hres = StgOpenStorage( wszPath, NULL, grfStgMode, NULL, 0L, &pstg ) ; #endif if (FAILED(hres)) { // if we failed to open the file, try w/READ ONLY access grfStgMode = STGM_SHARE_EXCLUSIVE | STGM_READ; #ifdef WINNT hres = StgOpenStorageEx(wszPath, grfStgMode, STGFMT_STORAGE, 0, NULL, NULL, &IID_IStorage, (void**)&pstg); #else hres = StgOpenStorage( wszPath, NULL, grfStgMode, NULL, 0L, &pstg ) ; #endif } if (SUCCEEDED(hres)) { int i; // Allocate our main structure and make sure it is zero filled! LPALLOBJS lpallobjs = (LPALLOBJS)GlobalAlloc(GPTR, sizeof(ALLOBJS)); if (lpallobjs) { PROPSHEETPAGE psp[NUM_PAGES]; lstrcpyn(lpallobjs->szPath, szPath, ARRAYSIZE(lpallobjs->szPath)); // Initialize Office property code #ifdef _ABBREVIATED_DOCPROP_ FOfficeCreateAndInitObjects( NULL, NULL, &lpallobjs->lpUDObj); #else _ABBREVIATED_DOCPROP_ FOfficeCreateAndInitObjects(&lpallobjs->lpSIObj, &lpallobjs->lpDSIObj, &lpallobjs->lpUDObj); #endif _ABBREVIATED_DOCPROP_ lpallobjs->lpfnDwQueryLinkData = NULL; lpallobjs->dwMask = 0; // Fill in some stuff for the Office code lpallobjs->fFiledataInit = FALSE; // Initialize OLE lpallobjs->fOleInit = SUCCEEDED(CoInitialize(0)); // Initialize the PropertySheets we're going to add FOfficeInitPropInfo(psp, PSP_USECALLBACK, (LPARAM)lpallobjs, PSPCallback); FLoadTextStrings(); #ifdef _ABBREVIATED_DOCPROP_ DwOfficeLoadProperties(pstg, NULL, NULL, lpallobjs->lpUDObj, 0, grfStgMode); #else _ABBREVIATED_DOCPROP_ DwOfficeLoadProperties(pstg, lpallobjs->lpSIObj, lpallobjs->lpDSIObj, lpallobjs->lpUDObj, 0, grfStgMode); #endif _ABBREVIATED_DOCPROP_ // Try to add our new property pages for (i = 0; i < NUM_PAGES; i++) { HPROPSHEETPAGE hpage = CreatePropertySheetPage(&psp[i]); if (hpage) { DllAddRef(); // matched in PSPCB_RELEASE if (lpfnAddPage(hpage, lParam)) { FAttach( lpallobjs, psp + i, hpage ); lpallobjs->uPageRef++; } else DestroyPropertySheetPage(hpage); } } if (lpallobjs->uPageRef == 0) { if (lpallobjs->fOleInit) CoUninitialize(); // Free our structures FOfficeDestroyObjects(&lpallobjs->lpSIObj, &lpallobjs->lpDSIObj, &lpallobjs->lpUDObj); GlobalFree(lpallobjs); } } // if (lpallobjs) } // StgOpenStorage ... if (SUCCEEDED(hres)) if (NULL != pstg ) { pstg->lpVtbl->Release(pstg); pstg = NULL; } ReleaseStgMedium(&medium); } return S_OK; } STDMETHODIMP CDocProp_SEI_Initialize(IShellExtInit *pei, LPCITEMIDLIST pidlFolder, LPDATAOBJECT pdtobj, HKEY hkeyProgID) { CDocProp *this = IToClass(CDocProp, _ei, pei); // Initialize can be called more than once. if (this->_pdtobj) this->_pdtobj->lpVtbl->Release(this->_pdtobj); // Duplicate the pdtobj pointer if (pdtobj) { this->_pdtobj = pdtobj; pdtobj->lpVtbl->AddRef(pdtobj); } return NOERROR; } STDMETHODIMP_(UINT) CDocProp_SEI_AddRef(IShellExtInit *pei) { CDocProp *this = IToClass(CDocProp, _ei, pei); return CDocProp_PSE_AddRef(&this->_pse); } STDMETHODIMP_(UINT) CDocProp_SEI_Release(IShellExtInit *pei) { CDocProp *this = IToClass(CDocProp, _ei, pei); return CDocProp_PSE_Release(&this->_pse); } STDMETHODIMP CDocProp_SEI_QueryInterface(IShellExtInit *pei, REFIID riid, void **ppv) { CDocProp *this = IToClass(CDocProp, _ei, pei); return CDocProp_PSE_QueryInterface(&this->_pse, riid, ppv); } extern IShellExtInitVtbl c_CDocProp_SXIVtbl; extern IShellPropSheetExtVtbl c_CDocProp_SPXVtbl; HRESULT CDocProp_CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppvOut) { CDocProp *pdp; if (punkOuter) return CLASS_E_NOAGGREGATION; pdp = LocalAlloc(LPTR, sizeof(CDocProp)); if (pdp) { HRESULT hres; DllAddRef(); pdp->_ei.lpVtbl = &c_CDocProp_SXIVtbl; pdp->_pse.lpVtbl = &c_CDocProp_SPXVtbl; pdp->_cRef = 1; hres = CDocProp_PSE_QueryInterface(&pdp->_pse, riid, ppvOut); CDocProp_PSE_Release(&pdp->_pse); return hres; // S_OK or E_NOINTERFACE } return E_OUTOFMEMORY; } IShellPropSheetExtVtbl c_CDocProp_SPXVtbl = { CDocProp_PSE_QueryInterface, CDocProp_PSE_AddRef, CDocProp_PSE_Release, CDocProp_PSE_AddPages }; IShellExtInitVtbl c_CDocProp_SXIVtbl = { CDocProp_SEI_QueryInterface, CDocProp_SEI_AddRef, CDocProp_SEI_Release, CDocProp_SEI_Initialize };