📄 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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);
static const CLSID CLSID_CompositeMoniker = {
0x309, 0, 0, {0xC0, 0, 0, 0, 0, 0, 0, 0x46}
};
#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.*/
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 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);
/* 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);
}
/******************************************************************************
* CompositeMoniker_Release
******************************************************************************/
static ULONG WINAPI
CompositeMonikerImpl_Release(IMoniker* iface)
{
CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
ULONG i;
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 */
for (i=0;i<This->tabLastIndex;i++)
IMoniker_Release(This->tabMoniker[i]);
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),stub!\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 constant;
CLSID clsid;
WCHAR string[1]={0};
CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
TRACE("(%p,%p)\n",iface,pStm);
/* this function call OleLoadFromStream function for each moniker within this object */
/* read the a constant written by CompositeMonikerImpl_Save (see CompositeMonikerImpl_Save for more details)*/
res=IStream_Read(pStm,&constant,sizeof(DWORD),NULL);
if (SUCCEEDED(res)&& constant!=3)
return E_FAIL;
while(1){
#if 0
res=OleLoadFromStream(pStm,&IID_IMoniker,(void**)&This->tabMoniker[This->tabLastIndex]);
#endif
res=ReadClassStm(pStm,&clsid);
DPRINTF("res=%ld",res);
if (FAILED(res))
break;
if (IsEqualIID(&clsid,&CLSID_FileMoniker)){
res=CreateFileMoniker(string,&This->tabMoniker[This->tabLastIndex]);
if (FAILED(res))
break;
res=IMoniker_Load(This->tabMoniker[This->tabLastIndex],pStm);
if (FAILED(res))
break;
}
else if (IsEqualIID(&clsid,&CLSID_ItemMoniker)){
CreateItemMoniker(string,string,&This->tabMoniker[This->tabLastIndex]);
if (res!=S_OK)
break;
IMoniker_Load(This->tabMoniker[This->tabLastIndex],pStm);
if (FAILED(res))
break;
}
else if (IsEqualIID(&clsid,&CLSID_AntiMoniker)){
CreateAntiMoniker(&This->tabMoniker[This->tabLastIndex]);
if (FAILED(res))
break;
IMoniker_Load(This->tabMoniker[This->tabLastIndex],pStm);
if (FAILED(res))
break;
}
else if (IsEqualIID(&clsid,&CLSID_CompositeMoniker))
return E_FAIL;
else
{
FIXME("()\n");
/* FIXME: To whoever wrote this code: It's either return or break. it cannot be both! */
break;
return E_NOTIMPL;
}
/* 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)
{
HRESULT res;
IEnumMoniker *enumMk;
IMoniker *pmk;
DWORD constant=3;
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,&constant,sizeof(constant),NULL);
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(pmk);
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!=NULL)
return E_POINTER;
pcbSize->u.LowPart =0;
pcbSize->u.HighPart=0;
IMoniker_Enum(iface,TRUE,&enumMk);
while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)){
IMoniker_GetSizeMax(pmk,&ptmpSize);
IMoniker_Release(pmk);
pcbSize->u.LowPart +=ptmpSize.u.LowPart;
pcbSize->u.HighPart+=ptmpSize.u.HighPart;
}
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=CompositeMonikerImpl_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;
IEnumMoniker *enumMoniker;
TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult);
*ppvResult=0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -