windows-nt/Source/XPSP1/NT/shell/ext/docprop/docprop.c
2020-09-26 16:20:57 +08:00

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
};