📄 compositemoniker.c
字号:
/*
* CompositeMonikers implementation
*
* Copyright 1999 Noomen Hamza
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <assert.h>
#include <stdarg.h>
#include <string.h>
#define COBJMACROS
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "winerror.h"
#include "wine/debug.h"
#include "wine/unicode.h"
#include "ole2.h"
#include "moniker.h"
WINE_DEFAULT_DEBUG_CHANNEL(ole);
#define BLOCK_TAB_SIZE 5 /* represent the first size table and it's increment block size */
/* CompositeMoniker data structure */
typedef struct CompositeMonikerImpl{
const IMonikerVtbl* lpvtbl1; /* VTable relative to the IMoniker interface.*/
/* The ROT (RunningObjectTable implementation) uses the IROTData
* interface to test whether two monikers are equal. That's why IROTData
* interface is implemented by monikers.
*/
const IROTDataVtbl* lpvtbl2; /* VTable relative to the IROTData interface.*/
const IMarshalVtbl* lpvtblMarshal; /* VTable relative to the IMarshal interface.*/
LONG ref; /* reference counter for this object */
IMoniker** tabMoniker; /* dynamaic table containing all components (monikers) of this composite moniker */
ULONG tabSize; /* size of tabMoniker */
ULONG tabLastIndex; /* first free index in tabMoniker */
} CompositeMonikerImpl;
/* EnumMoniker data structure */
typedef struct EnumMonikerImpl{
const IEnumMonikerVtbl *lpVtbl; /* VTable relative to the IEnumMoniker interface.*/
LONG ref; /* reference counter for this object */
IMoniker** tabMoniker; /* dynamic table containing the enumerated monikers */
ULONG tabSize; /* size of tabMoniker */
ULONG currentPos; /* index pointer on the current moniker */
} EnumMonikerImpl;
static inline IMoniker *impl_from_IROTData( IROTData *iface )
{
return (IMoniker *)((char*)iface - FIELD_OFFSET(CompositeMonikerImpl, lpvtbl2));
}
static inline IMoniker *impl_from_IMarshal( IMarshal *iface )
{
return (IMoniker *)((char*)iface - FIELD_OFFSET(CompositeMonikerImpl, lpvtblMarshal));
}
static HRESULT EnumMonikerImpl_CreateEnumMoniker(IMoniker** tabMoniker,ULONG tabSize,ULONG currentPos,BOOL leftToRigth,IEnumMoniker ** ppmk);
/*******************************************************************************
* CompositeMoniker_QueryInterface
*******************************************************************************/
static HRESULT WINAPI
CompositeMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject)
{
CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
TRACE("(%p,%p,%p)\n",This,riid,ppvObject);
/* Perform a sanity check on the parameters.*/
if ( (This==0) || (ppvObject==0) )
return E_INVALIDARG;
/* Initialize the return parameter */
*ppvObject = 0;
/* Compare the riid with the interface IDs implemented by this object.*/
if (IsEqualIID(&IID_IUnknown, riid) ||
IsEqualIID(&IID_IPersist, riid) ||
IsEqualIID(&IID_IPersistStream, riid) ||
IsEqualIID(&IID_IMoniker, riid)
)
*ppvObject = iface;
else if (IsEqualIID(&IID_IROTData, riid))
*ppvObject = (IROTData*)&(This->lpvtbl2);
else if (IsEqualIID(&IID_IMarshal, riid))
*ppvObject = (IROTData*)&(This->lpvtblMarshal);
/* Check that we obtained an interface.*/
if ((*ppvObject)==0)
return E_NOINTERFACE;
/* Query Interface always increases the reference count by one when it is successful */
IMoniker_AddRef(iface);
return S_OK;
}
/******************************************************************************
* CompositeMoniker_AddRef
******************************************************************************/
static ULONG WINAPI
CompositeMonikerImpl_AddRef(IMoniker* iface)
{
CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
TRACE("(%p)\n",This);
return InterlockedIncrement(&This->ref);
}
static void CompositeMonikerImpl_ReleaseMonikersInTable(CompositeMonikerImpl *This)
{
ULONG i;
for (i = 0; i < This->tabLastIndex; i++)
IMoniker_Release(This->tabMoniker[i]);
This->tabLastIndex = 0;
}
/******************************************************************************
* CompositeMoniker_Release
******************************************************************************/
static ULONG WINAPI
CompositeMonikerImpl_Release(IMoniker* iface)
{
CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
ULONG ref;
TRACE("(%p)\n",This);
ref = InterlockedDecrement(&This->ref);
/* destroy the object if there's no more reference on it */
if (ref == 0){
/* release all the components before destroying this object */
CompositeMonikerImpl_ReleaseMonikersInTable(This);
HeapFree(GetProcessHeap(),0,This->tabMoniker);
HeapFree(GetProcessHeap(),0,This);
}
return ref;
}
/******************************************************************************
* CompositeMoniker_GetClassID
******************************************************************************/
static HRESULT WINAPI
CompositeMonikerImpl_GetClassID(IMoniker* iface,CLSID *pClassID)
{
TRACE("(%p,%p)\n",iface,pClassID);
if (pClassID==NULL)
return E_POINTER;
*pClassID = CLSID_CompositeMoniker;
return S_OK;
}
/******************************************************************************
* CompositeMoniker_IsDirty
******************************************************************************/
static HRESULT WINAPI
CompositeMonikerImpl_IsDirty(IMoniker* iface)
{
/* Note that the OLE-provided implementations of the IPersistStream::IsDirty
method in the OLE-provided moniker interfaces always return S_FALSE because
their internal state never changes. */
TRACE("(%p)\n",iface);
return S_FALSE;
}
/******************************************************************************
* CompositeMoniker_Load
******************************************************************************/
static HRESULT WINAPI
CompositeMonikerImpl_Load(IMoniker* iface,IStream* pStm)
{
HRESULT res;
DWORD moniker_count;
DWORD i;
CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
TRACE("(%p,%p)\n",iface,pStm);
/* this function call OleLoadFromStream function for each moniker within this object */
res=IStream_Read(pStm,&moniker_count,sizeof(DWORD),NULL);
if (res != S_OK)
{
ERR("couldn't reading moniker count from stream\n");
return E_FAIL;
}
CompositeMonikerImpl_ReleaseMonikersInTable(This);
for (i = 0; i < moniker_count; i++)
{
res=OleLoadFromStream(pStm,&IID_IMoniker,(void**)&This->tabMoniker[This->tabLastIndex]);
if (FAILED(res))
{
ERR("couldn't load moniker from stream, res = 0x%08x\n", res);
break;
}
/* resize the table if needed */
if (++This->tabLastIndex==This->tabSize){
This->tabSize+=BLOCK_TAB_SIZE;
This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));
if (This->tabMoniker==NULL)
return E_OUTOFMEMORY;
}
}
return res;
}
/******************************************************************************
* CompositeMoniker_Save
******************************************************************************/
static HRESULT WINAPI
CompositeMonikerImpl_Save(IMoniker* iface,IStream* pStm,BOOL fClearDirty)
{
CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
HRESULT res;
IEnumMoniker *enumMk;
IMoniker *pmk;
DWORD moniker_count = This->tabLastIndex;
TRACE("(%p,%p,%d)\n",iface,pStm,fClearDirty);
/* This function calls OleSaveToStream function for each moniker within
* this object.
* When I tested this function in windows, I usually found this constant
* at the beginning of the stream. I don't known why (there's no
* indication in the specification) !
*/
res=IStream_Write(pStm,&moniker_count,sizeof(moniker_count),NULL);
if (FAILED(res)) return res;
IMoniker_Enum(iface,TRUE,&enumMk);
while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)==S_OK){
res=OleSaveToStream((IPersistStream*)pmk,pStm);
IMoniker_Release(pmk);
if (FAILED(res)){
IEnumMoniker_Release(enumMk);
return res;
}
}
IEnumMoniker_Release(enumMk);
return S_OK;
}
/******************************************************************************
* CompositeMoniker_GetSizeMax
******************************************************************************/
static HRESULT WINAPI
CompositeMonikerImpl_GetSizeMax(IMoniker* iface,ULARGE_INTEGER* pcbSize)
{
IEnumMoniker *enumMk;
IMoniker *pmk;
ULARGE_INTEGER ptmpSize;
/* The sizeMax of this object is calculated by calling GetSizeMax on
* each moniker within this object then summing all returned values
*/
TRACE("(%p,%p)\n",iface,pcbSize);
if (!pcbSize)
return E_POINTER;
pcbSize->QuadPart = sizeof(DWORD);
IMoniker_Enum(iface,TRUE,&enumMk);
while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)==S_OK){
IMoniker_GetSizeMax(pmk,&ptmpSize);
IMoniker_Release(pmk);
pcbSize->QuadPart = ptmpSize.QuadPart + sizeof(CLSID);
}
IEnumMoniker_Release(enumMk);
return S_OK;
}
/******************************************************************************
* CompositeMoniker_BindToObject
******************************************************************************/
static HRESULT WINAPI
CompositeMonikerImpl_BindToObject(IMoniker* iface, IBindCtx* pbc,
IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult)
{
HRESULT res;
IRunningObjectTable *prot;
IMoniker *tempMk,*antiMk,*mostRigthMk;
IEnumMoniker *enumMoniker;
TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult);
if (ppvResult==NULL)
return E_POINTER;
*ppvResult=0;
/* If pmkToLeft is NULL, this method looks for the moniker in the ROT, and if found, queries the retrieved */
/* object for the requested interface pointer. */
if(pmkToLeft==NULL){
res=IBindCtx_GetRunningObjectTable(pbc,&prot);
if (SUCCEEDED(res)){
/* if the requested class was loaded before ! we don't need to reload it */
res = IRunningObjectTable_GetObject(prot,iface,(IUnknown**)ppvResult);
if (res==S_OK)
return res;
}
}
else{
/* If pmkToLeft is not NULL, the method recursively calls IMoniker::BindToObject on the rightmost */
/* component of the composite, passing the rest of the composite as the pmkToLeft parameter for that call */
IMoniker_Enum(iface,FALSE,&enumMoniker);
IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
IEnumMoniker_Release(enumMoniker);
res=CreateAntiMoniker(&antiMk);
res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
IMoniker_Release(antiMk);
res=IMoniker_BindToObject(mostRigthMk,pbc,tempMk,riid,ppvResult);
IMoniker_Release(tempMk);
IMoniker_Release(mostRigthMk);
}
return res;
}
/******************************************************************************
* CompositeMoniker_BindToStorage
******************************************************************************/
static HRESULT WINAPI
CompositeMonikerImpl_BindToStorage(IMoniker* iface, IBindCtx* pbc,
IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult)
{
HRESULT res;
IMoniker *tempMk,*antiMk,*mostRigthMk,*leftMk;
IEnumMoniker *enumMoniker;
TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult);
*ppvResult=0;
/* This method recursively calls BindToStorage on the rightmost component of the composite, */
/* passing the rest of the composite as the pmkToLeft parameter for that call. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -