📄 filemoniker.c
字号:
/*
* FileMonikers 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 "winerror.h"
#include "winnls.h"
#include "wine/unicode.h"
#include "wine/debug.h"
#include "objbase.h"
#include "moniker.h"
#include "compobj_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(ole);
const CLSID CLSID_FileMoniker = {
0x303, 0, 0, {0xC0, 0, 0, 0, 0, 0, 0, 0x46}
};
/* filemoniker data structure */
typedef struct FileMonikerImpl{
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 whay IROTData interface is implemented by monikers.
*/
const IROTDataVtbl* lpvtbl2; /* VTable relative to the IROTData interface.*/
LONG ref; /* reference counter for this object */
LPOLESTR filePathName; /* path string identified by this filemoniker */
IUnknown *pMarshal; /* custom marshaler */
} FileMonikerImpl;
static inline IMoniker *impl_from_IROTData( IROTData *iface )
{
return (IMoniker *)((char*)iface - FIELD_OFFSET(FileMonikerImpl, lpvtbl2));
}
/* Local function used by filemoniker implementation */
static HRESULT WINAPI FileMonikerImpl_Construct(FileMonikerImpl* iface, LPCOLESTR lpszPathName);
static HRESULT WINAPI FileMonikerImpl_Destroy(FileMonikerImpl* iface);
/*******************************************************************************
* FileMoniker_QueryInterface
*/
static HRESULT WINAPI
FileMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject)
{
FileMonikerImpl *This = (FileMonikerImpl *)iface;
TRACE("(%p,%s,%p)\n",This,debugstr_guid(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))
{
HRESULT hr = S_OK;
if (!This->pMarshal)
hr = MonikerMarshal_Create(iface, &This->pMarshal);
if (hr != S_OK)
return hr;
return IUnknown_QueryInterface(This->pMarshal, riid, ppvObject);
}
/* 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;
}
/******************************************************************************
* FileMoniker_AddRef
*/
static ULONG WINAPI
FileMonikerImpl_AddRef(IMoniker* iface)
{
FileMonikerImpl *This = (FileMonikerImpl *)iface;
TRACE("(%p)\n",iface);
return InterlockedIncrement(&This->ref);
}
/******************************************************************************
* FileMoniker_Release
*/
static ULONG WINAPI
FileMonikerImpl_Release(IMoniker* iface)
{
FileMonikerImpl *This = (FileMonikerImpl *)iface;
ULONG ref;
TRACE("(%p)\n",iface);
ref = InterlockedDecrement(&This->ref);
/* destroy the object if there's no more reference on it */
if (ref == 0) FileMonikerImpl_Destroy(This);
return ref;
}
/******************************************************************************
* FileMoniker_GetClassID
*/
static HRESULT WINAPI
FileMonikerImpl_GetClassID(IMoniker* iface, CLSID *pClassID)
{
TRACE("(%p,%p)\n",iface,pClassID);
if (pClassID==NULL)
return E_POINTER;
*pClassID = CLSID_FileMoniker;
return S_OK;
}
/******************************************************************************
* FileMoniker_IsDirty
*
* 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.
*/
static HRESULT WINAPI
FileMonikerImpl_IsDirty(IMoniker* iface)
{
TRACE("(%p)\n",iface);
return S_FALSE;
}
/******************************************************************************
* FileMoniker_Load
*
* this function locates and reads from the stream the filePath string
* written by FileMonikerImpl_Save
*/
static HRESULT WINAPI
FileMonikerImpl_Load(IMoniker* iface, IStream* pStm)
{
HRESULT res;
CHAR* filePathA = NULL;
WCHAR* filePathW = NULL;
ULONG bread;
WORD wbuffer;
DWORD dwbuffer, bytesA, bytesW, len;
int i;
FileMonikerImpl *This = (FileMonikerImpl *)iface;
TRACE("(%p,%p)\n",iface,pStm);
/* first WORD must be 0 */
res=IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread);
if (bread!=sizeof(WORD) || wbuffer!=0)
{
WARN("Couldn't read 0 word\n");
goto fail;
}
/* read filePath string length (plus one) */
res=IStream_Read(pStm,&bytesA,sizeof(DWORD),&bread);
if (bread != sizeof(DWORD))
{
WARN("Couldn't read file string length\n");
goto fail;
}
/* read filePath string */
filePathA=HeapAlloc(GetProcessHeap(),0,bytesA);
if (!filePathA)
{
res = E_OUTOFMEMORY;
goto fail;
}
res=IStream_Read(pStm,filePathA,bytesA,&bread);
if (bread != bytesA)
{
WARN("Couldn't read file path string\n");
goto fail;
}
/* read the first constant */
IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread);
if (bread != sizeof(DWORD) || dwbuffer != 0xDEADFFFF)
{
WARN("Couldn't read 0xDEADFFFF constant\n");
goto fail;
}
for(i=0;i<5;i++)
{
res=IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread);
if (bread!=sizeof(DWORD) || dwbuffer!=0)
{
WARN("Couldn't read 0 padding\n");
goto fail;
}
}
res=IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread);
if (bread!=sizeof(DWORD))
goto fail;
if (!dwbuffer) /* No W-string */
{
bytesA--;
len=MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, filePathA, bytesA, NULL, 0);
if (!len)
goto fail;
filePathW=HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR));
if (!filePathW)
{
res = E_OUTOFMEMORY;
goto fail;
}
MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, filePathA, -1, filePathW, len+1);
goto succeed;
}
if (dwbuffer < 6)
goto fail;
bytesW=dwbuffer - 6;
res=IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread);
if (bread!=sizeof(DWORD) || dwbuffer!=bytesW)
goto fail;
res=IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread);
if (bread!=sizeof(WORD) || wbuffer!=0x3)
goto fail;
len=bytesW/sizeof(WCHAR);
filePathW=HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR));
if(!filePathW)
{
res = E_OUTOFMEMORY;
goto fail;
}
res=IStream_Read(pStm,filePathW,bytesW,&bread);
if (bread!=bytesW)
goto fail;
filePathW[len]=0;
succeed:
HeapFree(GetProcessHeap(),0,filePathA);
HeapFree(GetProcessHeap(),0,This->filePathName);
This->filePathName=filePathW;
return S_OK;
fail:
HeapFree(GetProcessHeap(), 0, filePathA);
HeapFree(GetProcessHeap(), 0, filePathW);
if (SUCCEEDED(res))
res = E_FAIL;
return res;
}
/******************************************************************************
* FileMoniker_Save
*
* This function saves data of this object. In the beginning I thought
* that I have just to write the filePath string on Stream. But, when I
* tested this function with windows programs samples, I noticed that it
* was not the case. This implementation is based on XP SP2. Other versions
* of Windows have minor variations.
*
* Data which must be written on stream is:
* 1) WORD constant:zero
* 2) length of the path string ("\0" included)
* 3) path string type A
* 4) DWORD constant : 0xDEADFFFF
* 5) five DWORD constant: zero
* 6) If we're only writing the multibyte version,
* write a zero DWORD and finish.
*
* 7) DWORD: double-length of the the path string type W ("\0" not
* included)
* 8) WORD constant: 0x3
* 9) filePath unicode string.
*
*/
static HRESULT WINAPI
FileMonikerImpl_Save(IMoniker* iface, IStream* pStm, BOOL fClearDirty)
{
FileMonikerImpl *This = (FileMonikerImpl *)iface;
HRESULT res;
LPOLESTR filePathW=This->filePathName;
CHAR* filePathA;
DWORD bytesA, bytesW, len;
static const DWORD DEADFFFF = 0xDEADFFFF; /* Constants */
static const DWORD ZERO = 0;
static const WORD THREE = 0x3;
int i;
BOOL bUsedDefault, bWriteWide;
TRACE("(%p,%p,%d)\n",iface,pStm,fClearDirty);
if (pStm==NULL)
return E_POINTER;
/* write a 0 WORD */
res=IStream_Write(pStm,&ZERO,sizeof(WORD),NULL);
if (!SUCCEEDED(res)) return res;
/* write length of filePath string ( 0 included )*/
bytesA = WideCharToMultiByte( CP_ACP, 0, filePathW, -1, NULL, 0, NULL, NULL );
res=IStream_Write(pStm,&bytesA,sizeof(DWORD),NULL);
if (!SUCCEEDED(res)) return res;
/* write A string (with '\0') */
filePathA=HeapAlloc(GetProcessHeap(),0,bytesA);
if (!filePathA)
return E_OUTOFMEMORY;
WideCharToMultiByte( CP_ACP, 0, filePathW, -1, filePathA, bytesA, NULL, &bUsedDefault);
res=IStream_Write(pStm,filePathA,bytesA,NULL);
HeapFree(GetProcessHeap(),0,filePathA);
if (!SUCCEEDED(res)) return res;
/* write a DWORD 0xDEADFFFF */
res=IStream_Write(pStm,&DEADFFFF,sizeof(DWORD),NULL);
if (!SUCCEEDED(res)) return res;
/* write 5 zero DWORDs */
for(i=0;i<5;i++)
{
res=IStream_Write(pStm,&ZERO,sizeof(DWORD),NULL);
if (!SUCCEEDED(res)) return res;
}
/* Write the wide version if:
* + couldn't convert to CP_ACP,
* or + it's a directory,
* or + there's a character > 0xFF
*/
len = lstrlenW(filePathW);
bWriteWide = (bUsedDefault || (len > 0 && filePathW[len-1]=='\\' ));
if (!bWriteWide)
{
WCHAR* pch;
for(pch=filePathW;*pch;++pch)
{
if (*pch > 0xFF)
{
bWriteWide = TRUE;
break;
}
}
}
if (!bWriteWide)
{
res=IStream_Write(pStm,&ZERO,sizeof(DWORD),NULL);
return res;
}
/* write bytes needed for the filepathW (without 0) + 6 */
bytesW = len*sizeof(WCHAR) + 6;
res=IStream_Write(pStm,&bytesW,sizeof(DWORD),NULL);
if (!SUCCEEDED(res)) return res;
/* try again, without the extra 6 */
bytesW -= 6;
res=IStream_Write(pStm,&bytesW,sizeof(DWORD),NULL);
if (!SUCCEEDED(res)) return res;
/* write a WORD 3 */
res=IStream_Write(pStm,&THREE,sizeof(WORD),NULL);
if (!SUCCEEDED(res)) return res;
/* write W string (no 0) */
res=IStream_Write(pStm,filePathW,bytesW,NULL);
return res;
}
/******************************************************************************
* FileMoniker_GetSizeMax
*/
static HRESULT WINAPI
FileMonikerImpl_GetSizeMax(IMoniker* iface, ULARGE_INTEGER* pcbSize)
{
FileMonikerImpl *This = (FileMonikerImpl *)iface;
TRACE("(%p,%p)\n",iface,pcbSize);
if (!pcbSize)
return E_POINTER;
/* We could calculate exactly (see ...::Save()) but instead
* we'll make a quick over-estimate, like Windows (NT4, XP) does.
*/
pcbSize->u.LowPart = 0x38 + 4 * lstrlenW(This->filePathName);
pcbSize->u.HighPart = 0;
return S_OK;
}
/******************************************************************************
* FileMoniker_Destroy (local function)
*******************************************************************************/
HRESULT WINAPI FileMonikerImpl_Destroy(FileMonikerImpl* This)
{
TRACE("(%p)\n",This);
if (This->pMarshal) IUnknown_Release(This->pMarshal);
HeapFree(GetProcessHeap(),0,This->filePathName);
HeapFree(GetProcessHeap(),0,This);
return S_OK;
}
/******************************************************************************
* FileMoniker_BindToObject
*/
static HRESULT WINAPI
FileMonikerImpl_BindToObject(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
REFIID riid, VOID** ppvResult)
{
HRESULT res=E_FAIL;
CLSID clsID;
IUnknown* pObj=0;
IRunningObjectTable *prot=0;
IPersistFile *ppf=0;
IClassFactory *pcf=0;
IClassActivator *pca=0;
FileMonikerImpl *This = (FileMonikerImpl *)iface;
*ppvResult=0;
TRACE("(%p,%p,%p,%s,%p)\n",iface,pbc,pmkToLeft,debugstr_guid(riid),ppvResult);
if(pmkToLeft==NULL){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -