418 lines
11 KiB
C
418 lines
11 KiB
C
#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
|
|
};
|
|
|