From f662eaa54888f32a0aa4c7453f45f97125339d6c Mon Sep 17 00:00:00 2001 From: The Wine Synchronizer Date: Fri, 20 Apr 2007 12:23:52 +0000 Subject: [PATCH] Autosyncing with Wine HEAD svn path=/trunk/; revision=26436 --- reactos/dll/win32/ole32/antimoniker.c | 124 +- reactos/dll/win32/ole32/bindctx.c | 158 +- reactos/dll/win32/ole32/classmoniker.c | 882 +++++++++++ reactos/dll/win32/ole32/clipboard.c | 44 +- reactos/dll/win32/ole32/compobj.c | 1566 ++++++++++++++------ reactos/dll/win32/ole32/compobj.spec | 2 +- reactos/dll/win32/ole32/compobj_private.h | 73 +- reactos/dll/win32/ole32/compositemoniker.c | 624 ++++++-- reactos/dll/win32/ole32/datacache.c | 1197 ++++++++++----- reactos/dll/win32/ole32/dcom.h | 515 ------- reactos/dll/win32/ole32/dcom.idl | 16 +- reactos/dll/win32/ole32/defaulthandler.c | 61 +- reactos/dll/win32/ole32/dictionary.c | 2 +- reactos/dll/win32/ole32/dictionary.h | 2 +- reactos/dll/win32/ole32/enumx.c | 202 +++ reactos/dll/win32/ole32/enumx.h | 34 + reactos/dll/win32/ole32/errorinfo.c | 44 +- reactos/dll/win32/ole32/filemoniker.c | 112 +- reactos/dll/win32/ole32/ftmarshal.c | 190 ++- reactos/dll/win32/ole32/git.c | 58 +- reactos/dll/win32/ole32/hglobalstream.c | 85 +- reactos/dll/win32/ole32/ifs.c | 20 +- reactos/dll/win32/ole32/ifs.h | 5 +- reactos/dll/win32/ole32/itemmoniker.c | 39 +- reactos/dll/win32/ole32/marshal.c | 502 +++++-- reactos/dll/win32/ole32/memlockbytes.c | 134 +- reactos/dll/win32/ole32/memlockbytes16.c | 30 +- reactos/dll/win32/ole32/moniker.c | 493 ++++-- reactos/dll/win32/ole32/moniker.h | 41 +- reactos/dll/win32/ole32/ole16.c | 109 +- reactos/dll/win32/ole32/ole2.c | 593 ++++---- reactos/dll/win32/ole32/ole2_16.c | 11 +- reactos/dll/win32/ole32/ole2impl.c | 2 +- reactos/dll/win32/ole32/ole2nls.c | 2 +- reactos/dll/win32/ole32/ole2stubs.c | 6 +- reactos/dll/win32/ole32/ole32.rbuild | 15 +- reactos/dll/win32/ole32/ole32.spec | 33 +- reactos/dll/win32/ole32/ole32_main.c | 65 +- reactos/dll/win32/ole32/ole32_ros.diff | 12 + reactos/dll/win32/ole32/ole32res.rc | 2 +- reactos/dll/win32/ole32/oleobj.c | 300 +++- reactos/dll/win32/ole32/oleproxy.c | 122 +- reactos/dll/win32/ole32/olestd.h | 2 +- reactos/dll/win32/ole32/regsvr.c | 195 ++- reactos/dll/win32/ole32/rpc.c | 1218 +++++++++++++-- reactos/dll/win32/ole32/stg_bigblockfile.c | 437 +++--- reactos/dll/win32/ole32/stg_prop.c | 445 ++++-- reactos/dll/win32/ole32/stg_stream.c | 184 ++- reactos/dll/win32/ole32/storage.c | 101 +- reactos/dll/win32/ole32/storage32.c | 1115 ++++++++------ reactos/dll/win32/ole32/storage32.h | 241 +-- reactos/dll/win32/ole32/stubmanager.c | 123 +- reactos/dll/win32/ole32/usrmarshal.c | 1275 ++++++++++++++-- reactos/dll/win32/ole32/version.rc | 2 +- 54 files changed, 10012 insertions(+), 3853 deletions(-) create mode 100644 reactos/dll/win32/ole32/classmoniker.c delete mode 100644 reactos/dll/win32/ole32/dcom.h create mode 100644 reactos/dll/win32/ole32/enumx.c create mode 100644 reactos/dll/win32/ole32/enumx.h create mode 100644 reactos/dll/win32/ole32/ole32_ros.diff diff --git a/reactos/dll/win32/ole32/antimoniker.c b/reactos/dll/win32/ole32/antimoniker.c index bcd59e12684..829fc4f0080 100644 --- a/reactos/dll/win32/ole32/antimoniker.c +++ b/reactos/dll/win32/ole32/antimoniker.c @@ -1,4 +1,4 @@ -/*************************************************************************************** +/* * AntiMonikers implementation * * Copyright 1999 Noomen Hamza @@ -15,8 +15,8 @@ * * 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 - ***************************************************************************************/ + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ #include #include @@ -35,10 +35,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole); -const CLSID CLSID_AntiMoniker = { - 0x305, 0, 0, {0xC0, 0, 0, 0, 0, 0, 0, 0x46} -}; - /* AntiMoniker data structure */ typedef struct AntiMonikerImpl{ @@ -51,6 +47,7 @@ typedef struct AntiMonikerImpl{ LONG ref; /* reference counter for this object */ + IUnknown *pMarshal; /* custom marshaler */ } AntiMonikerImpl; static inline IMoniker *impl_from_IROTData( IROTData *iface ) @@ -84,6 +81,15 @@ AntiMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject) *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) @@ -122,7 +128,11 @@ AntiMonikerImpl_Release(IMoniker* iface) ref = InterlockedDecrement(&This->ref); /* destroy the object if there's no more reference on it */ - if (ref == 0) HeapFree(GetProcessHeap(),0,This); + if (ref == 0) + { + if (This->pMarshal) IUnknown_Release(This->pMarshal); + HeapFree(GetProcessHeap(),0,This); + } return ref; } @@ -133,7 +143,7 @@ AntiMonikerImpl_Release(IMoniker* iface) static HRESULT WINAPI AntiMonikerImpl_GetClassID(IMoniker* iface,CLSID *pClassID) { - TRACE("(%p,%p),stub!\n",iface,pClassID); + TRACE("(%p,%p)\n",iface,pClassID); if (pClassID==NULL) return E_POINTER; @@ -202,7 +212,7 @@ AntiMonikerImpl_GetSizeMax(IMoniker* iface, ULARGE_INTEGER* pcbSize) { TRACE("(%p,%p)\n",iface,pcbSize); - if (pcbSize!=NULL) + if (!pcbSize) return E_POINTER; /* for more details see AntiMonikerImpl_Save coments */ @@ -248,7 +258,7 @@ static HRESULT WINAPI AntiMonikerImpl_Reduce(IMoniker* iface, IBindCtx* pbc, DWORD dwReduceHowFar, IMoniker** ppmkToLeft, IMoniker** ppmkReduced) { - TRACE("(%p,%p,%ld,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced); + TRACE("(%p,%p,%d,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced); if (ppmkReduced==NULL) return E_POINTER; @@ -325,7 +335,7 @@ static HRESULT WINAPI AntiMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash) if (pdwHash==NULL) return E_POINTER; - *pdwHash=0; + *pdwHash = 0x80000001; return S_OK; } @@ -395,7 +405,7 @@ AntiMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther,IMoniker** p IMoniker_IsSystemMoniker(pmkOther,&mkSys); - if(mkSys==MKSYS_ITEMMONIKER){ + if(mkSys==MKSYS_ANTIMONIKER){ IMoniker_AddRef(iface); @@ -525,11 +535,21 @@ static ULONG WINAPI AntiMonikerROTDataImpl_Release(IROTData* iface) * AntiMonikerIROTData_GetComparaisonData ******************************************************************************/ static HRESULT WINAPI -AntiMonikerROTDataImpl_GetComparaisonData(IROTData* iface, BYTE* pbData, +AntiMonikerROTDataImpl_GetComparisonData(IROTData* iface, BYTE* pbData, ULONG cbMax, ULONG* pcbData) { - FIXME("(),stub!\n"); - return E_NOTIMPL; + DWORD constant = 1; + + TRACE("(%p, %u, %p)\n", pbData, cbMax, pcbData); + + *pcbData = sizeof(CLSID) + sizeof(DWORD); + if (cbMax < *pcbData) + return E_OUTOFMEMORY; + + memcpy(pbData, &CLSID_AntiMoniker, sizeof(CLSID)); + memcpy(pbData+sizeof(CLSID), &constant, sizeof(DWORD)); + + return S_OK; } /********************************************************************************/ @@ -569,7 +589,7 @@ static const IROTDataVtbl VT_ROTDataImpl = AntiMonikerROTDataImpl_QueryInterface, AntiMonikerROTDataImpl_AddRef, AntiMonikerROTDataImpl_Release, - AntiMonikerROTDataImpl_GetComparaisonData + AntiMonikerROTDataImpl_GetComparisonData }; /****************************************************************************** @@ -584,6 +604,7 @@ static HRESULT AntiMonikerImpl_Construct(AntiMonikerImpl* This) This->lpvtbl1 = &VT_AntiMonikerImpl; This->lpvtbl2 = &VT_ROTDataImpl; This->ref = 0; + This->pMarshal = NULL; return S_OK; } @@ -615,3 +636,72 @@ HRESULT WINAPI CreateAntiMoniker(LPMONIKER * ppmk) return hr; } + +static HRESULT WINAPI AntiMonikerCF_QueryInterface(LPCLASSFACTORY iface, + REFIID riid, LPVOID *ppv) +{ + *ppv = NULL; + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory)) + { + *ppv = iface; + IUnknown_AddRef(iface); + return S_OK; + } + return E_NOINTERFACE; +} + +static ULONG WINAPI AntiMonikerCF_AddRef(LPCLASSFACTORY iface) +{ + return 2; /* non-heap based object */ +} + +static ULONG WINAPI AntiMonikerCF_Release(LPCLASSFACTORY iface) +{ + return 1; /* non-heap based object */ +} + +static HRESULT WINAPI AntiMonikerCF_CreateInstance(LPCLASSFACTORY iface, + LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv) +{ + IMoniker *pMoniker; + HRESULT hr; + + TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv); + + *ppv = NULL; + + if (pUnk) + return CLASS_E_NOAGGREGATION; + + hr = CreateAntiMoniker(&pMoniker); + if (FAILED(hr)) + return hr; + + hr = IMoniker_QueryInterface(pMoniker, riid, ppv); + + if (FAILED(hr)) + IMoniker_Release(pMoniker); + + return hr; +} + +static HRESULT WINAPI AntiMonikerCF_LockServer(LPCLASSFACTORY iface, BOOL fLock) +{ + FIXME("(%d), stub!\n",fLock); + return S_OK; +} + +static const IClassFactoryVtbl AntiMonikerCFVtbl = +{ + AntiMonikerCF_QueryInterface, + AntiMonikerCF_AddRef, + AntiMonikerCF_Release, + AntiMonikerCF_CreateInstance, + AntiMonikerCF_LockServer +}; +static const IClassFactoryVtbl *AntiMonikerCF = &AntiMonikerCFVtbl; + +HRESULT AntiMonikerCF_Create(REFIID riid, LPVOID *ppv) +{ + return IClassFactory_QueryInterface((IClassFactory *)&AntiMonikerCF, riid, ppv); +} diff --git a/reactos/dll/win32/ole32/bindctx.c b/reactos/dll/win32/ole32/bindctx.c index a58457d133a..da68f33ab8d 100644 --- a/reactos/dll/win32/ole32/bindctx.c +++ b/reactos/dll/win32/ole32/bindctx.c @@ -1,4 +1,4 @@ -/*************************************************************************************** +/* * BindCtx implementation * * Copyright 1999 Noomen Hamza @@ -15,26 +15,25 @@ * * 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 - ***************************************************************************************/ + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ #include #include -#include #define COBJMACROS #include "winerror.h" #include "windef.h" #include "winbase.h" +#include "winnls.h" #include "objbase.h" + #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(ole); -/* represent the first size table and it's increment block size */ -#define BLOCK_TAB_SIZE 10 -#define MAX_TAB_SIZE 0xFFFFFFFF +#define BINDCTX_FIRST_TABLE_SIZE 4 /* data structure of the BindCtx table elements */ typedef struct BindCtxObject{ @@ -65,6 +64,7 @@ typedef struct BindCtxImpl{ /* IBindCtx prototype functions : */ static HRESULT WINAPI BindCtxImpl_ReleaseBoundObjects(IBindCtx*); static HRESULT BindCtxImpl_GetObjectIndex(BindCtxImpl*, IUnknown*, LPOLESTR, DWORD *); +static HRESULT BindCtxImpl_ExpandTable(BindCtxImpl *); /******************************************************************************* * BindCtx_QueryInterface @@ -157,7 +157,14 @@ BindCtxImpl_RegisterObjectBound(IBindCtx* iface,IUnknown* punk) TRACE("(%p,%p)\n",This,punk); if (punk==NULL) - return E_POINTER; + return S_OK; + + if (lastIndex == This->bindCtxTableSize) + { + HRESULT hr = BindCtxImpl_ExpandTable(This); + if (FAILED(hr)) + return hr; + } IUnknown_AddRef(punk); @@ -167,20 +174,6 @@ BindCtxImpl_RegisterObjectBound(IBindCtx* iface,IUnknown* punk) This->bindCtxTable[lastIndex].regType = 0; lastIndex= ++This->bindCtxTableLastIndex; - if (lastIndex == This->bindCtxTableSize){ /* the table is full so it must be resized */ - - if (This->bindCtxTableSize > (MAX_TAB_SIZE-BLOCK_TAB_SIZE)){ - FIXME("This->bindCtxTableSize: %ld is out of data limite\n", This->bindCtxTableSize); - return E_FAIL; - } - - This->bindCtxTableSize+=BLOCK_TAB_SIZE; /* new table size */ - - This->bindCtxTable = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,This->bindCtxTable, - This->bindCtxTableSize * sizeof(BindCtxObject)); - if (!This->bindCtxTable) - return E_OUTOFMEMORY; - } return S_OK; } @@ -196,6 +189,9 @@ BindCtxImpl_RevokeObjectBound(IBindCtx* iface, IUnknown* punk) TRACE("(%p,%p)\n",This,punk); + if (!punk) + return E_INVALIDARG; + /* check if the object was registered or not */ if (BindCtxImpl_GetObjectIndex(This,punk,NULL,&index)==S_FALSE) return MK_E_NOTBOUND; @@ -266,18 +262,20 @@ static HRESULT WINAPI BindCtxImpl_GetBindOptions(IBindCtx* iface,BIND_OPTS *pbindopts) { BindCtxImpl *This = (BindCtxImpl *)iface; + ULONG cbStruct; TRACE("(%p,%p)\n",This,pbindopts); if (pbindopts==NULL) return E_POINTER; - if (pbindopts->cbStruct > sizeof(BIND_OPTS2)) - { - WARN("invalid size\n"); - return E_INVALIDARG; /* FIXME : not verified */ - } - memcpy(pbindopts, &This->bindOption2, pbindopts->cbStruct); + cbStruct = pbindopts->cbStruct; + if (cbStruct > sizeof(BIND_OPTS2)) + cbStruct = sizeof(BIND_OPTS2); + + memcpy(pbindopts, &This->bindOption2, cbStruct); + pbindopts->cbStruct = cbStruct; + return S_OK; } @@ -324,6 +322,14 @@ BindCtxImpl_RegisterObjectParam(IBindCtx* iface,LPOLESTR pszkey, IUnknown* punk) IUnknown_AddRef(punk); return S_OK; } + + if (This->bindCtxTableLastIndex == This->bindCtxTableSize) + { + HRESULT hr = BindCtxImpl_ExpandTable(This); + if (FAILED(hr)) + return hr; + } + This->bindCtxTable[This->bindCtxTableLastIndex].pObj = punk; This->bindCtxTable[This->bindCtxTableLastIndex].regType = 1; @@ -344,21 +350,6 @@ BindCtxImpl_RegisterObjectParam(IBindCtx* iface,LPOLESTR pszkey, IUnknown* punk) This->bindCtxTableLastIndex++; - if (This->bindCtxTableLastIndex == This->bindCtxTableSize) - { - /* table is full ! must be resized */ - - This->bindCtxTableSize+=BLOCK_TAB_SIZE; /* new table size */ - if (This->bindCtxTableSize > (MAX_TAB_SIZE-BLOCK_TAB_SIZE)) - { - FIXME("This->bindCtxTableSize: %ld is out of data limite\n", This->bindCtxTableSize); - return E_FAIL; - } - This->bindCtxTable = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,This->bindCtxTable, - This->bindCtxTableSize * sizeof(BindCtxObject)); - if (!This->bindCtxTable) - return E_OUTOFMEMORY; - } IUnknown_AddRef(punk); return S_OK; } @@ -424,7 +415,11 @@ BindCtxImpl_RevokeObjectParam(IBindCtx* iface,LPOLESTR ppenum) static HRESULT WINAPI BindCtxImpl_EnumObjectParam(IBindCtx* iface,IEnumString** pszkey) { - FIXME("(%p,%p),stub!\n",iface,pszkey); + TRACE("(%p,%p)\n",iface,pszkey); + + *pszkey = NULL; + + /* not implemented in native either */ return E_NOTIMPL; } @@ -473,6 +468,29 @@ static HRESULT BindCtxImpl_GetObjectIndex(BindCtxImpl* This, return S_FALSE; } +static HRESULT BindCtxImpl_ExpandTable(BindCtxImpl *This) +{ + if (!This->bindCtxTableSize) + { + This->bindCtxTableSize = BINDCTX_FIRST_TABLE_SIZE; + This->bindCtxTable = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, + This->bindCtxTableSize * sizeof(BindCtxObject)); + } + else + { + This->bindCtxTableSize *= 2; + + This->bindCtxTable = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,This->bindCtxTable, + This->bindCtxTableSize * sizeof(BindCtxObject)); + } + + if (!This->bindCtxTable) + return E_OUTOFMEMORY; + + return S_OK; +} + + /* Virtual function table for the BindCtx class. */ static const IBindCtxVtbl VT_BindCtxImpl = { @@ -510,31 +528,48 @@ static HRESULT BindCtxImpl_Construct(BindCtxImpl* This) This->bindOption2.dwTrackFlags = 0; This->bindOption2.dwClassContext = CLSCTX_SERVER; - This->bindOption2.locale = 1033; + This->bindOption2.locale = GetThreadLocale(); This->bindOption2.pServerInfo = 0; /* Initialize the bindctx table */ - This->bindCtxTableSize=BLOCK_TAB_SIZE; + This->bindCtxTableSize=0; This->bindCtxTableLastIndex=0; - This->bindCtxTable = HeapAlloc(GetProcessHeap(), 0, - This->bindCtxTableSize*sizeof(BindCtxObject)); - - if (This->bindCtxTable==NULL) - return E_OUTOFMEMORY; + This->bindCtxTable = NULL; return S_OK; } /****************************************************************************** * CreateBindCtx (OLE32.@) - ******************************************************************************/ + * + * Creates a bind context. A bind context encompasses information and options + * used when binding to a moniker. + * + * PARAMS + * reserved [I] Reserved. Set to 0. + * ppbc [O] Address that receives the bind context object. + * + * RETURNS + * Success: S_OK. + * Failure: Any HRESULT code. + */ HRESULT WINAPI CreateBindCtx(DWORD reserved, LPBC * ppbc) { BindCtxImpl* newBindCtx = 0; HRESULT hr; IID riid=IID_IBindCtx; - TRACE("(%ld,%p)\n",reserved,ppbc); + TRACE("(%d,%p)\n",reserved,ppbc); + + if (!ppbc) return E_INVALIDARG; + + *ppbc = NULL; + + if (reserved != 0) + { + ERR("reserved should be 0, not 0x%x\n", reserved); + return E_INVALIDARG; + } newBindCtx = HeapAlloc(GetProcessHeap(), 0, sizeof(BindCtxImpl)); if (newBindCtx == 0) @@ -552,12 +587,27 @@ HRESULT WINAPI CreateBindCtx(DWORD reserved, LPBC * ppbc) return hr; } +/****************************************************************************** + * BindMoniker [OLE32.@] + * + * Binds to a moniker. + * + * PARAMS + * pmk [I] Moniker to bind to. + * grfOpt [I] Reserved option flags. Set to 0. + * riid [I] ID of the interface to bind to. + * pvResult [O] Address that receives the interface of the object that was bound to. + * + * RETURNS + * Success: S_OK. + * Failure: Any HRESULT code. + */ HRESULT WINAPI BindMoniker(LPMONIKER pmk, DWORD grfOpt, REFIID riid, LPVOID * ppvResult) { HRESULT res; IBindCtx * pbc; - TRACE("(%p, %lx, %s, %p)\n", pmk, grfOpt, debugstr_guid(riid), ppvResult); + TRACE("(%p, %x, %s, %p)\n", pmk, grfOpt, debugstr_guid(riid), ppvResult); res = CreateBindCtx(grfOpt, &pbc); if (SUCCEEDED(res)) diff --git a/reactos/dll/win32/ole32/classmoniker.c b/reactos/dll/win32/ole32/classmoniker.c new file mode 100644 index 00000000000..07db6225b54 --- /dev/null +++ b/reactos/dll/win32/ole32/classmoniker.c @@ -0,0 +1,882 @@ +/* + * Class Monikers + * + * Copyright 1999 Noomen Hamza + * Copyright 2005-2007 Robert Shearman + * + * 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 +#include +#include + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "winerror.h" +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winnls.h" +#include "wine/debug.h" +#include "ole2.h" +#include "wine/unicode.h" +#include "moniker.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +#define CHARS_IN_GUID 39 + +/* ClassMoniker data structure */ +typedef struct ClassMoniker +{ + const IMonikerVtbl* lpVtbl; /* VTable relative to the IMoniker interface.*/ + const IROTDataVtbl* lpVtblRotData; /* VTable relative to the IROTData interface.*/ + LONG ref; /* reference counter for this object */ + CLSID clsid; /* clsid identified by this moniker */ + IUnknown *pMarshal; /* custom marshaler */ +} ClassMoniker; + +static inline IMoniker *impl_from_IROTData( IROTData *iface ) +{ + return (IMoniker *)((char*)iface - FIELD_OFFSET(ClassMoniker, lpVtblRotData)); +} + +/******************************************************************************* + * ClassMoniker_QueryInterface + *******************************************************************************/ +static HRESULT WINAPI ClassMoniker_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject) +{ + ClassMoniker *This = (ClassMoniker *)iface; + + TRACE("(%p,%p,%p)\n",This,riid,ppvObject); + + /* Perform a sanity check on the parameters.*/ + if (!ppvObject) + return E_POINTER; + + /* 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->lpVtblRotData); + 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) + return E_NOINTERFACE; + + /* Query Interface always increases the reference count by one when it is successful */ + IMoniker_AddRef(iface); + + return S_OK; +} + +/****************************************************************************** + * ClassMoniker_AddRef + ******************************************************************************/ +static ULONG WINAPI ClassMoniker_AddRef(IMoniker* iface) +{ + ClassMoniker *This = (ClassMoniker *)iface; + + TRACE("(%p)\n",This); + + return InterlockedIncrement(&This->ref); +} + +/****************************************************************************** + * ClassMoniker_Destroy (local function) + *******************************************************************************/ +static HRESULT WINAPI ClassMoniker_Destroy(ClassMoniker* This) +{ + TRACE("(%p)\n",This); + + if (This->pMarshal) IUnknown_Release(This->pMarshal); + + HeapFree(GetProcessHeap(),0,This); + + return S_OK; +} + +/****************************************************************************** + * ClassMoniker_Release + ******************************************************************************/ +static ULONG WINAPI ClassMoniker_Release(IMoniker* iface) +{ + ClassMoniker *This = (ClassMoniker *)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) ClassMoniker_Destroy(This); + + return ref; +} + +/****************************************************************************** + * ClassMoniker_GetClassID + ******************************************************************************/ +static HRESULT WINAPI ClassMoniker_GetClassID(IMoniker* iface,CLSID *pClassID) +{ + TRACE("(%p,%p),stub!\n",iface,pClassID); + + if (pClassID==NULL) + return E_POINTER; + + *pClassID = CLSID_ClassMoniker; + + return S_OK; +} + +/****************************************************************************** + * ClassMoniker_IsDirty + ******************************************************************************/ +static HRESULT WINAPI ClassMoniker_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; +} + +/****************************************************************************** + * ClassMoniker_Load + ******************************************************************************/ +static HRESULT WINAPI ClassMoniker_Load(IMoniker* iface,IStream* pStm) +{ + ClassMoniker *This = (ClassMoniker *)iface; + HRESULT hr; + DWORD zero; + + TRACE("(%p)\n", pStm); + + hr = IStream_Read(pStm, &This->clsid, sizeof(This->clsid), NULL); + if (hr != S_OK) return STG_E_READFAULT; + + hr = IStream_Read(pStm, &zero, sizeof(zero), NULL); + if ((hr != S_OK) || (zero != 0)) return STG_E_READFAULT; + + return S_OK; +} + +/****************************************************************************** + * ClassMoniker_Save + ******************************************************************************/ +static HRESULT WINAPI ClassMoniker_Save(IMoniker* iface, + IStream* pStm,/* pointer to the stream where the object is to be saved */ + BOOL fClearDirty)/* Specifies whether to clear the dirty flag */ +{ + ClassMoniker *This = (ClassMoniker *)iface; + HRESULT hr; + DWORD zero = 0; + + TRACE("(%p, %s)\n", pStm, fClearDirty ? "TRUE" : "FALSE"); + + hr = IStream_Write(pStm, &This->clsid, sizeof(This->clsid), NULL); + if (FAILED(hr)) return hr; + + hr = IStream_Write(pStm, &zero, sizeof(zero), NULL); + + return hr; +} + +/****************************************************************************** + * ClassMoniker_GetSizeMax + ******************************************************************************/ +static HRESULT WINAPI ClassMoniker_GetSizeMax(IMoniker* iface, + ULARGE_INTEGER* pcbSize)/* Pointer to size of stream needed to save object */ +{ + TRACE("(%p)\n", pcbSize); + + pcbSize->QuadPart = sizeof(CLSID) + sizeof(DWORD); + + return S_OK; +} + +/****************************************************************************** + * ClassMoniker_BindToObject + ******************************************************************************/ +static HRESULT WINAPI ClassMoniker_BindToObject(IMoniker* iface, + IBindCtx* pbc, + IMoniker* pmkToLeft, + REFIID riid, + VOID** ppvResult) +{ + ClassMoniker *This = (ClassMoniker *)iface; + BIND_OPTS2 bindopts; + IClassActivator *pActivator; + HRESULT hr; + + TRACE("(%p,%p,%p,%p)\n", pbc, pmkToLeft, riid, ppvResult); + + bindopts.cbStruct = sizeof(bindopts); + IBindCtx_GetBindOptions(pbc, (BIND_OPTS *)&bindopts); + + if (!pmkToLeft) + return CoGetClassObject(&This->clsid, bindopts.dwClassContext, NULL, + riid, ppvResult); + else + { + hr = IMoniker_BindToObject(pmkToLeft, pbc, NULL, &IID_IClassActivator, + (void **)&pActivator); + if (FAILED(hr)) return hr; + + hr = IClassActivator_GetClassObject(pActivator, &This->clsid, + bindopts.dwClassContext, + bindopts.locale, riid, ppvResult); + + IClassActivator_Release(pActivator); + + return hr; + } +} + +/****************************************************************************** + * ClassMoniker_BindToStorage + ******************************************************************************/ +static HRESULT WINAPI ClassMoniker_BindToStorage(IMoniker* iface, + IBindCtx* pbc, + IMoniker* pmkToLeft, + REFIID riid, + VOID** ppvResult) +{ + TRACE("(%p,%p,%p,%p)\n",pbc, pmkToLeft, riid, ppvResult); + return ClassMoniker_BindToObject(iface, pbc, pmkToLeft, riid, ppvResult); +} + +/****************************************************************************** + * ClassMoniker_Reduce + ******************************************************************************/ +static HRESULT WINAPI ClassMoniker_Reduce(IMoniker* iface, + IBindCtx* pbc, + DWORD dwReduceHowFar, + IMoniker** ppmkToLeft, + IMoniker** ppmkReduced) +{ + TRACE("(%p,%p,%d,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced); + + if (!ppmkReduced) + return E_POINTER; + + ClassMoniker_AddRef(iface); + + *ppmkReduced = iface; + + return MK_S_REDUCED_TO_SELF; +} +/****************************************************************************** + * ClassMoniker_ComposeWith + ******************************************************************************/ +static HRESULT WINAPI ClassMoniker_ComposeWith(IMoniker* iface, + IMoniker* pmkRight, + BOOL fOnlyIfNotGeneric, + IMoniker** ppmkComposite) +{ + HRESULT res=S_OK; + DWORD mkSys,mkSys2; + IEnumMoniker* penumMk=0; + IMoniker *pmostLeftMk=0; + IMoniker* tempMkComposite=0; + + TRACE("(%p,%d,%p)\n", pmkRight, fOnlyIfNotGeneric, ppmkComposite); + + if ((ppmkComposite==NULL)||(pmkRight==NULL)) + return E_POINTER; + + *ppmkComposite=0; + + IMoniker_IsSystemMoniker(pmkRight,&mkSys); + + /* If pmkRight is an anti-moniker, the returned moniker is NULL */ + if(mkSys==MKSYS_ANTIMONIKER) + return res; + + else + /* if pmkRight is a composite whose leftmost component is an anti-moniker, */ + /* the returned moniker is the composite after the leftmost anti-moniker is removed. */ + + if(mkSys==MKSYS_GENERICCOMPOSITE){ + + res=IMoniker_Enum(pmkRight,TRUE,&penumMk); + + if (FAILED(res)) + return res; + + res=IEnumMoniker_Next(penumMk,1,&pmostLeftMk,NULL); + + IMoniker_IsSystemMoniker(pmostLeftMk,&mkSys2); + + if(mkSys2==MKSYS_ANTIMONIKER){ + + IMoniker_Release(pmostLeftMk); + + tempMkComposite=iface; + IMoniker_AddRef(iface); + + while(IEnumMoniker_Next(penumMk,1,&pmostLeftMk,NULL)==S_OK){ + + res=CreateGenericComposite(tempMkComposite,pmostLeftMk,ppmkComposite); + + IMoniker_Release(tempMkComposite); + IMoniker_Release(pmostLeftMk); + + tempMkComposite=*ppmkComposite; + IMoniker_AddRef(tempMkComposite); + } + return res; + } + else + return CreateGenericComposite(iface,pmkRight,ppmkComposite); + } + /* If pmkRight is not an anti-moniker, the method combines the two monikers into a generic + composite if fOnlyIfNotGeneric is FALSE; if fOnlyIfNotGeneric is TRUE, the method returns + a NULL moniker and a return value of MK_E_NEEDGENERIC */ + else + if (!fOnlyIfNotGeneric) + return CreateGenericComposite(iface,pmkRight,ppmkComposite); + + else + return MK_E_NEEDGENERIC; +} + +/****************************************************************************** + * ClassMoniker_Enum + ******************************************************************************/ +static HRESULT WINAPI ClassMoniker_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker) +{ + TRACE("(%p,%d,%p)\n",iface,fForward,ppenumMoniker); + + if (ppenumMoniker == NULL) + return E_POINTER; + + *ppenumMoniker = NULL; + + return S_OK; +} + +/****************************************************************************** + * ClassMoniker_IsEqual + ******************************************************************************/ +static HRESULT WINAPI ClassMoniker_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker) +{ + + CLSID clsid; + LPOLESTR dispName1,dispName2; + IBindCtx* bind; + HRESULT res = S_FALSE; + + TRACE("(%p,%p)\n",iface,pmkOtherMoniker); + + if (!pmkOtherMoniker) return S_FALSE; + + + /* check if both are ClassMoniker */ + if(FAILED (IMoniker_GetClassID(pmkOtherMoniker,&clsid))) return S_FALSE; + if(!IsEqualCLSID(&clsid,&CLSID_ClassMoniker)) return S_FALSE; + + /* check if both displaynames are the same */ + if(SUCCEEDED ((res = CreateBindCtx(0,&bind)))) { + if(SUCCEEDED (IMoniker_GetDisplayName(iface,bind,NULL,&dispName1))) { + if(SUCCEEDED (IMoniker_GetDisplayName(pmkOtherMoniker,bind,NULL,&dispName2))) { + if(lstrcmpW(dispName1,dispName2)==0) res = S_OK; + CoTaskMemFree(dispName2); + } + CoTaskMemFree(dispName1); + } + } + return res; +} + +/****************************************************************************** + * ClassMoniker_Hash + ******************************************************************************/ +static HRESULT WINAPI ClassMoniker_Hash(IMoniker* iface,DWORD* pdwHash) +{ + ClassMoniker *This = (ClassMoniker *)iface; + + TRACE("(%p)\n", pdwHash); + + *pdwHash = This->clsid.Data1; + + return S_OK; +} + +/****************************************************************************** + * ClassMoniker_IsRunning + ******************************************************************************/ +static HRESULT WINAPI ClassMoniker_IsRunning(IMoniker* iface, + IBindCtx* pbc, + IMoniker* pmkToLeft, + IMoniker* pmkNewlyRunning) +{ + TRACE("(%p, %p, %p)\n", pbc, pmkToLeft, pmkNewlyRunning); + + /* as in native */ + return E_NOTIMPL; +} + +/****************************************************************************** + * ClassMoniker_GetTimeOfLastChange + ******************************************************************************/ +static HRESULT WINAPI ClassMoniker_GetTimeOfLastChange(IMoniker* iface, + IBindCtx* pbc, + IMoniker* pmkToLeft, + FILETIME* pItemTime) +{ + TRACE("(%p, %p, %p)\n", pbc, pmkToLeft, pItemTime); + + return MK_E_UNAVAILABLE; +} + +/****************************************************************************** + * ClassMoniker_Inverse + ******************************************************************************/ +static HRESULT WINAPI ClassMoniker_Inverse(IMoniker* iface,IMoniker** ppmk) +{ + TRACE("(%p)\n",ppmk); + + if (!ppmk) + return E_POINTER; + + return CreateAntiMoniker(ppmk); +} + +/****************************************************************************** + * ClassMoniker_CommonPrefixWith + ******************************************************************************/ +static HRESULT WINAPI ClassMoniker_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther,IMoniker** ppmkPrefix) +{ + DWORD mkSys; + + TRACE("(%p, %p)\n", pmkOther, ppmkPrefix); + + *ppmkPrefix = NULL; + + IMoniker_IsSystemMoniker(pmkOther, &mkSys); + + /* If the other moniker is an class moniker that is equal to this moniker, this method sets *ppmkPrefix */ + /* to this moniker and returns MK_S_US */ + + if (mkSys == MKSYS_CLASSMONIKER) + { + if (IMoniker_IsEqual(iface, pmkOther) == S_OK) + { + *ppmkPrefix = iface; + + IMoniker_AddRef(iface); + + return MK_S_US; + } + else + return MK_E_NOPREFIX; + } + else + /* otherwise, the method calls the MonikerCommonPrefixWith function. This function correctly handles */ + /* the case where the other moniker is a generic composite. */ + return MonikerCommonPrefixWith(iface, pmkOther, ppmkPrefix); +} + +/****************************************************************************** + * ClassMoniker_RelativePathTo + ******************************************************************************/ +static HRESULT WINAPI ClassMoniker_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath) +{ + TRACE("(%p, %p)\n",pmOther,ppmkRelPath); + + if (!ppmkRelPath) + return E_POINTER; + + *ppmkRelPath = NULL; + + return MK_E_NOTBINDABLE; +} + +/****************************************************************************** + * ClassMoniker_GetDisplayName + ******************************************************************************/ +static HRESULT WINAPI ClassMoniker_GetDisplayName(IMoniker* iface, + IBindCtx* pbc, + IMoniker* pmkToLeft, + LPOLESTR *ppszDisplayName) +{ + ClassMoniker *This = (ClassMoniker *)iface; + static const WCHAR wszClsidPrefix[] = {'c','l','s','i','d',':',0}; + + TRACE("(%p, %p, %p)\n", pbc, pmkToLeft, ppszDisplayName); + + if (!ppszDisplayName) + return E_POINTER; + + if (pmkToLeft) + return E_INVALIDARG; + + *ppszDisplayName = CoTaskMemAlloc(sizeof(wszClsidPrefix) + (CHARS_IN_GUID-2) * sizeof(WCHAR)); + + StringFromGUID2(&This->clsid, *ppszDisplayName+sizeof(wszClsidPrefix)/sizeof(WCHAR)-2, CHARS_IN_GUID); + + /* note: this overwrites the opening curly bracket of the CLSID string generated above */ + memcpy(*ppszDisplayName, wszClsidPrefix, sizeof(wszClsidPrefix)-sizeof(WCHAR)); + + /* note: this overwrites the closing curly bracket of the CLSID string generated above */ + (*ppszDisplayName)[sizeof(wszClsidPrefix)/sizeof(WCHAR)-2+CHARS_IN_GUID-2] = ':'; + (*ppszDisplayName)[sizeof(wszClsidPrefix)/sizeof(WCHAR)-2+CHARS_IN_GUID-1] = '\0'; + + TRACE("string is %s\n", debugstr_w(*ppszDisplayName)); + return S_OK; +} + +/****************************************************************************** + * ClassMoniker_ParseDisplayName + ******************************************************************************/ +static HRESULT WINAPI ClassMoniker_ParseDisplayName(IMoniker* iface, + IBindCtx* pbc, + IMoniker* pmkToLeft, + LPOLESTR pszDisplayName, + ULONG* pchEaten, + IMoniker** ppmkOut) +{ + FIXME("(%p, %p, %s, %p, %p)\n", pbc, pmkToLeft, debugstr_w(pszDisplayName), pchEaten, ppmkOut); + return E_NOTIMPL; +} + +/****************************************************************************** + * ClassMoniker_IsSystemMoniker + ******************************************************************************/ +static HRESULT WINAPI ClassMoniker_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys) +{ + TRACE("(%p,%p)\n",iface,pwdMksys); + + if (!pwdMksys) + return E_POINTER; + + *pwdMksys = MKSYS_CLASSMONIKER; + + return S_OK; +} + +/******************************************************************************* + * ClassMonikerIROTData_QueryInterface + *******************************************************************************/ +static HRESULT WINAPI ClassMonikerROTData_QueryInterface(IROTData *iface,REFIID riid,VOID** ppvObject) +{ + + IMoniker *This = impl_from_IROTData(iface); + + TRACE("(%p,%p,%p)\n",iface,riid,ppvObject); + + return ClassMoniker_QueryInterface(This, riid, ppvObject); +} + +/*********************************************************************** + * ClassMonikerIROTData_AddRef + */ +static ULONG WINAPI ClassMonikerROTData_AddRef(IROTData *iface) +{ + IMoniker *This = impl_from_IROTData(iface); + + TRACE("(%p)\n",iface); + + return ClassMoniker_AddRef(This); +} + +/*********************************************************************** + * ClassMonikerIROTData_Release + */ +static ULONG WINAPI ClassMonikerROTData_Release(IROTData* iface) +{ + IMoniker *This = impl_from_IROTData(iface); + + TRACE("(%p)\n",iface); + + return ClassMoniker_Release(This); +} + +/****************************************************************************** + * ClassMonikerIROTData_GetComparaisonData + ******************************************************************************/ +static HRESULT WINAPI ClassMonikerROTData_GetComparaisonData(IROTData* iface, + BYTE* pbData, + ULONG cbMax, + ULONG* pcbData) +{ + ClassMoniker *This = (ClassMoniker *)impl_from_IROTData(iface); + + TRACE("(%p, %u, %p)\n", pbData, cbMax, pcbData); + + *pcbData = 2*sizeof(CLSID); + if (cbMax < *pcbData) + return E_OUTOFMEMORY; + + /* write CLSID of the moniker */ + memcpy(pbData, &CLSID_ClassMoniker, sizeof(CLSID)); + /* write CLSID the moniker represents */ + memcpy(pbData+sizeof(CLSID), &This->clsid, sizeof(CLSID)); + + return S_OK; +} + +/********************************************************************************/ +/* Virtual function table for the ClassMoniker class which include IPersist,*/ +/* IPersistStream and IMoniker functions. */ +static const IMonikerVtbl ClassMonikerVtbl = +{ + ClassMoniker_QueryInterface, + ClassMoniker_AddRef, + ClassMoniker_Release, + ClassMoniker_GetClassID, + ClassMoniker_IsDirty, + ClassMoniker_Load, + ClassMoniker_Save, + ClassMoniker_GetSizeMax, + ClassMoniker_BindToObject, + ClassMoniker_BindToStorage, + ClassMoniker_Reduce, + ClassMoniker_ComposeWith, + ClassMoniker_Enum, + ClassMoniker_IsEqual, + ClassMoniker_Hash, + ClassMoniker_IsRunning, + ClassMoniker_GetTimeOfLastChange, + ClassMoniker_Inverse, + ClassMoniker_CommonPrefixWith, + ClassMoniker_RelativePathTo, + ClassMoniker_GetDisplayName, + ClassMoniker_ParseDisplayName, + ClassMoniker_IsSystemMoniker +}; + +/********************************************************************************/ +/* Virtual function table for the IROTData class. */ +static const IROTDataVtbl ROTDataVtbl = +{ + ClassMonikerROTData_QueryInterface, + ClassMonikerROTData_AddRef, + ClassMonikerROTData_Release, + ClassMonikerROTData_GetComparaisonData +}; + +/****************************************************************************** + * ClassMoniker_Construct (local function) + *******************************************************************************/ +static HRESULT WINAPI ClassMoniker_Construct(ClassMoniker* This, REFCLSID rclsid) +{ + TRACE("(%p,%s)\n",This,debugstr_guid(rclsid)); + + /* Initialize the virtual function table. */ + This->lpVtbl = &ClassMonikerVtbl; + This->lpVtblRotData = &ROTDataVtbl; + This->ref = 0; + This->clsid = *rclsid; + This->pMarshal = NULL; + + return S_OK; +} + +/****************************************************************************** + * CreateClassMoniker [OLE32.@] + ******************************************************************************/ +HRESULT WINAPI CreateClassMoniker(REFCLSID rclsid, IMoniker **ppmk) +{ + ClassMoniker* newClassMoniker; + HRESULT hr; + + TRACE("(%s,%p)\n", debugstr_guid(rclsid), ppmk); + + newClassMoniker = HeapAlloc(GetProcessHeap(), 0, sizeof(ClassMoniker)); + + if (!newClassMoniker) + return STG_E_INSUFFICIENTMEMORY; + + hr = ClassMoniker_Construct(newClassMoniker, rclsid); + + if (FAILED(hr)) + { + HeapFree(GetProcessHeap(), 0, newClassMoniker); + return hr; + } + + return ClassMoniker_QueryInterface((IMoniker *)newClassMoniker, &IID_IMoniker, (void**)ppmk); +} + +HRESULT ClassMoniker_CreateFromDisplayName(LPBC pbc, LPCOLESTR szDisplayName, + LPDWORD pchEaten, LPMONIKER *ppmk) +{ + HRESULT hr; + LPCWSTR s = strchrW(szDisplayName, ':'); + LPCWSTR end; + CLSID clsid; + BYTE table[256]; + int i; + + if (!s) + return MK_E_SYNTAX; + + s++; + + for (end = s; *end && (*end != ':'); end++) + ; + + TRACE("parsing %s\n", debugstr_wn(s, end - s)); + + /* validate the CLSID string */ + if (s[0] == '{') + { + if ((end - s != 38) || (s[37] != '}')) + return MK_E_SYNTAX; + s++; + } + else + { + if (end - s != 36) + return MK_E_SYNTAX; + } + + for (i=0; i<36; i++) + { + if ((i == 8)||(i == 13)||(i == 18)||(i == 23)) + { + if (s[i] != '-') + return MK_E_SYNTAX; + continue; + } + if (!(((s[i] >= '0') && (s[i] <= '9')) || + ((s[i] >= 'a') && (s[i] <= 'f')) || + ((s[i] >= 'A') && (s[i] <= 'F')))) + return MK_E_SYNTAX; + } + + /* quick lookup table */ + memset(table, 0, 256); + + for (i = 0; i < 10; i++) + table['0' + i] = i; + for (i = 0; i < 6; i++) + { + table['A' + i] = i+10; + table['a' + i] = i+10; + } + + /* in form XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX */ + + clsid.Data1 = (table[s[0]] << 28 | table[s[1]] << 24 | table[s[2]] << 20 | table[s[3]] << 16 | + table[s[4]] << 12 | table[s[5]] << 8 | table[s[6]] << 4 | table[s[7]]); + clsid.Data2 = table[s[9]] << 12 | table[s[10]] << 8 | table[s[11]] << 4 | table[s[12]]; + clsid.Data3 = table[s[14]] << 12 | table[s[15]] << 8 | table[s[16]] << 4 | table[s[17]]; + + /* these are just sequential bytes */ + clsid.Data4[0] = table[s[19]] << 4 | table[s[20]]; + clsid.Data4[1] = table[s[21]] << 4 | table[s[22]]; + clsid.Data4[2] = table[s[24]] << 4 | table[s[25]]; + clsid.Data4[3] = table[s[26]] << 4 | table[s[27]]; + clsid.Data4[4] = table[s[28]] << 4 | table[s[29]]; + clsid.Data4[5] = table[s[30]] << 4 | table[s[31]]; + clsid.Data4[6] = table[s[32]] << 4 | table[s[33]]; + clsid.Data4[7] = table[s[34]] << 4 | table[s[35]]; + + hr = CreateClassMoniker(&clsid, ppmk); + if (SUCCEEDED(hr)) + *pchEaten = (*end == ':' ? end + 1 : end) - szDisplayName; + return hr; +} + +static HRESULT WINAPI ClassMonikerCF_QueryInterface(LPCLASSFACTORY iface, + REFIID riid, LPVOID *ppv) +{ + *ppv = NULL; + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory)) + { + *ppv = iface; + IUnknown_AddRef(iface); + return S_OK; + } + return E_NOINTERFACE; +} + +static ULONG WINAPI ClassMonikerCF_AddRef(LPCLASSFACTORY iface) +{ + return 2; /* non-heap based object */ +} + +static ULONG WINAPI ClassMonikerCF_Release(LPCLASSFACTORY iface) +{ + return 1; /* non-heap based object */ +} + +static HRESULT WINAPI ClassMonikerCF_CreateInstance(LPCLASSFACTORY iface, + LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv) +{ + HRESULT hr; + IMoniker *pmk; + + TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv); + + *ppv = NULL; + + if (pUnk) + return CLASS_E_NOAGGREGATION; + + hr = CreateClassMoniker(&CLSID_NULL, &pmk); + if (FAILED(hr)) return hr; + + hr = IMoniker_QueryInterface(pmk, riid, ppv); + IMoniker_Release(pmk); + + return hr; +} + +static HRESULT WINAPI ClassMonikerCF_LockServer(LPCLASSFACTORY iface, BOOL fLock) +{ + FIXME("(%d), stub!\n",fLock); + return S_OK; +} + +static const IClassFactoryVtbl ClassMonikerCFVtbl = +{ + ClassMonikerCF_QueryInterface, + ClassMonikerCF_AddRef, + ClassMonikerCF_Release, + ClassMonikerCF_CreateInstance, + ClassMonikerCF_LockServer +}; +static const IClassFactoryVtbl *ClassMonikerCF = &ClassMonikerCFVtbl; + +HRESULT ClassMonikerCF_Create(REFIID riid, LPVOID *ppv) +{ + return IClassFactory_QueryInterface((IClassFactory *)&ClassMonikerCF, riid, ppv); +} diff --git a/reactos/dll/win32/ole32/clipboard.c b/reactos/dll/win32/ole32/clipboard.c index 61c9441a0b8..89ecfd58bc1 100644 --- a/reactos/dll/win32/ole32/clipboard.c +++ b/reactos/dll/win32/ole32/clipboard.c @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * NOTES: * This file contains the implementation for the OLE Clipboard and its @@ -78,12 +78,7 @@ #include "storage32.h" -#define HANDLE_ERROR(err) { hr = err; TRACE("(HRESULT=%lx)\n", (HRESULT)err); goto CLEANUP; } - -/* For CoGetMalloc (MEMCTX_TASK is currently ignored) */ -#ifndef MEMCTX_TASK -# define MEMCTX_TASK -1 -#endif +#define HANDLE_ERROR(err) { hr = err; TRACE("(HRESULT=%x)\n", (HRESULT)err); goto CLEANUP; } WINE_DEFAULT_DEBUG_CHANNEL(ole); @@ -178,7 +173,7 @@ static OLEClipbrd* OLEClipbrd_Construct(void); static void OLEClipbrd_Destroy(OLEClipbrd* ptrToDestroy); static HWND OLEClipbrd_CreateWindow(void); static void OLEClipbrd_DestroyWindow(HWND hwnd); -LRESULT CALLBACK OLEClipbrd_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); +static LRESULT CALLBACK OLEClipbrd_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); static HRESULT OLEClipbrd_RenderFormat( IDataObject *pIDataObject, LPFORMATETC pFormatetc ); static HGLOBAL OLEClipbrd_GlobalDupMem( HGLOBAL hGlobalSrc ); @@ -283,7 +278,7 @@ static const IEnumFORMATETCVtbl efvt = /* * Name of our registered OLE clipboard window class */ -CHAR OLEClipbrd_WNDCLASS[] = "CLIPBRDWNDCLASS"; +static const CHAR OLEClipbrd_WNDCLASS[] = "CLIPBRDWNDCLASS"; /* * If we need to store state info we can store it here. @@ -487,7 +482,7 @@ HRESULT WINAPI OleGetClipboard(IDataObject** ppDataObj) * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL * back to TYMED_IStorage. */ -HRESULT WINAPI OleFlushClipboard() +HRESULT WINAPI OleFlushClipboard(void) { IEnumFORMATETC* penumFormatetc = NULL; FORMATETC rgelt; @@ -577,7 +572,7 @@ CLEANUP: /*********************************************************************** * OleIsCurrentClipboard [OLE32.@] */ -HRESULT WINAPI OleIsCurrentClipboard ( IDataObject *pDataObject) +HRESULT WINAPI OleIsCurrentClipboard(IDataObject *pDataObject) { TRACE("()\n"); /* @@ -638,7 +633,7 @@ void OLEClipbrd_UnInitialize(void) /********************************************************* * Construct the OLEClipbrd class. */ -static OLEClipbrd* OLEClipbrd_Construct() +static OLEClipbrd* OLEClipbrd_Construct(void) { OLEClipbrd* newObject = NULL; HGLOBAL hNewObject = 0; @@ -711,7 +706,7 @@ static void OLEClipbrd_Destroy(OLEClipbrd* ptrToDestroy) * OLEClipbrd_CreateWindow() * Create the clipboard window */ -static HWND OLEClipbrd_CreateWindow() +static HWND OLEClipbrd_CreateWindow(void) { HWND hwnd = 0; WNDCLASSEXA wcex; @@ -776,7 +771,7 @@ static void OLEClipbrd_DestroyWindow(HWND hwnd) * has been placed in the clipboard via OleSetClipboard(). * i.e. Only when OLE owns the windows clipboard. */ -LRESULT CALLBACK OLEClipbrd_WndProc +static LRESULT CALLBACK OLEClipbrd_WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) @@ -919,7 +914,8 @@ static HRESULT OLEClipbrd_RenderFormat(IDataObject *pIDataObject, LPFORMATETC pF ILockBytes *ptrILockBytes = 0; HGLOBAL hStorage = 0; - GetClipboardFormatNameA(pFormatetc->cfFormat, szFmtName, MAX_CLIPFORMAT_NAME); + if (!GetClipboardFormatNameA(pFormatetc->cfFormat, szFmtName, MAX_CLIPFORMAT_NAME)) + szFmtName[0] = '\0'; /* If embed source */ if (!strcmp(szFmtName, CF_EMBEDSOURCE)) @@ -935,7 +931,7 @@ static HRESULT OLEClipbrd_RenderFormat(IDataObject *pIDataObject, LPFORMATETC pF if (FAILED(hr = IDataObject_GetDataHere(theOleClipboard->pIDataObjectSrc, pFormatetc, &std))) { - WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%lx)\n", hr); + WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr); GlobalFree(hStorage); return hr; } @@ -1017,7 +1013,7 @@ static HRESULT OLEClipbrd_RenderFormat(IDataObject *pIDataObject, LPFORMATETC pF { if (FAILED(hr = IDataObject_GetData(pIDataObject, pFormatetc, &std))) { - WARN("() : IDataObject_GetData failed to render clipboard data! (%lx)\n", hr); + WARN("() : IDataObject_GetData failed to render clipboard data! (%x)\n", hr); GlobalFree(hStorage); return hr; } @@ -1159,7 +1155,7 @@ static ULONG WINAPI OLEClipbrd_IDataObject_AddRef( */ OLEClipbrd *This = (OLEClipbrd *)iface; - TRACE("(%p)->(count=%lu)\n",This, This->ref); + TRACE("(%p)->(count=%u)\n",This, This->ref); return InterlockedIncrement(&This->ref); @@ -1179,7 +1175,7 @@ static ULONG WINAPI OLEClipbrd_IDataObject_Release( OLEClipbrd *This = (OLEClipbrd *)iface; ULONG ref; - TRACE("(%p)->(count=%lu)\n",This, This->ref); + TRACE("(%p)->(count=%u)\n",This, This->ref); /* * Decrease the reference count on this object. @@ -1411,7 +1407,7 @@ static HRESULT WINAPI OLEClipbrd_IDataObject_EnumFormatEtc( */ OLEClipbrd *This = (OLEClipbrd *)iface; - TRACE("(%p, %lx, %p)\n", iface, dwDirection, ppenumFormatEtc); + TRACE("(%p, %x, %p)\n", iface, dwDirection, ppenumFormatEtc); /* * If we have a data source placed on the clipboard (via OleSetClipboard) @@ -1559,7 +1555,7 @@ static HRESULT WINAPI OLEClipbrd_IDataObject_EnumDAdvise( * NOTE: this does not AddRef the interface. */ -LPENUMFORMATETC OLEClipbrd_IEnumFORMATETC_Construct(UINT cfmt, const FORMATETC afmt[], +static LPENUMFORMATETC OLEClipbrd_IEnumFORMATETC_Construct(UINT cfmt, const FORMATETC afmt[], LPUNKNOWN pUnkDataObj) { IEnumFORMATETCImpl* ef; @@ -1642,7 +1638,7 @@ static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface) { IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface; - TRACE("(%p)->(count=%lu)\n",This, This->ref); + TRACE("(%p)->(count=%u)\n",This, This->ref); if (This->pUnkDataObj) IUnknown_AddRef(This->pUnkDataObj); @@ -1661,7 +1657,7 @@ static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface) LPMALLOC pIMalloc; ULONG ref; - TRACE("(%p)->(count=%lu)\n",This, This->ref); + TRACE("(%p)->(count=%u)\n",This, This->ref); if (This->pUnkDataObj) IUnknown_Release(This->pUnkDataObj); /* Release parent data object */ @@ -1728,7 +1724,7 @@ static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt) { IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface; - TRACE("(%p)->(num=%lu)\n", This, celt); + TRACE("(%p)->(num=%u)\n", This, celt); This->posFmt += celt; if (This->posFmt > This->countFmt) diff --git a/reactos/dll/win32/ole32/compobj.c b/reactos/dll/win32/ole32/compobj.c index b2cf72b07cb..af43074aa26 100644 --- a/reactos/dll/win32/ole32/compobj.c +++ b/reactos/dll/win32/ole32/compobj.c @@ -7,6 +7,7 @@ * Copyright 1999 Sylvain St-Germain * Copyright 2002 Marcus Meissner * Copyright 2004 Mike Hearn + * Copyright 2005-2006 Robert Shearman (for CodeWeavers) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,7 +21,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * Note * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED @@ -33,18 +34,13 @@ * - Implement the OXID resolver so we don't need magic endpoint names for * clients and servers to meet up * - * - Pump the message loop during RPC calls. - * - Call IMessageFilter functions. - * * - Make all ole interface marshaling use NDR to be wire compatible with * native DCOM - * - Use & interpret ORPCTHIS & ORPCTHAT. * */ #include "config.h" -#include #include #include #include @@ -82,10 +78,10 @@ HINSTANCE OLE32_hInstance = 0; /* FIXME: make static ... */ static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk); static void COM_RevokeAllClasses(void); +static HRESULT get_inproc_class_object(HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv); -const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} }; - -APARTMENT *MTA; /* protected by csApartment */ +static APARTMENT *MTA; /* protected by csApartment */ +static APARTMENT *MainApartment; /* the first STA apartment */ static struct list apts = LIST_INIT( apts ); /* protected by csApartment */ static CRITICAL_SECTION csApartment; @@ -97,12 +93,21 @@ static CRITICAL_SECTION_DEBUG critsect_debug = }; static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 }; +struct registered_psclsid +{ + struct list entry; + IID iid; + CLSID clsid; +}; + /* * This lock count counts the number of times CoInitialize is called. It is * decreased every time CoUninitialize is called. When it hits 0, the COM * libraries are freed */ static LONG s_COMLockCount = 0; +/* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */ +static LONG s_COMServerProcessReferences = 0; /* * This linked list contains the list of registered class objects. These @@ -114,16 +119,17 @@ static LONG s_COMLockCount = 0; */ typedef struct tagRegisteredClass { + struct list entry; CLSID classIdentifier; LPUNKNOWN classObject; DWORD runContext; DWORD connectFlags; DWORD dwCookie; LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */ - struct tagRegisteredClass* nextClass; + void *RpcRegistration; } RegisteredClass; -static RegisteredClass* firstRegisteredClass = NULL; +static struct list RegisteredClassList = LIST_INIT(RegisteredClassList); static CRITICAL_SECTION csRegisteredClassList; static CRITICAL_SECTION_DEBUG class_cs_debug = @@ -145,12 +151,20 @@ static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, * next unload-call but not before 600 sec. */ -typedef struct tagOpenDll { - HINSTANCE hLibrary; - struct tagOpenDll *next; +typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv); +typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void); + +typedef struct tagOpenDll +{ + LONG refs; + LPWSTR library_name; + HANDLE library; + DllGetClassObjectFunc DllGetClassObject; + DllCanUnloadNowFunc DllCanUnloadNow; + struct list entry; } OpenDll; -static OpenDll *openDllList = NULL; /* linked list of open dlls */ +static struct list openDllList = LIST_INIT(openDllList); static CRITICAL_SECTION csOpenDllList; static CRITICAL_SECTION_DEBUG dll_cs_debug = @@ -161,12 +175,23 @@ static CRITICAL_SECTION_DEBUG dll_cs_debug = }; static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 }; +struct apartment_loaded_dll +{ + struct list entry; + OpenDll *dll; +}; + static const WCHAR wszAptWinClass[] = {'O','l','e','M','a','i','n','T','h','r','e','a','d','W','n','d','C','l','a','s','s',' ', '0','x','#','#','#','#','#','#','#','#',' ',0}; static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); +static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath, + REFCLSID rclsid, REFIID riid, void **ppv); -static void COMPOBJ_DLLList_Add(HANDLE hLibrary); -static void COMPOBJ_DllList_FreeUnused(int Timeout); +static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret); +static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name); +static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry); + +static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen); static void COMPOBJ_InitProcess( void ) { @@ -211,18 +236,20 @@ static void COM_TlsDestroy(void) */ /* allocates memory and fills in the necessary fields for a new apartment - * object */ + * object. must be called inside apartment cs */ static APARTMENT *apartment_construct(DWORD model) { APARTMENT *apt; - TRACE("creating new apartment, model=%ld\n", model); + TRACE("creating new apartment, model=%d\n", model); apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt)); apt->tid = GetCurrentThreadId(); list_init(&apt->proxies); list_init(&apt->stubmgrs); + list_init(&apt->psclsids); + list_init(&apt->loaded_dlls); apt->ipidc = 0; apt->refs = 1; apt->remunk_exported = FALSE; @@ -230,29 +257,22 @@ static APARTMENT *apartment_construct(DWORD model) InitializeCriticalSection(&apt->cs); DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment"); - apt->model = model; + apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED); - if (model & COINIT_APARTMENTTHREADED) - { - /* FIXME: should be randomly generated by in an RPC call to rpcss */ - apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId(); - apt->win = CreateWindowW(wszAptWinClass, NULL, 0, - 0, 0, 0, 0, - 0, 0, OLE32_hInstance, NULL); - } - else + if (apt->multi_threaded) { /* FIXME: should be randomly generated by in an RPC call to rpcss */ apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe; } + else + { + /* FIXME: should be randomly generated by in an RPC call to rpcss */ + apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId(); + } TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid)); - /* the locking here is not currently needed for the MTA case, but it - * doesn't hurt and makes the code simpler */ - EnterCriticalSection(&csApartment); list_add_head(&apts, &apt->entry); - LeaveCriticalSection(&csApartment); return apt; } @@ -268,8 +288,17 @@ static APARTMENT *apartment_get_or_create(DWORD model) { if (model & COINIT_APARTMENTTHREADED) { + EnterCriticalSection(&csApartment); + apt = apartment_construct(model); - COM_CurrentInfo()->apt = apt; + if (!MainApartment) + { + MainApartment = apt; + apt->main = TRUE; + TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid)); + } + + LeaveCriticalSection(&csApartment); } else { @@ -287,19 +316,24 @@ static APARTMENT *apartment_get_or_create(DWORD model) MTA = apartment_construct(model); apt = MTA; - COM_CurrentInfo()->apt = apt; LeaveCriticalSection(&csApartment); } + COM_CurrentInfo()->apt = apt; } return apt; } +static inline BOOL apartment_is_model(APARTMENT *apt, DWORD model) +{ + return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED)); +} + DWORD apartment_addref(struct apartment *apt) { DWORD refs = InterlockedIncrement(&apt->refs); - TRACE("%s: before = %ld\n", wine_dbgstr_longlong(apt->oxid), refs - 1); + TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1); return refs; } @@ -310,11 +344,12 @@ DWORD apartment_release(struct apartment *apt) EnterCriticalSection(&csApartment); ret = InterlockedDecrement(&apt->refs); - TRACE("%s: after = %ld\n", wine_dbgstr_longlong(apt->oxid), ret); + TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret); /* destruction stuff that needs to happen under csApartment CS */ if (ret == 0) { if (apt == MTA) MTA = NULL; + else if (apt == MainApartment) MainApartment = NULL; list_remove(&apt->entry); } @@ -344,6 +379,15 @@ DWORD apartment_release(struct apartment *apt) stub_manager_int_release(stubmgr); } + LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->psclsids) + { + struct registered_psclsid *registered_psclsid = + LIST_ENTRY(cursor, struct registered_psclsid, entry); + + list_remove(®istered_psclsid->entry); + HeapFree(GetProcessHeap(), 0, registered_psclsid); + } + /* if this assert fires, then another thread took a reference to a * stub manager without taking a reference to the containing * apartment, which it must do. */ @@ -351,6 +395,14 @@ DWORD apartment_release(struct apartment *apt) if (apt->filter) IUnknown_Release(apt->filter); + while ((cursor = list_head(&apt->loaded_dlls))) + { + struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry); + COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll); + list_remove(cursor); + HeapFree(GetProcessHeap(), 0, apartment_loaded_dll); + } + DEBUG_CLEAR_CRITSEC_NAME(&apt->cs); DeleteCriticalSection(&apt->cs); @@ -410,6 +462,75 @@ APARTMENT *apartment_findfromtid(DWORD tid) return result; } +/* gets an apartment which has a given type. The caller must + * release the reference from the apartment as soon as the apartment pointer + * is no longer required. */ +static APARTMENT *apartment_findfromtype(BOOL multi_threaded, BOOL main_apartment) +{ + APARTMENT *result = NULL; + struct apartment *apt; + + EnterCriticalSection(&csApartment); + + if (!multi_threaded && main_apartment) + { + result = MainApartment; + if (result) apartment_addref(result); + LeaveCriticalSection(&csApartment); + return result; + } + + LIST_FOR_EACH_ENTRY( apt, &apts, struct apartment, entry ) + { + if (apt->multi_threaded == multi_threaded) + { + result = apt; + apartment_addref(result); + break; + } + } + LeaveCriticalSection(&csApartment); + + return result; +} + +struct host_object_params +{ + HKEY hkeydll; + CLSID clsid; /* clsid of object to marshal */ + IID iid; /* interface to marshal */ + IStream *stream; /* stream that the object will be marshaled into */ +}; + +static HRESULT apartment_hostobject(struct apartment *apt, + const struct host_object_params *params) +{ + IUnknown *object; + HRESULT hr; + static const LARGE_INTEGER llZero; + WCHAR dllpath[MAX_PATH+1]; + + TRACE("\n"); + + if (COM_RegReadPath(params->hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS) + { + /* failure: CLSID is not found in registry */ + WARN("class %s not registered inproc\n", debugstr_guid(¶ms->clsid)); + return REGDB_E_CLASSNOTREG; + } + + hr = apartment_getclassobject(apt, dllpath, ¶ms->clsid, ¶ms->iid, (void **)&object); + if (FAILED(hr)) + return hr; + + hr = CoMarshalInterface(params->stream, ¶ms->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); + if (FAILED(hr)) + IUnknown_Release(object); + IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL); + + return hr; +} + static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) @@ -417,84 +538,223 @@ static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LP case DM_EXECUTERPC: RPC_ExecuteCall((struct dispatch_params *)lParam); return 0; + case DM_HOSTOBJECT: + return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam); default: return DefWindowProcW(hWnd, msg, wParam, lParam); } } -/***************************************************************************** - * This section contains OpenDllList implemantation - */ - -static void COMPOBJ_DLLList_Add(HANDLE hLibrary) +HRESULT apartment_createwindowifneeded(struct apartment *apt) { - OpenDll *ptr; - OpenDll *tmp; + if (apt->multi_threaded) + return S_OK; - TRACE("\n"); - - EnterCriticalSection( &csOpenDllList ); - - if (openDllList == NULL) { - /* empty list -- add first node */ - openDllList = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll)); - openDllList->hLibrary=hLibrary; - openDllList->next = NULL; - } else { - /* search for this dll */ - int found = FALSE; - for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) { - if (ptr->hLibrary == hLibrary) { - found = TRUE; - break; - } + if (!apt->win) + { + HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0, + 0, 0, 0, 0, + 0, 0, OLE32_hInstance, NULL); + if (!hwnd) + { + ERR("CreateWindow failed with error %d\n", GetLastError()); + return HRESULT_FROM_WIN32(GetLastError()); } - if (!found) { - /* dll not found, add it */ - tmp = openDllList; - openDllList = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll)); - openDllList->hLibrary = hLibrary; - openDllList->next = tmp; - } + if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL)) + /* someone beat us to it */ + DestroyWindow(hwnd); } - LeaveCriticalSection( &csOpenDllList ); + return S_OK; } -static void COMPOBJ_DllList_FreeUnused(int Timeout) +HWND apartment_getwindow(struct apartment *apt) { - OpenDll *curr, *next, *prev = NULL; - typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void); + assert(!apt->multi_threaded); + return apt->win; +} + +void apartment_joinmta(void) +{ + apartment_addref(MTA); + COM_CurrentInfo()->apt = MTA; +} + +static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath, + REFCLSID rclsid, REFIID riid, void **ppv) +{ + HRESULT hr = S_OK; + BOOL found = FALSE; + struct apartment_loaded_dll *apartment_loaded_dll; + + EnterCriticalSection(&apt->cs); + + LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry) + if (!strcmpiW(dllpath, apartment_loaded_dll->dll->library_name)) + { + TRACE("found %s already loaded\n", debugstr_w(dllpath)); + found = TRUE; + break; + } + + if (!found) + { + apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll)); + if (!apartment_loaded_dll) + hr = E_OUTOFMEMORY; + if (SUCCEEDED(hr)) + { + hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll ); + if (FAILED(hr)) + HeapFree(GetProcessHeap(), 0, apartment_loaded_dll); + } + if (SUCCEEDED(hr)) + { + TRACE("added new loaded dll %s\n", debugstr_w(dllpath)); + list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry); + } + } + + LeaveCriticalSection(&apt->cs); + + if (SUCCEEDED(hr)) + { + TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject); + /* OK: get the ClassObject */ + hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv); + + if (hr != S_OK) + ERR("DllGetClassObject returned error 0x%08x\n", hr); + } + + return hr; +} + +static void apartment_freeunusedlibraries(struct apartment *apt) +{ + struct apartment_loaded_dll *entry, *next; + EnterCriticalSection(&apt->cs); + LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry) + { + if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK)) + { + list_remove(&entry->entry); + COMPOBJ_DllList_ReleaseRef(entry->dll); + HeapFree(GetProcessHeap(), 0, entry); + } + } + LeaveCriticalSection(&apt->cs); +} + +/***************************************************************************** + * This section contains OpenDllList implementation + */ + +/* caller must ensure that library_name is not already in the open dll list */ +static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret) +{ + OpenDll *entry; + int len; + HRESULT hr = S_OK; + HANDLE hLibrary; DllCanUnloadNowFunc DllCanUnloadNow; + DllGetClassObjectFunc DllGetClassObject; TRACE("\n"); + *ret = COMPOBJ_DllList_Get(library_name); + if (*ret) return S_OK; + + /* do this outside the csOpenDllList to avoid creating a lock dependency on + * the loader lock */ + hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH); + if (!hLibrary) + { + ERR("couldn't load in-process dll %s\n", debugstr_w(library_name)); + /* failure: DLL could not be loaded */ + return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */ + } + + DllCanUnloadNow = GetProcAddress(hLibrary, "DllCanUnloadNow"); + /* Note: failing to find DllCanUnloadNow is not a failure */ + DllGetClassObject = GetProcAddress(hLibrary, "DllGetClassObject"); + if (!DllGetClassObject) + { + /* failure: the dll did not export DllGetClassObject */ + ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name)); + FreeLibrary(hLibrary); + return CO_E_DLLNOTFOUND; + } + EnterCriticalSection( &csOpenDllList ); - for (curr = openDllList; curr != NULL; ) { - DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow"); - - if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) { - next = curr->next; - - TRACE("freeing %p\n", curr->hLibrary); - FreeLibrary(curr->hLibrary); - - HeapFree(GetProcessHeap(), 0, curr); - if (curr == openDllList) { - openDllList = next; - } else { - prev->next = next; - } - - curr = next; - } else { - prev = curr; - curr = curr->next; - } + *ret = COMPOBJ_DllList_Get(library_name); + if (*ret) + { + /* another caller to this function already added the dll while we + * weren't in the critical section */ + FreeLibrary(hLibrary); + } + else + { + len = strlenW(library_name); + entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll)); + if (entry) + entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR)); + if (entry && entry->library_name) + { + memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR)); + entry->library = hLibrary; + entry->refs = 1; + entry->DllCanUnloadNow = DllCanUnloadNow; + entry->DllGetClassObject = DllGetClassObject; + list_add_tail(&openDllList, &entry->entry); + } + else + { + hr = E_OUTOFMEMORY; + FreeLibrary(hLibrary); + } + *ret = entry; } LeaveCriticalSection( &csOpenDllList ); + + return hr; +} + +static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name) +{ + OpenDll *ptr; + OpenDll *ret = NULL; + EnterCriticalSection(&csOpenDllList); + LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry) + { + if (!strcmpiW(library_name, ptr->library_name) && + (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */) + { + ret = ptr; + break; + } + } + LeaveCriticalSection(&csOpenDllList); + return ret; +} + +static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry) +{ + if (!InterlockedDecrement(&entry->refs)) + { + EnterCriticalSection(&csOpenDllList); + list_remove(&entry->entry); + LeaveCriticalSection(&csOpenDllList); + + TRACE("freeing %p\n", entry->library); + FreeLibrary(entry->library); + + HeapFree(GetProcessHeap(), 0, entry->library_name); + HeapFree(GetProcessHeap(), 0, entry); + } } /****************************************************************************** @@ -557,7 +817,7 @@ HRESULT WINAPI CoInitialize(LPVOID lpReserved) * * The behavior used to set the IMalloc used for memory management is * obsolete. - * The dwCoInit parameter must specify of of the following apartment + * The dwCoInit parameter must specify one of the following apartment * threading models: *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA). *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA). @@ -602,11 +862,13 @@ HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit) apt = apartment_get_or_create(dwCoInit); if (!apt) return E_OUTOFMEMORY; } - else if (dwCoInit != apt->model) + else if (!apartment_is_model(apt, dwCoInit)) { /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine code then we are probably using the wrong threading model to implement that API. */ - ERR("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit); + ERR("Attempt to change threading model of this apartment from %s to %s\n", + apt->multi_threaded ? "multi-threaded" : "apartment threaded", + dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded"); return RPC_E_CHANGED_MODE; } else @@ -710,7 +972,6 @@ void WINAPI CoUninitialize(void) /****************************************************************************** * CoDisconnectObject [OLE32.@] - * CoDisconnectObject [COMPOBJ.15] * * Disconnects all connections to this object from remote processes. Dispatches * pending RPCs while blocking new RPCs from occurring, and then calls @@ -736,7 +997,7 @@ HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved ) IMarshal *marshal; APARTMENT *apt; - TRACE("(%p, 0x%08lx)\n", lpUnk, reserved); + TRACE("(%p, 0x%08x)\n", lpUnk, reserved); hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal); if (hr == S_OK) @@ -795,31 +1056,23 @@ HRESULT WINAPI CoCreateGuid(GUID *pguid) * S_OK on success * CO_E_CLASSSTRING if idstr is not a valid CLSID * - * BUGS - * - * In Windows, if idstr is not a valid CLSID string then it gets - * treated as a ProgID. Wine currently doesn't do this. If idstr is - * NULL it's treated as an all-zero GUID. - * * SEE ALSO * StringFromCLSID */ -HRESULT WINAPI __CLSIDFromStringA(LPCSTR idstr, CLSID *id) +static HRESULT WINAPI __CLSIDFromString(LPCWSTR s, CLSID *id) { - const BYTE *s; int i; BYTE table[256]; - if (!idstr) { + if (!s) { memset( id, 0, sizeof (CLSID) ); return S_OK; } /* validate the CLSID string */ - if (strlen(idstr) != 38) + if (strlenW(s) != 38) return CO_E_CLASSSTRING; - s = (const BYTE *) idstr; if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}')) return CO_E_CLASSSTRING; @@ -831,7 +1084,7 @@ HRESULT WINAPI __CLSIDFromStringA(LPCSTR idstr, CLSID *id) return CO_E_CLASSSTRING; } - TRACE("%s -> %p\n", s, id); + TRACE("%s -> %p\n", debugstr_w(s), id); /* quick lookup table */ memset(table, 0, 256); @@ -868,14 +1121,12 @@ HRESULT WINAPI __CLSIDFromStringA(LPCSTR idstr, CLSID *id) HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id ) { - char xid[40]; HRESULT ret; - if (!WideCharToMultiByte( CP_ACP, 0, idstr, -1, xid, sizeof(xid), NULL, NULL )) - return CO_E_CLASSSTRING; + if (!id) + return E_INVALIDARG; - - ret = __CLSIDFromStringA(xid,id); + ret = __CLSIDFromString(idstr, id); if(ret != S_OK) { /* It appears a ProgID is also valid */ ret = CLSIDFromProgID(idstr, id); } @@ -887,7 +1138,7 @@ HRESULT WINE_StringFromCLSID( const CLSID *id, /* [in] GUID to be converted */ LPSTR idstr /* [out] pointer to buffer to contain converted guid */ ) { - static const char *hex = "0123456789ABCDEF"; + static const char hex[] = "0123456789ABCDEF"; char *s; int i; @@ -897,7 +1148,7 @@ HRESULT WINE_StringFromCLSID( return E_FAIL; } - sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-", + sprintf(idstr, "{%08X-%04X-%04X-%02X%02X-", id->Data1, id->Data2, id->Data3, id->Data4[0], id->Data4[1]); s = &idstr[25]; @@ -1010,6 +1261,43 @@ HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY return S_OK; } +/* open HKCR\\AppId\\{string form of appid clsid} key */ +HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey) +{ + static const WCHAR szAppId[] = { 'A','p','p','I','d',0 }; + static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 }; + DWORD res; + WCHAR buf[CHARS_IN_GUID]; + WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID]; + DWORD size; + HKEY hkey; + DWORD type; + HRESULT hr; + + /* read the AppID value under the class's key */ + hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey); + if (FAILED(hr)) + return hr; + + size = sizeof(buf); + res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size); + RegCloseKey(hkey); + if (res == ERROR_FILE_NOT_FOUND) + return REGDB_E_KEYMISSING; + else if (res != ERROR_SUCCESS || type!=REG_SZ) + return REGDB_E_READREGDB; + + strcpyW(keyname, szAppIdKey); + strcatW(keyname, buf); + res = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, access, subkey); + if (res == ERROR_FILE_NOT_FOUND) + return REGDB_E_KEYMISSING; + else if (res != ERROR_SUCCESS) + return REGDB_E_READREGDB; + + return S_OK; +} + /****************************************************************************** * ProgIDFromCLSID [OLE32.@] * @@ -1017,20 +1305,27 @@ HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY * * PARAMS * clsid [I] Class ID, as found in registry. - * lplpszProgID [O] Associated ProgID. + * ppszProgID [O] Associated ProgID. * * RETURNS * S_OK * E_OUTOFMEMORY * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID */ -HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *lplpszProgID) +HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID) { static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0}; HKEY hkey; HRESULT ret; LONG progidlen = 0; + if (!ppszProgID) + { + ERR("ppszProgId isn't optional\n"); + return E_INVALIDARG; + } + + *ppszProgID = NULL; ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey); if (FAILED(ret)) return ret; @@ -1040,10 +1335,10 @@ HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *lplpszProgID) if (ret == S_OK) { - *lplpszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR)); - if (*lplpszProgID) + *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR)); + if (*ppszProgID) { - if (RegQueryValueW(hkey, NULL, *lplpszProgID, &progidlen)) + if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen)) ret = REGDB_E_CLASSNOTREG; } else @@ -1061,25 +1356,36 @@ HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *lplpszProgID) * * PARAMS * progid [I] Unicode program ID, as found in registry. - * riid [O] Associated CLSID. + * clsid [O] Associated CLSID. * * RETURNS * Success: S_OK * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found. */ -HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID riid) +HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid) { static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 }; WCHAR buf2[CHARS_IN_GUID]; LONG buf2len = sizeof(buf2); HKEY xhkey; + WCHAR *buf; - WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) ); + if (!progid || !clsid) + { + ERR("neither progid (%p) nor clsid (%p) are optional\n", progid, clsid); + return E_INVALIDARG; + } + + /* initialise clsid in case of failure */ + memset(clsid, 0, sizeof(*clsid)); + + buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) ); strcpyW( buf, progid ); strcatW( buf, clsidW ); if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey)) { HeapFree(GetProcessHeap(),0,buf); + WARN("couldn't open key for ProgID %s\n", debugstr_w(progid)); return CO_E_CLASSSTRING; } HeapFree(GetProcessHeap(),0,buf); @@ -1087,10 +1393,11 @@ HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID riid) if (RegQueryValueW(xhkey,NULL,buf2,&buf2len)) { RegCloseKey(xhkey); + WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid)); return CO_E_CLASSSTRING; } RegCloseKey(xhkey); - return CLSIDFromString(buf2,riid); + return CLSIDFromString(buf2,clsid); } @@ -1123,11 +1430,12 @@ HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID riid) * * BUGS * - * We only search the registry, not ids registered with - * CoRegisterPSClsid. - * Also, native returns S_OK for interfaces with a key in HKCR\Interface, but + * Native returns S_OK for interfaces with a key in HKCR\Interface, but * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be * considered a bug in native unless an application depends on this (unlikely). + * + * SEE ALSO + * CoRegisterPSClsid. */ HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid) { @@ -1137,9 +1445,35 @@ HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid) WCHAR value[CHARS_IN_GUID]; LONG len; HKEY hkey; + APARTMENT *apt = COM_CurrentApt(); + struct registered_psclsid *registered_psclsid; TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid); + if (!apt) + { + ERR("apartment not initialised\n"); + return CO_E_NOTINITIALIZED; + } + + if (!pclsid) + { + ERR("pclsid isn't optional\n"); + return E_INVALIDARG; + } + + EnterCriticalSection(&apt->cs); + + LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry) + if (IsEqualIID(®istered_psclsid->iid, riid)) + { + *pclsid = registered_psclsid->clsid; + LeaveCriticalSection(&apt->cs); + return S_OK; + } + + LeaveCriticalSection(&apt->cs); + /* Interface\\{string form of riid}\\ProxyStubClsid32 */ strcpyW(path, wszInterface); StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID); @@ -1172,63 +1506,65 @@ HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid) return S_OK; } - - -/*********************************************************************** - * WriteClassStm (OLE32.@) +/***************************************************************************** + * CoRegisterPSClsid [OLE32.@] * - * Writes a CLSID to a stream. + * Register a proxy/stub CLSID for the given interface in the current process + * only. * * PARAMS - * pStm [I] Stream to write to. - * rclsid [I] CLSID to write. - * + * riid [I] Interface whose proxy/stub CLSID is to be registered. + * rclsid [I] CLSID of the proxy/stub. + * * RETURNS - * Success: S_OK. - * Failure: HRESULT code. + * Success: S_OK + * Failure: E_OUTOFMEMORY + * + * NOTES + * + * This function does not add anything to the registry and the effects are + * limited to the lifetime of the current process. + * + * SEE ALSO + * CoGetPSClsid. */ -HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid) +HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid) { - TRACE("(%p,%p)\n",pStm,rclsid); + APARTMENT *apt = COM_CurrentApt(); + struct registered_psclsid *registered_psclsid; - if (rclsid==NULL) - return E_INVALIDARG; + TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid)); - return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL); -} + if (!apt) + { + ERR("apartment not initialised\n"); + return CO_E_NOTINITIALIZED; + } -/*********************************************************************** - * ReadClassStm (OLE32.@) - * - * Reads a CLSID from a stream. - * - * PARAMS - * pStm [I] Stream to read from. - * rclsid [O] CLSID to read. - * - * RETURNS - * Success: S_OK. - * Failure: HRESULT code. - */ -HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid) -{ - ULONG nbByte; - HRESULT res; + EnterCriticalSection(&apt->cs); - TRACE("(%p,%p)\n",pStm,pclsid); + LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry) + if (IsEqualIID(®istered_psclsid->iid, riid)) + { + registered_psclsid->clsid = *rclsid; + LeaveCriticalSection(&apt->cs); + return S_OK; + } - if (pclsid==NULL) - return E_INVALIDARG; + registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid)); + if (!registered_psclsid) + { + LeaveCriticalSection(&apt->cs); + return E_OUTOFMEMORY; + } - res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte); + registered_psclsid->iid = *riid; + registered_psclsid->clsid = *rclsid; + list_add_head(&apt->psclsids, ®istered_psclsid->entry); - if (FAILED(res)) - return res; + LeaveCriticalSection(&apt->cs); - if (nbByte != sizeof(CLSID)) - return S_FALSE; - else - return S_OK; + return S_OK; } @@ -1251,32 +1587,23 @@ static HRESULT COM_GetRegisteredClassObject( LPUNKNOWN* ppUnk) { HRESULT hr = S_FALSE; - RegisteredClass* curClass; - - EnterCriticalSection( &csRegisteredClassList ); + RegisteredClass *curClass; /* * Sanity check */ assert(ppUnk!=0); - /* - * Iterate through the whole list and try to match the class ID. - */ - curClass = firstRegisteredClass; + EnterCriticalSection( &csRegisteredClassList ); - while (curClass != 0) + LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry) { /* - * Check if we have a match on the class ID. + * Check if we have a match on the class ID and context. */ - if (IsEqualGUID(&(curClass->classIdentifier), rclsid)) + if ((dwClsContext & curClass->runContext) && + IsEqualGUID(&(curClass->classIdentifier), rclsid)) { - /* - * Since we don't do out-of process or DCOM just right away, let's ignore the - * class context. - */ - /* * We have a match, return the pointer to the class object. */ @@ -1285,20 +1612,12 @@ static HRESULT COM_GetRegisteredClassObject( IUnknown_AddRef(curClass->classObject); hr = S_OK; - goto end; + break; } - - /* - * Step to the next class in the list. - */ - curClass = curClass->nextClass; } -end: LeaveCriticalSection( &csRegisteredClassList ); - /* - * If we get to here, we haven't found our class. - */ + return hr; } @@ -1339,7 +1658,7 @@ HRESULT WINAPI CoRegisterClassObject( LPUNKNOWN foundObject; HRESULT hr; - TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n", + TRACE("(%s,%p,0x%08x,0x%08x,%p)\n", debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister); if ( (lpdwRegister==0) || (pUnk==0) ) @@ -1353,6 +1672,11 @@ HRESULT WINAPI CoRegisterClassObject( *lpdwRegister = 0; + /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what + * differentiates the flag from REGCLS_MULTI_SEPARATE. */ + if (flags & REGCLS_MULTIPLEUSE) + dwClsContext |= CLSCTX_INPROC_SERVER; + /* * First, check if the class is already registered. * If it is, this should cause an error. @@ -1374,19 +1698,17 @@ HRESULT WINAPI CoRegisterClassObject( if ( newClass == NULL ) return E_OUTOFMEMORY; - EnterCriticalSection( &csRegisteredClassList ); - newClass->classIdentifier = *rclsid; newClass->runContext = dwClsContext; newClass->connectFlags = flags; newClass->pMarshaledData = NULL; + newClass->RpcRegistration = NULL; /* * Use the address of the chain node as the cookie since we are sure it's * unique. FIXME: not on 64-bit platforms. */ newClass->dwCookie = (DWORD)newClass; - newClass->nextClass = firstRegisteredClass; /* * Since we're making a copy of the object pointer, we have to increase its @@ -1395,7 +1717,8 @@ HRESULT WINAPI CoRegisterClassObject( newClass->classObject = pUnk; IUnknown_AddRef(newClass->classObject); - firstRegisteredClass = newClass; + EnterCriticalSection( &csRegisteredClassList ); + list_add_tail(&RegisteredClassList, &newClass->entry); LeaveCriticalSection( &csRegisteredClassList ); *lpdwRegister = newClass->dwCookie; @@ -1409,7 +1732,7 @@ HRESULT WINAPI CoRegisterClassObject( hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData); if (hr) { - FIXME("Failed to create stream on hglobal, %lx\n", hr); + FIXME("Failed to create stream on hglobal, %x\n", hr); IUnknown_Release(classfac); return hr; } @@ -1417,14 +1740,17 @@ HRESULT WINAPI CoRegisterClassObject( (LPVOID)classfac, MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG); if (hr) { - FIXME("CoMarshalInterface failed, %lx!\n",hr); + FIXME("CoMarshalInterface failed, %x!\n",hr); IUnknown_Release(classfac); return hr; } IUnknown_Release(classfac); - RPC_StartLocalServer(&newClass->classIdentifier, newClass->pMarshaledData); + hr = RPC_StartLocalServer(&newClass->classIdentifier, + newClass->pMarshaledData, + flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE), + &newClass->RpcRegistration); } return S_OK; } @@ -1448,30 +1774,23 @@ HRESULT WINAPI CoRevokeClassObject( DWORD dwRegister) { HRESULT hr = E_INVALIDARG; - RegisteredClass** prevClassLink; - RegisteredClass* curClass; + RegisteredClass *curClass; - TRACE("(%08lx)\n",dwRegister); + TRACE("(%08x)\n",dwRegister); EnterCriticalSection( &csRegisteredClassList ); - /* - * Iterate through the whole list and try to match the cookie. - */ - curClass = firstRegisteredClass; - prevClassLink = &firstRegisteredClass; - - while (curClass != 0) + LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry) { /* * Check if we have a match on the cookie. */ if (curClass->dwCookie == dwRegister) { - /* - * Remove the class from the chain. - */ - *prevClassLink = curClass->nextClass; + list_remove(&curClass->entry); + + if (curClass->runContext & CLSCTX_LOCAL_SERVER) + RPC_StopLocalServer(curClass->RpcRegistration); /* * Release the reference to the class object. @@ -1482,8 +1801,7 @@ HRESULT WINAPI CoRevokeClassObject( { LARGE_INTEGER zero; memset(&zero, 0, sizeof(zero)); - /* FIXME: stop local server thread */ - IStream_Seek(curClass->pMarshaledData, zero, SEEK_SET, NULL); + IStream_Seek(curClass->pMarshaledData, zero, STREAM_SEEK_SET, NULL); CoReleaseMarshalData(curClass->pMarshaledData); } @@ -1493,21 +1811,12 @@ HRESULT WINAPI CoRevokeClassObject( HeapFree(GetProcessHeap(), 0, curClass); hr = S_OK; - goto end; + break; } - - /* - * Step to the next class in the list. - */ - prevClassLink = &(curClass->nextClass); - curClass = curClass->nextClass; } -end: LeaveCriticalSection( &csRegisteredClassList ); - /* - * If we get to here, we haven't found our class. - */ + return hr; } @@ -1516,33 +1825,120 @@ end: * * Reads a registry value and expands it when necessary */ -HRESULT COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen) +static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen) { - HRESULT hres; + DWORD ret; HKEY key; DWORD keytype; WCHAR src[MAX_PATH]; DWORD dwLength = dstlen * sizeof(WCHAR); - if((hres = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) { - if( (hres = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) { + if((ret = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) { + if( (ret = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) { if (keytype == REG_EXPAND_SZ) { - if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) hres = ERROR_MORE_DATA; + if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA; } else { lstrcpynW(dst, src, dstlen); } } RegCloseKey (key); } - return hres; + return ret; +} + +static void get_threading_model(HKEY key, LPWSTR value, DWORD len) +{ + static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0}; + DWORD keytype; + DWORD ret; + DWORD dwLength = len * sizeof(WCHAR); + + ret = RegQueryValueExW(key, wszThreadingModel, NULL, &keytype, (LPBYTE)value, &dwLength); + if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ)) + value[0] = '\0'; } static HRESULT get_inproc_class_object(HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv) { - HINSTANCE hLibrary; - typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv); - DllGetClassObjectFunc DllGetClassObject; + static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0}; + static const WCHAR wszFree[] = {'F','r','e','e',0}; + static const WCHAR wszBoth[] = {'B','o','t','h',0}; WCHAR dllpath[MAX_PATH+1]; + WCHAR threading_model[10 /* strlenW(L"apartment")+1 */]; + HRESULT hr; + APARTMENT *apt = COM_CurrentApt(); + + get_threading_model(hkeydll, threading_model, ARRAYSIZE(threading_model)); + /* "Apartment" */ + if (!strcmpiW(threading_model, wszApartment)) + { + if (apt->multi_threaded) + { + /* try to find an STA */ + APARTMENT *host_apt = apartment_findfromtype(FALSE, FALSE); + if (!host_apt) + FIXME("create a host apartment for apartment-threaded object %s\n", debugstr_guid(rclsid)); + if (host_apt) + { + struct host_object_params params; + HWND hwnd = apartment_getwindow(host_apt); + + params.hkeydll = hkeydll; + params.clsid = *rclsid; + params.iid = *riid; + hr = CreateStreamOnHGlobal(NULL, TRUE, ¶ms.stream); + if (FAILED(hr)) + return hr; + hr = SendMessageW(hwnd, DM_HOSTOBJECT, 0, (LPARAM)¶ms); + if (SUCCEEDED(hr)) + hr = CoUnmarshalInterface(params.stream, riid, ppv); + IStream_Release(params.stream); + return hr; + } + } + } + /* "Free" */ + else if (!strcmpiW(threading_model, wszFree)) + { + if (!apt->multi_threaded) + { + FIXME("should create object %s in multi-threaded apartment\n", + debugstr_guid(rclsid)); + } + } + /* everything except "Apartment", "Free" and "Both" */ + else if (strcmpiW(threading_model, wszBoth)) + { + /* everything else is main-threaded */ + if (threading_model[0]) + FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n", + debugstr_w(threading_model), debugstr_guid(rclsid)); + + if (apt->multi_threaded || !apt->main) + { + /* try to find an STA */ + APARTMENT *host_apt = apartment_findfromtype(FALSE, TRUE); + if (!host_apt) + FIXME("create a host apartment for main-threaded object %s\n", debugstr_guid(rclsid)); + if (host_apt) + { + struct host_object_params params; + HWND hwnd = apartment_getwindow(host_apt); + + params.hkeydll = hkeydll; + params.clsid = *rclsid; + params.iid = *riid; + hr = CreateStreamOnHGlobal(NULL, TRUE, ¶ms.stream); + if (FAILED(hr)) + return hr; + hr = SendMessageW(hwnd, DM_HOSTOBJECT, 0, (LPARAM)¶ms); + if (SUCCEEDED(hr)) + hr = CoUnmarshalInterface(params.stream, riid, ppv); + IStream_Release(params.stream); + return hr; + } + } + } if (COM_RegReadPath(hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS) { @@ -1551,33 +1947,34 @@ static HRESULT get_inproc_class_object(HKEY hkeydll, REFCLSID rclsid, REFIID rii return REGDB_E_CLASSNOTREG; } - if ((hLibrary = LoadLibraryExW(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) - { - /* failure: DLL could not be loaded */ - ERR("couldn't load in-process dll %s\n", debugstr_w(dllpath)); - return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */ - } - - if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject"))) - { - /* failure: the dll did not export DllGetClassObject */ - ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(dllpath)); - FreeLibrary( hLibrary ); - return CO_E_DLLNOTFOUND; - } - - /* OK: get the ClassObject */ - COMPOBJ_DLLList_Add( hLibrary ); - return DllGetClassObject(rclsid, riid, ppv); + return apartment_getclassobject(apt, dllpath, rclsid, riid, ppv); } /*********************************************************************** * CoGetClassObject [OLE32.@] * - * FIXME. If request allows of several options and there is a failure - * with one (other than not being registered) do we try the - * others or return failure? (E.g. inprocess is registered but - * the DLL is not found but the server version works) + * Creates an object of the specified class. + * + * PARAMS + * rclsid [I] Class ID to create an instance of. + * dwClsContext [I] Flags to restrict the location of the created instance. + * pServerInfo [I] Optional. Details for connecting to a remote server. + * iid [I] The ID of the interface of the instance to return. + * ppv [O] On returns, contains a pointer to the specified interface of the object. + * + * RETURNS + * Success: S_OK + * Failure: HRESULT code. + * + * NOTES + * The dwClsContext parameter can be one or more of the following: + *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL. + *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process. + *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process. + *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine. + * + * SEE ALSO + * CoCreateInstance() */ HRESULT WINAPI CoGetClassObject( REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo, @@ -1588,6 +1985,17 @@ HRESULT WINAPI CoGetClassObject( TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid)); + if (!ppv) + return E_INVALIDARG; + + *ppv = NULL; + + if (!COM_CurrentApt()) + { + ERR("apartment not initialised\n"); + return CO_E_NOTINITIALIZED; + } + if (pServerInfo) { FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName)); FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo); @@ -1618,6 +2026,9 @@ HRESULT WINAPI CoGetClassObject( static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0}; HKEY hkey; + if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler)) + return FTMarshalCF_Create(iid, ppv); + hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey); if (FAILED(hres)) { @@ -1669,7 +2080,9 @@ HRESULT WINAPI CoGetClassObject( /* Next try out of process */ if (CLSCTX_LOCAL_SERVER & dwClsContext) { - return RPC_GetLocalClassObject(rclsid,iid,ppv); + hres = RPC_GetLocalClassObject(rclsid,iid,ppv); + if (SUCCEEDED(hres)) + return hres; } /* Finally try remote: this requires networked DCOM (a lot of work) */ @@ -1680,7 +2093,7 @@ HRESULT WINAPI CoGetClassObject( } if (FAILED(hres)) - ERR("no class object %s could be created for for context 0x%lx\n", + ERR("no class object %s could be created for context 0x%x\n", debugstr_guid(rclsid), dwClsContext); return hres; } @@ -1700,102 +2113,36 @@ HRESULT WINAPI CoResumeClassObjects(void) return S_OK; } -/*********************************************************************** - * GetClassFile (OLE32.@) - * - * This function supplies the CLSID associated with the given filename. - */ -HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid) -{ - IStorage *pstg=0; - HRESULT res; - int nbElm, length, i; - LONG sizeProgId; - LPOLESTR *pathDec=0,absFile=0,progId=0; - LPWSTR extension; - static const WCHAR bkslashW[] = {'\\',0}; - static const WCHAR dotW[] = {'.',0}; - - TRACE("%s, %p\n", debugstr_w(filePathName), pclsid); - - /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/ - if((StgIsStorageFile(filePathName))==S_OK){ - - res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg); - - if (SUCCEEDED(res)) - res=ReadClassStg(pstg,pclsid); - - IStorage_Release(pstg); - - return res; - } - /* if the file is not a storage object then attemps to match various bits in the file against a - pattern in the registry. this case is not frequently used ! so I present only the psodocode for - this case - - for(i=0;i= 0) && *(extension = &absFile[i]) != '.'; i--) - /* nothing */; - - if (!extension || !lstrcmpW(extension, dotW)) - return MK_E_INVALIDEXTENSION; - - res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId); - - /* get the progId associated to the extension */ - progId = CoTaskMemAlloc(sizeProgId); - res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId); - - if (res==ERROR_SUCCESS) - /* return the clsid associated to the progId */ - res= CLSIDFromProgID(progId,pclsid); - - for(i=0; pathDec[i]!=NULL;i++) - CoTaskMemFree(pathDec[i]); - CoTaskMemFree(pathDec); - - CoTaskMemFree(progId); - - if (res==ERROR_SUCCESS) - return res; - - return MK_E_INVALIDEXTENSION; -} - /*********************************************************************** * CoCreateInstance [OLE32.@] + * + * Creates an instance of the specified class. + * + * PARAMS + * rclsid [I] Class ID to create an instance of. + * pUnkOuter [I] Optional outer unknown to allow aggregation with another object. + * dwClsContext [I] Flags to restrict the location of the created instance. + * iid [I] The ID of the interface of the instance to return. + * ppv [O] On returns, contains a pointer to the specified interface of the instance. + * + * RETURNS + * Success: S_OK + * Failure: HRESULT code. + * + * NOTES + * The dwClsContext parameter can be one or more of the following: + *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL. + *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process. + *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process. + *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine. + * + * Aggregation is the concept of deferring the IUnknown of an object to another + * object. This allows a separate object to behave as though it was part of + * the object and to allow this the pUnkOuter parameter can be set. Note that + * not all objects support having an outer of unknown. + * + * SEE ALSO + * CoGetClassObject() */ HRESULT WINAPI CoCreateInstance( REFCLSID rclsid, @@ -1807,11 +2154,9 @@ HRESULT WINAPI CoCreateInstance( HRESULT hres; LPCLASSFACTORY lpclf = 0; - TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08lx, riid=%s, ppv=%p)\n", debugstr_guid(rclsid), + TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid), pUnkOuter, dwClsContext, debugstr_guid(iid), ppv); - if (!COM_CurrentApt()) return CO_E_NOTINITIALIZED; - /* * Sanity check */ @@ -1823,6 +2168,12 @@ HRESULT WINAPI CoCreateInstance( */ *ppv = 0; + if (!COM_CurrentApt()) + { + ERR("apartment not initialised\n"); + return CO_E_NOTINITIALIZED; + } + /* * The Standard Global Interface Table (GIT) object is a process-wide singleton. * Rather than create a class factory, we can just check for it here @@ -1846,11 +2197,8 @@ HRESULT WINAPI CoCreateInstance( &IID_IClassFactory, (LPVOID)&lpclf); - if (FAILED(hres)) { - FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n", - debugstr_guid(rclsid),hres); + if (FAILED(hres)) return hres; - } /* * Create the object and don't forget to release the factory @@ -1858,7 +2206,7 @@ HRESULT WINAPI CoCreateInstance( hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv); IClassFactory_Release(lpclf); if(FAILED(hres)) - FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n", + FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n", debugstr_guid(iid), debugstr_guid(rclsid),hres); return hres; @@ -2012,9 +2360,14 @@ void WINAPI CoFreeAllLibraries(void) */ void WINAPI CoFreeUnusedLibraries(void) { - /* FIXME: Calls to CoFreeUnusedLibraries from any thread always route - * through the main apartment's thread to call DllCanUnloadNow */ - COMPOBJ_DllList_FreeUnused(0); + struct apartment *apt = COM_CurrentApt(); + if (!apt) + { + ERR("apartment not initialised\n"); + return; + } + + apartment_freeunusedlibraries(apt); } /*********************************************************************** @@ -2035,13 +2388,15 @@ HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime ) return S_OK; } -static void COM_RevokeAllClasses() +static void COM_RevokeAllClasses(void) { EnterCriticalSection( &csRegisteredClassList ); - while (firstRegisteredClass!=0) + while (list_head(&RegisteredClassList)) { - CoRevokeClassObject(firstRegisteredClass->dwCookie); + RegisteredClass *curClass = LIST_ENTRY(list_head(&RegisteredClassList), + RegisteredClass, entry); + CoRevokeClassObject(curClass->dwCookie); } LeaveCriticalSection( &csRegisteredClassList ); @@ -2062,6 +2417,10 @@ static void COM_RevokeAllClasses() * RETURNS * Success: S_OK. * Failure: HRESULT code. + * + * NOTES + * If fLock is TRUE and an object is passed in that doesn't have a stub + * manager then a new stub manager is created for the object. */ HRESULT WINAPI CoLockObjectExternal( LPUNKNOWN pUnk, @@ -2084,12 +2443,24 @@ HRESULT WINAPI CoLockObjectExternal( if (fLock) stub_manager_ext_addref(stubmgr, 1); else - stub_manager_ext_release(stubmgr, 1); + stub_manager_ext_release(stubmgr, 1, fLastUnlockReleases); stub_manager_int_release(stubmgr); return S_OK; } + else if (fLock) + { + stubmgr = new_stub_manager(apt, pUnk); + + if (stubmgr) + { + stub_manager_ext_addref(stubmgr, 1); + stub_manager_int_release(stubmgr); + } + + return S_OK; + } else { WARN("stub object not found %p\n", pUnk); @@ -2114,7 +2485,7 @@ HRESULT WINAPI CoLockObjectExternal( */ HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y) { - FIXME("(0x%08lx,0x%08lx),stub!\n",x,y); + FIXME("(0x%08x,0x%08x),stub!\n",x,y); return 0; } @@ -2189,33 +2560,6 @@ HRESULT WINAPI CoSetState(IUnknown * pv) } -/****************************************************************************** - * OleGetAutoConvert [OLE32.@] - */ -HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew) -{ - static const WCHAR wszAutoConvertTo[] = {'A','u','t','o','C','o','n','v','e','r','t','T','o',0}; - HKEY hkey = NULL; - WCHAR buf[CHARS_IN_GUID]; - LONG len; - HRESULT res = S_OK; - - res = COM_OpenKeyForCLSID(clsidOld, wszAutoConvertTo, KEY_READ, &hkey); - if (FAILED(res)) - goto done; - - len = sizeof(buf); - if (RegQueryValueW(hkey, NULL, buf, &len)) - { - res = REGDB_E_KEYMISSING; - goto done; - } - res = CLSIDFromString(buf, pClsidNew); -done: - if (hkey) RegCloseKey(hkey); - return res; -} - /****************************************************************************** * CoTreatAsClass [OLE32.@] * @@ -2312,7 +2656,7 @@ HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew) } res = CLSIDFromString(szClsidNew,clsidNew); if (FAILED(res)) - ERR("Failed CLSIDFromStringA(%s), hres 0x%08lx\n", debugstr_w(szClsidNew), res); + ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res); done: if (hkey) RegCloseKey(hkey); return res; @@ -2347,15 +2691,50 @@ DWORD WINAPI CoGetCurrentProcess(void) * RETURNS * Success: S_OK. * Failure: HRESULT code. + * + * NOTES + * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL + * lpMessageFilter removes the message filter. + * + * If lplpMessageFilter is not NULL the previous message filter will be + * returned in the memory pointer to this parameter and the caller is + * responsible for releasing the object. + * + * The current thread be in an apartment otherwise the function will crash. */ HRESULT WINAPI CoRegisterMessageFilter( LPMESSAGEFILTER lpMessageFilter, LPMESSAGEFILTER *lplpMessageFilter) { - FIXME("stub\n"); - if (lplpMessageFilter) { - *lplpMessageFilter = NULL; + struct apartment *apt; + IMessageFilter *lpOldMessageFilter; + + TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter); + + apt = COM_CurrentApt(); + + /* can't set a message filter in a multi-threaded apartment */ + if (!apt || apt->multi_threaded) + { + WARN("can't set message filter in MTA or uninitialized apt\n"); + return CO_E_NOT_SUPPORTED; } + + if (lpMessageFilter) + IMessageFilter_AddRef(lpMessageFilter); + + EnterCriticalSection(&apt->cs); + + lpOldMessageFilter = apt->filter; + apt->filter = lpMessageFilter; + + LeaveCriticalSection(&apt->cs); + + if (lplpMessageFilter) + *lplpMessageFilter = lpOldMessageFilter; + else if (lpOldMessageFilter) + IMessageFilter_Release(lpOldMessageFilter); + return S_OK; } @@ -2405,7 +2784,7 @@ HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc DWORD dwImpLevel, void* pReserved2, DWORD dwCapabilities, void* pReserved3) { - FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc, + FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc, asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2, dwCapabilities, pReserved3); return S_OK; @@ -2435,11 +2814,23 @@ HRESULT WINAPI CoSuspendClassObjects(void) * * RETURNS * New reference count. + * + * SEE ALSO + * CoReleaseServerProcess(). */ ULONG WINAPI CoAddRefServerProcess(void) { - FIXME("\n"); - return 2; + ULONG refs; + + TRACE("\n"); + + EnterCriticalSection(&csRegisteredClassList); + refs = ++s_COMServerProcessReferences; + LeaveCriticalSection(&csRegisteredClassList); + + TRACE("refs before: %d\n", refs - 1); + + return refs; } /*********************************************************************** @@ -2450,11 +2841,30 @@ ULONG WINAPI CoAddRefServerProcess(void) * * RETURNS * New reference count. + * + * NOTES + * When reference count reaches 0, this function suspends all registered + * classes so no new connections are accepted. + * + * SEE ALSO + * CoAddRefServerProcess(), CoSuspendClassObjects(). */ ULONG WINAPI CoReleaseServerProcess(void) { - FIXME("\n"); - return 1; + ULONG refs; + + TRACE("\n"); + + EnterCriticalSection(&csRegisteredClassList); + + refs = --s_COMServerProcessReferences; + /* FIXME: if (!refs) COM_SuspendClassObjects(); */ + + LeaveCriticalSection(&csRegisteredClassList); + + TRACE("refs after: %d\n", refs); + + return refs; } /*********************************************************************** @@ -2527,7 +2937,7 @@ HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc, IClientSecurity_Release(pCliSec); } - if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr); + if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr); return hr; } @@ -2572,7 +2982,7 @@ HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc, IClientSecurity_Release(pCliSec); } - if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr); + if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr); return hr; } @@ -2606,11 +3016,162 @@ HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy) IClientSecurity_Release(pCliSec); } - if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr); + if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr); return hr; } +/*********************************************************************** + * CoGetCallContext [OLE32.@] + * + * Gets the context of the currently executing server call in the current + * thread. + * + * PARAMS + * riid [I] Context interface to return. + * ppv [O] Pointer to memory that will receive the context on return. + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT code. + */ +HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv) +{ + FIXME("(%s, %p): stub\n", debugstr_guid(riid), ppv); + + *ppv = NULL; + return E_NOINTERFACE; +} + +/*********************************************************************** + * CoQueryClientBlanket [OLE32.@] + * + * Retrieves the authentication information about the client of the currently + * executing server call in the current thread. + * + * PARAMS + * pAuthnSvc [O] Optional. The type of authentication service. + * pAuthzSvc [O] Optional. The type of authorization service. + * pServerPrincName [O] Optional. The server prinicple name. + * pAuthnLevel [O] Optional. The authentication level. + * pImpLevel [O] Optional. The impersonation level. + * pPrivs [O] Optional. Information about the privileges of the client. + * pCapabilities [IO] Optional. Flags affecting the security behaviour. + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT code. + * + * SEE ALSO + * CoImpersonateClient, CoRevertToSelf, CoGetCallContext. + */ +HRESULT WINAPI CoQueryClientBlanket( + DWORD *pAuthnSvc, + DWORD *pAuthzSvc, + OLECHAR **pServerPrincName, + DWORD *pAuthnLevel, + DWORD *pImpLevel, + RPC_AUTHZ_HANDLE *pPrivs, + DWORD *pCapabilities) +{ + IServerSecurity *pSrvSec; + HRESULT hr; + + TRACE("(%p, %p, %p, %p, %p, %p, %p)\n", + pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel, + pPrivs, pCapabilities); + + hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec); + if (SUCCEEDED(hr)) + { + hr = IServerSecurity_QueryBlanket( + pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, + pImpLevel, pPrivs, pCapabilities); + IServerSecurity_Release(pSrvSec); + } + + return hr; +} + +/*********************************************************************** + * CoImpersonateClient [OLE32.@] + * + * Impersonates the client of the currently executing server call in the + * current thread. + * + * PARAMS + * None. + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT code. + * + * NOTES + * If this function fails then the current thread will not be impersonating + * the client and all actions will take place on behalf of the server. + * Therefore, it is important to check the return value from this function. + * + * SEE ALSO + * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext. + */ +HRESULT WINAPI CoImpersonateClient(void) +{ + IServerSecurity *pSrvSec; + HRESULT hr; + + TRACE("\n"); + + hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec); + if (SUCCEEDED(hr)) + { + hr = IServerSecurity_ImpersonateClient(pSrvSec); + IServerSecurity_Release(pSrvSec); + } + + return hr; +} + +/*********************************************************************** + * CoRevertToSelf [OLE32.@] + * + * Ends the impersonation of the client of the currently executing server + * call in the current thread. + * + * PARAMS + * None. + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT code. + * + * SEE ALSO + * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext. + */ +HRESULT WINAPI CoRevertToSelf(void) +{ + IServerSecurity *pSrvSec; + HRESULT hr; + + TRACE("\n"); + + hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec); + if (SUCCEEDED(hr)) + { + hr = IServerSecurity_RevertToSelf(pSrvSec); + IServerSecurity_Release(pSrvSec); + } + + return hr; +} + +static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg) +{ + /* first try to retrieve messages for incoming COM calls to the apartment window */ + return PeekMessageW(msg, apt->win, WM_USER, WM_APP - 1, PM_REMOVE|PM_NOYIELD) || + /* next retrieve other messages necessary for the app to remain responsive */ + PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_POSTMESSAGE|PM_REMOVE|PM_NOYIELD); +} + /*********************************************************************** * CoWaitForMultipleHandles [OLE32.@] * @@ -2637,51 +3198,101 @@ HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy) * MsgWaitForMultipleObjects, WaitForMultipleObjects. */ HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout, - ULONG cHandles, const HANDLE* pHandles, LPDWORD lpdwindex) + ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex) { HRESULT hr = S_OK; - DWORD wait_flags = (dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0 | - (dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0; DWORD start_time = GetTickCount(); + APARTMENT *apt = COM_CurrentApt(); + BOOL message_loop = apt && !apt->multi_threaded; - TRACE("(0x%08lx, 0x%08lx, %ld, %p, %p)\n", dwFlags, dwTimeout, cHandles, + TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles, pHandles, lpdwindex); while (TRUE) { DWORD now = GetTickCount(); DWORD res; - + if ((dwTimeout != INFINITE) && (start_time + dwTimeout >= now)) { hr = RPC_S_CALLPENDING; break; } - TRACE("waiting for rpc completion or window message\n"); - - res = MsgWaitForMultipleObjectsEx(cHandles, pHandles, - (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now, - QS_ALLINPUT, wait_flags); - - if (res == WAIT_OBJECT_0 + cHandles) /* messages available */ + if (message_loop) { - MSG msg; - while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) + DWORD wait_flags = (dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0 | + (dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0; + + TRACE("waiting for rpc completion or window message\n"); + + res = MsgWaitForMultipleObjectsEx(cHandles, pHandles, + (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now, + QS_ALLINPUT, wait_flags); + + if (res == WAIT_OBJECT_0 + cHandles) /* messages available */ { - /* FIXME: filter the messages here */ - TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message); - TranslateMessage(&msg); - DispatchMessageW(&msg); - if (msg.message == WM_QUIT) + MSG msg; + + /* call message filter */ + + if (COM_CurrentApt()->filter) { - TRACE("resending WM_QUIT to outer message loop\n"); - PostQuitMessage(msg.wParam); - goto done; + PENDINGTYPE pendingtype = + COM_CurrentInfo()->pending_call_count_server ? + PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL; + DWORD be_handled = IMessageFilter_MessagePending( + COM_CurrentApt()->filter, 0 /* FIXME */, + now - start_time, pendingtype); + TRACE("IMessageFilter_MessagePending returned %d\n", be_handled); + switch (be_handled) + { + case PENDINGMSG_CANCELCALL: + WARN("call canceled\n"); + hr = RPC_E_CALL_CANCELED; + break; + case PENDINGMSG_WAITNOPROCESS: + case PENDINGMSG_WAITDEFPROCESS: + default: + /* FIXME: MSDN is very vague about the difference + * between WAITNOPROCESS and WAITDEFPROCESS - there + * appears to be none, so it is possibly a left-over + * from the 16-bit world. */ + break; + } } + + /* note: using "if" here instead of "while" might seem less + * efficient, but only if we are optimising for quick delivery + * of pending messages, rather than quick completion of the + * COM call */ + if (COM_PeekMessage(apt, &msg)) + { + TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message); + TranslateMessage(&msg); + DispatchMessageW(&msg); + if (msg.message == WM_QUIT) + { + TRACE("resending WM_QUIT to outer message loop\n"); + PostQuitMessage(msg.wParam); + /* no longer need to process messages */ + message_loop = FALSE; + } + } + continue; } } - else if ((res >= WAIT_OBJECT_0) && (res < WAIT_OBJECT_0 + cHandles)) + else + { + TRACE("waiting for rpc completion\n"); + + res = WaitForMultipleObjectsEx(cHandles, pHandles, + (dwFlags & COWAIT_WAITALL) ? TRUE : FALSE, + (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now, + (dwFlags & COWAIT_ALERTABLE) ? TRUE : FALSE); + } + + if ((res >= WAIT_OBJECT_0) && (res < WAIT_OBJECT_0 + cHandles)) { /* handle signaled, store index */ *lpdwindex = (res - WAIT_OBJECT_0); @@ -2694,22 +3305,93 @@ HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout, } else { - ERR("Unexpected wait termination: %ld, %ld\n", res, GetLastError()); + ERR("Unexpected wait termination: %d, %d\n", res, GetLastError()); hr = E_UNEXPECTED; break; } } -done: - TRACE("-- 0x%08lx\n", hr); + TRACE("-- 0x%08x\n", hr); return hr; } + +/*********************************************************************** + * CoGetObject [OLE32.@] + * + * Gets the object named by coverting the name to a moniker and binding to it. + * + * PARAMS + * pszName [I] String representing the object. + * pBindOptions [I] Parameters affecting the binding to the named object. + * riid [I] Interface to bind to on the objecct. + * ppv [O] On output, the interface riid of the object represented + * by pszName. + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT code. + * + * SEE ALSO + * MkParseDisplayName. + */ +HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions, + REFIID riid, void **ppv) +{ + IBindCtx *pbc; + HRESULT hr; + + *ppv = NULL; + + hr = CreateBindCtx(0, &pbc); + if (SUCCEEDED(hr)) + { + if (pBindOptions) + hr = IBindCtx_SetBindOptions(pbc, pBindOptions); + + if (SUCCEEDED(hr)) + { + ULONG chEaten; + IMoniker *pmk; + + hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk); + if (SUCCEEDED(hr)) + { + hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv); + IMoniker_Release(pmk); + } + } + + IBindCtx_Release(pbc); + } + return hr; +} + +/*********************************************************************** + * CoRegisterChannelHook [OLE32.@] + * + * Registers a process-wide hook that is called during ORPC calls. + * + * PARAMS + * guidExtension [I] GUID of the channel hook to register. + * pChannelHook [I] Channel hook object to register. + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT code. + */ +HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook) +{ + TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook); + + return RPC_RegisterChannelHook(guidExtension, pChannelHook); +} + /*********************************************************************** * DllMain (OLE32.@) */ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad) { - TRACE("%p 0x%lx %p\n", hinstDLL, fdwReason, fImpLoad); + TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad); switch(fdwReason) { case DLL_PROCESS_ATTACH: @@ -2720,7 +3402,9 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad) case DLL_PROCESS_DETACH: if (TRACE_ON(ole)) CoRevokeMallocSpy(); + OLEDD_UnInitialize(); COMPOBJ_UninitProcess(); + RPC_UnregisterAllChannelHooks(); OLE32_hInstance = 0; break; diff --git a/reactos/dll/win32/ole32/compobj.spec b/reactos/dll/win32/ole32/compobj.spec index af946920192..078dfc26ed3 100644 --- a/reactos/dll/win32/ole32/compobj.spec +++ b/reactos/dll/win32/ole32/compobj.spec @@ -12,7 +12,7 @@ 12 stub COFREEALLLIBRARIES 13 pascal CoCreateInstance(ptr ptr long ptr ptr) CoCreateInstance16 14 stub STRINGFROMIID -15 pascal CoDisconnectObject(ptr long) CoDisconnectObject +15 pascal CoDisconnectObject(ptr long) CoDisconnectObject16 16 stub CORELEASEMARSHALDATA 17 pascal -ret16 CoFreeUnusedLibraries() CoFreeUnusedLibraries 18 pascal -ret16 IsEqualGUID(ptr ptr) IsEqualGUID16 diff --git a/reactos/dll/win32/ole32/compobj_private.h b/reactos/dll/win32/ole32/compobj_private.h index 790042ed463..e877cce0269 100644 --- a/reactos/dll/win32/ole32/compobj_private.h +++ b/reactos/dll/win32/ole32/compobj_private.h @@ -19,7 +19,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __WINE_OLE_COMPOBJ_H @@ -41,6 +41,13 @@ struct apartment; typedef struct apartment APARTMENT; +DEFINE_OLEGUID( CLSID_DfMarshal, 0x0000030b, 0, 0 ); +DEFINE_OLEGUID( CLSID_PSFactoryBuffer, 0x00000320, 0, 0 ); +DEFINE_OLEGUID( CLSID_InProcFreeMarshaler, 0x0000033a, 0, 0 ); + +/* signal to stub manager that this is a rem unknown object */ +#define MSHLFLAGSP_REMUNKNOWN 0x80000000 + /* Thread-safety Annotation Legend: * * RO - The value is read only. It never changes after creation, so no @@ -72,6 +79,7 @@ struct ifstub IPID ipid; /* RO */ IUnknown *iface; /* RO */ MSHLFLAGS flags; /* so we can enforce process-local marshalling rules (RO) */ + IRpcChannelBuffer*chan; /* channel passed to IRpcStubBuffer::Invoke (RO) */ }; @@ -88,6 +96,7 @@ struct stub_manager OID oid; /* apartment-scoped unique identifier (RO) */ IUnknown *object; /* the object we are managing the stub for (RO) */ ULONG next_ipid; /* currently unused (LOCK) */ + OXID_INFO oxid_info; /* string binding, ipid of rem unknown and other information (RO) */ /* We need to keep a count of the outstanding marshals, so we can enforce the * marshalling rules (ie, you can only unmarshal normal marshals once). Note @@ -107,7 +116,7 @@ struct ifproxy STDOBJREF stdobjref; /* marshal data that represents this object (RO) */ IID iid; /* interface ID (RO) */ LPRPCPROXYBUFFER proxy; /* interface proxy (RO) */ - DWORD refs; /* imported (public) references (MUTEX parent->remoting_mutex) */ + ULONG refs; /* imported (public) references (LOCK) */ IRpcChannelBuffer *chan; /* channel to object (CS parent->cs) */ }; @@ -116,9 +125,11 @@ struct proxy_manager { const IMultiQIVtbl *lpVtbl; const IMarshalVtbl *lpVtblMarshal; + const IClientSecurityVtbl *lpVtblCliSec; struct apartment *parent; /* owning apartment (RO) */ struct list entry; /* entry in apartment (CS parent->cs) */ OXID oxid; /* object exported ID (RO) */ + OXID_INFO oxid_info; /* string binding, ipid of rem unknown and other information (RO) */ OID oid; /* object ID (RO) */ struct list interfaces; /* imported interfaces (CS cs) */ LONG refs; /* proxy reference count (LOCK) */ @@ -126,28 +137,35 @@ struct proxy_manager ULONG sorflags; /* STDOBJREF flags (RO) */ IRemUnknown *remunk; /* proxy to IRemUnknown used for lifecycle management (CS cs) */ HANDLE remoting_mutex; /* mutex used for synchronizing access to IRemUnknown */ + MSHCTX dest_context; /* context used for activating optimisations (LOCK) */ + void *dest_context_data; /* reserved context value (LOCK) */ }; /* this needs to become a COM object that implements IRemUnknown */ struct apartment { - struct list entry; + struct list entry; LONG refs; /* refcount of the apartment (LOCK) */ - DWORD model; /* threading model (RO) */ + BOOL multi_threaded; /* multi-threaded or single-threaded apartment? (RO) */ DWORD tid; /* thread id (RO) */ OXID oxid; /* object exporter ID (RO) */ LONG ipidc; /* interface pointer ID counter, starts at 1 (LOCK) */ - HWND win; /* message window (RO) */ CRITICAL_SECTION cs; /* thread safety */ - LPMESSAGEFILTER filter; /* message filter (CS cs) */ struct list proxies; /* imported objects (CS cs) */ struct list stubmgrs; /* stub managers for exported objects (CS cs) */ BOOL remunk_exported; /* has the IRemUnknown interface for this apartment been created yet? (CS cs) */ LONG remoting_started; /* has the RPC system been started for this apartment? (LOCK) */ + struct list psclsids; /* list of registered PS CLSIDs (CS cs) */ + struct list loaded_dlls; /* list of dlls loaded by this apartment (CS cs) */ /* FIXME: OID's should be given out by RPCSS */ OID oidc; /* object ID counter, starts at 1, zero is invalid OID (CS cs) */ + + /* STA-only fields */ + HWND win; /* message window (LOCK) */ + LPMESSAGEFILTER filter; /* message filter (CS cs) */ + BOOL main; /* is this a main-threaded-apartment? (RO) */ }; /* this is what is stored in TEB->ReservedForOle */ @@ -157,22 +175,26 @@ struct oletls IErrorInfo *errorinfo; /* see errorinfo.c */ IUnknown *state; /* see CoSetState */ DWORD inits; /* number of times CoInitializeEx called */ + DWORD ole_inits; /* number of times OleInitialize called */ + GUID causality_id; /* unique identifier for each COM call */ + LONG pending_call_count_client; /* number of client calls pending */ + LONG pending_call_count_server; /* number of server calls pending */ }; /* Global Interface Table Functions */ extern void* StdGlobalInterfaceTable_Construct(void); -extern void StdGlobalInterfaceTable_Destroy(void* self); extern HRESULT StdGlobalInterfaceTable_GetFactory(LPVOID *ppv); extern void* StdGlobalInterfaceTableInstance; /* FIXME: these shouldn't be needed, except for 16-bit functions */ extern HRESULT WINE_StringFromCLSID(const CLSID *id,LPSTR idstr); -HRESULT WINAPI __CLSIDFromStringA(LPCSTR idstr, CLSID *id); HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *key); +HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey); HRESULT MARSHAL_GetStandardMarshalCF(LPVOID *ppv); +HRESULT FTMarshalCF_Create(REFIID riid, LPVOID *ppv); /* Stub Manager */ @@ -180,7 +202,7 @@ ULONG stub_manager_int_addref(struct stub_manager *This); ULONG stub_manager_int_release(struct stub_manager *This); struct stub_manager *new_stub_manager(APARTMENT *apt, IUnknown *object); ULONG stub_manager_ext_addref(struct stub_manager *m, ULONG refs); -ULONG stub_manager_ext_release(struct stub_manager *m, ULONG refs); +ULONG stub_manager_ext_release(struct stub_manager *m, ULONG refs, BOOL last_unlock_releases); struct ifstub *stub_manager_new_ifstub(struct stub_manager *m, IRpcStubBuffer *sb, IUnknown *iptr, REFIID iid, MSHLFLAGS flags); struct ifstub *stub_manager_find_ifstub(struct stub_manager *m, REFIID iid, MSHLFLAGS flags); struct stub_manager *get_stub_manager(APARTMENT *apt, OID oid); @@ -189,7 +211,7 @@ BOOL stub_manager_notify_unmarshal(struct stub_manager *m, const IPID *ipid); BOOL stub_manager_is_table_marshaled(struct stub_manager *m, const IPID *ipid); void stub_manager_release_marshal_data(struct stub_manager *m, ULONG refs, const IPID *ipid); HRESULT ipid_to_stub_manager(const IPID *ipid, APARTMENT **stub_apt, struct stub_manager **stubmgr_ret); -IRpcStubBuffer *ipid_to_apt_and_stubbuffer(const IPID *ipid, APARTMENT **stub_apt); +HRESULT ipid_get_dispatch_params(const IPID *ipid, APARTMENT **stub_apt, IRpcStubBuffer **stub, IRpcChannelBuffer **chan, IID *iid, IUnknown **iface); HRESULT start_apartment_remote_unknown(void); HRESULT marshal_object(APARTMENT *apt, STDOBJREF *stdobjref, REFIID riid, IUnknown *obj, MSHLFLAGS mshlflags); @@ -199,12 +221,20 @@ HRESULT marshal_object(APARTMENT *apt, STDOBJREF *stdobjref, REFIID riid, IUnkno struct dispatch_params; void RPC_StartRemoting(struct apartment *apt); -HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid, IRpcChannelBuffer **pipebuf); +HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid, + const OXID_INFO *oxid_info, + DWORD dest_context, void *dest_context_data, + IRpcChannelBuffer **chan); +HRESULT RPC_CreateServerChannel(IRpcChannelBuffer **chan); void RPC_ExecuteCall(struct dispatch_params *params); HRESULT RPC_RegisterInterface(REFIID riid); void RPC_UnregisterInterface(REFIID riid); -void RPC_StartLocalServer(REFCLSID clsid, IStream *stream); +HRESULT RPC_StartLocalServer(REFCLSID clsid, IStream *stream, BOOL multi_use, void **registration); +void RPC_StopLocalServer(void *registration); HRESULT RPC_GetLocalClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv); +HRESULT RPC_RegisterChannelHook(REFGUID rguid, IChannelHook *hook); +void RPC_UnregisterAllChannelHooks(void); +HRESULT RPC_ResolveOxid(OXID oxid, OXID_INFO *oxid_info); /* This function initialize the Running Object Table */ HRESULT WINAPI RunningObjectTableImpl_Initialize(void); @@ -212,9 +242,8 @@ HRESULT WINAPI RunningObjectTableImpl_Initialize(void); /* This function uninitialize the Running Object Table */ HRESULT WINAPI RunningObjectTableImpl_UnInitialize(void); -/* This function decomposes a String path to a String Table containing all the elements ("\" or "subDirectory" or "Directory" or "FileName") of the path */ -int FileMonikerImpl_DecomposePath(LPCOLESTR str, LPOLESTR** stringTable); - +/* Drag and drop */ +void OLEDD_UnInitialize(void); /* Apartment Functions */ @@ -229,10 +258,14 @@ static inline HRESULT apartment_getoxid(struct apartment *apt, OXID *oxid) *oxid = apt->oxid; return S_OK; } +HRESULT apartment_createwindowifneeded(struct apartment *apt); +HWND apartment_getwindow(struct apartment *apt); +void apartment_joinmta(void); /* DCOM messages used by the apartment window (not compatible with native) */ #define DM_EXECUTERPC (WM_USER + 0) /* WPARAM = 0, LPARAM = (struct dispatch_params *) */ +#define DM_HOSTOBJECT (WM_USER + 1) /* WPARAM = 0, LPARAM = (struct host_object_params *) */ /* * Per-thread values are stored in the TEB on offset 0xF80, @@ -253,6 +286,16 @@ static inline APARTMENT* COM_CurrentApt(void) return COM_CurrentInfo()->apt; } +static inline GUID COM_CurrentCausalityId(void) +{ + struct oletls *info = COM_CurrentInfo(); + if (!info) + return GUID_NULL; + if (IsEqualGUID(&info->causality_id, &GUID_NULL)) + CoCreateGuid(&info->causality_id); + return info->causality_id; +} + #define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field)) /* helpers for debugging */ diff --git a/reactos/dll/win32/ole32/compositemoniker.c b/reactos/dll/win32/ole32/compositemoniker.c index c6510abefc5..4a0af25a8cd 100644 --- a/reactos/dll/win32/ole32/compositemoniker.c +++ b/reactos/dll/win32/ole32/compositemoniker.c @@ -15,7 +15,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include @@ -37,10 +37,6 @@ 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 */ @@ -54,6 +50,8 @@ typedef struct CompositeMonikerImpl{ */ 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 */ @@ -85,6 +83,11 @@ 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); /******************************************************************************* @@ -113,6 +116,8 @@ CompositeMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject *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) @@ -137,6 +142,16 @@ CompositeMonikerImpl_AddRef(IMoniker* iface) 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 ******************************************************************************/ @@ -144,7 +159,6 @@ static ULONG WINAPI CompositeMonikerImpl_Release(IMoniker* iface) { CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface; - ULONG i; ULONG ref; TRACE("(%p)\n",This); @@ -155,8 +169,7 @@ CompositeMonikerImpl_Release(IMoniker* iface) if (ref == 0){ /* release all the components before destroying this object */ - for (i=0;itabLastIndex;i++) - IMoniker_Release(This->tabMoniker[i]); + CompositeMonikerImpl_ReleaseMonikersInTable(This); HeapFree(GetProcessHeap(),0,This->tabMoniker); HeapFree(GetProcessHeap(),0,This); @@ -170,7 +183,7 @@ CompositeMonikerImpl_Release(IMoniker* iface) static HRESULT WINAPI CompositeMonikerImpl_GetClassID(IMoniker* iface,CLSID *pClassID) { - TRACE("(%p,%p),stub!\n",iface,pClassID); + TRACE("(%p,%p)\n",iface,pClassID); if (pClassID==NULL) return E_POINTER; @@ -202,9 +215,8 @@ static HRESULT WINAPI CompositeMonikerImpl_Load(IMoniker* iface,IStream* pStm) { HRESULT res; - DWORD constant; - CLSID clsid; - WCHAR string[1]={0}; + DWORD moniker_count; + DWORD i; CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface; @@ -212,54 +224,22 @@ CompositeMonikerImpl_Load(IMoniker* iface,IStream* 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) + 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; + } - while(1){ -#if 0 + CompositeMonikerImpl_ReleaseMonikersInTable(This); + + for (i = 0; i < moniker_count; i++) + { 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! */ + ERR("couldn't load moniker from stream, res = 0x%08x\n", res); break; - return E_NOTIMPL; } /* resize the table if needed */ @@ -282,10 +262,11 @@ CompositeMonikerImpl_Load(IMoniker* iface,IStream* pStm) static HRESULT WINAPI CompositeMonikerImpl_Save(IMoniker* iface,IStream* pStm,BOOL fClearDirty) { + CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface; HRESULT res; IEnumMoniker *enumMk; IMoniker *pmk; - DWORD constant=3; + DWORD moniker_count = This->tabLastIndex; TRACE("(%p,%p,%d)\n",iface,pStm,fClearDirty); @@ -295,7 +276,8 @@ CompositeMonikerImpl_Save(IMoniker* iface,IStream* pStm,BOOL fClearDirty) * 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); + res=IStream_Write(pStm,&moniker_count,sizeof(moniker_count),NULL); + if (FAILED(res)) return res; IMoniker_Enum(iface,TRUE,&enumMk); @@ -307,7 +289,7 @@ CompositeMonikerImpl_Save(IMoniker* iface,IStream* pStm,BOOL fClearDirty) if (FAILED(res)){ - IEnumMoniker_Release(pmk); + IEnumMoniker_Release(enumMk); return res; } } @@ -333,22 +315,20 @@ CompositeMonikerImpl_GetSizeMax(IMoniker* iface,ULARGE_INTEGER* pcbSize) TRACE("(%p,%p)\n",iface,pcbSize); - if (pcbSize!=NULL) + if (!pcbSize) return E_POINTER; - pcbSize->u.LowPart =0; - pcbSize->u.HighPart=0; + pcbSize->QuadPart = sizeof(DWORD); IMoniker_Enum(iface,TRUE,&enumMk); - while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)){ + while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)==S_OK){ IMoniker_GetSizeMax(pmk,&ptmpSize); IMoniker_Release(pmk); - pcbSize->u.LowPart +=ptmpSize.u.LowPart; - pcbSize->u.HighPart+=ptmpSize.u.HighPart; + pcbSize->QuadPart = ptmpSize.QuadPart + sizeof(CLSID); } IEnumMoniker_Release(enumMk); @@ -401,7 +381,7 @@ CompositeMonikerImpl_BindToObject(IMoniker* iface, IBindCtx* pbc, res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk); IMoniker_Release(antiMk); - res=CompositeMonikerImpl_BindToObject(mostRigthMk,pbc,tempMk,riid,ppvResult); + res=IMoniker_BindToObject(mostRigthMk,pbc,tempMk,riid,ppvResult); IMoniker_Release(tempMk); IMoniker_Release(mostRigthMk); @@ -418,7 +398,7 @@ CompositeMonikerImpl_BindToStorage(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult) { HRESULT res; - IMoniker *tempMk,*antiMk,*mostRigthMk; + IMoniker *tempMk,*antiMk,*mostRigthMk,*leftMk; IEnumMoniker *enumMoniker; TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult); @@ -428,26 +408,34 @@ CompositeMonikerImpl_BindToStorage(IMoniker* iface, IBindCtx* pbc, /* 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. */ - if (pmkToLeft!=NULL){ - - 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_BindToStorage(mostRigthMk,pbc,tempMk,riid,ppvResult); - - IMoniker_Release(tempMk); - - IMoniker_Release(mostRigthMk); - - return res; + if (pmkToLeft) + { + res = IMoniker_ComposeWith(pmkToLeft, iface, FALSE, &leftMk); + if (FAILED(res)) return res; } else - return IMoniker_BindToStorage(iface,pbc,NULL,riid,ppvResult); + leftMk = iface; + + IMoniker_Enum(iface, FALSE, &enumMoniker); + IEnumMoniker_Next(enumMoniker, 1, &mostRigthMk, NULL); + IEnumMoniker_Release(enumMoniker); + + res = CreateAntiMoniker(&antiMk); + if (FAILED(res)) return res; + res = IMoniker_ComposeWith(leftMk, antiMk, 0, &tempMk); + if (FAILED(res)) return res; + IMoniker_Release(antiMk); + + res = IMoniker_BindToStorage(mostRigthMk, pbc, tempMk, riid, ppvResult); + + IMoniker_Release(tempMk); + + IMoniker_Release(mostRigthMk); + + if (pmkToLeft) + IMoniker_Release(leftMk); + + return res; } /****************************************************************************** @@ -461,7 +449,7 @@ CompositeMonikerImpl_Reduce(IMoniker* iface, IBindCtx* pbc, DWORD dwReduceHowFar IMoniker *tempMk,*antiMk,*mostRigthMk,*leftReducedComposedMk,*mostRigthReducedMk; IEnumMoniker *enumMoniker; - TRACE("(%p,%p,%ld,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced); + TRACE("(%p,%p,%d,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced); if (ppmkReduced==NULL) return E_POINTER; @@ -478,7 +466,7 @@ CompositeMonikerImpl_Reduce(IMoniker* iface, IBindCtx* pbc, DWORD dwReduceHowFar res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk); IMoniker_Release(antiMk); - return CompositeMonikerImpl_Reduce(mostRigthMk,pbc,dwReduceHowFar,&tempMk, ppmkReduced); + return IMoniker_Reduce(mostRigthMk,pbc,dwReduceHowFar,&tempMk, ppmkReduced); } else if (*ppmkToLeft==NULL) @@ -498,7 +486,7 @@ CompositeMonikerImpl_Reduce(IMoniker* iface, IBindCtx* pbc, DWORD dwReduceHowFar /* If any of the components reduces itself, the method returns S_OK and passes back a composite */ /* of the reduced components */ if (IMoniker_Reduce(mostRigthMk,pbc,dwReduceHowFar,NULL,&mostRigthReducedMk) && - CompositeMonikerImpl_Reduce(mostRigthMk,pbc,dwReduceHowFar,&tempMk,&leftReducedComposedMk) + IMoniker_Reduce(mostRigthMk,pbc,dwReduceHowFar,&tempMk,&leftReducedComposedMk) ) return CreateGenericComposite(leftReducedComposedMk,mostRigthReducedMk,ppmkReduced); @@ -634,15 +622,13 @@ CompositeMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash) if(FAILED(res)) return res; - while(1){ - res=IEnumMoniker_Next(enumMoniker,1,&tempMk,NULL); - if(FAILED(res)) - break; - + *pdwHash = 0; + + while(IEnumMoniker_Next(enumMoniker,1,&tempMk,NULL)==S_OK){ res = IMoniker_Hash(tempMk, &tempHash); if(FAILED(res)) break; - *pdwHash = (*pdwHash * 37) + tempHash; + *pdwHash = *pdwHash ^ tempHash; IMoniker_Release(tempMk); } @@ -737,9 +723,8 @@ static HRESULT WINAPI CompositeMonikerImpl_GetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft, FILETIME* pCompositeTime) { - IRunningObjectTable* rot; HRESULT res; - IMoniker *tempMk,*antiMk,*mostRigthMk; + IMoniker *tempMk,*antiMk,*mostRigthMk,*leftMk; IEnumMoniker *enumMoniker; TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pCompositeTime); @@ -751,36 +736,45 @@ CompositeMonikerImpl_GetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc, /* retrieve the time of last change. If the object is not in the ROT, the method recursively calls */ /* IMoniker::GetTimeOfLastChange on the rightmost component of the composite, passing the remainder */ /* of the composite as the pmkToLeft parameter for that call. */ - if (pmkToLeft!=NULL){ + if (pmkToLeft) + { + IRunningObjectTable* rot; - res=CreateGenericComposite(pmkToLeft,iface,&tempMk); - - res=IBindCtx_GetRunningObjectTable(pbc,&rot); + res = IMoniker_ComposeWith(pmkToLeft, iface, FALSE, &leftMk); + res = IBindCtx_GetRunningObjectTable(pbc,&rot); if (FAILED(res)) + { + IMoniker_Release(leftMk); return res; + } - if (IRunningObjectTable_GetTimeOfLastChange(rot,tempMk,pCompositeTime)==S_OK) - return res; - else - - 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_GetTimeOfLastChange(mostRigthMk,pbc,tempMk,pCompositeTime); - - IMoniker_Release(tempMk); - IMoniker_Release(mostRigthMk); - + if (IRunningObjectTable_GetTimeOfLastChange(rot,leftMk,pCompositeTime)==S_OK) + { + IMoniker_Release(leftMk); return res; + } } else - return IMoniker_GetTimeOfLastChange(iface,pbc,NULL,pCompositeTime); + leftMk = iface; + + IMoniker_Enum(iface, FALSE, &enumMoniker); + IEnumMoniker_Next(enumMoniker, 1, &mostRigthMk, NULL); + IEnumMoniker_Release(enumMoniker); + + res = CreateAntiMoniker(&antiMk); + res = IMoniker_ComposeWith(leftMk, antiMk, 0, &tempMk); + IMoniker_Release(antiMk); + + res = IMoniker_GetTimeOfLastChange(mostRigthMk, pbc, tempMk, pCompositeTime); + + IMoniker_Release(tempMk); + IMoniker_Release(mostRigthMk); + + if (pmkToLeft) + IMoniker_Release(leftMk); + + return res; } /****************************************************************************** @@ -1245,14 +1239,267 @@ static ULONG WINAPI CompositeMonikerROTDataImpl_Release(IROTData* iface) } /****************************************************************************** - * CompositeMonikerIROTData_GetComparaisonData + * CompositeMonikerIROTData_GetComparisonData ******************************************************************************/ static HRESULT WINAPI -CompositeMonikerROTDataImpl_GetComparaisonData(IROTData* iface, +CompositeMonikerROTDataImpl_GetComparisonData(IROTData* iface, BYTE* pbData, ULONG cbMax, ULONG* pcbData) { - FIXME("(),stub!\n"); - return E_NOTIMPL; + IMoniker *This = impl_from_IROTData(iface); + IEnumMoniker *pEnumMk; + IMoniker *pmk; + HRESULT hr; + + TRACE("(%p, %u, %p)\n", pbData, cbMax, pcbData); + + *pcbData = sizeof(CLSID); + + hr = IMoniker_Enum(This, TRUE, &pEnumMk); + if (FAILED(hr)) return hr; + + while(IEnumMoniker_Next(pEnumMk, 1, &pmk, NULL) == S_OK) + { + IROTData *pROTData; + hr = IMoniker_QueryInterface(pmk, &IID_IROTData, (void **)&pROTData); + if (FAILED(hr)) + ERR("moniker doesn't support IROTData interface\n"); + + if (SUCCEEDED(hr)) + { + ULONG cbData; + hr = IROTData_GetComparisonData(pROTData, NULL, 0, &cbData); + IROTData_Release(pROTData); + if (SUCCEEDED(hr) || (hr == E_OUTOFMEMORY)) + { + *pcbData += cbData; + hr = S_OK; + } + else + ERR("IROTData_GetComparisonData failed with error 0x%08x\n", hr); + } + + IMoniker_Release(pmk); + + if (FAILED(hr)) + { + IEnumMoniker_Release(pEnumMk); + return hr; + } + } + if (cbMax < *pcbData) + return E_OUTOFMEMORY; + + IEnumMoniker_Reset(pEnumMk); + + memcpy(pbData, &CLSID_CompositeMoniker, sizeof(CLSID)); + pbData += sizeof(CLSID); + cbMax -= sizeof(CLSID); + + while (IEnumMoniker_Next(pEnumMk, 1, &pmk, NULL) == S_OK) + { + IROTData *pROTData; + hr = IMoniker_QueryInterface(pmk, &IID_IROTData, (void **)&pROTData); + if (FAILED(hr)) + ERR("moniker doesn't support IROTData interface\n"); + + if (SUCCEEDED(hr)) + { + ULONG cbData; + hr = IROTData_GetComparisonData(pROTData, pbData, cbMax, &cbData); + IROTData_Release(pROTData); + if (SUCCEEDED(hr)) + { + pbData += cbData; + cbMax -= cbData; + } + else + ERR("IROTData_GetComparisonData failed with error 0x%08x\n", hr); + } + + IMoniker_Release(pmk); + + if (FAILED(hr)) + { + IEnumMoniker_Release(pEnumMk); + return hr; + } + } + + IEnumMoniker_Release(pEnumMk); + + return S_OK; +} + +static HRESULT WINAPI CompositeMonikerMarshalImpl_QueryInterface(IMarshal *iface, REFIID riid, LPVOID *ppv) +{ + IMoniker *This = impl_from_IMarshal(iface); + + TRACE("(%p,%s,%p)\n",iface,debugstr_guid(riid),ppv); + + return CompositeMonikerImpl_QueryInterface(This, riid, ppv); +} + +static ULONG WINAPI CompositeMonikerMarshalImpl_AddRef(IMarshal *iface) +{ + IMoniker *This = impl_from_IMarshal(iface); + + TRACE("(%p)\n",iface); + + return CompositeMonikerImpl_AddRef(This); +} + +static ULONG WINAPI CompositeMonikerMarshalImpl_Release(IMarshal *iface) +{ + IMoniker *This = impl_from_IMarshal(iface); + + TRACE("(%p)\n",iface); + + return CompositeMonikerImpl_Release(This); +} + +static HRESULT WINAPI CompositeMonikerMarshalImpl_GetUnmarshalClass( + LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext, + void* pvDestContext, DWORD mshlflags, CLSID* pCid) +{ + IMoniker *This = impl_from_IMarshal(iface); + + TRACE("(%s, %p, %x, %p, %x, %p)\n", debugstr_guid(riid), pv, + dwDestContext, pvDestContext, mshlflags, pCid); + + return IMoniker_GetClassID(This, pCid); +} + +static HRESULT WINAPI CompositeMonikerMarshalImpl_GetMarshalSizeMax( + LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext, + void* pvDestContext, DWORD mshlflags, DWORD* pSize) +{ + IMoniker *This = impl_from_IMarshal(iface); + IEnumMoniker *pEnumMk; + IMoniker *pmk; + HRESULT hr; + ULARGE_INTEGER size; + + TRACE("(%s, %p, %x, %p, %x, %p)\n", debugstr_guid(riid), pv, + dwDestContext, pvDestContext, mshlflags, pSize); + + *pSize = 0x10; /* to match native */ + + hr = IMoniker_Enum(This, TRUE, &pEnumMk); + if (FAILED(hr)) return hr; + + hr = IMoniker_GetSizeMax(This, &size); + + while (IEnumMoniker_Next(pEnumMk, 1, &pmk, NULL) == S_OK) + { + ULONG size; + + hr = CoGetMarshalSizeMax(&size, &IID_IMoniker, (IUnknown *)pmk, dwDestContext, pvDestContext, mshlflags); + if (SUCCEEDED(hr)) + *pSize += size; + + IMoniker_Release(pmk); + + if (FAILED(hr)) + { + IEnumMoniker_Release(pEnumMk); + return hr; + } + } + + IEnumMoniker_Release(pEnumMk); + + return S_OK; +} + +static HRESULT WINAPI CompositeMonikerMarshalImpl_MarshalInterface(LPMARSHAL iface, IStream *pStm, + REFIID riid, void* pv, DWORD dwDestContext, + void* pvDestContext, DWORD mshlflags) +{ + IMoniker *This = impl_from_IMarshal(iface); + IEnumMoniker *pEnumMk; + IMoniker *pmk; + HRESULT hr; + ULONG i = 0; + + TRACE("(%p, %s, %p, %x, %p, %x)\n", pStm, debugstr_guid(riid), pv, + dwDestContext, pvDestContext, mshlflags); + + hr = IMoniker_Enum(This, TRUE, &pEnumMk); + if (FAILED(hr)) return hr; + + while (IEnumMoniker_Next(pEnumMk, 1, &pmk, NULL) == S_OK) + { + hr = CoMarshalInterface(pStm, &IID_IMoniker, (IUnknown *)pmk, dwDestContext, pvDestContext, mshlflags); + + IMoniker_Release(pmk); + + if (FAILED(hr)) + { + IEnumMoniker_Release(pEnumMk); + return hr; + } + i++; + } + + if (i != 2) + FIXME("moniker count of %d not supported\n", i); + + IEnumMoniker_Release(pEnumMk); + + return S_OK; +} + +static HRESULT WINAPI CompositeMonikerMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, void **ppv) +{ + CompositeMonikerImpl *This = (CompositeMonikerImpl *)impl_from_IMarshal(iface); + HRESULT hr; + + TRACE("(%p, %s, %p)\n", pStm, debugstr_guid(riid), ppv); + + CompositeMonikerImpl_ReleaseMonikersInTable(This); + + /* resize the table if needed */ + if (This->tabLastIndex + 2 > This->tabSize) + { + This->tabSize += max(BLOCK_TAB_SIZE, 2); + This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker)); + + if (This->tabMoniker==NULL) + return E_OUTOFMEMORY; + } + + hr = CoUnmarshalInterface(pStm, &IID_IMoniker, (void**)&This->tabMoniker[This->tabLastIndex]); + if (FAILED(hr)) + { + ERR("couldn't unmarshal moniker, hr = 0x%08x\n", hr); + return hr; + } + This->tabLastIndex++; + hr = CoUnmarshalInterface(pStm, &IID_IMoniker, (void**)&This->tabMoniker[This->tabLastIndex]); + if (FAILED(hr)) + { + ERR("couldn't unmarshal moniker, hr = 0x%08x\n", hr); + return hr; + } + This->tabLastIndex++; + + return IMoniker_QueryInterface((IMoniker *)&This->lpvtbl1, riid, ppv); +} + +static HRESULT WINAPI CompositeMonikerMarshalImpl_ReleaseMarshalData(LPMARSHAL iface, IStream *pStm) +{ + TRACE("(%p)\n", pStm); + /* can't release a state-based marshal as nothing on server side to + * release */ + return S_OK; +} + +static HRESULT WINAPI CompositeMonikerMarshalImpl_DisconnectObject(LPMARSHAL iface, DWORD dwReserved) +{ + TRACE("(0x%x)\n", dwReserved); + /* can't disconnect a state-based marshal as nothing on server side to + * disconnect from */ + return S_OK; } /****************************************************************************** @@ -1337,8 +1584,10 @@ EnumMonikerImpl_Next(IEnumMoniker* iface,ULONG celt, IMoniker** rgelt, /* retrieve the requested number of moniker from the current position */ for(i=0;((This->currentPos < This->tabSize) && (i < celt));i++) - + { rgelt[i]=This->tabMoniker[This->currentPos++]; + IMoniker_AddRef(rgelt[i]); + } if (pceltFethed!=NULL) *pceltFethed= i; @@ -1423,7 +1672,7 @@ EnumMonikerImpl_CreateEnumMoniker(IMoniker** tabMoniker, ULONG tabSize, /* Initialize the virtual function table. */ newEnumMoniker->lpVtbl = &VT_EnumMonikerImpl; - newEnumMoniker->ref = 0; + newEnumMoniker->ref = 1; newEnumMoniker->tabSize=tabSize; newEnumMoniker->currentPos=currentPos; @@ -1491,27 +1740,47 @@ static const IROTDataVtbl VT_ROTDataImpl = CompositeMonikerROTDataImpl_QueryInterface, CompositeMonikerROTDataImpl_AddRef, CompositeMonikerROTDataImpl_Release, - CompositeMonikerROTDataImpl_GetComparaisonData + CompositeMonikerROTDataImpl_GetComparisonData +}; + +static const IMarshalVtbl VT_MarshalImpl = +{ + CompositeMonikerMarshalImpl_QueryInterface, + CompositeMonikerMarshalImpl_AddRef, + CompositeMonikerMarshalImpl_Release, + CompositeMonikerMarshalImpl_GetUnmarshalClass, + CompositeMonikerMarshalImpl_GetMarshalSizeMax, + CompositeMonikerMarshalImpl_MarshalInterface, + CompositeMonikerMarshalImpl_UnmarshalInterface, + CompositeMonikerMarshalImpl_ReleaseMarshalData, + CompositeMonikerMarshalImpl_DisconnectObject }; /****************************************************************************** * Composite-Moniker_Construct (local function) *******************************************************************************/ static HRESULT -CompositeMonikerImpl_Construct(CompositeMonikerImpl* This, +CompositeMonikerImpl_Construct(IMoniker** ppMoniker, LPMONIKER pmkFirst, LPMONIKER pmkRest) { DWORD mkSys; IEnumMoniker *enumMoniker; IMoniker *tempMk; HRESULT res; + CompositeMonikerImpl *This; + + This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); + + if (!This) + return E_OUTOFMEMORY; TRACE("(%p,%p,%p)\n",This,pmkFirst,pmkRest); /* Initialize the virtual function table. */ This->lpvtbl1 = &VT_CompositeMonikerImpl; This->lpvtbl2 = &VT_ROTDataImpl; - This->ref = 0; + This->lpvtblMarshal= &VT_MarshalImpl; + This->ref = 1; This->tabSize=BLOCK_TAB_SIZE; This->tabLastIndex=0; @@ -1520,6 +1789,12 @@ CompositeMonikerImpl_Construct(CompositeMonikerImpl* This, if (This->tabMoniker==NULL) return E_OUTOFMEMORY; + if (!pmkFirst && !pmkRest) + { + *ppMoniker = (IMoniker *)This; + return S_OK; + } + IMoniker_IsSystemMoniker(pmkFirst,&mkSys); /* put the first moniker contents in the beginning of the table */ @@ -1637,6 +1912,16 @@ CompositeMonikerImpl_Construct(CompositeMonikerImpl* This, IEnumMoniker_Release(enumMoniker); } + /* only one moniker, then just return it */ + if (This->tabLastIndex == 1) + { + *ppMoniker = This->tabMoniker[0]; + IMoniker_AddRef(*ppMoniker); + IMoniker_Release((IMoniker *)This); + } + else + *ppMoniker = (IMoniker *)This; + return S_OK; } @@ -1647,7 +1932,7 @@ HRESULT WINAPI CreateGenericComposite(LPMONIKER pmkFirst, LPMONIKER pmkRest, LPMONIKER* ppmkComposite) { - CompositeMonikerImpl* newCompositeMoniker = 0; + IMoniker* moniker = 0; HRESULT hr = S_OK; TRACE("(%p,%p,%p)\n",pmkFirst,pmkRest,ppmkComposite); @@ -1669,24 +1954,13 @@ CreateGenericComposite(LPMONIKER pmkFirst, LPMONIKER pmkRest, else if (pmkFirst==NULL && pmkRest==NULL) return S_OK; - newCompositeMoniker = HeapAlloc(GetProcessHeap(), 0,sizeof(CompositeMonikerImpl)); + hr = CompositeMonikerImpl_Construct(&moniker,pmkFirst,pmkRest); - if (newCompositeMoniker == 0) - return STG_E_INSUFFICIENTMEMORY; - - hr = CompositeMonikerImpl_Construct(newCompositeMoniker,pmkFirst,pmkRest); - - if (FAILED(hr)){ - - HeapFree(GetProcessHeap(),0,newCompositeMoniker); + if (FAILED(hr)) return hr; - } - if (newCompositeMoniker->tabLastIndex==1) - hr = IMoniker_QueryInterface(newCompositeMoniker->tabMoniker[0],&IID_IMoniker,(void**)ppmkComposite); - else - - hr = IMoniker_QueryInterface((IMoniker*)newCompositeMoniker,&IID_IMoniker,(void**)ppmkComposite); + hr = IMoniker_QueryInterface(moniker,&IID_IMoniker,(void**)ppmkComposite); + IMoniker_Release(moniker); return hr; } @@ -1700,3 +1974,71 @@ MonikerCommonPrefixWith(IMoniker* pmkThis,IMoniker* pmkOther,IMoniker** ppmkComm FIXME("(),stub!\n"); return E_NOTIMPL; } + +static HRESULT WINAPI CompositeMonikerCF_QueryInterface(LPCLASSFACTORY iface, + REFIID riid, LPVOID *ppv) +{ + *ppv = NULL; + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory)) + { + *ppv = iface; + IUnknown_AddRef(iface); + return S_OK; + } + return E_NOINTERFACE; +} + +static ULONG WINAPI CompositeMonikerCF_AddRef(LPCLASSFACTORY iface) +{ + return 2; /* non-heap based object */ +} + +static ULONG WINAPI CompositeMonikerCF_Release(LPCLASSFACTORY iface) +{ + return 1; /* non-heap based object */ +} + +static HRESULT WINAPI CompositeMonikerCF_CreateInstance(LPCLASSFACTORY iface, + LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv) +{ + IMoniker* pMoniker; + HRESULT hr; + + TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv); + + *ppv = NULL; + + if (pUnk) + return CLASS_E_NOAGGREGATION; + + hr = CompositeMonikerImpl_Construct(&pMoniker, NULL, NULL); + + if (SUCCEEDED(hr)) + { + hr = IMoniker_QueryInterface(pMoniker, riid, ppv); + IMoniker_Release(pMoniker); + } + + return hr; +} + +static HRESULT WINAPI CompositeMonikerCF_LockServer(LPCLASSFACTORY iface, BOOL fLock) +{ + FIXME("(%d), stub!\n",fLock); + return S_OK; +} + +static const IClassFactoryVtbl CompositeMonikerCFVtbl = +{ + CompositeMonikerCF_QueryInterface, + CompositeMonikerCF_AddRef, + CompositeMonikerCF_Release, + CompositeMonikerCF_CreateInstance, + CompositeMonikerCF_LockServer +}; +static const IClassFactoryVtbl *CompositeMonikerCF = &CompositeMonikerCFVtbl; + +HRESULT CompositeMonikerCF_Create(REFIID riid, LPVOID *ppv) +{ + return IClassFactory_QueryInterface((IClassFactory *)&CompositeMonikerCF, riid, ppv); +} diff --git a/reactos/dll/win32/ole32/datacache.c b/reactos/dll/win32/ole32/datacache.c index a3beacab4ee..249882e8597 100644 --- a/reactos/dll/win32/ole32/datacache.c +++ b/reactos/dll/win32/ole32/datacache.c @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * NOTES: * The OLE2 data cache supports a whole whack of @@ -43,7 +43,6 @@ * header. I was able to figure-out where the extent of the object * was stored and the aspect, but that's about it. */ -#include #include #include @@ -58,6 +57,7 @@ #include "winerror.h" #include "wine/unicode.h" #include "ole2.h" +#include "wine/list.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(ole); @@ -67,24 +67,50 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole); * * This structure represents the header of the \002OlePresXXX stream in * the OLE object strorage. - * - * Most fields are still unknown. */ typedef struct PresentationDataHeader { - DWORD unknown1; /* -1 */ - DWORD unknown2; /* 3, possibly CF_METAFILEPICT */ + /* clipformat: + * - standard clipformat: + * DWORD length = 0xffffffff; + * DWORD cfFormat; + * - or custom clipformat: + * DWORD length; + * CHAR format_name[length]; (null-terminated) + */ DWORD unknown3; /* 4, possibly TYMED_ISTREAM */ DVASPECT dvAspect; - DWORD unknown5; /* -1 */ - - DWORD unknown6; + DWORD lindex; + DWORD tymed; DWORD unknown7; /* 0 */ DWORD dwObjectExtentX; DWORD dwObjectExtentY; DWORD dwSize; } PresentationDataHeader; +typedef struct DataCacheEntry +{ + struct list entry; + /* format of this entry */ + FORMATETC fmtetc; + /* the clipboard format of the data */ + CLIPFORMAT data_cf; + /* cached data */ + STGMEDIUM stgmedium; + /* + * This storage pointer is set through a call to + * IPersistStorage_Load. This is where the visual + * representation of the object is stored. + */ + IStorage *storage; + /* connection ID */ + DWORD id; + /* dirty flag */ + BOOL dirty; + /* stream number (-1 if not set ) */ + unsigned short stream_number; +} DataCacheEntry; + /**************************************************************************** * DataCache */ @@ -110,13 +136,6 @@ struct DataCache */ IUnknown* outerUnknown; - /* - * This storage pointer is set through a call to - * IPersistStorage_Load. This is where the visual - * representation of the object is stored. - */ - IStorage* presentationStorage; - /* * The user of this object can setup ONE advise sink * connection with the object. These parameters describe @@ -125,7 +144,14 @@ struct DataCache DWORD sinkAspects; DWORD sinkAdviseFlag; IAdviseSink* sinkInterface; + IStorage *presentationStorage; + /* list of cache entries */ + struct list cache_list; + /* last id assigned to an entry */ + DWORD last_cache_id; + /* dirty flag */ + BOOL dirty; }; typedef struct DataCache DataCache; @@ -167,19 +193,36 @@ static inline DataCache *impl_from_IOleCacheControl( IOleCacheControl *iface ) return (DataCache *)((char*)iface - FIELD_OFFSET(DataCache, lpvtblIOleCacheControl)); } +static const char * debugstr_formatetc(const FORMATETC *formatetc) +{ + return wine_dbg_sprintf("{ cfFormat = 0x%x, ptd = %p, dwAspect = %d, lindex = %d, tymed = %d }", + formatetc->cfFormat, formatetc->ptd, formatetc->dwAspect, + formatetc->lindex, formatetc->tymed); +} /* * Prototypes for the methods of the DataCache class. */ static DataCache* DataCache_Construct(REFCLSID clsid, LPUNKNOWN pUnkOuter); -static HRESULT DataCache_OpenPresStream(DataCache *this, - DWORD drawAspect, +static HRESULT DataCacheEntry_OpenPresStream(DataCacheEntry *This, IStream **pStm); +static void DataCacheEntry_Destroy(DataCacheEntry *This) +{ + list_remove(&This->entry); + if (This->storage) + IStorage_Release(This->storage); + HeapFree(GetProcessHeap(), 0, This->fmtetc.ptd); + ReleaseStgMedium(&This->stgmedium); + HeapFree(GetProcessHeap(), 0, This); +} + static void DataCache_Destroy( DataCache* ptrToDestroy) { + DataCacheEntry *cache_entry, *next_cache_entry; + TRACE("()\n"); if (ptrToDestroy->sinkInterface != NULL) @@ -188,11 +231,8 @@ static void DataCache_Destroy( ptrToDestroy->sinkInterface = NULL; } - if (ptrToDestroy->presentationStorage != NULL) - { - IStorage_Release(ptrToDestroy->presentationStorage); - ptrToDestroy->presentationStorage = NULL; - } + LIST_FOR_EACH_ENTRY_SAFE(cache_entry, next_cache_entry, &ptrToDestroy->cache_list, DataCacheEntry, entry) + DataCacheEntry_Destroy(cache_entry); /* * Free the datacache pointer. @@ -200,60 +240,69 @@ static void DataCache_Destroy( HeapFree(GetProcessHeap(), 0, ptrToDestroy); } -/************************************************************************ - * DataCache_ReadPresentationData - * - * This method will read information for the requested presentation - * into the given structure. - * - * Param: - * this - Pointer to the DataCache object - * drawAspect - The aspect of the object that we wish to draw. - * header - The structure containing information about this - * aspect of the object. - */ -static HRESULT DataCache_ReadPresentationData( - DataCache* this, - DWORD drawAspect, - PresentationDataHeader* header) +static DataCacheEntry *DataCache_GetEntryForFormatEtc(DataCache *This, const FORMATETC *formatetc) { - IStream* presStream = NULL; - HRESULT hres; + DataCacheEntry *cache_entry; + LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry) + { + /* FIXME: also compare DVTARGETDEVICEs */ + if ((!cache_entry->fmtetc.cfFormat || !formatetc->cfFormat || (formatetc->cfFormat == cache_entry->fmtetc.cfFormat)) && + (formatetc->dwAspect == cache_entry->fmtetc.dwAspect) && + (formatetc->lindex == cache_entry->fmtetc.lindex) && + (!cache_entry->fmtetc.tymed || !formatetc->tymed || (formatetc->tymed == cache_entry->fmtetc.tymed))) + return cache_entry; + } + return NULL; +} - /* - * Open the presentation stream. - */ - hres = DataCache_OpenPresStream( - this, - drawAspect, - &presStream); +/* checks that the clipformat and tymed are valid and returns an error if they +* aren't and CACHE_S_NOTSUPPORTED if they are valid, but can't be rendered by +* DataCache_Draw */ +static HRESULT check_valid_clipformat_and_tymed(CLIPFORMAT cfFormat, DWORD tymed) +{ + if (!cfFormat || !tymed || + (cfFormat == CF_METAFILEPICT && tymed == TYMED_MFPICT) || + (cfFormat == CF_BITMAP && tymed == TYMED_GDI) || + (cfFormat == CF_DIB && tymed == TYMED_HGLOBAL) || + (cfFormat == CF_ENHMETAFILE && tymed == TYMED_ENHMF)) + return S_OK; + else if (tymed == TYMED_HGLOBAL) + return CACHE_S_FORMATETC_NOTSUPPORTED; + else + { + WARN("invalid clipformat/tymed combination: %d/%d\n", cfFormat, tymed); + return DV_E_TYMED; + } +} - if (FAILED(hres)) - return hres; +static HRESULT DataCache_CreateEntry(DataCache *This, const FORMATETC *formatetc, DataCacheEntry **cache_entry) +{ + HRESULT hr; - /* - * Read the header. - */ + hr = check_valid_clipformat_and_tymed(formatetc->cfFormat, formatetc->tymed); + if (FAILED(hr)) + return hr; + if (hr == CACHE_S_FORMATETC_NOTSUPPORTED) + TRACE("creating unsupported format %d\n", formatetc->cfFormat); - hres = IStream_Read( - presStream, - header, - sizeof(PresentationDataHeader), - NULL); + *cache_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(**cache_entry)); + if (!*cache_entry) + return E_OUTOFMEMORY; - /* - * Cleanup. - */ - IStream_Release(presStream); - - /* - * We don't want to propagate any other error - * code than a failure. - */ - if (hres!=S_OK) - hres = E_FAIL; - - return hres; + (*cache_entry)->fmtetc = *formatetc; + if (formatetc->ptd) + { + (*cache_entry)->fmtetc.ptd = HeapAlloc(GetProcessHeap(), 0, formatetc->ptd->tdSize); + memcpy((*cache_entry)->fmtetc.ptd, formatetc->ptd, formatetc->ptd->tdSize); + } + (*cache_entry)->stgmedium.tymed = TYMED_NULL; + (*cache_entry)->stgmedium.pUnkForRelease = NULL; + (*cache_entry)->storage = NULL; + (*cache_entry)->id = This->last_cache_id++; + (*cache_entry)->dirty = TRUE; + (*cache_entry)->stream_number = -1; + list_add_tail(&This->cache_list, &(*cache_entry)->entry); + return hr; } /************************************************************************ @@ -269,7 +318,7 @@ static void DataCache_FireOnViewChange( DWORD aspect, LONG lindex) { - TRACE("(%p, %lx, %ld)\n", this, aspect, lindex); + TRACE("(%p, %x, %d)\n", this, aspect, lindex); /* * The sink supplies a filter when it registers @@ -300,7 +349,7 @@ static void DataCache_FireOnViewChange( } } -/* Helper for DataCache_OpenPresStream */ +/* Helper for DataCacheEntry_OpenPresStream */ static BOOL DataCache_IsPresentationStream(const STATSTG *elem) { /* The presentation streams have names of the form "\002OlePresXXX", @@ -310,7 +359,6 @@ static BOOL DataCache_IsPresentationStream(const STATSTG *elem) LPCWSTR name = elem->pwcsName; return (elem->type == STGTY_STREAM) - && (elem->cbSize.u.LowPart >= sizeof(PresentationDataHeader)) && (strlenW(name) == 11) && (strncmpW(name, OlePres, 8) == 0) && (name[8] >= '0') && (name[8] <= '9') @@ -318,8 +366,73 @@ static BOOL DataCache_IsPresentationStream(const STATSTG *elem) && (name[10] >= '0') && (name[10] <= '9'); } +static HRESULT read_clipformat(IStream *stream, CLIPFORMAT *clipformat) +{ + DWORD length; + HRESULT hr; + ULONG read; + + *clipformat = 0; + + hr = IStream_Read(stream, &length, sizeof(length), &read); + if (hr != S_OK || read != sizeof(length)) + return DV_E_CLIPFORMAT; + if (length == -1) + { + DWORD cf; + hr = IStream_Read(stream, &cf, sizeof(cf), 0); + if (hr != S_OK || read != sizeof(cf)) + return DV_E_CLIPFORMAT; + *clipformat = cf; + } + else + { + char *format_name = HeapAlloc(GetProcessHeap(), 0, length); + if (!format_name) + return E_OUTOFMEMORY; + hr = IStream_Read(stream, format_name, length, &read); + if (hr != S_OK || read != length || format_name[length - 1] != '\0') + { + HeapFree(GetProcessHeap(), 0, format_name); + return DV_E_CLIPFORMAT; + } + *clipformat = RegisterClipboardFormatA(format_name); + HeapFree(GetProcessHeap(), 0, format_name); + } + return S_OK; +} + +static HRESULT write_clipformat(IStream *stream, CLIPFORMAT clipformat) +{ + DWORD length; + HRESULT hr; + + if (clipformat < 0xc000) + length = -1; + else + length = GetClipboardFormatNameA(clipformat, NULL, 0); + hr = IStream_Write(stream, &length, sizeof(length), NULL); + if (FAILED(hr)) + return hr; + if (clipformat < 0xc000) + { + DWORD cf = clipformat; + hr = IStream_Write(stream, &cf, sizeof(cf), NULL); + } + else + { + char *format_name = HeapAlloc(GetProcessHeap(), 0, length); + if (!format_name) + return E_OUTOFMEMORY; + GetClipboardFormatNameA(clipformat, format_name, length); + hr = IStream_Write(stream, format_name, length, NULL); + HeapFree(GetProcessHeap(), 0, format_name); + } + return hr; +} + /************************************************************************ - * DataCache_OpenPresStream + * DataCacheEntry_OpenPresStream * * This method will find the stream for the given presentation. It makes * no attempt at fallback. @@ -338,14 +451,13 @@ static BOOL DataCache_IsPresentationStream(const STATSTG *elem) * Notes: * Algorithm: Scan the elements of the presentation storage, looking * for presentation streams. For each presentation stream, - * load the header and check to see if the aspect maches. + * load the header and check to see if the aspect matches. * * If a fallback is desired, just opening the first presentation stream * is a possibility. */ -static HRESULT DataCache_OpenPresStream( - DataCache *this, - DWORD drawAspect, +static HRESULT DataCacheEntry_OpenPresStream( + DataCacheEntry *This, IStream **ppStm) { STATSTG elem; @@ -354,7 +466,7 @@ static HRESULT DataCache_OpenPresStream( if (!ppStm) return E_POINTER; - hr = IStorage_EnumElements(this->presentationStorage, 0, NULL, 0, &pEnum); + hr = IStorage_EnumElements(This->storage, 0, NULL, 0, &pEnum); if (FAILED(hr)) return hr; while ((hr = IEnumSTATSTG_Next(pEnum, 1, &elem, NULL)) == S_OK) @@ -363,19 +475,23 @@ static HRESULT DataCache_OpenPresStream( { IStream *pStm; - hr = IStorage_OpenStream(this->presentationStorage, elem.pwcsName, + hr = IStorage_OpenStream(This->storage, elem.pwcsName, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStm); if (SUCCEEDED(hr)) { PresentationDataHeader header; ULONG actual_read; + CLIPFORMAT clipformat; - hr = IStream_Read(pStm, &header, sizeof(header), &actual_read); + hr = read_clipformat(pStm, &clipformat); + + if (hr == S_OK) + hr = IStream_Read(pStm, &header, sizeof(header), &actual_read); /* can't use SUCCEEDED(hr): S_FALSE counts as an error */ if (hr == S_OK && actual_read == sizeof(header) - && header.dvAspect == drawAspect) + && header.dvAspect == This->fmtetc.dwAspect) { /* Rewind the stream before returning it. */ LARGE_INTEGER offset; @@ -404,40 +520,40 @@ static HRESULT DataCache_OpenPresStream( } /************************************************************************ - * DataCache_ReadPresentationData + * DataCacheEntry_LoadData * * This method will read information for the requested presentation * into the given structure. * * Param: - * this - Pointer to the DataCache object - * drawAspect - The aspect of the object that we wish to draw. + * This - The entry to load the data from. * * Returns: * This method returns a metafile handle if it is successful. * it will return 0 if not. */ -static HMETAFILE DataCache_ReadPresMetafile( - DataCache* this, - DWORD drawAspect) +static HRESULT DataCacheEntry_LoadData(DataCacheEntry *This) { - LARGE_INTEGER offset; IStream* presStream = NULL; HRESULT hres; - void* metafileBits; + ULARGE_INTEGER current_pos; STATSTG streamInfo; - HMETAFILE newMetafile = 0; + void* metafileBits; + METAFILEPICT *mfpict; + HGLOBAL hmfpict; + PresentationDataHeader header; + CLIPFORMAT clipformat; + static const LARGE_INTEGER offset_zero; /* * Open the presentation stream. */ - hres = DataCache_OpenPresStream( - this, - drawAspect, + hres = DataCacheEntry_OpenPresStream( + This, &presStream); if (FAILED(hres)) - return (HMETAFILE)hres; + return hres; /* * Get the size of the stream. @@ -447,18 +563,38 @@ static HMETAFILE DataCache_ReadPresMetafile( STATFLAG_NONAME); /* - * Skip the header + * Read the header. */ - offset.u.HighPart = 0; - offset.u.LowPart = sizeof(PresentationDataHeader); - hres = IStream_Seek( - presStream, - offset, - STREAM_SEEK_SET, - NULL); + hres = read_clipformat(presStream, &clipformat); + if (FAILED(hres)) + { + IStream_Release(presStream); + return hres; + } - streamInfo.cbSize.u.LowPart -= offset.u.LowPart; + hres = IStream_Read( + presStream, + &header, + sizeof(PresentationDataHeader), + NULL); + if (hres != S_OK) + { + IStream_Release(presStream); + return E_FAIL; + } + + hres = IStream_Seek(presStream, offset_zero, STREAM_SEEK_CUR, ¤t_pos); + + streamInfo.cbSize.QuadPart -= current_pos.QuadPart; + + hmfpict = GlobalAlloc(GMEM_MOVEABLE, sizeof(METAFILEPICT)); + if (!hmfpict) + { + IStream_Release(presStream); + return E_OUTOFMEMORY; + } + mfpict = GlobalLock(hmfpict); /* * Allocate a buffer for the metafile bits. @@ -481,19 +617,237 @@ static HMETAFILE DataCache_ReadPresMetafile( */ if (SUCCEEDED(hres)) { - newMetafile = SetMetaFileBitsEx(streamInfo.cbSize.u.LowPart, metafileBits); + /* FIXME: get this from the stream */ + mfpict->mm = MM_ANISOTROPIC; + mfpict->xExt = header.dwObjectExtentX; + mfpict->yExt = header.dwObjectExtentY; + mfpict->hMF = SetMetaFileBitsEx(streamInfo.cbSize.u.LowPart, metafileBits); + if (!mfpict->hMF) + hres = E_FAIL; } + GlobalUnlock(hmfpict); + if (SUCCEEDED(hres)) + { + This->data_cf = This->fmtetc.cfFormat; + This->stgmedium.tymed = TYMED_MFPICT; + This->stgmedium.u.hMetaFilePict = hmfpict; + } + else + GlobalFree(hmfpict); + /* * Cleanup. */ HeapFree(GetProcessHeap(), 0, metafileBits); IStream_Release(presStream); - if (newMetafile==0) - hres = E_FAIL; + return hres; +} - return newMetafile; +static HRESULT DataCacheEntry_CreateStream(DataCacheEntry *This, + IStorage *storage, IStream **stream) +{ + HRESULT hr; + WCHAR wszName[] = {2,'O','l','e','P','r','e','s', + '0' + (This->stream_number / 100) % 10, + '0' + (This->stream_number / 10) % 10, + '0' + This->stream_number % 10, 0}; + + /* FIXME: cache the created stream in This? */ + hr = IStorage_CreateStream(storage, wszName, + STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE, + 0, 0, stream); + return hr; +} + +static HRESULT DataCacheEntry_Save(DataCacheEntry *This, IStorage *storage, + BOOL same_as_load) +{ + PresentationDataHeader header; + HRESULT hr; + IStream *pres_stream; + void *data = NULL; + + TRACE("stream_number = %d, fmtetc = %s\n", This->stream_number, debugstr_formatetc(&This->fmtetc)); + + hr = DataCacheEntry_CreateStream(This, storage, &pres_stream); + if (FAILED(hr)) + return hr; + + hr = write_clipformat(pres_stream, This->data_cf); + if (FAILED(hr)) + return hr; + + if (This->fmtetc.ptd) + FIXME("ptd not serialized\n"); + header.unknown3 = 4; + header.dvAspect = This->fmtetc.dwAspect; + header.lindex = This->fmtetc.lindex; + header.tymed = This->stgmedium.tymed; + header.unknown7 = 0; + header.dwObjectExtentX = 0; + header.dwObjectExtentY = 0; + header.dwSize = 0; + + /* size the data */ + switch (This->data_cf) + { + case CF_METAFILEPICT: + { + if (This->stgmedium.tymed != TYMED_NULL) + { + const METAFILEPICT *mfpict = GlobalLock(This->stgmedium.u.hMetaFilePict); + if (!mfpict) + { + IStream_Release(pres_stream); + return DV_E_STGMEDIUM; + } + header.dwObjectExtentX = mfpict->xExt; + header.dwObjectExtentY = mfpict->yExt; + header.dwSize = GetMetaFileBitsEx(mfpict->hMF, 0, NULL); + GlobalUnlock(This->stgmedium.u.hMetaFilePict); + } + break; + } + default: + break; + } + + /* + * Write the header. + */ + hr = IStream_Write(pres_stream, &header, sizeof(PresentationDataHeader), + NULL); + if (FAILED(hr)) + { + IStream_Release(pres_stream); + return hr; + } + + /* get the data */ + switch (This->data_cf) + { + case CF_METAFILEPICT: + { + if (This->stgmedium.tymed != TYMED_NULL) + { + const METAFILEPICT *mfpict = GlobalLock(This->stgmedium.u.hMetaFilePict); + if (!mfpict) + { + IStream_Release(pres_stream); + return DV_E_STGMEDIUM; + } + data = HeapAlloc(GetProcessHeap(), 0, header.dwSize); + GetMetaFileBitsEx(mfpict->hMF, header.dwSize, data); + GlobalUnlock(This->stgmedium.u.hMetaFilePict); + } + break; + } + default: + break; + } + + if (data) + hr = IStream_Write(pres_stream, data, header.dwSize, NULL); + + IStream_Release(pres_stream); + return hr; +} + +/* helper for copying STGMEDIUM of type bitmap, MF, EMF or HGLOBAL. +* does no checking of whether src_stgm has a supported tymed, so this should be +* done in the caller */ +static HRESULT copy_stg_medium(CLIPFORMAT cf, STGMEDIUM *dest_stgm, + const STGMEDIUM *src_stgm) +{ + if (src_stgm->tymed == TYMED_MFPICT) + { + const METAFILEPICT *src_mfpict = GlobalLock(src_stgm->u.hMetaFilePict); + METAFILEPICT *dest_mfpict; + + if (!src_mfpict) + return DV_E_STGMEDIUM; + dest_stgm->u.hMetaFilePict = GlobalAlloc(GMEM_MOVEABLE, sizeof(METAFILEPICT)); + dest_mfpict = GlobalLock(dest_stgm->u.hMetaFilePict); + if (!dest_mfpict) + { + GlobalUnlock(src_stgm->u.hMetaFilePict); + return E_OUTOFMEMORY; + } + *dest_mfpict = *src_mfpict; + dest_mfpict->hMF = CopyMetaFileW(src_mfpict->hMF, NULL); + GlobalUnlock(src_stgm->u.hMetaFilePict); + GlobalUnlock(dest_stgm->u.hMetaFilePict); + } + else if (src_stgm->tymed != TYMED_NULL) + { + dest_stgm->u.hGlobal = OleDuplicateData(src_stgm->u.hGlobal, cf, + GMEM_MOVEABLE); + if (!dest_stgm->u.hGlobal) + return E_OUTOFMEMORY; + } + dest_stgm->tymed = src_stgm->tymed; + dest_stgm->pUnkForRelease = src_stgm->pUnkForRelease; + if (dest_stgm->pUnkForRelease) + IUnknown_AddRef(dest_stgm->pUnkForRelease); + return S_OK; +} + +static HRESULT DataCacheEntry_SetData(DataCacheEntry *This, + const FORMATETC *formatetc, + const STGMEDIUM *stgmedium, + BOOL fRelease) +{ + if ((!This->fmtetc.cfFormat && !formatetc->cfFormat) || + (This->fmtetc.tymed == TYMED_NULL && formatetc->tymed == TYMED_NULL) || + stgmedium->tymed == TYMED_NULL) + { + WARN("invalid formatetc\n"); + return DV_E_FORMATETC; + } + + This->dirty = TRUE; + ReleaseStgMedium(&This->stgmedium); + This->data_cf = This->fmtetc.cfFormat ? This->fmtetc.cfFormat : formatetc->cfFormat; + if (fRelease) + { + This->stgmedium = *stgmedium; + return S_OK; + } + else + return copy_stg_medium(This->data_cf, + &This->stgmedium, stgmedium); +} + +static HRESULT DataCacheEntry_GetData(DataCacheEntry *This, + STGMEDIUM *stgmedium) +{ + if (stgmedium->tymed == TYMED_NULL && This->storage) + { + HRESULT hr = DataCacheEntry_LoadData(This); + if (FAILED(hr)) + return hr; + } + if (stgmedium->tymed == TYMED_NULL) + return OLE_E_BLANK; + return copy_stg_medium(This->data_cf, stgmedium, &This->stgmedium); +} + +static inline HRESULT DataCacheEntry_DiscardData(DataCacheEntry *This) +{ + ReleaseStgMedium(&This->stgmedium); + This->data_cf = This->fmtetc.cfFormat; + return S_OK; +} + +static inline void DataCacheEntry_HandsOffStorage(DataCacheEntry *This) +{ + if (This->storage) + { + IStorage_Release(This->storage); + This->storage = NULL; + } } /********************************************************* @@ -669,104 +1023,22 @@ static ULONG WINAPI DataCache_IDataObject_Release( * * Get Data from a source dataobject using format pformatetcIn->cfFormat * See Windows documentation for more details on GetData. - * TODO: Currently only CF_METAFILEPICT is implemented */ static HRESULT WINAPI DataCache_GetData( IDataObject* iface, LPFORMATETC pformatetcIn, STGMEDIUM* pmedium) { - HRESULT hr = 0; - HRESULT hrRet = E_UNEXPECTED; - IPersistStorage *pPersistStorage = 0; - IStorage *pStorage = 0; - IStream *pStream = 0; - OLECHAR name[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0}; - HGLOBAL hGlobalMF = 0; - void *mfBits = 0; - PresentationDataHeader pdh; - METAFILEPICT *mfPict; - HMETAFILE hMetaFile = 0; + DataCache *This = impl_from_IDataObject(iface); + DataCacheEntry *cache_entry; - if (pformatetcIn->cfFormat == CF_METAFILEPICT) - { - /* Get the Persist Storage */ + memset(pmedium, 0, sizeof(*pmedium)); - hr = IDataObject_QueryInterface(iface, &IID_IPersistStorage, (void**)&pPersistStorage); + cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetcIn); + if (!cache_entry) + return OLE_E_BLANK; - if (hr != S_OK) - goto cleanup; - - /* Create a doc file to copy the doc to a storage */ - - hr = StgCreateDocfile(NULL, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pStorage); - - if (hr != S_OK) - goto cleanup; - - /* Save it to storage */ - - hr = OleSave(pPersistStorage, pStorage, FALSE); - - if (hr != S_OK) - goto cleanup; - - /* Open the Presentation data srteam */ - - hr = IStorage_OpenStream(pStorage, name, 0, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &pStream); - - if (hr != S_OK) - goto cleanup; - - /* Read the presentation header */ - - hr = IStream_Read(pStream, &pdh, sizeof(PresentationDataHeader), NULL); - - if (hr != S_OK) - goto cleanup; - - mfBits = HeapAlloc(GetProcessHeap(), 0, pdh.dwSize); - - /* Read the Metafile bits */ - - hr = IStream_Read(pStream, mfBits, pdh.dwSize, NULL); - - if (hr != S_OK) - goto cleanup; - - /* Create the metafile and place it in the STGMEDIUM structure */ - - hMetaFile = SetMetaFileBitsEx(pdh.dwSize, mfBits); - - hGlobalMF = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, sizeof(METAFILEPICT)); - mfPict = (METAFILEPICT *)GlobalLock(hGlobalMF); - mfPict->hMF = hMetaFile; - - GlobalUnlock(hGlobalMF); - - pmedium->u.hGlobal = hGlobalMF; - pmedium->tymed = TYMED_MFPICT; - hrRet = S_OK; - -cleanup: - - HeapFree(GetProcessHeap(), 0, mfBits); - - if (pStream) - IStream_Release(pStream); - - if (pStorage) - IStorage_Release(pStorage); - - if (pPersistStorage) - IPersistStorage_Release(pPersistStorage); - - return hrRet; - } - - /* TODO: Other formats are not implemented */ - - return E_NOTIMPL; + return DataCacheEntry_GetData(cache_entry, pmedium); } static HRESULT WINAPI DataCache_GetDataHere( @@ -953,24 +1225,51 @@ static HRESULT WINAPI DataCache_GetClassID( IPersistStorage* iface, CLSID* pClassID) { + DataCache *This = impl_from_IPersistStorage(iface); + DataCacheEntry *cache_entry; + TRACE("(%p, %p)\n", iface, pClassID); - return E_NOTIMPL; + + LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry) + { + if (cache_entry->storage != NULL) + { + STATSTG statstg; + HRESULT hr = IStorage_Stat(cache_entry->storage, &statstg, STATFLAG_NONAME); + if (SUCCEEDED(hr)) + { + memcpy(pClassID, &statstg.clsid, sizeof(*pClassID)); + return S_OK; + } + } + } + + memcpy(pClassID, &CLSID_NULL, sizeof(*pClassID)); + + return S_OK; } /************************************************************************ * DataCache_IsDirty (IPersistStorage) * - * Until we actully connect to a running object and retrieve new - * information to it, we never get dirty. - * * See Windows documentation for more details on IPersistStorage methods. */ static HRESULT WINAPI DataCache_IsDirty( IPersistStorage* iface) { - TRACE("(%p)\n", iface); + DataCache *This = impl_from_IPersistStorage(iface); + DataCacheEntry *cache_entry; - return S_FALSE; + TRACE("(%p)\n", iface); + + if (This->dirty) + return S_OK; + + LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry) + if (cache_entry->dirty) + return S_OK; + + return S_FALSE; } /************************************************************************ @@ -985,9 +1284,19 @@ static HRESULT WINAPI DataCache_InitNew( IPersistStorage* iface, IStorage* pStg) { - TRACE("(%p, %p)\n", iface, pStg); + DataCache *This = impl_from_IPersistStorage(iface); - return IPersistStorage_Load(iface, pStg); + TRACE("(%p, %p)\n", iface, pStg); + + if (This->presentationStorage != NULL) + IStorage_Release(This->presentationStorage); + + This->presentationStorage = pStg; + + IStorage_AddRef(This->presentationStorage); + This->dirty = TRUE; + + return S_OK; } /************************************************************************ @@ -1004,30 +1313,90 @@ static HRESULT WINAPI DataCache_Load( IPersistStorage* iface, IStorage* pStg) { - DataCache *this = impl_from_IPersistStorage(iface); + DataCache *This = impl_from_IPersistStorage(iface); + STATSTG elem; + IEnumSTATSTG *pEnum; + HRESULT hr; - TRACE("(%p, %p)\n", iface, pStg); + TRACE("(%p, %p)\n", iface, pStg); - if (this->presentationStorage != NULL) - { - IStorage_Release(this->presentationStorage); - } + if (This->presentationStorage != NULL) + IStorage_Release(This->presentationStorage); - this->presentationStorage = pStg; + This->presentationStorage = pStg; - if (this->presentationStorage != NULL) - { - IStorage_AddRef(this->presentationStorage); - } - return S_OK; + hr = IStorage_EnumElements(pStg, 0, NULL, 0, &pEnum); + if (FAILED(hr)) return hr; + + while ((hr = IEnumSTATSTG_Next(pEnum, 1, &elem, NULL)) == S_OK) + { + if (DataCache_IsPresentationStream(&elem)) + { + IStream *pStm; + + hr = IStorage_OpenStream(This->presentationStorage, elem.pwcsName, + NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, + &pStm); + if (SUCCEEDED(hr)) + { + PresentationDataHeader header; + ULONG actual_read; + CLIPFORMAT clipformat; + + hr = read_clipformat(pStm, &clipformat); + + if (hr == S_OK) + hr = IStream_Read(pStm, &header, sizeof(header), + &actual_read); + + /* can't use SUCCEEDED(hr): S_FALSE counts as an error */ + if (hr == S_OK && actual_read == sizeof(header)) + { + DataCacheEntry *cache_entry; + FORMATETC fmtetc; + + fmtetc.cfFormat = clipformat; + fmtetc.ptd = NULL; /* FIXME */ + fmtetc.dwAspect = header.dvAspect; + fmtetc.lindex = header.lindex; + fmtetc.tymed = header.tymed; + + TRACE("loading entry with formatetc: %s\n", debugstr_formatetc(&fmtetc)); + + cache_entry = DataCache_GetEntryForFormatEtc(This, &fmtetc); + if (!cache_entry) + hr = DataCache_CreateEntry(This, &fmtetc, &cache_entry); + if (SUCCEEDED(hr)) + { + DataCacheEntry_DiscardData(cache_entry); + if (cache_entry->storage) IStorage_Release(cache_entry->storage); + cache_entry->storage = pStg; + IStorage_AddRef(pStg); + cache_entry->dirty = FALSE; + } + } + + IStream_Release(pStm); + } + } + + CoTaskMemFree(elem.pwcsName); + } + + This->dirty = FALSE; + + IEnumSTATSTG_Release(pEnum); + + IStorage_AddRef(This->presentationStorage); + return S_OK; } /************************************************************************ * DataCache_Save (IPersistStorage) * - * Until we actully connect to a running object and retrieve new + * Until we actually connect to a running object and retrieve new * information to it, we never have to save anything. However, it is - * our responsability to copy the information when saving to a new + * our responsibility to copy the information when saving to a new * storage. * * See Windows documentation for more details on IPersistStorage methods. @@ -1037,28 +1406,64 @@ static HRESULT WINAPI DataCache_Save( IStorage* pStg, BOOL fSameAsLoad) { - DataCache *this = impl_from_IPersistStorage(iface); + DataCache *This = impl_from_IPersistStorage(iface); + DataCacheEntry *cache_entry; + BOOL dirty = FALSE; + HRESULT hr = S_OK; + unsigned short stream_number = 0; - TRACE("(%p, %p, %d)\n", iface, pStg, fSameAsLoad); + TRACE("(%p, %p, %d)\n", iface, pStg, fSameAsLoad); - if ( (!fSameAsLoad) && - (this->presentationStorage!=NULL) ) - { - return IStorage_CopyTo(this->presentationStorage, - 0, - NULL, - NULL, - pStg); - } + dirty = This->dirty; + if (!dirty) + { + LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry) + { + dirty = cache_entry->dirty; + if (dirty) + break; + } + } - return S_OK; + /* this is a shortcut if nothing changed */ + if (!dirty && !fSameAsLoad && This->presentationStorage) + { + return IStorage_CopyTo(This->presentationStorage, 0, NULL, NULL, pStg); + } + + /* assign stream numbers to the cache entries */ + LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry) + { + if (cache_entry->stream_number != stream_number) + { + cache_entry->dirty = TRUE; /* needs to be written out again */ + cache_entry->stream_number = stream_number; + } + stream_number++; + } + + /* write out the cache entries */ + LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry) + { + if (!fSameAsLoad || cache_entry->dirty) + { + hr = DataCacheEntry_Save(cache_entry, pStg, fSameAsLoad); + if (FAILED(hr)) + break; + + cache_entry->dirty = FALSE; + } + } + + This->dirty = FALSE; + return hr; } /************************************************************************ * DataCache_SaveCompleted (IPersistStorage) * * This method is called to tell the cache to release the storage - * pointer it's currentlu holding. + * pointer it's currently holding. * * See Windows documentation for more details on IPersistStorage methods. */ @@ -1090,7 +1495,7 @@ static HRESULT WINAPI DataCache_SaveCompleted( * DataCache_HandsOffStorage (IPersistStorage) * * This method is called to tell the cache to release the storage - * pointer it's currentlu holding. + * pointer it's currently holding. * * See Windows documentation for more details on IPersistStorage methods. */ @@ -1098,6 +1503,7 @@ static HRESULT WINAPI DataCache_HandsOffStorage( IPersistStorage* iface) { DataCache *this = impl_from_IPersistStorage(iface); + DataCacheEntry *cache_entry; TRACE("(%p)\n", iface); @@ -1107,6 +1513,9 @@ static HRESULT WINAPI DataCache_HandsOffStorage( this->presentationStorage = NULL; } + LIST_FOR_EACH_ENTRY(cache_entry, &this->cache_list, DataCacheEntry, entry) + DataCacheEntry_HandsOffStorage(cache_entry); + return S_OK; } @@ -1177,13 +1586,11 @@ static HRESULT WINAPI DataCache_Draw( BOOL (CALLBACK *pfnContinue)(ULONG_PTR dwContinue), ULONG_PTR dwContinue) { - PresentationDataHeader presData; - HMETAFILE presMetafile = 0; + DataCache *This = impl_from_IViewObject2(iface); HRESULT hres; + DataCacheEntry *cache_entry; - DataCache *this = impl_from_IViewObject2(iface); - - TRACE("(%p, %lx, %ld, %p, %p, %p, %p, %p, %p, %lx)\n", + TRACE("(%p, %x, %d, %p, %p, %p, %p, %p, %p, %lx)\n", iface, dwDrawAspect, lindex, @@ -1201,77 +1608,89 @@ static HRESULT WINAPI DataCache_Draw( if (lprcBounds==NULL) return E_INVALIDARG; - /* - * First, we need to retrieve the dimensions of the - * image in the metafile. - */ - hres = DataCache_ReadPresentationData(this, - dwDrawAspect, - &presData); - - if (FAILED(hres)) - return hres; - - /* - * Then, we can extract the metafile itself from the cached - * data. - * - * FIXME Unless it isn't a metafile. I think it could be any CF_XXX type, - * particularly CF_DIB. - */ - presMetafile = DataCache_ReadPresMetafile(this, - dwDrawAspect); - - /* - * If we have a metafile, just draw baby... - * We have to be careful not to modify the state of the - * DC. - */ - if (presMetafile!=0) + LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry) { - INT prevMapMode = SetMapMode(hdcDraw, MM_ANISOTROPIC); - SIZE oldWindowExt; - SIZE oldViewportExt; - POINT oldViewportOrg; + /* FIXME: compare ptd too */ + if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) || + (cache_entry->fmtetc.lindex != lindex)) + continue; - SetWindowExtEx(hdcDraw, - presData.dwObjectExtentX, - presData.dwObjectExtentY, - &oldWindowExt); + /* if the data hasn't been loaded yet, do it now */ + if ((cache_entry->stgmedium.tymed == TYMED_NULL) && cache_entry->storage) + { + hres = DataCacheEntry_LoadData(cache_entry); + if (FAILED(hres)) + continue; + } - SetViewportExtEx(hdcDraw, - lprcBounds->right - lprcBounds->left, - lprcBounds->bottom - lprcBounds->top, - &oldViewportExt); + /* no data */ + if (cache_entry->stgmedium.tymed == TYMED_NULL) + continue; - SetViewportOrgEx(hdcDraw, - lprcBounds->left, - lprcBounds->top, - &oldViewportOrg); + switch (cache_entry->data_cf) + { + case CF_METAFILEPICT: + { + /* + * We have to be careful not to modify the state of the + * DC. + */ + INT prevMapMode; + SIZE oldWindowExt; + SIZE oldViewportExt; + POINT oldViewportOrg; + METAFILEPICT *mfpict; - PlayMetaFile(hdcDraw, presMetafile); + if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) || + !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict)))) + continue; - SetWindowExtEx(hdcDraw, - oldWindowExt.cx, - oldWindowExt.cy, - NULL); + prevMapMode = SetMapMode(hdcDraw, mfpict->mm); - SetViewportExtEx(hdcDraw, - oldViewportExt.cx, - oldViewportExt.cy, - NULL); + SetWindowExtEx(hdcDraw, + mfpict->xExt, + mfpict->yExt, + &oldWindowExt); - SetViewportOrgEx(hdcDraw, - oldViewportOrg.x, - oldViewportOrg.y, - NULL); + SetViewportExtEx(hdcDraw, + lprcBounds->right - lprcBounds->left, + lprcBounds->bottom - lprcBounds->top, + &oldViewportExt); - SetMapMode(hdcDraw, prevMapMode); + SetViewportOrgEx(hdcDraw, + lprcBounds->left, + lprcBounds->top, + &oldViewportOrg); - DeleteMetaFile(presMetafile); + PlayMetaFile(hdcDraw, mfpict->hMF); + + SetWindowExtEx(hdcDraw, + oldWindowExt.cx, + oldWindowExt.cy, + NULL); + + SetViewportExtEx(hdcDraw, + oldViewportExt.cx, + oldViewportExt.cy, + NULL); + + SetViewportOrgEx(hdcDraw, + oldViewportOrg.x, + oldViewportOrg.y, + NULL); + + SetMapMode(hdcDraw, prevMapMode); + + GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict); + + return S_OK; + } + } } - return S_OK; + WARN("no data could be found to be drawn\n"); + + return OLE_E_BLANK; } static HRESULT WINAPI DataCache_GetColorSet( @@ -1322,7 +1741,7 @@ static HRESULT WINAPI DataCache_SetAdvise( { DataCache *this = impl_from_IViewObject2(iface); - TRACE("(%p, %lx, %lx, %p)\n", iface, aspects, advf, pAdvSink); + TRACE("(%p, %x, %x, %p)\n", iface, aspects, advf, pAdvSink); /* * A call to this function removes the previous sink @@ -1353,9 +1772,7 @@ static HRESULT WINAPI DataCache_SetAdvise( */ if (advf & ADVF_PRIMEFIRST) { - DataCache_FireOnViewChange(this, - DVASPECT_CONTENT, - -1); + DataCache_FireOnViewChange(this, aspects, -1); } return S_OK; @@ -1414,12 +1831,11 @@ static HRESULT WINAPI DataCache_GetExtent( DVTARGETDEVICE* ptd, LPSIZEL lpsizel) { - PresentationDataHeader presData; + DataCache *This = impl_from_IViewObject2(iface); HRESULT hres = E_FAIL; + DataCacheEntry *cache_entry; - DataCache *this = impl_from_IViewObject2(iface); - - TRACE("(%p, %lx, %ld, %p, %p)\n", + TRACE("(%p, %x, %d, %p, %p)\n", iface, dwDrawAspect, lindex, ptd, lpsizel); /* @@ -1438,7 +1854,7 @@ static HRESULT WINAPI DataCache_GetExtent( * This flag should be set to -1. */ if (lindex!=-1) - FIXME("Unimplemented flag lindex = %ld\n", lindex); + FIXME("Unimplemented flag lindex = %d\n", lindex); /* * Right now, we support only the callback from @@ -1447,27 +1863,52 @@ static HRESULT WINAPI DataCache_GetExtent( if (ptd!=NULL) FIXME("Unimplemented ptd = %p\n", ptd); - /* - * Get the presentation information from the - * cache. - */ - hres = DataCache_ReadPresentationData(this, - dwDrawAspect, - &presData); - - if (SUCCEEDED(hres)) + LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry) { - lpsizel->cx = presData.dwObjectExtentX; - lpsizel->cy = presData.dwObjectExtentY; + /* FIXME: compare ptd too */ + if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) || + (cache_entry->fmtetc.lindex != lindex)) + continue; + + /* if the data hasn't been loaded yet, do it now */ + if ((cache_entry->stgmedium.tymed == TYMED_NULL) && cache_entry->storage) + { + hres = DataCacheEntry_LoadData(cache_entry); + if (FAILED(hres)) + continue; + } + + /* no data */ + if (cache_entry->stgmedium.tymed == TYMED_NULL) + continue; + + + switch (cache_entry->data_cf) + { + case CF_METAFILEPICT: + { + METAFILEPICT *mfpict; + + if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) || + !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict)))) + continue; + + lpsizel->cx = mfpict->xExt; + lpsizel->cy = mfpict->yExt; + + GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict); + + return S_OK; + } + } } + WARN("no data could be found to get the extents from\n"); + /* * This method returns OLE_E_BLANK when it fails. */ - if (FAILED(hres)) - hres = OLE_E_BLANK; - - return hres; + return OLE_E_BLANK; } @@ -1523,16 +1964,50 @@ static HRESULT WINAPI DataCache_Cache( DWORD advf, DWORD* pdwConnection) { - FIXME("stub\n"); - return E_NOTIMPL; + DataCache *This = impl_from_IOleCache2(iface); + DataCacheEntry *cache_entry; + HRESULT hr; + + TRACE("(%p, 0x%x, %p)\n", pformatetc, advf, pdwConnection); + TRACE("pformatetc = %s\n", debugstr_formatetc(pformatetc)); + + *pdwConnection = 0; + + cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetc); + if (cache_entry) + { + TRACE("found an existing cache entry\n"); + *pdwConnection = cache_entry->id; + return CACHE_S_SAMECACHE; + } + + hr = DataCache_CreateEntry(This, pformatetc, &cache_entry); + + if (SUCCEEDED(hr)) + *pdwConnection = cache_entry->id; + + return hr; } static HRESULT WINAPI DataCache_Uncache( IOleCache2* iface, DWORD dwConnection) { - FIXME("stub\n"); - return E_NOTIMPL; + DataCache *This = impl_from_IOleCache2(iface); + DataCacheEntry *cache_entry; + + TRACE("(%d)\n", dwConnection); + + LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry) + if (cache_entry->id == dwConnection) + { + DataCacheEntry_Destroy(cache_entry); + return S_OK; + } + + WARN("no connection found for %d\n", dwConnection); + + return OLE_E_NOCONNECTION; } static HRESULT WINAPI DataCache_EnumCache( @@ -1557,8 +2032,27 @@ static HRESULT WINAPI DataCache_IOleCache2_SetData( STGMEDIUM* pmedium, BOOL fRelease) { - FIXME("stub\n"); - return E_NOTIMPL; + DataCache *This = impl_from_IOleCache2(iface); + DataCacheEntry *cache_entry; + HRESULT hr; + + TRACE("(%p, %p, %s)\n", pformatetc, pmedium, fRelease ? "TRUE" : "FALSE"); + TRACE("formatetc = %s\n", debugstr_formatetc(pformatetc)); + + cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetc); + if (cache_entry) + { + hr = DataCacheEntry_SetData(cache_entry, pformatetc, pmedium, fRelease); + + if (SUCCEEDED(hr)) + DataCache_FireOnViewChange(This, cache_entry->fmtetc.dwAspect, + cache_entry->fmtetc.lindex); + + return hr; + } + WARN("cache entry not found\n"); + + return OLE_E_BLANK; } static HRESULT WINAPI DataCache_UpdateCache( @@ -1567,7 +2061,7 @@ static HRESULT WINAPI DataCache_UpdateCache( DWORD grfUpdf, LPVOID pReserved) { - FIXME("stub\n"); + FIXME("(%p, 0x%x, %p): stub\n", pDataObject, grfUpdf, pReserved); return E_NOTIMPL; } @@ -1575,8 +2069,24 @@ static HRESULT WINAPI DataCache_DiscardCache( IOleCache2* iface, DWORD dwDiscardOptions) { - FIXME("stub\n"); - return E_NOTIMPL; + DataCache *This = impl_from_IOleCache2(iface); + DataCacheEntry *cache_entry; + HRESULT hr = S_OK; + + TRACE("(%d)\n", dwDiscardOptions); + + if (dwDiscardOptions == DISCARDCACHE_SAVEIFDIRTY) + hr = DataCache_Save((IPersistStorage *)&This->lpvtblIPersistStorage, + This->presentationStorage, TRUE); + + LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry) + { + hr = DataCacheEntry_DiscardData(cache_entry); + if (FAILED(hr)) + break; + } + + return hr; } @@ -1720,6 +2230,24 @@ static const IOleCacheControlVtbl DataCache_IOleCacheControl_VTable = /****************************************************************************** * CreateDataCache [OLE32.@] + * + * Creates a data cache to allow an object to render one or more of its views, + * whether running or not. + * + * PARAMS + * pUnkOuter [I] Outer unknown for the object. + * rclsid [I] + * riid [I] IID of interface to return. + * ppvObj [O] Address where the data cache object will be stored on return. + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT code. + * + * NOTES + * The following interfaces are supported by the returned data cache object: + * IOleCache, IOleCache2, IOleCacheControl, IPersistStorae, IDataObject, + * IViewObject and IViewObject2. */ HRESULT WINAPI CreateDataCache( LPUNKNOWN pUnkOuter, @@ -1809,7 +2337,7 @@ static DataCache* DataCache_Construct( /* * Initialize the outer unknown * We don't keep a reference on the outer unknown since, the way - * aggregation works, our lifetime is at least as large as it's + * aggregation works, our lifetime is at least as large as its * lifetime. */ if (pUnkOuter==NULL) @@ -1820,10 +2348,13 @@ static DataCache* DataCache_Construct( /* * Initialize the other members of the structure. */ - newObject->presentationStorage = NULL; newObject->sinkAspects = 0; newObject->sinkAdviseFlag = 0; newObject->sinkInterface = 0; + newObject->presentationStorage = NULL; + list_init(&newObject->cache_list); + newObject->last_cache_id = 1; + newObject->dirty = FALSE; return newObject; } diff --git a/reactos/dll/win32/ole32/dcom.h b/reactos/dll/win32/ole32/dcom.h deleted file mode 100644 index 3ea35faaf13..00000000000 --- a/reactos/dll/win32/ole32/dcom.h +++ /dev/null @@ -1,515 +0,0 @@ -/*** Autogenerated by WIDL 0.1 from dcom.idl - Do not edit ***/ -#include -#include - -#ifndef __WIDL_DCOM_H -#define __WIDL_DCOM_H -#ifdef __cplusplus -extern "C" { -#endif -#include -typedef MIDL_uhyper ID; - -typedef ID MID; - -typedef ID OXID; - -typedef ID OID; - -typedef ID SETID; - -typedef GUID IPID; - -typedef GUID CID; - -typedef REFGUID REFIPID; - -#define COM_MINOR_VERSION_1 (1) - -#define COM_MINOR_VERSION_2 (2) - -#define COM_MAJOR_VERSION (5) - -#define COM_MINOR_VERSION (3) - -typedef struct tagCOMVERSION { - unsigned short MajorVersion; - unsigned short MinorVersion; -} COMVERSION; - -#define ORPCF_NULL (0) - -#define ORPCF_LOCAL (1) - -#define ORPCF_RESERVED1 (2) - -#define ORPCF_RESERVED2 (4) - -#define ORPCF_RESERVED3 (8) - -#define ORPCF_RESERVED4 (16) - -typedef struct tagORPC_EXTENT { - GUID id; - unsigned long size; - byte data[1]; -} ORPC_EXTENT; - -typedef struct tagORPC_EXTENT_ARRAY { - unsigned long size; - unsigned long reserved; - ORPC_EXTENT **extent; -} ORPC_EXTENT_ARRAY; - -typedef struct tagORPCTHIS { - COMVERSION version; - unsigned long flags; - unsigned long reserved1; - CID cid; - ORPC_EXTENT_ARRAY *extensions; -} ORPCTHIS; - -typedef struct tagORPCTHAT { - unsigned long flags; - ORPC_EXTENT_ARRAY *extensions; -} ORPCTHAT; - -#define NCADG_IP_UDP (0x8) - -#define NCACN_IP_TCP (0x7) - -#define NCADG_IPX (0xe) - -#define NCACN_SPX (0xc) - -#define NCACN_NB_NB (0x12) - -#define NCACN_NB_IPX (0xd) - -#define NCACN_DNET_NSP (0x4) - -#define NCACN_HTTP (0x1f) - -typedef struct tagSTRINGBINDING { - unsigned short wTowerId; - unsigned short aNetworkAddr[1]; -} STRINGBINDING; - -#define COM_C_AUTHZ_NONE (0xffff) - -typedef struct tagSECURITYBINDING { - unsigned short wAuthnSvc; - unsigned short wAuthzSvc; - unsigned short aPrincName[1]; -} SECURITYBINDING; - -typedef struct tagDUALSTRINGARRAY { - unsigned short wNumEntries; - unsigned short wSecurityOffset; - unsigned short aStringArray[1]; -} DUALSTRINGARRAY; - -#define OBJREF_SIGNATURE (0x574f454d) - -#define OBJREF_STANDARD (0x1) - -#define OBJREF_HANDLER (0x2) - -#define OBJREF_CUSTOM (0x4) - -#define SORF_OXRES1 (0x1) - -#define SORF_OXRES2 (0x20) - -#define SORF_OXRES3 (0x40) - -#define SORF_OXRES4 (0x80) - -#define SORF_OXRES5 (0x100) - -#define SORF_OXRES6 (0x200) - -#define SORF_OXRES7 (0x400) - -#define SORF_OXRES8 (0x800) - -#define SORF_NULL (0x0) - -#define SORF_NOPING (0x1000) - -typedef struct tagSTDOBJREF { - unsigned long flags; - unsigned long cPublicRefs; - OXID oxid; - OID oid; - IPID ipid; -} STDOBJREF; - -typedef struct tagOBJREF { - unsigned long signature; - unsigned long flags; - GUID iid; - union { - struct OR_STANDARD { - STDOBJREF std; - DUALSTRINGARRAY saResAddr; - } u_standard; - struct OR_HANDLER { - STDOBJREF std; - CLSID clsid; - DUALSTRINGARRAY saResAddr; - } u_handler; - struct OR_CUSTOM { - CLSID clsid; - unsigned long cbExtension; - unsigned long size; - byte *pData; - } u_custom; - } u_objref; -} OBJREF; - -typedef struct tagMInterfacePointer { - ULONG ulCntData; - BYTE abData[1]; -} MInterfacePointer; - -typedef MInterfacePointer *PMInterfacePointer; - -#ifndef __IRemUnknown_FWD_DEFINED__ -#define __IRemUnknown_FWD_DEFINED__ -typedef struct IRemUnknown IRemUnknown; -#endif - -typedef IRemUnknown *LPREMUNKNOWN; - -typedef struct tagREMQIRESULT { - HRESULT hResult; - STDOBJREF std; -} REMQIRESULT; - -typedef struct tagREMINTERFACEREF { - IPID ipid; - unsigned long cPublicRefs; - unsigned long cPrivateRefs; -} REMINTERFACEREF; - -/***************************************************************************** - * IRemUnknown interface - */ -#ifndef __IRemUnknown_INTERFACE_DEFINED__ -#define __IRemUnknown_INTERFACE_DEFINED__ - -DEFINE_GUID(IID_IRemUnknown, 0x00000131, 0x0000, 0x0000, 0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x46); -#if defined(__cplusplus) && !defined(CINTERFACE) -struct IRemUnknown : public IUnknown -{ - virtual HRESULT STDMETHODCALLTYPE RemQueryInterface( - REFIPID ripid, - unsigned long cRefs, - unsigned short cIids, - IID* iids, - REMQIRESULT** ppQIResults) = 0; - - virtual HRESULT STDMETHODCALLTYPE RemAddRef( - unsigned short cInterfaceRefs, - REMINTERFACEREF* InterfaceRefs, - HRESULT* pResults) = 0; - - virtual HRESULT STDMETHODCALLTYPE RemRelease( - unsigned short cInterfaceRefs, - REMINTERFACEREF* InterfaceRefs) = 0; - -}; -#else -typedef struct IRemUnknownVtbl IRemUnknownVtbl; -struct IRemUnknown { - const IRemUnknownVtbl* lpVtbl; -}; -struct IRemUnknownVtbl { - BEGIN_INTERFACE - - /*** IUnknown methods ***/ - HRESULT (STDMETHODCALLTYPE *QueryInterface)( - IRemUnknown* This, - REFIID riid, - void** ppvObject); - - ULONG (STDMETHODCALLTYPE *AddRef)( - IRemUnknown* This); - - ULONG (STDMETHODCALLTYPE *Release)( - IRemUnknown* This); - - /*** IRemUnknown methods ***/ - HRESULT (STDMETHODCALLTYPE *RemQueryInterface)( - IRemUnknown* This, - REFIPID ripid, - unsigned long cRefs, - unsigned short cIids, - IID* iids, - REMQIRESULT** ppQIResults); - - HRESULT (STDMETHODCALLTYPE *RemAddRef)( - IRemUnknown* This, - unsigned short cInterfaceRefs, - REMINTERFACEREF* InterfaceRefs, - HRESULT* pResults); - - HRESULT (STDMETHODCALLTYPE *RemRelease)( - IRemUnknown* This, - unsigned short cInterfaceRefs, - REMINTERFACEREF* InterfaceRefs); - - END_INTERFACE -}; - -#ifdef COBJMACROS -/*** IUnknown methods ***/ -#define IRemUnknown_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) -#define IRemUnknown_AddRef(p) (p)->lpVtbl->AddRef(p) -#define IRemUnknown_Release(p) (p)->lpVtbl->Release(p) -/*** IRemUnknown methods ***/ -#define IRemUnknown_RemQueryInterface(p,a,b,c,d,e) (p)->lpVtbl->RemQueryInterface(p,a,b,c,d,e) -#define IRemUnknown_RemAddRef(p,a,b,c) (p)->lpVtbl->RemAddRef(p,a,b,c) -#define IRemUnknown_RemRelease(p,a,b) (p)->lpVtbl->RemRelease(p,a,b) -#endif - -#endif - -#define IRemUnknown_METHODS \ - /*** IUnknown methods ***/ \ - STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; \ - STDMETHOD_(ULONG,AddRef)(THIS) PURE; \ - STDMETHOD_(ULONG,Release)(THIS) PURE; \ - /*** IRemUnknown methods ***/ \ - STDMETHOD_(HRESULT,RemQueryInterface)(THIS_ REFIPID ripid, unsigned long cRefs, unsigned short cIids, IID* iids, REMQIRESULT** ppQIResults) PURE; \ - STDMETHOD_(HRESULT,RemAddRef)(THIS_ unsigned short cInterfaceRefs, REMINTERFACEREF* InterfaceRefs, HRESULT* pResults) PURE; \ - STDMETHOD_(HRESULT,RemRelease)(THIS_ unsigned short cInterfaceRefs, REMINTERFACEREF* InterfaceRefs) PURE; - -HRESULT CALLBACK IRemUnknown_RemQueryInterface_Proxy( - IRemUnknown* This, - REFIPID ripid, - unsigned long cRefs, - unsigned short cIids, - IID* iids, - REMQIRESULT** ppQIResults); -void __RPC_STUB IRemUnknown_RemQueryInterface_Stub( - struct IRpcStubBuffer* This, - struct IRpcChannelBuffer* pRpcChannelBuffer, - PRPC_MESSAGE pRpcMessage, - DWORD* pdwStubPhase); -HRESULT CALLBACK IRemUnknown_RemAddRef_Proxy( - IRemUnknown* This, - unsigned short cInterfaceRefs, - REMINTERFACEREF* InterfaceRefs, - HRESULT* pResults); -void __RPC_STUB IRemUnknown_RemAddRef_Stub( - struct IRpcStubBuffer* This, - struct IRpcChannelBuffer* pRpcChannelBuffer, - PRPC_MESSAGE pRpcMessage, - DWORD* pdwStubPhase); -HRESULT CALLBACK IRemUnknown_RemRelease_Proxy( - IRemUnknown* This, - unsigned short cInterfaceRefs, - REMINTERFACEREF* InterfaceRefs); -void __RPC_STUB IRemUnknown_RemRelease_Stub( - struct IRpcStubBuffer* This, - struct IRpcChannelBuffer* pRpcChannelBuffer, - PRPC_MESSAGE pRpcMessage, - DWORD* pdwStubPhase); - -#endif /* __IRemUnknown_INTERFACE_DEFINED__ */ - -#ifndef __IRemUnknown2_FWD_DEFINED__ -#define __IRemUnknown2_FWD_DEFINED__ -typedef struct IRemUnknown2 IRemUnknown2; -#endif - -typedef IRemUnknown2 *LPREMUNKNOWN2; - -/***************************************************************************** - * IRemUnknown2 interface - */ -#ifndef __IRemUnknown2_INTERFACE_DEFINED__ -#define __IRemUnknown2_INTERFACE_DEFINED__ - -DEFINE_GUID(IID_IRemUnknown2, 0x00000142, 0x0000, 0x0000, 0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x46); -#if defined(__cplusplus) && !defined(CINTERFACE) -struct IRemUnknown2 : public IRemUnknown -{ - virtual HRESULT STDMETHODCALLTYPE RemQueryInterface2( - REFIPID ripid, - unsigned short cIids, - IID* iids, - HRESULT* phr, - MInterfacePointer** ppMIF) = 0; - -}; -#else -typedef struct IRemUnknown2Vtbl IRemUnknown2Vtbl; -struct IRemUnknown2 { - const IRemUnknown2Vtbl* lpVtbl; -}; -struct IRemUnknown2Vtbl { - BEGIN_INTERFACE - - /*** IUnknown methods ***/ - HRESULT (STDMETHODCALLTYPE *QueryInterface)( - IRemUnknown2* This, - REFIID riid, - void** ppvObject); - - ULONG (STDMETHODCALLTYPE *AddRef)( - IRemUnknown2* This); - - ULONG (STDMETHODCALLTYPE *Release)( - IRemUnknown2* This); - - /*** IRemUnknown methods ***/ - HRESULT (STDMETHODCALLTYPE *RemQueryInterface)( - IRemUnknown2* This, - REFIPID ripid, - unsigned long cRefs, - unsigned short cIids, - IID* iids, - REMQIRESULT** ppQIResults); - - HRESULT (STDMETHODCALLTYPE *RemAddRef)( - IRemUnknown2* This, - unsigned short cInterfaceRefs, - REMINTERFACEREF* InterfaceRefs, - HRESULT* pResults); - - HRESULT (STDMETHODCALLTYPE *RemRelease)( - IRemUnknown2* This, - unsigned short cInterfaceRefs, - REMINTERFACEREF* InterfaceRefs); - - /*** IRemUnknown2 methods ***/ - HRESULT (STDMETHODCALLTYPE *RemQueryInterface2)( - IRemUnknown2* This, - REFIPID ripid, - unsigned short cIids, - IID* iids, - HRESULT* phr, - MInterfacePointer** ppMIF); - - END_INTERFACE -}; - -#ifdef COBJMACROS -/*** IUnknown methods ***/ -#define IRemUnknown2_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) -#define IRemUnknown2_AddRef(p) (p)->lpVtbl->AddRef(p) -#define IRemUnknown2_Release(p) (p)->lpVtbl->Release(p) -/*** IRemUnknown methods ***/ -#define IRemUnknown2_RemQueryInterface(p,a,b,c,d,e) (p)->lpVtbl->RemQueryInterface(p,a,b,c,d,e) -#define IRemUnknown2_RemAddRef(p,a,b,c) (p)->lpVtbl->RemAddRef(p,a,b,c) -#define IRemUnknown2_RemRelease(p,a,b) (p)->lpVtbl->RemRelease(p,a,b) -/*** IRemUnknown2 methods ***/ -#define IRemUnknown2_RemQueryInterface2(p,a,b,c,d,e) (p)->lpVtbl->RemQueryInterface2(p,a,b,c,d,e) -#endif - -#endif - -#define IRemUnknown2_METHODS \ - /*** IUnknown methods ***/ \ - STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; \ - STDMETHOD_(ULONG,AddRef)(THIS) PURE; \ - STDMETHOD_(ULONG,Release)(THIS) PURE; \ - /*** IRemUnknown methods ***/ \ - STDMETHOD_(HRESULT,RemQueryInterface)(THIS_ REFIPID ripid, unsigned long cRefs, unsigned short cIids, IID* iids, REMQIRESULT** ppQIResults) PURE; \ - STDMETHOD_(HRESULT,RemAddRef)(THIS_ unsigned short cInterfaceRefs, REMINTERFACEREF* InterfaceRefs, HRESULT* pResults) PURE; \ - STDMETHOD_(HRESULT,RemRelease)(THIS_ unsigned short cInterfaceRefs, REMINTERFACEREF* InterfaceRefs) PURE; \ - /*** IRemUnknown2 methods ***/ \ - STDMETHOD_(HRESULT,RemQueryInterface2)(THIS_ REFIPID ripid, unsigned short cIids, IID* iids, HRESULT* phr, MInterfacePointer** ppMIF) PURE; - -HRESULT CALLBACK IRemUnknown2_RemQueryInterface2_Proxy( - IRemUnknown2* This, - REFIPID ripid, - unsigned short cIids, - IID* iids, - HRESULT* phr, - MInterfacePointer** ppMIF); -void __RPC_STUB IRemUnknown2_RemQueryInterface2_Stub( - struct IRpcStubBuffer* This, - struct IRpcChannelBuffer* pRpcChannelBuffer, - PRPC_MESSAGE pRpcMessage, - DWORD* pdwStubPhase); - -#endif /* __IRemUnknown2_INTERFACE_DEFINED__ */ - -#if 0 -/***************************************************************************** - * IOXIDResolver interface (v0.0) - */ -DEFINE_GUID(IID_IOXIDResolver, 0x99fcfec4, 0x5260, 0x101b, 0xbb,0xcb, 0x00,0xaa,0x00,0x21,0x34,0x7a); -extern RPC_IF_HANDLE IOXIDResolver_v0_0_c_ifspec; -extern RPC_IF_HANDLE IOXIDResolver_v0_0_s_ifspec; -error_status_t ResolveOxid( - handle_t hRpc, - OXID* pOxid, - unsigned short cRequestedProtseqs, - unsigned short arRequestedProtseqs[], - DUALSTRINGARRAY** ppdsaOxidBindings, - IPID* pipidRemUnknown, - DWORD* pAuthnHint); -error_status_t SimplePing( - handle_t hRpc, - SETID* pSetId); -error_status_t ComplexPing( - handle_t hRpc, - SETID* pSetId, - unsigned short SequenceNum, - unsigned short cAddToSet, - unsigned short cDelFromSet, - OID AddToSet[], - OID DelFromSet[], - unsigned short* pPingBackoffFactor); -error_status_t ServerAlive( - handle_t hRpc); -error_status_t ResolveOxid2( - handle_t hRpc, - OXID* pOxid, - unsigned short cRequestedProtseqs, - unsigned short arRequestedProtseqs[], - DUALSTRINGARRAY** ppdsaOxidBindings, - IPID* pipidRemUnknown, - DWORD* pAuthnHint, - COMVERSION* pComVersion); - -#define MODE_GET_CLASS_OBJECT (0xffffffff) - -/***************************************************************************** - * IRemoteActivation interface (v0.0) - */ -DEFINE_GUID(IID_IRemoteActivation, 0x4d9f4ab8, 0x7d1c, 0x11cf, 0x86,0x1e, 0x00,0x20,0xaf,0x6e,0x7c,0x57); -extern RPC_IF_HANDLE IRemoteActivation_v0_0_c_ifspec; -extern RPC_IF_HANDLE IRemoteActivation_v0_0_s_ifspec; -HRESULT RemoteActivation( - handle_t hRpc, - ORPCTHIS* ORPCthis, - ORPCTHAT* ORPCthat, - GUID* Clsid, - WCHAR* pwszObjectName, - MInterfacePointer* pObjectStorage, - DWORD ClientImpLevel, - DWORD Mode, - DWORD Interfaces, - IID* pIIDs, - unsigned short cRequestedProtseqs, - unsigned short RequestedProtseqs[], - OXID* pOxid, - DUALSTRINGARRAY** ppdsaOxidBindings, - IPID* pipidRemUnknown, - DWORD* pAuthnHint, - COMVERSION* pServerVersion, - HRESULT* phr, - MInterfacePointer** ppInterfaceData, - HRESULT* pResults); - -#endif -#ifdef __cplusplus -} -#endif -#endif /* __WIDL_DCOM_H */ diff --git a/reactos/dll/win32/ole32/dcom.idl b/reactos/dll/win32/ole32/dcom.idl index 7d95f3704c4..6e5a454dc77 100644 --- a/reactos/dll/win32/ole32/dcom.idl +++ b/reactos/dll/win32/ole32/dcom.idl @@ -13,7 +13,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ /* see http://www.microsoft.com/msj/0398/dcom.htm */ @@ -108,6 +108,14 @@ interface ObjectRpcBaseTypes [size_is(wNumEntries)] unsigned short aStringArray[]; } DUALSTRINGARRAY; + typedef struct tagOXID_INFO { + DWORD dwTid; + DWORD dwPid; + IPID ipidRemUnknown; + DWORD dwAuthnHint; + DUALSTRINGARRAY *psa; + } OXID_INFO; + const unsigned long OBJREF_SIGNATURE = 0x574f454d; /* "MEOW" */ const unsigned long OBJREF_STANDARD = 0x1; const unsigned long OBJREF_HANDLER = 0x2; @@ -148,7 +156,7 @@ interface ObjectRpcBaseTypes [case(OBJREF_CUSTOM)] struct OR_CUSTOM { CLSID clsid; unsigned long cbExtension; - unsigned long size; + ULONG size; [size_is(size), ref] byte *pData; } u_custom; } u_objref; @@ -184,7 +192,7 @@ interface IRemUnknown : IUnknown HRESULT RemQueryInterface( [in] REFIPID ripid, - [in] unsigned long cRefs, + [in] ULONG cRefs, [in] unsigned short cIids, [in, size_is(cIids)] IID *iids, [out, size_is(,cIids)] REMQIRESULT **ppQIResults); @@ -215,7 +223,6 @@ interface IRemUnknown2 : IRemUnknown [out, size_is(cIids)] MInterfacePointer **ppMIF); } -cpp_quote("#if 0") [ uuid(99fcfec4-5260-101b-bbcb-00aa0021347a), pointer_default(unique) @@ -289,4 +296,3 @@ interface IRemoteActivation [out,size_is(Interfaces)] MInterfacePointer **ppInterfaceData, [out,size_is(Interfaces)] HRESULT *pResults); } -cpp_quote("#endif") diff --git a/reactos/dll/win32/ole32/defaulthandler.c b/reactos/dll/win32/ole32/defaulthandler.c index 7f742bccbab..9486813f105 100644 --- a/reactos/dll/win32/ole32/defaulthandler.c +++ b/reactos/dll/win32/ole32/defaulthandler.c @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * NOTES: * The OLE2 default object handler supports a whole whack of @@ -416,7 +416,8 @@ static void WINAPI DefaultHandler_Stop(DefaultHandler *This) /* FIXME: call IOleCache_OnStop */ - DataAdviseHolder_OnDisconnect(This->dataAdviseHolder); + if (This->dataAdviseHolder) + DataAdviseHolder_OnDisconnect(This->dataAdviseHolder); if (This->pDataDelegate) { IDataObject_Release(This->pDataDelegate); @@ -446,7 +447,7 @@ static HRESULT WINAPI DefaultHandler_Close( DefaultHandler *This = impl_from_IOleObject(iface); HRESULT hr; - TRACE("(%ld)\n", dwSaveOption); + TRACE("(%d)\n", dwSaveOption); if (!This->pOleDelegate) return S_OK; @@ -472,7 +473,7 @@ static HRESULT WINAPI DefaultHandler_SetMoniker( { DefaultHandler *This = impl_from_IOleObject(iface); - TRACE("(%p, %ld, %p)\n", + TRACE("(%p, %d, %p)\n", iface, dwWhichMoniker, pmk); @@ -498,7 +499,7 @@ static HRESULT WINAPI DefaultHandler_GetMoniker( { DefaultHandler *This = impl_from_IOleObject(iface); - TRACE("(%p, %ld, %ld, %p)\n", + TRACE("(%p, %d, %d, %p)\n", iface, dwAssign, dwWhichMoniker, ppmk); if (This->pOleDelegate) @@ -533,7 +534,7 @@ static HRESULT WINAPI DefaultHandler_InitFromData( { DefaultHandler *This = impl_from_IOleObject(iface); - TRACE("(%p, %p, %d, %ld)\n", + TRACE("(%p, %p, %d, %d)\n", iface, pDataObject, fCreation, dwReserved); if (This->pOleDelegate) @@ -556,7 +557,7 @@ static HRESULT WINAPI DefaultHandler_GetClipboardData( { DefaultHandler *This = impl_from_IOleObject(iface); - TRACE("(%p, %ld, %p)\n", + TRACE("(%p, %d, %p)\n", iface, dwReserved, ppDataObject); if (This->pOleDelegate) @@ -579,7 +580,7 @@ static HRESULT WINAPI DefaultHandler_DoVerb( IRunnableObject *pRunnableObj = (IRunnableObject *)&This->lpvtblIRunnableObject; HRESULT hr; - TRACE("(%ld, %p, %p, %ld, %p, %s)\n", iVerb, lpmsg, pActiveSite, lindex, hwndParent, wine_dbgstr_rect(lprcPosRect)); + TRACE("(%d, %p, %p, %d, %p, %s)\n", iVerb, lpmsg, pActiveSite, lindex, hwndParent, wine_dbgstr_rect(lprcPosRect)); hr = IRunnableObject_Run(pRunnableObj, NULL); if (FAILED(hr)) return hr; @@ -651,9 +652,6 @@ static HRESULT WINAPI DefaultHandler_GetUserClassID( TRACE("(%p, %p)\n", iface, pClsid); - if (This->pOleDelegate) - return IOleObject_GetUserClassID(This->pOleDelegate, pClsid); - if (This->pOleDelegate) return IOleObject_GetUserClassID(This->pOleDelegate, pClsid); @@ -681,7 +679,7 @@ static HRESULT WINAPI DefaultHandler_GetUserType( { DefaultHandler *This = impl_from_IOleObject(iface); - TRACE("(%p, %ld, %p)\n", iface, dwFormOfType, pszUserType); + TRACE("(%p, %d, %p)\n", iface, dwFormOfType, pszUserType); return OleRegGetUserType(&This->clsid, dwFormOfType, pszUserType); } @@ -700,7 +698,7 @@ static HRESULT WINAPI DefaultHandler_SetExtent( { DefaultHandler *This = impl_from_IOleObject(iface); - TRACE("(%p, %lx, (%ld x %ld))\n", iface, + TRACE("(%p, %x, (%d x %d))\n", iface, dwDrawAspect, psizel->cx, psizel->cy); if (This->pOleDelegate) @@ -728,7 +726,7 @@ static HRESULT WINAPI DefaultHandler_GetExtent( DefaultHandler *This = impl_from_IOleObject(iface); - TRACE("(%p, %lx, %p)\n", iface, dwDrawAspect, psizel); + TRACE("(%p, %x, %p)\n", iface, dwDrawAspect, psizel); if (This->pOleDelegate) return IOleObject_GetExtent(This->pOleDelegate, dwDrawAspect, psizel); @@ -805,7 +803,7 @@ static HRESULT WINAPI DefaultHandler_Unadvise( { DefaultHandler *This = impl_from_IOleObject(iface); - TRACE("(%p, %ld)\n", iface, dwConnection); + TRACE("(%p, %d)\n", iface, dwConnection); /* * If we don't have an advise holder yet, it means we don't have @@ -841,10 +839,9 @@ static HRESULT WINAPI DefaultHandler_EnumAdvise( *ppenumAdvise = NULL; if (!This->oleAdviseHolder) - return IOleAdviseHolder_EnumAdvise(This->oleAdviseHolder, - ppenumAdvise); + return S_OK; - return S_OK; + return IOleAdviseHolder_EnumAdvise(This->oleAdviseHolder, ppenumAdvise); } /************************************************************************ @@ -863,10 +860,7 @@ static HRESULT WINAPI DefaultHandler_GetMiscStatus( HRESULT hres; DefaultHandler *This = impl_from_IOleObject(iface); - TRACE("(%p, %lx, %p)\n", iface, dwAspect, pdwStatus); - - if (This->pOleDelegate) - return IOleObject_GetMiscStatus(This->pOleDelegate, dwAspect, pdwStatus); + TRACE("(%p, %x, %p)\n", iface, dwAspect, pdwStatus); if (This->pOleDelegate) return IOleObject_GetMiscStatus(This->pOleDelegate, dwAspect, pdwStatus); @@ -978,6 +972,9 @@ static HRESULT WINAPI DefaultHandler_GetData( IDataObject_Release(cacheDataObject); + if (FAILED(hres) && This->pDataDelegate) + hres = IDataObject_GetData(This->pDataDelegate, pformatetcIn, pmedium); + return hres; } @@ -1021,6 +1018,9 @@ static HRESULT WINAPI DefaultHandler_QueryGetData( IDataObject_Release(cacheDataObject); + if (FAILED(hres) && This->pDataDelegate) + hres = IDataObject_QueryGetData(This->pDataDelegate, pformatetc); + return hres; } @@ -1037,16 +1037,13 @@ static HRESULT WINAPI DefaultHandler_GetCanonicalFormatEtc( LPFORMATETC pformatetcOut) { DefaultHandler *This = impl_from_IDataObject(iface); - IDataObject *pDataObject; - HRESULT hr; TRACE("(%p, %p, %p)\n", iface, pformatetcIn, pformatetcOut); - if (!This->pOleDelegate) + if (!This->pDataDelegate) return OLE_E_NOTRUNNING; - hr = IOleObject_QueryInterface(This->pOleDelegate, &IID_IDataObject, (void **)&pDataObject); - return IDataObject_GetCanonicalFormatEtc(pDataObject, pformatetcIn, pformatetcOut); + return IDataObject_GetCanonicalFormatEtc(This->pDataDelegate, pformatetcIn, pformatetcOut); } /************************************************************************ @@ -1102,7 +1099,7 @@ static HRESULT WINAPI DefaultHandler_EnumFormatEtc( HRESULT hres; DefaultHandler *This = impl_from_IDataObject(iface); - TRACE("(%p, %lx, %p)\n", iface, dwDirection, ppenumFormatEtc); + TRACE("(%p, %x, %p)\n", iface, dwDirection, ppenumFormatEtc); hres = OleRegEnumFormatEtc(&This->clsid, dwDirection, ppenumFormatEtc); @@ -1127,12 +1124,16 @@ static HRESULT WINAPI DefaultHandler_DAdvise( HRESULT hres = S_OK; DefaultHandler *This = impl_from_IDataObject(iface); - TRACE("(%p, %p, %ld, %p, %p)\n", + TRACE("(%p, %p, %d, %p, %p)\n", iface, pformatetc, advf, pAdvSink, pdwConnection); /* Make sure we have a data advise holder before we start. */ if (!This->dataAdviseHolder) + { hres = CreateDataAdviseHolder(&This->dataAdviseHolder); + if (SUCCEEDED(hres) && This->pDataDelegate) + DataAdviseHolder_OnConnect(This->dataAdviseHolder, This->pDataDelegate); + } if (SUCCEEDED(hres)) hres = IDataAdviseHolder_Advise(This->dataAdviseHolder, @@ -1159,7 +1160,7 @@ static HRESULT WINAPI DefaultHandler_DUnadvise( { DefaultHandler *This = impl_from_IDataObject(iface); - TRACE("(%p, %ld)\n", iface, dwConnection); + TRACE("(%p, %d)\n", iface, dwConnection); /* * If we don't have a data advise holder yet, it means that diff --git a/reactos/dll/win32/ole32/dictionary.c b/reactos/dll/win32/ole32/dictionary.c index b64f24f53ea..6e114786385 100644 --- a/reactos/dll/win32/ole32/dictionary.c +++ b/reactos/dll/win32/ole32/dictionary.c @@ -15,7 +15,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include diff --git a/reactos/dll/win32/ole32/dictionary.h b/reactos/dll/win32/ole32/dictionary.h index db648343b92..231a6474723 100644 --- a/reactos/dll/win32/ole32/dictionary.h +++ b/reactos/dll/win32/ole32/dictionary.h @@ -17,7 +17,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DICTIONARY_H__ #define __DICTIONARY_H__ diff --git a/reactos/dll/win32/ole32/enumx.c b/reactos/dll/win32/ole32/enumx.c new file mode 100644 index 00000000000..232abec66c1 --- /dev/null +++ b/reactos/dll/win32/ole32/enumx.c @@ -0,0 +1,202 @@ +/* + * IEnum* implementation + * + * Copyright 2006 Mike McCormack + * + * 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 + */ + +#define COBJMACROS + +#include + +#include "windef.h" +#include "winbase.h" +#include "objbase.h" +#include "wine/list.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +typedef struct tagEnumSTATPROPSETSTG_impl +{ + const void *vtbl; + LONG ref; + struct list elements; + struct list *current; + ULONG elem_size; + GUID riid; +} enumx_impl; + +/************************************************************************ + * enumx_QueryInterface + */ +HRESULT WINAPI enumx_QueryInterface( + enumx_impl *This, + REFIID riid, + void** ppvObject) +{ + if ( (This==0) || (ppvObject==0) ) + return E_INVALIDARG; + + *ppvObject = 0; + + if (IsEqualGUID(&IID_IUnknown, riid) || + IsEqualGUID(&This->riid, riid)) + { + IUnknown_AddRef(((IUnknown*)This)); + *ppvObject = This; + return S_OK; + } + + return E_NOINTERFACE; +} + +/************************************************************************ + * enumx_AddRef + */ +ULONG WINAPI enumx_AddRef(enumx_impl *This) +{ + return InterlockedIncrement(&This->ref); +} + +/************************************************************************ + * enumx_Release + */ +ULONG WINAPI enumx_Release(enumx_impl *This) +{ + ULONG ref; + + ref = InterlockedDecrement(&This->ref); + if (ref == 0) + { + while (!list_empty(&This->elements)) + { + struct list *x = list_head(&This->elements); + list_remove(x); + HeapFree(GetProcessHeap(), 0, x); + } + HeapFree(GetProcessHeap(), 0, This); + } + return ref; +} + +/************************************************************************ + * enumx_Next + */ +HRESULT WINAPI enumx_Next(enumx_impl *This, ULONG celt, + void *rgelt, ULONG *pceltFetched) +{ + unsigned char *p; + ULONG count = 0; + + TRACE("%p %u %p\n", This, celt, pceltFetched); + + if (This->current == NULL) + This->current = list_head(&This->elements); + p = rgelt; + while (count < celt && This->current && This->current != &This->elements) + { + memcpy(p, &This->current[1], This->elem_size); + p += This->elem_size; + This->current = This->current->next; + count++; + } + if (pceltFetched) + *pceltFetched = count; + if (count < celt) + return S_FALSE; + return S_OK; +} + +/************************************************************************ + * enumx_Skip + */ +HRESULT WINAPI enumx_Skip(enumx_impl *This, ULONG celt) +{ + ULONG count = 0; + + TRACE("%p %u\n", This, celt); + + if (This->current == NULL) + This->current = list_head(&This->elements); + + while (count < celt && This->current && This->current != &This->elements) + count++; + + return S_OK; +} + +/************************************************************************ + * enumx_Reset + */ +HRESULT WINAPI enumx_Reset(enumx_impl *This) +{ + TRACE("\n"); + + This->current = NULL; + return S_OK; +} + +/************************************************************************ + * enumx_fnClone + */ +HRESULT WINAPI enumx_Clone( + enumx_impl *iface, + enumx_impl **ppenum) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +/************************************************************************ + * enumx_allocate + * + * Allocate a generic enumerator + */ +enumx_impl *enumx_allocate(REFIID riid, const void *vtbl, ULONG elem_size) +{ + enumx_impl *enumx; + + enumx = HeapAlloc(GetProcessHeap(), 0, sizeof *enumx); + if (enumx) + { + enumx->vtbl = vtbl; + enumx->ref = 1; + enumx->current = NULL; + enumx->elem_size = elem_size; + memcpy(&enumx->riid, riid, sizeof *riid); + list_init(&enumx->elements); + } + + return enumx; +} + +/************************************************************************ + * enumx_add_element + * + * Add an element to the enumeration. + */ +void *enumx_add_element(enumx_impl *enumx, void *data) +{ + struct list *element; + + element = HeapAlloc(GetProcessHeap(), 0, sizeof *element + enumx->elem_size); + if (!element) + return NULL; + memcpy(&element[1], data, enumx->elem_size); + list_add_tail(&enumx->elements, element); + return &element[1]; +} diff --git a/reactos/dll/win32/ole32/enumx.h b/reactos/dll/win32/ole32/enumx.h new file mode 100644 index 00000000000..2d36b732549 --- /dev/null +++ b/reactos/dll/win32/ole32/enumx.h @@ -0,0 +1,34 @@ +/* + * Copyright 2006 Mike McCormack + * + * 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 + */ + +#ifndef __OLE_ENUM_H__ +#define __OLE_ENUM_H__ + +typedef struct tagEnumSTATPROPSETSTG_impl enumx_impl; + +extern HRESULT WINAPI enumx_QueryInterface(enumx_impl *, REFIID, void**); +extern ULONG WINAPI enumx_AddRef(enumx_impl *); +extern ULONG WINAPI enumx_Release(enumx_impl *); +extern HRESULT WINAPI enumx_Next(enumx_impl *, ULONG, void *, ULONG *); +extern HRESULT WINAPI enumx_Skip(enumx_impl *, ULONG); +extern HRESULT WINAPI enumx_Reset(enumx_impl *); +extern HRESULT WINAPI enumx_Clone(enumx_impl *, enumx_impl **); +extern enumx_impl *enumx_allocate(REFIID, const void *, ULONG); +extern void *enumx_add_element(enumx_impl *, void *); + +#endif diff --git a/reactos/dll/win32/ole32/errorinfo.c b/reactos/dll/win32/ole32/errorinfo.c index 7404c6cf1ac..01dc30531ff 100644 --- a/reactos/dll/win32/ole32/errorinfo.c +++ b/reactos/dll/win32/ole32/errorinfo.c @@ -15,7 +15,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * NOTES: * @@ -52,7 +52,7 @@ static BSTR WINAPI ERRORINFO_SysAllocString(const OLECHAR* in) if (in == NULL) return NULL; /* - * Find the lenth of the buffer passed-in in bytes. + * Find the length of the buffer passed-in, in bytes. */ len = strlenW(in); bufferSize = len * sizeof (WCHAR); @@ -83,14 +83,10 @@ static BSTR WINAPI ERRORINFO_SysAllocString(const OLECHAR* in) newBuffer++; /* - * Copy the information in the buffer. - * Since it is valid to pass a NULL pointer here, we'll initialize the - * buffer to nul if it is the case. + * Copy the information in the buffer. It is not possible to pass + * a NULL pointer here. */ - if (in != 0) - memcpy(newBuffer, in, bufferSize); - else - memset(newBuffer, 0, bufferSize); + memcpy(newBuffer, in, bufferSize); /* * Make sure that there is a nul character at the end of the @@ -171,7 +167,7 @@ static inline ErrorInfoImpl *impl_from_ISupportErrorInfo( ISupportErrorInfo *ifa #define _ICreateErrorInfo_(This) (ICreateErrorInfo*)&(This->lpvtcei) #define _ISupportErrorInfo_(This) (ISupportErrorInfo*)&(This->lpvtsei) -IErrorInfo * IErrorInfoImpl_Constructor(void) +static IErrorInfo * IErrorInfoImpl_Constructor(void) { ErrorInfoImpl * ei = HeapAlloc(GetProcessHeap(), 0, sizeof(ErrorInfoImpl)); if (ei) @@ -226,7 +222,7 @@ static ULONG WINAPI IErrorInfoImpl_AddRef( IErrorInfo* iface) { ErrorInfoImpl *This = impl_from_IErrorInfo(iface); - TRACE("(%p)->(count=%lu)\n",This,This->ref); + TRACE("(%p)->(count=%u)\n",This,This->ref); return InterlockedIncrement(&This->ref); } @@ -236,7 +232,7 @@ static ULONG WINAPI IErrorInfoImpl_Release( ErrorInfoImpl *This = impl_from_IErrorInfo(iface); ULONG ref = InterlockedDecrement(&This->ref); - TRACE("(%p)->(count=%lu)\n",This,ref+1); + TRACE("(%p)->(count=%u)\n",This,ref+1); if (!ref) { @@ -252,7 +248,7 @@ static HRESULT WINAPI IErrorInfoImpl_GetGUID( GUID * pGUID) { ErrorInfoImpl *This = impl_from_IErrorInfo(iface); - TRACE("(%p)->(count=%lu)\n",This,This->ref); + TRACE("(%p)->(count=%u)\n",This,This->ref); if(!pGUID )return E_INVALIDARG; memcpy(pGUID, &This->m_Guid, sizeof(GUID)); return S_OK; @@ -405,7 +401,7 @@ static HRESULT WINAPI ICreateErrorInfoImpl_SetHelpContext( DWORD dwHelpContext) { ErrorInfoImpl *This = impl_from_ICreateErrorInfo(iface); - TRACE("(%p,%ld)\n",This,dwHelpContext); + TRACE("(%p,%d)\n",This,dwHelpContext); This->m_dwHelpContext = dwHelpContext; return S_OK; } @@ -490,10 +486,16 @@ HRESULT WINAPI CreateErrorInfo(ICreateErrorInfo **pperrinfo) */ HRESULT WINAPI GetErrorInfo(ULONG dwReserved, IErrorInfo **pperrinfo) { - TRACE("(%ld, %p, %p)\n", dwReserved, pperrinfo, COM_CurrentInfo()->errorinfo); + TRACE("(%d, %p, %p)\n", dwReserved, pperrinfo, COM_CurrentInfo()->errorinfo); + + if (dwReserved) + { + ERR("dwReserved (0x%x) != 0\n", dwReserved); + return E_INVALIDARG; + } if(!pperrinfo) return E_INVALIDARG; - + if (!COM_CurrentInfo()->errorinfo) { *pperrinfo = NULL; @@ -514,8 +516,14 @@ HRESULT WINAPI SetErrorInfo(ULONG dwReserved, IErrorInfo *perrinfo) { IErrorInfo * pei; - TRACE("(%ld, %p)\n", dwReserved, perrinfo); - + TRACE("(%d, %p)\n", dwReserved, perrinfo); + + if (dwReserved) + { + ERR("dwReserved (0x%x) != 0\n", dwReserved); + return E_INVALIDARG; + } + /* release old errorinfo */ pei = COM_CurrentInfo()->errorinfo; if (pei) IErrorInfo_Release(pei); diff --git a/reactos/dll/win32/ole32/filemoniker.c b/reactos/dll/win32/ole32/filemoniker.c index d4494361462..7578836dbcf 100644 --- a/reactos/dll/win32/ole32/filemoniker.c +++ b/reactos/dll/win32/ole32/filemoniker.c @@ -2,6 +2,7 @@ * FileMonikers implementation * * Copyright 1999 Noomen Hamza + * Copyright 2007 Robert Shearman * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -15,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include @@ -39,10 +40,6 @@ 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{ @@ -530,7 +527,7 @@ FileMonikerImpl_BindToObject(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft } if (pcf!=NULL){ - IClassFactory_CreateInstance(pcf,NULL,&IID_IPersistFile,(void**)ppf); + IClassFactory_CreateInstance(pcf,NULL,&IID_IPersistFile,(void**)&ppf); res=IPersistFile_Load(ppf,This->filePathName,STGM_READ); @@ -643,7 +640,7 @@ static HRESULT WINAPI FileMonikerImpl_Reduce(IMoniker* iface, IBindCtx* pbc, DWORD dwReduceHowFar, IMoniker** ppmkToLeft, IMoniker** ppmkReduced) { - TRACE("(%p,%p,%ld,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced); + TRACE("(%p,%p,%d,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced); if (ppmkReduced==NULL) return E_POINTER; @@ -1249,7 +1246,7 @@ FileMonikerROTDataImpl_GetComparisonData(IROTData* iface, BYTE* pbData, int i; LPWSTR pszFileName; - TRACE("(%p, %lu, %p)\n", pbData, cbMax, pcbData); + TRACE("(%p, %u, %p)\n", pbData, cbMax, pcbData); *pcbData = sizeof(CLSID) + len * sizeof(WCHAR); if (cbMax < *pcbData) @@ -1409,6 +1406,105 @@ HRESULT WINAPI CreateFileMoniker(LPCOLESTR lpszPathName, LPMONIKER * ppmk) return hr; } +/* find a character from a set in reverse without the string having to be null-terminated */ +static inline WCHAR *memrpbrkW(const WCHAR *ptr, size_t n, const WCHAR *accept) +{ + const WCHAR *end, *ret = NULL; + for (end = ptr + n; ptr < end; ptr++) if (strchrW(accept, *ptr)) ret = ptr; + return (WCHAR *)ret; +} + +HRESULT FileMoniker_CreateFromDisplayName(LPBC pbc, LPCOLESTR szDisplayName, + LPDWORD pchEaten, LPMONIKER *ppmk) +{ + LPCWSTR end; + static const WCHAR wszSeparators[] = {':','\\','/','!',0}; + + for (end = szDisplayName + strlenW(szDisplayName); + end && (end != szDisplayName); + end = memrpbrkW(szDisplayName, end - szDisplayName, wszSeparators)) + { + HRESULT hr; + IRunningObjectTable *rot; + IMoniker *file_moniker; + LPWSTR file_display_name; + LPWSTR full_path_name; + DWORD full_path_name_len; + int len = end - szDisplayName; + + file_display_name = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)); + if (!file_display_name) return E_OUTOFMEMORY; + memcpy(file_display_name, szDisplayName, len * sizeof(WCHAR)); + file_display_name[len] = '\0'; + + hr = CreateFileMoniker(file_display_name, &file_moniker); + if (FAILED(hr)) + { + HeapFree(GetProcessHeap(), 0, file_display_name); + return hr; + } + + hr = IBindCtx_GetRunningObjectTable(pbc, &rot); + if (FAILED(hr)) + { + HeapFree(GetProcessHeap(), 0, file_display_name); + IMoniker_Release(file_moniker); + return hr; + } + + hr = IRunningObjectTable_IsRunning(rot, file_moniker); + IRunningObjectTable_Release(rot); + if (FAILED(hr)) + { + HeapFree(GetProcessHeap(), 0, file_display_name); + IMoniker_Release(file_moniker); + return hr; + } + if (hr == S_OK) + { + TRACE("found running file moniker for %s\n", debugstr_w(file_display_name)); + *pchEaten = len; + *ppmk = file_moniker; + HeapFree(GetProcessHeap(), 0, file_display_name); + return S_OK; + } + + full_path_name_len = GetFullPathNameW(file_display_name, 0, NULL, NULL); + if (!full_path_name_len) + { + HeapFree(GetProcessHeap(), 0, file_display_name); + IMoniker_Release(file_moniker); + return MK_E_SYNTAX; + } + full_path_name = HeapAlloc(GetProcessHeap(), 0, full_path_name_len * sizeof(WCHAR)); + if (!full_path_name) + { + HeapFree(GetProcessHeap(), 0, file_display_name); + IMoniker_Release(file_moniker); + return E_OUTOFMEMORY; + } + GetFullPathNameW(file_display_name, full_path_name_len, full_path_name, NULL); + + if (GetFileAttributesW(full_path_name) == INVALID_FILE_ATTRIBUTES) + TRACE("couldn't open file %s\n", debugstr_w(full_path_name)); + else + { + TRACE("got file moniker for %s\n", debugstr_w(szDisplayName)); + *pchEaten = len; + *ppmk = file_moniker; + HeapFree(GetProcessHeap(), 0, file_display_name); + HeapFree(GetProcessHeap(), 0, full_path_name); + return S_OK; + } + HeapFree(GetProcessHeap(), 0, file_display_name); + HeapFree(GetProcessHeap(), 0, full_path_name); + IMoniker_Release(file_moniker); + } + + return MK_E_CANTOPENFILE; +} + + static HRESULT WINAPI FileMonikerCF_QueryInterface(LPCLASSFACTORY iface, REFIID riid, LPVOID *ppv) { diff --git a/reactos/dll/win32/ole32/ftmarshal.c b/reactos/dll/win32/ole32/ftmarshal.c index 31e1262ce1f..9f6ad8ca647 100644 --- a/reactos/dll/win32/ole32/ftmarshal.c +++ b/reactos/dll/win32/ole32/ftmarshal.c @@ -15,7 +15,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" @@ -34,6 +34,8 @@ #include "wine/debug.h" +#include "compobj_private.h" + WINE_DEFAULT_DEBUG_CHANNEL(ole); typedef struct _FTMarshalImpl { @@ -136,7 +138,12 @@ static HRESULT WINAPI FTMarshalImpl_GetUnmarshalClass (LPMARSHAL iface, REFIID riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, CLSID * pCid) { - FIXME ("(), stub!\n"); + TRACE("(%s, %p, 0x%x, %p, 0x%x, %p)\n", debugstr_guid(riid), pv, + dwDestContext, pvDestContext, mshlflags, pCid); + if (dwDestContext == MSHCTX_INPROC || dwDestContext == MSHCTX_CROSSCTX) + memcpy(pCid, &CLSID_InProcFreeMarshaler, sizeof(CLSID_InProcFreeMarshaler)); + else + memcpy(pCid, &CLSID_DfMarshal, sizeof(CLSID_InProcFreeMarshaler)); return S_OK; } @@ -148,15 +155,14 @@ FTMarshalImpl_GetMarshalSizeMax (LPMARSHAL iface, REFIID riid, void *pv, DWORD d IMarshal *pMarshal = NULL; HRESULT hres; - FTMarshalImpl *This = impl_from_IMarshal(iface); - - FIXME ("(), stub!\n"); + TRACE("(%s, %p, 0x%x, %p, 0x%x, %p)\n", debugstr_guid(riid), pv, + dwDestContext, pvDestContext, mshlflags, pSize); /* if the marshalling happens inside the same process the interface pointer is copied between the apartments */ if (dwDestContext == MSHCTX_INPROC || dwDestContext == MSHCTX_CROSSCTX) { - *pSize = sizeof (This); - return S_OK; + *pSize = sizeof (mshlflags) + sizeof (pv) + sizeof (DWORD) + sizeof (GUID); + return S_OK; } /* use the standard marshaller to handle all other cases */ @@ -174,14 +180,37 @@ FTMarshalImpl_MarshalInterface (LPMARSHAL iface, IStream * pStm, REFIID riid, vo IMarshal *pMarshal = NULL; HRESULT hres; - FTMarshalImpl *This = impl_from_IMarshal(iface); - - FIXME ("(), stub!\n"); + TRACE("(%p, %s, %p, 0x%x, %p, 0x%x)\n", pStm, debugstr_guid(riid), pv, + dwDestContext, pvDestContext, mshlflags); /* if the marshalling happens inside the same process the interface pointer is copied between the apartments */ if (dwDestContext == MSHCTX_INPROC || dwDestContext == MSHCTX_CROSSCTX) { - return IStream_Write (pStm, This, sizeof (This), 0); + void *object; + DWORD constant = 0; + GUID unknown_guid = { 0 }; + + hres = IUnknown_QueryInterface((IUnknown *)pv, riid, &object); + if (FAILED(hres)) + return hres; + + /* don't hold a reference to table-weak marshaled interfaces */ + if (mshlflags & MSHLFLAGS_TABLEWEAK) + IUnknown_Release((IUnknown *)object); + + hres = IStream_Write (pStm, &mshlflags, sizeof (mshlflags), NULL); + if (hres != S_OK) return STG_E_MEDIUMFULL; + + hres = IStream_Write (pStm, &object, sizeof (object), NULL); + if (hres != S_OK) return STG_E_MEDIUMFULL; + + hres = IStream_Write (pStm, &constant, sizeof (constant), NULL); + if (hres != S_OK) return STG_E_MEDIUMFULL; + + hres = IStream_Write (pStm, &unknown_guid, sizeof (unknown_guid), NULL); + if (hres != S_OK) return STG_E_MEDIUMFULL; + + return S_OK; } /* use the standard marshaler to handle all other cases */ @@ -194,19 +223,66 @@ FTMarshalImpl_MarshalInterface (LPMARSHAL iface, IStream * pStm, REFIID riid, vo static HRESULT WINAPI FTMarshalImpl_UnmarshalInterface (LPMARSHAL iface, IStream * pStm, REFIID riid, void **ppv) { - FIXME ("(), stub!\n"); - return S_OK; + DWORD mshlflags; + IUnknown *object; + DWORD constant; + GUID unknown_guid; + HRESULT hres; + + TRACE ("(%p, %s, %p)\n", pStm, debugstr_guid(riid), ppv); + + hres = IStream_Read (pStm, &mshlflags, sizeof (mshlflags), NULL); + if (hres != S_OK) return STG_E_READFAULT; + + hres = IStream_Read (pStm, &object, sizeof (object), NULL); + if (hres != S_OK) return STG_E_READFAULT; + + hres = IStream_Read (pStm, &constant, sizeof (constant), NULL); + if (hres != S_OK) return STG_E_READFAULT; + if (constant != 0) + FIXME("constant is 0x%x instead of 0\n", constant); + + hres = IStream_Read (pStm, &unknown_guid, sizeof (unknown_guid), NULL); + if (hres != S_OK) return STG_E_READFAULT; + + hres = IUnknown_QueryInterface(object, riid, ppv); + if (!(mshlflags & (MSHLFLAGS_TABLEWEAK|MSHLFLAGS_TABLESTRONG))) + IUnknown_Release(object); + return hres; } static HRESULT WINAPI FTMarshalImpl_ReleaseMarshalData (LPMARSHAL iface, IStream * pStm) { - FIXME ("(), stub!\n"); + DWORD mshlflags; + IUnknown *object; + DWORD constant; + GUID unknown_guid; + HRESULT hres; + + TRACE ("(%p)\n", pStm); + + hres = IStream_Read (pStm, &mshlflags, sizeof (mshlflags), NULL); + if (hres != S_OK) return STG_E_READFAULT; + + hres = IStream_Read (pStm, &object, sizeof (object), NULL); + if (hres != S_OK) return STG_E_READFAULT; + + hres = IStream_Read (pStm, &constant, sizeof (constant), NULL); + if (hres != S_OK) return STG_E_READFAULT; + if (constant != 0) + FIXME("constant is 0x%x instead of 0\n", constant); + + hres = IStream_Read (pStm, &unknown_guid, sizeof (unknown_guid), NULL); + if (hres != S_OK) return STG_E_READFAULT; + + IUnknown_Release(object); return S_OK; } static HRESULT WINAPI FTMarshalImpl_DisconnectObject (LPMARSHAL iface, DWORD dwReserved) { - FIXME ("(), stub!\n"); + TRACE ("()\n"); + /* nothing to do */ return S_OK; } @@ -226,6 +302,23 @@ static const IMarshalVtbl ftmvtbl = /*********************************************************************** * CoCreateFreeThreadedMarshaler [OLE32.@] * + * Creates a free-threaded marshaler. + * + * PARAMS + * punkOuter [I] Optional. Outer unknown. + * ppunkMarshal [O] On return, the inner unknown of the created free-threaded marshaler. + * + * RETURNS + * Success: S_OK + * Failure: E_OUTOFMEMORY if no memory available to create object. + * + * NOTES + * Objects that ensure their state is maintained consistent when used by + * multiple threads and reference no single-threaded objects are known as + * free-threaded. The free-threaded marshaler enables these objects to be + * efficiently marshaled within the same process, by not creating proxies + * (as they aren't needed for the object to be safely used), whilst still + * allowing the object to be used in inter-process and inter-machine contexts. */ HRESULT WINAPI CoCreateFreeThreadedMarshaler (LPUNKNOWN punkOuter, LPUNKNOWN * ppunkMarshal) { @@ -241,8 +334,73 @@ HRESULT WINAPI CoCreateFreeThreadedMarshaler (LPUNKNOWN punkOuter, LPUNKNOWN * p ftm->lpVtbl = &iunkvt; ftm->lpvtblFTM = &ftmvtbl; ftm->ref = 1; - ftm->pUnkOuter = punkOuter; + ftm->pUnkOuter = punkOuter ? punkOuter : _IFTMUnknown_(ftm); *ppunkMarshal = _IFTMUnknown_ (ftm); return S_OK; } + +static HRESULT WINAPI FTMarshalCF_QueryInterface(LPCLASSFACTORY iface, + REFIID riid, LPVOID *ppv) +{ + *ppv = NULL; + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory)) + { + *ppv = iface; + IUnknown_AddRef(iface); + return S_OK; + } + return E_NOINTERFACE; +} + +static ULONG WINAPI FTMarshalCF_AddRef(LPCLASSFACTORY iface) +{ + return 2; /* non-heap based object */ +} + +static ULONG WINAPI FTMarshalCF_Release(LPCLASSFACTORY iface) +{ + return 1; /* non-heap based object */ +} + +static HRESULT WINAPI FTMarshalCF_CreateInstance(LPCLASSFACTORY iface, + LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv) +{ + IUnknown *pUnknown; + HRESULT hr; + + TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv); + + *ppv = NULL; + + hr = CoCreateFreeThreadedMarshaler(pUnk, &pUnknown); + + if (SUCCEEDED(hr)) + { + hr = IUnknown_QueryInterface(pUnknown, riid, ppv); + IUnknown_Release(pUnknown); + } + + return hr; +} + +static HRESULT WINAPI FTMarshalCF_LockServer(LPCLASSFACTORY iface, BOOL fLock) +{ + FIXME("(%d), stub!\n",fLock); + return S_OK; +} + +static const IClassFactoryVtbl FTMarshalCFVtbl = +{ + FTMarshalCF_QueryInterface, + FTMarshalCF_AddRef, + FTMarshalCF_Release, + FTMarshalCF_CreateInstance, + FTMarshalCF_LockServer +}; +static const IClassFactoryVtbl *FTMarshalCF = &FTMarshalCFVtbl; + +HRESULT FTMarshalCF_Create(REFIID riid, LPVOID *ppv) +{ + return IClassFactory_QueryInterface((IClassFactory *)&FTMarshalCF, riid, ppv); +} diff --git a/reactos/dll/win32/ole32/git.c b/reactos/dll/win32/ole32/git.c index cdf763a2f5a..222eb6f375f 100644 --- a/reactos/dll/win32/ole32/git.c +++ b/reactos/dll/win32/ole32/git.c @@ -21,16 +21,10 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include "config.h" - -#include -#include #include -#include -#include #define COBJMACROS #define NONAMELESSUNION @@ -42,11 +36,10 @@ #include "objbase.h" #include "ole2.h" #include "winerror.h" -#include "winreg.h" -#include "winternl.h" #include "compobj_private.h" +#include "wine/list.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(ole); @@ -65,8 +58,7 @@ typedef struct StdGITEntry IID iid; /* IID of the interface */ IStream* stream; /* Holds the marshalled interface */ - struct StdGITEntry* next; - struct StdGITEntry* prev; + struct list entry; } StdGITEntry; /* Class data */ @@ -75,8 +67,7 @@ typedef struct StdGlobalInterfaceTableImpl const IGlobalInterfaceTableVtbl *lpVtbl; ULONG ref; - struct StdGITEntry* firstEntry; - struct StdGITEntry* lastEntry; + struct list list; ULONG nextCookie; } StdGlobalInterfaceTableImpl; @@ -94,7 +85,8 @@ static CRITICAL_SECTION git_section = { &critsect_debug, -1, 0, 0, 0, 0 }; /** This destroys it again. It should revoke all the held interfaces first **/ -void StdGlobalInterfaceTable_Destroy(void* self) { +static void StdGlobalInterfaceTable_Destroy(void* self) +{ TRACE("(%p)\n", self); FIXME("Revoke held interfaces here\n"); @@ -115,13 +107,11 @@ StdGlobalInterfaceTable_FindEntry(IGlobalInterfaceTable* iface, DWORD cookie) TRACE("iface=%p, cookie=0x%x\n", iface, (UINT)cookie); EnterCriticalSection(&git_section); - e = self->firstEntry; - while (e != NULL) { + LIST_FOR_EACH_ENTRY(e, &self->list, StdGITEntry, entry) { if (e->cookie == cookie) { LeaveCriticalSection(&git_section); return e; } - e = e->next; } LeaveCriticalSection(&git_section); @@ -210,7 +200,7 @@ StdGlobalInterfaceTable_RegisterInterfaceInGlobal( } zero.QuadPart = 0; - IStream_Seek(stream, zero, SEEK_SET, NULL); + IStream_Seek(stream, zero, STREAM_SEEK_SET, NULL); entry = HeapAlloc(GetProcessHeap(), 0, sizeof(StdGITEntry)); if (entry == NULL) return E_OUTOFMEMORY; @@ -223,18 +213,14 @@ StdGlobalInterfaceTable_RegisterInterfaceInGlobal( self->nextCookie++; /* inc the cookie count */ /* insert the new entry at the end of the list */ - entry->next = NULL; - entry->prev = self->lastEntry; - if (entry->prev) entry->prev->next = entry; - else self->firstEntry = entry; - self->lastEntry = entry; + list_add_tail(&self->list, &entry->entry); /* and return the cookie */ *pdwCookie = entry->cookie; LeaveCriticalSection(&git_section); - TRACE("Cookie is 0x%lx\n", entry->cookie); + TRACE("Cookie is 0x%x\n", entry->cookie); return S_OK; } @@ -242,7 +228,6 @@ static HRESULT WINAPI StdGlobalInterfaceTable_RevokeInterfaceFromGlobal( IGlobalInterfaceTable* iface, DWORD dwCookie) { - StdGlobalInterfaceTableImpl* const self = (StdGlobalInterfaceTableImpl*) iface; StdGITEntry* entry; HRESULT hr; @@ -258,17 +243,14 @@ StdGlobalInterfaceTable_RevokeInterfaceFromGlobal( hr = CoReleaseMarshalData(entry->stream); if (hr != S_OK) { - WARN("Failed to release marshal data, hr = 0x%08lx\n", hr); + WARN("Failed to release marshal data, hr = 0x%08x\n", hr); return hr; } IStream_Release(entry->stream); /* chop entry out of the list, and free the memory */ EnterCriticalSection(&git_section); - if (entry->prev) entry->prev->next = entry->next; - else self->firstEntry = entry->next; - if (entry->next) entry->next->prev = entry->prev; - else self->lastEntry = entry->prev; + list_remove(&entry->entry); LeaveCriticalSection(&git_section); HeapFree(GetProcessHeap(), 0, entry); @@ -285,7 +267,7 @@ StdGlobalInterfaceTable_GetInterfaceFromGlobal( LARGE_INTEGER move; LPUNKNOWN lpUnk; - TRACE("dwCookie=0x%lx, riid=%s, ppv=%p\n", dwCookie, debugstr_guid(riid), ppv); + TRACE("dwCookie=0x%x, riid=%s, ppv=%p\n", dwCookie, debugstr_guid(riid), ppv); entry = StdGlobalInterfaceTable_FindEntry(iface, dwCookie); if (entry == NULL) return E_INVALIDARG; @@ -298,16 +280,17 @@ StdGlobalInterfaceTable_GetInterfaceFromGlobal( /* unmarshal the interface */ hres = CoUnmarshalInterface(entry->stream, riid, ppv); - if (hres) { - WARN("Failed to unmarshal stream\n"); - return hres; - } /* rewind stream, in case it's used again */ move.u.LowPart = 0; move.u.HighPart = 0; IStream_Seek(entry->stream, move, STREAM_SEEK_SET, NULL); + if (hres) { + WARN("Failed to unmarshal stream\n"); + return hres; + } + /* addref it */ lpUnk = *ppv; IUnknown_AddRef(lpUnk); @@ -389,7 +372,7 @@ static const IGlobalInterfaceTableVtbl StdGlobalInterfaceTableImpl_Vtbl = }; /** This function constructs the GIT. It should only be called once **/ -void* StdGlobalInterfaceTable_Construct() +void* StdGlobalInterfaceTable_Construct(void) { StdGlobalInterfaceTableImpl* newGIT; @@ -398,8 +381,7 @@ void* StdGlobalInterfaceTable_Construct() newGIT->lpVtbl = &StdGlobalInterfaceTableImpl_Vtbl; newGIT->ref = 1; /* Initialise the reference count */ - newGIT->firstEntry = NULL; /* we start with an empty table */ - newGIT->lastEntry = NULL; + list_init(&newGIT->list); newGIT->nextCookie = 0xf100; /* that's where windows starts, so that's where we start */ TRACE("Created the GIT at %p\n", newGIT); diff --git a/reactos/dll/win32/ole32/hglobalstream.c b/reactos/dll/win32/ole32/hglobalstream.c index 4d1d4b5ebfb..d98c0c53402 100644 --- a/reactos/dll/win32/ole32/hglobalstream.c +++ b/reactos/dll/win32/ole32/hglobalstream.c @@ -18,7 +18,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" @@ -49,7 +49,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(storage); /**************************************************************************** * HGLOBALStreamImpl definition. * - * This class imlements the IStream inteface and represents a stream + * This class implements the IStream interface and represents a stream * supported by an HGLOBAL pointer. */ struct HGLOBALStreamImpl @@ -148,11 +148,9 @@ static HRESULT WINAPI HGLOBALStreamImpl_QueryInterface( /* * Compare the riid with the interface IDs implemented by this object. */ - if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) - { - *ppvObject = (IStream*)This; - } - else if (memcmp(&IID_IStream, riid, sizeof(IID_IStream)) == 0) + if (IsEqualIID(&IID_IUnknown, riid) || + IsEqualIID(&IID_ISequentialStream, riid) || + IsEqualIID(&IID_IStream, riid)) { *ppvObject = (IStream*)This; } @@ -216,7 +214,7 @@ static HRESULT WINAPI HGLOBALStreamImpl_Read( ULONG bytesReadBuffer; ULONG bytesToReadFromBuffer; - TRACE("(%p, %p, %ld, %p)\n", iface, + TRACE("(%p, %p, %d, %p)\n", iface, pv, cb, pcbRead); /* @@ -255,14 +253,11 @@ static HRESULT WINAPI HGLOBALStreamImpl_Read( GlobalUnlock(This->supportHandle); /* - * The function returns S_OK if the buffer was filled completely - * it returns S_FALSE if the end of the stream is reached before the + * Always returns S_OK even if the end of the stream is reached before the * buffer is filled */ - if(*pcbRead == cb) - return S_OK; - return S_FALSE; + return S_OK; } /*** @@ -287,8 +282,7 @@ static HRESULT WINAPI HGLOBALStreamImpl_Write( ULARGE_INTEGER newSize; ULONG bytesWritten = 0; - TRACE("(%p, %p, %ld, %p)\n", iface, - pv, cb, pcbWritten); + TRACE("(%p, %p, %d, %p)\n", iface, pv, cb, pcbWritten); /* * If the caller is not interested in the number of bytes written, @@ -298,14 +292,10 @@ static HRESULT WINAPI HGLOBALStreamImpl_Write( pcbWritten = &bytesWritten; if (cb == 0) - { - return S_OK; - } - else - { - newSize.u.HighPart = 0; - newSize.u.LowPart = This->currentPosition.u.LowPart + cb; - } + goto out; + + newSize.u.HighPart = 0; + newSize.u.LowPart = This->currentPosition.u.LowPart + cb; /* * Verify if we need to grow the stream @@ -316,7 +306,7 @@ static HRESULT WINAPI HGLOBALStreamImpl_Write( HRESULT hr = IStream_SetSize(iface, newSize); if (FAILED(hr)) { - ERR("IStream_SetSize failed with error 0x%08lx\n", hr); + ERR("IStream_SetSize failed with error 0x%08x\n", hr); return hr; } } @@ -333,16 +323,17 @@ static HRESULT WINAPI HGLOBALStreamImpl_Write( */ This->currentPosition.u.LowPart+=cb; - /* - * Return the number of bytes read. - */ - *pcbWritten = cb; - /* * Cleanup */ GlobalUnlock(This->supportHandle); +out: + /* + * Return the number of bytes read. + */ + *pcbWritten = cb; + return S_OK; } @@ -364,7 +355,7 @@ static HRESULT WINAPI HGLOBALStreamImpl_Seek( ULARGE_INTEGER newPosition; - TRACE("(%p, %lx%08lx, %ld, %p)\n", iface, dlibMove.u.HighPart, + TRACE("(%p, %x%08x, %d, %p)\n", iface, dlibMove.u.HighPart, dlibMove.u.LowPart, dwOrigin, plibNewPosition); /* @@ -418,13 +409,11 @@ static HRESULT WINAPI HGLOBALStreamImpl_SetSize( HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface; HGLOBAL supportHandle; - TRACE("(%p, %ld)\n", iface, libNewSize.u.LowPart); + TRACE("(%p, %d)\n", iface, libNewSize.u.LowPart); /* - * As documented. + * HighPart is ignored as shown in tests */ - if (libNewSize.u.HighPart != 0) - return STG_E_INVALIDFUNCTION; if (This->streamSize.u.LowPart == libNewSize.u.LowPart) return S_OK; @@ -435,7 +424,7 @@ static HRESULT WINAPI HGLOBALStreamImpl_SetSize( supportHandle = GlobalReAlloc(This->supportHandle, libNewSize.u.LowPart, 0); if (supportHandle == 0) - return STG_E_MEDIUMFULL; + return E_OUTOFMEMORY; This->supportHandle = supportHandle; This->streamSize.u.LowPart = libNewSize.u.LowPart; @@ -463,7 +452,7 @@ static HRESULT WINAPI HGLOBALStreamImpl_CopyTo( ULARGE_INTEGER totalBytesRead; ULARGE_INTEGER totalBytesWritten; - TRACE("(%p, %p, %ld, %p, %p)\n", iface, pstm, + TRACE("(%p, %p, %d, %p, %p)\n", iface, pstm, cb.u.LowPart, pcbRead, pcbWritten); /* @@ -487,21 +476,19 @@ static HRESULT WINAPI HGLOBALStreamImpl_CopyTo( else copySize = cb.u.LowPart; - IStream_Read(iface, tmpBuffer, copySize, &bytesRead); + hr = IStream_Read(iface, tmpBuffer, copySize, &bytesRead); + if (FAILED(hr)) + break; totalBytesRead.u.LowPart += bytesRead; - IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten); - - totalBytesWritten.u.LowPart += bytesWritten; - - /* - * Check that read & write operations were succesfull - */ - if (bytesRead != bytesWritten) + if (bytesRead) { - hr = STG_E_MEDIUMFULL; - break; + hr = IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten); + if (FAILED(hr)) + break; + + totalBytesWritten.u.LowPart += bytesWritten; } if (bytesRead!=copySize) @@ -570,7 +557,7 @@ static HRESULT WINAPI HGLOBALStreamImpl_LockRegion( ULARGE_INTEGER cb, /* [in] */ DWORD dwLockType) /* [in] */ { - return S_OK; + return STG_E_INVALIDFUNCTION; } /* @@ -664,7 +651,7 @@ static const IStreamVtbl HGLOBALStreamImpl_Vtbl = * fDeleteOnRelease - Flag set to TRUE if the HGLOBAL will be released * when the IStream object is destroyed. */ -HGLOBALStreamImpl* HGLOBALStreamImpl_Construct( +static HGLOBALStreamImpl* HGLOBALStreamImpl_Construct( HGLOBAL hGlobal, BOOL fDeleteOnRelease) { diff --git a/reactos/dll/win32/ole32/ifs.c b/reactos/dll/win32/ole32/ifs.c index 0696139edf2..37ef44e2873 100644 --- a/reactos/dll/win32/ole32/ifs.c +++ b/reactos/dll/win32/ole32/ifs.c @@ -15,7 +15,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" @@ -166,7 +166,7 @@ static LPVOID WINAPI IMalloc_fnAlloc(LPMALLOC iface, DWORD cb) { LPVOID addr; - TRACE("(%ld)\n",cb); + TRACE("(%d)\n",cb); if(Malloc32.pSpy) { DWORD preAllocResult; @@ -200,7 +200,7 @@ static LPVOID WINAPI IMalloc_fnRealloc(LPMALLOC iface,LPVOID pv,DWORD cb) { LPVOID pNewMemory; - TRACE("(%p,%ld)\n",pv,cb); + TRACE("(%p,%d)\n",pv,cb); if(Malloc32.pSpy) { LPVOID pRealMemory; @@ -396,7 +396,7 @@ static ULONG WINAPI IMallocSpy_fnAddRef (LPMALLOCSPY iface) _MallocSpy *This = (_MallocSpy *)iface; ULONG ref = InterlockedIncrement(&This->ref); - TRACE ("(%p)->(count=%lu)\n", This, ref - 1); + TRACE ("(%p)->(count=%u)\n", This, ref - 1); return ref; } @@ -413,7 +413,7 @@ static ULONG WINAPI IMallocSpy_fnRelease (LPMALLOCSPY iface) _MallocSpy *This = (_MallocSpy *)iface; ULONG ref = InterlockedDecrement(&This->ref); - TRACE ("(%p)->(count=%lu)\n", This, ref + 1); + TRACE ("(%p)->(count=%u)\n", This, ref + 1); if (!ref) { /* our allocation list MUST be empty here */ @@ -424,7 +424,7 @@ static ULONG WINAPI IMallocSpy_fnRelease (LPMALLOCSPY iface) static ULONG WINAPI IMallocSpy_fnPreAlloc(LPMALLOCSPY iface, ULONG cbRequest) { _MallocSpy *This = (_MallocSpy *)iface; - TRACE ("(%p)->(%lu)\n", This, cbRequest); + TRACE ("(%p)->(%u)\n", This, cbRequest); return cbRequest; } static PVOID WINAPI IMallocSpy_fnPostAlloc(LPMALLOCSPY iface, void* pActual) @@ -449,7 +449,7 @@ static void WINAPI IMallocSpy_fnPostFree(LPMALLOCSPY iface, BOOL fSpyed) static ULONG WINAPI IMallocSpy_fnPreRealloc(LPMALLOCSPY iface, void* pRequest, ULONG cbRequest, void** ppNewRequest, BOOL fSpyed) { _MallocSpy *This = (_MallocSpy *)iface; - TRACE ("(%p)->(%p %lu %u)\n", This, pRequest, cbRequest, fSpyed); + TRACE ("(%p)->(%p %u %u)\n", This, pRequest, cbRequest, fSpyed); *ppNewRequest = pRequest; return cbRequest; } @@ -471,7 +471,7 @@ static PVOID WINAPI IMallocSpy_fnPreGetSize(LPMALLOCSPY iface, void* pRequest, B static ULONG WINAPI IMallocSpy_fnPostGetSize(LPMALLOCSPY iface, ULONG cbActual, BOOL fSpyed) { _MallocSpy *This = (_MallocSpy *)iface; - TRACE ("(%p)->(%lu %u)\n", This, cbActual, fSpyed); + TRACE ("(%p)->(%u %u)\n", This, cbActual, fSpyed); return cbActual; } @@ -502,7 +502,7 @@ static void WINAPI IMallocSpy_fnPostHeapMinimize(LPMALLOCSPY iface) } static void MallocSpyDumpLeaks(void) { - TRACE("leaks: %lu\n", Malloc32.SpyedAllocationsLeft); + TRACE("leaks: %u\n", Malloc32.SpyedAllocationsLeft); } static const IMallocSpyVtbl VT_IMallocSpy = @@ -665,7 +665,7 @@ HRESULT WINAPI CoRevokeMallocSpy(void) } if (Malloc32.SpyedAllocationsLeft) { - TRACE("SpyReleasePending with %lu allocations left\n", Malloc32.SpyedAllocationsLeft); + TRACE("SpyReleasePending with %u allocations left\n", Malloc32.SpyedAllocationsLeft); Malloc32.SpyReleasePending = TRUE; hres = E_ACCESSDENIED; } else { diff --git a/reactos/dll/win32/ole32/ifs.h b/reactos/dll/win32/ole32/ifs.h index c7d5ff445de..89ae1e20c56 100644 --- a/reactos/dll/win32/ole32/ifs.h +++ b/reactos/dll/win32/ole32/ifs.h @@ -13,7 +13,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __WINE_OLE_IFS_H @@ -38,7 +38,6 @@ typedef LPCSTR LPCOLESTR16; * IMalloc16 interface */ -#undef INTERFACE typedef struct IMalloc16 *LPMALLOC16; #define INTERFACE IMalloc16 @@ -58,8 +57,6 @@ DECLARE_INTERFACE_(IMalloc16,IUnknown) }; #undef INTERFACE -typedef struct IMalloc16 *LPMALLOC16; - /**********************************************************************/ extern LPMALLOC16 IMalloc16_Constructor(void); diff --git a/reactos/dll/win32/ole32/itemmoniker.c b/reactos/dll/win32/ole32/itemmoniker.c index d812df50416..2a8ed22a205 100644 --- a/reactos/dll/win32/ole32/itemmoniker.c +++ b/reactos/dll/win32/ole32/itemmoniker.c @@ -1,4 +1,4 @@ -/*************************************************************************************** +/* * ItemMonikers implementation * * Copyright 1999 Noomen Hamza @@ -15,8 +15,8 @@ * * 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 - ***************************************************************************************/ + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ #include #include @@ -38,10 +38,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole); -const CLSID CLSID_ItemMoniker = { - 0x304, 0, 0, {0xC0, 0, 0, 0, 0, 0, 0, 0x46} -}; - /* ItemMoniker data structure */ typedef struct ItemMonikerImpl{ @@ -101,8 +97,8 @@ static HRESULT WINAPI ItemMonikerImpl_ParseDisplayName(IMoniker* iface,IBindCtx* static HRESULT WINAPI ItemMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys); /* Local function used by ItemMoniker implementation */ -HRESULT WINAPI ItemMonikerImpl_Construct(ItemMonikerImpl* iface, LPCOLESTR lpszDelim,LPCOLESTR lpszPathName); -HRESULT WINAPI ItemMonikerImpl_Destroy(ItemMonikerImpl* iface); +static HRESULT WINAPI ItemMonikerImpl_Construct(ItemMonikerImpl* iface, LPCOLESTR lpszDelim,LPCOLESTR lpszPathName); +static HRESULT WINAPI ItemMonikerImpl_Destroy(ItemMonikerImpl* iface); /********************************************************************************/ /* IROTData prototype functions */ @@ -392,7 +388,7 @@ HRESULT WINAPI ItemMonikerImpl_GetSizeMax(IMoniker* iface, /****************************************************************************** * ItemMoniker_Construct (local function) *******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_Construct(ItemMonikerImpl* This, LPCOLESTR lpszDelim,LPCOLESTR lpszItem) +static HRESULT WINAPI ItemMonikerImpl_Construct(ItemMonikerImpl* This, LPCOLESTR lpszDelim,LPCOLESTR lpszItem) { int sizeStr1=lstrlenW(lpszItem), sizeStr2; @@ -430,7 +426,7 @@ HRESULT WINAPI ItemMonikerImpl_Construct(ItemMonikerImpl* This, LPCOLESTR lpszDe /****************************************************************************** * ItemMoniker_Destroy (local function) *******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_Destroy(ItemMonikerImpl* This) +static HRESULT WINAPI ItemMonikerImpl_Destroy(ItemMonikerImpl* This) { TRACE("(%p)\n",This); @@ -521,7 +517,7 @@ HRESULT WINAPI ItemMonikerImpl_Reduce(IMoniker* iface, IMoniker** ppmkToLeft, IMoniker** ppmkReduced) { - TRACE("(%p,%p,%ld,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced); + TRACE("(%p,%p,%d,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced); if (ppmkReduced==NULL) return E_POINTER; @@ -661,8 +657,8 @@ HRESULT WINAPI ItemMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker HRESULT WINAPI ItemMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash) { ItemMonikerImpl *This = (ItemMonikerImpl *)iface; - - int h = 0,i,skip,len; + DWORD h = 0; + int i,len; int off = 0; LPOLESTR val; @@ -672,17 +668,8 @@ HRESULT WINAPI ItemMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash) val = This->itemName; len = lstrlenW(val); - if (len < 16) { - for (i = len ; i > 0; i--) { - h = (h * 37) + val[off++]; - } - } else { - /* only sample some characters */ - skip = len / 8; - for (i = len ; i > 0; i -= skip, off += skip) { - h = (h * 39) + val[off]; - } - } + for (i = len ; i > 0; i--) + h = (h * 3) ^ toupperW(val[off++]); *pdwHash=h; @@ -980,7 +967,7 @@ HRESULT WINAPI ItemMonikerROTDataImpl_GetComparisonData(IROTData* iface, LPWSTR pszItemName; LPWSTR pszItemDelimiter; - TRACE("(%p, %lu, %p)\n", pbData, cbMax, pcbData); + TRACE("(%p, %u, %p)\n", pbData, cbMax, pcbData); *pcbData = sizeof(CLSID) + sizeof(WCHAR) + len * sizeof(WCHAR); if (cbMax < *pcbData) diff --git a/reactos/dll/win32/ole32/marshal.c b/reactos/dll/win32/ole32/marshal.c index 6b4679d8b5a..120361aa48c 100644 --- a/reactos/dll/win32/ole32/marshal.c +++ b/reactos/dll/win32/ole32/marshal.c @@ -17,14 +17,10 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include "config.h" - -#include #include -#include #include #include @@ -35,10 +31,7 @@ #include "winuser.h" #include "objbase.h" #include "ole2.h" -#include "rpc.h" #include "winerror.h" -#include "winreg.h" -#include "wtypes.h" #include "wine/unicode.h" #include "compobj_private.h" @@ -50,13 +43,16 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole); extern const CLSID CLSID_DfMarshal; /* number of refs given out for normal marshaling */ -#define NORMALEXTREFS 1 /* FIXME: this should be 5, but we have to wait for IRemUnknown support first */ +#define NORMALEXTREFS 5 /* private flag indicating that the caller does not want to notify the stub * when the proxy disconnects or is destroyed */ #define SORFP_NOLIFETIMEMGMT SORF_OXRES1 -static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt, REFIID riid, void **object); +static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt, + MSHCTX dest_context, void *dest_context_data, + REFIID riid, const OXID_INFO *oxid_info, + void **object); /* Marshalling just passes a unique identifier to the remote client, * that makes it possible to find the passed interface again. @@ -73,7 +69,7 @@ static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt, REFI * IPIDs identify an interface stub and are apartment scoped */ -inline static HRESULT get_facbuf_for_iid(REFIID riid, IPSFactoryBuffer **facbuf) +static inline HRESULT get_facbuf_for_iid(REFIID riid, IPSFactoryBuffer **facbuf) { HRESULT hr; CLSID clsid; @@ -98,10 +94,14 @@ HRESULT marshal_object(APARTMENT *apt, STDOBJREF *stdobjref, REFIID riid, IUnkno if (hr != S_OK) return hr; + hr = apartment_createwindowifneeded(apt); + if (hr != S_OK) + return hr; + hr = IUnknown_QueryInterface(object, riid, (void **)&iobject); if (hr != S_OK) { - ERR("object doesn't expose interface %s, failing with error 0x%08lx\n", + ERR("object doesn't expose interface %s, failing with error 0x%08x\n", debugstr_guid(riid), hr); return E_NOINTERFACE; } @@ -124,7 +124,8 @@ HRESULT marshal_object(APARTMENT *apt, STDOBJREF *stdobjref, REFIID riid, IUnkno IPSFactoryBuffer_Release(psfb); if (hr != S_OK) { - ERR("Failed to create an IRpcStubBuffer from IPSFactory for %s\n", debugstr_guid(riid)); + ERR("Failed to create an IRpcStubBuffer from IPSFactory for %s with error 0x%08x\n", + debugstr_guid(riid), hr); IUnknown_Release(iobject); return hr; } @@ -156,17 +157,18 @@ HRESULT marshal_object(APARTMENT *apt, STDOBJREF *stdobjref, REFIID riid, IUnkno /* make sure ifstub that we are creating is unique */ ifstub = stub_manager_find_ifstub(manager, riid, mshlflags); if (!ifstub) - { ifstub = stub_manager_new_ifstub(manager, stub, iobject, riid, mshlflags); - IUnknown_Release(iobject); - if (stub) IRpcStubBuffer_Release(stub); - if (!ifstub) - { - stub_manager_int_release(manager); - /* FIXME: should we do another release to completely destroy the - * stub manager? */ - return E_OUTOFMEMORY; - } + + if (stub) IRpcStubBuffer_Release(stub); + IUnknown_Release(iobject); + + if (!ifstub) + { + stub_manager_int_release(manager); + /* destroy the stub manager if it has no ifstubs by releasing + * zero external references */ + stub_manager_ext_release(manager, 0, TRUE); + return E_OUTOFMEMORY; } if (!tablemarshal) @@ -216,7 +218,7 @@ static HRESULT WINAPI ClientIdentity_QueryInterface(IMultiQI * iface, REFIID rii static ULONG WINAPI ClientIdentity_AddRef(IMultiQI * iface) { struct proxy_manager * This = (struct proxy_manager *)iface; - TRACE("%p - before %ld\n", iface, This->refs); + TRACE("%p - before %d\n", iface, This->refs); return InterlockedIncrement(&This->refs); } @@ -224,7 +226,7 @@ static ULONG WINAPI ClientIdentity_Release(IMultiQI * iface) { struct proxy_manager * This = (struct proxy_manager *)iface; ULONG refs = InterlockedDecrement(&This->refs); - TRACE("%p - after %ld\n", iface, refs); + TRACE("%p - after %d\n", iface, refs); if (!refs) proxy_manager_destroy(This); return refs; @@ -241,13 +243,13 @@ static HRESULT WINAPI ClientIdentity_QueryMultipleInterfaces(IMultiQI *iface, UL /* mapping of RemQueryInterface index to QueryMultipleInterfaces index */ ULONG *mapping = HeapAlloc(GetProcessHeap(), 0, cMQIs * sizeof(*mapping)); - TRACE("cMQIs: %ld\n", cMQIs); + TRACE("cMQIs: %d\n", cMQIs); /* try to get a local interface - this includes already active proxy * interfaces and also interfaces exposed by the proxy manager */ for (i = 0; i < cMQIs; i++) { - TRACE("iid[%ld] = %s\n", i, debugstr_guid(pMQIs[i].pIID)); + TRACE("iid[%d] = %s\n", i, debugstr_guid(pMQIs[i].pIID)); pMQIs[i].hr = proxy_manager_query_local_interface(This, pMQIs[i].pIID, (void **)&pMQIs[i].pItf); if (pMQIs[i].hr == S_OK) successful_mqis++; @@ -259,7 +261,7 @@ static HRESULT WINAPI ClientIdentity_QueryMultipleInterfaces(IMultiQI *iface, UL } } - TRACE("%ld interfaces not found locally\n", nonlocal_mqis); + TRACE("%d interfaces not found locally\n", nonlocal_mqis); /* if we have more than one interface not found locally then we must try * to query the remote object for it */ @@ -282,7 +284,7 @@ static HRESULT WINAPI ClientIdentity_QueryMultipleInterfaces(IMultiQI *iface, UL hr = IRemUnknown_RemQueryInterface(remunk, ipid, NORMALEXTREFS, nonlocal_mqis, iids, &qiresults); if (FAILED(hr)) - ERR("IRemUnknown_RemQueryInterface failed with error 0x%08lx\n", hr); + ERR("IRemUnknown_RemQueryInterface failed with error 0x%08x\n", hr); } /* IRemUnknown_RemQueryInterface can return S_FALSE if only some of @@ -296,7 +298,9 @@ static HRESULT WINAPI ClientIdentity_QueryMultipleInterfaces(IMultiQI *iface, UL HRESULT hrobj = qiresults[i].hResult; if (hrobj == S_OK) hrobj = unmarshal_object(&qiresults[i].std, This->parent, - pMQIs[index].pIID, + This->dest_context, + This->dest_context_data, + pMQIs[index].pIID, &This->oxid_info, (void **)&pMQIs[index].pItf); if (hrobj == S_OK) @@ -311,7 +315,7 @@ static HRESULT WINAPI ClientIdentity_QueryMultipleInterfaces(IMultiQI *iface, UL CoTaskMemFree(qiresults); } - TRACE("%ld/%ld successfully queried\n", successful_mqis, cMQIs); + TRACE("%d/%d successfully queried\n", successful_mqis, cMQIs); HeapFree(GetProcessHeap(), 0, iids); HeapFree(GetProcessHeap(), 0, mapping); @@ -332,6 +336,13 @@ static const IMultiQIVtbl ClientIdentity_Vtbl = ClientIdentity_QueryMultipleInterfaces }; +/* FIXME: remove these */ +static HRESULT WINAPI StdMarshalImpl_GetUnmarshalClass(LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext, void* pvDestContext, DWORD mshlflags, CLSID* pCid); +static HRESULT WINAPI StdMarshalImpl_GetMarshalSizeMax(LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext, void* pvDestContext, DWORD mshlflags, DWORD* pSize); +static HRESULT WINAPI StdMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, void **ppv); +static HRESULT WINAPI StdMarshalImpl_ReleaseMarshalData(LPMARSHAL iface, IStream *pStm); +static HRESULT WINAPI StdMarshalImpl_DisconnectObject(LPMARSHAL iface, DWORD dwReserved); + static HRESULT WINAPI Proxy_QueryInterface(IMarshal *iface, REFIID riid, void **ppvObject) { ICOM_THIS_MULTI(struct proxy_manager, lpVtblMarshal, iface); @@ -344,13 +355,6 @@ static ULONG WINAPI Proxy_AddRef(IMarshal *iface) return IMultiQI_AddRef((IMultiQI *)&This->lpVtbl); } -/* FIXME: remove these */ -static HRESULT WINAPI StdMarshalImpl_GetUnmarshalClass(LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext, void* pvDestContext, DWORD mshlflags, CLSID* pCid); -static HRESULT WINAPI StdMarshalImpl_GetMarshalSizeMax(LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext, void* pvDestContext, DWORD mshlflags, DWORD* pSize); -static HRESULT WINAPI StdMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, void **ppv); -static HRESULT WINAPI StdMarshalImpl_ReleaseMarshalData(LPMARSHAL iface, IStream *pStm); -static HRESULT WINAPI StdMarshalImpl_DisconnectObject(LPMARSHAL iface, DWORD dwReserved); - static ULONG WINAPI Proxy_Release(IMarshal *iface) { ICOM_THIS_MULTI(struct proxy_manager, lpVtblMarshal, iface); @@ -362,25 +366,97 @@ static HRESULT WINAPI Proxy_MarshalInterface( void* pvDestContext, DWORD mshlflags) { ICOM_THIS_MULTI(struct proxy_manager, lpVtblMarshal, iface); - ULONG res; HRESULT hr; - STDOBJREF stdobjref; struct ifproxy *ifproxy; TRACE("(...,%s,...)\n", debugstr_guid(riid)); hr = proxy_manager_find_ifproxy(This, riid, &ifproxy); - if (FAILED(hr)) + if (SUCCEEDED(hr)) { - ERR("couldn't find proxy for interface %s, error 0x%08lx\n", debugstr_guid(riid), hr); - return hr; - } + STDOBJREF stdobjref = ifproxy->stdobjref; + ULONG cPublicRefs = ifproxy->refs; + ULONG cPublicRefsOld; - stdobjref = ifproxy->stdobjref; - /* FIXME: optimization - share out proxy's public references if possible - * instead of making new proxy do a roundtrip through the server */ - stdobjref.cPublicRefs = 0; /* InterlockedDecrement(&This->stdobjref.cPublicRefs) >= 0 ? 1 : 0 */ - hr = IStream_Write(pStm, &stdobjref, sizeof(stdobjref), &res); + /* optimization - share out proxy's public references if possible + * instead of making new proxy do a roundtrip through the server */ + do + { + ULONG cPublicRefsNew; + cPublicRefsOld = cPublicRefs; + stdobjref.cPublicRefs = cPublicRefs / 2; + cPublicRefsNew = cPublicRefs - stdobjref.cPublicRefs; + cPublicRefs = InterlockedCompareExchange( + (LONG *)&ifproxy->refs, cPublicRefsNew, cPublicRefsOld); + } while (cPublicRefs != cPublicRefsOld); + + if (!stdobjref.cPublicRefs) + { + IRemUnknown *remunk; + hr = proxy_manager_get_remunknown(This, &remunk); + if (hr == S_OK) + { + HRESULT hrref = S_OK; + REMINTERFACEREF rif; + rif.ipid = ifproxy->stdobjref.ipid; + rif.cPublicRefs = NORMALEXTREFS; + rif.cPrivateRefs = 0; + hr = IRemUnknown_RemAddRef(remunk, 1, &rif, &hrref); + if (hr == S_OK && hrref == S_OK) + stdobjref.cPublicRefs = rif.cPublicRefs; + else + ERR("IRemUnknown_RemAddRef returned with 0x%08x, hrref = 0x%08x\n", hr, hrref); + } + } + + if (SUCCEEDED(hr)) + { + TRACE("writing stdobjref:\n\tflags = %04lx\n\tcPublicRefs = %ld\n\toxid = %s\n\toid = %s\n\tipid = %s\n", + stdobjref.flags, stdobjref.cPublicRefs, + wine_dbgstr_longlong(stdobjref.oxid), + wine_dbgstr_longlong(stdobjref.oid), + debugstr_guid(&stdobjref.ipid)); + hr = IStream_Write(pStm, &stdobjref, sizeof(stdobjref), NULL); + } + } + else + { + /* we don't have the interface already unmarshaled so we have to + * request the object from the server */ + IRemUnknown *remunk; + IPID *ipid; + REMQIRESULT *qiresults = NULL; + IID iid = *riid; + + /* get the ipid of the first entry */ + /* FIXME: should we implement ClientIdentity on the ifproxies instead + * of the proxy_manager so we use the correct ipid here? */ + ipid = &LIST_ENTRY(list_head(&This->interfaces), struct ifproxy, entry)->stdobjref.ipid; + + /* get IRemUnknown proxy so we can communicate with the remote object */ + hr = proxy_manager_get_remunknown(This, &remunk); + + if (hr == S_OK) + { + hr = IRemUnknown_RemQueryInterface(remunk, ipid, NORMALEXTREFS, + 1, &iid, &qiresults); + if (SUCCEEDED(hr)) + { + hr = IStream_Write(pStm, &qiresults->std, sizeof(qiresults->std), NULL); + if (FAILED(hr)) + { + REMINTERFACEREF rif; + rif.ipid = qiresults->std.ipid; + rif.cPublicRefs = qiresults->std.cPublicRefs; + rif.cPrivateRefs = 0; + IRemUnknown_RemRelease(remunk, 1, &rif); + } + CoTaskMemFree(qiresults); + } + else + ERR("IRemUnknown_RemQueryInterface failed with error 0x%08x\n", hr); + } + } return hr; } @@ -398,6 +474,72 @@ static const IMarshalVtbl ProxyMarshal_Vtbl = StdMarshalImpl_DisconnectObject }; +static HRESULT WINAPI ProxyCliSec_QueryInterface(IClientSecurity *iface, REFIID riid, void **ppvObject) +{ + ICOM_THIS_MULTI(struct proxy_manager, lpVtblCliSec, iface); + return IMultiQI_QueryInterface((IMultiQI *)&This->lpVtbl, riid, ppvObject); +} + +static ULONG WINAPI ProxyCliSec_AddRef(IClientSecurity *iface) +{ + ICOM_THIS_MULTI(struct proxy_manager, lpVtblCliSec, iface); + return IMultiQI_AddRef((IMultiQI *)&This->lpVtbl); +} + +static ULONG WINAPI ProxyCliSec_Release(IClientSecurity *iface) +{ + ICOM_THIS_MULTI(struct proxy_manager, lpVtblCliSec, iface); + return IMultiQI_Release((IMultiQI *)&This->lpVtbl); +} + +static HRESULT WINAPI ProxyCliSec_QueryBlanket(IClientSecurity *iface, + IUnknown *pProxy, + DWORD *pAuthnSvc, + DWORD *pAuthzSvc, + OLECHAR **pServerPrincName, + DWORD *pAuthnLevel, + DWORD *pImpLevel, + void **pAuthInfo, + DWORD *pCapabilities) +{ + FIXME("(%p, %p, %p, %p, %p, %p, %p, %p): stub\n", pProxy, pAuthnSvc, + pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel, pAuthInfo, + pCapabilities); + return E_NOTIMPL; +} + +static HRESULT WINAPI ProxyCliSec_SetBlanket(IClientSecurity *iface, + IUnknown *pProxy, DWORD AuthnSvc, + DWORD AuthzSvc, + OLECHAR *pServerPrincName, + DWORD AuthnLevel, DWORD ImpLevel, + void *pAuthInfo, + DWORD Capabilities) +{ + FIXME("(%p, %d, %d, %s, %d, %d, %p, 0x%x): stub\n", pProxy, AuthnSvc, + AuthzSvc, debugstr_w(pServerPrincName), AuthnLevel, ImpLevel, + pAuthInfo, Capabilities); + return E_NOTIMPL; +} + +static HRESULT WINAPI ProxyCliSec_CopyProxy(IClientSecurity *iface, + IUnknown *pProxy, IUnknown **ppCopy) +{ + FIXME("(%p, %p): stub\n", pProxy, ppCopy); + *ppCopy = NULL; + return E_NOTIMPL; +} + +static const IClientSecurityVtbl ProxyCliSec_Vtbl = +{ + ProxyCliSec_QueryInterface, + ProxyCliSec_AddRef, + ProxyCliSec_Release, + ProxyCliSec_QueryBlanket, + ProxyCliSec_SetBlanket, + ProxyCliSec_CopyProxy +}; + static HRESULT ifproxy_get_public_ref(struct ifproxy * This) { HRESULT hr = S_OK; @@ -417,16 +559,16 @@ static HRESULT ifproxy_get_public_ref(struct ifproxy * This) hr = proxy_manager_get_remunknown(This->parent, &remunk); if (hr == S_OK) { - HRESULT hrref; + HRESULT hrref = S_OK; REMINTERFACEREF rif; rif.ipid = This->stdobjref.ipid; rif.cPublicRefs = NORMALEXTREFS; rif.cPrivateRefs = 0; hr = IRemUnknown_RemAddRef(remunk, 1, &rif, &hrref); if (hr == S_OK && hrref == S_OK) - This->refs += NORMALEXTREFS; + InterlockedExchangeAdd((LONG *)&This->refs, NORMALEXTREFS); else - ERR("IRemUnknown_RemAddRef returned with 0x%08lx, hrref = 0x%08lx\n", hr, hrref); + ERR("IRemUnknown_RemAddRef returned with 0x%08x, hrref = 0x%08x\n", hr, hrref); } } ReleaseMutex(This->parent->remoting_mutex); @@ -437,6 +579,7 @@ static HRESULT ifproxy_get_public_ref(struct ifproxy * This) static HRESULT ifproxy_release_public_refs(struct ifproxy * This) { HRESULT hr = S_OK; + LONG public_refs; if (WAIT_OBJECT_0 != WaitForSingleObject(This->parent->remoting_mutex, INFINITE)) { @@ -444,29 +587,30 @@ static HRESULT ifproxy_release_public_refs(struct ifproxy * This) return E_UNEXPECTED; } - if (This->refs > 0) + public_refs = This->refs; + if (public_refs > 0) { IRemUnknown *remunk = NULL; - TRACE("releasing %ld refs\n", This->refs); + TRACE("releasing %d refs\n", public_refs); hr = proxy_manager_get_remunknown(This->parent, &remunk); if (hr == S_OK) { REMINTERFACEREF rif; rif.ipid = This->stdobjref.ipid; - rif.cPublicRefs = This->refs; + rif.cPublicRefs = public_refs; rif.cPrivateRefs = 0; hr = IRemUnknown_RemRelease(remunk, 1, &rif); if (hr == S_OK) - This->refs = 0; + InterlockedExchangeAdd((LONG *)&This->refs, -public_refs); else if (hr == RPC_E_DISCONNECTED) WARN("couldn't release references because object was " "disconnected: oxid = %s, oid = %s\n", wine_dbgstr_longlong(This->parent->oxid), wine_dbgstr_longlong(This->parent->oid)); else - ERR("IRemUnknown_RemRelease failed with error 0x%08lx\n", hr); + ERR("IRemUnknown_RemRelease failed with error 0x%08x\n", hr); } } ReleaseMutex(This->parent->remoting_mutex); @@ -501,16 +645,14 @@ static void ifproxy_destroy(struct ifproxy * This) This->chan = NULL; } - /* note: we don't call Release for This->proxy because its lifetime is - * controlled by the return value from ClientIdentity_Release, which this - * function is always called from */ + if (This->proxy) IRpcProxyBuffer_Release(This->proxy); HeapFree(GetProcessHeap(), 0, This); } static HRESULT proxy_manager_construct( APARTMENT * apt, ULONG sorflags, OXID oxid, OID oid, - struct proxy_manager ** proxy_manager) + const OXID_INFO *oxid_info, struct proxy_manager ** proxy_manager) { struct proxy_manager * This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); if (!This) return E_OUTOFMEMORY; @@ -522,8 +664,28 @@ static HRESULT proxy_manager_construct( return HRESULT_FROM_WIN32(GetLastError()); } + if (oxid_info) + { + This->oxid_info.dwPid = oxid_info->dwPid; + This->oxid_info.dwTid = oxid_info->dwTid; + This->oxid_info.ipidRemUnknown = oxid_info->ipidRemUnknown; + This->oxid_info.dwAuthnHint = oxid_info->dwAuthnHint; + This->oxid_info.psa = NULL /* FIXME: copy from oxid_info */; + } + else + { + HRESULT hr = RPC_ResolveOxid(oxid, &This->oxid_info); + if (FAILED(hr)) + { + CloseHandle(This->remoting_mutex); + HeapFree(GetProcessHeap(), 0, This); + return hr; + } + } + This->lpVtbl = &ClientIdentity_Vtbl; This->lpVtblMarshal = &ProxyMarshal_Vtbl; + This->lpVtblCliSec = &ProxyCliSec_Vtbl; list_init(&This->entry); list_init(&This->interfaces); @@ -548,6 +710,11 @@ static HRESULT proxy_manager_construct( /* we create the IRemUnknown proxy on demand */ This->remunk = NULL; + /* initialise these values to the weakest values and they will be + * overwritten in proxy_manager_set_context */ + This->dest_context = MSHCTX_INPROC; + This->dest_context_data = NULL; + EnterCriticalSection(&apt->cs); /* FIXME: we are dependent on the ordering in here to make sure a proxy's * IRemUnknown proxy doesn't get destroyed before the regual proxy does @@ -564,6 +731,63 @@ static HRESULT proxy_manager_construct( return S_OK; } +static inline void proxy_manager_set_context(struct proxy_manager *This, MSHCTX dest_context, void *dest_context_data) +{ + MSHCTX old_dest_context = This->dest_context; + MSHCTX new_dest_context; + + do + { + new_dest_context = old_dest_context; + /* "stronger" values overwrite "weaker" values. stronger values are + * ones that disable more optimisations */ + switch (old_dest_context) + { + case MSHCTX_INPROC: + new_dest_context = dest_context; + break; + case MSHCTX_CROSSCTX: + switch (dest_context) + { + case MSHCTX_INPROC: + break; + default: + new_dest_context = dest_context; + } + break; + case MSHCTX_LOCAL: + switch (dest_context) + { + case MSHCTX_INPROC: + case MSHCTX_CROSSCTX: + break; + default: + new_dest_context = dest_context; + } + break; + case MSHCTX_NOSHAREDMEM: + switch (dest_context) + { + case MSHCTX_DIFFERENTMACHINE: + new_dest_context = dest_context; + break; + default: + break; + } + break; + default: + break; + } + + if (old_dest_context == new_dest_context) break; + + old_dest_context = InterlockedCompareExchange((PLONG)&This->dest_context, new_dest_context, old_dest_context); + } while (new_dest_context != old_dest_context); + + if (dest_context_data) + InterlockedExchangePointer(&This->dest_context_data, dest_context_data); +} + static HRESULT proxy_manager_query_local_interface(struct proxy_manager * This, REFIID riid, void ** ppv) { HRESULT hr; @@ -586,9 +810,9 @@ static HRESULT proxy_manager_query_local_interface(struct proxy_manager * This, } if (IsEqualIID(riid, &IID_IClientSecurity)) { - FIXME("requesting IClientSecurity, but it is unimplemented\n"); - *ppv = NULL; - return E_NOINTERFACE; + *ppv = (void *)&This->lpVtblCliSec; + IUnknown_AddRef((IUnknown *)*ppv); + return S_OK; } hr = proxy_manager_find_ifproxy(This, riid, &ifproxy); @@ -617,7 +841,7 @@ static HRESULT proxy_manager_create_ifproxy( ifproxy->parent = This; ifproxy->stdobjref = *stdobjref; ifproxy->iid = *riid; - ifproxy->refs = stdobjref->cPublicRefs; + ifproxy->refs = 0; ifproxy->proxy = NULL; assert(channel); @@ -644,21 +868,17 @@ static HRESULT proxy_manager_create_ifproxy( &ifproxy->proxy, &ifproxy->iface); IPSFactoryBuffer_Release(psfb); if (hr != S_OK) - ERR("Could not create proxy for interface %s, error 0x%08lx\n", + ERR("Could not create proxy for interface %s, error 0x%08x\n", debugstr_guid(riid), hr); } else - ERR("Could not get IPSFactoryBuffer for interface %s, error 0x%08lx\n", + ERR("Could not get IPSFactoryBuffer for interface %s, error 0x%08x\n", debugstr_guid(riid), hr); if (hr == S_OK) hr = IRpcProxyBuffer_Connect(ifproxy->proxy, ifproxy->chan); } - /* get at least one external reference to the object to keep it alive */ - if (hr == S_OK) - hr = ifproxy_get_public_ref(ifproxy); - if (hr == S_OK) { EnterCriticalSection(&This->cs); @@ -751,23 +971,18 @@ static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnk stdobjref.oxid = This->oxid; /* FIXME: what should be used for the oid? The DCOM draft doesn't say */ stdobjref.oid = (OID)-1; - /* FIXME: this is a hack around not having an OXID resolver yet - - * the OXID resolver should give us the IPID of the IRemUnknown - * interface */ - stdobjref.ipid.Data1 = 0xffffffff; - stdobjref.ipid.Data2 = 0xffff; - stdobjref.ipid.Data3 = 0xffff; - assert(sizeof(stdobjref.ipid.Data4) == sizeof(stdobjref.oxid)); - memcpy(&stdobjref.ipid.Data4, &stdobjref.oxid, sizeof(OXID)); - + stdobjref.ipid = This->oxid_info.ipidRemUnknown; + /* do the unmarshal */ - hr = unmarshal_object(&stdobjref, This->parent, &IID_IRemUnknown, (void**)&This->remunk); + hr = unmarshal_object(&stdobjref, This->parent, This->dest_context, + This->dest_context_data, &IID_IRemUnknown, + &This->oxid_info, (void**)&This->remunk); if (hr == S_OK) *remunk = This->remunk; } LeaveCriticalSection(&This->cs); - TRACE("got IRemUnknown* pointer %p, hr = 0x%08lx\n", *remunk, hr); + TRACE("got IRemUnknown* pointer %p, hr = 0x%08x\n", *remunk, hr); return hr; } @@ -808,6 +1023,7 @@ static void proxy_manager_destroy(struct proxy_manager * This) } if (This->remunk) IRemUnknown_Release(This->remunk); + CoTaskMemFree(This->oxid_info.psa); DEBUG_CLEAR_CRITSEC_NAME(&This->cs); DeleteCriticalSection(&This->cs); @@ -939,7 +1155,7 @@ StdMarshalImpl_MarshalInterface( hres = marshal_object(apt, &stdobjref, riid, (IUnknown *)pv, mshlflags); if (hres) { - ERR("Failed to create ifstub, hres=0x%lx\n", hres); + ERR("Failed to create ifstub, hres=0x%x\n", hres); return hres; } @@ -952,7 +1168,10 @@ StdMarshalImpl_MarshalInterface( /* helper for StdMarshalImpl_UnmarshalInterface - does the unmarshaling with * no questions asked about the rules surrounding same-apartment unmarshals * and table marshaling */ -static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt, REFIID riid, void **object) +static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt, + MSHCTX dest_context, void *dest_context_data, + REFIID riid, const OXID_INFO *oxid_info, + void **object) { struct proxy_manager *proxy_manager = NULL; HRESULT hr = S_OK; @@ -965,12 +1184,12 @@ static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt, REFI wine_dbgstr_longlong(stdobjref->oid), debugstr_guid(&stdobjref->ipid)); - /* create an a new proxy manager if one doesn't already exist for the + /* create a new proxy manager if one doesn't already exist for the * object */ if (!find_proxy_manager(apt, stdobjref->oxid, stdobjref->oid, &proxy_manager)) { hr = proxy_manager_construct(apt, stdobjref->flags, - stdobjref->oxid, stdobjref->oid, + stdobjref->oxid, stdobjref->oid, oxid_info, &proxy_manager); } else @@ -979,11 +1198,18 @@ static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt, REFI if (hr == S_OK) { struct ifproxy * ifproxy; + + proxy_manager_set_context(proxy_manager, dest_context, dest_context_data); + hr = proxy_manager_find_ifproxy(proxy_manager, riid, &ifproxy); if (hr == E_NOINTERFACE) { IRpcChannelBuffer *chanbuf; - hr = RPC_CreateClientChannel(&stdobjref->oxid, &stdobjref->ipid, &chanbuf); + hr = RPC_CreateClientChannel(&stdobjref->oxid, &stdobjref->ipid, + &proxy_manager->oxid_info, + proxy_manager->dest_context, + proxy_manager->dest_context_data, + &chanbuf); if (hr == S_OK) hr = proxy_manager_create_ifproxy(proxy_manager, stdobjref, riid, chanbuf, &ifproxy); @@ -991,6 +1217,15 @@ static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt, REFI else IUnknown_AddRef((IUnknown *)ifproxy->iface); + if (hr == S_OK) + { + InterlockedExchangeAdd((LONG *)&ifproxy->refs, stdobjref->cPublicRefs); + /* get at least one external reference to the object to keep it alive */ + hr = ifproxy_get_public_ref(ifproxy); + if (FAILED(hr)) + ifproxy_destroy(ifproxy); + } + if (hr == S_OK) *object = ifproxy->iface; } @@ -1005,7 +1240,8 @@ static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt, REFI static HRESULT WINAPI StdMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, void **ppv) { - struct stub_manager *stubmgr; + StdMarshalImpl *This = (StdMarshalImpl *)iface; + struct stub_manager *stubmgr = NULL; STDOBJREF stdobjref; ULONG res; HRESULT hres; @@ -1039,7 +1275,7 @@ StdMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, v /* unref the ifstub. FIXME: only do this on success? */ if (!stub_manager_is_table_marshaled(stubmgr, &stdobjref.ipid)) - stub_manager_ext_release(stubmgr, stdobjref.cPublicRefs); + stub_manager_ext_release(stubmgr, stdobjref.cPublicRefs, TRUE); stub_manager_int_release(stubmgr); return hres; @@ -1056,8 +1292,6 @@ StdMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, v { if (!stub_manager_notify_unmarshal(stubmgr, &stdobjref.ipid)) hres = CO_E_OBJNOTCONNECTED; - - stub_manager_int_release(stubmgr); } else { @@ -1066,17 +1300,20 @@ StdMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, v wine_dbgstr_longlong(stdobjref.oid)); hres = CO_E_OBJNOTCONNECTED; } - - apartment_release(stub_apt); } else TRACE("Treating unmarshal from OXID %s as inter-process\n", wine_dbgstr_longlong(stdobjref.oxid)); if (hres == S_OK) - hres = unmarshal_object(&stdobjref, apt, riid, ppv); + hres = unmarshal_object(&stdobjref, apt, This->dwDestContext, + This->pvDestContext, riid, + stubmgr ? &stubmgr->oxid_info : NULL, ppv); - if (hres) WARN("Failed with error 0x%08lx\n", hres); + if (stubmgr) stub_manager_int_release(stubmgr); + if (stub_apt) apartment_release(stub_apt); + + if (hres) WARN("Failed with error 0x%08x\n", hres); else TRACE("Successfully created proxy %p\n", *ppv); return hres; @@ -1185,11 +1422,11 @@ HRESULT WINAPI CoGetStandardMarshal(REFIID riid, IUnknown *pUnk, if (pUnk == NULL) { - FIXME("(%s,NULL,%lx,%p,%lx,%p), unimplemented yet.\n", + FIXME("(%s,NULL,%x,%p,%x,%p), unimplemented yet.\n", debugstr_guid(riid),dwDestContext,pvDestContext,mshlflags,ppMarshal); return E_NOTIMPL; } - TRACE("(%s,%p,%lx,%p,%lx,%p)\n", + TRACE("(%s,%p,%x,%p,%x,%p)\n", debugstr_guid(riid),pUnk,dwDestContext,pvDestContext,mshlflags,ppMarshal); *ppMarshal = HeapAlloc(GetProcessHeap(),0,sizeof(StdMarshalImpl)); dm = (StdMarshalImpl*) *ppMarshal; @@ -1241,7 +1478,7 @@ static HRESULT get_unmarshaler_from_stream(IStream *stream, IMarshal **marshal, hr = IStream_Read(stream, &objref, FIELD_OFFSET(OBJREF, u_objref), &res); if (hr || (res != FIELD_OFFSET(OBJREF, u_objref))) { - ERR("Failed to read common OBJREF header, 0x%08lx\n", hr); + ERR("Failed to read common OBJREF header, 0x%08x\n", hr); return STG_E_READFAULT; } @@ -1270,7 +1507,7 @@ static HRESULT get_unmarshaler_from_stream(IStream *stream, IMarshal **marshal, custom_header_size, &res); if (hr || (res != custom_header_size)) { - ERR("Failed to read OR_CUSTOM header, 0x%08lx\n", hr); + ERR("Failed to read OR_CUSTOM header, 0x%08x\n", hr); return STG_E_READFAULT; } /* now create the marshaler specified in the stream */ @@ -1286,7 +1523,7 @@ static HRESULT get_unmarshaler_from_stream(IStream *stream, IMarshal **marshal, } if (hr) - ERR("Failed to create marshal, 0x%08lx\n", hr); + ERR("Failed to create marshal, 0x%08x\n", hr); return hr; } @@ -1327,20 +1564,20 @@ HRESULT WINAPI CoGetMarshalSizeMax(ULONG *pulSize, REFIID riid, IUnknown *pUnk, pvDestContext, mshlFlags, &marshaler_clsid); if (hr) { - ERR("IMarshal::GetUnmarshalClass failed, 0x%08lx\n", hr); + ERR("IMarshal::GetUnmarshalClass failed, 0x%08x\n", hr); IMarshal_Release(pMarshal); return hr; } hr = IMarshal_GetMarshalSizeMax(pMarshal, riid, pUnk, dwDestContext, pvDestContext, mshlFlags, pulSize); - /* add on the size of the common header */ - *pulSize += FIELD_OFFSET(OBJREF, u_objref); - - /* if custom marshaling, add on size of custom header */ - if (!IsEqualCLSID(&marshaler_clsid, &CLSID_DfMarshal)) - *pulSize += FIELD_OFFSET(OBJREF, u_objref.u_custom.pData) - - FIELD_OFFSET(OBJREF, u_objref.u_custom); + if (IsEqualCLSID(&marshaler_clsid, &CLSID_DfMarshal)) + /* add on the size of the common header */ + *pulSize += FIELD_OFFSET(OBJREF, u_objref); + else + /* custom marshaling: add on the size of the whole OBJREF structure + * like native does */ + *pulSize += sizeof(OBJREF); IMarshal_Release(pMarshal); return hr; @@ -1400,12 +1637,12 @@ HRESULT WINAPI CoMarshalInterface(IStream *pStream, REFIID riid, IUnknown *pUnk, OBJREF objref; LPMARSHAL pMarshal; - TRACE("(%p, %s, %p, %lx, %p,", pStream, debugstr_guid(riid), pUnk, + TRACE("(%p, %s, %p, %x, %p,", pStream, debugstr_guid(riid), pUnk, dwDestContext, pvDestContext); dump_MSHLFLAGS(mshlFlags); TRACE(")\n"); - if (pUnk == NULL) + if (!pUnk || !pStream) return E_INVALIDARG; objref.signature = OBJREF_SIGNATURE; @@ -1415,7 +1652,7 @@ HRESULT WINAPI CoMarshalInterface(IStream *pStream, REFIID riid, IUnknown *pUnk, hr = get_marshaler(riid, pUnk, dwDestContext, pvDestContext, mshlFlags, &pMarshal); if (hr) { - ERR("Failed to get marshaller, 0x%08lx\n", hr); + ERR("Failed to get marshaller, 0x%08x\n", hr); return hr; } @@ -1423,7 +1660,7 @@ HRESULT WINAPI CoMarshalInterface(IStream *pStream, REFIID riid, IUnknown *pUnk, pvDestContext, mshlFlags, &marshaler_clsid); if (hr) { - ERR("IMarshal::GetUnmarshalClass failed, 0x%08lx\n", hr); + ERR("IMarshal::GetUnmarshalClass failed, 0x%08x\n", hr); goto cleanup; } @@ -1437,7 +1674,7 @@ HRESULT WINAPI CoMarshalInterface(IStream *pStream, REFIID riid, IUnknown *pUnk, hr = IStream_Write(pStream, &objref, FIELD_OFFSET(OBJREF, u_objref), NULL); if (hr) { - ERR("Failed to write OBJREF header to stream, 0x%08lx\n", hr); + ERR("Failed to write OBJREF header to stream, 0x%08x\n", hr); goto cleanup; } } @@ -1453,7 +1690,7 @@ HRESULT WINAPI CoMarshalInterface(IStream *pStream, REFIID riid, IUnknown *pUnk, &objref.u_objref.u_custom.size); if (hr) { - ERR("Failed to get max size of marshal data, error 0x%08lx\n", hr); + ERR("Failed to get max size of marshal data, error 0x%08x\n", hr); goto cleanup; } /* write constant sized common header and OR_CUSTOM data into stream */ @@ -1461,7 +1698,7 @@ HRESULT WINAPI CoMarshalInterface(IStream *pStream, REFIID riid, IUnknown *pUnk, FIELD_OFFSET(OBJREF, u_objref.u_custom.pData), NULL); if (hr) { - ERR("Failed to write OR_CUSTOM header to stream with 0x%08lx\n", hr); + ERR("Failed to write OR_CUSTOM header to stream with 0x%08x\n", hr); goto cleanup; } } @@ -1473,14 +1710,14 @@ HRESULT WINAPI CoMarshalInterface(IStream *pStream, REFIID riid, IUnknown *pUnk, if (hr) { - ERR("Failed to marshal the interface %s, %lx\n", debugstr_guid(riid), hr); + ERR("Failed to marshal the interface %s, %x\n", debugstr_guid(riid), hr); goto cleanup; } cleanup: IMarshal_Release(pMarshal); - TRACE("completed with hr 0x%08lx\n", hr); + TRACE("completed with hr 0x%08x\n", hr); return hr; } @@ -1514,6 +1751,9 @@ HRESULT WINAPI CoUnmarshalInterface(IStream *pStream, REFIID riid, LPVOID *ppv) TRACE("(%p, %s, %p)\n", pStream, debugstr_guid(riid), ppv); + if (!pStream || !ppv) + return E_INVALIDARG; + hr = get_unmarshaler_from_stream(pStream, &pMarshal, &iid); if (hr != S_OK) return hr; @@ -1521,20 +1761,17 @@ HRESULT WINAPI CoUnmarshalInterface(IStream *pStream, REFIID riid, LPVOID *ppv) /* call the helper object to do the actual unmarshaling */ hr = IMarshal_UnmarshalInterface(pMarshal, pStream, &iid, (LPVOID*)&object); if (hr) - ERR("IMarshal::UnmarshalInterface failed, 0x%08lx\n", hr); - - /* IID_NULL means use the interface ID of the marshaled object */ - if (!IsEqualIID(riid, &IID_NULL)) - iid = *riid; + ERR("IMarshal::UnmarshalInterface failed, 0x%08x\n", hr); if (hr == S_OK) { - if (!IsEqualIID(riid, &iid)) + /* IID_NULL means use the interface ID of the marshaled object */ + if (!IsEqualIID(riid, &IID_NULL) && !IsEqualIID(riid, &iid)) { TRACE("requested interface != marshalled interface, additional QI needed\n"); - hr = IUnknown_QueryInterface(object, &iid, ppv); + hr = IUnknown_QueryInterface(object, riid, ppv); if (hr) - ERR("Couldn't query for interface %s, hr = 0x%08lx\n", + ERR("Couldn't query for interface %s, hr = 0x%08x\n", debugstr_guid(riid), hr); IUnknown_Release(object); } @@ -1546,7 +1783,7 @@ HRESULT WINAPI CoUnmarshalInterface(IStream *pStream, REFIID riid, LPVOID *ppv) IMarshal_Release(pMarshal); - TRACE("completed with hr 0x%lx\n", hr); + TRACE("completed with hr 0x%x\n", hr); return hr; } @@ -1588,7 +1825,7 @@ HRESULT WINAPI CoReleaseMarshalData(IStream *pStream) /* call the helper object to do the releasing of marshal data */ hr = IMarshal_ReleaseMarshalData(pMarshal, pStream); if (hr) - ERR("IMarshal::ReleaseMarshalData failed with error 0x%08lx\n", hr); + ERR("IMarshal::ReleaseMarshalData failed with error 0x%08x\n", hr); IMarshal_Release(pMarshal); return hr; @@ -1603,7 +1840,7 @@ HRESULT WINAPI CoReleaseMarshalData(IStream *pStream) * PARAMS * riid [I] Identifier of the interface to be marshalled. * pUnk [I] Pointer to IUnknown-derived interface that will be marshalled. - * ppStm [O] Pointer to IStream object that is created and then used to store the marshalled inteface. + * ppStm [O] Pointer to IStream object that is created and then used to store the marshalled interface. * * RETURNS * Success: S_OK @@ -1628,7 +1865,7 @@ HRESULT WINAPI CoMarshalInterThreadInterfaceInStream( if (SUCCEEDED(hres)) { memset(&seekto, 0, sizeof(seekto)); - IStream_Seek(*ppStm, seekto, SEEK_SET, &xpos); + IStream_Seek(*ppStm, seekto, STREAM_SEEK_SET, &xpos); } else { @@ -1642,10 +1879,10 @@ HRESULT WINAPI CoMarshalInterThreadInterfaceInStream( /*********************************************************************** * CoGetInterfaceAndReleaseStream [OLE32.@] * - * Unmarshalls an inteface from a stream and then releases the stream. + * Unmarshalls an interface from a stream and then releases the stream. * * PARAMS - * pStm [I] Stream that contains the marshalled inteface. + * pStm [I] Stream that contains the marshalled interface. * riid [I] Interface identifier of the object to unmarshall. * ppv [O] Address of pointer where the requested interface object will be stored. * @@ -1654,7 +1891,7 @@ HRESULT WINAPI CoMarshalInterThreadInterfaceInStream( * Failure: A COM error code * * SEE ALSO - * CoMarshalInterThreadInterfaceInStream() and CoUnmarshalInteface() + * CoMarshalInterThreadInterfaceInStream() and CoUnmarshalInterface() */ HRESULT WINAPI CoGetInterfaceAndReleaseStream(LPSTREAM pStm, REFIID riid, LPVOID *ppv) @@ -1663,6 +1900,7 @@ HRESULT WINAPI CoGetInterfaceAndReleaseStream(LPSTREAM pStm, REFIID riid, TRACE("(%p, %s, %p)\n", pStm, debugstr_guid(riid), ppv); + if(!pStm) return E_INVALIDARG; hres = CoUnmarshalInterface(pStm, riid, ppv); IStream_Release(pStm); return hres; diff --git a/reactos/dll/win32/ole32/memlockbytes.c b/reactos/dll/win32/ole32/memlockbytes.c index 2b5503475d7..57c5b0bfa4f 100644 --- a/reactos/dll/win32/ole32/memlockbytes.c +++ b/reactos/dll/win32/ole32/memlockbytes.c @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" @@ -43,7 +43,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole); /****************************************************************************** * HGLOBALLockBytesImpl definition. * - * This class imlements the ILockBytes inteface and represents a byte array + * This class implements the ILockBytes interface and represents a byte array * object supported by an HGLOBAL pointer. */ struct HGLOBALLockBytesImpl @@ -81,77 +81,15 @@ typedef struct HGLOBALLockBytesImpl HGLOBALLockBytesImpl; /* * Method definition for the HGLOBALLockBytesImpl class. */ -HGLOBALLockBytesImpl* HGLOBALLockBytesImpl_Construct( +static HGLOBALLockBytesImpl* HGLOBALLockBytesImpl_Construct( HGLOBAL hGlobal, BOOL fDeleteOnRelease); -void HGLOBALLockBytesImpl_Destroy(HGLOBALLockBytesImpl* This); +static void HGLOBALLockBytesImpl_Destroy(HGLOBALLockBytesImpl* This); -HRESULT WINAPI HGLOBALLockBytesImpl_QueryInterface( - ILockBytes* iface, - REFIID riid, /* [in] */ - void** ppvObject); /* [iid_is][out] */ +static HRESULT WINAPI HGLOBALLockBytesImpl_SetSize( ILockBytes* iface, ULARGE_INTEGER libNewSize ); -ULONG WINAPI HGLOBALLockBytesImpl_AddRef( - ILockBytes* iface); - -ULONG WINAPI HGLOBALLockBytesImpl_Release( - ILockBytes* iface); - -HRESULT WINAPI HGLOBALLockBytesImpl_ReadAt( - ILockBytes* iface, - ULARGE_INTEGER ulOffset, /* [in] */ - void* pv, /* [length_is][size_is][out] */ - ULONG cb, /* [in] */ - ULONG* pcbRead); /* [out] */ - -HRESULT WINAPI HGLOBALLockBytesImpl_WriteAt( - ILockBytes* iface, - ULARGE_INTEGER ulOffset, /* [in] */ - const void* pv, /* [size_is][in] */ - ULONG cb, /* [in] */ - ULONG* pcbWritten); /* [out] */ - -HRESULT WINAPI HGLOBALLockBytesImpl_Flush( - ILockBytes* iface); - -HRESULT WINAPI HGLOBALLockBytesImpl_SetSize( - ILockBytes* iface, - ULARGE_INTEGER libNewSize); /* [in] */ - -HRESULT WINAPI HGLOBALLockBytesImpl_LockRegion( - ILockBytes* iface, - ULARGE_INTEGER libOffset, /* [in] */ - ULARGE_INTEGER cb, /* [in] */ - DWORD dwLockType); /* [in] */ - -HRESULT WINAPI HGLOBALLockBytesImpl_UnlockRegion( - ILockBytes* iface, - ULARGE_INTEGER libOffset, /* [in] */ - ULARGE_INTEGER cb, /* [in] */ - DWORD dwLockType); /* [in] */ - -HRESULT WINAPI HGLOBALLockBytesImpl_Stat( - ILockBytes* iface, - STATSTG* pstatstg, /* [out] */ - DWORD grfStatFlag); /* [in] */ - -/* - * Virtual function table for the HGLOBALLockBytesImpl class. - */ -static const ILockBytesVtbl HGLOBALLockBytesImpl_Vtbl = -{ - HGLOBALLockBytesImpl_QueryInterface, - HGLOBALLockBytesImpl_AddRef, - HGLOBALLockBytesImpl_Release, - HGLOBALLockBytesImpl_ReadAt, - HGLOBALLockBytesImpl_WriteAt, - HGLOBALLockBytesImpl_Flush, - HGLOBALLockBytesImpl_SetSize, - HGLOBALLockBytesImpl_LockRegion, - HGLOBALLockBytesImpl_UnlockRegion, - HGLOBALLockBytesImpl_Stat, -}; +static const ILockBytesVtbl HGLOBALLockBytesImpl_Vtbl; /****************************************************************************** * CreateILockBytesOnHGlobal [OLE32.@] @@ -224,10 +162,10 @@ HRESULT WINAPI GetHGlobalFromILockBytes(ILockBytes* plkbyt, HGLOBAL* phglobal) /* It is not our lockbytes implementation, so use a more generic way */ hres = ILockBytes_Stat(plkbyt,&stbuf,0); if (hres != S_OK) { - ERR("Cannot ILockBytes_Stat, %lx\n",hres); + ERR("Cannot ILockBytes_Stat, %x\n",hres); return hres; } - FIXME("cbSize is %ld\n",stbuf.cbSize.u.LowPart); + FIXME("cbSize is %d\n",stbuf.cbSize.u.LowPart); *phglobal = GlobalAlloc( GMEM_MOVEABLE|GMEM_SHARE, stbuf.cbSize.u.LowPart); if (!*phglobal) return E_INVALIDARG; @@ -235,11 +173,11 @@ HRESULT WINAPI GetHGlobalFromILockBytes(ILockBytes* plkbyt, HGLOBAL* phglobal) hres = ILockBytes_ReadAt(plkbyt, start, GlobalLock(*phglobal), stbuf.cbSize.u.LowPart, &xread); GlobalUnlock(*phglobal); if (hres != S_OK) { - FIXME("%p->ReadAt failed with %lx\n",plkbyt,hres); + FIXME("%p->ReadAt failed with %x\n",plkbyt,hres); return hres; } if (stbuf.cbSize.u.LowPart != xread) { - FIXME("Read size is not requested size %ld vs %ld?\n",stbuf.cbSize.u.LowPart, xread); + FIXME("Read size is not requested size %d vs %d?\n",stbuf.cbSize.u.LowPart, xread); } return S_OK; } @@ -258,8 +196,8 @@ HRESULT WINAPI GetHGlobalFromILockBytes(ILockBytes* plkbyt, HGLOBAL* phglobal) * fDeleteOnRelease [ I] Flag set to TRUE if the HGLOBAL will be released * when the IStream object is destroyed. */ -HGLOBALLockBytesImpl* HGLOBALLockBytesImpl_Construct(HGLOBAL hGlobal, - BOOL fDeleteOnRelease) +static HGLOBALLockBytesImpl* HGLOBALLockBytesImpl_Construct(HGLOBAL hGlobal, + BOOL fDeleteOnRelease) { HGLOBALLockBytesImpl* newLockBytes; newLockBytes = HeapAlloc(GetProcessHeap(), 0, sizeof(HGLOBALLockBytesImpl)); @@ -306,7 +244,7 @@ HGLOBALLockBytesImpl* HGLOBALLockBytesImpl_Construct(HGLOBAL hGlobal, * HGLOBALLockBytesImpl class. The pointer passed-in to this function will be * freed and will not be valid anymore. */ -void HGLOBALLockBytesImpl_Destroy(HGLOBALLockBytesImpl* This) +static void HGLOBALLockBytesImpl_Destroy(HGLOBALLockBytesImpl* This) { /* * Release the HGlobal if the constructor asked for that. @@ -327,7 +265,7 @@ void HGLOBALLockBytesImpl_Destroy(HGLOBALLockBytesImpl* This) * This implements the IUnknown method QueryInterface for this * class */ -HRESULT WINAPI HGLOBALLockBytesImpl_QueryInterface( +static HRESULT WINAPI HGLOBALLockBytesImpl_QueryInterface( ILockBytes* iface, REFIID riid, /* [in] */ void** ppvObject) /* [iid_is][out] */ @@ -348,11 +286,8 @@ HRESULT WINAPI HGLOBALLockBytesImpl_QueryInterface( /* * Compare the riid with the interface IDs implemented by this object. */ - if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) - { - *ppvObject = (ILockBytes*)This; - } - else if (memcmp(&IID_ILockBytes, riid, sizeof(IID_ILockBytes)) == 0) + if (IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid, &IID_ILockBytes)) { *ppvObject = (ILockBytes*)This; } @@ -367,7 +302,7 @@ HRESULT WINAPI HGLOBALLockBytesImpl_QueryInterface( * Query Interface always increases the reference count by one when it is * successful */ - HGLOBALLockBytesImpl_AddRef(iface); + IUnknown_AddRef(iface); return S_OK; } @@ -376,7 +311,7 @@ HRESULT WINAPI HGLOBALLockBytesImpl_QueryInterface( * This implements the IUnknown method AddRef for this * class */ -ULONG WINAPI HGLOBALLockBytesImpl_AddRef(ILockBytes* iface) +static ULONG WINAPI HGLOBALLockBytesImpl_AddRef(ILockBytes* iface) { HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface; return InterlockedIncrement(&This->ref); @@ -386,7 +321,7 @@ ULONG WINAPI HGLOBALLockBytesImpl_AddRef(ILockBytes* iface) * This implements the IUnknown method Release for this * class */ -ULONG WINAPI HGLOBALLockBytesImpl_Release(ILockBytes* iface) +static ULONG WINAPI HGLOBALLockBytesImpl_Release(ILockBytes* iface) { HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface; ULONG ref; @@ -412,7 +347,7 @@ ULONG WINAPI HGLOBALLockBytesImpl_Release(ILockBytes* iface) * * See the documentation of ILockBytes for more info. */ -HRESULT WINAPI HGLOBALLockBytesImpl_ReadAt( +static HRESULT WINAPI HGLOBALLockBytesImpl_ReadAt( ILockBytes* iface, ULARGE_INTEGER ulOffset, /* [in] */ void* pv, /* [length_is][size_is][out] */ @@ -484,7 +419,7 @@ HRESULT WINAPI HGLOBALLockBytesImpl_ReadAt( * * See the documentation of ILockBytes for more info. */ -HRESULT WINAPI HGLOBALLockBytesImpl_WriteAt( +static HRESULT WINAPI HGLOBALLockBytesImpl_WriteAt( ILockBytes* iface, ULARGE_INTEGER ulOffset, /* [in] */ const void* pv, /* [size_is][in] */ @@ -549,7 +484,7 @@ HRESULT WINAPI HGLOBALLockBytesImpl_WriteAt( * * See the documentation of ILockBytes for more info. */ -HRESULT WINAPI HGLOBALLockBytesImpl_Flush(ILockBytes* iface) +static HRESULT WINAPI HGLOBALLockBytesImpl_Flush(ILockBytes* iface) { return S_OK; } @@ -561,7 +496,7 @@ HRESULT WINAPI HGLOBALLockBytesImpl_Flush(ILockBytes* iface) * * See the documentation of ILockBytes for more info. */ -HRESULT WINAPI HGLOBALLockBytesImpl_SetSize( +static HRESULT WINAPI HGLOBALLockBytesImpl_SetSize( ILockBytes* iface, ULARGE_INTEGER libNewSize) /* [in] */ { @@ -598,7 +533,7 @@ HRESULT WINAPI HGLOBALLockBytesImpl_SetSize( * * See the documentation of ILockBytes for more info. */ -HRESULT WINAPI HGLOBALLockBytesImpl_LockRegion( +static HRESULT WINAPI HGLOBALLockBytesImpl_LockRegion( ILockBytes* iface, ULARGE_INTEGER libOffset, /* [in] */ ULARGE_INTEGER cb, /* [in] */ @@ -614,7 +549,7 @@ HRESULT WINAPI HGLOBALLockBytesImpl_LockRegion( * * See the documentation of ILockBytes for more info. */ -HRESULT WINAPI HGLOBALLockBytesImpl_UnlockRegion( +static HRESULT WINAPI HGLOBALLockBytesImpl_UnlockRegion( ILockBytes* iface, ULARGE_INTEGER libOffset, /* [in] */ ULARGE_INTEGER cb, /* [in] */ @@ -631,7 +566,7 @@ HRESULT WINAPI HGLOBALLockBytesImpl_UnlockRegion( * * See the documentation of ILockBytes for more info. */ -HRESULT WINAPI HGLOBALLockBytesImpl_Stat( +static HRESULT WINAPI HGLOBALLockBytesImpl_Stat( ILockBytes* iface, STATSTG* pstatstg, /* [out] */ DWORD grfStatFlag) /* [in] */ @@ -646,3 +581,20 @@ HRESULT WINAPI HGLOBALLockBytesImpl_Stat( return S_OK; } + +/* + * Virtual function table for the HGLOBALLockBytesImpl class. + */ +static const ILockBytesVtbl HGLOBALLockBytesImpl_Vtbl = +{ + HGLOBALLockBytesImpl_QueryInterface, + HGLOBALLockBytesImpl_AddRef, + HGLOBALLockBytesImpl_Release, + HGLOBALLockBytesImpl_ReadAt, + HGLOBALLockBytesImpl_WriteAt, + HGLOBALLockBytesImpl_Flush, + HGLOBALLockBytesImpl_SetSize, + HGLOBALLockBytesImpl_LockRegion, + HGLOBALLockBytesImpl_UnlockRegion, + HGLOBALLockBytesImpl_Stat, +}; diff --git a/reactos/dll/win32/ole32/memlockbytes16.c b/reactos/dll/win32/ole32/memlockbytes16.c index 61078f8fede..bccb953c735 100644 --- a/reactos/dll/win32/ole32/memlockbytes16.c +++ b/reactos/dll/win32/ole32/memlockbytes16.c @@ -15,7 +15,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" @@ -43,7 +43,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole); /****************************************************************************** * HGLOBALLockBytesImpl16 definition. * - * This class imlements the ILockBytes inteface and represents a byte array + * This class implements the ILockBytes interface and represents a byte array * object supported by an HGLOBAL pointer. */ struct HGLOBALLockBytesImpl16 @@ -174,7 +174,7 @@ static void HGLOBALLockBytesImpl16_Destroy(HGLOBALLockBytesImpl16* This) * This implements the IUnknown method AddRef for this * class */ -ULONG HGLOBALLockBytesImpl16_AddRef(ILockBytes16* iface) +ULONG CDECL HGLOBALLockBytesImpl16_AddRef(ILockBytes16* iface) { HGLOBALLockBytesImpl16* const This=(HGLOBALLockBytesImpl16*)iface; @@ -188,7 +188,7 @@ ULONG HGLOBALLockBytesImpl16_AddRef(ILockBytes16* iface) * This implements the IUnknown method QueryInterface for this * class */ -HRESULT HGLOBALLockBytesImpl16_QueryInterface( +HRESULT CDECL HGLOBALLockBytesImpl16_QueryInterface( ILockBytes16* iface, /* [in] SEGPTR */ REFIID riid, /* [in] */ void** ppvObject) /* [out][iid_is] (ptr to SEGPTR!) */ @@ -235,7 +235,7 @@ HRESULT HGLOBALLockBytesImpl16_QueryInterface( * This implements the IUnknown method Release for this * class */ -ULONG HGLOBALLockBytesImpl16_Release(ILockBytes16* iface) +ULONG CDECL HGLOBALLockBytesImpl16_Release(ILockBytes16* iface) { HGLOBALLockBytesImpl16* const This=(HGLOBALLockBytesImpl16*)iface; ULONG ref; @@ -260,7 +260,7 @@ ULONG HGLOBALLockBytesImpl16_Release(ILockBytes16* iface) * * See the documentation of ILockBytes for more info. */ -HRESULT HGLOBALLockBytesImpl16_ReadAt( +HRESULT CDECL HGLOBALLockBytesImpl16_ReadAt( ILockBytes16* iface, ULARGE_INTEGER ulOffset, /* [in] */ void* pv, /* [out][length_is][size_is] */ @@ -273,7 +273,7 @@ HRESULT HGLOBALLockBytesImpl16_ReadAt( ULONG bytesReadBuffer = 0; ULONG bytesToReadFromBuffer; - TRACE("(%p,%ld,%p,%ld,%p)\n",This,ulOffset.u.LowPart,pv,cb,pcbRead); + TRACE("(%p,%d,%p,%d,%p)\n",This,ulOffset.u.LowPart,pv,cb,pcbRead); /* * If the caller is not interested in the number of bytes read, * we use another buffer to avoid "if" statements in the code. @@ -332,14 +332,14 @@ HRESULT HGLOBALLockBytesImpl16_ReadAt( * * See the documentation of ILockBytes for more info. */ -HRESULT HGLOBALLockBytesImpl16_SetSize( +HRESULT CDECL HGLOBALLockBytesImpl16_SetSize( ILockBytes16* iface, ULARGE_INTEGER libNewSize) /* [in] */ { HGLOBALLockBytesImpl16* const This=(HGLOBALLockBytesImpl16*)iface; HGLOBAL16 supportHandle; - TRACE("(%p,%ld)\n",This,libNewSize.u.LowPart); + TRACE("(%p,%d)\n",This,libNewSize.u.LowPart); /* * As documented. */ @@ -371,7 +371,7 @@ HRESULT HGLOBALLockBytesImpl16_SetSize( * * See the documentation of ILockBytes for more info. */ -HRESULT HGLOBALLockBytesImpl16_WriteAt( +HRESULT CDECL HGLOBALLockBytesImpl16_WriteAt( ILockBytes16* iface, ULARGE_INTEGER ulOffset, /* [in] */ const void* pv, /* [in][size_is] */ @@ -384,7 +384,7 @@ HRESULT HGLOBALLockBytesImpl16_WriteAt( ULARGE_INTEGER newSize; ULONG bytesWritten = 0; - TRACE("(%p,%ld,%p,%ld,%p)\n",This,ulOffset.u.LowPart,pv,cb,pcbWritten); + TRACE("(%p,%d,%p,%d,%p)\n",This,ulOffset.u.LowPart,pv,cb,pcbWritten); /* * If the caller is not interested in the number of bytes written, * we use another buffer to avoid "if" statements in the code. @@ -433,7 +433,7 @@ HRESULT HGLOBALLockBytesImpl16_WriteAt( * * See the documentation of ILockBytes for more info. */ -HRESULT HGLOBALLockBytesImpl16_Flush(ILockBytes16* iface) +HRESULT CDECL HGLOBALLockBytesImpl16_Flush(ILockBytes16* iface) { TRACE("(%p)\n",iface); return S_OK; @@ -446,7 +446,7 @@ HRESULT HGLOBALLockBytesImpl16_Flush(ILockBytes16* iface) * * See the documentation of ILockBytes for more info. */ -HRESULT HGLOBALLockBytesImpl16_LockRegion( +HRESULT CDECL HGLOBALLockBytesImpl16_LockRegion( ILockBytes16* iface, ULARGE_INTEGER libOffset, /* [in] */ ULARGE_INTEGER cb, /* [in] */ @@ -462,7 +462,7 @@ HRESULT HGLOBALLockBytesImpl16_LockRegion( * * See the documentation of ILockBytes for more info. */ -HRESULT HGLOBALLockBytesImpl16_UnlockRegion( +HRESULT CDECL HGLOBALLockBytesImpl16_UnlockRegion( ILockBytes16* iface, ULARGE_INTEGER libOffset, /* [in] */ ULARGE_INTEGER cb, /* [in] */ @@ -479,7 +479,7 @@ HRESULT HGLOBALLockBytesImpl16_UnlockRegion( * * See the documentation of ILockBytes for more info. */ -HRESULT HGLOBALLockBytesImpl16_Stat( +HRESULT CDECL HGLOBALLockBytesImpl16_Stat( ILockBytes16*iface, STATSTG16* pstatstg, /* [out] */ DWORD grfStatFlag) /* [in] */ diff --git a/reactos/dll/win32/ole32/moniker.c b/reactos/dll/win32/ole32/moniker.c index a7425f13002..a4d2a5efc59 100644 --- a/reactos/dll/win32/ole32/moniker.c +++ b/reactos/dll/win32/ole32/moniker.c @@ -4,6 +4,7 @@ * Copyright 1998 Marcus Meissner * Copyright 1999 Noomen Hamza * Copyright 2005 Robert Shearman (for CodeWeavers) + * Copyright 2007 Robert Shearman * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -17,7 +18,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * TODO: * - IRunningObjectTable should work interprocess, but currently doesn't. @@ -40,11 +41,17 @@ #include "wine/list.h" #include "wine/debug.h" +#include "wine/unicode.h" #include "compobj_private.h" +#include "moniker.h" WINE_DEFAULT_DEBUG_CHANNEL(ole); +/* see MSDN docs for IROTData::GetComparisonData, which states what this + * constant is (http://msdn2.microsoft.com/en-us/library/ms693773.aspx) */ +#define MAX_COMPARISON_DATA 2048 + /* define the structure of the running object table elements */ struct rot_entry { @@ -139,26 +146,77 @@ static HRESULT get_moniker_comparison_data(IMoniker *pMoniker, MInterfacePointer { HRESULT hr; IROTData *pROTData = NULL; - ULONG size = 0; hr = IMoniker_QueryInterface(pMoniker, &IID_IROTData, (void *)&pROTData); - if (hr != S_OK) + if (SUCCEEDED(hr)) { - ERR("Failed to query moniker for IROTData interface, hr = 0x%08lx\n", hr); - return hr; + ULONG size = MAX_COMPARISON_DATA; + *moniker_data = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(MInterfacePointer, abData[size])); + hr = IROTData_GetComparisonData(pROTData, (*moniker_data)->abData, size, &size); + if (hr != S_OK) + { + ERR("Failed to copy comparison data into buffer, hr = 0x%08x\n", hr); + HeapFree(GetProcessHeap(), 0, *moniker_data); + return hr; + } + (*moniker_data)->ulCntData = size; } - IROTData_GetComparisonData(pROTData, NULL, 0, &size); - *moniker_data = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(MInterfacePointer, abData[size])); - (*moniker_data)->ulCntData = size; - hr = IROTData_GetComparisonData(pROTData, (*moniker_data)->abData, size, &size); - if (hr != S_OK) + else { - ERR("Failed to copy comparison data into buffer, hr = 0x%08lx\n", hr); - HeapFree(GetProcessHeap(), 0, *moniker_data); - return hr; + IBindCtx *pbc; + LPOLESTR pszDisplayName; + CLSID clsid; + int len; + + TRACE("generating comparison data from display name\n"); + + hr = CreateBindCtx(0, &pbc); + if (FAILED(hr)) + return hr; + hr = IMoniker_GetDisplayName(pMoniker, pbc, NULL, &pszDisplayName); + IBindCtx_Release(pbc); + if (FAILED(hr)) + return hr; + hr = IMoniker_GetClassID(pMoniker, &clsid); + if (FAILED(hr)) + { + CoTaskMemFree(pszDisplayName); + return hr; + } + + len = strlenW(pszDisplayName); + *moniker_data = HeapAlloc(GetProcessHeap(), 0, + FIELD_OFFSET(MInterfacePointer, abData[sizeof(CLSID) + (len+1)*sizeof(WCHAR)])); + if (!*moniker_data) + { + CoTaskMemFree(pszDisplayName); + return E_OUTOFMEMORY; + } + (*moniker_data)->ulCntData = sizeof(CLSID) + (len+1)*sizeof(WCHAR); + + memcpy(&(*moniker_data)->abData[0], &clsid, sizeof(clsid)); + memcpy(&(*moniker_data)->abData[sizeof(clsid)], pszDisplayName, (len+1)*sizeof(WCHAR)); } return S_OK; } +static HRESULT reduce_moniker(IMoniker *pmk, IBindCtx *pbc, IMoniker **pmkReduced) +{ + IBindCtx *pbcNew = NULL; + HRESULT hr; + if (!pbc) + { + hr = CreateBindCtx(0, &pbcNew); + if (FAILED(hr)) + return hr; + pbc = pbcNew; + } + hr = IMoniker_Reduce(pmk, pbc, MKRREDUCE_ALL, NULL, pmkReduced); + if (FAILED(hr)) + ERR("reducing moniker failed with error 0x%08x\n", hr); + if (pbcNew) IBindCtx_Release(pbcNew); + return hr; +} + /*********************************************************************** * RunningObjectTable_QueryInterface */ @@ -223,6 +281,9 @@ RunningObjectTableImpl_Destroy(void) rot_entry_delete(rot_entry); } + DEBUG_CLEAR_CRITSEC_NAME(&runningObjectTableInstance->lock); + DeleteCriticalSection(&runningObjectTableInstance->lock); + /* free the ROT structure memory */ HeapFree(GetProcessHeap(),0,runningObjectTableInstance); runningObjectTableInstance = NULL; @@ -279,18 +340,13 @@ RunningObjectTableImpl_Register(IRunningObjectTable* iface, DWORD grfFlags, HRESULT hr = S_OK; IStream *pStream = NULL; DWORD mshlflags; + IBindCtx *pbc; - TRACE("(%p,%ld,%p,%p,%p)\n",This,grfFlags,punkObject,pmkObjectName,pdwRegister); + TRACE("(%p,%d,%p,%p,%p)\n",This,grfFlags,punkObject,pmkObjectName,pdwRegister); - /* - * there's only two types of register : strong and or weak registration - * (only one must be passed on parameter) - */ - if ( ( (grfFlags & ROTFLAGS_REGISTRATIONKEEPSALIVE) || !(grfFlags & ROTFLAGS_ALLOWANYCLIENT)) && - (!(grfFlags & ROTFLAGS_REGISTRATIONKEEPSALIVE) || (grfFlags & ROTFLAGS_ALLOWANYCLIENT)) && - (grfFlags) ) + if (grfFlags & ~(ROTFLAGS_REGISTRATIONKEEPSALIVE|ROTFLAGS_ALLOWANYCLIENT)) { - ERR("Invalid combination of ROTFLAGS: %lx\n", grfFlags); + ERR("Invalid grfFlags: 0x%08x\n", grfFlags & ~(ROTFLAGS_REGISTRATIONKEEPSALIVE|ROTFLAGS_ALLOWANYCLIENT)); return E_INVALIDARG; } @@ -301,8 +357,6 @@ RunningObjectTableImpl_Register(IRunningObjectTable* iface, DWORD grfFlags, if (!rot_entry) return E_OUTOFMEMORY; - CoFileTimeNow(&rot_entry->last_modified); - /* marshal object */ hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream); if (hr != S_OK) @@ -335,10 +389,36 @@ RunningObjectTableImpl_Register(IRunningObjectTable* iface, DWORD grfFlags, return hr; } - hr = get_moniker_comparison_data(pmkObjectName, &rot_entry->moniker_data); + hr = CreateBindCtx(0, &pbc); + if (FAILED(hr)) + { + rot_entry_delete(rot_entry); + return hr; + } + + hr = reduce_moniker(pmkObjectName, pbc, &pmkObjectName); + if (FAILED(hr)) + { + rot_entry_delete(rot_entry); + IBindCtx_Release(pbc); + return hr; + } + + hr = IMoniker_GetTimeOfLastChange(pmkObjectName, pbc, NULL, + &rot_entry->last_modified); + IBindCtx_Release(pbc); + if (FAILED(hr)) + { + CoFileTimeNow(&rot_entry->last_modified); + hr = S_OK; + } + + hr = get_moniker_comparison_data(pmkObjectName, + &rot_entry->moniker_data); if (hr != S_OK) { rot_entry_delete(rot_entry); + IMoniker_Release(pmkObjectName); return hr; } @@ -346,10 +426,12 @@ RunningObjectTableImpl_Register(IRunningObjectTable* iface, DWORD grfFlags, if (hr != S_OK) { rot_entry_delete(rot_entry); + IMoniker_Release(pmkObjectName); return hr; } /* marshal moniker */ - hr = CoMarshalInterface(pStream, &IID_IMoniker, (IUnknown *)pmkObjectName, MSHCTX_LOCAL | MSHCTX_NOSHAREDMEM, NULL, MSHLFLAGS_TABLESTRONG); + hr = CoMarshalInterface(pStream, &IID_IMoniker, (IUnknown *)pmkObjectName, + MSHCTX_LOCAL | MSHCTX_NOSHAREDMEM, NULL, MSHLFLAGS_TABLESTRONG); /* FIXME: a cleaner way would be to create an IStream class that writes * directly to an MInterfacePointer */ if (hr == S_OK) @@ -367,6 +449,7 @@ RunningObjectTableImpl_Register(IRunningObjectTable* iface, DWORD grfFlags, } } IStream_Release(pStream); + IMoniker_Release(pmkObjectName); if (hr != S_OK) { rot_entry_delete(rot_entry); @@ -404,7 +487,7 @@ RunningObjectTableImpl_Revoke( IRunningObjectTable* iface, DWORD dwRegister) RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface; struct rot_entry *rot_entry; - TRACE("(%p,%ld)\n",This,dwRegister); + TRACE("(%p,%d)\n",This,dwRegister); EnterCriticalSection(&This->lock); LIST_FOR_EACH_ENTRY(rot_entry, &This->rot, struct rot_entry, entry) @@ -439,7 +522,11 @@ RunningObjectTableImpl_IsRunning( IRunningObjectTable* iface, IMoniker *pmkObjec TRACE("(%p,%p)\n",This,pmkObjectName); + hr = reduce_moniker(pmkObjectName, NULL, &pmkObjectName); + if (FAILED(hr)) + return hr; hr = get_moniker_comparison_data(pmkObjectName, &moniker_data); + IMoniker_Release(pmkObjectName); if (hr != S_OK) return hr; @@ -448,7 +535,7 @@ RunningObjectTableImpl_IsRunning( IRunningObjectTable* iface, IMoniker *pmkObjec LIST_FOR_EACH_ENTRY(rot_entry, &This->rot, struct rot_entry, entry) { if ((rot_entry->moniker_data->ulCntData == moniker_data->ulCntData) && - !memcmp(moniker_data, rot_entry->moniker_data, moniker_data->ulCntData)) + !memcmp(&moniker_data->abData, &rot_entry->moniker_data->abData, moniker_data->ulCntData)) { hr = S_OK; break; @@ -486,7 +573,11 @@ RunningObjectTableImpl_GetObject( IRunningObjectTable* iface, *ppunkObject = NULL; + hr = reduce_moniker(pmkObjectName, NULL, &pmkObjectName); + if (FAILED(hr)) + return hr; hr = get_moniker_comparison_data(pmkObjectName, &moniker_data); + IMoniker_Release(pmkObjectName); if (hr != S_OK) return hr; @@ -494,7 +585,7 @@ RunningObjectTableImpl_GetObject( IRunningObjectTable* iface, LIST_FOR_EACH_ENTRY(rot_entry, &This->rot, struct rot_entry, entry) { if ((rot_entry->moniker_data->ulCntData == moniker_data->ulCntData) && - !memcmp(moniker_data, rot_entry->moniker_data, moniker_data->ulCntData)) + !memcmp(&moniker_data->abData, &rot_entry->moniker_data->abData, moniker_data->ulCntData)) { IStream *pStream; hr = create_stream_on_mip_ro(rot_entry->object, &pStream); @@ -535,7 +626,7 @@ RunningObjectTableImpl_NoteChangeTime(IRunningObjectTable* iface, RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface; struct rot_entry *rot_entry; - TRACE("(%p,%ld,%p)\n",This,dwRegister,pfiletime); + TRACE("(%p,%d,%p)\n",This,dwRegister,pfiletime); EnterCriticalSection(&This->lock); LIST_FOR_EACH_ENTRY(rot_entry, &This->rot, struct rot_entry, entry) @@ -575,7 +666,11 @@ RunningObjectTableImpl_GetTimeOfLastChange(IRunningObjectTable* iface, if (pmkObjectName==NULL || pfiletime==NULL) return E_INVALIDARG; + hr = reduce_moniker(pmkObjectName, NULL, &pmkObjectName); + if (FAILED(hr)) + return hr; hr = get_moniker_comparison_data(pmkObjectName, &moniker_data); + IMoniker_Release(pmkObjectName); if (hr != S_OK) return hr; @@ -585,7 +680,7 @@ RunningObjectTableImpl_GetTimeOfLastChange(IRunningObjectTable* iface, LIST_FOR_EACH_ENTRY(rot_entry, &This->rot, struct rot_entry, entry) { if ((rot_entry->moniker_data->ulCntData == moniker_data->ulCntData) && - !memcmp(moniker_data, rot_entry->moniker_data, moniker_data->ulCntData)) + !memcmp(&moniker_data->abData, &rot_entry->moniker_data->abData, moniker_data->ulCntData)) { *pfiletime = rot_entry->last_modified; hr = S_OK; @@ -641,70 +736,6 @@ RunningObjectTableImpl_EnumRunning(IRunningObjectTable* iface, return hr; } -/*********************************************************************** - * GetRunningObjectTable (OLE32.@) - */ -HRESULT WINAPI -GetRunningObjectTable(DWORD reserved, LPRUNNINGOBJECTTABLE *pprot) -{ - IID riid=IID_IRunningObjectTable; - HRESULT res; - - TRACE("()\n"); - - if (reserved!=0) - return E_UNEXPECTED; - - if(runningObjectTableInstance==NULL) - return CO_E_NOTINITIALIZED; - - res = IRunningObjectTable_QueryInterface((IRunningObjectTable*)runningObjectTableInstance,&riid,(void**)pprot); - - return res; -} - -/****************************************************************************** - * OleRun [OLE32.@] - */ -HRESULT WINAPI OleRun(LPUNKNOWN pUnknown) -{ - IRunnableObject *runable; - IRunnableObject *This = (IRunnableObject *)pUnknown; - LRESULT ret; - - ret = IRunnableObject_QueryInterface(This,&IID_IRunnableObject,(LPVOID*)&runable); - if (ret) - return 0; /* Appears to return no error. */ - ret = IRunnableObject_Run(runable,NULL); - IRunnableObject_Release(runable); - return ret; -} - -/****************************************************************************** - * MkParseDisplayName [OLE32.@] - */ -HRESULT WINAPI MkParseDisplayName(LPBC pbc, LPCOLESTR szUserName, - LPDWORD pchEaten, LPMONIKER *ppmk) -{ - FIXME("(%p, %s, %p, %p): stub.\n", pbc, debugstr_w(szUserName), pchEaten, *ppmk); - - if (!(IsValidInterface((LPUNKNOWN) pbc))) - return E_INVALIDARG; - - return MK_E_SYNTAX; -} - -/****************************************************************************** - * CreateClassMoniker [OLE32.@] - */ -HRESULT WINAPI CreateClassMoniker(REFCLSID rclsid, IMoniker ** ppmk) -{ - FIXME("%s\n", debugstr_guid( rclsid )); - if( ppmk ) - *ppmk = NULL; - return E_NOTIMPL; -} - /* Virtual function table for the IRunningObjectTable class. */ static const IRunningObjectTableVtbl VT_RunningObjectTableImpl = { @@ -743,6 +774,7 @@ HRESULT WINAPI RunningObjectTableImpl_Initialize(void) list_init(&runningObjectTableInstance->rot); InitializeCriticalSection(&runningObjectTableInstance->lock); + DEBUG_SET_CRITSEC_NAME(&runningObjectTableInstance->lock, "RunningObjectTableImpl.lock"); return S_OK; } @@ -750,7 +782,7 @@ HRESULT WINAPI RunningObjectTableImpl_Initialize(void) /*********************************************************************** * RunningObjectTable_UnInitialize */ -HRESULT WINAPI RunningObjectTableImpl_UnInitialize() +HRESULT WINAPI RunningObjectTableImpl_UnInitialize(void) { TRACE("\n"); @@ -764,6 +796,265 @@ HRESULT WINAPI RunningObjectTableImpl_UnInitialize() return S_OK; } +/*********************************************************************** + * GetRunningObjectTable (OLE32.@) + * + * Retrieves the global running object table. + * + * PARAMS + * reserved [I] Reserved. Set to 0. + * pprot [O] Address that receives the pointer to the running object table. + * + * RETURNS + * Success: S_OK. + * Failure: Any HRESULT code. + */ +HRESULT WINAPI +GetRunningObjectTable(DWORD reserved, LPRUNNINGOBJECTTABLE *pprot) +{ + IID riid=IID_IRunningObjectTable; + HRESULT res; + + TRACE("()\n"); + + if (reserved!=0) + return E_UNEXPECTED; + + if(runningObjectTableInstance==NULL) + return CO_E_NOTINITIALIZED; + + res = IRunningObjectTable_QueryInterface((IRunningObjectTable*)runningObjectTableInstance,&riid,(void**)pprot); + + return res; +} + +static HRESULT get_moniker_for_progid_display_name(LPBC pbc, + LPCOLESTR szDisplayName, + LPDWORD pchEaten, + LPMONIKER *ppmk) +{ + CLSID clsid; + HRESULT hr; + LPWSTR progid; + LPCWSTR start = szDisplayName; + LPCWSTR end; + int len; + IMoniker *class_moniker; + + if (*start == '@') + start++; + + /* find end delimiter */ + for (end = start; *end; end++) + if (*end == ':') + break; + + len = end - start; + + /* must start with '@' or have a ':' somewhere and mustn't be one character + * long (since that looks like an absolute path) */ + if (((start == szDisplayName) && (*end == '\0')) || (len <= 1)) + return MK_E_SYNTAX; + + progid = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)); + if (progid) + { + memcpy(progid, start, len * sizeof(WCHAR)); + progid[len] = '\0'; + } + hr = CLSIDFromProgID(progid, &clsid); + HeapFree(GetProcessHeap(), 0, progid); + if (FAILED(hr)) + return MK_E_SYNTAX; + + hr = CreateClassMoniker(&clsid, &class_moniker); + if (SUCCEEDED(hr)) + { + IParseDisplayName *pdn; + hr = IMoniker_BindToObject(class_moniker, pbc, NULL, + &IID_IParseDisplayName, (void **)&pdn); + IMoniker_Release(class_moniker); + if (SUCCEEDED(hr)) + { + hr = IParseDisplayName_ParseDisplayName(pdn, pbc, + (LPOLESTR)szDisplayName, + pchEaten, ppmk); + IParseDisplayName_Release(pdn); + } + } + return hr; +} + +/****************************************************************************** + * MkParseDisplayName [OLE32.@] + */ +HRESULT WINAPI MkParseDisplayName(LPBC pbc, LPCOLESTR szDisplayName, + LPDWORD pchEaten, LPMONIKER *ppmk) +{ + HRESULT hr = MK_E_SYNTAX; + static const WCHAR wszClsidColon[] = {'c','l','s','i','d',':'}; + IMoniker *moniker; + DWORD chEaten; + + TRACE("(%p, %s, %p, %p)\n", pbc, debugstr_w(szDisplayName), pchEaten, ppmk); + + if (!(IsValidInterface((LPUNKNOWN) pbc))) + return E_INVALIDARG; + + *pchEaten = 0; + *ppmk = NULL; + + if (!strncmpiW(szDisplayName, wszClsidColon, sizeof(wszClsidColon)/sizeof(wszClsidColon[0]))) + { + hr = ClassMoniker_CreateFromDisplayName(pbc, szDisplayName, &chEaten, &moniker); + if (FAILED(hr) && (hr != MK_E_SYNTAX)) + return hr; + } + else + { + hr = get_moniker_for_progid_display_name(pbc, szDisplayName, &chEaten, &moniker); + if (FAILED(hr) && (hr != MK_E_SYNTAX)) + return hr; + } + + if (FAILED(hr)) + { + hr = FileMoniker_CreateFromDisplayName(pbc, szDisplayName, &chEaten, &moniker); + if (FAILED(hr) && (hr != MK_E_SYNTAX)) + return hr; + } + + if (SUCCEEDED(hr)) + { + while (TRUE) + { + IMoniker *next_moniker; + *pchEaten += chEaten; + szDisplayName += chEaten; + if (!*szDisplayName) + { + *ppmk = moniker; + return S_OK; + } + chEaten = 0; + hr = IMoniker_ParseDisplayName(moniker, pbc, NULL, + (LPOLESTR)szDisplayName, &chEaten, + &next_moniker); + IMoniker_Release(moniker); + if (FAILED(hr)) + { + *pchEaten = 0; + break; + } + moniker = next_moniker; + } + } + + return hr; +} + +/*********************************************************************** + * GetClassFile (OLE32.@) + * + * Retrieves the class ID associated with the given filename. + * + * PARAMS + * filePathName [I] Filename to retrieve the class ID for. + * pclsid [O] Address that receives the class ID for the file. + * + * RETURNS + * Success: S_OK. + * Failure: Any HRESULT code. + */ +HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid) +{ + IStorage *pstg=0; + HRESULT res; + int nbElm, length, i; + LONG sizeProgId; + LPOLESTR *pathDec=0,absFile=0,progId=0; + LPWSTR extension; + static const WCHAR bkslashW[] = {'\\',0}; + static const WCHAR dotW[] = {'.',0}; + + TRACE("%s, %p\n", debugstr_w(filePathName), pclsid); + + /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/ + if((StgIsStorageFile(filePathName))==S_OK){ + + res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg); + + if (SUCCEEDED(res)) + res=ReadClassStg(pstg,pclsid); + + IStorage_Release(pstg); + + return res; + } + /* if the file is not a storage object then attemps to match various bits in the file against a + pattern in the registry. this case is not frequently used ! so I present only the psodocode for + this case + + for(i=0;i= 0) && *(extension = &absFile[i]) != '.'; i--) + /* nothing */; + + if (!extension || !lstrcmpW(extension, dotW)) + return MK_E_INVALIDEXTENSION; + + res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId); + + /* get the progId associated to the extension */ + progId = CoTaskMemAlloc(sizeProgId); + res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId); + + if (res==ERROR_SUCCESS) + /* return the clsid associated to the progId */ + res= CLSIDFromProgID(progId,pclsid); + + for(i=0; pathDec[i]!=NULL;i++) + CoTaskMemFree(pathDec[i]); + CoTaskMemFree(pathDec); + + CoTaskMemFree(progId); + + if (res==ERROR_SUCCESS) + return res; + + return MK_E_INVALIDEXTENSION; +} + /*********************************************************************** * EnumMoniker_QueryInterface */ @@ -817,7 +1108,7 @@ static ULONG WINAPI EnumMonikerImpl_Release(IEnumMoniker* iface) ref = InterlockedDecrement(&This->ref); - /* unitialize rot structure if there's no more reference to it*/ + /* uninitialize rot structure if there's no more reference to it*/ if (ref == 0) { ULONG i; @@ -841,7 +1132,7 @@ static HRESULT WINAPI EnumMonikerImpl_Next(IEnumMoniker* iface, ULONG celt, IM EnumMonikerImpl *This = (EnumMonikerImpl *)iface; HRESULT hr = S_OK; - TRACE("(%p) TabCurrentPos %ld Tablastindx %ld\n", This, This->pos, This->moniker_count); + TRACE("(%p) TabCurrentPos %d Tablastindx %d\n", This, This->pos, This->moniker_count); /* retrieve the requested number of moniker from the current position */ for(i = 0; (This->pos < This->moniker_count) && (i < celt); i++) @@ -1046,7 +1337,7 @@ static HRESULT WINAPI MonikerMarshal_GetUnmarshalClass( { MonikerMarshal *This = impl_from_IMarshal(iface); - TRACE("(%s, %p, %lx, %p, %lx, %p)\n", debugstr_guid(riid), pv, + TRACE("(%s, %p, %x, %p, %x, %p)\n", debugstr_guid(riid), pv, dwDestContext, pvDestContext, mshlflags, pCid); return IMoniker_GetClassID(This->moniker, pCid); @@ -1060,7 +1351,7 @@ static HRESULT WINAPI MonikerMarshal_GetMarshalSizeMax( HRESULT hr; ULARGE_INTEGER size; - TRACE("(%s, %p, %lx, %p, %lx, %p)\n", debugstr_guid(riid), pv, + TRACE("(%s, %p, %x, %p, %x, %p)\n", debugstr_guid(riid), pv, dwDestContext, pvDestContext, mshlflags, pSize); hr = IMoniker_GetSizeMax(This->moniker, &size); @@ -1075,7 +1366,7 @@ static HRESULT WINAPI MonikerMarshal_MarshalInterface(LPMARSHAL iface, IStream * { MonikerMarshal *This = impl_from_IMarshal(iface); - TRACE("(%p, %s, %p, %lx, %p, %lx)\n", pStm, debugstr_guid(riid), pv, + TRACE("(%p, %s, %p, %x, %p, %x)\n", pStm, debugstr_guid(riid), pv, dwDestContext, pvDestContext, mshlflags); return IMoniker_Save(This->moniker, pStm, FALSE); diff --git a/reactos/dll/win32/ole32/moniker.h b/reactos/dll/win32/ole32/moniker.h index 4c64b9b13ce..d3ce652105d 100644 --- a/reactos/dll/win32/ole32/moniker.h +++ b/reactos/dll/win32/ole32/moniker.h @@ -1,12 +1,47 @@ +/* + * Monikers + * + * Copyright 1998 Marcus Meissner + * Copyright 1999 Noomen Hamza + * Copyright 2005 Robert Shearman (for CodeWeavers) + * + * 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 + */ + #ifndef __WINE_MONIKER_H__ #define __WINE_MONIKER_H__ -extern const CLSID CLSID_FileMoniker; -extern const CLSID CLSID_ItemMoniker; -extern const CLSID CLSID_AntiMoniker; +DEFINE_OLEGUID( CLSID_FileMoniker, 0x303, 0, 0 ); +DEFINE_OLEGUID( CLSID_ItemMoniker, 0x304, 0, 0 ); +DEFINE_OLEGUID( CLSID_AntiMoniker, 0x305, 0, 0 ); +DEFINE_OLEGUID( CLSID_CompositeMoniker, 0x309, 0, 0 ); +DEFINE_OLEGUID( CLSID_ClassMoniker, 0x31a, 0, 0 ); HRESULT FileMonikerCF_Create(REFIID riid, LPVOID *ppv); HRESULT ItemMonikerCF_Create(REFIID riid, LPVOID *ppv); +HRESULT AntiMonikerCF_Create(REFIID riid, LPVOID *ppv); +HRESULT CompositeMonikerCF_Create(REFIID riid, LPVOID *ppv); +HRESULT ClassMonikerCF_Create(REFIID riid, LPVOID *ppv); + +/* This function decomposes a String path to a String Table containing all the elements ("\" or "subDirectory" or "Directory" or "FileName") of the path */ +int FileMonikerImpl_DecomposePath(LPCOLESTR str, LPOLESTR** stringTable); + +HRESULT FileMoniker_CreateFromDisplayName(LPBC pbc, LPCOLESTR szDisplayName, + LPDWORD pchEaten, LPMONIKER *ppmk); +HRESULT ClassMoniker_CreateFromDisplayName(LPBC pbc, LPCOLESTR szDisplayName, + LPDWORD pchEaten, LPMONIKER *ppmk); HRESULT MonikerMarshal_Create(IMoniker *inner, IUnknown **outer); diff --git a/reactos/dll/win32/ole32/ole16.c b/reactos/dll/win32/ole32/ole16.c index 117d484a5ec..d9c2202a118 100644 --- a/reactos/dll/win32/ole32/ole16.c +++ b/reactos/dll/win32/ole32/ole16.c @@ -19,7 +19,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" @@ -69,7 +69,7 @@ typedef struct /****************************************************************************** * IMalloc16_QueryInterface [COMPOBJ.500] */ -HRESULT IMalloc16_fnQueryInterface(IMalloc16* iface,REFIID refiid,LPVOID *obj) { +HRESULT CDECL IMalloc16_fnQueryInterface(IMalloc16* iface,REFIID refiid,LPVOID *obj) { IMalloc16Impl *This = (IMalloc16Impl *)iface; TRACE("(%p)->QueryInterface(%s,%p)\n",This,debugstr_guid(refiid),obj); @@ -85,7 +85,7 @@ HRESULT IMalloc16_fnQueryInterface(IMalloc16* iface,REFIID refiid,LPVOID *obj) { /****************************************************************************** * IMalloc16_AddRef [COMPOBJ.501] */ -ULONG IMalloc16_fnAddRef(IMalloc16* iface) { +ULONG CDECL IMalloc16_fnAddRef(IMalloc16* iface) { IMalloc16Impl *This = (IMalloc16Impl *)iface; TRACE("(%p)->AddRef()\n",This); return 1; /* cannot be freed */ @@ -94,7 +94,7 @@ ULONG IMalloc16_fnAddRef(IMalloc16* iface) { /****************************************************************************** * IMalloc16_Release [COMPOBJ.502] */ -ULONG IMalloc16_fnRelease(IMalloc16* iface) { +ULONG CDECL IMalloc16_fnRelease(IMalloc16* iface) { IMalloc16Impl *This = (IMalloc16Impl *)iface; TRACE("(%p)->Release()\n",This); return 1; /* cannot be freed */ @@ -103,20 +103,20 @@ ULONG IMalloc16_fnRelease(IMalloc16* iface) { /****************************************************************************** * IMalloc16_Alloc [COMPOBJ.503] */ -SEGPTR IMalloc16_fnAlloc(IMalloc16* iface,DWORD cb) { +SEGPTR CDECL IMalloc16_fnAlloc(IMalloc16* iface,DWORD cb) { IMalloc16Impl *This = (IMalloc16Impl *)iface; - TRACE("(%p)->Alloc(%ld)\n",This,cb); + TRACE("(%p)->Alloc(%d)\n",This,cb); return MapLS( HeapAlloc( GetProcessHeap(), 0, cb ) ); } /****************************************************************************** * IMalloc16_Free [COMPOBJ.505] */ -VOID IMalloc16_fnFree(IMalloc16* iface,SEGPTR pv) +VOID CDECL IMalloc16_fnFree(IMalloc16* iface,SEGPTR pv) { void *ptr = MapSL(pv); IMalloc16Impl *This = (IMalloc16Impl *)iface; - TRACE("(%p)->Free(%08lx)\n",This,pv); + TRACE("(%p)->Free(%08x)\n",This,pv); UnMapLS(pv); HeapFree( GetProcessHeap(), 0, ptr ); } @@ -124,11 +124,11 @@ VOID IMalloc16_fnFree(IMalloc16* iface,SEGPTR pv) /****************************************************************************** * IMalloc16_Realloc [COMPOBJ.504] */ -SEGPTR IMalloc16_fnRealloc(IMalloc16* iface,SEGPTR pv,DWORD cb) +SEGPTR CDECL IMalloc16_fnRealloc(IMalloc16* iface,SEGPTR pv,DWORD cb) { SEGPTR ret; IMalloc16Impl *This = (IMalloc16Impl *)iface; - TRACE("(%p)->Realloc(%08lx,%ld)\n",This,pv,cb); + TRACE("(%p)->Realloc(%08x,%d)\n",This,pv,cb); if (!pv) ret = IMalloc16_fnAlloc(iface, cb); else if (cb) { @@ -144,17 +144,17 @@ SEGPTR IMalloc16_fnRealloc(IMalloc16* iface,SEGPTR pv,DWORD cb) /****************************************************************************** * IMalloc16_GetSize [COMPOBJ.506] */ -DWORD IMalloc16_fnGetSize(IMalloc16* iface,SEGPTR pv) +DWORD CDECL IMalloc16_fnGetSize(IMalloc16* iface,SEGPTR pv) { IMalloc16Impl *This = (IMalloc16Impl *)iface; - TRACE("(%p)->GetSize(%08lx)\n",This,pv); + TRACE("(%p)->GetSize(%08x)\n",This,pv); return HeapSize( GetProcessHeap(), 0, MapSL(pv) ); } /****************************************************************************** * IMalloc16_DidAlloc [COMPOBJ.507] */ -INT16 IMalloc16_fnDidAlloc(IMalloc16* iface,LPVOID pv) { +INT16 CDECL IMalloc16_fnDidAlloc(IMalloc16* iface,LPVOID pv) { IMalloc16 *This = (IMalloc16 *)iface; TRACE("(%p)->DidAlloc(%p)\n",This,pv); return (INT16)-1; @@ -163,7 +163,7 @@ INT16 IMalloc16_fnDidAlloc(IMalloc16* iface,LPVOID pv) { /****************************************************************************** * IMalloc16_HeapMinimize [COMPOBJ.508] */ -LPVOID IMalloc16_fnHeapMinimize(IMalloc16* iface) { +LPVOID CDECL IMalloc16_fnHeapMinimize(IMalloc16* iface) { IMalloc16Impl *This = (IMalloc16Impl *)iface; TRACE("(%p)->HeapMinimize()\n",This); return NULL; @@ -284,8 +284,62 @@ HRESULT WINAPI CLSIDFromString16( LPCOLESTR16 idstr, /* [in] string representation of guid */ CLSID *id) /* [out] GUID converted from string */ { + const BYTE *s; + int i; + BYTE table[256]; - return __CLSIDFromStringA(idstr,id); + if (!idstr) { + memset( id, 0, sizeof (CLSID) ); + return S_OK; + } + + /* validate the CLSID string */ + if (strlen(idstr) != 38) + return CO_E_CLASSSTRING; + + s = (const BYTE *) idstr; + if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}')) + return CO_E_CLASSSTRING; + + for (i=1; i<37; i++) { + if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue; + if (!(((s[i] >= '0') && (s[i] <= '9')) || + ((s[i] >= 'a') && (s[i] <= 'f')) || + ((s[i] >= 'A') && (s[i] <= 'F')))) + return CO_E_CLASSSTRING; + } + + TRACE("%s -> %p\n", s, id); + + /* quick lookup table */ + memset(table, 0, 256); + + for (i = 0; i < 10; i++) { + table['0' + i] = i; + } + for (i = 0; i < 6; i++) { + table['A' + i] = i+10; + table['a' + i] = i+10; + } + + /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */ + + id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 | + table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]); + id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]]; + id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]]; + + /* these are just sequential bytes */ + id->Data4[0] = table[s[20]] << 4 | table[s[21]]; + id->Data4[1] = table[s[22]] << 4 | table[s[23]]; + id->Data4[2] = table[s[25]] << 4 | table[s[26]]; + id->Data4[3] = table[s[27]] << 4 | table[s[28]]; + id->Data4[4] = table[s[29]] << 4 | table[s[30]]; + id->Data4[5] = table[s[31]] << 4 | table[s[32]]; + id->Data4[6] = table[s[33]] << 4 | table[s[34]]; + id->Data4[7] = table[s[35]] << 4 | table[s[36]]; + + return S_OK; } /****************************************************************************** @@ -317,7 +371,7 @@ _xmalloc16(DWORD size, SEGPTR *ptr) { (LPVOID)args, (LPDWORD)ptr )) { - ERR("CallTo16 IMalloc16 (%ld) failed\n",size); + ERR("CallTo16 IMalloc16 (%d) failed\n",size); return E_FAIL; } return S_OK; @@ -429,7 +483,7 @@ HRESULT WINAPI CoRegisterClassObject16( DWORD flags, /* [in] REGCLS flags indicating how connections are made */ LPDWORD lpdwRegister ) { - FIXME("(%s,%p,0x%08lx,0x%08lx,%p),stub\n", + FIXME("(%s,%p,0x%08x,0x%08x,%p),stub\n", debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister ); return 0; @@ -441,7 +495,7 @@ HRESULT WINAPI CoRegisterClassObject16( */ HRESULT WINAPI CoRevokeClassObject16(DWORD dwRegister) /* [in] token on class obj */ { - FIXME("(0x%08lx),stub!\n", dwRegister); + FIXME("(0x%08x),stub!\n", dwRegister); return 0; } @@ -504,7 +558,7 @@ HRESULT WINAPI CoGetState16(LPDWORD state) */ BOOL WINAPI COMPOBJ_DllEntryPoint(DWORD Reason, HINSTANCE16 hInst, WORD ds, WORD HeapSize, DWORD res1, WORD res2) { - TRACE("(%08lx, %04x, %04x, %04x, %08lx, %04x)\n", Reason, hInst, ds, HeapSize, res1, res2); + TRACE("(%08x, %04x, %04x, %04x, %08x, %04x)\n", Reason, hInst, ds, HeapSize, res1, res2); return TRUE; } @@ -516,7 +570,7 @@ SEGPTR WINAPI CoMemAlloc(DWORD size, DWORD dwMemContext, DWORD x) { SEGPTR segptr; /* FIXME: check context handling */ - TRACE("(%ld, 0x%08lx, 0x%08lx)\n", size, dwMemContext, x); + TRACE("(%d, 0x%08x, 0x%08x)\n", size, dwMemContext, x); hres = _xmalloc16(size, &segptr); if (hres != S_OK) return (SEGPTR)0; @@ -556,7 +610,7 @@ HRESULT WINAPI CLSIDFromProgID16(LPCOLESTR16 progid, LPCLSID riid) return CO_E_CLASSSTRING; } RegCloseKey(xhkey); - return __CLSIDFromStringA(buf2,riid); + return CLSIDFromString16(buf2,riid); } /*********************************************************************** @@ -586,13 +640,22 @@ HRESULT WINAPI CoCreateInstance16( REFIID iid, LPVOID *ppv) { - FIXME("(%s, %p, %lx, %s, %p), stub!\n", + FIXME("(%s, %p, %x, %s, %p), stub!\n", debugstr_guid(rclsid), pUnkOuter, dwClsContext, debugstr_guid(iid), ppv ); return E_NOTIMPL; } +/*********************************************************************** + * CoDisconnectObject [COMPOBJ.15] + */ +HRESULT WINAPI CoDisconnectObject16( LPUNKNOWN lpUnk, DWORD reserved ) +{ + FIXME("(%p, 0x%08x): stub!\n", lpUnk, reserved); + return E_NOTIMPL; +} + /*********************************************************************** * DllGetClassObject [OLE2.4] */ @@ -608,6 +671,6 @@ HRESULT WINAPI DllGetClassObject16(REFCLSID rclsid, REFIID iid, LPVOID *ppv) HRESULT WINAPI GetRunningObjectTable16(DWORD reserved, LPRUNNINGOBJECTTABLE *pprot) { - FIXME("(%ld,%p),stub!\n",reserved,pprot); + FIXME("(%d,%p),stub!\n",reserved,pprot); return E_NOTIMPL; } diff --git a/reactos/dll/win32/ole32/ole2.c b/reactos/dll/win32/ole32/ole2.c index fd55930203a..908eb09d1d8 100644 --- a/reactos/dll/win32/ole32/ole2.c +++ b/reactos/dll/win32/ole32/ole2.c @@ -19,7 +19,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" @@ -48,6 +48,7 @@ #include "wine/unicode.h" #include "compobj_private.h" +#include "wine/list.h" #include "wine/debug.h" @@ -61,9 +62,8 @@ WINE_DECLARE_DEBUG_CHANNEL(accel); typedef struct tagDropTargetNode { HWND hwndTarget; - IDropTarget* dropTarget; - struct tagDropTargetNode* prevDropTarget; - struct tagDropTargetNode* nextDropTarget; + IDropTarget* dropTarget; + struct list entry; } DropTargetNode; typedef struct tagTrackerWindowInfo @@ -107,7 +107,7 @@ static OleMenuHookItem *hook_list; * This is the lock count on the OLE library. It is controlled by the * OLEInitialize/OLEUninitialize methods. */ -static ULONG OLE_moduleLockCount = 0; +static LONG OLE_moduleLockCount = 0; /* * Name of our registered window class. @@ -117,7 +117,7 @@ static const char OLEDD_DRAGTRACKERCLASS[] = "WineDragDropTracker32"; /* * This is the head of the Drop target container. */ -static DropTargetNode* targetListHead = NULL; +static struct list targetListHead = LIST_INIT(targetListHead); /****************************************************************************** * These are the prototypes of miscelaneous utility methods @@ -129,13 +129,13 @@ static void OLEUTL_ReadRegistryDWORDValue(HKEY regKey, DWORD* pdwValue); */ static void OLEMenu_Initialize(void); static void OLEMenu_UnInitialize(void); -BOOL OLEMenu_InstallHooks( DWORD tid ); -BOOL OLEMenu_UnInstallHooks( DWORD tid ); -OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid ); +static BOOL OLEMenu_InstallHooks( DWORD tid ); +static BOOL OLEMenu_UnInstallHooks( DWORD tid ); +static OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid ); static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos ); -BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor ); -LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam); -LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam); +static BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor ); +static LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam); +static LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam); /****************************************************************************** * These are the prototypes of the OLE Clipboard initialization methods (in clipboard.c) @@ -147,13 +147,9 @@ extern void OLEClipbrd_Initialize(void); * These are the prototypes of the utility methods used for OLE Drag n Drop */ static void OLEDD_Initialize(void); -static void OLEDD_UnInitialize(void); -static void OLEDD_InsertDropTarget( - DropTargetNode* nodeToAdd); -static DropTargetNode* OLEDD_ExtractDropTarget( - HWND hwndOfTarget); static DropTargetNode* OLEDD_FindDropTarget( HWND hwndOfTarget); +static void OLEDD_FreeDropTarget(DropTargetNode*); static LRESULT WINAPI OLEDD_DragTrackerWindowProc( HWND hwnd, UINT uMsg, @@ -206,7 +202,8 @@ HRESULT WINAPI OleInitialize(LPVOID reserved) * Object linking and Embedding * In-place activation */ - if (OLE_moduleLockCount==0) + if (!COM_CurrentInfo()->ole_inits++ && + InterlockedIncrement(&OLE_moduleLockCount) == 1) { /* * Initialize the libraries. @@ -229,11 +226,6 @@ HRESULT WINAPI OleInitialize(LPVOID reserved) OLEMenu_Initialize(); } - /* - * Then, we increase the lock count on the OLE module. - */ - OLE_moduleLockCount++; - return hr; } @@ -245,15 +237,10 @@ void WINAPI OleUninitialize(void) { TRACE("()\n"); - /* - * Decrease the lock count on the OLE module. - */ - OLE_moduleLockCount--; - /* * If we hit the bottom of the lock stack, free the libraries. */ - if (OLE_moduleLockCount==0) + if (!--COM_CurrentInfo()->ole_inits && !InterlockedDecrement(&OLE_moduleLockCount)) { /* * Actually free the libraries. @@ -265,11 +252,6 @@ void WINAPI OleUninitialize(void) */ OLEClipbrd_UnInitialize(); - /* - * Drag and Drop - */ - OLEDD_UnInitialize(); - /* * OLE shared menu */ @@ -286,7 +268,7 @@ void WINAPI OleUninitialize(void) * OleInitializeWOW [OLE32.@] */ HRESULT WINAPI OleInitializeWOW(DWORD x, DWORD y) { - FIXME("(0x%08lx, 0x%08lx),stub!\n",x, y); + FIXME("(0x%08x, 0x%08x),stub!\n",x, y); return 0; } @@ -301,9 +283,21 @@ HRESULT WINAPI RegisterDragDrop( TRACE("(%p,%p)\n", hwnd, pDropTarget); + if (!COM_CurrentApt()) + { + ERR("COM not initialized\n"); + return CO_E_NOTINITIALIZED; + } + if (!pDropTarget) return E_INVALIDARG; - + + if (!IsWindow(hwnd)) + { + ERR("invalid hwnd %p\n", hwnd); + return DRAGDROP_E_INVALIDHWND; + } + /* * First, check if the window is already registered. */ @@ -321,19 +315,17 @@ HRESULT WINAPI RegisterDragDrop( return E_OUTOFMEMORY; dropTargetInfo->hwndTarget = hwnd; - dropTargetInfo->prevDropTarget = NULL; - dropTargetInfo->nextDropTarget = NULL; /* * Don't forget that this is an interface pointer, need to nail it down since * we keep a copy of it. */ + IDropTarget_AddRef(pDropTarget); dropTargetInfo->dropTarget = pDropTarget; - IDropTarget_AddRef(dropTargetInfo->dropTarget); - OLEDD_InsertDropTarget(dropTargetInfo); + list_add_tail(&targetListHead, &dropTargetInfo->entry); - return S_OK; + return S_OK; } /*********************************************************************** @@ -346,10 +338,16 @@ HRESULT WINAPI RevokeDragDrop( TRACE("(%p)\n", hwnd); + if (!IsWindow(hwnd)) + { + ERR("invalid hwnd %p\n", hwnd); + return DRAGDROP_E_INVALIDHWND; + } + /* * First, check if the window is already registered. */ - dropTargetInfo = OLEDD_ExtractDropTarget(hwnd); + dropTargetInfo = OLEDD_FindDropTarget(hwnd); /* * If it ain't in there, it's an error. @@ -357,14 +355,9 @@ HRESULT WINAPI RevokeDragDrop( if (dropTargetInfo==NULL) return DRAGDROP_E_NOTREGISTERED; - /* - * If it's in there, clean-up it's used memory and - * references - */ - IDropTarget_Release(dropTargetInfo->dropTarget); - HeapFree(GetProcessHeap(), 0, dropTargetInfo); + OLEDD_FreeDropTarget(dropTargetInfo); - return S_OK; + return S_OK; } /*********************************************************************** @@ -395,12 +388,12 @@ HRESULT WINAPI OleRegGetUserType( /* * Build the key name we're looking for */ - sprintf( keyName, "CLSID\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\", + sprintf( keyName, "CLSID\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\", clsid->Data1, clsid->Data2, clsid->Data3, clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3], clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] ); - TRACE("(%s, %ld, %p)\n", keyName, dwFormOfType, pszUserType); + TRACE("(%s, %d, %p)\n", keyName, dwFormOfType, pszUserType); /* * Open the class id Key @@ -526,6 +519,8 @@ HRESULT WINAPI DoDragDrop ( */ SetCapture(hwndTrackWindow); + msg.message = 0; + /* * Pump messages. All mouse input should go the the capture window. */ @@ -564,6 +559,9 @@ HRESULT WINAPI DoDragDrop ( } } + /* re-post the quit message to outer message loop */ + if (msg.message == WM_QUIT) + PostQuitMessage(msg.wParam); /* * Destroy the temporary window. */ @@ -607,12 +605,12 @@ HRESULT WINAPI OleRegGetMiscStatus( /* * Build the key name we're looking for */ - sprintf( keyName, "CLSID\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\", + sprintf( keyName, "CLSID\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\", clsid->Data1, clsid->Data2, clsid->Data3, clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3], clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] ); - TRACE("(%s, %ld, %p)\n", keyName, dwAspect, pdwStatus); + TRACE("(%s, %d, %p)\n", keyName, dwAspect, pdwStatus); /* * Open the class id Key @@ -646,7 +644,7 @@ HRESULT WINAPI OleRegGetMiscStatus( /* * Open the key specific to the requested aspect. */ - sprintf(keyName, "%ld", dwAspect); + sprintf(keyName, "%d", dwAspect); result = RegOpenKeyA(miscStatusKey, keyName, @@ -721,7 +719,7 @@ static HRESULT WINAPI EnumOLEVERB_Next( EnumOLEVERB *This = (EnumOLEVERB *)iface; HRESULT hr = S_OK; - TRACE("(%ld, %p, %p)\n", celt, rgelt, pceltFetched); + TRACE("(%d, %p, %p)\n", celt, rgelt, pceltFetched); if (pceltFetched) *pceltFetched = 0; @@ -741,14 +739,14 @@ static HRESULT WINAPI EnumOLEVERB_Next( } else if (res != ERROR_SUCCESS) { - ERR("RegEnumKeyW failed with error %ld\n", res); + ERR("RegEnumKeyW failed with error %d\n", res); hr = REGDB_E_READREGDB; break; } res = RegQueryValueW(This->hkeyVerb, wszSubKey, NULL, &cbData); if (res != ERROR_SUCCESS) { - ERR("RegQueryValueW failed with error %ld\n", res); + ERR("RegQueryValueW failed with error %d\n", res); hr = REGDB_E_READREGDB; break; } @@ -761,7 +759,7 @@ static HRESULT WINAPI EnumOLEVERB_Next( res = RegQueryValueW(This->hkeyVerb, wszSubKey, pwszOLEVERB, &cbData); if (res != ERROR_SUCCESS) { - ERR("RegQueryValueW failed with error %ld\n", res); + ERR("RegQueryValueW failed with error %d\n", res); hr = REGDB_E_READREGDB; CoTaskMemFree(pwszOLEVERB); break; @@ -796,7 +794,7 @@ static HRESULT WINAPI EnumOLEVERB_Next( rgelt->grfAttribs = atolW(pwszAttribs); if (pceltFetched) - *pceltFetched++; + (*pceltFetched)++; This->index++; } return hr; @@ -807,7 +805,7 @@ static HRESULT WINAPI EnumOLEVERB_Skip( { EnumOLEVERB *This = (EnumOLEVERB *)iface; - TRACE("(%ld)\n", celt); + TRACE("(%d)\n", celt); This->index += celt; return S_OK; @@ -896,7 +894,7 @@ HRESULT WINAPI OleRegEnumVerbs (REFCLSID clsid, LPENUMOLEVERB* ppenum) else if (res == REGDB_E_KEYMISSING) ERR("no Verbs key for class %s\n", debugstr_guid(clsid)); else - ERR("failed to open Verbs key for CLSID %s with error %ld\n", + ERR("failed to open Verbs key for CLSID %s with error %d\n", debugstr_guid(clsid), res); return res; } @@ -905,7 +903,7 @@ HRESULT WINAPI OleRegEnumVerbs (REFCLSID clsid, LPENUMOLEVERB* ppenum) NULL, NULL, NULL, NULL, NULL, NULL); if (res != ERROR_SUCCESS) { - ERR("failed to get subkey count with error %ld\n", GetLastError()); + ERR("failed to get subkey count with error %d\n", GetLastError()); return REGDB_E_READREGDB; } @@ -929,7 +927,7 @@ HRESULT WINAPI OleSetContainedObject( IRunnableObject* runnable = NULL; HRESULT hres; - TRACE("(%p,%x), stub!\n", pUnknown, fContained); + TRACE("(%p,%x)\n", pUnknown, fContained); hres = IUnknown_QueryInterface(pUnknown, &IID_IRunnableObject, @@ -947,6 +945,34 @@ HRESULT WINAPI OleSetContainedObject( return S_OK; } +/****************************************************************************** + * OleRun [OLE32.@] + * + * Set the OLE object to the running state. + * + * PARAMS + * pUnknown [I] OLE object to run. + * + * RETURNS + * Success: S_OK. + * Failure: Any HRESULT code. + */ +HRESULT WINAPI OleRun(LPUNKNOWN pUnknown) +{ + IRunnableObject *runable; + HRESULT hres; + + TRACE("(%p)\n", pUnknown); + + hres = IUnknown_QueryInterface(pUnknown, &IID_IRunnableObject, (void**)&runable); + if (FAILED(hres)) + return S_OK; /* Appears to return no error. */ + + hres = IRunnableObject_Run(runable, NULL); + IRunnableObject_Release(runable); + return hres; +} + /****************************************************************************** * OleLoad [OLE32.@] */ @@ -957,11 +983,14 @@ HRESULT WINAPI OleLoad( LPVOID* ppvObj) { IPersistStorage* persistStorage = NULL; - IOleObject* oleObject = NULL; + IUnknown* pUnk; + IOleObject* pOleObject = NULL; STATSTG storageInfo; HRESULT hres; - TRACE("(%p,%p,%p,%p)\n", pStg, riid, pClientSite, ppvObj); + TRACE("(%p, %s, %p, %p)\n", pStg, debugstr_guid(riid), pClientSite, ppvObj); + + *ppvObj = NULL; /* * TODO, Conversion ... OleDoAutoConvert @@ -977,9 +1006,9 @@ HRESULT WINAPI OleLoad( */ hres = CoCreateInstance(&storageInfo.clsid, NULL, - CLSCTX_INPROC_HANDLER, - &IID_IOleObject, - (void**)&oleObject); + CLSCTX_INPROC_HANDLER|CLSCTX_INPROC_SERVER, + riid, + (void**)&pUnk); /* * If that fails, as it will most times, load the default @@ -989,8 +1018,8 @@ HRESULT WINAPI OleLoad( { hres = OleCreateDefaultHandler(&storageInfo.clsid, NULL, - &IID_IOleObject, - (void**)&oleObject); + riid, + (void**)&pUnk); } /* @@ -999,35 +1028,63 @@ HRESULT WINAPI OleLoad( if (FAILED(hres)) return hres; - /* - * Inform the new object of it's client site. - */ - hres = IOleObject_SetClientSite(oleObject, pClientSite); + if (pClientSite) + { + hres = IUnknown_QueryInterface(pUnk, &IID_IOleObject, (void **)&pOleObject); + if (SUCCEEDED(hres)) + { + DWORD dwStatus; + hres = IOleObject_GetMiscStatus(pOleObject, DVASPECT_CONTENT, &dwStatus); + } + } - /* - * Initialize the object with it's IPersistStorage interface. - */ - hres = IOleObject_QueryInterface(oleObject, - &IID_IPersistStorage, - (void**)&persistStorage); + if (SUCCEEDED(hres)) + /* + * Initialize the object with it's IPersistStorage interface. + */ + hres = IOleObject_QueryInterface(pUnk, + &IID_IPersistStorage, + (void**)&persistStorage); if (SUCCEEDED(hres)) { - IPersistStorage_Load(persistStorage, pStg); + hres = IPersistStorage_Load(persistStorage, pStg); IPersistStorage_Release(persistStorage); persistStorage = NULL; } - /* - * Return the requested interface to the caller. - */ - hres = IOleObject_QueryInterface(oleObject, riid, ppvObj); + if (SUCCEEDED(hres) && pClientSite) + /* + * Inform the new object of it's client site. + */ + hres = IOleObject_SetClientSite(pOleObject, pClientSite); /* * Cleanup interfaces used internally */ - IOleObject_Release(oleObject); + if (pOleObject) + IOleObject_Release(pOleObject); + + if (SUCCEEDED(hres)) + { + IOleLink *pOleLink; + HRESULT hres1; + hres1 = IUnknown_QueryInterface(pUnk, &IID_IOleLink, (void **)&pOleLink); + if (SUCCEEDED(hres1)) + { + FIXME("handle OLE link\n"); + IOleLink_Release(pOleLink); + } + } + + if (FAILED(hres)) + { + IUnknown_Release(pUnk); + pUnk = NULL; + } + + *ppvObj = pUnk; return hres; } @@ -1108,7 +1165,7 @@ HRESULT WINAPI OleLockRunning(LPUNKNOWN pUnknown, BOOL fLock, BOOL fLastUnlockCl * * Initializes the OLEMENU data structures. */ -static void OLEMenu_Initialize() +static void OLEMenu_Initialize(void) { } @@ -1117,7 +1174,7 @@ static void OLEMenu_Initialize() * * Releases the OLEMENU data structures. */ -static void OLEMenu_UnInitialize() +static void OLEMenu_UnInitialize(void) { } @@ -1128,7 +1185,7 @@ static void OLEMenu_UnInitialize() * RETURNS: TRUE if message hooks were successfully installed * FALSE on failure */ -BOOL OLEMenu_InstallHooks( DWORD tid ) +static BOOL OLEMenu_InstallHooks( DWORD tid ) { OleMenuHookItem *pHookItem = NULL; @@ -1177,7 +1234,7 @@ CLEANUP: * RETURNS: TRUE if message hooks were successfully installed * FALSE on failure */ -BOOL OLEMenu_UnInstallHooks( DWORD tid ) +static BOOL OLEMenu_UnInstallHooks( DWORD tid ) { OleMenuHookItem *pHookItem = NULL; OleMenuHookItem **ppHook = &hook_list; @@ -1219,7 +1276,7 @@ CLEANUP: * RETURNS: The pointer and index of the hook table entry for the tid * NULL and -1 for the index if no hooks were installed for this thread */ -OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid ) +static OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid ) { OleMenuHookItem *pHookItem = NULL; @@ -1285,7 +1342,7 @@ static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT * * RETURNS: TRUE if the popup menu is part of a server owned group * FALSE if the popup menu is part of a container owned group */ -BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor ) +static BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor ) { UINT nPos = 0, nWidth, i; @@ -1324,7 +1381,7 @@ BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor * Thread scope WH_CALLWNDPROC hook proc filter function (callback) * This is invoked from a message hook installed in OleSetMenuDescriptor. */ -LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam) +static LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam) { LPCWPSTRUCT pMsg = NULL; HOLEMENU hOleMenu = 0; @@ -1429,7 +1486,7 @@ NEXTHOOK: * Thread scope WH_GETMESSAGE hook proc filter function (callback) * This is invoked from a message hook installed in OleSetMenuDescriptor. */ -LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam) +static LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam) { LPMSG pMsg = NULL; HOLEMENU hOleMenu = 0; @@ -1819,7 +1876,7 @@ void WINAPI ReleaseStgMedium( * * Initializes the OLE drag and drop data structures. */ -static void OLEDD_Initialize() +static void OLEDD_Initialize(void) { WNDCLASSA wndClass; @@ -1835,151 +1892,36 @@ static void OLEDD_Initialize() RegisterClassA (&wndClass); } +/*** + * OLEDD_FreeDropTarget() + * + * Frees the drag and drop data structure + */ +static void OLEDD_FreeDropTarget(DropTargetNode *dropTargetInfo) +{ + list_remove(&dropTargetInfo->entry); + IDropTarget_Release(dropTargetInfo->dropTarget); + HeapFree(GetProcessHeap(), 0, dropTargetInfo); +} + /*** * OLEDD_UnInitialize() * * Releases the OLE drag and drop data structures. */ -static void OLEDD_UnInitialize() +void OLEDD_UnInitialize(void) { /* * Simply empty the list. */ - while (targetListHead!=NULL) + while (!list_empty(&targetListHead)) { - RevokeDragDrop(targetListHead->hwndTarget); + DropTargetNode* curNode; + curNode = LIST_ENTRY(list_head(&targetListHead), DropTargetNode, entry); + OLEDD_FreeDropTarget(curNode); } } -/*** - * OLEDD_InsertDropTarget() - * - * Insert the target node in the tree. - */ -static void OLEDD_InsertDropTarget(DropTargetNode* nodeToAdd) -{ - DropTargetNode* curNode; - DropTargetNode** parentNodeLink; - - /* - * Iterate the tree to find the insertion point. - */ - curNode = targetListHead; - parentNodeLink = &targetListHead; - - while (curNode!=NULL) - { - if (nodeToAdd->hwndTargethwndTarget) - { - /* - * If the node we want to add has a smaller HWND, go left - */ - parentNodeLink = &curNode->prevDropTarget; - curNode = curNode->prevDropTarget; - } - else if (nodeToAdd->hwndTarget>curNode->hwndTarget) - { - /* - * If the node we want to add has a larger HWND, go right - */ - parentNodeLink = &curNode->nextDropTarget; - curNode = curNode->nextDropTarget; - } - else - { - /* - * The item was found in the list. It shouldn't have been there - */ - assert(FALSE); - return; - } - } - - /* - * If we get here, we have found a spot for our item. The parentNodeLink - * pointer points to the pointer that we have to modify. - * The curNode should be NULL. We just have to establish the link and Voila! - */ - assert(curNode==NULL); - assert(parentNodeLink!=NULL); - assert(*parentNodeLink==NULL); - - *parentNodeLink=nodeToAdd; -} - -/*** - * OLEDD_ExtractDropTarget() - * - * Removes the target node from the tree. - */ -static DropTargetNode* OLEDD_ExtractDropTarget(HWND hwndOfTarget) -{ - DropTargetNode* curNode; - DropTargetNode** parentNodeLink; - - /* - * Iterate the tree to find the insertion point. - */ - curNode = targetListHead; - parentNodeLink = &targetListHead; - - while (curNode!=NULL) - { - if (hwndOfTargethwndTarget) - { - /* - * If the node we want to add has a smaller HWND, go left - */ - parentNodeLink = &curNode->prevDropTarget; - curNode = curNode->prevDropTarget; - } - else if (hwndOfTarget>curNode->hwndTarget) - { - /* - * If the node we want to add has a larger HWND, go right - */ - parentNodeLink = &curNode->nextDropTarget; - curNode = curNode->nextDropTarget; - } - else - { - /* - * The item was found in the list. Detach it from it's parent and - * re-insert it's kids in the tree. - */ - assert(parentNodeLink!=NULL); - assert(*parentNodeLink==curNode); - - /* - * We arbitrately re-attach the left sub-tree to the parent. - */ - *parentNodeLink = curNode->prevDropTarget; - - /* - * And we re-insert the right subtree - */ - if (curNode->nextDropTarget!=NULL) - { - OLEDD_InsertDropTarget(curNode->nextDropTarget); - } - - /* - * The node we found is still a valid node once we complete - * the unlinking of the kids. - */ - curNode->nextDropTarget=NULL; - curNode->prevDropTarget=NULL; - - return curNode; - } - } - - /* - * If we get here, the node is not in the tree - */ - return NULL; -} - /*** * OLEDD_FindDropTarget() * @@ -1990,34 +1932,11 @@ static DropTargetNode* OLEDD_FindDropTarget(HWND hwndOfTarget) DropTargetNode* curNode; /* - * Iterate the tree to find the HWND value. + * Iterate the list to find the HWND value. */ - curNode = targetListHead; - - while (curNode!=NULL) - { - if (hwndOfTargethwndTarget) - { - /* - * If the node we want to add has a smaller HWND, go left - */ - curNode = curNode->prevDropTarget; - } - else if (hwndOfTarget>curNode->hwndTarget) - { - /* - * If the node we want to add has a larger HWND, go right - */ - curNode = curNode->nextDropTarget; - } - else - { - /* - * The item was found in the list. - */ + LIST_FOR_EACH_ENTRY(curNode, &targetListHead, DropTargetNode, entry) + if (hwndOfTarget==curNode->hwndTarget) return curNode; - } - } /* * If we get here, the item is not in the list @@ -2303,7 +2222,7 @@ static void OLEDD_TrackStateChange(TrackerWindowInfo* trackerInfo) * a button state mask equivalent to the one passed in the * WM_MOUSEMOVE wParam. */ -static DWORD OLEDD_GetButtonState() +static DWORD OLEDD_GetButtonState(void) { BYTE keyboardState[256]; DWORD keyMask = 0; @@ -2442,40 +2361,115 @@ HRESULT WINAPI OleCreate( LPSTORAGE pStg, LPVOID* ppvObj) { - HRESULT hres, hres1; + HRESULT hres; IUnknown * pUnk = NULL; + IOleObject *pOleObject = NULL; - FIXME("\n\t%s\n\t%s semi-stub!\n", debugstr_guid(rclsid), debugstr_guid(riid)); + TRACE("(%s, %s, %d, %p, %p, %p, %p)\n", debugstr_guid(rclsid), + debugstr_guid(riid), renderopt, pFormatEtc, pClientSite, pStg, ppvObj); - if (SUCCEEDED((hres = CoCreateInstance(rclsid, 0, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER|CLSCTX_LOCAL_SERVER , riid, (LPVOID*)&pUnk)))) + hres = CoCreateInstance(rclsid, 0, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, riid, (LPVOID*)&pUnk); + + if (SUCCEEDED(hres)) + hres = IStorage_SetClass(pStg, rclsid); + + if (pClientSite && SUCCEEDED(hres)) { - if (pClientSite) + hres = IUnknown_QueryInterface(pUnk, &IID_IOleObject, (LPVOID*)&pOleObject); + if (SUCCEEDED(hres)) { - IOleObject * pOE; - IPersistStorage * pPS; - if (SUCCEEDED((hres = IUnknown_QueryInterface( pUnk, &IID_IOleObject, (LPVOID*)&pOE)))) + DWORD dwStatus; + hres = IOleObject_GetMiscStatus(pOleObject, DVASPECT_CONTENT, &dwStatus); + } + } + + if (SUCCEEDED(hres)) + { + IPersistStorage * pPS; + if (SUCCEEDED((hres = IUnknown_QueryInterface(pUnk, &IID_IPersistStorage, (LPVOID*)&pPS)))) + { + TRACE("trying to set stg %p\n", pStg); + hres = IPersistStorage_InitNew(pPS, pStg); + TRACE("-- result 0x%08x\n", hres); + IPersistStorage_Release(pPS); + } + } + + if (pClientSite && SUCCEEDED(hres)) + { + TRACE("trying to set clientsite %p\n", pClientSite); + hres = IOleObject_SetClientSite(pOleObject, pClientSite); + TRACE("-- result 0x%08x\n", hres); + } + + if (pOleObject) + IOleObject_Release(pOleObject); + + if (((renderopt == OLERENDER_DRAW) || (renderopt == OLERENDER_FORMAT)) && + SUCCEEDED(hres)) + { + IRunnableObject *pRunnable; + IOleCache *pOleCache; + HRESULT hres2; + + hres2 = IUnknown_QueryInterface(pUnk, &IID_IRunnableObject, (void **)&pRunnable); + if (SUCCEEDED(hres2)) + { + hres = IRunnableObject_Run(pRunnable, NULL); + IRunnableObject_Release(pRunnable); + } + + if (SUCCEEDED(hres)) + { + hres2 = IUnknown_QueryInterface(pUnk, &IID_IOleCache, (void **)&pOleCache); + if (SUCCEEDED(hres2)) { - TRACE("trying to set clientsite %p\n", pClientSite); - hres1 = IOleObject_SetClientSite(pOE, pClientSite); - TRACE("-- result 0x%08lx\n", hres1); - IOleObject_Release(pOE); - } - if (SUCCEEDED((hres = IUnknown_QueryInterface( pUnk, &IID_IPersistStorage, (LPVOID*)&pPS)))) - { - TRACE("trying to set stg %p\n", pStg); - hres1 = IPersistStorage_InitNew(pPS, pStg); - TRACE("-- result 0x%08lx\n", hres1); - IPersistStorage_Release(pPS); + DWORD dwConnection; + hres = IOleCache_Cache(pOleCache, pFormatEtc, ADVF_PRIMEFIRST, &dwConnection); + IOleCache_Release(pOleCache); } } } + if (FAILED(hres) && pUnk) + { + IUnknown_Release(pUnk); + pUnk = NULL; + } + *ppvObj = pUnk; TRACE("-- %p\n", pUnk); return hres; } +/****************************************************************************** + * OleGetAutoConvert [OLE32.@] + */ +HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew) +{ + static const WCHAR wszAutoConvertTo[] = {'A','u','t','o','C','o','n','v','e','r','t','T','o',0}; + HKEY hkey = NULL; + WCHAR buf[CHARS_IN_GUID]; + LONG len; + HRESULT res = S_OK; + + res = COM_OpenKeyForCLSID(clsidOld, wszAutoConvertTo, KEY_READ, &hkey); + if (FAILED(res)) + goto done; + + len = sizeof(buf); + if (RegQueryValueW(hkey, NULL, buf, &len)) + { + res = REGDB_E_KEYMISSING; + goto done; + } + res = CLSIDFromString(buf, pClsidNew); +done: + if (hkey) RegCloseKey(hkey); + return res; +} + /****************************************************************************** * OleSetAutoConvert [OLE32.@] */ @@ -2531,6 +2525,16 @@ BOOL WINAPI OleIsRunning(LPOLEOBJECT pObject) return running; } +/*********************************************************************** + * OleNoteObjectVisible [OLE32.@] + */ +HRESULT WINAPI OleNoteObjectVisible(LPUNKNOWN pUnknown, BOOL bVisible) +{ + TRACE("(%p, %s)\n", pUnknown, bVisible ? "TRUE" : "FALSE"); + return CoLockObjectExternal(pUnknown, bVisible, TRUE); +} + + /*********************************************************************** * OLE_FreeClipDataArray [internal] * @@ -2561,13 +2565,13 @@ BSTR WINAPI PropSysAllocString(LPCOLESTR str) len = lstrlenW(str); /* - * Find the length of the buffer passed-in in bytes. + * Find the length of the buffer passed-in, in bytes. */ bufferSize = len * sizeof (WCHAR); /* * Allocate a new buffer to hold the string. - * don't forget to keep an empty spot at the beginning of the + * Don't forget to keep an empty spot at the beginning of the * buffer for the character count and an extra character at the * end for the NULL. */ @@ -2590,15 +2594,7 @@ BSTR WINAPI PropSysAllocString(LPCOLESTR str) */ newBuffer++; - /* - * Copy the information in the buffer. - * Since it is valid to pass a NULL pointer here, we'll initialize the - * buffer to nul if it is the case. - */ - if (str != 0) - memcpy(newBuffer, str, bufferSize); - else - memset(newBuffer, 0, bufferSize); + memcpy(newBuffer, str, bufferSize); /* * Make sure that there is a nul character at the end of the @@ -2715,6 +2711,23 @@ HRESULT WINAPI PropVariantClear(PROPVARIANT * pvar) /* [in/out] */ switch(pvar->vt) { + case VT_EMPTY: + case VT_NULL: + case VT_I2: + case VT_I4: + case VT_R4: + case VT_R8: + case VT_CY: + case VT_DATE: + case VT_ERROR: + case VT_BOOL: + case VT_UI1: + case VT_UI2: + case VT_UI4: + case VT_I8: + case VT_UI8: + case VT_FILETIME: + break; case VT_STREAM: case VT_STREAMED_OBJECT: case VT_STORAGE: @@ -2737,7 +2750,7 @@ HRESULT WINAPI PropVariantClear(PROPVARIANT * pvar) /* [in/out] */ if (pvar->u.bstrVal) PropSysFreeString(pvar->u.bstrVal); break; - case VT_CF: + case VT_CF: if (pvar->u.pclipdata) { OLE_FreeClipDataArray(1, pvar->u.pclipdata); @@ -2806,6 +2819,8 @@ HRESULT WINAPI PropVariantCopy(PROPVARIANT *pvarDest, /* [out] */ switch(pvarSrc->vt) { + case VT_FILETIME: + break; case VT_STREAM: case VT_STREAMED_OBJECT: case VT_STORAGE: @@ -2842,7 +2857,10 @@ HRESULT WINAPI PropVariantCopy(PROPVARIANT *pvarDest, /* [out] */ if (pvarSrc->u.pclipdata) { len = pvarSrc->u.pclipdata->cbSize - sizeof(pvarSrc->u.pclipdata->ulClipFmt); - CoTaskMemAlloc(len); + pvarDest->u.pclipdata = CoTaskMemAlloc(sizeof (CLIPDATA)); + pvarDest->u.pclipdata->cbSize = pvarSrc->u.pclipdata->cbSize; + pvarDest->u.pclipdata->ulClipFmt = pvarSrc->u.pclipdata->ulClipFmt; + pvarDest->u.pclipdata->pClipData = CoTaskMemAlloc(len); CopyMemory(pvarDest->u.pclipdata->pClipData, pvarSrc->u.pclipdata->pClipData, len); } break; @@ -2937,7 +2955,10 @@ HRESULT WINAPI FreePropVariantArray(ULONG cVariants, /* [in] */ { ULONG i; - TRACE("(%lu, %p)\n", cVariants, rgvars); + TRACE("(%u, %p)\n", cVariants, rgvars); + + if (!rgvars) + return E_INVALIDARG; for(i = 0; i < cVariants; i++) PropVariantClear(&rgvars[i]); diff --git a/reactos/dll/win32/ole32/ole2_16.c b/reactos/dll/win32/ole32/ole2_16.c index 12599002332..20e9725a14b 100644 --- a/reactos/dll/win32/ole32/ole2_16.c +++ b/reactos/dll/win32/ole32/ole2_16.c @@ -18,7 +18,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" @@ -120,7 +120,7 @@ HGLOBAL16 WINAPI OleMetaFilePictFromIconAndLabel16( mf16 = (METAFILEPICT16 *)GlobalLock16(hmf16); mf16->mm = MM_ANISOTROPIC; mf16->xExt = 20; /* FIXME: bogus */ - mf16->yExt = 20; /* dito */ + mf16->yExt = 20; /* ditto */ mfSize = GetMetaFileBitsEx(hmf, 0, 0); mf16->hMF = GlobalAlloc16(GMEM_MOVEABLE, mfSize); if(mf16->hMF) @@ -154,9 +154,12 @@ HRESULT WINAPI CreateFileMoniker16(LPCOLESTR16 lpszPathName,LPMONIKER* ppmk) /****************************************************************************** * OleSetMenuDescriptor (OLE2.41) + * + * PARAMS + * hOleMenu FIXME: Should probably be an HOLEMENU16. */ HRESULT WINAPI OleSetMenuDescriptor16( - HOLEMENU hOleMenu, /* FIXME: HOLEMENU16 likely */ + HOLEMENU hOleMenu, HWND16 hwndFrame, HWND16 hwndActiveObject, LPOLEINPLACEFRAME lpFrame, @@ -205,7 +208,7 @@ HRESULT WINAPI OleLoad16( SEGPTR pClientSite, LPVOID* ppvObj) { - FIXME("(%lx,%s,%lx,%p), stub!\n", pStg, debugstr_guid(riid), pClientSite, ppvObj); + FIXME("(%x,%s,%x,%p), stub!\n", pStg, debugstr_guid(riid), pClientSite, ppvObj); return E_NOTIMPL; } diff --git a/reactos/dll/win32/ole32/ole2impl.c b/reactos/dll/win32/ole32/ole2impl.c index b939623e470..f123fe9c9c4 100644 --- a/reactos/dll/win32/ole32/ole2impl.c +++ b/reactos/dll/win32/ole32/ole2impl.c @@ -15,7 +15,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include diff --git a/reactos/dll/win32/ole32/ole2nls.c b/reactos/dll/win32/ole32/ole2nls.c index c30807e0c27..9851d707d2c 100644 --- a/reactos/dll/win32/ole32/ole2nls.c +++ b/reactos/dll/win32/ole32/ole2nls.c @@ -17,7 +17,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" diff --git a/reactos/dll/win32/ole32/ole2stubs.c b/reactos/dll/win32/ole32/ole2stubs.c index 9eca37ab216..e3396516564 100644 --- a/reactos/dll/win32/ole32/ole2stubs.c +++ b/reactos/dll/win32/ole32/ole2stubs.c @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #define NONAMELESSUNION @@ -39,7 +39,7 @@ HRESULT WINAPI OleCreateLinkToFile(LPCOLESTR lpszFileName, REFIID riid, DWORD renderopt, LPFORMATETC lpFormatEtc, LPOLECLIENTSITE pClientSite, LPSTORAGE pStg, LPVOID* ppvObj) { - FIXME("(%p,%p,%li,%p,%p,%p,%p), stub!\n",lpszFileName, riid, renderopt, lpFormatEtc, pClientSite, pStg, ppvObj); + FIXME("(%p,%p,%i,%p,%p,%p,%p), stub!\n",lpszFileName, riid, renderopt, lpFormatEtc, pClientSite, pStg, ppvObj); return E_NOTIMPL; } @@ -115,7 +115,7 @@ HRESULT WINAPI OleRegEnumFormatEtc ( DWORD dwDirection, LPENUMFORMATETC* ppenumFormatetc) { - FIXME("(%p, %ld, %p), stub!\n", clsid, dwDirection, ppenumFormatetc); + FIXME("(%p, %d, %p), stub!\n", clsid, dwDirection, ppenumFormatetc); return E_NOTIMPL; } diff --git a/reactos/dll/win32/ole32/ole32.rbuild b/reactos/dll/win32/ole32/ole32.rbuild index 82740c8cc30..a178b681825 100644 --- a/reactos/dll/win32/ole32/ole32.rbuild +++ b/reactos/dll/win32/ole32/ole32.rbuild @@ -4,27 +4,29 @@ . include/reactos/wine + 0x600 0x501 0x501 - wine - uuid - ntdll - kernel32 advapi32 - gdi32 user32 + gdi32 rpcrt4 + kernel32 + ntdll + uuid antimoniker.c bindctx.c + classmoniker.c clipboard.c compobj.c compositemoniker.c datacache.c - dictionary.c defaulthandler.c + dictionary.c + enumx.c errorinfo.c filemoniker.c ftmarshal.c @@ -50,5 +52,6 @@ stubmanager.c usrmarshal.c ole32res.rc + dcom.idl ole32.spec diff --git a/reactos/dll/win32/ole32/ole32.spec b/reactos/dll/win32/ole32/ole32.spec index 26f7c6fa1fb..3ae0240bd3e 100644 --- a/reactos/dll/win32/ole32/ole32.spec +++ b/reactos/dll/win32/ole32/ole32.spec @@ -20,7 +20,7 @@ @ stdcall CoFreeAllLibraries() @ stdcall CoFreeLibrary(long) @ stdcall CoFreeUnusedLibraries() -@ stub CoGetCallContext #@ stdcall (ptr ptr) return 0,ERR_NOTIMPLEMENTED +@ stdcall CoGetCallContext(ptr ptr) @ stub CoGetCallerTID @ stdcall CoGetClassObject(ptr long ptr ptr ptr) @ stub CoGetCurrentLogicalThreadId @@ -30,13 +30,13 @@ @ stdcall CoGetInterfaceAndReleaseStream(ptr ptr ptr) @ stdcall CoGetMalloc(long ptr) @ stdcall CoGetMarshalSizeMax(ptr ptr ptr long ptr long) -@ stub CoGetObject +@ stdcall CoGetObject(wstr ptr ptr ptr) @ stdcall CoGetPSClsid(ptr ptr) @ stdcall CoGetStandardMarshal(ptr ptr long ptr long ptr) @ stdcall CoGetState(ptr) @ stub CoGetTIDFromIPID @ stdcall CoGetTreatAsClass(ptr ptr) -@ stub CoImpersonateClient +@ stdcall CoImpersonateClient() @ stdcall CoInitialize(ptr) @ stdcall CoInitializeEx(ptr long) @ stdcall CoInitializeSecurity(ptr long ptr ptr long long ptr long ptr) @@ -49,19 +49,19 @@ @ stdcall CoMarshalInterThreadInterfaceInStream(ptr ptr ptr) @ stdcall CoMarshalInterface(ptr ptr ptr long ptr long) @ stub CoQueryAuthenticationServices -@ stub CoQueryClientBlanket +@ stdcall CoQueryClientBlanket(ptr ptr ptr ptr ptr ptr ptr) @ stdcall CoQueryProxyBlanket(ptr ptr ptr ptr ptr ptr ptr ptr) @ stub CoQueryReleaseObject -@ stub CoRegisterChannelHook +@ stdcall CoRegisterChannelHook(ptr ptr) @ stdcall CoRegisterClassObject(ptr ptr long long ptr) @ stdcall CoRegisterMallocSpy (ptr) @ stdcall CoRegisterMessageFilter(ptr ptr) -@ stub CoRegisterPSClsid #@ stdcall (ptr ptr) return 0,ERR_NOTIMPLEMENTED +@ stdcall CoRegisterPSClsid(ptr ptr) @ stub CoRegisterSurrogate @ stdcall CoReleaseMarshalData(ptr) @ stdcall CoReleaseServerProcess() @ stdcall CoResumeClassObjects() -@ stub CoRevertToSelf #@ stdcall () return 0,ERR_NOTIMPLEMENTED +@ stdcall CoRevertToSelf() @ stdcall CoRevokeClassObject(long) @ stdcall CoRevokeMallocSpy() @ stdcall CoSetProxyBlanket(ptr long long wstr long long ptr long) @@ -76,6 +76,7 @@ @ stub CoUnloadingWOW @ stdcall CoUnmarshalHresult(ptr ptr) @ stdcall CoUnmarshalInterface(ptr ptr ptr) +@ stdcall CoWaitForMultipleHandles(long long long ptr ptr) @ stdcall CreateAntiMoniker(ptr) @ stdcall CreateBindCtx(long ptr) @ stdcall CreateClassMoniker(ptr ptr) @@ -135,14 +136,14 @@ @ stdcall HMENU_UserMarshal(ptr ptr ptr) @ stdcall HMENU_UserSize(ptr long ptr) @ stdcall HMENU_UserUnmarshal(ptr ptr ptr) -@ stub HMETAFILEPICT_UserFree -@ stub HMETAFILEPICT_UserMarshal -@ stub HMETAFILEPICT_UserSize -@ stub HMETAFILEPICT_UserUnmarshal -@ stub HMETAFILE_UserFree -@ stub HMETAFILE_UserMarshal -@ stub HMETAFILE_UserSize -@ stub HMETAFILE_UserUnmarshal +@ stdcall HMETAFILEPICT_UserFree(ptr ptr) +@ stdcall HMETAFILEPICT_UserMarshal(ptr ptr ptr) +@ stdcall HMETAFILEPICT_UserSize(ptr long ptr) +@ stdcall HMETAFILEPICT_UserUnmarshal(ptr ptr ptr) +@ stdcall HMETAFILE_UserFree(ptr ptr) +@ stdcall HMETAFILE_UserMarshal(ptr ptr ptr) +@ stdcall HMETAFILE_UserSize(ptr long ptr) +@ stdcall HMETAFILE_UserUnmarshal(ptr ptr ptr) @ stdcall HPALETTE_UserFree(ptr ptr) @ stdcall HPALETTE_UserMarshal(ptr ptr ptr) @ stdcall HPALETTE_UserSize(ptr long ptr) @@ -200,7 +201,7 @@ @ stdcall OleLoadFromStream(ptr ptr ptr) @ stdcall OleLockRunning(ptr long long) @ stdcall OleMetafilePictFromIconAndLabel(long ptr ptr long) -@ stub OleNoteObjectVisible +@ stdcall OleNoteObjectVisible(ptr long) @ stdcall OleQueryCreateFromData(ptr) @ stdcall OleQueryLinkFromData(ptr) @ stdcall OleRegEnumFormatEtc(ptr long ptr) diff --git a/reactos/dll/win32/ole32/ole32_main.c b/reactos/dll/win32/ole32/ole32_main.c index 4a133822527..328a972dda6 100644 --- a/reactos/dll/win32/ole32/ole32_main.c +++ b/reactos/dll/win32/ole32/ole32_main.c @@ -15,7 +15,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include @@ -32,6 +32,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole); +#define HIMETRIC_INCHES 2540 + /*********************************************************************** * OleMetafilePictFromIconAndLabel (OLE32.@) */ @@ -40,27 +42,70 @@ HGLOBAL WINAPI OleMetafilePictFromIconAndLabel(HICON hIcon, LPOLESTR lpszLabel, { METAFILEPICT mfp; HDC hdc; - UINT dy; HGLOBAL hmem = NULL; LPVOID mfdata; static const char szIconOnly[] = "IconOnly"; + SIZE text_size = { 0, 0 }; + INT width; + INT icon_width; + INT icon_height; + INT label_offset; + HDC hdcScreen; + LOGFONTW lf; + HFONT font; TRACE("%p %p %s %d\n", hIcon, lpszLabel, debugstr_w(lpszSourceFile), iIconIndex); if( !hIcon ) return NULL; + if (!SystemParametersInfoW(SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, 0)) + return NULL; + + font = CreateFontIndirectW(&lf); + if (!font) + return NULL; + hdc = CreateMetaFileW(NULL); if( !hdc ) + { + DeleteObject(font); return NULL; + } + + SelectObject(hdc, font); ExtEscape(hdc, MFCOMMENT, sizeof(szIconOnly), szIconOnly, 0, NULL); - /* FIXME: things are drawn in the wrong place */ - DrawIcon(hdc, 0, 0, hIcon); - dy = GetSystemMetrics(SM_CXICON); + icon_width = GetSystemMetrics(SM_CXICON); + icon_height = GetSystemMetrics(SM_CYICON); + /* FIXME: should we give the label a bit of padding here? */ + label_offset = icon_height; + if (lpszLabel) + { + HFONT screen_old_font; + /* metafile DCs don't support GetTextExtentPoint32, so size the font + * using the desktop window DC */ + hdcScreen = GetDC(NULL); + screen_old_font = SelectObject(hdcScreen, font); + GetTextExtentPoint32W(hdcScreen, lpszLabel, lstrlenW(lpszLabel), &text_size); + SelectObject(hdcScreen, screen_old_font); + ReleaseDC(NULL, hdcScreen); + + width = 3 * icon_width; + } + else + width = icon_width; + + SetMapMode(hdc, MM_ANISOTROPIC); + SetWindowOrgEx(hdc, 0, 0, NULL); + SetWindowExtEx(hdc, width, label_offset + text_size.cy, NULL); + + /* draw the icon centred */ + DrawIcon(hdc, (width-icon_width) / 2, 0, hIcon); if(lpszLabel) - TextOutW(hdc, 0, dy, lpszLabel, lstrlenW(lpszLabel)); + /* draw the label centred too, if provided */ + TextOutW(hdc, (width-text_size.cx) / 2, label_offset, lpszLabel, lstrlenW(lpszLabel)); if (lpszSourceFile) { @@ -80,9 +125,13 @@ HGLOBAL WINAPI OleMetafilePictFromIconAndLabel(HICON hIcon, LPOLESTR lpszLabel, ExtEscape(hdc, MFCOMMENT, strlen(szIconIndex)+1, szIconIndex, 0, NULL); } - mfp.mm = MM_ISOTROPIC; - mfp.xExt = mfp.yExt = 0; /* FIXME ? */ + mfp.mm = MM_ANISOTROPIC; + hdcScreen = GetDC(NULL); + mfp.xExt = MulDiv(width, HIMETRIC_INCHES, GetDeviceCaps(hdcScreen, LOGPIXELSX)); + mfp.yExt = MulDiv(label_offset + text_size.cy, HIMETRIC_INCHES, GetDeviceCaps(hdcScreen, LOGPIXELSY)); + ReleaseDC(NULL, hdcScreen); mfp.hMF = CloseMetaFile(hdc); + DeleteObject(font); if( !mfp.hMF ) return NULL; diff --git a/reactos/dll/win32/ole32/ole32_ros.diff b/reactos/dll/win32/ole32/ole32_ros.diff new file mode 100644 index 00000000000..091e7aad98b --- /dev/null +++ b/reactos/dll/win32/ole32/ole32_ros.diff @@ -0,0 +1,12 @@ +Index: rpc.c +=================================================================== +--- rpc.c (revision 23782) ++++ rpc.c (working copy) +@@ -24,6 +24,7 @@ + #include "wine/port.h" + + #include ++#include + #include + + #define COBJMACROS diff --git a/reactos/dll/win32/ole32/ole32res.rc b/reactos/dll/win32/ole32/ole32res.rc index 06156decc47..35173640a17 100644 --- a/reactos/dll/win32/ole32/ole32res.rc +++ b/reactos/dll/win32/ole32/ole32res.rc @@ -15,7 +15,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "windef.h" diff --git a/reactos/dll/win32/ole32/oleobj.c b/reactos/dll/win32/ole32/oleobj.c index 3943aec6b88..1c887977ac5 100644 --- a/reactos/dll/win32/ole32/oleobj.c +++ b/reactos/dll/win32/ole32/oleobj.c @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ @@ -50,6 +50,156 @@ typedef struct OleAdviseHolderImpl } OleAdviseHolderImpl; +static HRESULT EnumOleSTATDATA_Construct(OleAdviseHolderImpl *pOleAdviseHolder, ULONG index, IEnumSTATDATA **ppenum); + +typedef struct +{ + const IEnumSTATDATAVtbl *lpvtbl; + LONG ref; + + ULONG index; + OleAdviseHolderImpl *pOleAdviseHolder; +} EnumOleSTATDATA; + +static HRESULT WINAPI EnumOleSTATDATA_QueryInterface( + IEnumSTATDATA *iface, REFIID riid, void **ppv) +{ + TRACE("(%s, %p)\n", debugstr_guid(riid), ppv); + if (IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid, &IID_IEnumSTATDATA)) + { + IUnknown_AddRef(iface); + *ppv = iface; + return S_OK; + } + return E_NOINTERFACE; +} + +static ULONG WINAPI EnumOleSTATDATA_AddRef( + IEnumSTATDATA *iface) +{ + EnumOleSTATDATA *This = (EnumOleSTATDATA *)iface; + TRACE("()\n"); + return InterlockedIncrement(&This->ref); +} + +static ULONG WINAPI EnumOleSTATDATA_Release( + IEnumSTATDATA *iface) +{ + EnumOleSTATDATA *This = (EnumOleSTATDATA *)iface; + LONG refs = InterlockedDecrement(&This->ref); + TRACE("()\n"); + if (!refs) + { + IOleAdviseHolder_Release((IOleAdviseHolder *)This->pOleAdviseHolder); + HeapFree(GetProcessHeap(), 0, This); + } + return refs; +} + +static HRESULT WINAPI EnumOleSTATDATA_Next( + IEnumSTATDATA *iface, ULONG celt, LPSTATDATA rgelt, + ULONG *pceltFetched) +{ + EnumOleSTATDATA *This = (EnumOleSTATDATA *)iface; + HRESULT hr = S_OK; + + TRACE("(%d, %p, %p)\n", celt, rgelt, pceltFetched); + + if (pceltFetched) + *pceltFetched = 0; + + for (; celt; celt--, rgelt++) + { + while ((This->index < This->pOleAdviseHolder->maxSinks) && + !This->pOleAdviseHolder->arrayOfSinks[This->index]) + { + This->index++; + } + if (This->index >= This->pOleAdviseHolder->maxSinks) + { + hr = S_FALSE; + break; + } + + memset(&rgelt->formatetc, 0, sizeof(rgelt->formatetc)); + rgelt->advf = 0; + rgelt->pAdvSink = This->pOleAdviseHolder->arrayOfSinks[This->index]; + IAdviseSink_AddRef(rgelt->pAdvSink); + rgelt->dwConnection = This->index; + + if (pceltFetched) + (*pceltFetched)++; + This->index++; + } + return hr; +} + +static HRESULT WINAPI EnumOleSTATDATA_Skip( + IEnumSTATDATA *iface, ULONG celt) +{ + EnumOleSTATDATA *This = (EnumOleSTATDATA *)iface; + + TRACE("(%d)\n", celt); + + for (; celt; celt--) + { + while ((This->index < This->pOleAdviseHolder->maxSinks) && + !This->pOleAdviseHolder->arrayOfSinks[This->index]) + { + This->index++; + } + if (This->index >= This->pOleAdviseHolder->maxSinks) + return S_FALSE; + This->index++; + } + return S_OK; +} + +static HRESULT WINAPI EnumOleSTATDATA_Reset( + IEnumSTATDATA *iface) +{ + EnumOleSTATDATA *This = (EnumOleSTATDATA *)iface; + + TRACE("()\n"); + + This->index = 0; + return S_OK; +} + +static HRESULT WINAPI EnumOleSTATDATA_Clone( + IEnumSTATDATA *iface, + IEnumSTATDATA **ppenum) +{ + EnumOleSTATDATA *This = (EnumOleSTATDATA *)iface; + return EnumOleSTATDATA_Construct(This->pOleAdviseHolder, This->index, ppenum); +} + +static const IEnumSTATDATAVtbl EnumOleSTATDATA_VTable = +{ + EnumOleSTATDATA_QueryInterface, + EnumOleSTATDATA_AddRef, + EnumOleSTATDATA_Release, + EnumOleSTATDATA_Next, + EnumOleSTATDATA_Skip, + EnumOleSTATDATA_Reset, + EnumOleSTATDATA_Clone +}; + +static HRESULT EnumOleSTATDATA_Construct(OleAdviseHolderImpl *pOleAdviseHolder, ULONG index, IEnumSTATDATA **ppenum) +{ + EnumOleSTATDATA *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); + if (!This) + return E_OUTOFMEMORY; + This->lpvtbl = &EnumOleSTATDATA_VTable; + This->ref = 1; + This->index = index; + This->pOleAdviseHolder = pOleAdviseHolder; + IOleAdviseHolder_AddRef((IOleAdviseHolder *)pOleAdviseHolder); + *ppenum = (IEnumSTATDATA *)&This->lpvtbl; + return S_OK; +} + /************************************************************************** * OleAdviseHolderImpl_Destructor */ @@ -127,7 +277,7 @@ static ULONG WINAPI OleAdviseHolderImpl_AddRef( OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface; ULONG ref = InterlockedIncrement(&This->ref); - TRACE("(%p)->(ref=%ld)\n", This, ref - 1); + TRACE("(%p)->(ref=%d)\n", This, ref - 1); return ref; } @@ -140,7 +290,7 @@ static ULONG WINAPI OleAdviseHolderImpl_Release( { OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface; ULONG ref; - TRACE("(%p)->(ref=%ld)\n", This, This->ref); + TRACE("(%p)->(ref=%d)\n", This, This->ref); ref = InterlockedDecrement(&This->ref); if (ref == 0) OleAdviseHolderImpl_Destructor(This); @@ -224,7 +374,7 @@ static HRESULT WINAPI OleAdviseHolderImpl_Unadvise( { OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface; - TRACE("(%p)->(%lu)\n", This, dwConnection); + TRACE("(%p)->(%u)\n", This, dwConnection); /* * So we don't return 0 as a cookie, the index was @@ -258,11 +408,12 @@ static HRESULT WINAPI OleAdviseHolderImpl_EnumAdvise (LPOLEADVISEHOLDER iface, IEnumSTATDATA **ppenumAdvise) { OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface; - FIXME("(%p)->(%p)\n", This, ppenumAdvise); + + TRACE("(%p)->(%p)\n", This, ppenumAdvise); *ppenumAdvise = NULL; - return S_OK; + return EnumOleSTATDATA_Construct(This, 0, ppenumAdvise); } /****************************************************************************** @@ -271,11 +422,25 @@ OleAdviseHolderImpl_EnumAdvise (LPOLEADVISEHOLDER iface, IEnumSTATDATA **ppenumA static HRESULT WINAPI OleAdviseHolderImpl_SendOnRename (LPOLEADVISEHOLDER iface, IMoniker *pmk) { - OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface; - FIXME("(%p)->(%p)\n", This, pmk); + IEnumSTATDATA *pEnum; + HRESULT hr; + TRACE("(%p)->(%p)\n", iface, pmk); - return S_OK; + hr = IOleAdviseHolder_EnumAdvise(iface, &pEnum); + if (SUCCEEDED(hr)) + { + STATDATA statdata; + while (IEnumSTATDATA_Next(pEnum, 1, &statdata, NULL) == S_OK) + { + IAdviseSink_OnRename(statdata.pAdvSink, pmk); + + IAdviseSink_Release(statdata.pAdvSink); + } + IEnumSTATDATA_Release(pEnum); + } + + return hr; } /****************************************************************************** @@ -284,10 +449,25 @@ OleAdviseHolderImpl_SendOnRename (LPOLEADVISEHOLDER iface, IMoniker *pmk) static HRESULT WINAPI OleAdviseHolderImpl_SendOnSave (LPOLEADVISEHOLDER iface) { - OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface; - FIXME("(%p)\n", This); + IEnumSTATDATA *pEnum; + HRESULT hr; - return S_OK; + TRACE("(%p)->()\n", iface); + + hr = IOleAdviseHolder_EnumAdvise(iface, &pEnum); + if (SUCCEEDED(hr)) + { + STATDATA statdata; + while (IEnumSTATDATA_Next(pEnum, 1, &statdata, NULL) == S_OK) + { + IAdviseSink_OnSave(statdata.pAdvSink); + + IAdviseSink_Release(statdata.pAdvSink); + } + IEnumSTATDATA_Release(pEnum); + } + + return hr; } /****************************************************************************** @@ -296,11 +476,25 @@ OleAdviseHolderImpl_SendOnSave (LPOLEADVISEHOLDER iface) static HRESULT WINAPI OleAdviseHolderImpl_SendOnClose (LPOLEADVISEHOLDER iface) { - OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface; - FIXME("(%p)\n", This); + IEnumSTATDATA *pEnum; + HRESULT hr; + TRACE("(%p)->()\n", iface); - return S_OK; + hr = IOleAdviseHolder_EnumAdvise(iface, &pEnum); + if (SUCCEEDED(hr)) + { + STATDATA statdata; + while (IEnumSTATDATA_Next(pEnum, 1, &statdata, NULL) == S_OK) + { + IAdviseSink_OnClose(statdata.pAdvSink); + + IAdviseSink_Release(statdata.pAdvSink); + } + IEnumSTATDATA_Release(pEnum); + } + + return hr; } /************************************************************************** @@ -361,6 +555,7 @@ typedef struct DataAdviseHolder LONG ref; DWORD maxCons; DataAdviseConnection* Connections; + IDataObject* delegate; } DataAdviseHolder; /* this connection has also has been advised to the delegate data object */ @@ -378,6 +573,11 @@ static void DataAdviseHolder_Destructor(DataAdviseHolder* ptrToDestroy) { if (ptrToDestroy->Connections[index].sink != NULL) { + if (ptrToDestroy->delegate && + (ptrToDestroy->Connections[index].advf & WINE_ADVF_REMOTE)) + IDataObject_DUnadvise(ptrToDestroy->delegate, + ptrToDestroy->Connections[index].remote_connection); + IAdviseSink_Release(ptrToDestroy->Connections[index].sink); ptrToDestroy->Connections[index].sink = NULL; } @@ -445,7 +645,7 @@ static ULONG WINAPI DataAdviseHolder_AddRef( IDataAdviseHolder* iface) { DataAdviseHolder *This = (DataAdviseHolder *)iface; - TRACE("(%p) (ref=%ld)\n", This, This->ref); + TRACE("(%p) (ref=%d)\n", This, This->ref); return InterlockedIncrement(&This->ref); } @@ -459,7 +659,7 @@ static ULONG WINAPI DataAdviseHolder_Release( { DataAdviseHolder *This = (DataAdviseHolder *)iface; ULONG ref; - TRACE("(%p) (ref=%ld)\n", This, This->ref); + TRACE("(%p) (ref=%d)\n", This, This->ref); /* * Decrease the reference count on this object. @@ -490,7 +690,7 @@ static HRESULT WINAPI DataAdviseHolder_Advise( DataAdviseHolder *This = (DataAdviseHolder *)iface; - TRACE("(%p)->(%p, %p, %08lx, %p, %p)\n", This, pDataObject, pFetc, advf, + TRACE("(%p)->(%p, %p, %08x, %p, %p)\n", This, pDataObject, pFetc, advf, pAdvise, pdwConnection); /* * Sanity check @@ -523,14 +723,42 @@ static HRESULT WINAPI DataAdviseHolder_Advise( * Store the new sink */ This->Connections[index].sink = pAdvise; - memcpy(&(This->Connections[index].fmat), pFetc, sizeof(FORMATETC)); This->Connections[index].advf = advf & ~WINE_ADVF_REMOTE; + memcpy(&(This->Connections[index].fmat), pFetc, sizeof(FORMATETC)); + if (pFetc->ptd) + { + This->Connections[index].fmat.ptd = CoTaskMemAlloc(pFetc->ptd->tdSize); + if (!This->Connections[index].fmat.ptd) + { + IDataAdviseHolder_Unadvise(iface, index + 1); + return E_OUTOFMEMORY; + } + memcpy(This->Connections[index].fmat.ptd, pFetc->ptd, pFetc->ptd->tdSize); + } if (This->Connections[index].sink != NULL) { IAdviseSink_AddRef(This->Connections[index].sink); - if(advf & ADVF_PRIMEFIRST) { - IDataAdviseHolder_SendOnDataChange(iface, pDataObject, 0, advf); + + /* if we are already connected advise the remote object */ + if (This->delegate) + { + HRESULT hr; + + hr = IDataObject_DAdvise(This->delegate, &This->Connections[index].fmat, + This->Connections[index].advf, + This->Connections[index].sink, + &This->Connections[index].remote_connection); + if (FAILED(hr)) + { + IDataAdviseHolder_Unadvise(iface, index + 1); + return hr; + } + This->Connections[index].advf |= WINE_ADVF_REMOTE; } + else if(advf & ADVF_PRIMEFIRST) + /* only do this if we have no delegate, since in the above case the + * delegate will do the priming for us */ + IDataAdviseHolder_SendOnDataChange(iface, pDataObject, 0, advf); } /* * Return the index as the cookie. @@ -551,7 +779,7 @@ static HRESULT WINAPI DataAdviseHolder_Unadvise( { DataAdviseHolder *This = (DataAdviseHolder *)iface; - TRACE("(%p)->(%lu)\n", This, dwConnection); + TRACE("(%p)->(%u)\n", This, dwConnection); /* * So we don't return 0 as a cookie, the index was @@ -569,11 +797,16 @@ static HRESULT WINAPI DataAdviseHolder_Unadvise( if (This->Connections[dwConnection].sink == NULL) return OLE_E_NOCONNECTION; + if (This->delegate && This->Connections[dwConnection].advf & WINE_ADVF_REMOTE) + IDataObject_DUnadvise(This->delegate, + This->Connections[dwConnection].remote_connection); + /* * Release the sink and mark the spot in the list as free. */ IAdviseSink_Release(This->Connections[dwConnection].sink); memset(&(This->Connections[dwConnection]), 0, sizeof(DataAdviseConnection)); + return S_OK; } @@ -601,16 +834,17 @@ static HRESULT WINAPI DataAdviseHolder_SendOnDataChange( STGMEDIUM stg; HRESULT res; - TRACE("(%p)->(%p,%08lx,%08lx)\n", This, pDataObject, dwReserved, advf); + TRACE("(%p)->(%p,%08x,%08x)\n", This, pDataObject, dwReserved, advf); for(index = 0; index < This->maxCons; index++) { if(This->Connections[index].sink != NULL) { + memset(&stg, 0, sizeof(stg)); if(!(This->Connections[index].advf & ADVF_NODATA)) { TRACE("Calling IDataObject_GetData\n"); res = IDataObject_GetData(pDataObject, &(This->Connections[index].fmat), &stg); - TRACE("returns %08lx\n", res); + TRACE("returns %08x\n", res); } TRACE("Calling IAdviseSink_OnDataChange\n"); IAdviseSink_OnDataChange(This->Connections[index].sink, @@ -658,13 +892,26 @@ HRESULT DataAdviseHolder_OnConnect(IDataAdviseHolder *iface, IDataObject *pDeleg This->Connections[index].advf |= WINE_ADVF_REMOTE; } } - /* FIXME: store pDelegate somewhere */ + This->delegate = pDelegate; return hr; } void DataAdviseHolder_OnDisconnect(IDataAdviseHolder *iface) { - /* FIXME: Unadvise all remote interfaces */ + DataAdviseHolder *This = (DataAdviseHolder *)iface; + DWORD index; + + for(index = 0; index < This->maxCons; index++) + { + if((This->Connections[index].sink != NULL) && + (This->Connections[index].advf & WINE_ADVF_REMOTE)) + { + IDataObject_DUnadvise(This->delegate, + This->Connections[index].remote_connection); + This->Connections[index].advf &= ~WINE_ADVF_REMOTE; + } + } + This->delegate = NULL; } /****************************************************************************** @@ -683,6 +930,7 @@ static IDataAdviseHolder* DataAdviseHolder_Constructor(void) HEAP_ZERO_MEMORY, newHolder->maxCons * sizeof(DataAdviseConnection)); + newHolder->delegate = NULL; TRACE("returning %p\n", newHolder); return (IDataAdviseHolder*)newHolder; diff --git a/reactos/dll/win32/ole32/oleproxy.c b/reactos/dll/win32/ole32/oleproxy.c index 095876b940b..dd12e5c3787 100644 --- a/reactos/dll/win32/ole32/oleproxy.c +++ b/reactos/dll/win32/ole32/oleproxy.c @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ /* Documentation on MSDN: @@ -39,7 +39,6 @@ #include #include -#include #include #include @@ -64,8 +63,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole); -const CLSID CLSID_DfMarshal = { 0x0000030b, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} }; -const CLSID CLSID_PSFactoryBuffer = { 0x00000320, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} }; +static ULONG WINAPI RURpcProxyBufferImpl_Release(LPRPCPROXYBUFFER iface); /* From: http://msdn.microsoft.com/library/en-us/com/cmi_m_4lda.asp * @@ -161,7 +159,7 @@ CFStub_Invoke( ULONG res; if (msg->cbBuffer < sizeof(IID)) { - FIXME("Not enough bytes in buffer (%ld instead of %d)?\n",msg->cbBuffer,sizeof(IID)); + FIXME("Not enough bytes in buffer (%d)?\n",msg->cbBuffer); return E_FAIL; } memcpy(&iid,msg->Buffer,sizeof(iid)); @@ -173,51 +171,58 @@ CFStub_Invoke( } hres = IClassFactory_CreateInstance(classfac,NULL,&iid,(LPVOID*)&ppv); IClassFactory_Release(classfac); + msg->cbBuffer = 0; if (hres) { - msg->cbBuffer = 0; FIXME("Failed to create an instance of %s\n",debugstr_guid(&iid)); - return hres; + goto getbuffer; } hres = CreateStreamOnHGlobal(0,TRUE,&pStm); if (hres) { FIXME("Failed to create stream on hglobal\n"); - return hres; + goto getbuffer; } - hres = CoMarshalInterface(pStm,&iid,ppv,0,NULL,0); - IUnknown_Release((IUnknown*)ppv); + hres = IStream_Write(pStm, &ppv, sizeof(ppv), NULL); if (hres) { - FIXME("CoMarshalInterface failed, %lx!\n",hres); - msg->cbBuffer = 0; - return hres; + ERR("IStream_Write failed, 0x%08x\n", hres); + goto getbuffer; } + if (ppv) { + hres = CoMarshalInterface(pStm,&iid,ppv,0,NULL,0); + IUnknown_Release(ppv); + if (hres) { + FIXME("CoMarshalInterface failed, %x!\n",hres); + goto getbuffer; + } + } hres = IStream_Stat(pStm,&ststg,0); if (hres) { FIXME("Stat failed.\n"); - return hres; + goto getbuffer; } msg->cbBuffer = ststg.cbSize.u.LowPart; - I_RpcGetBuffer((RPC_MESSAGE *)msg); +getbuffer: + IRpcChannelBuffer_GetBuffer(chanbuf, msg, &IID_IClassFactory); if (hres) return hres; seekto.u.LowPart = 0;seekto.u.HighPart = 0; hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos); if (hres) { - FIXME("IStream_Seek failed, %lx\n",hres); + FIXME("IStream_Seek failed, %x\n",hres); return hres; } hres = IStream_Read(pStm,msg->Buffer,msg->cbBuffer,&res); if (hres) { - FIXME("Stream Read failed, %lx\n",hres); + FIXME("Stream Read failed, %x\n",hres); return hres; } IStream_Release(pStm); return S_OK; } FIXME("(%p,%p), stub!\n",msg,chanbuf); - FIXME("iMethod is %ld\n",msg->iMethod); - FIXME("cbBuffer is %ld\n",msg->cbBuffer); + FIXME("iMethod is %d\n",msg->iMethod); + FIXME("cbBuffer is %d\n",msg->cbBuffer); return E_FAIL; } @@ -346,18 +351,11 @@ static ULONG WINAPI CFProxy_AddRef(LPCLASSFACTORY iface) { } static ULONG WINAPI CFProxy_Release(LPCLASSFACTORY iface) { - ULONG ref; ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface); if (This->outer_unknown) - ref = IUnknown_Release(This->outer_unknown); - else - ref = InterlockedDecrement(&This->ref); - - if (!ref) { - if (This->chanbuf) IRpcChannelBuffer_Release(This->chanbuf); - HeapFree(GetProcessHeap(),0,This); - } - return ref; + return IUnknown_Release(This->outer_unknown); + else + return IRpcProxyBufferImpl_Release((IRpcProxyBuffer *)&This->lpvtbl_proxy); } static HRESULT WINAPI CFProxy_CreateInstance( @@ -384,36 +382,48 @@ static HRESULT WINAPI CFProxy_CreateInstance( msg.Buffer = NULL; hres = IRpcChannelBuffer_GetBuffer(This->chanbuf,&msg,&IID_IClassFactory); if (hres) { - FIXME("IRpcChannelBuffer_GetBuffer failed with %lx?\n",hres); + FIXME("IRpcChannelBuffer_GetBuffer failed with %x?\n",hres); return hres; } memcpy(msg.Buffer,riid,sizeof(*riid)); hres = IRpcChannelBuffer_SendReceive(This->chanbuf,&msg,&srstatus); if (hres) { - FIXME("IRpcChannelBuffer_SendReceive failed with %lx?\n",hres); + FIXME("IRpcChannelBuffer_SendReceive failed with %x?\n",hres); + IRpcChannelBuffer_FreeBuffer(This->chanbuf,&msg); return hres; } - if (!msg.cbBuffer) /* interface not found on remote */ + if (!msg.cbBuffer) { /* interface not found on remote */ + IRpcChannelBuffer_FreeBuffer(This->chanbuf,&msg); return srstatus; + } /* We got back: [Marshalled Interface data] */ - TRACE("got %ld bytes data.\n",msg.cbBuffer); + TRACE("got %d bytes data.\n",msg.cbBuffer); hGlobal = GlobalAlloc(GMEM_MOVEABLE|GMEM_NODISCARD|GMEM_SHARE,msg.cbBuffer); memcpy(GlobalLock(hGlobal),msg.Buffer,msg.cbBuffer); hres = CreateStreamOnHGlobal(hGlobal,TRUE,&pStream); if (hres) { - FIXME("CreateStreamOnHGlobal failed with %lx\n",hres); + FIXME("CreateStreamOnHGlobal failed with %x\n",hres); + IRpcChannelBuffer_FreeBuffer(This->chanbuf,&msg); return hres; } - hres = CoUnmarshalInterface( - pStream, - riid, - ppv - ); + hres = IStream_Read(pStream, ppv, sizeof(*ppv), NULL); + if (hres != S_OK) + hres = E_FAIL; + else if (*ppv) { + hres = CoUnmarshalInterface( + pStream, + riid, + ppv + ); + } IStream_Release(pStream); /* Does GlobalFree hGlobal too. */ + + IRpcChannelBuffer_FreeBuffer(This->chanbuf,&msg); + if (hres) { - FIXME("CoMarshalInterface failed, %lx\n",hres); + FIXME("CoMarshalInterface failed, %x\n",hres); return hres; } return S_OK; @@ -530,7 +540,7 @@ static HRESULT WINAPI RemUnkStub_Invoke(LPRPCSTUBBUFFER iface, LPBYTE buf = pMsg->Buffer; HRESULT hr = RPC_E_INVALIDMETHOD; - TRACE("(%p)->Invoke(%p,%p) method %ld\n", This, pMsg, pChannel, iMethod); + TRACE("(%p)->Invoke(%p,%p) method %d\n", This, pMsg, pChannel, iMethod); switch (iMethod) { case 3: /* RemQueryInterface */ @@ -555,7 +565,7 @@ static HRESULT WINAPI RemUnkStub_Invoke(LPRPCSTUBBUFFER iface, /* out */ pMsg->cbBuffer = cIids * sizeof(REMQIRESULT) + sizeof(HRESULT); - I_RpcGetBuffer((RPC_MESSAGE *)pMsg); + IRpcChannelBuffer_GetBuffer(pChannel, pMsg, &IID_IRemUnknown); buf = pMsg->Buffer; *(HRESULT *)buf = hr; @@ -585,7 +595,7 @@ static HRESULT WINAPI RemUnkStub_Invoke(LPRPCSTUBBUFFER iface, /* out */ pMsg->cbBuffer = cIids * sizeof(HRESULT); - I_RpcGetBuffer((RPC_MESSAGE *)pMsg); + IRpcChannelBuffer_GetBuffer(pChannel, pMsg, &IID_IRemUnknown); if (!hr) { buf = pMsg->Buffer; @@ -610,6 +620,7 @@ static HRESULT WINAPI RemUnkStub_Invoke(LPRPCSTUBBUFFER iface, /* out */ pMsg->cbBuffer = 0; + IRpcChannelBuffer_GetBuffer(pChannel, pMsg, &IID_IRemUnknown); break; } } @@ -713,19 +724,12 @@ static ULONG WINAPI RemUnkProxy_AddRef(LPREMUNKNOWN iface) static ULONG WINAPI RemUnkProxy_Release(LPREMUNKNOWN iface) { RemUnkProxy *This = (RemUnkProxy *)iface; - ULONG refs; TRACE("(%p)->Release()\n",This); if (This->outer_unknown) - refs = IUnknown_Release(This->outer_unknown); - else - refs = InterlockedDecrement(&This->refs); - - if (!refs) { - if (This->chan) IRpcChannelBuffer_Release(This->chan); - HeapFree(GetProcessHeap(),0,This); - } - return refs; + return IUnknown_Release(This->outer_unknown); + else + return IRpcProxyBufferImpl_Release((IRpcProxyBuffer *)&This->lpvtbl_proxy); } static HRESULT WINAPI RemUnkProxy_RemQueryInterface(LPREMUNKNOWN iface, @@ -740,7 +744,7 @@ static HRESULT WINAPI RemUnkProxy_RemQueryInterface(LPREMUNKNOWN iface, HRESULT hr = S_OK; ULONG status; - TRACE("(%p)->(%s,%ld,%d,%p,%p)\n",This, + TRACE("(%p)->(%s,%d,%d,%p,%p)\n",This, debugstr_guid(ripid),cRefs,cIids,iids,ppQIResults); *ppQIResults = NULL; @@ -869,14 +873,14 @@ static HRESULT WINAPI RURpcProxyBufferImpl_QueryInterface(LPRPCPROXYBUFFER iface static ULONG WINAPI RURpcProxyBufferImpl_AddRef(LPRPCPROXYBUFFER iface) { ICOM_THIS_MULTI(RemUnkProxy,lpvtbl_proxy,iface); - TRACE("%p, %ld\n", iface, This->refs + 1); + TRACE("%p, %d\n", iface, This->refs + 1); return InterlockedIncrement(&This->refs); } static ULONG WINAPI RURpcProxyBufferImpl_Release(LPRPCPROXYBUFFER iface) { ICOM_THIS_MULTI(RemUnkProxy,lpvtbl_proxy,iface); ULONG ref = InterlockedDecrement(&This->refs); - TRACE("%p, %ld\n", iface, ref); + TRACE("%p, %d\n", iface, ref); if (!ref) { IRpcProxyBuffer_Disconnect(iface); HeapFree(GetProcessHeap(),0,This); @@ -1015,6 +1019,12 @@ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv) return FileMonikerCF_Create(iid, ppv); if (IsEqualCLSID(rclsid, &CLSID_ItemMoniker)) return ItemMonikerCF_Create(iid, ppv); + if (IsEqualCLSID(rclsid, &CLSID_AntiMoniker)) + return AntiMonikerCF_Create(iid, ppv); + if (IsEqualCLSID(rclsid, &CLSID_CompositeMoniker)) + return CompositeMonikerCF_Create(iid, ppv); + if (IsEqualCLSID(rclsid, &CLSID_ClassMoniker)) + return ClassMonikerCF_Create(iid, ppv); FIXME("\n\tCLSID:\t%s,\n\tIID:\t%s\n",debugstr_guid(rclsid),debugstr_guid(iid)); return CLASS_E_CLASSNOTAVAILABLE; diff --git a/reactos/dll/win32/ole32/olestd.h b/reactos/dll/win32/ole32/olestd.h index b5814fad4a4..02a4d3b2aab 100644 --- a/reactos/dll/win32/ole32/olestd.h +++ b/reactos/dll/win32/ole32/olestd.h @@ -13,7 +13,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #if !defined( __WINE_OLESTD_H_ ) diff --git a/reactos/dll/win32/ole32/regsvr.c b/reactos/dll/win32/ole32/regsvr.c index 12961b542bd..fdb45c8a82f 100644 --- a/reactos/dll/win32/ole32/regsvr.c +++ b/reactos/dll/win32/ole32/regsvr.c @@ -15,7 +15,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" @@ -30,9 +30,11 @@ #include "winerror.h" #include "objbase.h" -#include "compobj_private.h" #include "ole2.h" #include "olectl.h" +#include "initguid.h" +#include "compobj_private.h" +#include "moniker.h" #include "wine/debug.h" @@ -66,6 +68,7 @@ struct regsvr_coclass LPCSTR ips; /* can be NULL to omit */ LPCSTR ips32; /* can be NULL to omit */ LPCSTR ips32_tmodel; /* can be NULL to omit */ + LPCSTR progid; /* can be NULL to omit */ }; static HRESULT register_coclasses(struct regsvr_coclass const *list); @@ -95,6 +98,8 @@ static WCHAR const ips_keyname[13] = { static WCHAR const ips32_keyname[15] = { 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r', '3', '2', 0 }; +static WCHAR const progid_keyname[7] = { + 'P', 'r', 'o', 'g', 'I', 'D', 0 }; static char const tmodel_valuename[] = "ThreadingModel"; /*********************************************************************** @@ -105,7 +110,10 @@ static LONG register_key_defvalueW(HKEY base, WCHAR const *name, WCHAR const *value); static LONG register_key_defvalueA(HKEY base, WCHAR const *name, char const *value); +static LONG register_progid(WCHAR const *clsid, char const *progid, + char const *name); static LONG recursive_delete_key(HKEY key); +static LONG recursive_delete_keyA(HKEY base, char const *name); /*********************************************************************** @@ -137,7 +145,7 @@ static HRESULT register_interfaces(struct regsvr_interface const *list) } if (list->base_iid) { - register_key_guid(iid_key, base_ifa_keyname, list->base_iid); + res = register_key_guid(iid_key, base_ifa_keyname, list->base_iid); if (res != ERROR_SUCCESS) goto error_close_iid_key; } @@ -159,12 +167,12 @@ static HRESULT register_interfaces(struct regsvr_interface const *list) } if (list->ps_clsid) { - register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid); + res = register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid); if (res != ERROR_SUCCESS) goto error_close_iid_key; } if (list->ps_clsid32) { - register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32); + res = register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32); if (res != ERROR_SUCCESS) goto error_close_iid_key; } @@ -266,6 +274,15 @@ static HRESULT register_coclasses(struct regsvr_coclass const *list) if (res != ERROR_SUCCESS) goto error_close_clsid_key; } + if (list->progid) { + res = register_key_defvalueA(clsid_key, progid_keyname, + list->progid); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + + res = register_progid(buf, list->progid, list->name); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + error_close_clsid_key: RegCloseKey(clsid_key); } @@ -304,6 +321,11 @@ static HRESULT unregister_coclasses(struct regsvr_coclass const *list) res = recursive_delete_key(clsid_key); RegCloseKey(clsid_key); if (res != ERROR_SUCCESS) goto error_close_coclass_key; + + if (list->progid) { + res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->progid); + if (res != ERROR_SUCCESS) goto error_close_coclass_key; + } } error_close_coclass_key: @@ -363,6 +385,38 @@ static LONG register_key_defvalueA( return res; } +/*********************************************************************** + * regsvr_progid + */ +static LONG register_progid( + WCHAR const *clsid, + char const *progid, + char const *name) +{ + LONG res; + HKEY progid_key; + + res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0, + NULL, 0, KEY_READ | KEY_WRITE, NULL, + &progid_key, NULL); + if (res != ERROR_SUCCESS) return res; + + if (name) { + res = RegSetValueExA(progid_key, NULL, 0, REG_SZ, + (CONST BYTE*)name, strlen(name) + 1); + if (res != ERROR_SUCCESS) goto error_close_progid_key; + } + + if (clsid) { + res = register_key_defvalueW(progid_key, clsid_keyname, clsid); + if (res != ERROR_SUCCESS) goto error_close_progid_key; + } + +error_close_progid_key: + RegCloseKey(progid_key); + return res; +} + /*********************************************************************** * recursive_delete_key */ @@ -395,29 +449,50 @@ static LONG recursive_delete_key(HKEY key) return res; } +/*********************************************************************** + * recursive_delete_keyA + */ +static LONG recursive_delete_keyA(HKEY base, char const *name) +{ + LONG res; + HKEY key; + + res = RegOpenKeyExA(base, name, 0, KEY_READ | KEY_WRITE, &key); + if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS; + if (res != ERROR_SUCCESS) return res; + res = recursive_delete_key(key); + RegCloseKey(key); + return res; +} + /*********************************************************************** * coclass list */ -static GUID const CLSID_FileMoniker = { - 0x00000303, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} }; +static GUID const CLSID_StdOleLink = { + 0x00000300, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} }; -static GUID const CLSID_ItemMoniker = { - 0x00000304, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} }; +static GUID const CLSID_PointerMoniker = { + 0x00000306, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} }; -/* FIXME: DfMarshal and PSFactoryBuffer are defined elsewhere too */ +static GUID const CLSID_PackagerMoniker = { + 0x00000308, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} }; -static GUID const CLSID_DfMarshal = { - 0x0000030B, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} }; - -static GUID const CLSID_PSFactoryBuffer = { - 0x00000320, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} }; +extern GUID const CLSID_Picture_Metafile; +extern GUID const CLSID_Picture_Dib; static struct regsvr_coclass const coclass_list[] = { + { &CLSID_StdOleLink, + "StdOleLink", + NULL, + "ole32.dll", + NULL + }, { &CLSID_FileMoniker, "FileMoniker", NULL, "ole32.dll", - "Both" + "Both", + "file" }, { &CLSID_ItemMoniker, "ItemMoniker", @@ -425,12 +500,57 @@ static struct regsvr_coclass const coclass_list[] = { "ole32.dll", "Both" }, + { &CLSID_AntiMoniker, + "AntiMoniker", + NULL, + "ole32.dll", + "Both" + }, + { &CLSID_PointerMoniker, + "PointerMoniker", + NULL, + "ole32.dll", + "Both" + }, + { &CLSID_PackagerMoniker, + "PackagerMoniker", + NULL, + "ole32.dll", + "Both" + }, + { &CLSID_CompositeMoniker, + "CompositeMoniker", + NULL, + "ole32.dll", + "Both" + }, { &CLSID_DfMarshal, "DfMarshal", NULL, "ole32.dll", "Both" }, + { &CLSID_Picture_Metafile, + "Picture (Metafile)", + NULL, + "ole32.dll", + NULL, + "StaticMetafile" + }, + { &CLSID_Picture_Dib, + "Picture (Device Independent Bitmap)", + NULL, + "ole32.dll", + NULL, + "StaticDib" + }, + { &CLSID_ClassMoniker, + "ClassMoniker", + NULL, + "ole32.dll", + "Both", + "CLSID" + }, { &CLSID_PSFactoryBuffer, "PSFactoryBuffer", NULL, @@ -451,6 +571,7 @@ static struct regsvr_coclass const coclass_list[] = { */ #define INTERFACE_ENTRY(interface, base, clsid32, clsid16) { &IID_##interface, #interface, base, sizeof(interface##Vtbl)/sizeof(void*), clsid16, clsid32 } +#define BAS_INTERFACE_ENTRY(interface, base) INTERFACE_ENTRY(interface, &IID_##base, &CLSID_PSFactoryBuffer, NULL) #define STD_INTERFACE_ENTRY(interface) INTERFACE_ENTRY(interface, NULL, &CLSID_PSFactoryBuffer, NULL) #define LCL_INTERFACE_ENTRY(interface) INTERFACE_ENTRY(interface, NULL, NULL, NULL) @@ -459,31 +580,65 @@ static const struct regsvr_interface interface_list[] = { STD_INTERFACE_ENTRY(IClassFactory), LCL_INTERFACE_ENTRY(IMalloc), LCL_INTERFACE_ENTRY(IMarshal), + STD_INTERFACE_ENTRY(ILockBytes), STD_INTERFACE_ENTRY(IStorage), + STD_INTERFACE_ENTRY(IStream), + STD_INTERFACE_ENTRY(IEnumSTATSTG), + STD_INTERFACE_ENTRY(IBindCtx), + BAS_INTERFACE_ENTRY(IMoniker, IPersistStream), + STD_INTERFACE_ENTRY(IRunningObjectTable), + STD_INTERFACE_ENTRY(IRootStorage), LCL_INTERFACE_ENTRY(IMessageFilter), LCL_INTERFACE_ENTRY(IStdMarshalInfo), LCL_INTERFACE_ENTRY(IExternalConnection), LCL_INTERFACE_ENTRY(IMallocSpy), LCL_INTERFACE_ENTRY(IMultiQI), - STD_INTERFACE_ENTRY(IStream), - STD_INTERFACE_ENTRY(IPersistStorage), + STD_INTERFACE_ENTRY(IEnumUnknown), + STD_INTERFACE_ENTRY(IEnumString), + STD_INTERFACE_ENTRY(IEnumMoniker), + STD_INTERFACE_ENTRY(IEnumFORMATETC), + STD_INTERFACE_ENTRY(IEnumOLEVERB), + STD_INTERFACE_ENTRY(IEnumSTATDATA), + BAS_INTERFACE_ENTRY(IPersistStream, IPersist), + BAS_INTERFACE_ENTRY(IPersistStorage, IPersist), + BAS_INTERFACE_ENTRY(IPersistFile, IPersist), + STD_INTERFACE_ENTRY(IPersist), + STD_INTERFACE_ENTRY(IViewObject), STD_INTERFACE_ENTRY(IDataObject), STD_INTERFACE_ENTRY(IAdviseSink), LCL_INTERFACE_ENTRY(IDataAdviseHolder), LCL_INTERFACE_ENTRY(IOleAdviseHolder), STD_INTERFACE_ENTRY(IOleObject), + BAS_INTERFACE_ENTRY(IOleInPlaceObject, IOleWindow), + STD_INTERFACE_ENTRY(IOleWindow), + BAS_INTERFACE_ENTRY(IOleInPlaceUIWindow, IOleWindow), + STD_INTERFACE_ENTRY(IOleInPlaceFrame), + BAS_INTERFACE_ENTRY(IOleInPlaceActiveObject, IOleWindow), STD_INTERFACE_ENTRY(IOleClientSite), + BAS_INTERFACE_ENTRY(IOleInPlaceSite, IOleWindow), + STD_INTERFACE_ENTRY(IParseDisplayName), + BAS_INTERFACE_ENTRY(IOleContainer, IParseDisplayName), + BAS_INTERFACE_ENTRY(IOleItemContainer, IOleContainer), + STD_INTERFACE_ENTRY(IOleLink), + STD_INTERFACE_ENTRY(IOleCache), LCL_INTERFACE_ENTRY(IDropSource), + STD_INTERFACE_ENTRY(IDropTarget), + BAS_INTERFACE_ENTRY(IAdviseSink2, IAdviseSink), + STD_INTERFACE_ENTRY(IRunnableObject), + BAS_INTERFACE_ENTRY(IViewObject2, IViewObject), + BAS_INTERFACE_ENTRY(IOleCache2, IOleCache), + STD_INTERFACE_ENTRY(IOleCacheControl), STD_INTERFACE_ENTRY(IRemUnknown), LCL_INTERFACE_ENTRY(IClientSecurity), LCL_INTERFACE_ENTRY(IServerSecurity), + STD_INTERFACE_ENTRY(ISequentialStream), { NULL } /* list terminator */ }; /*********************************************************************** * DllRegisterServer (OLE32.@) */ -HRESULT WINAPI DllRegisterServer() +HRESULT WINAPI DllRegisterServer(void) { HRESULT hr; @@ -498,7 +653,7 @@ HRESULT WINAPI DllRegisterServer() /*********************************************************************** * DllUnregisterServer (OLE32.@) */ -HRESULT WINAPI DllUnregisterServer() +HRESULT WINAPI DllUnregisterServer(void) { HRESULT hr; diff --git a/reactos/dll/win32/ole32/rpc.c b/reactos/dll/win32/ole32/rpc.c index c57bab5e6ac..39957d052ae 100644 --- a/reactos/dll/win32/ole32/rpc.c +++ b/reactos/dll/win32/ole32/rpc.c @@ -17,16 +17,15 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" +#include "wine/port.h" -#include #include #include #include -#include #define COBJMACROS #define NONAMELESSUNION @@ -41,10 +40,7 @@ #include "rpc.h" #include "winerror.h" #include "winreg.h" -#include "wtypes.h" -#include "excpt.h" #include "wine/unicode.h" -#include "wine/exception.h" #include "compobj_private.h" @@ -69,7 +65,17 @@ static CRITICAL_SECTION_DEBUG csRegIf_debug = }; static CRITICAL_SECTION csRegIf = { &csRegIf_debug, -1, 0, 0, 0, 0 }; -static WCHAR wszPipeTransport[] = {'n','c','a','c','n','_','n','p',0}; +static struct list channel_hooks = LIST_INIT(channel_hooks); /* (CS csChannelHook) */ +static CRITICAL_SECTION csChannelHook; +static CRITICAL_SECTION_DEBUG csChannelHook_debug = +{ + 0, 0, &csChannelHook, + { &csChannelHook_debug.ProcessLocksList, &csChannelHook_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": channel hooks") } +}; +static CRITICAL_SECTION csChannelHook = { &csChannelHook_debug, -1, 0, 0, 0, 0 }; + +static WCHAR wszRpcTransport[] = {'n','c','a','l','r','p','c',0}; struct registered_if @@ -98,6 +104,11 @@ typedef struct RpcChannelBuffer super; /* superclass */ RPC_BINDING_HANDLE bind; /* handle to the remote server */ + OXID oxid; /* apartment in which the channel is valid */ + DWORD server_pid; /* id of server process */ + DWORD dest_context; /* returned from GetDestCtx */ + LPVOID dest_context_data; /* returned from GetDestCtx */ + HANDLE event; /* cached event handle */ } ClientRpcChannelBuffer; struct dispatch_params @@ -105,18 +116,323 @@ struct dispatch_params RPCOLEMESSAGE *msg; /* message */ IRpcStubBuffer *stub; /* stub buffer, if applicable */ IRpcChannelBuffer *chan; /* server channel buffer, if applicable */ + IID iid; /* ID of interface being called */ + IUnknown *iface; /* interface being called */ HANDLE handle; /* handle that will become signaled when call finishes */ RPC_STATUS status; /* status (out) */ HRESULT hr; /* hresult (out) */ }; -static WINE_EXCEPTION_FILTER(ole_filter) +struct message_state { - if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) - return EXCEPTION_CONTINUE_SEARCH; - return EXCEPTION_EXECUTE_HANDLER; + RPC_BINDING_HANDLE binding_handle; + ULONG prefix_data_len; + SChannelHookCallInfo channel_hook_info; +}; + +typedef struct +{ + ULONG conformance; /* NDR */ + GUID id; + ULONG size; + /* [size_is((size+7)&~7)] */ unsigned char data[1]; +} WIRE_ORPC_EXTENT; + +struct channel_hook_entry +{ + struct list entry; + GUID id; + IChannelHook *hook; +}; + +struct channel_hook_buffer_data +{ + GUID id; + ULONG extension_size; +}; + + +static HRESULT unmarshal_ORPCTHAT(RPC_MESSAGE *msg, ORPCTHAT *orpcthat, + ORPC_EXTENT_ARRAY *orpc_ext_array, WIRE_ORPC_EXTENT **first_wire_orpc_extent); + +/* Channel Hook Functions */ + +static ULONG ChannelHooks_ClientGetSize(SChannelHookCallInfo *info, + struct channel_hook_buffer_data **data, unsigned int *hook_count, + ULONG *extension_count) +{ + struct channel_hook_entry *entry; + ULONG total_size = 0; + unsigned int hook_index = 0; + + *hook_count = 0; + *extension_count = 0; + + EnterCriticalSection(&csChannelHook); + + LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry) + (*hook_count)++; + + if (*hook_count) + *data = HeapAlloc(GetProcessHeap(), 0, *hook_count * sizeof(struct channel_hook_buffer_data)); + else + *data = NULL; + + LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry) + { + ULONG extension_size = 0; + + IChannelHook_ClientGetSize(entry->hook, &entry->id, &info->iid, &extension_size); + + TRACE("%s: extension_size = %u\n", debugstr_guid(&entry->id), extension_size); + + extension_size = (extension_size+7)&~7; + (*data)[hook_index].id = entry->id; + (*data)[hook_index].extension_size = extension_size; + + /* an extension is only put onto the wire if it has data to write */ + if (extension_size) + { + total_size += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[extension_size]); + (*extension_count)++; + } + + hook_index++; + } + + LeaveCriticalSection(&csChannelHook); + + return total_size; } +static unsigned char * ChannelHooks_ClientFillBuffer(SChannelHookCallInfo *info, + unsigned char *buffer, struct channel_hook_buffer_data *data, + unsigned int hook_count) +{ + struct channel_hook_entry *entry; + + EnterCriticalSection(&csChannelHook); + + LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry) + { + unsigned int i; + ULONG extension_size = 0; + WIRE_ORPC_EXTENT *wire_orpc_extent = (WIRE_ORPC_EXTENT *)buffer; + + for (i = 0; i < hook_count; i++) + if (IsEqualGUID(&entry->id, &data[i].id)) + extension_size = data[i].extension_size; + + /* an extension is only put onto the wire if it has data to write */ + if (!extension_size) + continue; + + IChannelHook_ClientFillBuffer(entry->hook, &entry->id, &info->iid, + &extension_size, buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0])); + + TRACE("%s: extension_size = %u\n", debugstr_guid(&entry->id), extension_size); + + /* FIXME: set unused portion of wire_orpc_extent->data to 0? */ + + wire_orpc_extent->conformance = (extension_size+7)&~7; + wire_orpc_extent->size = extension_size; + memcpy(&wire_orpc_extent->id, &entry->id, sizeof(wire_orpc_extent->id)); + buffer += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[wire_orpc_extent->conformance]); + } + + LeaveCriticalSection(&csChannelHook); + + HeapFree(GetProcessHeap(), 0, data); + + return buffer; +} + +static void ChannelHooks_ServerNotify(SChannelHookCallInfo *info, + DWORD lDataRep, WIRE_ORPC_EXTENT *first_wire_orpc_extent, + ULONG extension_count) +{ + struct channel_hook_entry *entry; + ULONG i; + + EnterCriticalSection(&csChannelHook); + + LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry) + { + WIRE_ORPC_EXTENT *wire_orpc_extent; + for (i = 0, wire_orpc_extent = first_wire_orpc_extent; + i < extension_count; + i++, wire_orpc_extent = (WIRE_ORPC_EXTENT *)&wire_orpc_extent->data[wire_orpc_extent->conformance]) + { + if (IsEqualGUID(&entry->id, &wire_orpc_extent->id)) + break; + } + if (i == extension_count) wire_orpc_extent = NULL; + + IChannelHook_ServerNotify(entry->hook, &entry->id, &info->iid, + wire_orpc_extent ? wire_orpc_extent->size : 0, + wire_orpc_extent ? wire_orpc_extent->data : NULL, + lDataRep); + } + + LeaveCriticalSection(&csChannelHook); +} + +static ULONG ChannelHooks_ServerGetSize(SChannelHookCallInfo *info, + struct channel_hook_buffer_data **data, unsigned int *hook_count, + ULONG *extension_count) +{ + struct channel_hook_entry *entry; + ULONG total_size = 0; + unsigned int hook_index = 0; + + *hook_count = 0; + *extension_count = 0; + + EnterCriticalSection(&csChannelHook); + + LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry) + (*hook_count)++; + + if (*hook_count) + *data = HeapAlloc(GetProcessHeap(), 0, *hook_count * sizeof(struct channel_hook_buffer_data)); + else + *data = NULL; + + LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry) + { + ULONG extension_size = 0; + + IChannelHook_ServerGetSize(entry->hook, &entry->id, &info->iid, S_OK, + &extension_size); + + TRACE("%s: extension_size = %u\n", debugstr_guid(&entry->id), extension_size); + + extension_size = (extension_size+7)&~7; + (*data)[hook_index].id = entry->id; + (*data)[hook_index].extension_size = extension_size; + + /* an extension is only put onto the wire if it has data to write */ + if (extension_size) + { + total_size += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[extension_size]); + (*extension_count)++; + } + + hook_index++; + } + + LeaveCriticalSection(&csChannelHook); + + return total_size; +} + +static unsigned char * ChannelHooks_ServerFillBuffer(SChannelHookCallInfo *info, + unsigned char *buffer, struct channel_hook_buffer_data *data, + unsigned int hook_count) +{ + struct channel_hook_entry *entry; + + EnterCriticalSection(&csChannelHook); + + LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry) + { + unsigned int i; + ULONG extension_size = 0; + WIRE_ORPC_EXTENT *wire_orpc_extent = (WIRE_ORPC_EXTENT *)buffer; + + for (i = 0; i < hook_count; i++) + if (IsEqualGUID(&entry->id, &data[i].id)) + extension_size = data[i].extension_size; + + /* an extension is only put onto the wire if it has data to write */ + if (!extension_size) + continue; + + IChannelHook_ServerFillBuffer(entry->hook, &entry->id, &info->iid, + &extension_size, buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]), + S_OK); + + TRACE("%s: extension_size = %u\n", debugstr_guid(&entry->id), extension_size); + + /* FIXME: set unused portion of wire_orpc_extent->data to 0? */ + + wire_orpc_extent->conformance = (extension_size+7)&~7; + wire_orpc_extent->size = extension_size; + memcpy(&wire_orpc_extent->id, &entry->id, sizeof(wire_orpc_extent->id)); + buffer += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[wire_orpc_extent->conformance]); + } + + LeaveCriticalSection(&csChannelHook); + + HeapFree(GetProcessHeap(), 0, data); + + return buffer; +} + +static void ChannelHooks_ClientNotify(SChannelHookCallInfo *info, + DWORD lDataRep, WIRE_ORPC_EXTENT *first_wire_orpc_extent, + ULONG extension_count, HRESULT hrFault) +{ + struct channel_hook_entry *entry; + ULONG i; + + EnterCriticalSection(&csChannelHook); + + LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry) + { + WIRE_ORPC_EXTENT *wire_orpc_extent; + for (i = 0, wire_orpc_extent = first_wire_orpc_extent; + i < extension_count; + i++, wire_orpc_extent = (WIRE_ORPC_EXTENT *)&wire_orpc_extent->data[wire_orpc_extent->conformance]) + { + if (IsEqualGUID(&entry->id, &wire_orpc_extent->id)) + break; + } + if (i == extension_count) wire_orpc_extent = NULL; + + IChannelHook_ClientNotify(entry->hook, &entry->id, &info->iid, + wire_orpc_extent ? wire_orpc_extent->size : 0, + wire_orpc_extent ? wire_orpc_extent->data : NULL, + lDataRep, hrFault); + } + + LeaveCriticalSection(&csChannelHook); +} + +HRESULT RPC_RegisterChannelHook(REFGUID rguid, IChannelHook *hook) +{ + struct channel_hook_entry *entry; + + TRACE("(%s, %p)\n", debugstr_guid(rguid), hook); + + entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry)); + if (!entry) + return E_OUTOFMEMORY; + + memcpy(&entry->id, rguid, sizeof(entry->id)); + entry->hook = hook; + IChannelHook_AddRef(hook); + + EnterCriticalSection(&csChannelHook); + list_add_tail(&channel_hooks, &entry->entry); + LeaveCriticalSection(&csChannelHook); + + return S_OK; +} + +void RPC_UnregisterAllChannelHooks(void) +{ + struct channel_hook_entry *cursor; + struct channel_hook_entry *cursor2; + + EnterCriticalSection(&csChannelHook); + LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &channel_hooks, struct channel_hook_entry, entry) + HeapFree(GetProcessHeap(), 0, cursor); + LeaveCriticalSection(&csChannelHook); +} + +/* RPC Channel Buffer Functions */ + static HRESULT WINAPI RpcChannelBuffer_QueryInterface(LPRPCCHANNELBUFFER iface, REFIID riid, LPVOID *ppv) { *ppv = NULL; @@ -157,6 +473,7 @@ static ULONG WINAPI ClientRpcChannelBuffer_Release(LPRPCCHANNELBUFFER iface) if (ref) return ref; + if (This->event) CloseHandle(This->event); RpcBindingFree(&This->bind); HeapFree(GetProcessHeap(), 0, This); return 0; @@ -167,11 +484,77 @@ static HRESULT WINAPI ServerRpcChannelBuffer_GetBuffer(LPRPCCHANNELBUFFER iface, RpcChannelBuffer *This = (RpcChannelBuffer *)iface; RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg; RPC_STATUS status; + ORPCTHAT *orpcthat; + struct message_state *message_state; + ULONG extensions_size; + struct channel_hook_buffer_data *channel_hook_data; + unsigned int channel_hook_count; + ULONG extension_count; TRACE("(%p)->(%p,%s)\n", This, olemsg, debugstr_guid(riid)); + message_state = (struct message_state *)msg->Handle; + /* restore the binding handle and the real start of data */ + msg->Handle = message_state->binding_handle; + msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len; + + extensions_size = ChannelHooks_ServerGetSize(&message_state->channel_hook_info, + &channel_hook_data, &channel_hook_count, &extension_count); + + msg->BufferLength += FIELD_OFFSET(ORPCTHAT, extensions) + 4; + if (extensions_size) + { + msg->BufferLength += FIELD_OFFSET(ORPC_EXTENT_ARRAY, extent) + 2*sizeof(DWORD) + extensions_size; + if (extension_count & 1) + msg->BufferLength += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]); + } + status = I_RpcGetBuffer(msg); + orpcthat = (ORPCTHAT *)msg->Buffer; + msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(ORPCTHAT, extensions); + + orpcthat->flags = ORPCF_NULL /* FIXME? */; + + /* NDR representation of orpcthat->extensions */ + *(DWORD *)msg->Buffer = extensions_size ? 1 : 0; + msg->Buffer = (char *)msg->Buffer + sizeof(DWORD); + + if (extensions_size) + { + ORPC_EXTENT_ARRAY *orpc_extent_array = msg->Buffer; + orpc_extent_array->size = extension_count; + orpc_extent_array->reserved = 0; + msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(ORPC_EXTENT_ARRAY, extent); + /* NDR representation of orpc_extent_array->extent */ + *(DWORD *)msg->Buffer = 1; + msg->Buffer = (char *)msg->Buffer + sizeof(DWORD); + /* NDR representation of [size_is] attribute of orpc_extent_array->extent */ + *(DWORD *)msg->Buffer = (extension_count + 1) & ~1; + msg->Buffer = (char *)msg->Buffer + sizeof(DWORD); + + msg->Buffer = ChannelHooks_ServerFillBuffer(&message_state->channel_hook_info, + msg->Buffer, channel_hook_data, channel_hook_count); + + /* we must add a dummy extension if there is an odd extension + * count to meet the contract specified by the size_is attribute */ + if (extension_count & 1) + { + WIRE_ORPC_EXTENT *wire_orpc_extent = msg->Buffer; + wire_orpc_extent->conformance = 0; + memcpy(&wire_orpc_extent->id, &GUID_NULL, sizeof(wire_orpc_extent->id)); + wire_orpc_extent->size = 0; + msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]); + } + } + + /* store the prefixed data length so that we can restore the real buffer + * later */ + message_state->prefix_data_len = (char *)msg->Buffer - (char *)orpcthat; + msg->BufferLength -= message_state->prefix_data_len; + /* save away the message state again */ + msg->Handle = message_state; + TRACE("-- %ld\n", status); return HRESULT_FROM_WIN32(status); @@ -183,6 +566,12 @@ static HRESULT WINAPI ClientRpcChannelBuffer_GetBuffer(LPRPCCHANNELBUFFER iface, RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg; RPC_CLIENT_INTERFACE *cif; RPC_STATUS status; + ORPCTHIS *orpcthis; + struct message_state *message_state; + ULONG extensions_size; + struct channel_hook_buffer_data *channel_hook_data; + unsigned int channel_hook_count; + ULONG extension_count; TRACE("(%p)->(%p,%s)\n", This, olemsg, debugstr_guid(riid)); @@ -190,52 +579,199 @@ static HRESULT WINAPI ClientRpcChannelBuffer_GetBuffer(LPRPCCHANNELBUFFER iface, if (!cif) return E_OUTOFMEMORY; + message_state = HeapAlloc(GetProcessHeap(), 0, sizeof(*message_state)); + if (!message_state) + { + HeapFree(GetProcessHeap(), 0, cif); + return E_OUTOFMEMORY; + } + cif->Length = sizeof(RPC_CLIENT_INTERFACE); /* RPC interface ID = COM interface ID */ cif->InterfaceId.SyntaxGUID = *riid; /* COM objects always have a version of 0.0 */ cif->InterfaceId.SyntaxVersion.MajorVersion = 0; cif->InterfaceId.SyntaxVersion.MinorVersion = 0; - msg->RpcInterfaceInformation = cif; msg->Handle = This->bind; - + msg->RpcInterfaceInformation = cif; + + message_state->channel_hook_info.iid = *riid; + message_state->channel_hook_info.cbSize = sizeof(message_state->channel_hook_info); + message_state->channel_hook_info.uCausality = COM_CurrentCausalityId(); + message_state->channel_hook_info.dwServerPid = This->server_pid; + message_state->channel_hook_info.iMethod = msg->ProcNum; + message_state->channel_hook_info.pObject = NULL; /* only present on server-side */ + + extensions_size = ChannelHooks_ClientGetSize(&message_state->channel_hook_info, + &channel_hook_data, &channel_hook_count, &extension_count); + + msg->BufferLength += FIELD_OFFSET(ORPCTHIS, extensions) + 4; + if (extensions_size) + { + msg->BufferLength += FIELD_OFFSET(ORPC_EXTENT_ARRAY, extent) + 2*sizeof(DWORD) + extensions_size; + if (extension_count & 1) + msg->BufferLength += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]); + } + status = I_RpcGetBuffer(msg); + message_state->prefix_data_len = 0; + message_state->binding_handle = This->bind; + msg->Handle = message_state; + + if (status == RPC_S_OK) + { + orpcthis = (ORPCTHIS *)msg->Buffer; + msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(ORPCTHIS, extensions); + + orpcthis->version.MajorVersion = COM_MAJOR_VERSION; + orpcthis->version.MinorVersion = COM_MINOR_VERSION; + orpcthis->flags = message_state->channel_hook_info.dwServerPid ? ORPCF_LOCAL : ORPCF_NULL; + orpcthis->reserved1 = 0; + orpcthis->cid = message_state->channel_hook_info.uCausality; + + /* NDR representation of orpcthis->extensions */ + *(DWORD *)msg->Buffer = extensions_size ? 1 : 0; + msg->Buffer = (char *)msg->Buffer + sizeof(DWORD); + + if (extensions_size) + { + ORPC_EXTENT_ARRAY *orpc_extent_array = msg->Buffer; + orpc_extent_array->size = extension_count; + orpc_extent_array->reserved = 0; + msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(ORPC_EXTENT_ARRAY, extent); + /* NDR representation of orpc_extent_array->extent */ + *(DWORD *)msg->Buffer = 1; + msg->Buffer = (char *)msg->Buffer + sizeof(DWORD); + /* NDR representation of [size_is] attribute of orpc_extent_array->extent */ + *(DWORD *)msg->Buffer = (extension_count + 1) & ~1; + msg->Buffer = (char *)msg->Buffer + sizeof(DWORD); + + msg->Buffer = ChannelHooks_ClientFillBuffer(&message_state->channel_hook_info, + msg->Buffer, channel_hook_data, channel_hook_count); + + /* we must add a dummy extension if there is an odd extension + * count to meet the contract specified by the size_is attribute */ + if (extension_count & 1) + { + WIRE_ORPC_EXTENT *wire_orpc_extent = msg->Buffer; + wire_orpc_extent->conformance = 0; + memcpy(&wire_orpc_extent->id, &GUID_NULL, sizeof(wire_orpc_extent->id)); + wire_orpc_extent->size = 0; + msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]); + } + } + + /* store the prefixed data length so that we can restore the real buffer + * pointer in ClientRpcChannelBuffer_SendReceive. */ + message_state->prefix_data_len = (char *)msg->Buffer - (char *)orpcthis; + msg->BufferLength -= message_state->prefix_data_len; + } + TRACE("-- %ld\n", status); return HRESULT_FROM_WIN32(status); } +static HRESULT WINAPI ServerRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE *olemsg, ULONG *pstatus) +{ + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HANDLE ClientRpcChannelBuffer_GetEventHandle(ClientRpcChannelBuffer *This) +{ + HANDLE event = InterlockedExchangePointer(&This->event, NULL); + + /* Note: must be auto-reset event so we can reuse it without a call + * to ResetEvent */ + if (!event) event = CreateEventW(NULL, FALSE, FALSE, NULL); + + return event; +} + +static void ClientRpcChannelBuffer_ReleaseEventHandle(ClientRpcChannelBuffer *This, HANDLE event) +{ + if (InterlockedCompareExchangePointer(&This->event, event, NULL)) + /* already a handle cached in This */ + CloseHandle(event); +} + /* this thread runs an outgoing RPC */ static DWORD WINAPI rpc_sendreceive_thread(LPVOID param) { struct dispatch_params *data = (struct dispatch_params *) param; - - /* FIXME: trap and rethrow RPC exceptions in app thread */ + + /* Note: I_RpcSendReceive doesn't raise exceptions like the higher-level + * RPC functions do */ data->status = I_RpcSendReceive((RPC_MESSAGE *)data->msg); TRACE("completed with status 0x%lx\n", data->status); - + + SetEvent(data->handle); + return 0; } -static HRESULT WINAPI RpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE *olemsg, ULONG *pstatus) +static inline HRESULT ClientRpcChannelBuffer_IsCorrectApartment(ClientRpcChannelBuffer *This, APARTMENT *apt) { - HRESULT hr = S_OK; + OXID oxid; + if (!apt) + return S_FALSE; + if (apartment_getoxid(apt, &oxid) != S_OK) + return S_FALSE; + if (This->oxid != oxid) + return S_FALSE; + return S_OK; +} + +static HRESULT WINAPI ClientRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE *olemsg, ULONG *pstatus) +{ + ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface; + HRESULT hr; RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg; RPC_STATUS status; DWORD index; struct dispatch_params *params; - DWORD tid; - IRpcStubBuffer *stub; - APARTMENT *apt; + APARTMENT *apt = NULL; IPID ipid; + struct message_state *message_state; + ORPCTHAT orpcthat; + ORPC_EXTENT_ARRAY orpc_ext_array; + WIRE_ORPC_EXTENT *first_wire_orpc_extent = NULL; + HRESULT hrFault = S_OK; - TRACE("(%p) iMethod=%ld\n", olemsg, olemsg->iMethod); + TRACE("(%p) iMethod=%d\n", olemsg, olemsg->iMethod); + + hr = ClientRpcChannelBuffer_IsCorrectApartment(This, COM_CurrentApt()); + if (hr != S_OK) + { + ERR("called from wrong apartment, should have been 0x%s\n", + wine_dbgstr_longlong(This->oxid)); + return RPC_E_WRONG_THREAD; + } + /* this situation should be impossible in multi-threaded apartments, + * because the calling thread isn't re-entrable. + * Note: doing a COM call during the processing of a sent message is + * only disallowed if a client call is already being waited for + * completion */ + if (!COM_CurrentApt()->multi_threaded && + COM_CurrentInfo()->pending_call_count_client && + InSendMessage()) + { + ERR("can't make an outgoing COM call in response to a sent message\n"); + return RPC_E_CANTCALLOUT_ININPUTSYNCCALL; + } params = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*params)); if (!params) return E_OUTOFMEMORY; - + + message_state = (struct message_state *)msg->Handle; + /* restore the binding handle and the real start of data */ + msg->Handle = message_state->binding_handle; + msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len; + msg->BufferLength += message_state->prefix_data_len; + params->msg = olemsg; params->status = RPC_S_OK; params->hr = S_OK; @@ -247,21 +783,31 @@ static HRESULT WINAPI RpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER iface, RPC * a thread to process the RPC when this function is called indirectly * from DllMain */ - RpcBindingInqObject(msg->Handle, &ipid); - stub = ipid_to_apt_and_stubbuffer(&ipid, &apt); - if (apt && (apt->model & COINIT_APARTMENTTHREADED)) + RpcBindingInqObject(message_state->binding_handle, &ipid); + hr = ipid_get_dispatch_params(&ipid, &apt, ¶ms->stub, ¶ms->chan, + ¶ms->iid, ¶ms->iface); + params->handle = ClientRpcChannelBuffer_GetEventHandle(This); + if ((hr == S_OK) && !apt->multi_threaded) { - params->stub = stub; - params->chan = NULL; /* FIXME: pass server channel */ - params->handle = CreateEventW(NULL, FALSE, FALSE, NULL); + TRACE("Calling apartment thread 0x%08x...\n", apt->tid); - TRACE("Calling apartment thread 0x%08lx...\n", apt->tid); - - PostMessageW(apt->win, DM_EXECUTERPC, 0, (LPARAM)params); + if (!PostMessageW(apartment_getwindow(apt), DM_EXECUTERPC, 0, (LPARAM)params)) + { + ERR("PostMessage failed with error %u\n", GetLastError()); + hr = HRESULT_FROM_WIN32(GetLastError()); + } } else { - if (stub) IRpcStubBuffer_Release(stub); + if (hr == S_OK) + { + /* otherwise, we go via RPC runtime so the stub and channel aren't + * needed here */ + IRpcStubBuffer_Release(params->stub); + params->stub = NULL; + IRpcChannelBuffer_Release(params->chan); + params->chan = NULL; + } /* we use a separate thread here because we need to be able to * pump the message loop in the application thread: if we do not, @@ -269,38 +815,87 @@ static HRESULT WINAPI RpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER iface, RPC * and re-enter this STA from an incoming server thread will * deadlock. InstallShield is an example of that. */ - params->handle = CreateThread(NULL, 0, rpc_sendreceive_thread, params, 0, &tid); - if (!params->handle) + if (!QueueUserWorkItem(rpc_sendreceive_thread, params, WT_EXECUTEDEFAULT)) { - ERR("Could not create RpcSendReceive thread, error %lx\n", GetLastError()); + ERR("QueueUserWorkItem failed with error %u\n", GetLastError()); hr = E_UNEXPECTED; } + else + hr = S_OK; } if (apt) apartment_release(apt); if (hr == S_OK) - hr = CoWaitForMultipleHandles(0, INFINITE, 1, ¶ms->handle, &index); - CloseHandle(params->handle); + { + if (WaitForSingleObject(params->handle, 0)) + { + COM_CurrentInfo()->pending_call_count_client++; + hr = CoWaitForMultipleHandles(0, INFINITE, 1, ¶ms->handle, &index); + COM_CurrentInfo()->pending_call_count_client--; + } + } + ClientRpcChannelBuffer_ReleaseEventHandle(This, params->handle); - if (hr == S_OK) hr = params->hr; + /* for WM shortcut, faults are returned in params->hr */ + if (hr == S_OK) + hrFault = params->hr; status = params->status; HeapFree(GetProcessHeap(), 0, params); params = NULL; - if (hr) return hr; - - if (pstatus) *pstatus = status; + orpcthat.flags = ORPCF_NULL; + orpcthat.extensions = NULL; + /* for normal RPC calls, faults are returned in first 4 bytes of the + * buffer */ TRACE("RPC call status: 0x%lx\n", status); - if (status == RPC_S_OK) - hr = S_OK; - else if (status == RPC_S_CALL_FAILED) - hr = *(HRESULT *)olemsg->Buffer; - else + if (status == RPC_S_CALL_FAILED) + hrFault = *(HRESULT *)olemsg->Buffer; + else if (status != RPC_S_OK) hr = HRESULT_FROM_WIN32(status); - TRACE("-- 0x%08lx\n", hr); + TRACE("hrFault = 0x%08x\n", hrFault); + + /* FIXME: this condition should be + * "hr == S_OK && (!hrFault || msg->BufferLength > FIELD_OFFSET(ORPCTHAT, extensions) + 4)" + * but we don't currently reset the message length for PostMessage + * dispatched calls */ + if (hr == S_OK && hrFault == S_OK) + { + HRESULT hr2; + char *original_buffer = msg->Buffer; + + /* handle ORPCTHAT and client extensions */ + + hr2 = unmarshal_ORPCTHAT(msg, &orpcthat, &orpc_ext_array, &first_wire_orpc_extent); + if (FAILED(hr2)) + hr = hr2; + + message_state->prefix_data_len = (char *)msg->Buffer - original_buffer; + msg->BufferLength -= message_state->prefix_data_len; + } + else + message_state->prefix_data_len = 0; + + if (hr == S_OK) + { + ChannelHooks_ClientNotify(&message_state->channel_hook_info, + msg->DataRepresentation, + first_wire_orpc_extent, + orpcthat.extensions && first_wire_orpc_extent ? orpcthat.extensions->size : 0, + hrFault); + } + + /* save away the message state again */ + msg->Handle = message_state; + + if (pstatus) *pstatus = status; + + if (hr == S_OK) + hr = hrFault; + + TRACE("-- 0x%08x\n", hr); return hr; } @@ -309,11 +904,21 @@ static HRESULT WINAPI ServerRpcChannelBuffer_FreeBuffer(LPRPCCHANNELBUFFER iface { RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg; RPC_STATUS status; + struct message_state *message_state; TRACE("(%p)\n", msg); + message_state = (struct message_state *)msg->Handle; + /* restore the binding handle and the real start of data */ + msg->Handle = message_state->binding_handle; + msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len; + msg->BufferLength += message_state->prefix_data_len; + message_state->prefix_data_len = 0; + status = I_RpcFreeBuffer(msg); + msg->Handle = message_state; + TRACE("-- %ld\n", status); return HRESULT_FROM_WIN32(status); @@ -323,20 +928,40 @@ static HRESULT WINAPI ClientRpcChannelBuffer_FreeBuffer(LPRPCCHANNELBUFFER iface { RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg; RPC_STATUS status; + struct message_state *message_state; TRACE("(%p)\n", msg); + message_state = (struct message_state *)msg->Handle; + /* restore the binding handle and the real start of data */ + msg->Handle = message_state->binding_handle; + msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len; + msg->BufferLength += message_state->prefix_data_len; + status = I_RpcFreeBuffer(msg); HeapFree(GetProcessHeap(), 0, msg->RpcInterfaceInformation); msg->RpcInterfaceInformation = NULL; + HeapFree(GetProcessHeap(), 0, message_state); TRACE("-- %ld\n", status); return HRESULT_FROM_WIN32(status); } -static HRESULT WINAPI RpcChannelBuffer_GetDestCtx(LPRPCCHANNELBUFFER iface, DWORD* pdwDestContext, void** ppvDestContext) +static HRESULT WINAPI ClientRpcChannelBuffer_GetDestCtx(LPRPCCHANNELBUFFER iface, DWORD* pdwDestContext, void** ppvDestContext) +{ + ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface; + + TRACE("(%p,%p)\n", pdwDestContext, ppvDestContext); + + *pdwDestContext = This->dest_context; + *ppvDestContext = This->dest_context_data; + + return S_OK; +} + +static HRESULT WINAPI ServerRpcChannelBuffer_GetDestCtx(LPRPCCHANNELBUFFER iface, DWORD* pdwDestContext, void** ppvDestContext) { FIXME("(%p,%p), stub!\n", pdwDestContext, ppvDestContext); return E_FAIL; @@ -355,9 +980,9 @@ static const IRpcChannelBufferVtbl ClientRpcChannelBufferVtbl = RpcChannelBuffer_AddRef, ClientRpcChannelBuffer_Release, ClientRpcChannelBuffer_GetBuffer, - RpcChannelBuffer_SendReceive, + ClientRpcChannelBuffer_SendReceive, ClientRpcChannelBuffer_FreeBuffer, - RpcChannelBuffer_GetDestCtx, + ClientRpcChannelBuffer_GetDestCtx, RpcChannelBuffer_IsConnected }; @@ -367,14 +992,17 @@ static const IRpcChannelBufferVtbl ServerRpcChannelBufferVtbl = RpcChannelBuffer_AddRef, ServerRpcChannelBuffer_Release, ServerRpcChannelBuffer_GetBuffer, - RpcChannelBuffer_SendReceive, + ServerRpcChannelBuffer_SendReceive, ServerRpcChannelBuffer_FreeBuffer, - RpcChannelBuffer_GetDestCtx, + ServerRpcChannelBuffer_GetDestCtx, RpcChannelBuffer_IsConnected }; /* returns a channel buffer for proxies */ -HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid, IRpcChannelBuffer **chan) +HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid, + const OXID_INFO *oxid_info, + DWORD dest_context, void *dest_context_data, + IRpcChannelBuffer **chan) { ClientRpcChannelBuffer *This; WCHAR endpoint[200]; @@ -382,14 +1010,14 @@ HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid, IRpcChannelB RPC_STATUS status; LPWSTR string_binding; - /* connect to the apartment listener thread */ + /* FIXME: get the endpoint from oxid_info->psa instead */ get_rpc_endpoint(endpoint, oxid); TRACE("proxy pipe: connecting to endpoint: %s\n", debugstr_w(endpoint)); status = RpcStringBindingComposeW( NULL, - wszPipeTransport, + wszRpcTransport, NULL, endpoint, NULL, @@ -426,6 +1054,11 @@ HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid, IRpcChannelB This->super.lpVtbl = &ClientRpcChannelBufferVtbl; This->super.refs = 1; This->bind = bind; + apartment_getoxid(COM_CurrentApt(), &This->oxid); + This->server_pid = oxid_info->dwPid; + This->dest_context = dest_context; + This->dest_context_data = dest_context_data; + This->event = NULL; *chan = (IRpcChannelBuffer*)This; @@ -446,68 +1079,344 @@ HRESULT RPC_CreateServerChannel(IRpcChannelBuffer **chan) return S_OK; } +/* unmarshals ORPC_EXTENT_ARRAY according to NDR rules, but doesn't allocate + * any memory */ +static HRESULT unmarshal_ORPC_EXTENT_ARRAY(RPC_MESSAGE *msg, const char *end, + ORPC_EXTENT_ARRAY *extensions, + WIRE_ORPC_EXTENT **first_wire_orpc_extent) +{ + DWORD pointer_id; + DWORD i; + + memcpy(extensions, msg->Buffer, FIELD_OFFSET(ORPC_EXTENT_ARRAY, extent)); + msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(ORPC_EXTENT_ARRAY, extent); + + if ((const char *)msg->Buffer + 2 * sizeof(DWORD) > end) + return RPC_E_INVALID_HEADER; + + pointer_id = *(DWORD *)msg->Buffer; + msg->Buffer = (char *)msg->Buffer + sizeof(DWORD); + extensions->extent = NULL; + + if (pointer_id) + { + WIRE_ORPC_EXTENT *wire_orpc_extent; + + /* conformance */ + if (*(DWORD *)msg->Buffer != ((extensions->size+1)&~1)) + return RPC_S_INVALID_BOUND; + + msg->Buffer = (char *)msg->Buffer + sizeof(DWORD); + + /* arbritary limit for security (don't know what native does) */ + if (extensions->size > 256) + { + ERR("too many extensions: %ld\n", extensions->size); + return RPC_S_INVALID_BOUND; + } + + *first_wire_orpc_extent = wire_orpc_extent = (WIRE_ORPC_EXTENT *)msg->Buffer; + for (i = 0; i < ((extensions->size+1)&~1); i++) + { + if ((const char *)&wire_orpc_extent->data[0] > end) + return RPC_S_INVALID_BOUND; + if (wire_orpc_extent->conformance != ((wire_orpc_extent->size+7)&~7)) + return RPC_S_INVALID_BOUND; + if ((const char *)&wire_orpc_extent->data[wire_orpc_extent->conformance] > end) + return RPC_S_INVALID_BOUND; + TRACE("size %u, guid %s\n", wire_orpc_extent->size, debugstr_guid(&wire_orpc_extent->id)); + wire_orpc_extent = (WIRE_ORPC_EXTENT *)&wire_orpc_extent->data[wire_orpc_extent->conformance]; + } + msg->Buffer = wire_orpc_extent; + } + + return S_OK; +} + +/* unmarshals ORPCTHIS according to NDR rules, but doesn't allocate any memory */ +static HRESULT unmarshal_ORPCTHIS(RPC_MESSAGE *msg, ORPCTHIS *orpcthis, + ORPC_EXTENT_ARRAY *orpc_ext_array, WIRE_ORPC_EXTENT **first_wire_orpc_extent) +{ + const char *end = (char *)msg->Buffer + msg->BufferLength; + + *first_wire_orpc_extent = NULL; + + if (msg->BufferLength < FIELD_OFFSET(ORPCTHIS, extensions) + 4) + { + ERR("invalid buffer length\n"); + return RPC_E_INVALID_HEADER; + } + + memcpy(orpcthis, msg->Buffer, FIELD_OFFSET(ORPCTHIS, extensions)); + msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(ORPCTHIS, extensions); + + if ((const char *)msg->Buffer + sizeof(DWORD) > end) + return RPC_E_INVALID_HEADER; + + if (*(DWORD *)msg->Buffer) + orpcthis->extensions = orpc_ext_array; + else + orpcthis->extensions = NULL; + + msg->Buffer = (char *)msg->Buffer + sizeof(DWORD); + + if (orpcthis->extensions) + { + HRESULT hr = unmarshal_ORPC_EXTENT_ARRAY(msg, end, orpc_ext_array, + first_wire_orpc_extent); + if (FAILED(hr)) + return hr; + } + + if ((orpcthis->version.MajorVersion != COM_MAJOR_VERSION) || + (orpcthis->version.MinorVersion > COM_MINOR_VERSION)) + { + ERR("COM version {%d, %d} not supported\n", + orpcthis->version.MajorVersion, orpcthis->version.MinorVersion); + return RPC_E_VERSION_MISMATCH; + } + + if (orpcthis->flags & ~(ORPCF_LOCAL|ORPCF_RESERVED1|ORPCF_RESERVED2|ORPCF_RESERVED3|ORPCF_RESERVED4)) + { + ERR("invalid flags 0x%lx\n", orpcthis->flags & ~(ORPCF_LOCAL|ORPCF_RESERVED1|ORPCF_RESERVED2|ORPCF_RESERVED3|ORPCF_RESERVED4)); + return RPC_E_INVALID_HEADER; + } + + return S_OK; +} + +static HRESULT unmarshal_ORPCTHAT(RPC_MESSAGE *msg, ORPCTHAT *orpcthat, + ORPC_EXTENT_ARRAY *orpc_ext_array, WIRE_ORPC_EXTENT **first_wire_orpc_extent) +{ + const char *end = (char *)msg->Buffer + msg->BufferLength; + + *first_wire_orpc_extent = NULL; + + if (msg->BufferLength < FIELD_OFFSET(ORPCTHAT, extensions) + 4) + { + ERR("invalid buffer length\n"); + return RPC_E_INVALID_HEADER; + } + + memcpy(orpcthat, msg->Buffer, FIELD_OFFSET(ORPCTHAT, extensions)); + msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(ORPCTHAT, extensions); + + if ((const char *)msg->Buffer + sizeof(DWORD) > end) + return RPC_E_INVALID_HEADER; + + if (*(DWORD *)msg->Buffer) + orpcthat->extensions = orpc_ext_array; + else + orpcthat->extensions = NULL; + + msg->Buffer = (char *)msg->Buffer + sizeof(DWORD); + + if (orpcthat->extensions) + { + HRESULT hr = unmarshal_ORPC_EXTENT_ARRAY(msg, end, orpc_ext_array, + first_wire_orpc_extent); + if (FAILED(hr)) + return hr; + } + + if (orpcthat->flags & ~(ORPCF_LOCAL|ORPCF_RESERVED1|ORPCF_RESERVED2|ORPCF_RESERVED3|ORPCF_RESERVED4)) + { + ERR("invalid flags 0x%lx\n", orpcthat->flags & ~(ORPCF_LOCAL|ORPCF_RESERVED1|ORPCF_RESERVED2|ORPCF_RESERVED3|ORPCF_RESERVED4)); + return RPC_E_INVALID_HEADER; + } + + return S_OK; +} void RPC_ExecuteCall(struct dispatch_params *params) { - __TRY + struct message_state *message_state = NULL; + RPC_MESSAGE *msg = (RPC_MESSAGE *)params->msg; + char *original_buffer = msg->Buffer; + ORPCTHIS orpcthis; + ORPC_EXTENT_ARRAY orpc_ext_array; + WIRE_ORPC_EXTENT *first_wire_orpc_extent; + GUID old_causality_id; + + /* handle ORPCTHIS and server extensions */ + + params->hr = unmarshal_ORPCTHIS(msg, &orpcthis, &orpc_ext_array, &first_wire_orpc_extent); + if (params->hr != S_OK) { - params->hr = IRpcStubBuffer_Invoke(params->stub, params->msg, params->chan); + msg->Buffer = original_buffer; + goto exit; } - __EXCEPT(ole_filter) + + message_state = HeapAlloc(GetProcessHeap(), 0, sizeof(*message_state)); + if (!message_state) { - params->hr = GetExceptionCode(); + params->hr = E_OUTOFMEMORY; + msg->Buffer = original_buffer; + goto exit; } - __ENDTRY + + message_state->prefix_data_len = (char *)msg->Buffer - original_buffer; + message_state->binding_handle = msg->Handle; + + message_state->channel_hook_info.iid = params->iid; + message_state->channel_hook_info.cbSize = sizeof(message_state->channel_hook_info); + message_state->channel_hook_info.uCausality = orpcthis.cid; + message_state->channel_hook_info.dwServerPid = GetCurrentProcessId(); + message_state->channel_hook_info.iMethod = msg->ProcNum; + message_state->channel_hook_info.pObject = params->iface; + + if (orpcthis.extensions && first_wire_orpc_extent && + orpcthis.extensions->size) + ChannelHooks_ServerNotify(&message_state->channel_hook_info, msg->DataRepresentation, first_wire_orpc_extent, orpcthis.extensions->size); + + msg->Handle = message_state; + msg->BufferLength -= message_state->prefix_data_len; + + /* call message filter */ + + if (COM_CurrentApt()->filter) + { + DWORD handlecall; + INTERFACEINFO interface_info; + CALLTYPE calltype; + + interface_info.pUnk = params->iface; + interface_info.iid = params->iid; + interface_info.wMethod = msg->ProcNum; + + if (IsEqualGUID(&orpcthis.cid, &COM_CurrentInfo()->causality_id)) + calltype = CALLTYPE_NESTED; + else if (COM_CurrentInfo()->pending_call_count_server == 0) + calltype = CALLTYPE_TOPLEVEL; + else + calltype = CALLTYPE_TOPLEVEL_CALLPENDING; + + handlecall = IMessageFilter_HandleInComingCall(COM_CurrentApt()->filter, + calltype, + (HTASK)GetCurrentProcessId(), + 0 /* FIXME */, + &interface_info); + TRACE("IMessageFilter_HandleInComingCall returned %d\n", handlecall); + switch (handlecall) + { + case SERVERCALL_REJECTED: + params->hr = RPC_E_CALL_REJECTED; + goto exit_reset_state; + case SERVERCALL_RETRYLATER: +#if 0 /* FIXME: handle retries on the client side before enabling this code */ + params->hr = RPC_E_RETRY; + goto exit_reset_state; +#else + FIXME("retry call later not implemented\n"); + break; +#endif + case SERVERCALL_ISHANDLED: + default: + break; + } + } + + /* invoke the method */ + + /* save the old causality ID - note: any calls executed while processing + * messages received during the SendReceive will appear to originate from + * this call - this should be checked with what Windows does */ + old_causality_id = COM_CurrentInfo()->causality_id; + COM_CurrentInfo()->causality_id = orpcthis.cid; + COM_CurrentInfo()->pending_call_count_server++; + params->hr = IRpcStubBuffer_Invoke(params->stub, params->msg, params->chan); + COM_CurrentInfo()->pending_call_count_server--; + COM_CurrentInfo()->causality_id = old_causality_id; + +exit_reset_state: + message_state = (struct message_state *)msg->Handle; + msg->Handle = message_state->binding_handle; + msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len; + msg->BufferLength += message_state->prefix_data_len; + +exit: + HeapFree(GetProcessHeap(), 0, message_state); IRpcStubBuffer_Release(params->stub); + IRpcChannelBuffer_Release(params->chan); if (params->handle) SetEvent(params->handle); } static void __RPC_STUB dispatch_rpc(RPC_MESSAGE *msg) { struct dispatch_params *params; - IRpcStubBuffer *stub; - APARTMENT *apt; - IPID ipid; + APARTMENT *apt; + IPID ipid; + HRESULT hr; RpcBindingInqObject(msg->Handle, &ipid); TRACE("ipid = %s, iMethod = %d\n", debugstr_guid(&ipid), msg->ProcNum); - params = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*params)); - if (!params) return RpcRaiseException(E_OUTOFMEMORY); - - stub = ipid_to_apt_and_stubbuffer(&ipid, &apt); - if (!apt || !stub) + params = HeapAlloc(GetProcessHeap(), 0, sizeof(*params)); + if (!params) + { + RpcRaiseException(E_OUTOFMEMORY); + return; + } + + hr = ipid_get_dispatch_params(&ipid, &apt, ¶ms->stub, ¶ms->chan, + ¶ms->iid, ¶ms->iface); + if (hr != S_OK) { - if (apt) apartment_release(apt); ERR("no apartment found for ipid %s\n", debugstr_guid(&ipid)); - return RpcRaiseException(RPC_E_DISCONNECTED); + HeapFree(GetProcessHeap(), 0, params); + RpcRaiseException(hr); + return; } params->msg = (RPCOLEMESSAGE *)msg; - params->stub = stub; - params->chan = NULL; /* FIXME: pass server channel */ params->status = RPC_S_OK; + params->hr = S_OK; + params->handle = NULL; /* Note: this is the important difference between STAs and MTAs - we * always execute RPCs to STAs in the thread that originally created the * apartment (i.e. the one that pumps messages to the window) */ - if (apt->model & COINIT_APARTMENTTHREADED) + if (!apt->multi_threaded) { params->handle = CreateEventW(NULL, FALSE, FALSE, NULL); - TRACE("Calling apartment thread 0x%08lx...\n", apt->tid); + TRACE("Calling apartment thread 0x%08x...\n", apt->tid); - PostMessageW(apt->win, DM_EXECUTERPC, 0, (LPARAM)params); - WaitForSingleObject(params->handle, INFINITE); + if (PostMessageW(apartment_getwindow(apt), DM_EXECUTERPC, 0, (LPARAM)params)) + WaitForSingleObject(params->handle, INFINITE); + else + { + ERR("PostMessage failed with error %u\n", GetLastError()); + IRpcChannelBuffer_Release(params->chan); + IRpcStubBuffer_Release(params->stub); + } CloseHandle(params->handle); } else + { + BOOL joined = FALSE; + if (!COM_CurrentInfo()->apt) + { + apartment_joinmta(); + joined = TRUE; + } RPC_ExecuteCall(params); + if (joined) + { + apartment_release(COM_CurrentInfo()->apt); + COM_CurrentInfo()->apt = NULL; + } + } + hr = params->hr; HeapFree(GetProcessHeap(), 0, params); apartment_release(apt); + + /* if IRpcStubBuffer_Invoke fails, we should raise an exception to tell + * the RPC runtime that the call failed */ + if (hr) RpcRaiseException(hr); } /* stub registration */ @@ -578,12 +1487,9 @@ void RPC_UnregisterInterface(REFIID riid) { if (!--rif->refs) { -#if 0 /* this is a stub in builtin and spams the console with FIXME's */ - IID iid = *riid; /* RpcServerUnregisterIf doesn't take const IID */ - RpcServerUnregisterIf((RPC_IF_HANDLE)&rif->If, &iid, 0); + RpcServerUnregisterIf((RPC_IF_HANDLE)&rif->If, NULL, TRUE); list_remove(&rif->entry); HeapFree(GetProcessHeap(), 0, rif); -#endif } break; } @@ -591,6 +1497,27 @@ void RPC_UnregisterInterface(REFIID riid) LeaveCriticalSection(&csRegIf); } +/* get the info for an OXID, including the IPID for the rem unknown interface + * and the string binding */ +HRESULT RPC_ResolveOxid(OXID oxid, OXID_INFO *oxid_info) +{ + TRACE("%s\n", wine_dbgstr_longlong(oxid)); + + oxid_info->dwTid = 0; + oxid_info->dwPid = 0; + oxid_info->dwAuthnHint = RPC_C_AUTHN_LEVEL_NONE; + /* FIXME: this is a hack around not having an OXID resolver yet - + * this function should contact the machine's OXID resolver and then it + * should give us the IPID of the IRemUnknown interface */ + oxid_info->ipidRemUnknown.Data1 = 0xffffffff; + oxid_info->ipidRemUnknown.Data2 = 0xffff; + oxid_info->ipidRemUnknown.Data3 = 0xffff; + memcpy(&oxid_info->ipidRemUnknown.Data4, &oxid, sizeof(OXID)); + oxid_info->psa = NULL /* FIXME */; + + return S_OK; +} + /* make the apartment reachable by other threads and processes and create the * IRemUnknown object */ void RPC_StartRemoting(struct apartment *apt) @@ -603,7 +1530,7 @@ void RPC_StartRemoting(struct apartment *apt) get_rpc_endpoint(endpoint, &apt->oxid); status = RpcServerUseProtseqEpW( - wszPipeTransport, + wszRpcTransport, RPC_C_PROTSEQ_MAX_REQS_DEFAULT, endpoint, NULL); @@ -664,20 +1591,20 @@ static HRESULT create_server(REFCLSID rclsid) /* * start_local_service() - start a service given its name and parameters */ -static DWORD start_local_service(LPCWSTR name, DWORD num, LPWSTR *params) +static DWORD start_local_service(LPCWSTR name, DWORD num, LPCWSTR *params) { SC_HANDLE handle, hsvc; DWORD r = ERROR_FUNCTION_FAILED; - TRACE("Starting service %s %ld params\n", debugstr_w(name), num); + TRACE("Starting service %s %d params\n", debugstr_w(name), num); - handle = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS); + handle = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT); if (!handle) return r; - hsvc = OpenServiceW(handle, name, SC_MANAGER_ALL_ACCESS); + hsvc = OpenServiceW(handle, name, SERVICE_START); if (hsvc) { - if(StartServiceW(hsvc, num, (LPCWSTR*)params)) + if(StartServiceW(hsvc, num, params)) r = ERROR_SUCCESS; else r = GetLastError(); @@ -685,9 +1612,11 @@ static DWORD start_local_service(LPCWSTR name, DWORD num, LPWSTR *params) r = ERROR_SUCCESS; CloseServiceHandle(hsvc); } + else + r = GetLastError(); CloseServiceHandle(handle); - TRACE("StartService returned error %ld (%s)\n", r, r?"ok":"failed"); + TRACE("StartService returned error %u (%s)\n", r, (r == ERROR_SUCCESS) ? "ok":"failed"); return r; } @@ -704,9 +1633,7 @@ static DWORD start_local_service(LPCWSTR name, DWORD num, LPWSTR *params) static HRESULT create_local_service(REFCLSID rclsid) { HRESULT hres; - WCHAR buf[CHARS_IN_GUID], keyname[50]; - static const WCHAR szAppId[] = { 'A','p','p','I','d',0 }; - static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 }; + WCHAR buf[CHARS_IN_GUID]; static const WCHAR szLocalService[] = { 'L','o','c','a','l','S','e','r','v','i','c','e',0 }; static const WCHAR szServiceParams[] = {'S','e','r','v','i','c','e','P','a','r','a','m','s',0}; HKEY hkey; @@ -715,22 +1642,11 @@ static HRESULT create_local_service(REFCLSID rclsid) TRACE("Attempting to start Local service for %s\n", debugstr_guid(rclsid)); - /* read the AppID value under the class's key */ - hres = COM_OpenKeyForCLSID(rclsid, szAppId, KEY_READ, &hkey); + hres = COM_OpenKeyForAppIdFromCLSID(rclsid, KEY_READ, &hkey); if (FAILED(hres)) return hres; - sz = sizeof buf; - r = RegQueryValueExW(hkey, NULL, NULL, &type, (LPBYTE)buf, &sz); - RegCloseKey(hkey); - if (r!=ERROR_SUCCESS || type!=REG_SZ) - return hres; /* read the LocalService and ServiceParameters values from the AppID key */ - strcpyW(keyname, szAppIdKey); - strcatW(keyname, buf); - r = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &hkey); - if (r!=ERROR_SUCCESS) - return hres; sz = sizeof buf; r = RegQueryValueExW(hkey, szLocalService, NULL, &type, (LPBYTE)buf, &sz); if (r==ERROR_SUCCESS && type==REG_SZ) @@ -753,13 +1669,18 @@ static HRESULT create_local_service(REFCLSID rclsid) num_args++; RegQueryValueExW(hkey, szServiceParams, NULL, &type, (LPBYTE)args[0], &sz); } - r = start_local_service(buf, num_args, args); - if (r==ERROR_SUCCESS) - hres = S_OK; + r = start_local_service(buf, num_args, (LPCWSTR *)args); + if (r != ERROR_SUCCESS) + hres = REGDB_E_CLASSNOTREG; /* FIXME: check retval */ HeapFree(GetProcessHeap(),0,args[0]); } + else + { + WARN("No LocalService value\n"); + hres = REGDB_E_CLASSNOTREG; /* FIXME: check retval */ + } RegCloseKey(hkey); - + return hres; } @@ -797,12 +1718,12 @@ HRESULT RPC_GetLocalClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv) hPipe = CreateFileW(pipefn, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); if (hPipe == INVALID_HANDLE_VALUE) { if (tries == 1) { - if ( (hres = create_server(rclsid)) && - (hres = create_local_service(rclsid)) ) + if ( (hres = create_local_service(rclsid)) && + (hres = create_server(rclsid)) ) return hres; Sleep(1000); } else { - WARN("Connecting to %s, no response yet, retrying: le is %lx\n", debugstr_w(pipefn), GetLastError()); + WARN("Connecting to %s, no response yet, retrying: le is %u\n", debugstr_w(pipefn), GetLastError()); Sleep(1000); } continue; @@ -840,6 +1761,9 @@ struct local_server_params { CLSID clsid; IStream *stream; + HANDLE ready_event; + BOOL multi_use; + HANDLE pipe; }; /* FIXME: should call to rpcss instead */ @@ -856,27 +1780,43 @@ static DWORD WINAPI local_server_thread(LPVOID param) LARGE_INTEGER seekto; ULARGE_INTEGER newpos; ULONG res; + BOOL multi_use = lsp->multi_use; TRACE("Starting threader for %s.\n",debugstr_guid(&lsp->clsid)); get_localserver_pipe_name(pipefn, &lsp->clsid); - HeapFree(GetProcessHeap(), 0, lsp); - hPipe = CreateNamedPipeW( pipefn, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 4096, 4096, 500 /* 0.5 second timeout */, NULL ); - + + lsp->pipe = hPipe; + SetEvent(lsp->ready_event); + + HeapFree(GetProcessHeap(), 0, lsp); + if (hPipe == INVALID_HANDLE_VALUE) { - FIXME("pipe creation failed for %s, le is %ld\n", debugstr_w(pipefn), GetLastError()); + FIXME("pipe creation failed for %s, le is %u\n", debugstr_w(pipefn), GetLastError()); return 1; } while (1) { - if (!ConnectNamedPipe(hPipe,NULL)) { - ERR("Failure during ConnectNamedPipe %ld, ABORT!\n",GetLastError()); - break; + if (!ConnectNamedPipe(hPipe,NULL)) + { + DWORD error = GetLastError(); + /* client already connected isn't an error */ + if (error != ERROR_PIPE_CONNECTED) + { + /* if error wasn't caused by RPC_StopLocalServer closing the + * pipe for us */ + if (error != ERROR_INVALID_HANDLE) + { + ERR("Failure during ConnectNamedPipe %u\n", error); + CloseHandle(hPipe); + } + break; + } } TRACE("marshalling IClassFactory to client\n"); @@ -884,43 +1824,71 @@ static DWORD WINAPI local_server_thread(LPVOID param) hres = IStream_Stat(pStm,&ststg,0); if (hres) return hres; - buflen = ststg.cbSize.u.LowPart; - buffer = HeapAlloc(GetProcessHeap(),0,buflen); seekto.u.LowPart = 0; seekto.u.HighPart = 0; hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos); if (hres) { - FIXME("IStream_Seek failed, %lx\n",hres); + FIXME("IStream_Seek failed, %x\n",hres); return hres; } + + buflen = ststg.cbSize.u.LowPart; + buffer = HeapAlloc(GetProcessHeap(),0,buflen); hres = IStream_Read(pStm,buffer,buflen,&res); if (hres) { - FIXME("Stream Read failed, %lx\n",hres); + FIXME("Stream Read failed, %x\n",hres); + HeapFree(GetProcessHeap(),0,buffer); return hres; } WriteFile(hPipe,buffer,buflen,&res,NULL); + HeapFree(GetProcessHeap(),0,buffer); + FlushFileBuffers(hPipe); DisconnectNamedPipe(hPipe); TRACE("done marshalling IClassFactory\n"); + + if (!multi_use) + { + TRACE("single use object, shutting down pipe %s\n", debugstr_w(pipefn)); + CloseHandle(hPipe); + break; + } } - CloseHandle(hPipe); IStream_Release(pStm); return 0; } -void RPC_StartLocalServer(REFCLSID clsid, IStream *stream) +/* starts listening for a local server */ +HRESULT RPC_StartLocalServer(REFCLSID clsid, IStream *stream, BOOL multi_use, void **registration) { DWORD tid; - HANDLE thread; + HANDLE thread, ready_event; struct local_server_params *lsp = HeapAlloc(GetProcessHeap(), 0, sizeof(*lsp)); lsp->clsid = *clsid; lsp->stream = stream; + IStream_AddRef(stream); + lsp->ready_event = ready_event = CreateEventW(NULL, FALSE, FALSE, NULL); + lsp->multi_use = multi_use; thread = CreateThread(NULL, 0, local_server_thread, lsp, 0, &tid); + if (!thread) + return HRESULT_FROM_WIN32(GetLastError()); CloseHandle(thread); - /* FIXME: failure handling */ + + WaitForSingleObject(ready_event, INFINITE); + CloseHandle(ready_event); + + *registration = lsp->pipe; + return S_OK; +} + +/* stops listening for a local server */ +void RPC_StopLocalServer(void *registration) +{ + HANDLE pipe = registration; + CloseHandle(pipe); } diff --git a/reactos/dll/win32/ole32/stg_bigblockfile.c b/reactos/dll/win32/ole32/stg_bigblockfile.c index 57123c9a85e..4f22207edbc 100644 --- a/reactos/dll/win32/ole32/stg_bigblockfile.c +++ b/reactos/dll/win32/ole32/stg_bigblockfile.c @@ -28,7 +28,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include @@ -91,6 +91,7 @@ struct MappedPage MappedPage *prev; DWORD page_index; + DWORD mapped_bytes; LPVOID lpBytes; LONG refcnt; @@ -108,16 +109,12 @@ static void BIGBLOCKFILE_ReleaseMappedPage(LPBIGBLOCKFILE This, static void BIGBLOCKFILE_FreeAllMappedPages(LPBIGBLOCKFILE This); static void BIGBLOCKFILE_UnmapAllMappedPages(LPBIGBLOCKFILE This); static void BIGBLOCKFILE_RemapAllMappedPages(LPBIGBLOCKFILE This); -static void* BIGBLOCKFILE_GetBigBlockPointer(LPBIGBLOCKFILE This, - ULONG index, - DWORD desired_access); -static MappedPage* BIGBLOCKFILE_GetPageFromPointer(LPBIGBLOCKFILE This, - void* pBlock); static MappedPage* BIGBLOCKFILE_CreatePage(LPBIGBLOCKFILE This, ULONG page_index); static DWORD BIGBLOCKFILE_GetProtectMode(DWORD openFlags); static BOOL BIGBLOCKFILE_FileInit(LPBIGBLOCKFILE This, HANDLE hFile); static BOOL BIGBLOCKFILE_MemInit(LPBIGBLOCKFILE This, ILockBytes* plkbyt); +static void BIGBLOCKFILE_DeleteList(LPBIGBLOCKFILE This, MappedPage *list); /* Note that this evaluates a and b multiple times, so don't * pass expressions with side effects. */ @@ -248,7 +245,7 @@ static BOOL BIGBLOCKFILE_FileInit(LPBIGBLOCKFILE This, HANDLE hFile) This->maplist = NULL; - TRACE("file len %lu\n", This->filesize.u.LowPart); + TRACE("file len %u\n", This->filesize.u.LowPart); return TRUE; } @@ -285,7 +282,7 @@ static BOOL BIGBLOCKFILE_MemInit(LPBIGBLOCKFILE This, ILockBytes* plkbyt) This->pbytearray = GlobalLock(This->hbytearray); - TRACE("mem on %p len %lu\n", This->pbytearray, This->filesize.u.LowPart); + TRACE("mem on %p len %u\n", This->pbytearray, This->filesize.u.LowPart); return TRUE; } @@ -317,46 +314,11 @@ void BIGBLOCKFILE_Destructor( } /****************************************************************************** - * BIGBLOCKFILE_GetROBigBlock + * BIGBLOCKFILE_EnsureExists * - * Returns the specified block in read only mode. - * Will return NULL if the block doesn't exists. + * Grows the file if necessary to make sure the block is valid. */ -void* BIGBLOCKFILE_GetROBigBlock( - LPBIGBLOCKFILE This, - ULONG index) -{ - /* - * block index starts at -1 - * translate to zero based index - */ - if (index == 0xffffffff) - index = 0; - else - index++; - - /* - * validate the block index - * - */ - if (This->blocksize * (index + 1) - > ROUND_UP(This->filesize.u.LowPart, This->blocksize)) - { - TRACE("out of range %lu vs %lu\n", This->blocksize * (index + 1), - This->filesize.u.LowPart); - return NULL; - } - - return BIGBLOCKFILE_GetBigBlockPointer(This, index, FILE_MAP_READ); -} - -/****************************************************************************** - * BIGBLOCKFILE_GetBigBlock - * - * Returns the specified block. - * Will grow the file if necessary. - */ -void* BIGBLOCKFILE_GetBigBlock(LPBIGBLOCKFILE This, ULONG index) +void BIGBLOCKFILE_EnsureExists(LPBIGBLOCKFILE This, ULONG index) { /* * block index starts at -1 @@ -379,28 +341,6 @@ void* BIGBLOCKFILE_GetBigBlock(LPBIGBLOCKFILE This, ULONG index) BIGBLOCKFILE_SetSize(This, newSize); } - - return BIGBLOCKFILE_GetBigBlockPointer(This, index, FILE_MAP_WRITE); -} - -/****************************************************************************** - * BIGBLOCKFILE_ReleaseBigBlock - * - * Releases the specified block. - */ -void BIGBLOCKFILE_ReleaseBigBlock(LPBIGBLOCKFILE This, void *pBlock) -{ - MappedPage *page; - - if (pBlock == NULL) - return; - - page = BIGBLOCKFILE_GetPageFromPointer(This, pBlock); - - if (page == NULL) - return; - - BIGBLOCKFILE_ReleaseMappedPage(This, page); } /****************************************************************************** @@ -414,57 +354,40 @@ void BIGBLOCKFILE_SetSize(LPBIGBLOCKFILE This, ULARGE_INTEGER newSize) if (This->filesize.u.LowPart == newSize.u.LowPart) return; - TRACE("from %lu to %lu\n", This->filesize.u.LowPart, newSize.u.LowPart); + TRACE("from %u to %u\n", This->filesize.u.LowPart, newSize.u.LowPart); /* * unmap all views, must be done before call to SetEndFile + * + * Just ditch the victim list because there is no guarentee we will need them + * and it is not worth the performance hit to unmap and remap them all. */ + BIGBLOCKFILE_DeleteList(This, This->victimhead); + This->victimhead = NULL; + This->victimtail = NULL; + This->num_victim_pages = 0; + BIGBLOCKFILE_UnmapAllMappedPages(This); if (This->fileBased) { - char buf[10]; - DWORD w; + LARGE_INTEGER newpos; - /* - * close file-mapping object, must be done before call to SetEndFile - */ - if( This->hfilemap ) - CloseHandle(This->hfilemap); - This->hfilemap = 0; + newpos.QuadPart = newSize.QuadPart; + if (SetFilePointerEx(This->hfile, newpos, NULL, FILE_BEGIN)) + { + if( This->hfilemap ) CloseHandle(This->hfilemap); - /* - * BEGIN HACK - * This fixes a bug when saving through smbfs. - * smbmount a Windows shared directory, save a structured storage file - * to that dir: crash. - * - * The problem is that the SetFilePointer-SetEndOfFile combo below - * doesn't always succeed. The file is not grown. It seems like the - * operation is cached. By doing the WriteFile, the file is actually - * grown on disk. - * This hack is only needed when saving to smbfs. - */ - memset(buf, '0', 10); - SetFilePointer(This->hfile, newSize.u.LowPart, NULL, FILE_BEGIN); - WriteFile(This->hfile, buf, 10, &w, NULL); - /* - * END HACK - */ + SetEndOfFile(This->hfile); - /* - * set the new end of file - */ - SetFilePointer(This->hfile, newSize.u.LowPart, NULL, FILE_BEGIN); - SetEndOfFile(This->hfile); - - /* - * re-create the file mapping object - */ - This->hfilemap = CreateFileMappingA(This->hfile, - NULL, - This->flProtect, - 0, 0, - NULL); + /* + * re-create the file mapping object + */ + This->hfilemap = CreateFileMappingA(This->hfile, + NULL, + This->flProtect, + 0, 0, + NULL); + } } else { @@ -499,85 +422,6 @@ ULARGE_INTEGER BIGBLOCKFILE_GetSize(LPBIGBLOCKFILE This) return This->filesize; } -/****************************************************************************** - * BIGBLOCKFILE_AccessCheck [PRIVATE] - * - * block_index is the index within the page. - */ -static BOOL BIGBLOCKFILE_AccessCheck(MappedPage *page, ULONG block_index, - DWORD desired_access) -{ - assert(block_index < BLOCKS_PER_PAGE); - - if (desired_access == FILE_MAP_READ) - { - if (BIGBLOCKFILE_TestBit(&page->writable_blocks, block_index)) - return FALSE; - - BIGBLOCKFILE_SetBit(&page->readable_blocks, block_index); - } - else - { - assert(desired_access == FILE_MAP_WRITE); - - if (BIGBLOCKFILE_TestBit(&page->readable_blocks, block_index)) - return FALSE; - - BIGBLOCKFILE_SetBit(&page->writable_blocks, block_index); - } - - return TRUE; -} - -/****************************************************************************** - * BIGBLOCKFILE_GetBigBlockPointer [PRIVATE] - * - * Returns a pointer to the specified block. - */ -static void* BIGBLOCKFILE_GetBigBlockPointer( - LPBIGBLOCKFILE This, - ULONG block_index, - DWORD desired_access) -{ - DWORD page_index = block_index / BLOCKS_PER_PAGE; - DWORD block_on_page = block_index % BLOCKS_PER_PAGE; - - MappedPage *page = BIGBLOCKFILE_GetMappedView(This, page_index); - if (!page || !page->lpBytes) return NULL; - - if (!BIGBLOCKFILE_AccessCheck(page, block_on_page, desired_access)) - { - BIGBLOCKFILE_ReleaseMappedPage(This, page); - return NULL; - } - - return (LPBYTE)page->lpBytes + (block_on_page * This->blocksize); -} - -/****************************************************************************** - * BIGBLOCKFILE_GetMappedPageFromPointer [PRIVATE] - * - * pBlock is a pointer to a block on a page. - * The page has to be on the in-use list. (As oppsed to the victim list.) - * - * Does not increment the usage count. - */ -static MappedPage *BIGBLOCKFILE_GetPageFromPointer(LPBIGBLOCKFILE This, - void *pBlock) -{ - MappedPage *page; - - for (page = This->maplist; page != NULL; page = page->next) - { - if ((LPBYTE)pBlock >= (LPBYTE)page->lpBytes - && (LPBYTE)pBlock <= (LPBYTE)page->lpBytes + PAGE_SIZE) - break; - - } - - return page; -} - /****************************************************************************** * BIGBLOCKFILE_FindPageInList [PRIVATE] * @@ -686,13 +530,15 @@ static BOOL BIGBLOCKFILE_MapPage(LPBIGBLOCKFILE This, MappedPage *page) page->lpBytes = MapViewOfFile(This->hfilemap, desired_access, 0, lowoffset, numBytesToMap); + page->mapped_bytes = numBytesToMap; } else { page->lpBytes = (LPBYTE)This->pbytearray + lowoffset; + page->mapped_bytes = PAGE_SIZE; } - TRACE("mapped page %lu to %p\n", page->page_index, page->lpBytes); + TRACE("mapped page %u to %p\n", page->page_index, page->lpBytes); return page->lpBytes != NULL; } @@ -712,7 +558,11 @@ static MappedPage *BIGBLOCKFILE_CreatePage(LPBIGBLOCKFILE This, page->next = NULL; page->prev = NULL; - BIGBLOCKFILE_MapPage(This, page); + if (!BIGBLOCKFILE_MapPage(This, page)) + { + HeapFree(GetProcessHeap(),0,page); + return NULL; + } BIGBLOCKFILE_Zero(&page->readable_blocks); BIGBLOCKFILE_Zero(&page->writable_blocks); @@ -722,7 +572,7 @@ static MappedPage *BIGBLOCKFILE_CreatePage(LPBIGBLOCKFILE This, static void BIGBLOCKFILE_UnmapPage(LPBIGBLOCKFILE This, MappedPage *page) { - TRACE("%ld at %p\n", page->page_index, page->lpBytes); + TRACE("%d at %p\n", page->page_index, page->lpBytes); if (page->refcnt > 0) ERR("unmapping inuse page %p\n", page->lpBytes); @@ -836,7 +686,7 @@ static void BIGBLOCKFILE_RemapList(LPBIGBLOCKFILE This, MappedPage *list) if (list->page_index * PAGE_SIZE > This->filesize.u.LowPart) { - TRACE("discarding %lu\n", list->page_index); + TRACE("discarding %u\n", list->page_index); /* page is entirely outside of the file, delete it */ BIGBLOCKFILE_UnlinkPage(list); @@ -874,3 +724,206 @@ static DWORD BIGBLOCKFILE_GetProtectMode(DWORD openFlags) } return PAGE_READONLY; } + + +/* ILockByte Interfaces */ + +/****************************************************************************** + * This method is part of the ILockBytes interface. + * + * It reads a block of information from the byte array at the specified + * offset. + * + * See the documentation of ILockBytes for more info. + */ +static HRESULT WINAPI ImplBIGBLOCKFILE_ReadAt( + BigBlockFile* const This, + ULARGE_INTEGER ulOffset, /* [in] */ + void* pv, /* [length_is][size_is][out] */ + ULONG cb, /* [in] */ + ULONG* pcbRead) /* [out] */ +{ + ULONG first_page = ulOffset.u.LowPart / PAGE_SIZE; + ULONG offset_in_page = ulOffset.u.LowPart % PAGE_SIZE; + ULONG bytes_left = cb; + ULONG page_index = first_page; + ULONG bytes_from_page; + LPVOID writePtr = pv; + + HRESULT rc = S_OK; + + TRACE("(%p)-> %i %p %i %p\n",This, ulOffset.u.LowPart, pv, cb, pcbRead); + + /* verify a sane environment */ + if (!This) return E_FAIL; + + if (offset_in_page + bytes_left > PAGE_SIZE) + bytes_from_page = PAGE_SIZE - offset_in_page; + else + bytes_from_page = bytes_left; + + if (pcbRead) + *pcbRead = 0; + + while (bytes_left) + { + LPBYTE readPtr; + BOOL eof = FALSE; + MappedPage *page = BIGBLOCKFILE_GetMappedView(This, page_index); + + if (!page || !page->lpBytes) + { + rc = STG_E_READFAULT; + break; + } + + TRACE("page %i, offset %u, bytes_from_page %u, bytes_left %u\n", + page->page_index, offset_in_page, bytes_from_page, bytes_left); + + if (page->mapped_bytes < bytes_from_page) + { + eof = TRUE; + bytes_from_page = page->mapped_bytes; + } + + readPtr = (BYTE*)page->lpBytes + offset_in_page; + memcpy(writePtr,readPtr,bytes_from_page); + BIGBLOCKFILE_ReleaseMappedPage(This, page); + + if (pcbRead) + *pcbRead += bytes_from_page; + bytes_left -= bytes_from_page; + + if (bytes_left && !eof) + { + writePtr = (LPBYTE)writePtr + bytes_from_page; + page_index ++; + offset_in_page = 0; + if (bytes_left > PAGE_SIZE) + bytes_from_page = PAGE_SIZE; + else + bytes_from_page = bytes_left; + } + if (eof) + { + rc = STG_E_READFAULT; + break; + } + } + + TRACE("finished\n"); + return rc; +} + +/****************************************************************************** + * This method is part of the ILockBytes interface. + * + * It writes the specified bytes at the specified offset. + * position. If the file is too small, it will be resized. + * + * See the documentation of ILockBytes for more info. + */ +static HRESULT WINAPI ImplBIGBLOCKFILE_WriteAt( + BigBlockFile* const This, + ULARGE_INTEGER ulOffset, /* [in] */ + const void* pv, /* [size_is][in] */ + ULONG cb, /* [in] */ + ULONG* pcbWritten) /* [out] */ +{ + ULONG size_needed = ulOffset.u.LowPart + cb; + ULONG first_page = ulOffset.u.LowPart / PAGE_SIZE; + ULONG offset_in_page = ulOffset.u.LowPart % PAGE_SIZE; + ULONG bytes_left = cb; + ULONG page_index = first_page; + ULONG bytes_to_page; + LPCVOID readPtr = pv; + + HRESULT rc = S_OK; + + TRACE("(%p)-> %i %p %i %p\n",This, ulOffset.u.LowPart, pv, cb, pcbWritten); + + /* verify a sane environment */ + if (!This) return E_FAIL; + + if (This->flProtect != PAGE_READWRITE) + return STG_E_ACCESSDENIED; + + if (size_needed > This->filesize.u.LowPart) + { + ULARGE_INTEGER newSize; + newSize.u.HighPart = 0; + newSize.u.LowPart = size_needed; + BIGBLOCKFILE_SetSize(This, newSize); + } + + if (offset_in_page + bytes_left > PAGE_SIZE) + bytes_to_page = PAGE_SIZE - offset_in_page; + else + bytes_to_page = bytes_left; + + if (pcbWritten) + *pcbWritten = 0; + + while (bytes_left) + { + LPBYTE writePtr; + MappedPage *page = BIGBLOCKFILE_GetMappedView(This, page_index); + + TRACE("page %i, offset %u, bytes_to_page %u, bytes_left %u\n", + page ? page->page_index : 0, offset_in_page, bytes_to_page, bytes_left); + + if (!page) + { + ERR("Unable to get a page to write. This should never happen\n"); + rc = E_FAIL; + break; + } + + if (page->mapped_bytes < bytes_to_page) + { + ERR("Not enough bytes mapped to the page. This should never happen\n"); + rc = E_FAIL; + break; + } + + writePtr = (BYTE*)page->lpBytes + offset_in_page; + memcpy(writePtr,readPtr,bytes_to_page); + BIGBLOCKFILE_ReleaseMappedPage(This, page); + + if (pcbWritten) + *pcbWritten += bytes_to_page; + bytes_left -= bytes_to_page; + + if (bytes_left) + { + readPtr = (LPBYTE)readPtr + bytes_to_page; + page_index ++; + offset_in_page = 0; + if (bytes_left > PAGE_SIZE) + bytes_to_page = PAGE_SIZE; + else + bytes_to_page = bytes_left; + } + } + + return rc; +} + + +HRESULT BIGBLOCKFILE_ReadAt(LPBIGBLOCKFILE This, ULARGE_INTEGER offset, + void* buffer, ULONG size, ULONG* bytesRead) +{ + if (This->fileBased) + return ImplBIGBLOCKFILE_ReadAt(This,offset,buffer,size,bytesRead); + else + return ILockBytes_ReadAt(This->pLkbyt,offset,buffer,size,bytesRead); +} + +HRESULT BIGBLOCKFILE_WriteAt(LPBIGBLOCKFILE This, ULARGE_INTEGER offset, + void* buffer, const ULONG size, ULONG* bytesRead) +{ + if (This->fileBased) + return ImplBIGBLOCKFILE_WriteAt(This,offset,buffer,size,bytesRead); + else + return ILockBytes_WriteAt(This->pLkbyt,offset,buffer,size,bytesRead); +} diff --git a/reactos/dll/win32/ole32/stg_prop.c b/reactos/dll/win32/ole32/stg_prop.c index 1d7b2dbd0b3..45c760e65a3 100644 --- a/reactos/dll/win32/ole32/stg_prop.c +++ b/reactos/dll/win32/ole32/stg_prop.c @@ -23,7 +23,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * There's a decent overview of property set storage here: * http://msdn.microsoft.com/archive/en-us/dnarolegen/html/msdn_propset.asp @@ -39,7 +39,6 @@ * - Not all PROPVARIANT types are supported. * - User defined properties are not supported, see comment in * PropertyStorage_ReadFromStream - * - IPropertyStorage::Enum is unimplemented */ #include @@ -60,6 +59,7 @@ #include "wine/debug.h" #include "dictionary.h" #include "storage32.h" +#include "enumx.h" WINE_DEFAULT_DEBUG_CHANNEL(storage); @@ -82,6 +82,11 @@ static inline StorageImpl *impl_from_IPropertySetStorage( IPropertySetStorage *i #define MAX_VERSION_0_PROP_NAME_LENGTH 256 +#define CFTAG_WINDOWS (-1L) +#define CFTAG_MACINTOSH (-2L) +#define CFTAG_FMTID (-3L) +#define CFTAG_NODATA 0L + /* The format version (and what it implies) is described here: * http://msdn.microsoft.com/library/en-us/stg/stg/format_version.asp */ @@ -112,25 +117,23 @@ typedef struct tagPROPERTYIDOFFSET DWORD dwOffset; /* from beginning of section */ } PROPERTYIDOFFSET; -struct tagPropertyStorage_impl; +typedef struct tagPropertyStorage_impl PropertyStorage_impl; /* Initializes the property storage from the stream (and undoes any uncommitted * changes in the process.) Returns an error if there is an error reading or * if the stream format doesn't match what's expected. */ -static HRESULT PropertyStorage_ReadFromStream(struct tagPropertyStorage_impl *); +static HRESULT PropertyStorage_ReadFromStream(PropertyStorage_impl *); -static HRESULT PropertyStorage_WriteToStream(struct tagPropertyStorage_impl *); +static HRESULT PropertyStorage_WriteToStream(PropertyStorage_impl *); /* Creates the dictionaries used by the property storage. If successful, all * the dictionaries have been created. If failed, none has been. (This makes * it a bit easier to deal with destroying them.) */ -static HRESULT PropertyStorage_CreateDictionaries( - struct tagPropertyStorage_impl *); +static HRESULT PropertyStorage_CreateDictionaries(PropertyStorage_impl *); -static void PropertyStorage_DestroyDictionaries( - struct tagPropertyStorage_impl *); +static void PropertyStorage_DestroyDictionaries(PropertyStorage_impl *); /* Copies from propvar to prop. If propvar's type is VT_LPSTR, copies the * string using PropertyStorage_StringCopy. @@ -149,11 +152,15 @@ static HRESULT PropertyStorage_StringCopy(LPCSTR src, LCID srcCP, LPSTR *dst, LCID targetCP); static const IPropertyStorageVtbl IPropertyStorage_Vtbl; +static const IEnumSTATPROPSETSTGVtbl IEnumSTATPROPSETSTG_Vtbl; +static const IEnumSTATPROPSTGVtbl IEnumSTATPROPSTG_Vtbl; +static HRESULT create_EnumSTATPROPSETSTG(StorageImpl *, IEnumSTATPROPSETSTG**); +static HRESULT create_EnumSTATPROPSTG(PropertyStorage_impl *, IEnumSTATPROPSTG**); /*********************************************************************** * Implementation of IPropertyStorage */ -typedef struct tagPropertyStorage_impl +struct tagPropertyStorage_impl { const IPropertyStorageVtbl *vtbl; LONG ref; @@ -172,7 +179,7 @@ typedef struct tagPropertyStorage_impl struct dictionary *name_to_propid; struct dictionary *propid_to_name; struct dictionary *propid_to_prop; -} PropertyStorage_impl; +}; /************************************************************************ * IPropertyStorage_fnQueryInterface (IPropertyStorage) @@ -226,6 +233,7 @@ static ULONG WINAPI IPropertyStorage_fnRelease( if (This->dirty) IPropertyStorage_Commit(iface, STGC_DEFAULT); IStream_Release(This->stm); + This->cs.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&This->cs); PropertyStorage_DestroyDictionaries(This); HeapFree(GetProcessHeap(), 0, This); @@ -238,7 +246,6 @@ static PROPVARIANT *PropertyStorage_FindProperty(PropertyStorage_impl *This, { PROPVARIANT *ret = NULL; - assert(This); dictionary_find(This->propid_to_prop, (void *)propid, (void **)&ret); TRACE("returning %p\n", ret); return ret; @@ -251,7 +258,6 @@ static PROPVARIANT *PropertyStorage_FindPropertyByName( PROPVARIANT *ret = NULL; PROPID propid; - assert(This); if (!name) return NULL; if (This->codePage == CP_UNICODE) @@ -282,7 +288,6 @@ static LPWSTR PropertyStorage_FindPropertyNameById(PropertyStorage_impl *This, { LPWSTR ret = NULL; - assert(This); dictionary_find(This->propid_to_name, (void *)propid, (void **)&ret); TRACE("returning %p\n", ret); return ret; @@ -298,13 +303,14 @@ static HRESULT WINAPI IPropertyStorage_fnReadMultiple( PROPVARIANT rgpropvar[]) { PropertyStorage_impl *This = (PropertyStorage_impl *)iface; - HRESULT hr = S_FALSE; + HRESULT hr = S_OK; ULONG i; - TRACE("(%p, %ld, %p, %p)\n", iface, cpspec, rgpspec, rgpropvar); - if (!This) - return E_INVALIDARG; - if (cpspec && (!rgpspec || !rgpropvar)) + TRACE("(%p, %d, %p, %p)\n", iface, cpspec, rgpspec, rgpropvar); + + if (!cpspec) + return S_FALSE; + if (!rgpspec || !rgpropvar) return E_INVALIDARG; EnterCriticalSection(&This->cs); for (i = 0; i < cpspec; i++) @@ -339,6 +345,8 @@ static HRESULT WINAPI IPropertyStorage_fnReadMultiple( if (prop) PropertyStorage_PropVariantCopy(&rgpropvar[i], prop, GetACP(), This->codePage); + else + hr = S_FALSE; } } } @@ -353,7 +361,7 @@ static HRESULT PropertyStorage_StringCopy(LPCSTR src, LCID srcCP, LPSTR *dst, HRESULT hr = S_OK; int len; - TRACE("%s, %p, %ld, %ld\n", + TRACE("%s, %p, %d, %d\n", srcCP == CP_UNICODE ? debugstr_w((LPCWSTR)src) : debugstr_a(src), dst, dstCP, srcCP); assert(src); @@ -386,16 +394,20 @@ static HRESULT PropertyStorage_StringCopy(LPCSTR src, LCID srcCP, LPSTR *dst, } else { - LPWSTR wideStr; + LPCWSTR wideStr = NULL; + LPWSTR wideStr_tmp = NULL; if (srcCP == CP_UNICODE) - wideStr = (LPWSTR)src; + wideStr = (LPCWSTR)src; else { len = MultiByteToWideChar(srcCP, 0, src, -1, NULL, 0); - wideStr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); - if (wideStr) - MultiByteToWideChar(srcCP, 0, src, -1, wideStr, len); + wideStr_tmp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + if (wideStr_tmp) + { + MultiByteToWideChar(srcCP, 0, src, -1, wideStr_tmp, len); + wideStr = wideStr_tmp; + } else hr = STG_E_INSUFFICIENTMEMORY; } @@ -419,11 +431,10 @@ static HRESULT PropertyStorage_StringCopy(LPCSTR src, LCID srcCP, LPSTR *dst, } } } - if (wideStr != (LPWSTR)src) - HeapFree(GetProcessHeap(), 0, wideStr); + HeapFree(GetProcessHeap(), 0, wideStr_tmp); } } - TRACE("returning 0x%08lx (%s)\n", hr, + TRACE("returning 0x%08x (%s)\n", hr, dstCP == CP_UNICODE ? debugstr_w((LPCWSTR)*dst) : debugstr_a(*dst)); return hr; } @@ -460,7 +471,6 @@ static HRESULT PropertyStorage_StorePropWithId(PropertyStorage_impl *This, HRESULT hr = S_OK; PROPVARIANT *prop = PropertyStorage_FindProperty(This, propid); - assert(This); assert(propvar); if (propvar->vt & VT_BYREF || propvar->vt & VT_ARRAY) This->format = 1; @@ -473,7 +483,7 @@ static HRESULT PropertyStorage_StorePropWithId(PropertyStorage_impl *This, case VT_VECTOR|VT_I1: This->format = 1; } - TRACE("Setting 0x%08lx to type %d\n", propid, propvar->vt); + TRACE("Setting 0x%08x to type %d\n", propid, propvar->vt); if (prop) { PropVariantClear(prop); @@ -531,7 +541,7 @@ static HRESULT PropertyStorage_StoreNameWithId(PropertyStorage_impl *This, if (strlen(name) >= MAX_VERSION_0_PROP_NAME_LENGTH) This->format = 1; } - TRACE("Adding prop name %s, propid %ld\n", + TRACE("Adding prop name %s, propid %d\n", This->codePage == CP_UNICODE ? debugstr_w((LPCWSTR)name) : debugstr_a(name), id); dictionary_insert(This->name_to_propid, name, (void *)id); @@ -554,9 +564,8 @@ static HRESULT WINAPI IPropertyStorage_fnWriteMultiple( HRESULT hr = S_OK; ULONG i; - TRACE("(%p, %ld, %p, %p)\n", iface, cpspec, rgpspec, rgpropvar); - if (!This) - return E_INVALIDARG; + TRACE("(%p, %d, %p, %p)\n", iface, cpspec, rgpspec, rgpropvar); + if (cpspec && (!rgpspec || !rgpropvar)) return E_INVALIDARG; if (!(This->grfMode & STGM_READWRITE)) @@ -654,9 +663,8 @@ static HRESULT WINAPI IPropertyStorage_fnDeleteMultiple( ULONG i; HRESULT hr; - TRACE("(%p, %ld, %p)\n", iface, cpspec, rgpspec); - if (!This) - return E_INVALIDARG; + TRACE("(%p, %d, %p)\n", iface, cpspec, rgpspec); + if (cpspec && !rgpspec) return E_INVALIDARG; if (!(This->grfMode & STGM_READWRITE)) @@ -703,9 +711,8 @@ static HRESULT WINAPI IPropertyStorage_fnReadPropertyNames( ULONG i; HRESULT hr = S_FALSE; - TRACE("(%p, %ld, %p, %p)\n", iface, cpropid, rgpropid, rglpwstrName); - if (!This) - return E_INVALIDARG; + TRACE("(%p, %d, %p, %p)\n", iface, cpropid, rgpropid, rglpwstrName); + if (cpropid && (!rgpropid || !rglpwstrName)) return E_INVALIDARG; EnterCriticalSection(&This->cs); @@ -744,9 +751,8 @@ static HRESULT WINAPI IPropertyStorage_fnWritePropertyNames( ULONG i; HRESULT hr; - TRACE("(%p, %ld, %p, %p)\n", iface, cpropid, rgpropid, rglpwstrName); - if (!This) - return E_INVALIDARG; + TRACE("(%p, %d, %p, %p)\n", iface, cpropid, rgpropid, rglpwstrName); + if (cpropid && (!rgpropid || !rglpwstrName)) return E_INVALIDARG; if (!(This->grfMode & STGM_READWRITE)) @@ -778,9 +784,8 @@ static HRESULT WINAPI IPropertyStorage_fnDeletePropertyNames( ULONG i; HRESULT hr; - TRACE("(%p, %ld, %p)\n", iface, cpropid, rgpropid); - if (!This) - return E_INVALIDARG; + TRACE("(%p, %d, %p)\n", iface, cpropid, rgpropid); + if (cpropid && !rgpropid) return E_INVALIDARG; if (!(This->grfMode & STGM_READWRITE)) @@ -815,9 +820,8 @@ static HRESULT WINAPI IPropertyStorage_fnCommit( PropertyStorage_impl *This = (PropertyStorage_impl *)iface; HRESULT hr; - TRACE("(%p, 0x%08lx)\n", iface, grfCommitFlags); - if (!This) - return E_INVALIDARG; + TRACE("(%p, 0x%08x)\n", iface, grfCommitFlags); + if (!(This->grfMode & STGM_READWRITE)) return STG_E_ACCESSDENIED; EnterCriticalSection(&This->cs); @@ -839,8 +843,6 @@ static HRESULT WINAPI IPropertyStorage_fnRevert( PropertyStorage_impl *This = (PropertyStorage_impl *)iface; TRACE("%p\n", iface); - if (!This) - return E_INVALIDARG; EnterCriticalSection(&This->cs); if (This->dirty) @@ -863,8 +865,8 @@ static HRESULT WINAPI IPropertyStorage_fnEnum( IPropertyStorage* iface, IEnumSTATPROPSTG** ppenum) { - FIXME("\n"); - return E_NOTIMPL; + PropertyStorage_impl *This = (PropertyStorage_impl *)iface; + return create_EnumSTATPROPSTG(This, ppenum); } /************************************************************************ @@ -890,7 +892,8 @@ static HRESULT WINAPI IPropertyStorage_fnSetClass( PropertyStorage_impl *This = (PropertyStorage_impl *)iface; TRACE("%p, %s\n", iface, debugstr_guid(clsid)); - if (!This || !clsid) + + if (!clsid) return E_INVALIDARG; if (!(This->grfMode & STGM_READWRITE)) return STG_E_ACCESSDENIED; @@ -913,7 +916,8 @@ static HRESULT WINAPI IPropertyStorage_fnStat( HRESULT hr; TRACE("%p, %p\n", iface, statpsstg); - if (!This || !statpsstg) + + if (!statpsstg) return E_INVALIDARG; hr = IStream_Stat(This->stm, &stat, STATFLAG_NONAME); @@ -961,7 +965,7 @@ static void PropertyStorage_PropNameDestroy(void *k, void *d, void *extra) static int PropertyStorage_PropCompare(const void *a, const void *b, void *extra) { - TRACE("(%ld, %ld)\n", (PROPID)a, (PROPID)b); + TRACE("(%d, %d)\n", (PROPID)a, (PROPID)b); return (PROPID)a - (PROPID)b; } @@ -1000,12 +1004,11 @@ static HRESULT PropertyStorage_ReadDictionary(PropertyStorage_impl *This, DWORD numEntries, i; HRESULT hr = S_OK; - assert(This); assert(This->name_to_propid); assert(This->propid_to_name); StorageUtl_ReadDWord(ptr, 0, &numEntries); - TRACE("Reading %ld entries:\n", numEntries); + TRACE("Reading %d entries:\n", numEntries); ptr += sizeof(DWORD); for (i = 0; SUCCEEDED(hr) && i < numEntries; i++) { @@ -1016,7 +1019,7 @@ static HRESULT PropertyStorage_ReadDictionary(PropertyStorage_impl *This, ptr += sizeof(PROPID); StorageUtl_ReadDWord(ptr, 0, &cbEntry); ptr += sizeof(DWORD); - TRACE("Reading entry with ID 0x%08lx, %ld bytes\n", propid, cbEntry); + TRACE("Reading entry with ID 0x%08x, %d bytes\n", propid, cbEntry); /* Make sure the source string is NULL-terminated */ if (This->codePage != CP_UNICODE) ptr[cbEntry - 1] = '\0'; @@ -1075,7 +1078,7 @@ static HRESULT PropertyStorage_ReadProperty(PropertyStorage_impl *This, case VT_UINT: case VT_UI4: StorageUtl_ReadDWord(data, 0, &prop->u.ulVal); - TRACE("Read ulong %ld\n", prop->u.ulVal); + TRACE("Read ulong %d\n", prop->u.ulVal); break; case VT_LPSTR: { @@ -1138,6 +1141,25 @@ static HRESULT PropertyStorage_ReadProperty(PropertyStorage_impl *This, StorageUtl_ReadULargeInteger(data, 0, (ULARGE_INTEGER *)&prop->u.filetime); break; + case VT_CF: + { + DWORD len = 0, tag = 0; + + StorageUtl_ReadDWord(data, 0, &len); + StorageUtl_ReadDWord(data, 4, &tag); + if (len > 8) + { + len -= 8; + prop->u.pclipdata = CoTaskMemAlloc(sizeof (CLIPDATA)); + prop->u.pclipdata->cbSize = len; + prop->u.pclipdata->ulClipFmt = tag; + prop->u.pclipdata->pClipData = CoTaskMemAlloc(len); + memcpy(prop->u.pclipdata->pClipData, data+8, len); + } + else + hr = STG_E_INVALIDPARAMETER; + } + break; default: FIXME("unsupported type %d\n", prop->vt); hr = STG_E_INVALIDPARAMETER; @@ -1159,7 +1181,7 @@ static HRESULT PropertyStorage_ReadHeaderFromStream(IStream *stm, { if (count != sizeof(buf)) { - WARN("read %ld, expected %d\n", count, sizeof(buf)); + WARN("read only %d\n", count); hr = STG_E_INVALIDHEADER; } else @@ -1176,7 +1198,7 @@ static HRESULT PropertyStorage_ReadHeaderFromStream(IStream *stm, &hdr->reserved); } } - TRACE("returning 0x%08lx\n", hr); + TRACE("returning 0x%08x\n", hr); return hr; } @@ -1194,7 +1216,7 @@ static HRESULT PropertyStorage_ReadFmtIdOffsetFromStream(IStream *stm, { if (count != sizeof(buf)) { - WARN("read %ld, expected %d\n", count, sizeof(buf)); + WARN("read only %d\n", count); hr = STG_E_INVALIDHEADER; } else @@ -1205,7 +1227,7 @@ static HRESULT PropertyStorage_ReadFmtIdOffsetFromStream(IStream *stm, &fmt->dwOffset); } } - TRACE("returning 0x%08lx\n", hr); + TRACE("returning 0x%08x\n", hr); return hr; } @@ -1223,7 +1245,7 @@ static HRESULT PropertyStorage_ReadSectionHeaderFromStream(IStream *stm, { if (count != sizeof(buf)) { - WARN("read %ld, expected %d\n", count, sizeof(buf)); + WARN("read only %d\n", count); hr = STG_E_INVALIDHEADER; } else @@ -1234,7 +1256,7 @@ static HRESULT PropertyStorage_ReadSectionHeaderFromStream(IStream *stm, cProperties), &hdr->cProperties); } } - TRACE("returning 0x%08lx\n", hr); + TRACE("returning 0x%08x\n", hr); return hr; } @@ -1251,7 +1273,6 @@ static HRESULT PropertyStorage_ReadFromStream(PropertyStorage_impl *This) ULONG count = 0; DWORD dictOffset = 0; - assert(This); This->dirty = FALSE; This->highestProp = 0; hr = IStream_Stat(This->stm, &stat, STATFLAG_NONAME); @@ -1307,7 +1328,7 @@ static HRESULT PropertyStorage_ReadFromStream(PropertyStorage_impl *This) goto end; if (fmtOffset.dwOffset > stat.cbSize.u.LowPart) { - WARN("invalid offset %ld (stream length is %ld)\n", fmtOffset.dwOffset, + WARN("invalid offset %d (stream length is %d)\n", fmtOffset.dwOffset, stat.cbSize.u.LowPart); hr = STG_E_INVALIDHEADER; goto end; @@ -1325,8 +1346,7 @@ static HRESULT PropertyStorage_ReadFromStream(PropertyStorage_impl *This) /* The section size includes the section header, so check it */ if (sectionHdr.cbSection < sizeof(PROPERTYSECTIONHEADER)) { - WARN("section header too small, got %ld, expected at least %d\n", - sectionHdr.cbSection, sizeof(PROPERTYSECTIONHEADER)); + WARN("section header too small, got %d\n", sectionHdr.cbSection); hr = STG_E_INVALIDHEADER; goto end; } @@ -1341,7 +1361,7 @@ static HRESULT PropertyStorage_ReadFromStream(PropertyStorage_impl *This) sizeof(PROPERTYSECTIONHEADER), &count); if (FAILED(hr)) goto end; - TRACE("Reading %ld properties:\n", sectionHdr.cProperties); + TRACE("Reading %d properties:\n", sectionHdr.cProperties); for (i = 0; SUCCEEDED(hr) && i < sectionHdr.cProperties; i++) { PROPERTYIDOFFSET *idOffset = (PROPERTYIDOFFSET *)(buf + @@ -1363,16 +1383,17 @@ static HRESULT PropertyStorage_ReadFromStream(PropertyStorage_impl *This) * later. */ dictOffset = idOffset->dwOffset; - TRACE("Dictionary offset is %ld\n", dictOffset); + TRACE("Dictionary offset is %d\n", dictOffset); } else { PROPVARIANT prop; + PropVariantInit(&prop); if (SUCCEEDED(PropertyStorage_ReadProperty(This, &prop, buf + idOffset->dwOffset - sizeof(PROPERTYSECTIONHEADER)))) { - TRACE("Read property with ID 0x%08lx, type %d\n", + TRACE("Read property with ID 0x%08x, type %d\n", idOffset->propid, prop.vt); switch(idOffset->propid) { @@ -1410,7 +1431,7 @@ static HRESULT PropertyStorage_ReadFromStream(PropertyStorage_impl *This) } if (!This->locale) This->locale = LOCALE_SYSTEM_DEFAULT; - TRACE("Code page is %d, locale is %ld\n", This->codePage, This->locale); + TRACE("Code page is %d, locale is %d\n", This->codePage, This->locale); if (dictOffset) hr = PropertyStorage_ReadDictionary(This, buf + dictOffset - sizeof(PROPERTYSECTIONHEADER)); @@ -1432,7 +1453,6 @@ end: static void PropertyStorage_MakeHeader(PropertyStorage_impl *This, PROPERTYSETHEADER *hdr) { - assert(This); assert(hdr); StorageUtl_WriteWord((BYTE *)&hdr->wByteOrder, 0, PROPSETHDR_BYTEORDER_MAGIC); @@ -1445,7 +1465,6 @@ static void PropertyStorage_MakeHeader(PropertyStorage_impl *This, static void PropertyStorage_MakeFmtIdOffset(PropertyStorage_impl *This, FORMATIDOFFSET *fmtOffset) { - assert(This); assert(fmtOffset); StorageUtl_WriteGUID((BYTE *)fmtOffset, 0, &This->fmtid); StorageUtl_WriteDWord((BYTE *)fmtOffset, offsetof(FORMATIDOFFSET, dwOffset), @@ -1485,7 +1504,6 @@ static BOOL PropertyStorage_DictionaryWriter(const void *key, ULONG count; assert(key); - assert(This); assert(closure); StorageUtl_WriteDWord((LPBYTE)&propid, 0, (DWORD)value); c->hr = IStream_Write(This->stm, &propid, sizeof(propid), &count); @@ -1497,7 +1515,7 @@ static BOOL PropertyStorage_DictionaryWriter(const void *key, DWORD keyLen, pad = 0; StorageUtl_WriteDWord((LPBYTE)&keyLen, 0, - (lstrlenW((LPWSTR)key) + 1) * sizeof(WCHAR)); + (lstrlenW((LPCWSTR)key) + 1) * sizeof(WCHAR)); c->hr = IStream_Write(This->stm, &keyLen, sizeof(keyLen), &count); if (FAILED(c->hr)) goto end; @@ -1553,7 +1571,6 @@ static HRESULT PropertyStorage_WriteDictionaryToStream( DWORD dwTemp; struct DictionaryClosure closure; - assert(This); assert(sectionOffset); /* The dictionary's always the first property written, so seek to its @@ -1590,9 +1607,9 @@ static HRESULT PropertyStorage_WriteDictionaryToStream( *sectionOffset += closure.bytesWritten; if (closure.bytesWritten % sizeof(DWORD)) { - TRACE("adding %ld bytes of padding\n", sizeof(DWORD) - - closure.bytesWritten % sizeof(DWORD)); - *sectionOffset += sizeof(DWORD) - closure.bytesWritten % sizeof(DWORD); + DWORD padding = sizeof(DWORD) - closure.bytesWritten % sizeof(DWORD); + TRACE("adding %d bytes of padding\n", padding); + *sectionOffset += padding; } end: @@ -1608,11 +1625,10 @@ static HRESULT PropertyStorage_WritePropertyToStream(PropertyStorage_impl *This, ULONG count; DWORD dwType, bytesWritten; - assert(This); assert(var); assert(sectionOffset); - TRACE("%p, %ld, 0x%08lx, (%d), (%ld)\n", This, propNum, propid, var->vt, + TRACE("%p, %d, 0x%08x, (%d), (%d)\n", This, propNum, propid, var->vt, *sectionOffset); seek.QuadPart = SECTIONHEADER_OFFSET + sizeof(PROPERTYSECTIONHEADER) + @@ -1706,6 +1722,22 @@ static HRESULT PropertyStorage_WritePropertyToStream(PropertyStorage_impl *This, bytesWritten = count; break; } + case VT_CF: + { + DWORD cf_hdr[2], len; + + len = var->u.pclipdata->cbSize; + StorageUtl_WriteDWord((LPBYTE)&cf_hdr[0], 0, len + 8); + StorageUtl_WriteDWord((LPBYTE)&cf_hdr[1], 0, var->u.pclipdata->ulClipFmt); + hr = IStream_Write(This->stm, &cf_hdr, sizeof(cf_hdr), &count); + if (FAILED(hr)) + goto end; + hr = IStream_Write(This->stm, &var->u.pclipdata->pClipData, len, &count); + if (FAILED(hr)) + goto end; + bytesWritten = count + sizeof cf_hdr; + break; + } default: FIXME("unsupported type: %d\n", var->vt); return STG_E_INVALIDPARAMETER; @@ -1716,9 +1748,9 @@ static HRESULT PropertyStorage_WritePropertyToStream(PropertyStorage_impl *This, *sectionOffset += bytesWritten; if (bytesWritten % sizeof(DWORD)) { - TRACE("adding %ld bytes of padding\n", sizeof(DWORD) - - bytesWritten % sizeof(DWORD)); - *sectionOffset += sizeof(DWORD) - bytesWritten % sizeof(DWORD); + DWORD padding = sizeof(DWORD) - bytesWritten % sizeof(DWORD); + TRACE("adding %d bytes of padding\n", padding); + *sectionOffset += padding; } } @@ -1753,7 +1785,6 @@ static HRESULT PropertyStorage_WritePropertiesToStream( { struct PropertyClosure closure; - assert(This); assert(sectionOffset); closure.hr = S_OK; closure.propNum = startingPropNum; @@ -1771,7 +1802,6 @@ static HRESULT PropertyStorage_WriteHeadersToStream(PropertyStorage_impl *This) PROPERTYSETHEADER hdr; FORMATIDOFFSET fmtOffset; - assert(This); hr = IStream_Seek(This->stm, seek, STREAM_SEEK_SET, NULL); if (FAILED(hr)) goto end; @@ -1809,8 +1839,6 @@ static HRESULT PropertyStorage_WriteToStream(PropertyStorage_impl *This) DWORD numProps, prop, sectionOffset, dwTemp; PROPVARIANT var; - assert(This); - PropertyStorage_WriteHeadersToStream(This); /* Count properties. Always at least one property, the code page */ @@ -1897,7 +1925,6 @@ end: */ static void PropertyStorage_DestroyDictionaries(PropertyStorage_impl *This) { - assert(This); dictionary_destroy(This->name_to_propid); This->name_to_propid = NULL; dictionary_destroy(This->propid_to_name); @@ -1910,7 +1937,6 @@ static HRESULT PropertyStorage_CreateDictionaries(PropertyStorage_impl *This) { HRESULT hr = S_OK; - assert(This); This->name_to_propid = dictionary_create( PropertyStorage_PropNameCompare, PropertyStorage_PropNameDestroy, This); @@ -1953,6 +1979,7 @@ static HRESULT PropertyStorage_BaseConstruct(IStream *stm, (*pps)->vtbl = &IPropertyStorage_Vtbl; (*pps)->ref = 1; InitializeCriticalSection(&(*pps)->cs); + (*pps)->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": PropertyStorage_impl.cs"); (*pps)->stm = stm; memcpy(&(*pps)->fmtid, rfmtid, sizeof((*pps)->fmtid)); (*pps)->grfMode = grfMode; @@ -1961,6 +1988,7 @@ static HRESULT PropertyStorage_BaseConstruct(IStream *stm, if (FAILED(hr)) { IStream_Release(stm); + (*pps)->cs.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&(*pps)->cs); HeapFree(GetProcessHeap(), 0, *pps); *pps = NULL; @@ -2017,7 +2045,7 @@ static HRESULT PropertyStorage_ConstructEmpty(IStream *stm, else ps->codePage = CP_UNICODE; ps->locale = LOCALE_SYSTEM_DEFAULT; - TRACE("Code page is %d, locale is %ld\n", ps->codePage, ps->locale); + TRACE("Code page is %d, locale is %d\n", ps->codePage, ps->locale); *pps = (IPropertyStorage *)ps; TRACE("PropertyStorage %p constructed\n", ps); hr = S_OK; @@ -2084,7 +2112,7 @@ static HRESULT WINAPI IPropertySetStorage_fnCreate( IStream *stm = NULL; HRESULT r; - TRACE("%p %s %08lx %08lx %p\n", This, debugstr_guid(rfmtid), grfFlags, + TRACE("%p %s %08x %08x %p\n", This, debugstr_guid(rfmtid), grfFlags, grfMode, ppprstg); /* be picky */ @@ -2121,7 +2149,7 @@ static HRESULT WINAPI IPropertySetStorage_fnCreate( r = PropertyStorage_ConstructEmpty(stm, rfmtid, grfFlags, grfMode, ppprstg); end: - TRACE("returning 0x%08lx\n", r); + TRACE("returning 0x%08x\n", r); return r; } @@ -2139,7 +2167,7 @@ static HRESULT WINAPI IPropertySetStorage_fnOpen( WCHAR name[CCH_MAX_PROPSTG_NAME]; HRESULT r; - TRACE("%p %s %08lx %p\n", This, debugstr_guid(rfmtid), grfMode, ppprstg); + TRACE("%p %s %08x %p\n", This, debugstr_guid(rfmtid), grfMode, ppprstg); /* be picky */ if (grfMode != (STGM_READWRITE|STGM_SHARE_EXCLUSIVE) && @@ -2166,7 +2194,7 @@ static HRESULT WINAPI IPropertySetStorage_fnOpen( r = PropertyStorage_ConstructFromStream(stm, rfmtid, grfMode, ppprstg); end: - TRACE("returning 0x%08lx\n", r); + TRACE("returning 0x%08x\n", r); return r; } @@ -2203,10 +2231,201 @@ static HRESULT WINAPI IPropertySetStorage_fnEnum( IEnumSTATPROPSETSTG** ppenum) { StorageImpl *This = impl_from_IPropertySetStorage(ppstg); - FIXME("%p\n", This); - return E_NOTIMPL; + return create_EnumSTATPROPSETSTG(This, ppenum); } +/************************************************************************ + * Implement IEnumSTATPROPSETSTG using enumx + */ +static HRESULT WINAPI IEnumSTATPROPSETSTG_fnQueryInterface( + IEnumSTATPROPSETSTG *iface, + REFIID riid, + void** ppvObject) +{ + return enumx_QueryInterface((enumx_impl*)iface, riid, ppvObject); +} + +static ULONG WINAPI IEnumSTATPROPSETSTG_fnAddRef( + IEnumSTATPROPSETSTG *iface) +{ + return enumx_AddRef((enumx_impl*)iface); +} + +static ULONG WINAPI IEnumSTATPROPSETSTG_fnRelease( + IEnumSTATPROPSETSTG *iface) +{ + return enumx_Release((enumx_impl*)iface); +} + +static HRESULT WINAPI IEnumSTATPROPSETSTG_fnNext( + IEnumSTATPROPSETSTG *iface, + ULONG celt, + STATPROPSETSTG *rgelt, + ULONG *pceltFetched) +{ + return enumx_Next((enumx_impl*)iface, celt, rgelt, pceltFetched); +} + +static HRESULT WINAPI IEnumSTATPROPSETSTG_fnSkip( + IEnumSTATPROPSETSTG *iface, + ULONG celt) +{ + return enumx_Skip((enumx_impl*)iface, celt); +} + +static HRESULT WINAPI IEnumSTATPROPSETSTG_fnReset( + IEnumSTATPROPSETSTG *iface) +{ + return enumx_Reset((enumx_impl*)iface); +} + +static HRESULT WINAPI IEnumSTATPROPSETSTG_fnClone( + IEnumSTATPROPSETSTG *iface, + IEnumSTATPROPSETSTG **ppenum) +{ + return enumx_Clone((enumx_impl*)iface, (enumx_impl**)ppenum); +} + +static HRESULT create_EnumSTATPROPSETSTG( + StorageImpl *This, + IEnumSTATPROPSETSTG** ppenum) +{ + IStorage *stg = (IStorage*) &This->base.lpVtbl; + IEnumSTATSTG *penum = NULL; + STATSTG stat; + ULONG count; + HRESULT r; + STATPROPSETSTG statpss; + enumx_impl *enumx; + + TRACE("%p %p\n", This, ppenum); + + enumx = enumx_allocate(&IID_IEnumSTATPROPSETSTG, + &IEnumSTATPROPSETSTG_Vtbl, + sizeof (STATPROPSETSTG)); + + /* add all the property set elements into a list */ + r = IStorage_EnumElements(stg, 0, NULL, 0, &penum); + if (FAILED(r)) + return E_OUTOFMEMORY; + + while (1) + { + count = 0; + r = IEnumSTATSTG_Next(penum, 1, &stat, &count); + if (FAILED(r)) + break; + if (!count) + break; + if (!stat.pwcsName) + continue; + if (stat.pwcsName[0] == 5 && stat.type == STGTY_STREAM) + { + PropStgNameToFmtId(stat.pwcsName, &statpss.fmtid); + TRACE("adding %s (%s)\n", debugstr_w(stat.pwcsName), + debugstr_guid(&statpss.fmtid)); + statpss.mtime = stat.mtime; + statpss.atime = stat.atime; + statpss.ctime = stat.ctime; + statpss.grfFlags = stat.grfMode; + memcpy(&statpss.clsid, &stat.clsid, sizeof stat.clsid); + enumx_add_element(enumx, &statpss); + } + CoTaskMemFree(stat.pwcsName); + } + IEnumSTATSTG_Release(penum); + + *ppenum = (IEnumSTATPROPSETSTG*) enumx; + + return S_OK; +} + +/************************************************************************ + * Implement IEnumSTATPROPSTG using enumx + */ +static HRESULT WINAPI IEnumSTATPROPSTG_fnQueryInterface( + IEnumSTATPROPSTG *iface, + REFIID riid, + void** ppvObject) +{ + return enumx_QueryInterface((enumx_impl*)iface, riid, ppvObject); +} + +static ULONG WINAPI IEnumSTATPROPSTG_fnAddRef( + IEnumSTATPROPSTG *iface) +{ + return enumx_AddRef((enumx_impl*)iface); +} + +static ULONG WINAPI IEnumSTATPROPSTG_fnRelease( + IEnumSTATPROPSTG *iface) +{ + return enumx_Release((enumx_impl*)iface); +} + +static HRESULT WINAPI IEnumSTATPROPSTG_fnNext( + IEnumSTATPROPSTG *iface, + ULONG celt, + STATPROPSTG *rgelt, + ULONG *pceltFetched) +{ + return enumx_Next((enumx_impl*)iface, celt, rgelt, pceltFetched); +} + +static HRESULT WINAPI IEnumSTATPROPSTG_fnSkip( + IEnumSTATPROPSTG *iface, + ULONG celt) +{ + return enumx_Skip((enumx_impl*)iface, celt); +} + +static HRESULT WINAPI IEnumSTATPROPSTG_fnReset( + IEnumSTATPROPSTG *iface) +{ + return enumx_Reset((enumx_impl*)iface); +} + +static HRESULT WINAPI IEnumSTATPROPSTG_fnClone( + IEnumSTATPROPSTG *iface, + IEnumSTATPROPSTG **ppenum) +{ + return enumx_Clone((enumx_impl*)iface, (enumx_impl**)ppenum); +} + +static BOOL prop_enum_stat(const void *k, const void *v, void *extra, void *arg) +{ + enumx_impl *enumx = arg; + PROPID propid = (PROPID) k; + const PROPVARIANT *prop = v; + STATPROPSTG stat; + + stat.lpwstrName = NULL; + stat.propid = propid; + stat.vt = prop->vt; + + enumx_add_element(enumx, &stat); + + return TRUE; +} + +static HRESULT create_EnumSTATPROPSTG( + PropertyStorage_impl *This, + IEnumSTATPROPSTG** ppenum) +{ + enumx_impl *enumx; + + TRACE("%p %p\n", This, ppenum); + + enumx = enumx_allocate(&IID_IEnumSTATPROPSTG, + &IEnumSTATPROPSTG_Vtbl, + sizeof (STATPROPSTG)); + + dictionary_enumerate(This->propid_to_prop, prop_enum_stat, enumx); + + *ppenum = (IEnumSTATPROPSTG*) enumx; + + return S_OK; +} /*********************************************************************** * vtables @@ -2241,6 +2460,28 @@ static const IPropertyStorageVtbl IPropertyStorage_Vtbl = IPropertyStorage_fnStat, }; +static const IEnumSTATPROPSETSTGVtbl IEnumSTATPROPSETSTG_Vtbl = +{ + IEnumSTATPROPSETSTG_fnQueryInterface, + IEnumSTATPROPSETSTG_fnAddRef, + IEnumSTATPROPSETSTG_fnRelease, + IEnumSTATPROPSETSTG_fnNext, + IEnumSTATPROPSETSTG_fnSkip, + IEnumSTATPROPSETSTG_fnReset, + IEnumSTATPROPSETSTG_fnClone, +}; + +static const IEnumSTATPROPSTGVtbl IEnumSTATPROPSTG_Vtbl = +{ + IEnumSTATPROPSTG_fnQueryInterface, + IEnumSTATPROPSTG_fnAddRef, + IEnumSTATPROPSTG_fnRelease, + IEnumSTATPROPSTG_fnNext, + IEnumSTATPROPSTG_fnSkip, + IEnumSTATPROPSTG_fnReset, + IEnumSTATPROPSTG_fnClone, +}; + /*********************************************************************** * Format ID <-> name conversion */ @@ -2286,12 +2527,12 @@ HRESULT WINAPI FmtIdToPropStgName(const FMTID *rfmtid, LPOLESTR str) lstrcpyW(str, szDocSummaryInfo); else { - BYTE *fmtptr; + const BYTE *fmtptr; WCHAR *pstr = str; ULONG bitsRemaining = BITS_PER_BYTE; *pstr++ = 5; - for (fmtptr = (BYTE *)rfmtid; fmtptr < (BYTE *)rfmtid + sizeof(FMTID); ) + for (fmtptr = (const BYTE *)rfmtid; fmtptr < (const BYTE *)rfmtid + sizeof(FMTID); ) { ULONG i = *fmtptr >> (BITS_PER_BYTE - bitsRemaining); diff --git a/reactos/dll/win32/ole32/stg_stream.c b/reactos/dll/win32/ole32/stg_stream.c index 19b8bda5a7d..e144b2c9487 100644 --- a/reactos/dll/win32/ole32/stg_stream.c +++ b/reactos/dll/win32/ole32/stg_stream.c @@ -20,7 +20,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include @@ -58,8 +58,21 @@ static void StgStreamImpl_Destroy(StgStreamImpl* This) /* * Release the reference we are holding on the parent storage. + * IStorage_Release((IStorage*)This->parentStorage); + * + * No, don't do this. Some apps call IStorage_Release without + * calling IStream_Release first. If we grab a reference the + * file is not closed, and the app fails when it tries to + * reopen the file (Easy-PC, for example). Just inform the + * storage that we have closed the stream */ - IStorage_Release((IStorage*)This->parentStorage); + + if(This->parentStorage) { + + StorageBaseImpl_RemoveStream(This->parentStorage, This); + + } + This->parentStorage = 0; /* @@ -108,8 +121,11 @@ static HRESULT WINAPI StgStreamImpl_QueryInterface( /* * Compare the riid with the interface IDs implemented by this object. */ - if (IsEqualGUID(&IID_IUnknown, riid)|| - IsEqualGUID(&IID_IStream, riid)) + if (IsEqualIID(&IID_IUnknown, riid) || + IsEqualIID(&IID_IPersist, riid) || + IsEqualIID(&IID_IPersistStream, riid) || + IsEqualIID(&IID_ISequentialStream, riid) || + IsEqualIID(&IID_IStream, riid)) { *ppvObject = (IStream*)This; } @@ -173,7 +189,7 @@ static void StgStreamImpl_OpenBlockChain( StgStreamImpl* This) { StgProperty curProperty; - BOOL readSucessful; + BOOL readSuccessful; /* * Make sure no old object is left over. @@ -193,11 +209,11 @@ static void StgStreamImpl_OpenBlockChain( /* * Read the information from the property. */ - readSucessful = StorageImpl_ReadProperty(This->parentStorage->ancestorStorage, + readSuccessful = StorageImpl_ReadProperty(This->parentStorage->ancestorStorage, This->ownerProperty, &curProperty); - if (readSucessful) + if (readSuccessful) { This->streamSize = curProperty.size; @@ -251,9 +267,15 @@ static HRESULT WINAPI StgStreamImpl_Read( ULONG bytesToReadFromBuffer; HRESULT res; - TRACE("(%p, %p, %ld, %p)\n", + TRACE("(%p, %p, %d, %p)\n", iface, pv, cb, pcbRead); + if (!This->parentStorage) + { + WARN("storage reverted\n"); + return STG_E_REVERTED; + } + /* * If the caller is not interested in the number of bytes read, * we use another buffer to avoid "if" statements in the code. @@ -282,15 +304,11 @@ static HRESULT WINAPI StgStreamImpl_Read( } else if (This->bigBlockChain!=0) { - BOOL success = BlockChainStream_ReadAt(This->bigBlockChain, - This->currentPosition, - bytesToReadFromBuffer, - pv, - pcbRead); - if (success) - res = S_OK; - else - res = STG_E_READFAULT; + res = BlockChainStream_ReadAt(This->bigBlockChain, + This->currentPosition, + bytesToReadFromBuffer, + pv, + pcbRead); } else { @@ -319,7 +337,7 @@ static HRESULT WINAPI StgStreamImpl_Read( } end: - TRACE("<-- %08lx\n", res); + TRACE("<-- %08x\n", res); return res; } @@ -343,8 +361,9 @@ static HRESULT WINAPI StgStreamImpl_Write( ULARGE_INTEGER newSize; ULONG bytesWritten = 0; + HRESULT res; - TRACE("(%p, %p, %ld, %p)\n", + TRACE("(%p, %p, %d, %p)\n", iface, pv, cb, pcbWritten); /* @@ -356,12 +375,19 @@ static HRESULT WINAPI StgStreamImpl_Write( case STGM_READWRITE: break; default: + WARN("access denied by flags: 0x%x\n", STGM_ACCESS_MODE(This->grfMode)); return STG_E_ACCESSDENIED; } if (!pv) return STG_E_INVALIDPOINTER; + if (!This->parentStorage) + { + WARN("storage reverted\n"); + return STG_E_REVERTED; + } + /* * If the caller is not interested in the number of bytes written, * we use another buffer to avoid "if" statements in the code. @@ -376,6 +402,7 @@ static HRESULT WINAPI StgStreamImpl_Write( if (cb == 0) { + TRACE("<-- S_OK, written 0\n"); return S_OK; } else @@ -390,7 +417,9 @@ static HRESULT WINAPI StgStreamImpl_Write( if (newSize.u.LowPart > This->streamSize.u.LowPart) { /* grow stream */ - IStream_SetSize(iface, newSize); + res = IStream_SetSize(iface, newSize); + if (FAILED(res)) + return res; } /* @@ -399,7 +428,7 @@ static HRESULT WINAPI StgStreamImpl_Write( */ if (This->smallBlockChain!=0) { - SmallBlockChainStream_WriteAt(This->smallBlockChain, + res = SmallBlockChainStream_WriteAt(This->smallBlockChain, This->currentPosition, cb, pv, @@ -408,21 +437,27 @@ static HRESULT WINAPI StgStreamImpl_Write( } else if (This->bigBlockChain!=0) { - BlockChainStream_WriteAt(This->bigBlockChain, + res = BlockChainStream_WriteAt(This->bigBlockChain, This->currentPosition, cb, pv, pcbWritten); } else + { + /* this should never happen because the IStream_SetSize call above will + * make sure a big or small block chain is created */ assert(FALSE); + res = 0; + } /* * Advance the position pointer for the number of positions written. */ This->currentPosition.u.LowPart += *pcbWritten; - return S_OK; + TRACE("<-- S_OK, written %u\n", *pcbWritten); + return res; } /*** @@ -443,9 +478,19 @@ static HRESULT WINAPI StgStreamImpl_Seek( ULARGE_INTEGER newPosition; - TRACE("(%p, %ld, %ld, %p)\n", + TRACE("(%p, %d, %d, %p)\n", iface, dlibMove.u.LowPart, dwOrigin, plibNewPosition); + /* + * fail if the stream has no parent (as does windows) + */ + + if (!This->parentStorage) + { + WARN("storage reverted\n"); + return STG_E_REVERTED; + } + /* * The caller is allowed to pass in NULL as the new position return value. * If it happens, we assign it to a dynamic variable to avoid special cases @@ -473,6 +518,7 @@ static HRESULT WINAPI StgStreamImpl_Seek( *plibNewPosition = This->streamSize; break; default: + WARN("invalid dwOrigin %d\n", dwOrigin); return STG_E_INVALIDFUNCTION; } @@ -504,19 +550,31 @@ static HRESULT WINAPI StgStreamImpl_SetSize( StgProperty curProperty; BOOL Success; - TRACE("(%p, %ld)\n", iface, libNewSize.u.LowPart); + TRACE("(%p, %d)\n", iface, libNewSize.u.LowPart); + + if(!This->parentStorage) + { + WARN("storage reverted\n"); + return STG_E_REVERTED; + } /* * As documented. */ if (libNewSize.u.HighPart != 0) + { + WARN("invalid value for libNewSize.u.HighPart %d\n", libNewSize.u.HighPart); return STG_E_INVALIDFUNCTION; + } /* * Do we have permission? */ if (!(This->grfMode & (STGM_WRITE | STGM_READWRITE))) + { + WARN("access denied\n"); return STG_E_ACCESSDENIED; + } if (This->streamSize.u.LowPart == libNewSize.u.LowPart) return S_OK; @@ -609,18 +667,26 @@ static HRESULT WINAPI StgStreamImpl_CopyTo( ULARGE_INTEGER* pcbRead, /* [out] */ ULARGE_INTEGER* pcbWritten) /* [out] */ { + StgStreamImpl* const This=(StgStreamImpl*)iface; HRESULT hr = S_OK; BYTE tmpBuffer[128]; ULONG bytesRead, bytesWritten, copySize; ULARGE_INTEGER totalBytesRead; ULARGE_INTEGER totalBytesWritten; - TRACE("(%p, %p, %ld, %p, %p)\n", + TRACE("(%p, %p, %d, %p, %p)\n", iface, pstm, cb.u.LowPart, pcbRead, pcbWritten); /* * Sanity check */ + + if (!This->parentStorage) + { + WARN("storage reverted\n"); + return STG_E_REVERTED; + } + if ( pstm == 0 ) return STG_E_INVALIDPOINTER; @@ -653,6 +719,7 @@ static HRESULT WINAPI StgStreamImpl_CopyTo( if (bytesRead != bytesWritten) { hr = STG_E_MEDIUMFULL; + WARN("medium full\n"); break; } @@ -691,6 +758,14 @@ static HRESULT WINAPI StgStreamImpl_Commit( IStream* iface, DWORD grfCommitFlags) /* [in] */ { + StgStreamImpl* const This=(StgStreamImpl*)iface; + + if (!This->parentStorage) + { + WARN("storage reverted\n"); + return STG_E_REVERTED; + } + return S_OK; } @@ -714,6 +789,14 @@ static HRESULT WINAPI StgStreamImpl_LockRegion( ULARGE_INTEGER cb, /* [in] */ DWORD dwLockType) /* [in] */ { + StgStreamImpl* const This=(StgStreamImpl*)iface; + + if (!This->parentStorage) + { + WARN("storage reverted\n"); + return STG_E_REVERTED; + } + FIXME("not implemented!\n"); return E_NOTIMPL; } @@ -724,6 +807,14 @@ static HRESULT WINAPI StgStreamImpl_UnlockRegion( ULARGE_INTEGER cb, /* [in] */ DWORD dwLockType) /* [in] */ { + StgStreamImpl* const This=(StgStreamImpl*)iface; + + if (!This->parentStorage) + { + WARN("storage reverted\n"); + return STG_E_REVERTED; + } + FIXME("not implemented!\n"); return E_NOTIMPL; } @@ -744,16 +835,28 @@ static HRESULT WINAPI StgStreamImpl_Stat( StgStreamImpl* const This=(StgStreamImpl*)iface; StgProperty curProperty; - BOOL readSucessful; + BOOL readSuccessful; + + TRACE("%p %p %d\n", This, pstatstg, grfStatFlag); + + /* + * if stream has no parent, return STG_E_REVERTED + */ + + if (!This->parentStorage) + { + WARN("storage reverted\n"); + return STG_E_REVERTED; + } /* * Read the information from the property. */ - readSucessful = StorageImpl_ReadProperty(This->parentStorage->ancestorStorage, + readSuccessful = StorageImpl_ReadProperty(This->parentStorage->ancestorStorage, This->ownerProperty, &curProperty); - if (readSucessful) + if (readSuccessful) { StorageUtl_CopyPropertyToSTATSTG(pstatstg, &curProperty, @@ -764,6 +867,7 @@ static HRESULT WINAPI StgStreamImpl_Stat( return S_OK; } + WARN("failed to read properties\n"); return E_FAIL; } @@ -788,9 +892,15 @@ static HRESULT WINAPI StgStreamImpl_Clone( StgStreamImpl* new_stream; LARGE_INTEGER seek_pos; + TRACE("%p %p\n", This, ppstm); + /* * Sanity check */ + + if (!This->parentStorage) + return STG_E_REVERTED; + if ( ppstm == 0 ) return STG_E_INVALIDPOINTER; @@ -800,6 +910,8 @@ static HRESULT WINAPI StgStreamImpl_Clone( return STG_E_INSUFFICIENTMEMORY; /* Currently the only reason for new_stream=0 */ *ppstm = (IStream*) new_stream; + IStream_AddRef(*ppstm); + seek_pos.QuadPart = This->currentPosition.QuadPart; hres=StgStreamImpl_Seek (*ppstm, seek_pos, STREAM_SEEK_SET, NULL); @@ -858,12 +970,19 @@ StgStreamImpl* StgStreamImpl_Construct( newStream->lpVtbl = &StgStreamImpl_Vtbl; newStream->ref = 0; + newStream->parentStorage = parentStorage; + /* * We want to nail-down the reference to the storage in case the * stream out-lives the storage in the client application. + * + * -- IStorage_AddRef((IStorage*)newStream->parentStorage); + * + * No, don't do this. Some apps call IStorage_Release without + * calling IStream_Release first. If we grab a reference the + * file is not closed, and the app fails when it tries to + * reopen the file (Easy-PC, for example) */ - newStream->parentStorage = parentStorage; - IStorage_AddRef((IStorage*)newStream->parentStorage); newStream->grfMode = grfMode; newStream->ownerProperty = ownerProperty; @@ -887,6 +1006,9 @@ StgStreamImpl* StgStreamImpl_Construct( * this stream are large or small. */ StgStreamImpl_OpenBlockChain(newStream); + + /* add us to the storage's list of active streams */ + StorageBaseImpl_AddStream(parentStorage, newStream); } return newStream; diff --git a/reactos/dll/win32/ole32/storage.c b/reactos/dll/win32/ole32/storage.c index d1bd1933727..401c9845442 100644 --- a/reactos/dll/win32/ole32/storage.c +++ b/reactos/dll/win32/ole32/storage.c @@ -18,7 +18,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" @@ -353,12 +353,12 @@ STORAGE_get_big_block(stream_access16 *str,int n,BYTE *block) if ((SetFilePointer( str->hf, (n+1)*BIGSIZE, NULL, SEEK_SET ) == INVALID_SET_FILE_POINTER) && GetLastError()) { - WARN("(%p,%d,%p), seek failed (%ld)\n",str->hf, n, block, GetLastError()); + WARN("(%p,%d,%p), seek failed (%d)\n",str->hf, n, block, GetLastError()); return FALSE; } if (!ReadFile( str->hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE) { - WARN("(hf=%p, block size %d): read didn't read (%ld)\n",str->hf,n,GetLastError()); + WARN("(hf=%p, block size %d): read didn't read (%d)\n",str->hf,n,GetLastError()); return FALSE; } } else { @@ -382,7 +382,7 @@ STORAGE_get_big_block(stream_access16 *str,int n,BYTE *block) (LPVOID)args, (LPDWORD)&hres )) { - ERR("CallTo16 ILockBytes16::ReadAt() failed, hres %lx\n",hres); + ERR("CallTo16 ILockBytes16::ReadAt() failed, hres %x\n",hres); return FALSE; } memcpy(block, MapSL(args[3]), BIGSIZE); @@ -414,7 +414,7 @@ _ilockbytes16_writeat(SEGPTR lockbytes, DWORD offset, DWORD length, void *buffer (LPVOID)args, (LPDWORD)&hres )) { - ERR("CallTo16 ILockBytes16::WriteAt() failed, hres %lx\n",hres); + ERR("CallTo16 ILockBytes16::WriteAt() failed, hres %x\n",hres); return FALSE; } UnMapLS(args[3]); @@ -434,12 +434,12 @@ STORAGE_put_big_block(stream_access16 *str,int n,BYTE *block) if ((SetFilePointer( str->hf, (n+1)*BIGSIZE, NULL, SEEK_SET ) == INVALID_SET_FILE_POINTER) && GetLastError()) { - WARN("seek failed (%ld)\n",GetLastError()); + WARN("seek failed (%d)\n",GetLastError()); return FALSE; } if (!WriteFile( str->hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE) { - WARN(" write failed (%ld)\n",GetLastError()); + WARN(" write failed (%d)\n",GetLastError()); return FALSE; } return TRUE; @@ -719,9 +719,9 @@ STORAGE_dump_pps_entry(struct storage_pps_entry *stde) { return; DPRINTF("name: %s\n",name); DPRINTF("type: %d\n",stde->pps_type); - DPRINTF("prev pps: %ld\n",stde->pps_prev); - DPRINTF("next pps: %ld\n",stde->pps_next); - DPRINTF("dir pps: %ld\n",stde->pps_dir); + DPRINTF("prev pps: %d\n",stde->pps_prev); + DPRINTF("next pps: %d\n",stde->pps_next); + DPRINTF("dir pps: %d\n",stde->pps_dir); DPRINTF("guid: %s\n",debugstr_guid(&(stde->pps_guid))); if (stde->pps_type !=2) { time_t t; @@ -733,8 +733,8 @@ STORAGE_dump_pps_entry(struct storage_pps_entry *stde) { t = dw; DPRINTF("ts2: %s\n",ctime(&t)); } - DPRINTF("startblock: %ld\n",stde->pps_sb); - DPRINTF("size: %ld\n",stde->pps_size); + DPRINTF("startblock: %d\n",stde->pps_sb); + DPRINTF("size: %d\n",stde->pps_size); } /****************************************************************************** @@ -1071,7 +1071,7 @@ typedef struct /****************************************************************************** * IStream16_QueryInterface [STORAGE.518] */ -HRESULT IStream16_fnQueryInterface( +HRESULT CDECL IStream16_fnQueryInterface( IStream16* iface,REFIID refiid,LPVOID *obj ) { IStream16Impl *This = (IStream16Impl *)iface; @@ -1087,7 +1087,7 @@ HRESULT IStream16_fnQueryInterface( /****************************************************************************** * IStream16_AddRef [STORAGE.519] */ -ULONG IStream16_fnAddRef(IStream16* iface) { +ULONG CDECL IStream16_fnAddRef(IStream16* iface) { IStream16Impl *This = (IStream16Impl *)iface; return InterlockedIncrement(&This->ref); } @@ -1107,7 +1107,7 @@ _ilockbytes16_addref(SEGPTR lockbytes) { (LPVOID)args, (LPDWORD)&hres )) - ERR("CallTo16 ILockBytes16::AddRef() failed, hres %lx\n",hres); + ERR("CallTo16 ILockBytes16::AddRef() failed, hres %x\n",hres); } static void @@ -1125,7 +1125,7 @@ _ilockbytes16_release(SEGPTR lockbytes) { (LPVOID)args, (LPDWORD)&hres )) - ERR("CallTo16 ILockBytes16::Release() failed, hres %lx\n",hres); + ERR("CallTo16 ILockBytes16::Release() failed, hres %x\n",hres); } static void @@ -1143,13 +1143,13 @@ _ilockbytes16_flush(SEGPTR lockbytes) { (LPVOID)args, (LPDWORD)&hres )) - ERR("CallTo16 ILockBytes16::Flush() failed, hres %lx\n",hres); + ERR("CallTo16 ILockBytes16::Flush() failed, hres %x\n",hres); } /****************************************************************************** * IStream16_Release [STORAGE.520] */ -ULONG IStream16_fnRelease(IStream16* iface) { +ULONG CDECL IStream16_fnRelease(IStream16* iface) { IStream16Impl *This = (IStream16Impl *)iface; ULONG ref; @@ -1176,11 +1176,11 @@ ULONG IStream16_fnRelease(IStream16* iface) { * FIXME * Does not handle 64 bits */ -HRESULT IStream16_fnSeek( +HRESULT CDECL IStream16_fnSeek( IStream16* iface,LARGE_INTEGER offset,DWORD whence,ULARGE_INTEGER *newpos ) { IStream16Impl *This = (IStream16Impl *)iface; - TRACE_(relay)("(%p)->([%ld.%ld],%ld,%p)\n",This,offset.u.HighPart,offset.u.LowPart,whence,newpos); + TRACE_(relay)("(%p)->([%d.%d],%d,%p)\n",This,offset.u.HighPart,offset.u.LowPart,whence,newpos); switch (whence) { /* unix SEEK_xx should be the same as win95 ones */ @@ -1220,7 +1220,7 @@ HRESULT IStream16_fnSeek( /****************************************************************************** * IStream16_Read [STORAGE.521] */ -HRESULT IStream16_fnRead( +HRESULT CDECL IStream16_fnRead( IStream16* iface,void *pv,ULONG cb,ULONG *pcbRead ) { IStream16Impl *This = (IStream16Impl *)iface; @@ -1229,7 +1229,7 @@ HRESULT IStream16_fnRead( int blocknr; LPBYTE pbv = pv; - TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbRead); + TRACE_(relay)("(%p)->(%p,%d,%p)\n",This,pv,cb,pcbRead); if (!pcbRead) bytesread=&xxread; *bytesread = 0; @@ -1282,7 +1282,7 @@ HRESULT IStream16_fnRead( /****************************************************************************** * IStream16_Write [STORAGE.522] */ -HRESULT IStream16_fnWrite( +HRESULT CDECL IStream16_fnWrite( IStream16* iface,const void *pv,ULONG cb,ULONG *pcbWrite ) { IStream16Impl *This = (IStream16Impl *)iface; @@ -1294,7 +1294,7 @@ HRESULT IStream16_fnWrite( if (!pcbWrite) byteswritten=&xxwritten; *byteswritten = 0; - TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbWrite); + TRACE_(relay)("(%p)->(%p,%d,%p)\n",This,pv,cb,pcbWrite); /* do we need to junk some blocks? */ newsize = This->offset.u.LowPart+cb; oldsize = This->stde.pps_size; @@ -1667,7 +1667,7 @@ ULONG WINAPI IStream_fnRelease(IStream* iface) { /****************************************************************************** * IStorage16_QueryInterface [STORAGE.500] */ -HRESULT IStorage16_fnQueryInterface( +HRESULT CDECL IStorage16_fnQueryInterface( IStorage16* iface,REFIID refiid,LPVOID *obj ) { IStorage16Impl *This = (IStorage16Impl *)iface; @@ -1684,7 +1684,7 @@ HRESULT IStorage16_fnQueryInterface( /****************************************************************************** * IStorage16_AddRef [STORAGE.501] */ -ULONG IStorage16_fnAddRef(IStorage16* iface) { +ULONG CDECL IStorage16_fnAddRef(IStorage16* iface) { IStorage16Impl *This = (IStorage16Impl *)iface; return InterlockedIncrement(&This->ref); } @@ -1692,7 +1692,7 @@ ULONG IStorage16_fnAddRef(IStorage16* iface) { /****************************************************************************** * IStorage16_Release [STORAGE.502] */ -ULONG IStorage16_fnRelease(IStorage16* iface) { +ULONG CDECL IStorage16_fnRelease(IStorage16* iface) { IStorage16Impl *This = (IStorage16Impl *)iface; ULONG ref; ref = InterlockedDecrement(&This->ref); @@ -1707,14 +1707,14 @@ ULONG IStorage16_fnRelease(IStorage16* iface) { /****************************************************************************** * IStorage16_Stat [STORAGE.517] */ -HRESULT IStorage16_fnStat( +HRESULT CDECL IStorage16_fnStat( LPSTORAGE16 iface,STATSTG16 *pstatstg, DWORD grfStatFlag ) { IStorage16Impl *This = (IStorage16Impl *)iface; DWORD len = WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, NULL, 0, NULL, NULL ); LPSTR nameA = HeapAlloc( GetProcessHeap(), 0, len ); - TRACE("(%p)->(%p,0x%08lx)\n", + TRACE("(%p)->(%p,0x%08x)\n", This,pstatstg,grfStatFlag ); WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, nameA, len, NULL, NULL ); @@ -1735,11 +1735,11 @@ HRESULT IStorage16_fnStat( /****************************************************************************** * IStorage16_Commit [STORAGE.509] */ -HRESULT IStorage16_fnCommit( +HRESULT CDECL IStorage16_fnCommit( LPSTORAGE16 iface,DWORD commitflags ) { IStorage16Impl *This = (IStorage16Impl *)iface; - FIXME("(%p)->(0x%08lx),STUB!\n", + FIXME("(%p)->(0x%08x),STUB!\n", This,commitflags ); return S_OK; @@ -1748,9 +1748,9 @@ HRESULT IStorage16_fnCommit( /****************************************************************************** * IStorage16_CopyTo [STORAGE.507] */ -HRESULT IStorage16_fnCopyTo(LPSTORAGE16 iface,DWORD ciidExclude,const IID *rgiidExclude,SNB16 SNB16Exclude,IStorage16 *pstgDest) { +HRESULT CDECL IStorage16_fnCopyTo(LPSTORAGE16 iface,DWORD ciidExclude,const IID *rgiidExclude,SNB16 SNB16Exclude,IStorage16 *pstgDest) { IStorage16Impl *This = (IStorage16Impl *)iface; - FIXME("IStorage16(%p)->(0x%08lx,%s,%p,%p),stub!\n", + FIXME("IStorage16(%p)->(0x%08x,%s,%p,%p),stub!\n", This,ciidExclude,debugstr_guid(rgiidExclude),SNB16Exclude,pstgDest ); return S_OK; @@ -1760,7 +1760,7 @@ HRESULT IStorage16_fnCopyTo(LPSTORAGE16 iface,DWORD ciidExclude,const IID *rgiid /****************************************************************************** * IStorage16_CreateStorage [STORAGE.505] */ -HRESULT IStorage16_fnCreateStorage( +HRESULT CDECL IStorage16_fnCreateStorage( LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD dwStgFormat,DWORD reserved2, IStorage16 **ppstg ) { IStorage16Impl *This = (IStorage16Impl *)iface; @@ -1772,7 +1772,7 @@ HRESULT IStorage16_fnCreateStorage( int nPPSEntries; READ_HEADER(&This->str); - TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n", + TRACE("(%p)->(%s,0x%08x,0x%08x,0x%08x,%p)\n", This,pwcsName,grfMode,dwStgFormat,reserved2,ppstg ); if (grfMode & STGM_TRANSACTED) @@ -1829,7 +1829,7 @@ HRESULT IStorage16_fnCreateStorage( /****************************************************************************** * IStorage16_CreateStream [STORAGE.503] */ -HRESULT IStorage16_fnCreateStream( +HRESULT CDECL IStorage16_fnCreateStream( LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream16 **ppstm ) { IStorage16Impl *This = (IStorage16Impl *)iface; @@ -1839,7 +1839,7 @@ HRESULT IStorage16_fnCreateStream( BOOL ret; int nPPSEntries; - TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n", + TRACE("(%p)->(%s,0x%08x,0x%08x,0x%08x,%p)\n", This,pwcsName,grfMode,reserved1,reserved2,ppstm ); if (grfMode & STGM_TRANSACTED) @@ -1893,7 +1893,7 @@ HRESULT IStorage16_fnCreateStream( /****************************************************************************** * IStorage16_OpenStorage [STORAGE.506] */ -HRESULT IStorage16_fnOpenStorage( +HRESULT CDECL IStorage16_fnOpenStorage( LPSTORAGE16 iface,LPCOLESTR16 pwcsName, IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg ) { IStorage16Impl *This = (IStorage16Impl *)iface; @@ -1901,7 +1901,7 @@ HRESULT IStorage16_fnOpenStorage( WCHAR name[33]; int newpps; - TRACE("(%p)->(%s,%p,0x%08lx,%p,0x%08lx,%p)\n", + TRACE("(%p)->(%s,%p,0x%08x,%p,0x%08x,%p)\n", This,pwcsName,pstgPrio,grfMode,snbExclude,reserved,ppstg ); if (grfMode & STGM_TRANSACTED) @@ -1933,7 +1933,7 @@ HRESULT IStorage16_fnOpenStorage( /****************************************************************************** * IStorage16_OpenStream [STORAGE.504] */ -HRESULT IStorage16_fnOpenStream( +HRESULT CDECL IStorage16_fnOpenStream( LPSTORAGE16 iface,LPCOLESTR16 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream16 **ppstm ) { IStorage16Impl *This = (IStorage16Impl *)iface; @@ -1941,7 +1941,7 @@ HRESULT IStorage16_fnOpenStream( WCHAR name[33]; int newpps; - TRACE("(%p)->(%s,%p,0x%08lx,0x%08lx,%p)\n", + TRACE("(%p)->(%s,%p,0x%08x,0x%08x,%p)\n", This,pwcsName,reserved1,grfMode,reserved2,ppstm ); if (grfMode & STGM_TRANSACTED) @@ -2052,13 +2052,13 @@ HRESULT WINAPI StgCreateDocFile16( IStorage16Impl* lpstg; struct storage_pps_entry stde; - TRACE("(%s,0x%08lx,0x%08lx,%p)\n", + TRACE("(%s,0x%08x,0x%08x,%p)\n", pwcsName,grfMode,reserved,ppstgOpen ); _create_istorage16(ppstgOpen); hf = CreateFileA(pwcsName,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,0,0); if (hf==INVALID_HANDLE_VALUE) { - WARN("couldn't open file for storage:%ld\n",GetLastError()); + WARN("couldn't open file for storage:%d\n",GetLastError()); return E_FAIL; } lpstg = MapSL((SEGPTR)*ppstgOpen); @@ -2113,7 +2113,7 @@ HRESULT WINAPI StgOpenStorage16( IStorage16Impl* lpstg; struct storage_pps_entry stde; - TRACE("(%s,%p,0x%08lx,%p,%ld,%p)\n", + TRACE("(%s,%p,0x%08x,%p,%d,%p)\n", pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen ); _create_istorage16(ppstgOpen); @@ -2168,7 +2168,7 @@ HRESULT WINAPI StgIsStorageILockBytes16(SEGPTR plkbyt) (LPVOID)args, (LPDWORD)&hres )) { - ERR("CallTo16 ILockBytes16::ReadAt() failed, hres %lx\n",hres); + ERR("CallTo16 ILockBytes16::ReadAt() failed, hres %x\n",hres); return hres; } if (memcmp(MapSL(args[3]), STORAGE_magic, sizeof(STORAGE_magic)) == 0) { @@ -2181,9 +2181,12 @@ HRESULT WINAPI StgIsStorageILockBytes16(SEGPTR plkbyt) /****************************************************************************** * StgOpenStorageOnILockBytes [STORAGE.4] + * + * PARAMS + * plkbyt FIXME: Should probably be an ILockBytes16 *. */ HRESULT WINAPI StgOpenStorageOnILockBytes16( - SEGPTR /*ILockBytes16 **/plkbyt, + SEGPTR plkbyt, IStorage16 *pstgPriority, DWORD grfMode, SNB16 snbExclude, @@ -2194,7 +2197,7 @@ HRESULT WINAPI StgOpenStorageOnILockBytes16( int i,ret; struct storage_pps_entry stde; - FIXME("(%lx, %p, 0x%08lx, %d, %lx, %p)\n", plkbyt, pstgPriority, grfMode, (int)snbExclude, reserved, ppstgOpen); + FIXME("(%x, %p, 0x%08x, %d, %x, %p)\n", plkbyt, pstgPriority, grfMode, (int)snbExclude, reserved, ppstgOpen); if ((plkbyt == 0) || (ppstgOpen == 0)) return STG_E_INVALIDPOINTER; @@ -2241,7 +2244,7 @@ HRESULT WINAPI ReadClassStg16(SEGPTR pstg, CLSID *pclsid) HRESULT hres; DWORD args[3]; - TRACE("(%lx, %p)\n", pstg, pclsid); + TRACE("(%x, %p)\n", pstg, pclsid); if(pclsid==NULL) return E_POINTER; @@ -2262,7 +2265,7 @@ HRESULT WINAPI ReadClassStg16(SEGPTR pstg, CLSID *pclsid) (LPDWORD)&hres )) { WOWGlobalUnlockFree16(args[1]); - ERR("CallTo16 IStorage16::Stat() failed, hres %lx\n",hres); + ERR("CallTo16 IStorage16::Stat() failed, hres %x\n",hres); return hres; } memcpy(&statstg, MapSL(args[1]), sizeof(STATSTG16)); diff --git a/reactos/dll/win32/ole32/storage32.c b/reactos/dll/win32/ole32/storage32.c index c9d696e8c2c..97f53dfee7e 100644 --- a/reactos/dll/win32/ole32/storage32.c +++ b/reactos/dll/win32/ole32/storage32.c @@ -22,7 +22,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * NOTES * The compound file implementation of IStorage used for create @@ -62,8 +62,55 @@ WINE_DEFAULT_DEBUG_CHANNEL(storage); #define OLESTREAM_ID 0x501 #define OLESTREAM_MAX_STR_LEN 255 +/* + * These are signatures to detect the type of Document file. + */ +static const BYTE STORAGE_magic[8] ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1}; +static const BYTE STORAGE_oldmagic[8] ={0xd0,0xcf,0x11,0xe0,0x0e,0x11,0xfc,0x0d}; + static const char rootPropertyName[] = "Root Entry"; +/**************************************************************************** + * Storage32InternalImpl definitions. + * + * Definition of the implementation structure for the IStorage32 interface. + * This one implements the IStorage32 interface for storage that are + * inside another storage. + */ +struct StorageInternalImpl +{ + struct StorageBaseImpl base; + /* + * There is no specific data for this class. + */ +}; +typedef struct StorageInternalImpl StorageInternalImpl; + +/* Method definitions for the Storage32InternalImpl class. */ +static StorageInternalImpl* StorageInternalImpl_Construct(StorageImpl* ancestorStorage, + DWORD openFlags, ULONG rootTropertyIndex); +static void StorageImpl_Destroy(StorageBaseImpl* iface); +static BOOL StorageImpl_ReadBigBlock(StorageImpl* This, ULONG blockIndex, void* buffer); +static BOOL StorageImpl_WriteBigBlock(StorageImpl* This, ULONG blockIndex, void* buffer); +static void StorageImpl_SetNextBlockInChain(StorageImpl* This, ULONG blockIndex, ULONG nextBlock); +static HRESULT StorageImpl_LoadFileHeader(StorageImpl* This); +static void StorageImpl_SaveFileHeader(StorageImpl* This); + +static void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex); +static ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This); +static ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex); +static ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex); +static void Storage32Impl_SetExtDepotBlock(StorageImpl* This, ULONG depotIndex, ULONG blockIndex); + +static ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This); +static ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This); +static ULONG BlockChainStream_GetCount(BlockChainStream* This); + +static ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This); +static BOOL StorageImpl_WriteDWordToBigBlock( StorageImpl* This, + ULONG blockIndex, ULONG offset, DWORD value); +static BOOL StorageImpl_ReadDWordFromBigBlock( StorageImpl* This, + ULONG blockIndex, ULONG offset, DWORD* value); /* OLESTREAM memory structure to use for Get and Put Routines */ /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */ @@ -166,10 +213,78 @@ static DWORD GetCreationModeFromSTGM(DWORD stgm); extern const IPropertySetStorageVtbl IPropertySetStorage_Vtbl; +/**************************************************************************** + * IEnumSTATSTGImpl definitions. + * + * Definition of the implementation structure for the IEnumSTATSTGImpl interface. + * This class allows iterating through the content of a storage and to find + * specific items inside it. + */ +struct IEnumSTATSTGImpl +{ + const IEnumSTATSTGVtbl *lpVtbl; /* Needs to be the first item in the struct + * since we want to cast this in an IEnumSTATSTG pointer */ + + LONG ref; /* Reference count */ + StorageImpl* parentStorage; /* Reference to the parent storage */ + ULONG firstPropertyNode; /* Index of the root of the storage to enumerate */ + + /* + * The current implementation of the IEnumSTATSTGImpl class uses a stack + * to walk the property sets to get the content of a storage. This stack + * is implemented by the following 3 data members + */ + ULONG stackSize; + ULONG stackMaxSize; + ULONG* stackToVisit; + +#define ENUMSTATSGT_SIZE_INCREMENT 10 +}; + + +static IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(StorageImpl* This, ULONG firstPropertyNode); +static void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This); +static void IEnumSTATSTGImpl_PushSearchNode(IEnumSTATSTGImpl* This, ULONG nodeToPush); +static ULONG IEnumSTATSTGImpl_PopSearchNode(IEnumSTATSTGImpl* This, BOOL remove); +static ULONG IEnumSTATSTGImpl_FindProperty(IEnumSTATSTGImpl* This, const OLECHAR* lpszPropName, + StgProperty* buffer); +static INT IEnumSTATSTGImpl_FindParentProperty(IEnumSTATSTGImpl *This, ULONG childProperty, + StgProperty *currentProperty, ULONG *propertyId); + +/************************************************************************ +** Block Functions +*/ + +static ULONG BLOCK_GetBigBlockOffset(ULONG index) +{ + if (index == 0xffffffff) + index = 0; + else + index ++; + + return index * BIG_BLOCK_SIZE; +} /************************************************************************ ** Storage32BaseImpl implementatiion */ +static HRESULT StorageImpl_ReadAt(StorageImpl* This, + ULARGE_INTEGER offset, + void* buffer, + ULONG size, + ULONG* bytesRead) +{ + return BIGBLOCKFILE_ReadAt(This->bigBlockFile,offset,buffer,size,bytesRead); +} + +static HRESULT StorageImpl_WriteAt(StorageImpl* This, + ULARGE_INTEGER offset, + void* buffer, + const ULONG size, + ULONG* bytesWritten) +{ + return BIGBLOCKFILE_WriteAt(This->bigBlockFile,offset,buffer,size,bytesWritten); +} /************************************************************************ * Storage32BaseImpl_QueryInterface (IUnknown) @@ -179,7 +294,7 @@ extern const IPropertySetStorageVtbl IPropertySetStorage_Vtbl; * * See Windows documentation for more details on IUnknown methods. */ -HRESULT WINAPI StorageBaseImpl_QueryInterface( +static HRESULT WINAPI StorageBaseImpl_QueryInterface( IStorage* iface, REFIID riid, void** ppvObject) @@ -199,15 +314,12 @@ HRESULT WINAPI StorageBaseImpl_QueryInterface( /* * Compare the riid with the interface IDs implemented by this object. */ - if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) + if (IsEqualGUID(&IID_IUnknown, riid) || + IsEqualGUID(&IID_IStorage, riid)) { *ppvObject = (IStorage*)This; } - else if (memcmp(&IID_IStorage, riid, sizeof(IID_IStorage)) == 0) - { - *ppvObject = (IStorage*)This; - } - else if (memcmp(&IID_IPropertySetStorage, riid, sizeof(IID_IPropertySetStorage)) == 0) + else if (IsEqualGUID(&IID_IPropertySetStorage, riid)) { *ppvObject = (IStorage*)&This->pssVtbl; } @@ -235,13 +347,13 @@ HRESULT WINAPI StorageBaseImpl_QueryInterface( * * See Windows documentation for more details on IUnknown methods. */ -ULONG WINAPI StorageBaseImpl_AddRef( +static ULONG WINAPI StorageBaseImpl_AddRef( IStorage* iface) { StorageBaseImpl *This = (StorageBaseImpl *)iface; ULONG ref = InterlockedIncrement(&This->ref); - TRACE("(%p) AddRef to %ld\n", This, ref); + TRACE("(%p) AddRef to %d\n", This, ref); return ref; } @@ -254,7 +366,7 @@ ULONG WINAPI StorageBaseImpl_AddRef( * * See Windows documentation for more details on IUnknown methods. */ -ULONG WINAPI StorageBaseImpl_Release( +static ULONG WINAPI StorageBaseImpl_Release( IStorage* iface) { StorageBaseImpl *This = (StorageBaseImpl *)iface; @@ -263,7 +375,7 @@ ULONG WINAPI StorageBaseImpl_Release( */ ULONG ref = InterlockedDecrement(&This->ref); - TRACE("(%p) ReleaseRef to %ld\n", This, ref); + TRACE("(%p) ReleaseRef to %d\n", This, ref); /* * If the reference count goes down to 0, perform suicide. @@ -288,7 +400,7 @@ ULONG WINAPI StorageBaseImpl_Release( * * See Windows documentation for more details on IStorage methods. */ -HRESULT WINAPI StorageBaseImpl_OpenStream( +static HRESULT WINAPI StorageBaseImpl_OpenStream( IStorage* iface, const OLECHAR* pwcsName, /* [string][in] */ void* reserved1, /* [unique][in] */ @@ -302,9 +414,8 @@ HRESULT WINAPI StorageBaseImpl_OpenStream( StgProperty currentProperty; ULONG foundPropertyIndex; HRESULT res = STG_E_UNKNOWN; - DWORD parent_grfMode; - TRACE("(%p, %s, %p, %lx, %ld, %p)\n", + TRACE("(%p, %s, %p, %x, %d, %p)\n", iface, debugstr_w(pwcsName), reserved1, grfMode, reserved2, ppstm); /* @@ -324,7 +435,8 @@ HRESULT WINAPI StorageBaseImpl_OpenStream( /* * Validate the STGM flags */ - if ( FAILED( validateSTGM(grfMode) )) + if ( FAILED( validateSTGM(grfMode) ) || + STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE) { res = STG_E_INVALIDFLAG; goto end; @@ -333,22 +445,22 @@ HRESULT WINAPI StorageBaseImpl_OpenStream( /* * As documented. */ - if ( STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE || - (grfMode & STGM_DELETEONRELEASE) || - (grfMode & STGM_TRANSACTED) ) + if ( (grfMode & STGM_DELETEONRELEASE) || (grfMode & STGM_TRANSACTED) ) { res = STG_E_INVALIDFUNCTION; goto end; } /* - * Check that we're compatible with the parent's storage mode + * Check that we're compatible with the parent's storage mode, but + * only if we are not in transacted mode */ - parent_grfMode = STGM_ACCESS_MODE( This->ancestorStorage->base.openFlags ); - if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( parent_grfMode ) ) - { - res = STG_E_ACCESSDENIED; - goto end; + if(!(This->ancestorStorage->base.openFlags & STGM_TRANSACTED)) { + if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->openFlags ) ) + { + res = STG_E_ACCESSDENIED; + goto end; + } } /* @@ -403,7 +515,7 @@ HRESULT WINAPI StorageBaseImpl_OpenStream( end: if (res == S_OK) TRACE("<-- IStream %p\n", *ppstm); - TRACE("<-- %08lx\n", res); + TRACE("<-- %08x\n", res); return res; } @@ -414,7 +526,7 @@ end: * * See Windows documentation for more details on IStorage methods. */ -HRESULT WINAPI StorageBaseImpl_OpenStorage( +static HRESULT WINAPI StorageBaseImpl_OpenStorage( IStorage* iface, const OLECHAR* pwcsName, /* [string][unique][in] */ IStorage* pstgPriority, /* [unique][in] */ @@ -429,9 +541,8 @@ HRESULT WINAPI StorageBaseImpl_OpenStorage( StgProperty currentProperty; ULONG foundPropertyIndex; HRESULT res = STG_E_UNKNOWN; - DWORD parent_grfMode; - TRACE("(%p, %s, %p, %lx, %p, %ld, %p)\n", + TRACE("(%p, %s, %p, %x, %p, %d, %p)\n", iface, debugstr_w(pwcsName), pstgPriority, grfMode, snbExclude, reserved, ppstg); @@ -472,13 +583,15 @@ HRESULT WINAPI StorageBaseImpl_OpenStorage( } /* - * Check that we're compatible with the parent's storage mode + * Check that we're compatible with the parent's storage mode, + * but only if we are not transacted */ - parent_grfMode = STGM_ACCESS_MODE( This->ancestorStorage->base.openFlags ); - if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( parent_grfMode ) ) - { - res = STG_E_ACCESSDENIED; - goto end; + if(!(This->ancestorStorage->base.openFlags & STGM_TRANSACTED)) { + if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->openFlags ) ) + { + res = STG_E_ACCESSDENIED; + goto end; + } } /* @@ -541,7 +654,7 @@ HRESULT WINAPI StorageBaseImpl_OpenStorage( res = STG_E_FILENOTFOUND; end: - TRACE("<-- %08lx\n", res); + TRACE("<-- %08x\n", res); return res; } @@ -553,7 +666,7 @@ end: * * See Windows documentation for more details on IStorage methods. */ -HRESULT WINAPI StorageBaseImpl_EnumElements( +static HRESULT WINAPI StorageBaseImpl_EnumElements( IStorage* iface, DWORD reserved1, /* [in] */ void* reserved2, /* [size_is][unique][in] */ @@ -563,7 +676,7 @@ HRESULT WINAPI StorageBaseImpl_EnumElements( StorageBaseImpl *This = (StorageBaseImpl *)iface; IEnumSTATSTGImpl* newEnum; - TRACE("(%p, %ld, %p, %ld, %p)\n", + TRACE("(%p, %d, %p, %d, %p)\n", iface, reserved1, reserved2, reserved3, ppenum); /* @@ -602,7 +715,7 @@ HRESULT WINAPI StorageBaseImpl_EnumElements( * * See Windows documentation for more details on IStorage methods. */ -HRESULT WINAPI StorageBaseImpl_Stat( +static HRESULT WINAPI StorageBaseImpl_Stat( IStorage* iface, STATSTG* pstatstg, /* [out] */ DWORD grfStatFlag) /* [in] */ @@ -612,7 +725,7 @@ HRESULT WINAPI StorageBaseImpl_Stat( BOOL readSuccessful; HRESULT res = STG_E_UNKNOWN; - TRACE("(%p, %p, %lx)\n", + TRACE("(%p, %p, %x)\n", iface, pstatstg, grfStatFlag); /* @@ -639,6 +752,8 @@ HRESULT WINAPI StorageBaseImpl_Stat( &curProperty, grfStatFlag); + pstatstg->grfMode = This->openFlags; + res = S_OK; goto end; } @@ -648,9 +763,9 @@ HRESULT WINAPI StorageBaseImpl_Stat( end: if (res == S_OK) { - TRACE("<-- STATSTG: pwcsName: %s, type: %ld, cbSize.Low/High: %ld/%ld, grfMode: %08lx, grfLocksSupported: %ld, grfStateBits: %08lx\n", debugstr_w(pstatstg->pwcsName), pstatstg->type, pstatstg->cbSize.u.LowPart, pstatstg->cbSize.u.HighPart, pstatstg->grfMode, pstatstg->grfLocksSupported, pstatstg->grfStateBits); + TRACE("<-- STATSTG: pwcsName: %s, type: %d, cbSize.Low/High: %d/%d, grfMode: %08x, grfLocksSupported: %d, grfStateBits: %08x\n", debugstr_w(pstatstg->pwcsName), pstatstg->type, pstatstg->cbSize.u.LowPart, pstatstg->cbSize.u.HighPart, pstatstg->grfMode, pstatstg->grfLocksSupported, pstatstg->grfStateBits); } - TRACE("<-- %08lx\n", res); + TRACE("<-- %08x\n", res); return res; } @@ -665,7 +780,7 @@ end: * of the deleted StgProperty object setting it with the new name and to * perform a DestroyElement of the old StgProperty. */ -HRESULT WINAPI StorageBaseImpl_RenameElement( +static HRESULT WINAPI StorageBaseImpl_RenameElement( IStorage* iface, const OLECHAR* pwcsOldName, /* [in] */ const OLECHAR* pwcsNewName) /* [in] */ @@ -775,13 +890,13 @@ HRESULT WINAPI StorageBaseImpl_RenameElement( /* * At this point the renamed property has been inserted in the tree, - * now, before to Destroy the old property we must zeroed it's dirProperty + * now, before Destroying the old property we must zero its dirProperty * otherwise the DestroyProperty below will zap it all and we do not want * this to happen. * Also, we fake that the old property is a storage so the DestroyProperty * will not do a SetSize(0) on the stream data. * - * This means that we need to tweek the StgProperty if it is a stream or a + * This means that we need to tweak the StgProperty if it is a stream or a * non empty storage. */ StorageImpl_ReadProperty(This->ancestorStorage, @@ -797,7 +912,7 @@ HRESULT WINAPI StorageBaseImpl_RenameElement( /* * Invoke Destroy to get rid of the ole property and automatically redo - * the linking of it's previous and next members... + * the linking of its previous and next members... */ IStorage_DestroyElement((IStorage*)This->ancestorStorage, pwcsOldName); @@ -820,7 +935,7 @@ HRESULT WINAPI StorageBaseImpl_RenameElement( * * See Windows documentation for more details on IStorage methods. */ -HRESULT WINAPI StorageBaseImpl_CreateStream( +static HRESULT WINAPI StorageBaseImpl_CreateStream( IStorage* iface, const OLECHAR* pwcsName, /* [string][in] */ DWORD grfMode, /* [in] */ @@ -833,9 +948,8 @@ HRESULT WINAPI StorageBaseImpl_CreateStream( StgStreamImpl* newStream; StgProperty currentProperty, newStreamProperty; ULONG foundPropertyIndex, newPropertyIndex; - DWORD parent_grfMode; - TRACE("(%p, %s, %lx, %ld, %ld, %p)\n", + TRACE("(%p, %s, %x, %d, %d, %p)\n", iface, debugstr_w(pwcsName), grfMode, reserved1, reserved2, ppstm); @@ -869,10 +983,12 @@ HRESULT WINAPI StorageBaseImpl_CreateStream( /* * Check that we're compatible with the parent's storage mode + * if not in transacted mode */ - parent_grfMode = STGM_ACCESS_MODE( This->ancestorStorage->base.openFlags ); - if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( parent_grfMode ) ) - return STG_E_ACCESSDENIED; + if(!(This->ancestorStorage->base.openFlags & STGM_TRANSACTED)) { + if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->openFlags ) ) + return STG_E_ACCESSDENIED; + } /* * Initialize the out parameter @@ -903,6 +1019,11 @@ HRESULT WINAPI StorageBaseImpl_CreateStream( else return STG_E_FILEALREADYEXISTS; } + else if (STGM_ACCESS_MODE(This->openFlags) == STGM_READ) + { + WARN("read-only storage\n"); + return STG_E_ACCESSDENIED; + } /* * memset the empty property @@ -987,7 +1108,7 @@ HRESULT WINAPI StorageBaseImpl_CreateStream( * * See Windows documentation for more details on IStorage methods. */ -HRESULT WINAPI StorageBaseImpl_SetClass( +static HRESULT WINAPI StorageBaseImpl_SetClass( IStorage* iface, REFCLSID clsid) /* [in] */ { @@ -1026,7 +1147,7 @@ HRESULT WINAPI StorageBaseImpl_SetClass( * * See Windows documentation for more details on IStorage methods. */ -HRESULT WINAPI StorageImpl_CreateStorage( +static HRESULT WINAPI StorageImpl_CreateStorage( IStorage* iface, const OLECHAR *pwcsName, /* [string][in] */ DWORD grfMode, /* [in] */ @@ -1042,9 +1163,8 @@ HRESULT WINAPI StorageImpl_CreateStorage( ULONG foundPropertyIndex; ULONG newPropertyIndex; HRESULT hr; - DWORD parent_grfMode; - TRACE("(%p, %s, %lx, %ld, %ld, %p)\n", + TRACE("(%p, %s, %x, %d, %d, %p)\n", iface, debugstr_w(pwcsName), grfMode, reserved1, reserved2, ppstg); @@ -1068,15 +1188,14 @@ HRESULT WINAPI StorageImpl_CreateStorage( if ( FAILED( validateSTGM(grfMode) ) || (grfMode & STGM_DELETEONRELEASE) ) { - WARN("bad grfMode: 0x%lx\n", grfMode); + WARN("bad grfMode: 0x%x\n", grfMode); return STG_E_INVALIDFLAG; } /* * Check that we're compatible with the parent's storage mode */ - parent_grfMode = STGM_ACCESS_MODE( This->base.ancestorStorage->base.openFlags ); - if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( parent_grfMode ) ) + if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->base.openFlags ) ) { WARN("access denied\n"); return STG_E_ACCESSDENIED; @@ -1106,6 +1225,11 @@ HRESULT WINAPI StorageImpl_CreateStorage( return STG_E_FILEALREADYEXISTS; } } + else if (STGM_ACCESS_MODE(This->base.openFlags) == STGM_READ) + { + WARN("read-only storage\n"); + return STG_E_ACCESSDENIED; + } /* * memset the empty property @@ -1409,7 +1533,7 @@ static void updatePropertyChain( else { /* - * The root storage is empty, link the new property to it's dir property + * The root storage is empty, link the new property to its dir property */ currentProperty.dirProperty = newPropertyIndex; StorageImpl_WriteProperty(storage->base.ancestorStorage, @@ -1422,7 +1546,7 @@ static void updatePropertyChain( /************************************************************************* * CopyTo (IStorage) */ -HRESULT WINAPI StorageImpl_CopyTo( +static HRESULT WINAPI StorageImpl_CopyTo( IStorage* iface, DWORD ciidExclude, /* [in] */ const IID* rgiidExclude, /* [size_is][unique][in] */ @@ -1438,7 +1562,7 @@ HRESULT WINAPI StorageImpl_CopyTo( if ((ciidExclude != 0) || (rgiidExclude != NULL) || (snbExclude != NULL)) FIXME("Exclude option not implemented\n"); - TRACE("(%p, %ld, %p, %p, %p)\n", + TRACE("(%p, %d, %p, %p, %p)\n", iface, ciidExclude, rgiidExclude, snbExclude, pstgDest); @@ -1572,7 +1696,7 @@ HRESULT WINAPI StorageImpl_CopyTo( } else { - WARN("unknown element type: %ld\n", curElement.type); + WARN("unknown element type: %d\n", curElement.type); } } while (hr == S_OK); @@ -1588,14 +1712,16 @@ HRESULT WINAPI StorageImpl_CopyTo( /************************************************************************* * MoveElementTo (IStorage) */ -HRESULT WINAPI StorageImpl_MoveElementTo( +static HRESULT WINAPI StorageImpl_MoveElementTo( IStorage* iface, const OLECHAR *pwcsName, /* [string][in] */ IStorage *pstgDest, /* [unique][in] */ const OLECHAR *pwcsNewName,/* [string][in] */ DWORD grfFlags) /* [in] */ { - FIXME("not implemented!\n"); + FIXME("(%p %s %p %s %u): stub\n", iface, + debugstr_w(pwcsName), pstgDest, + debugstr_w(pwcsNewName), grfFlags); return E_NOTIMPL; } @@ -1609,11 +1735,11 @@ HRESULT WINAPI StorageImpl_MoveElementTo( * Wine doesn't implement transacted mode, which seems to be a basic * optimization, so we can ignore this stub for now. */ -HRESULT WINAPI StorageImpl_Commit( +static HRESULT WINAPI StorageImpl_Commit( IStorage* iface, DWORD grfCommitFlags)/* [in] */ { - FIXME("(%ld): stub!\n", grfCommitFlags); + FIXME("(%p %d): stub\n", iface, grfCommitFlags); return S_OK; } @@ -1622,25 +1748,25 @@ HRESULT WINAPI StorageImpl_Commit( * * Discard all changes that have been made since the last commit operation */ -HRESULT WINAPI StorageImpl_Revert( +static HRESULT WINAPI StorageImpl_Revert( IStorage* iface) { - FIXME("not implemented!\n"); + FIXME("(%p): stub\n", iface); return E_NOTIMPL; } /************************************************************************* * DestroyElement (IStorage) * - * Stategy: This implementation is build this way for simplicity not for speed. - * I always delete the top most element of the enumeration and adjust + * Strategy: This implementation is built this way for simplicity not for speed. + * I always delete the topmost element of the enumeration and adjust * the deleted element pointer all the time. This takes longer to * do but allow to reinvoke DestroyElement whenever we encounter a - * storage object. The optimisation reside in the usage of another - * enumeration stategy that would give all the leaves of a storage + * storage object. The optimisation resides in the usage of another + * enumeration strategy that would give all the leaves of a storage * first. (postfix order) */ -HRESULT WINAPI StorageImpl_DestroyElement( +static HRESULT WINAPI StorageImpl_DestroyElement( IStorage* iface, const OLECHAR *pwcsName)/* [string][in] */ { @@ -1653,7 +1779,7 @@ HRESULT WINAPI StorageImpl_DestroyElement( StgProperty parentProperty; ULONG foundPropertyIndexToDelete; ULONG typeOfRelation; - ULONG parentPropertyId; + ULONG parentPropertyId = 0; TRACE("(%p, %s)\n", iface, debugstr_w(pwcsName)); @@ -1686,7 +1812,7 @@ HRESULT WINAPI StorageImpl_DestroyElement( /* * Find the parent property of the property to delete (the one that * link to it). If This->dirProperty == foundPropertyIndexToDelete, - * the parent is This. Otherwise, the parent is one of it's sibling... + * the parent is This. Otherwise, the parent is one of its sibling... */ /* @@ -1771,7 +1897,7 @@ HRESULT WINAPI StorageImpl_DestroyElement( * * See Windows documentation for more details on IStorage methods. */ -HRESULT WINAPI StorageImpl_Stat( IStorage* iface, +static HRESULT WINAPI StorageImpl_Stat( IStorage* iface, STATSTG* pstatstg, /* [out] */ DWORD grfStatFlag) /* [in] */ { @@ -1788,6 +1914,34 @@ HRESULT WINAPI StorageImpl_Stat( IStorage* iface, return result; } +/****************************************************************************** + * Internal stream list handlers + */ + +void StorageBaseImpl_AddStream(StorageBaseImpl * stg, StgStreamImpl * strm) +{ + TRACE("Stream added (stg=%p strm=%p)\n", stg, strm); + list_add_tail(&stg->strmHead,&strm->StrmListEntry); +} + +void StorageBaseImpl_RemoveStream(StorageBaseImpl * stg, StgStreamImpl * strm) +{ + TRACE("Stream removed (stg=%p strm=%p)\n", stg,strm); + list_remove(&(strm->StrmListEntry)); +} + +static void StorageBaseImpl_DeleteAll(StorageBaseImpl * stg) +{ + struct list *cur, *cur2; + StgStreamImpl *strm=NULL; + + LIST_FOR_EACH_SAFE(cur, cur2, &stg->strmHead) { + strm = LIST_ENTRY(cur,StgStreamImpl,StrmListEntry); + TRACE("Streams deleted (stg=%p strm=%p next=%p prev=%p)\n", stg,strm,cur->next,cur->prev); + strm->parentStorage = NULL; + list_remove(cur); + } +} /********************************************************************* @@ -1815,7 +1969,7 @@ static HRESULT deleteStorageProperty( (IStorage*)parentStorage, propertyToDelete.name, 0, - STGM_SHARE_EXCLUSIVE, + STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &childStorage); @@ -1854,7 +2008,7 @@ static HRESULT deleteStorageProperty( } while ((hr == S_OK) && (destroyHr == S_OK)); /* - * Invalidate the property by zeroing it's name member. + * Invalidate the property by zeroing its name member. */ propertyToDelete.sizeOfNameString = 0; @@ -1916,7 +2070,7 @@ static HRESULT deleteStreamProperty( IStream_Release(pis); /* - * Invalidate the property by zeroing it's name member. + * Invalidate the property by zeroing its name member. */ propertyToDelete.sizeOfNameString = 0; @@ -2179,7 +2333,7 @@ static HRESULT adjustPropertyChain( /****************************************************************************** * SetElementTimes (IStorage) */ -HRESULT WINAPI StorageImpl_SetElementTimes( +static HRESULT WINAPI StorageImpl_SetElementTimes( IStorage* iface, const OLECHAR *pwcsName,/* [string][in] */ const FILETIME *pctime, /* [in] */ @@ -2193,7 +2347,7 @@ HRESULT WINAPI StorageImpl_SetElementTimes( /****************************************************************************** * SetStateBits (IStorage) */ -HRESULT WINAPI StorageImpl_SetStateBits( +static HRESULT WINAPI StorageImpl_SetStateBits( IStorage* iface, DWORD grfStateBits,/* [in] */ DWORD grfMask) /* [in] */ @@ -2227,7 +2381,7 @@ static const IStorageVtbl Storage32Impl_Vtbl = StorageImpl_Stat }; -HRESULT StorageImpl_Construct( +static HRESULT StorageImpl_Construct( StorageImpl* This, HANDLE hFile, LPCOLESTR pwcsName, @@ -2246,13 +2400,19 @@ HRESULT StorageImpl_Construct( memset(This, 0, sizeof(StorageImpl)); + /* + * Initialize stream list + */ + + list_init(&This->base.strmHead); + /* * Initialize the virtual function table. */ This->base.lpVtbl = &Storage32Impl_Vtbl; This->base.pssVtbl = &IPropertySetStorage_Vtbl; This->base.v_destructor = &StorageImpl_Destroy; - This->base.openFlags = openFlags; + This->base.openFlags = (openFlags & ~STGM_CREATE); /* * This is the top-level storage so initialize the ancestor pointer @@ -2293,7 +2453,7 @@ HRESULT StorageImpl_Construct( if (fileCreate) { ULARGE_INTEGER size; - BYTE* bigBlockBuffer; + BYTE bigBlockBuffer[BIG_BLOCK_SIZE]; /* * Initialize all header variables: @@ -2326,11 +2486,10 @@ HRESULT StorageImpl_Construct( /* * Initialize the big block depot */ - bigBlockBuffer = StorageImpl_GetBigBlock(This, 0); memset(bigBlockBuffer, BLOCK_UNUSED, This->bigBlockSize); StorageUtl_WriteDWord(bigBlockBuffer, 0, BLOCK_SPECIAL); StorageUtl_WriteDWord(bigBlockBuffer, sizeof(ULONG), BLOCK_END_OF_CHAIN); - StorageImpl_ReleaseBigBlock(This, bigBlockBuffer); + StorageImpl_WriteBigBlock(This, 0, bigBlockBuffer); } else { @@ -2370,7 +2529,7 @@ HRESULT StorageImpl_Construct( return STG_E_READFAULT; /* - * Write the root property + * Write the root property (memory only) */ if (fileCreate) { @@ -2434,11 +2593,13 @@ HRESULT StorageImpl_Construct( return hr; } -void StorageImpl_Destroy(StorageBaseImpl* iface) +static void StorageImpl_Destroy(StorageBaseImpl* iface) { StorageImpl *This = (StorageImpl*) iface; TRACE("(%p)\n", This); + StorageBaseImpl_DeleteAll(&This->base); + HeapFree(GetProcessHeap(), 0, This->pwcsName); BlockChainStream_Destroy(This->smallBlockRootChain); @@ -2456,11 +2617,12 @@ void StorageImpl_Destroy(StorageBaseImpl* iface) * If the big block depot is filled, this method will enlarge it. * */ -ULONG StorageImpl_GetNextFreeBigBlock( +static ULONG StorageImpl_GetNextFreeBigBlock( StorageImpl* This) { ULONG depotBlockIndexPos; - void *depotBuffer; + BYTE depotBuffer[BIG_BLOCK_SIZE]; + BOOL success; ULONG depotBlockOffset; ULONG blocksPerDepot = This->bigBlockSize / sizeof(ULONG); ULONG nextBlockIndex = BLOCK_SPECIAL; @@ -2553,9 +2715,9 @@ ULONG StorageImpl_GetNextFreeBigBlock( } } - depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos); + success = StorageImpl_ReadBigBlock(This, depotBlockIndexPos, depotBuffer); - if (depotBuffer != 0) + if (success) { while ( ( (depotBlockOffset/sizeof(ULONG) ) < blocksPerDepot) && ( nextBlockIndex != BLOCK_UNUSED)) @@ -2570,14 +2732,17 @@ ULONG StorageImpl_GetNextFreeBigBlock( depotBlockOffset += sizeof(ULONG); } - - StorageImpl_ReleaseBigBlock(This, depotBuffer); } depotIndex++; depotBlockOffset = 0; } + /* + * make sure that the block physically exists before using it + */ + BIGBLOCKFILE_EnsureExists(This->bigBlockFile, freeBlock); + This->prevFreeBlock = freeBlock; return freeBlock; @@ -2589,18 +2754,15 @@ ULONG StorageImpl_GetNextFreeBigBlock( * This will create a depot block, essentially it is a block initialized * to BLOCK_UNUSEDs. */ -void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex) +static void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex) { - BYTE* blockBuffer; - - blockBuffer = StorageImpl_GetBigBlock(This, blockIndex); + BYTE blockBuffer[BIG_BLOCK_SIZE]; /* * Initialize blocks as free */ memset(blockBuffer, BLOCK_UNUSED, This->bigBlockSize); - - StorageImpl_ReleaseBigBlock(This, blockBuffer); + StorageImpl_WriteBigBlock(This, blockIndex, blockBuffer); } /****************************************************************************** @@ -2610,7 +2772,7 @@ void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex) * index. This method is only for depot indexes equal or greater than * COUNT_BBDEPOTINHEADER. */ -ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex) +static ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex) { ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1; ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER; @@ -2631,20 +2793,8 @@ ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex) } if (extBlockIndex != BLOCK_UNUSED) - { - BYTE* depotBuffer; - - depotBuffer = StorageImpl_GetROBigBlock(This, extBlockIndex); - - if (depotBuffer != 0) - { - StorageUtl_ReadDWord(depotBuffer, - extBlockOffset * sizeof(ULONG), - &blockIndex); - - StorageImpl_ReleaseBigBlock(This, depotBuffer); - } - } + StorageImpl_ReadDWordFromBigBlock(This, extBlockIndex, + extBlockOffset * sizeof(ULONG), &blockIndex); return blockIndex; } @@ -2656,9 +2806,7 @@ ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex) * This method is only for depot indexes equal or greater than * COUNT_BBDEPOTINHEADER. */ -void Storage32Impl_SetExtDepotBlock(StorageImpl* This, - ULONG depotIndex, - ULONG blockIndex) +static void Storage32Impl_SetExtDepotBlock(StorageImpl* This, ULONG depotIndex, ULONG blockIndex) { ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1; ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER; @@ -2676,18 +2824,9 @@ void Storage32Impl_SetExtDepotBlock(StorageImpl* This, if (extBlockIndex != BLOCK_UNUSED) { - BYTE* depotBuffer; - - depotBuffer = StorageImpl_GetBigBlock(This, extBlockIndex); - - if (depotBuffer != 0) - { - StorageUtl_WriteDWord(depotBuffer, - extBlockOffset * sizeof(ULONG), - blockIndex); - - StorageImpl_ReleaseBigBlock(This, depotBuffer); - } + StorageImpl_WriteDWordToBigBlock(This, extBlockIndex, + extBlockOffset * sizeof(ULONG), + blockIndex); } } @@ -2696,11 +2835,11 @@ void Storage32Impl_SetExtDepotBlock(StorageImpl* This, * * Creates an extended depot block. */ -ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This) +static ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This) { ULONG numExtBlocks = This->extBigBlockDepotCount; ULONG nextExtBlock = This->extBigBlockDepotStart; - BYTE* depotBuffer = NULL; + BYTE depotBuffer[BIG_BLOCK_SIZE]; ULONG index = BLOCK_UNUSED; ULONG nextBlockOffset = This->bigBlockSize - sizeof(ULONG); ULONG blocksPerDepotBlock = This->bigBlockSize / sizeof(ULONG); @@ -2730,17 +2869,15 @@ ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This) /* * Add the new extended block to the chain. */ - depotBuffer = StorageImpl_GetBigBlock(This, nextExtBlock); - StorageUtl_WriteDWord(depotBuffer, nextBlockOffset, index); - StorageImpl_ReleaseBigBlock(This, depotBuffer); + StorageImpl_WriteDWordToBigBlock(This, nextExtBlock, nextBlockOffset, + index); } /* * Initialize this block. */ - depotBuffer = StorageImpl_GetBigBlock(This, index); memset(depotBuffer, BLOCK_UNUSED, This->bigBlockSize); - StorageImpl_ReleaseBigBlock(This, depotBuffer); + StorageImpl_WriteBigBlock(This, index, depotBuffer); return index; } @@ -2750,7 +2887,7 @@ ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This) * * This method will flag the specified block as free in the big block depot. */ -void StorageImpl_FreeBigBlock( +static void StorageImpl_FreeBigBlock( StorageImpl* This, ULONG blockIndex) { @@ -2784,7 +2921,7 @@ void StorageImpl_FreeBigBlock( * * See Windows documentation for more details on IStorage methods. */ -HRESULT StorageImpl_GetNextBlockInChain( +static HRESULT StorageImpl_GetNextBlockInChain( StorageImpl* This, ULONG blockIndex, ULONG* nextBlockIndex) @@ -2792,7 +2929,8 @@ HRESULT StorageImpl_GetNextBlockInChain( ULONG offsetInDepot = blockIndex * sizeof (ULONG); ULONG depotBlockCount = offsetInDepot / This->bigBlockSize; ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize; - void* depotBuffer; + BYTE depotBuffer[BIG_BLOCK_SIZE]; + BOOL success; ULONG depotBlockIndexPos; int index; @@ -2800,7 +2938,7 @@ HRESULT StorageImpl_GetNextBlockInChain( if(depotBlockCount >= This->bigBlockDepotCount) { - WARN("depotBlockCount %ld, bigBlockDepotCount %ld\n", depotBlockCount, + WARN("depotBlockCount %d, bigBlockDepotCount %d\n", depotBlockCount, This->bigBlockDepotCount); return STG_E_READFAULT; } @@ -2824,9 +2962,9 @@ HRESULT StorageImpl_GetNextBlockInChain( depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount); } - depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos); + success = StorageImpl_ReadBigBlock(This, depotBlockIndexPos, depotBuffer); - if (!depotBuffer) + if (!success) return STG_E_READFAULT; for (index = 0; index < NUM_BLOCKS_PER_DEPOT_BLOCK; index++) @@ -2834,7 +2972,6 @@ HRESULT StorageImpl_GetNextBlockInChain( StorageUtl_ReadDWord(depotBuffer, index*sizeof(ULONG), nextBlockIndex); This->blockDepotCached[index] = *nextBlockIndex; } - StorageImpl_ReleaseBigBlock(This, depotBuffer); } *nextBlockIndex = This->blockDepotCached[depotBlockOffset/sizeof(ULONG)]; @@ -2857,20 +2994,13 @@ HRESULT StorageImpl_GetNextBlockInChain( * - BLOCK_UNUSED: there is no next extended block. * - Any other return values denotes failure. */ -ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex) +static ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex) { ULONG nextBlockIndex = BLOCK_SPECIAL; ULONG depotBlockOffset = This->bigBlockSize - sizeof(ULONG); - void* depotBuffer; - depotBuffer = StorageImpl_GetROBigBlock(This, blockIndex); - - if (depotBuffer!=0) - { - StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex); - - StorageImpl_ReleaseBigBlock(This, depotBuffer); - } + StorageImpl_ReadDWordFromBigBlock(This, blockIndex, depotBlockOffset, + &nextBlockIndex); return nextBlockIndex; } @@ -2889,7 +3019,7 @@ ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex) * Storage32Impl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN); * */ -void StorageImpl_SetNextBlockInChain( +static void StorageImpl_SetNextBlockInChain( StorageImpl* This, ULONG blockIndex, ULONG nextBlock) @@ -2898,7 +3028,6 @@ void StorageImpl_SetNextBlockInChain( ULONG depotBlockCount = offsetInDepot / This->bigBlockSize; ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize; ULONG depotBlockIndexPos; - void* depotBuffer; assert(depotBlockCount < This->bigBlockDepotCount); assert(blockIndex != nextBlock); @@ -2915,14 +3044,8 @@ void StorageImpl_SetNextBlockInChain( depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount); } - depotBuffer = StorageImpl_GetBigBlock(This, depotBlockIndexPos); - - if (depotBuffer!=0) - { - StorageUtl_WriteDWord(depotBuffer, depotBlockOffset, nextBlock); - StorageImpl_ReleaseBigBlock(This, depotBuffer); - } - + StorageImpl_WriteDWordToBigBlock(This, depotBlockIndexPos, depotBlockOffset, + nextBlock); /* * Update the cached block depot, if necessary. */ @@ -2937,22 +3060,24 @@ void StorageImpl_SetNextBlockInChain( * * This method will read in the file header, i.e. big block index -1. */ -HRESULT StorageImpl_LoadFileHeader( +static HRESULT StorageImpl_LoadFileHeader( StorageImpl* This) { HRESULT hr = STG_E_FILENOTFOUND; - void* headerBigBlock = NULL; + BYTE headerBigBlock[BIG_BLOCK_SIZE]; + BOOL success; int index; + TRACE("\n"); /* * Get a pointer to the big block of data containing the header. */ - headerBigBlock = StorageImpl_GetROBigBlock(This, -1); + success = StorageImpl_ReadBigBlock(This, -1, headerBigBlock); /* * Extract the information from the header. */ - if (headerBigBlock!=0) + if (success) { /* * Check for the "magic number" signature and return an error if it is not @@ -2960,13 +3085,11 @@ HRESULT StorageImpl_LoadFileHeader( */ if (memcmp(headerBigBlock, STORAGE_oldmagic, sizeof(STORAGE_oldmagic))==0) { - StorageImpl_ReleaseBigBlock(This, headerBigBlock); return STG_E_OLDFORMAT; } if (memcmp(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic))!=0) { - StorageImpl_ReleaseBigBlock(This, headerBigBlock); return STG_E_INVALIDHEADER; } @@ -3039,11 +3162,6 @@ HRESULT StorageImpl_LoadFileHeader( } else hr = S_OK; - - /* - * Release the block. - */ - StorageImpl_ReleaseBigBlock(This, headerBigBlock); } return hr; @@ -3054,7 +3172,7 @@ HRESULT StorageImpl_LoadFileHeader( * * This method will save to the file the header, i.e. big block -1. */ -void StorageImpl_SaveFileHeader( +static void StorageImpl_SaveFileHeader( StorageImpl* This) { BYTE headerBigBlock[BIG_BLOCK_SIZE]; @@ -3160,20 +3278,20 @@ BOOL StorageImpl_ReadProperty( { BYTE currentProperty[PROPSET_BLOCK_SIZE]; ULARGE_INTEGER offsetInPropSet; - BOOL readSuccessful; + HRESULT readRes; ULONG bytesRead; offsetInPropSet.u.HighPart = 0; offsetInPropSet.u.LowPart = index * PROPSET_BLOCK_SIZE; - readSuccessful = BlockChainStream_ReadAt( + readRes = BlockChainStream_ReadAt( This->rootBlockChain, offsetInPropSet, PROPSET_BLOCK_SIZE, currentProperty, &bytesRead); - if (readSuccessful) + if (SUCCEEDED(readRes)) { /* replace the name of root entry (often "Root Entry") by the file name */ WCHAR *propName = (index == This->base.rootPropertySetIndex) ? @@ -3246,7 +3364,7 @@ BOOL StorageImpl_ReadProperty( buffer->size.u.HighPart = 0; } - return readSuccessful; + return SUCCEEDED(readRes) ? TRUE : FALSE; } /********************************************************************* @@ -3259,7 +3377,7 @@ BOOL StorageImpl_WriteProperty( { BYTE currentProperty[PROPSET_BLOCK_SIZE]; ULARGE_INTEGER offsetInPropSet; - BOOL writeSuccessful; + HRESULT writeRes; ULONG bytesWritten; offsetInPropSet.u.HighPart = 0; @@ -3329,75 +3447,79 @@ BOOL StorageImpl_WriteProperty( OFFSET_PS_SIZE, buffer->size.u.LowPart); - writeSuccessful = BlockChainStream_WriteAt(This->rootBlockChain, - offsetInPropSet, - PROPSET_BLOCK_SIZE, - currentProperty, - &bytesWritten); - return writeSuccessful; + writeRes = BlockChainStream_WriteAt(This->rootBlockChain, + offsetInPropSet, + PROPSET_BLOCK_SIZE, + currentProperty, + &bytesWritten); + return SUCCEEDED(writeRes) ? TRUE : FALSE; } -BOOL StorageImpl_ReadBigBlock( +static BOOL StorageImpl_ReadBigBlock( StorageImpl* This, ULONG blockIndex, void* buffer) { - void* bigBlockBuffer; + ULARGE_INTEGER ulOffset; + DWORD read; - bigBlockBuffer = StorageImpl_GetROBigBlock(This, blockIndex); + ulOffset.u.HighPart = 0; + ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex); - if (bigBlockBuffer!=0) - { - memcpy(buffer, bigBlockBuffer, This->bigBlockSize); - - StorageImpl_ReleaseBigBlock(This, bigBlockBuffer); - - return TRUE; - } - - return FALSE; + StorageImpl_ReadAt(This, ulOffset, buffer, This->bigBlockSize, &read); + return (read == This->bigBlockSize); } -BOOL StorageImpl_WriteBigBlock( +static BOOL StorageImpl_ReadDWordFromBigBlock( + StorageImpl* This, + ULONG blockIndex, + ULONG offset, + DWORD* value) +{ + ULARGE_INTEGER ulOffset; + DWORD read; + DWORD tmp; + + ulOffset.u.HighPart = 0; + ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex); + ulOffset.u.LowPart += offset; + + StorageImpl_ReadAt(This, ulOffset, &tmp, sizeof(DWORD), &read); + *value = le32toh(tmp); + return (read == sizeof(DWORD)); +} + +static BOOL StorageImpl_WriteBigBlock( StorageImpl* This, ULONG blockIndex, void* buffer) { - void* bigBlockBuffer; + ULARGE_INTEGER ulOffset; + DWORD wrote; - bigBlockBuffer = StorageImpl_GetBigBlock(This, blockIndex); + ulOffset.u.HighPart = 0; + ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex); - if (bigBlockBuffer!=0) - { - memcpy(bigBlockBuffer, buffer, This->bigBlockSize); - - StorageImpl_ReleaseBigBlock(This, bigBlockBuffer); - - return TRUE; - } - - return FALSE; + StorageImpl_WriteAt(This, ulOffset, buffer, This->bigBlockSize, &wrote); + return (wrote == This->bigBlockSize); } -void* StorageImpl_GetROBigBlock( +static BOOL StorageImpl_WriteDWordToBigBlock( StorageImpl* This, - ULONG blockIndex) + ULONG blockIndex, + ULONG offset, + DWORD value) { - return BIGBLOCKFILE_GetROBigBlock(This->bigBlockFile, blockIndex); -} + ULARGE_INTEGER ulOffset; + DWORD wrote; -void* StorageImpl_GetBigBlock( - StorageImpl* This, - ULONG blockIndex) -{ - return BIGBLOCKFILE_GetBigBlock(This->bigBlockFile, blockIndex); -} + ulOffset.u.HighPart = 0; + ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex); + ulOffset.u.LowPart += offset; -void StorageImpl_ReleaseBigBlock( - StorageImpl* This, - void* pBigBlock) -{ - BIGBLOCKFILE_ReleaseBigBlock(This->bigBlockFile, pBigBlock); + value = htole32(value); + StorageImpl_WriteAt(This, ulOffset, &value, sizeof(DWORD), &wrote); + return (wrote == sizeof(DWORD)); } /****************************************************************************** @@ -3412,10 +3534,11 @@ BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks( { ULONG bbHeadOfChain = BLOCK_END_OF_CHAIN; ULARGE_INTEGER size, offset; - ULONG cbRead, cbWritten, cbTotalRead, cbTotalWritten; + ULONG cbRead, cbWritten; + ULARGE_INTEGER cbTotalRead; ULONG propertyIndex; - BOOL successWrite; - HRESULT successRead; + HRESULT resWrite = S_OK; + HRESULT resRead; StgProperty chainProperty; BYTE *buffer; BlockChainStream *bbTempChain = NULL; @@ -3442,32 +3565,43 @@ BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks( */ offset.u.LowPart = 0; offset.u.HighPart = 0; - cbTotalRead = 0; - cbTotalWritten = 0; + cbTotalRead.QuadPart = 0; buffer = HeapAlloc(GetProcessHeap(),0,DEF_SMALL_BLOCK_SIZE); do { - successRead = SmallBlockChainStream_ReadAt(*ppsbChain, - offset, - DEF_SMALL_BLOCK_SIZE, - buffer, - &cbRead); - cbTotalRead += cbRead; + resRead = SmallBlockChainStream_ReadAt(*ppsbChain, + offset, + This->smallBlockSize, + buffer, + &cbRead); + if (FAILED(resRead)) + break; - successWrite = BlockChainStream_WriteAt(bbTempChain, + if (cbRead > 0) + { + cbTotalRead.QuadPart += cbRead; + + resWrite = BlockChainStream_WriteAt(bbTempChain, offset, cbRead, buffer, &cbWritten); - cbTotalWritten += cbWritten; - offset.u.LowPart += This->smallBlockSize; + if (FAILED(resWrite)) + break; - } while (SUCCEEDED(successRead) && successWrite); + offset.u.LowPart += This->smallBlockSize; + } + } while (cbTotalRead.QuadPart < size.QuadPart); HeapFree(GetProcessHeap(),0,buffer); - assert(cbTotalRead == cbTotalWritten); + if (FAILED(resRead) || FAILED(resWrite)) + { + ERR("conversion failed: resRead = 0x%08x, resWrite = 0x%08x\n", resRead, resWrite); + BlockChainStream_Destroy(bbTempChain); + return NULL; + } /* * Destroy the small block chain. @@ -3501,7 +3635,7 @@ BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks( return bigBlockChain; } -void StorageInternalImpl_Destroy( StorageBaseImpl *iface) +static void StorageInternalImpl_Destroy( StorageBaseImpl *iface) { StorageInternalImpl* This = (StorageInternalImpl*) iface; @@ -3516,7 +3650,7 @@ void StorageInternalImpl_Destroy( StorageBaseImpl *iface) ** The non-root storages cannot be opened in transacted mode thus this function ** does nothing. */ -HRESULT WINAPI StorageInternalImpl_Commit( +static HRESULT WINAPI StorageInternalImpl_Commit( IStorage* iface, DWORD grfCommitFlags) /* [in] */ { @@ -3530,20 +3664,20 @@ HRESULT WINAPI StorageInternalImpl_Commit( ** The non-root storages cannot be opened in transacted mode thus this function ** does nothing. */ -HRESULT WINAPI StorageInternalImpl_Revert( +static HRESULT WINAPI StorageInternalImpl_Revert( IStorage* iface) { return S_OK; } -void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This) +static void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This) { IStorage_Release((IStorage*)This->parentStorage); HeapFree(GetProcessHeap(), 0, This->stackToVisit); HeapFree(GetProcessHeap(), 0, This); } -HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface( +static HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface( IEnumSTATSTG* iface, REFIID riid, void** ppvObject) @@ -3565,7 +3699,7 @@ HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface( * Compare the riid with the interface IDs implemented by this object. */ if (IsEqualGUID(&IID_IUnknown, riid) || - IsEqualGUID(&IID_IStorage, riid)) + IsEqualGUID(&IID_IEnumSTATSTG, riid)) { *ppvObject = (IEnumSTATSTG*)This; IEnumSTATSTG_AddRef((IEnumSTATSTG*)This); @@ -3575,14 +3709,14 @@ HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface( return E_NOINTERFACE; } -ULONG WINAPI IEnumSTATSTGImpl_AddRef( +static ULONG WINAPI IEnumSTATSTGImpl_AddRef( IEnumSTATSTG* iface) { IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface; return InterlockedIncrement(&This->ref); } -ULONG WINAPI IEnumSTATSTGImpl_Release( +static ULONG WINAPI IEnumSTATSTGImpl_Release( IEnumSTATSTG* iface) { IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface; @@ -3602,7 +3736,7 @@ ULONG WINAPI IEnumSTATSTGImpl_Release( return newRef; } -HRESULT WINAPI IEnumSTATSTGImpl_Next( +static HRESULT WINAPI IEnumSTATSTGImpl_Next( IEnumSTATSTG* iface, ULONG celt, STATSTG* rgelt, @@ -3685,7 +3819,7 @@ HRESULT WINAPI IEnumSTATSTGImpl_Next( } -HRESULT WINAPI IEnumSTATSTGImpl_Skip( +static HRESULT WINAPI IEnumSTATSTGImpl_Skip( IEnumSTATSTG* iface, ULONG celt) { @@ -3737,7 +3871,7 @@ HRESULT WINAPI IEnumSTATSTGImpl_Skip( return S_FALSE; } -HRESULT WINAPI IEnumSTATSTGImpl_Reset( +static HRESULT WINAPI IEnumSTATSTGImpl_Reset( IEnumSTATSTG* iface) { IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface; @@ -3771,7 +3905,7 @@ HRESULT WINAPI IEnumSTATSTGImpl_Reset( return S_OK; } -HRESULT WINAPI IEnumSTATSTGImpl_Clone( +static HRESULT WINAPI IEnumSTATSTGImpl_Clone( IEnumSTATSTG* iface, IEnumSTATSTG** ppenum) { @@ -3814,7 +3948,7 @@ HRESULT WINAPI IEnumSTATSTGImpl_Clone( return S_OK; } -INT IEnumSTATSTGImpl_FindParentProperty( +static INT IEnumSTATSTGImpl_FindParentProperty( IEnumSTATSTGImpl *This, ULONG childProperty, StgProperty *currentProperty, @@ -3879,7 +4013,7 @@ INT IEnumSTATSTGImpl_FindParentProperty( return PROPERTY_NULL; } -ULONG IEnumSTATSTGImpl_FindProperty( +static ULONG IEnumSTATSTGImpl_FindProperty( IEnumSTATSTGImpl* This, const OLECHAR* lpszPropName, StgProperty* currentProperty) @@ -3924,7 +4058,7 @@ ULONG IEnumSTATSTGImpl_FindProperty( return PROPERTY_NULL; } -void IEnumSTATSTGImpl_PushSearchNode( +static void IEnumSTATSTGImpl_PushSearchNode( IEnumSTATSTGImpl* This, ULONG nodeToPush) { @@ -3973,7 +4107,7 @@ void IEnumSTATSTGImpl_PushSearchNode( } } -ULONG IEnumSTATSTGImpl_PopSearchNode( +static ULONG IEnumSTATSTGImpl_PopSearchNode( IEnumSTATSTGImpl* This, BOOL remove) { @@ -4008,7 +4142,7 @@ static const IEnumSTATSTGVtbl IEnumSTATSTGImpl_Vtbl = ** IEnumSTATSTGImpl implementation */ -IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct( +static IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct( StorageImpl* parentStorage, ULONG firstPropertyNode) { @@ -4079,7 +4213,7 @@ static const IStorageVtbl Storage32InternalImpl_Vtbl = ** Storage32InternalImpl implementation */ -StorageInternalImpl* StorageInternalImpl_Construct( +static StorageInternalImpl* StorageInternalImpl_Construct( StorageImpl* ancestorStorage, DWORD openFlags, ULONG rootPropertyIndex) @@ -4095,12 +4229,18 @@ StorageInternalImpl* StorageInternalImpl_Construct( { memset(newStorage, 0, sizeof(StorageInternalImpl)); + /* + * Initialize the stream list + */ + + list_init(&newStorage->base.strmHead); + /* * Initialize the virtual function table. */ newStorage->base.lpVtbl = &Storage32InternalImpl_Vtbl; newStorage->base.v_destructor = &StorageInternalImpl_Destroy; - newStorage->base.openFlags = openFlags; + newStorage->base.openFlags = (openFlags & ~STGM_CREATE); /* * Keep the ancestor storage pointer and nail a reference to it. @@ -4300,7 +4440,7 @@ void BlockChainStream_Destroy(BlockChainStream* This) * This->headOfStreamPlaceHolder. * */ -ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This) +static ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This) { StgProperty chainProperty; BOOL readSuccessful; @@ -4331,7 +4471,7 @@ ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This) * This is not the size of the stream as the last block may not be full! * */ -ULONG BlockChainStream_GetCount(BlockChainStream* This) +static ULONG BlockChainStream_GetCount(BlockChainStream* This) { ULONG blockIndex; ULONG count = 0; @@ -4359,7 +4499,7 @@ ULONG BlockChainStream_GetCount(BlockChainStream* This) * bytesRead may be NULL. * Failure will be returned if the specified number of bytes has not been read. */ -BOOL BlockChainStream_ReadAt(BlockChainStream* This, +HRESULT BlockChainStream_ReadAt(BlockChainStream* This, ULARGE_INTEGER offset, ULONG size, void* buffer, @@ -4370,7 +4510,8 @@ BOOL BlockChainStream_ReadAt(BlockChainStream* This, ULONG bytesToReadInBuffer; ULONG blockIndex; BYTE* bufferWalker; - BYTE* bigBlockBuffer; + + TRACE("(%p)-> %i %p %i %p\n",This, offset.u.LowPart, buffer, size, bytesRead); /* * Find the first block in the stream that contains part of the buffer. @@ -4394,12 +4535,12 @@ BOOL BlockChainStream_ReadAt(BlockChainStream* This, while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN)) { if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, &blockIndex))) - return FALSE; + return STG_E_DOCFILECORRUPT; blockNoInSequence--; } if ((blockNoInSequence > 0) && (blockIndex == BLOCK_END_OF_CHAIN)) - return FALSE; /* We failed to find the starting block */ + return STG_E_DOCFILECORRUPT; /* We failed to find the starting block */ This->lastBlockNoInSequenceIndex = blockIndex; @@ -4411,36 +4552,40 @@ BOOL BlockChainStream_ReadAt(BlockChainStream* This, while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) ) { + ULARGE_INTEGER ulOffset; + DWORD bytesReadAt; /* * Calculate how many bytes we can copy from this big block. */ bytesToReadInBuffer = min(This->parentStorage->bigBlockSize - offsetInBlock, size); - /* - * Copy those bytes to the buffer - */ - bigBlockBuffer = - StorageImpl_GetROBigBlock(This->parentStorage, blockIndex); - - memcpy(bufferWalker, bigBlockBuffer + offsetInBlock, bytesToReadInBuffer); - - StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer); + TRACE("block %i\n",blockIndex); + ulOffset.u.HighPart = 0; + ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex) + + offsetInBlock; + StorageImpl_ReadAt(This->parentStorage, + ulOffset, + bufferWalker, + bytesToReadInBuffer, + &bytesReadAt); /* * Step to the next big block. */ - if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, &blockIndex))) - return FALSE; + if( size > bytesReadAt && FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, &blockIndex))) + return STG_E_DOCFILECORRUPT; - bufferWalker += bytesToReadInBuffer; - size -= bytesToReadInBuffer; - *bytesRead += bytesToReadInBuffer; + bufferWalker += bytesReadAt; + size -= bytesReadAt; + *bytesRead += bytesReadAt; offsetInBlock = 0; /* There is no offset on the next block */ + if (bytesToReadInBuffer != bytesReadAt) + break; } - return (size == 0); + return (size == 0) ? S_OK : STG_E_READFAULT; } /****************************************************************************** @@ -4450,7 +4595,7 @@ BOOL BlockChainStream_ReadAt(BlockChainStream* This, * bytesWritten may be NULL. * Will fail if not all specified number of bytes have been written. */ -BOOL BlockChainStream_WriteAt(BlockChainStream* This, +HRESULT BlockChainStream_WriteAt(BlockChainStream* This, ULARGE_INTEGER offset, ULONG size, const void* buffer, @@ -4461,7 +4606,6 @@ BOOL BlockChainStream_WriteAt(BlockChainStream* This, ULONG bytesToWrite; ULONG blockIndex; const BYTE* bufferWalker; - BYTE* bigBlockBuffer; /* * Find the first block in the stream that contains part of the buffer. @@ -4486,12 +4630,20 @@ BOOL BlockChainStream_WriteAt(BlockChainStream* This, { if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, &blockIndex))) - return FALSE; + return STG_E_DOCFILECORRUPT; blockNoInSequence--; } This->lastBlockNoInSequenceIndex = blockIndex; + /* BlockChainStream_SetSize should have already been called to ensure we have + * enough blocks in the chain to write into */ + if (blockIndex == BLOCK_END_OF_CHAIN) + { + ERR("not enough blocks in chain to write data\n"); + return STG_E_DOCFILECORRUPT; + } + /* * Here, I'm casting away the constness on the buffer variable * This is OK since we don't intend to modify that buffer. @@ -4501,34 +4653,42 @@ BOOL BlockChainStream_WriteAt(BlockChainStream* This, while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) ) { + ULARGE_INTEGER ulOffset; + DWORD bytesWrittenAt; /* * Calculate how many bytes we can copy from this big block. */ bytesToWrite = min(This->parentStorage->bigBlockSize - offsetInBlock, size); - /* - * Copy those bytes to the buffer - */ - bigBlockBuffer = StorageImpl_GetBigBlock(This->parentStorage, blockIndex); + TRACE("block %i\n",blockIndex); + ulOffset.u.HighPart = 0; + ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex) + + offsetInBlock; - memcpy(bigBlockBuffer + offsetInBlock, bufferWalker, bytesToWrite); - - StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer); + StorageImpl_WriteAt(This->parentStorage, + ulOffset, + (BYTE*)bufferWalker, + bytesToWrite, + &bytesWrittenAt); /* * Step to the next big block. */ - if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, + if(size > bytesWrittenAt && FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, &blockIndex))) - return FALSE; - bufferWalker += bytesToWrite; - size -= bytesToWrite; - *bytesWritten += bytesToWrite; + return STG_E_DOCFILECORRUPT; + + bufferWalker += bytesWrittenAt; + size -= bytesWrittenAt; + *bytesWritten += bytesWrittenAt; offsetInBlock = 0; /* There is no offset on the next block */ + + if (bytesWrittenAt != bytesToWrite) + break; } - return (size == 0); + return (size == 0) ? S_OK : STG_E_WRITEFAULT; } /****************************************************************************** @@ -4536,8 +4696,8 @@ BOOL BlockChainStream_WriteAt(BlockChainStream* This, * * Shrinks this chain in the big block depot. */ -BOOL BlockChainStream_Shrink(BlockChainStream* This, - ULARGE_INTEGER newSize) +static BOOL BlockChainStream_Shrink(BlockChainStream* This, + ULARGE_INTEGER newSize) { ULONG blockIndex, extraBlock; ULONG numBlocks; @@ -4604,8 +4764,8 @@ BOOL BlockChainStream_Shrink(BlockChainStream* This, * * Grows this chain in the big block depot. */ -BOOL BlockChainStream_Enlarge(BlockChainStream* This, - ULARGE_INTEGER newSize) +static BOOL BlockChainStream_Enlarge(BlockChainStream* This, + ULARGE_INTEGER newSize) { ULONG blockIndex, currentBlock; ULONG newNumBlocks; @@ -4735,21 +4895,6 @@ BOOL BlockChainStream_SetSize( } else { - ULARGE_INTEGER fileSize = - BIGBLOCKFILE_GetSize(This->parentStorage->bigBlockFile); - - ULONG diff = newSize.u.LowPart - size.u.LowPart; - - /* - * Make sure the file stays a multiple of blocksize - */ - if ((diff % This->parentStorage->bigBlockSize) != 0) - diff += (This->parentStorage->bigBlockSize - - (diff % This->parentStorage->bigBlockSize) ); - - fileSize.u.LowPart += diff; - BIGBLOCKFILE_SetSize(This->parentStorage->bigBlockFile, fileSize); - BlockChainStream_Enlarge(This, newSize); } @@ -4762,7 +4907,7 @@ BOOL BlockChainStream_SetSize( * Returns the size of this chain. * Will return the block count if this chain doesn't have a property. */ -ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This) +static ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This) { StgProperty chainProperty; @@ -4826,7 +4971,7 @@ void SmallBlockChainStream_Destroy( * * Returns the head of this chain of small blocks. */ -ULONG SmallBlockChainStream_GetHeadOfChain( +static ULONG SmallBlockChainStream_GetHeadOfChain( SmallBlockChainStream* This) { StgProperty chainProperty; @@ -4858,7 +5003,7 @@ ULONG SmallBlockChainStream_GetHeadOfChain( * - BLOCK_END_OF_CHAIN: end of this chain * - BLOCK_UNUSED: small block 'blockIndex' is free */ -HRESULT SmallBlockChainStream_GetNextBlockInChain( +static HRESULT SmallBlockChainStream_GetNextBlockInChain( SmallBlockChainStream* This, ULONG blockIndex, ULONG* nextBlockInChain) @@ -4866,7 +5011,7 @@ HRESULT SmallBlockChainStream_GetNextBlockInChain( ULARGE_INTEGER offsetOfBlockInDepot; DWORD buffer; ULONG bytesRead; - BOOL success; + HRESULT res; *nextBlockInChain = BLOCK_END_OF_CHAIN; @@ -4876,20 +5021,20 @@ HRESULT SmallBlockChainStream_GetNextBlockInChain( /* * Read those bytes in the buffer from the small block file. */ - success = BlockChainStream_ReadAt( + res = BlockChainStream_ReadAt( This->parentStorage->smallBlockDepotChain, offsetOfBlockInDepot, sizeof(DWORD), &buffer, &bytesRead); - if (success) + if (SUCCEEDED(res)) { StorageUtl_ReadDWord((BYTE *)&buffer, 0, nextBlockInChain); return S_OK; } - return STG_E_READFAULT; + return res; } /****************************************************************************** @@ -4900,7 +5045,7 @@ HRESULT SmallBlockChainStream_GetNextBlockInChain( * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock. * To flag a block as free use BLOCK_UNUSED as nextBlock. */ -void SmallBlockChainStream_SetNextBlockInChain( +static void SmallBlockChainStream_SetNextBlockInChain( SmallBlockChainStream* This, ULONG blockIndex, ULONG nextBlock) @@ -4930,7 +5075,7 @@ void SmallBlockChainStream_SetNextBlockInChain( * * Flag small block 'blockIndex' as free in the small block depot. */ -void SmallBlockChainStream_FreeBlock( +static void SmallBlockChainStream_FreeBlock( SmallBlockChainStream* This, ULONG blockIndex) { @@ -4944,7 +5089,7 @@ void SmallBlockChainStream_FreeBlock( * enlarged if necessary. The small block chain will also be enlarged if * necessary. */ -ULONG SmallBlockChainStream_GetNextFreeBlock( +static ULONG SmallBlockChainStream_GetNextFreeBlock( SmallBlockChainStream* This) { ULARGE_INTEGER offsetOfBlockInDepot; @@ -4952,7 +5097,7 @@ ULONG SmallBlockChainStream_GetNextFreeBlock( ULONG bytesRead; ULONG blockIndex = 0; ULONG nextBlockIndex = BLOCK_END_OF_CHAIN; - BOOL success = TRUE; + HRESULT res = S_OK; ULONG smallBlocksPerBigBlock; offsetOfBlockInDepot.u.HighPart = 0; @@ -4964,7 +5109,7 @@ ULONG SmallBlockChainStream_GetNextFreeBlock( { offsetOfBlockInDepot.u.LowPart = blockIndex * sizeof(ULONG); - success = BlockChainStream_ReadAt( + res = BlockChainStream_ReadAt( This->parentStorage->smallBlockDepotChain, offsetOfBlockInDepot, sizeof(DWORD), @@ -4974,7 +5119,7 @@ ULONG SmallBlockChainStream_GetNextFreeBlock( /* * If we run out of space for the small block depot, enlarge it */ - if (success) + if (SUCCEEDED(res)) { StorageUtl_ReadDWord((BYTE *)&buffer, 0, &nextBlockIndex); @@ -4988,7 +5133,7 @@ ULONG SmallBlockChainStream_GetNextFreeBlock( ULONG sbdIndex = This->parentStorage->smallBlockDepotStart; ULONG nextBlock, newsbdIndex; - BYTE* smallBlockDepot; + BYTE smallBlockDepot[BIG_BLOCK_SIZE]; nextBlock = sbdIndex; while (nextBlock != BLOCK_END_OF_CHAIN) @@ -5012,11 +5157,8 @@ ULONG SmallBlockChainStream_GetNextFreeBlock( /* * Initialize all the small blocks to free */ - smallBlockDepot = - StorageImpl_GetBigBlock(This->parentStorage, newsbdIndex); - memset(smallBlockDepot, BLOCK_UNUSED, This->parentStorage->bigBlockSize); - StorageImpl_ReleaseBigBlock(This->parentStorage, smallBlockDepot); + StorageImpl_WriteBigBlock(This->parentStorage, newsbdIndex, smallBlockDepot); if (count == 0) { @@ -5166,29 +5308,29 @@ HRESULT SmallBlockChainStream_ReadAt( * The small block has already been identified so it shouldn't fail * unless the file is corrupt. */ - if (!BlockChainStream_ReadAt(This->parentStorage->smallBlockRootChain, + rc = BlockChainStream_ReadAt(This->parentStorage->smallBlockRootChain, offsetInBigBlockFile, bytesToReadInBuffer, bufferWalker, - &bytesReadFromBigBlockFile)) - return STG_E_DOCFILECORRUPT; + &bytesReadFromBigBlockFile); - assert(bytesReadFromBigBlockFile == bytesToReadInBuffer); + if (FAILED(rc)) + return rc; /* * Step to the next big block. */ rc = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex); if(FAILED(rc)) - return rc; + return STG_E_DOCFILECORRUPT; - bufferWalker += bytesToReadInBuffer; - size -= bytesToReadInBuffer; - *bytesRead += bytesToReadInBuffer; - offsetInBlock = 0; /* There is no offset on the next block */ + bufferWalker += bytesReadFromBigBlockFile; + size -= bytesReadFromBigBlockFile; + *bytesRead += bytesReadFromBigBlockFile; + offsetInBlock = (offsetInBlock + bytesReadFromBigBlockFile) % This->parentStorage->smallBlockSize; } - return rc; + return (size == 0) ? S_OK : STG_E_READFAULT; } /****************************************************************************** @@ -5198,7 +5340,7 @@ HRESULT SmallBlockChainStream_ReadAt( * bytesWritten may be NULL. * Will fail if not all specified number of bytes have been written. */ -BOOL SmallBlockChainStream_WriteAt( +HRESULT SmallBlockChainStream_WriteAt( SmallBlockChainStream* This, ULARGE_INTEGER offset, ULONG size, @@ -5212,8 +5354,9 @@ BOOL SmallBlockChainStream_WriteAt( ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->smallBlockSize; ULONG bytesToWriteInBuffer; ULONG blockIndex; - ULONG bytesWrittenFromBigBlockFile; + ULONG bytesWrittenToBigBlockFile; const BYTE* bufferWalker; + HRESULT res; /* * This should never happen on a small block file. @@ -5228,7 +5371,7 @@ BOOL SmallBlockChainStream_WriteAt( while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN)) { if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex))) - return FALSE; + return STG_E_DOCFILECORRUPT; blockNoInSequence--; } @@ -5260,13 +5403,14 @@ BOOL SmallBlockChainStream_WriteAt( /* * Write those bytes in the buffer to the small block file. */ - BlockChainStream_WriteAt(This->parentStorage->smallBlockRootChain, + res = BlockChainStream_WriteAt( + This->parentStorage->smallBlockRootChain, offsetInBigBlockFile, bytesToWriteInBuffer, bufferWalker, - &bytesWrittenFromBigBlockFile); - - assert(bytesWrittenFromBigBlockFile == bytesToWriteInBuffer); + &bytesWrittenToBigBlockFile); + if (FAILED(res)) + return res; /* * Step to the next big block. @@ -5274,13 +5418,13 @@ BOOL SmallBlockChainStream_WriteAt( if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex))) return FALSE; - bufferWalker += bytesToWriteInBuffer; - size -= bytesToWriteInBuffer; - *bytesWritten += bytesToWriteInBuffer; - offsetInBlock = 0; /* There is no offset on the next block */ + bufferWalker += bytesWrittenToBigBlockFile; + size -= bytesWrittenToBigBlockFile; + *bytesWritten += bytesWrittenToBigBlockFile; + offsetInBlock = (offsetInBlock + bytesWrittenToBigBlockFile) % This->parentStorage->smallBlockSize; } - return (size == 0); + return (size == 0) ? S_OK : STG_E_WRITEFAULT; } /****************************************************************************** @@ -5288,7 +5432,7 @@ BOOL SmallBlockChainStream_WriteAt( * * Shrinks this chain in the small block depot. */ -BOOL SmallBlockChainStream_Shrink( +static BOOL SmallBlockChainStream_Shrink( SmallBlockChainStream* This, ULARGE_INTEGER newSize) { @@ -5371,7 +5515,7 @@ BOOL SmallBlockChainStream_Shrink( * * Grows this chain in the small block depot. */ -BOOL SmallBlockChainStream_Enlarge( +static BOOL SmallBlockChainStream_Enlarge( SmallBlockChainStream* This, ULARGE_INTEGER newSize) { @@ -5445,30 +5589,6 @@ BOOL SmallBlockChainStream_Enlarge( return TRUE; } -/****************************************************************************** - * SmallBlockChainStream_GetCount - * - * Returns the number of blocks that comprises this chain. - * This is not the size of this chain as the last block may not be full! - */ -ULONG SmallBlockChainStream_GetCount(SmallBlockChainStream* This) -{ - ULONG blockIndex; - ULONG count = 0; - - blockIndex = SmallBlockChainStream_GetHeadOfChain(This); - - while (blockIndex != BLOCK_END_OF_CHAIN) - { - count++; - - if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex))) - return 0; - } - - return count; -} - /****************************************************************************** * SmallBlockChainStream_SetSize * @@ -5505,7 +5625,7 @@ BOOL SmallBlockChainStream_SetSize( * * Returns the size of this chain. */ -ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This) +static ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This) { StgProperty chainProperty; @@ -5519,6 +5639,22 @@ ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This) /****************************************************************************** * StgCreateDocfile [OLE32.@] + * Creates a new compound file storage object + * + * PARAMS + * pwcsName [ I] Unicode string with filename (can be relative or NULL) + * grfMode [ I] Access mode for opening the new storage object (see STGM_ constants) + * reserved [ ?] unused?, usually 0 + * ppstgOpen [IO] A pointer to IStorage pointer to the new onject + * + * RETURNS + * S_OK if the file was successfully created + * some STG_E_ value if error + * NOTES + * if pwcsName is NULL, create file with new unique name + * the function can returns + * STG_S_CONVERTED if the specified file was successfully converted to storage format + * (unrealized now) */ HRESULT WINAPI StgCreateDocfile( LPCOLESTR pwcsName, @@ -5535,7 +5671,7 @@ HRESULT WINAPI StgCreateDocfile( DWORD fileAttributes; WCHAR tempFileName[MAX_PATH]; - TRACE("(%s, %lx, %ld, %p)\n", + TRACE("(%s, %x, %d, %p)\n", debugstr_w(pwcsName), grfMode, reserved, ppstgOpen); @@ -5553,7 +5689,7 @@ HRESULT WINAPI StgCreateDocfile( if ( FAILED( validateSTGM(grfMode) )) goto end; - /* StgCreateDocFile always opens for write */ + /* StgCreateDocFile seems to refuse readonly access, despite MSDN */ switch(STGM_ACCESS_MODE(grfMode)) { case STGM_WRITE: @@ -5563,20 +5699,19 @@ HRESULT WINAPI StgCreateDocfile( goto end; } - /* can't share write */ - switch(STGM_SHARE_MODE(grfMode)) - { - case STGM_SHARE_EXCLUSIVE: - case STGM_SHARE_DENY_WRITE: - break; - default: - goto end; - } + /* if no share mode given then DENY_NONE is the default */ + if (STGM_SHARE_MODE(grfMode) == 0) + grfMode |= STGM_SHARE_DENY_NONE; - /* shared reading requires transacted mode */ - if( STGM_SHARE_MODE(grfMode) == STGM_SHARE_DENY_WRITE && - !(grfMode&STGM_TRANSACTED) ) + /* must have at least one access mode */ + if (STGM_ACCESS_MODE(grfMode) == 0) goto end; + + /* in direct mode, can only use SHARE_EXCLUSIVE */ + if (!(grfMode & STGM_TRANSACTED) && (STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE)) + goto end; + + /* but in transacted mode, any share mode is valid */ /* * Generate a unique name. @@ -5586,9 +5721,6 @@ HRESULT WINAPI StgCreateDocfile( WCHAR tempPath[MAX_PATH]; static const WCHAR prefix[] = { 'S', 'T', 'O', 0 }; - if (STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE) - goto end; - memset(tempPath, 0, sizeof(tempPath)); memset(tempFileName, 0, sizeof(tempFileName)); @@ -5680,7 +5812,7 @@ HRESULT WINAPI StgCreateDocfile( (REFIID)&IID_IStorage, (void**)ppstgOpen); end: - TRACE("<-- %p r = %08lx\n", *ppstgOpen, hr); + TRACE("<-- %p r = %08x\n", *ppstgOpen, hr); return hr; } @@ -5690,7 +5822,7 @@ end: */ HRESULT WINAPI StgCreateStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS* pStgOptions, void* reserved, REFIID riid, void** ppObjectOpen) { - TRACE("(%s, %lx, %lx, %lx, %p, %p, %p, %p)\n", debugstr_w(pwcsName), + TRACE("(%s, %x, %x, %x, %p, %p, %p, %p)\n", debugstr_w(pwcsName), grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen); if (stgfmt != STGFMT_FILE && grfAttrs != 0) @@ -5699,7 +5831,7 @@ HRESULT WINAPI StgCreateStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD st return STG_E_INVALIDPARAMETER; } - if (stgfmt != STGFMT_FILE && grfAttrs != 0 && grfAttrs != FILE_FLAG_NO_BUFFERING) + if (stgfmt == STGFMT_FILE && grfAttrs != 0 && grfAttrs != FILE_FLAG_NO_BUFFERING) { ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_FILE\n"); return STG_E_INVALIDPARAMETER; @@ -5729,7 +5861,7 @@ HRESULT WINAPI StgCreatePropSetStg(IStorage *pstg, DWORD reserved, { HRESULT hr; - TRACE("(%p, 0x%lx, %p): stub\n", pstg, reserved, ppPropSetStg); + TRACE("(%p, 0x%x, %p)\n", pstg, reserved, ppPropSetStg); if (reserved) hr = STG_E_INVALIDPARAMETER; else @@ -5743,7 +5875,7 @@ HRESULT WINAPI StgCreatePropSetStg(IStorage *pstg, DWORD reserved, */ HRESULT WINAPI StgOpenStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS* pStgOptions, void* reserved, REFIID riid, void** ppObjectOpen) { - TRACE("(%s, %lx, %lx, %lx, %p, %p, %p, %p)\n", debugstr_w(pwcsName), + TRACE("(%s, %x, %x, %x, %p, %p, %p, %p)\n", debugstr_w(pwcsName), grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen); if (stgfmt != STGFMT_DOCFILE && grfAttrs != 0) @@ -5752,28 +5884,33 @@ HRESULT WINAPI StgOpenStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD stgf return STG_E_INVALIDPARAMETER; } - if (stgfmt != STGFMT_DOCFILE && grfAttrs != 0 && grfAttrs != FILE_FLAG_NO_BUFFERING) - { - ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_DOCFILE\n"); - return STG_E_INVALIDPARAMETER; - } - - if (stgfmt == STGFMT_FILE) + switch (stgfmt) { + case STGFMT_FILE: ERR("Cannot use STGFMT_FILE - this is NTFS only\n"); return STG_E_INVALIDPARAMETER; + + case STGFMT_STORAGE: + break; + + case STGFMT_DOCFILE: + if (grfAttrs && grfAttrs != FILE_FLAG_NO_BUFFERING) + { + ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_DOCFILE\n"); + return STG_E_INVALIDPARAMETER; + } + FIXME("Stub: calling StgOpenStorage, but ignoring pStgOptions and grfAttrs\n"); + break; + + case STGFMT_ANY: + WARN("STGFMT_ANY assuming storage\n"); + break; + + default: + return STG_E_INVALIDPARAMETER; } - if (stgfmt == STGFMT_STORAGE || stgfmt == STGFMT_DOCFILE || stgfmt == STGFMT_ANY) - { - if (stgfmt == STGFMT_ANY) - WARN("STGFMT_ANY assuming storage\n"); - FIXME("Stub: calling StgOpenStorage, but ignoring pStgOptions and grfAttrs\n"); - return StgOpenStorage(pwcsName, NULL, grfMode, (SNB)NULL, 0, (IStorage **)ppObjectOpen); - } - - ERR("Invalid stgfmt argument\n"); - return STG_E_INVALIDPARAMETER; + return StgOpenStorage(pwcsName, NULL, grfMode, (SNB)NULL, 0, (IStorage **)ppObjectOpen); } @@ -5783,20 +5920,19 @@ HRESULT WINAPI StgOpenStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD stgf HRESULT WINAPI StgOpenStorage( const OLECHAR *pwcsName, IStorage *pstgPriority, - DWORD grfMode, - SNB snbExclude, - DWORD reserved, - IStorage **ppstgOpen) + DWORD grfMode, + SNB snbExclude, + DWORD reserved, + IStorage **ppstgOpen) { - StorageImpl* newStorage = 0; + StorageImpl* newStorage = 0; HRESULT hr = S_OK; - HANDLE hFile = 0; + HANDLE hFile = 0; DWORD shareMode; DWORD accessMode; WCHAR fullname[MAX_PATH]; - DWORD length; - TRACE("(%s, %p, %lx, %p, %ld, %p)\n", + TRACE("(%s, %p, %x, %p, %d, %p)\n", debugstr_w(pwcsName), pstgPriority, grfMode, snbExclude, reserved, ppstgOpen); @@ -5821,10 +5957,29 @@ HRESULT WINAPI StgOpenStorage( goto end; } + if (grfMode & STGM_PRIORITY) + { + if (grfMode & (STGM_TRANSACTED|STGM_SIMPLE|STGM_NOSCRATCH|STGM_NOSNAPSHOT)) + return STG_E_INVALIDFLAG; + if (grfMode & STGM_DELETEONRELEASE) + return STG_E_INVALIDFUNCTION; + if(STGM_ACCESS_MODE(grfMode) != STGM_READ) + return STG_E_INVALIDFLAG; + grfMode &= ~0xf0; /* remove the existing sharing mode */ + grfMode |= STGM_SHARE_DENY_NONE; + + /* STGM_PRIORITY stops other IStorage objects on the same file from + * committing until the STGM_PRIORITY IStorage is closed. it also + * stops non-transacted mode StgOpenStorage calls with write access from + * succeeding. obviously, both of these cannot be achieved through just + * file share flags */ + FIXME("STGM_PRIORITY mode not implemented correctly\n"); + } + /* * Validate the sharing mode */ - if (!(grfMode & STGM_TRANSACTED)) + if (!(grfMode & (STGM_TRANSACTED|STGM_PRIORITY))) switch(STGM_SHARE_MODE(grfMode)) { case STGM_SHARE_EXCLUSIVE: @@ -5909,8 +6064,7 @@ HRESULT WINAPI StgOpenStorage( * Refuse to open the file if it's too small to be a structured storage file * FIXME: verify the file when reading instead of here */ - length = GetFileSize(hFile, NULL); - if (length < 0x100) + if (GetFileSize(hFile, NULL) < 0x100) { CloseHandle(hFile); hr = STG_E_FILEALREADYEXISTS; @@ -5928,15 +6082,15 @@ HRESULT WINAPI StgOpenStorage( goto end; } - /* if the file's length was zero, initialize the storage */ + /* Initialize the storage */ hr = StorageImpl_Construct( newStorage, hFile, - pwcsName, + pwcsName, NULL, grfMode, TRUE, - FALSE ); + FALSE ); if (FAILED(hr)) { @@ -5963,7 +6117,7 @@ HRESULT WINAPI StgOpenStorage( (void**)ppstgOpen); end: - TRACE("<-- %08lx, IStorage %p\n", hr, ppstgOpen ? *ppstgOpen : NULL); + TRACE("<-- %08x, IStorage %p\n", hr, ppstgOpen ? *ppstgOpen : NULL); return hr; } @@ -6282,7 +6436,7 @@ static HRESULT validateSTGM(DWORD stgm) if (stgm&~STGM_KNOWN_FLAGS) { - ERR("unknown flags %08lx\n", stgm); + ERR("unknown flags %08x\n", stgm); return E_FAIL; } @@ -6880,7 +7034,7 @@ static HRESULT STREAM_ReadString( IStream *stm, LPWSTR *string ) if( count != sizeof(len) ) return E_OUTOFMEMORY; - TRACE("%ld bytes\n",len); + TRACE("%d bytes\n",len); str = CoTaskMemAlloc( len ); if( !str ) @@ -7012,7 +7166,7 @@ HRESULT WINAPI ReadFmtUserTypeStg (LPSTORAGE pstg, CLIPFORMAT* pcf, LPOLESTR* lp STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm ); if( FAILED ( r ) ) { - WARN("Failed to open stream r = %08lx\n", r); + WARN("Failed to open stream r = %08x\n", r); return r; } @@ -7519,6 +7673,8 @@ HRESULT WINAPI OleConvertOLESTREAMToIStorage ( HRESULT hRes=S_OK; OLECONVERT_OLESTREAM_DATA pOleStreamData[2]; + TRACE("%p %p %p\n", pOleStream, pstg, ptd); + memset(pOleStreamData, 0, sizeof(pOleStreamData)); if(ptd != NULL) @@ -7609,6 +7765,7 @@ HRESULT WINAPI OleConvertIStorageToOLESTREAM ( OLECONVERT_OLESTREAM_DATA pOleStreamData[2]; static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0}; + TRACE("%p %p\n", pstg, pOleStream); memset(pOleStreamData, 0, sizeof(pOleStreamData)); @@ -7666,6 +7823,14 @@ HRESULT WINAPI GetConvertStg(IStorage *stg) { /****************************************************************************** * StgIsStorageFile [OLE32.@] + * Verify if the file contains a storage object + * + * PARAMS + * fn [ I] Filename + * + * RETURNS + * S_OK if file has magic bytes as a storage object + * S_FALSE if file is not storage */ HRESULT WINAPI StgIsStorageFile(LPCOLESTR fn) @@ -7674,7 +7839,7 @@ StgIsStorageFile(LPCOLESTR fn) BYTE magic[8]; DWORD bytes_read; - TRACE("(\'%s\')\n", debugstr_w(fn)); + TRACE("%s\n", debugstr_w(fn)); hf = CreateFileW(fn, GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); @@ -7704,3 +7869,63 @@ StgIsStorageFile(LPCOLESTR fn) WARN(" -> Invalid header.\n"); return S_FALSE; } + +/*********************************************************************** + * WriteClassStm (OLE32.@) + * + * Writes a CLSID to a stream. + * + * PARAMS + * pStm [I] Stream to write to. + * rclsid [I] CLSID to write. + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT code. + */ +HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid) +{ + TRACE("(%p,%p)\n",pStm,rclsid); + + if (!pStm || !rclsid) + return E_INVALIDARG; + + return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL); +} + +/*********************************************************************** + * ReadClassStm (OLE32.@) + * + * Reads a CLSID from a stream. + * + * PARAMS + * pStm [I] Stream to read from. + * rclsid [O] CLSID to read. + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT code. + */ +HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid) +{ + ULONG nbByte; + HRESULT res; + + TRACE("(%p,%p)\n",pStm,pclsid); + + if (!pStm || !pclsid) + return E_INVALIDARG; + + /* clear the output args */ + memcpy(pclsid, &CLSID_NULL, sizeof(*pclsid)); + + res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte); + + if (FAILED(res)) + return res; + + if (nbByte != sizeof(CLSID)) + return STG_E_READFAULT; + else + return S_OK; +} diff --git a/reactos/dll/win32/ole32/storage32.h b/reactos/dll/win32/ole32/storage32.h index 0472524f3a1..ffad5503051 100644 --- a/reactos/dll/win32/ole32/storage32.h +++ b/reactos/dll/win32/ole32/storage32.h @@ -24,7 +24,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __STORAGE32_H__ #define __STORAGE32_H__ @@ -37,6 +37,7 @@ #include "objbase.h" #include "winreg.h" #include "winternl.h" +#include "wine/list.h" /* * Definitions for the file format offsets. @@ -110,19 +111,12 @@ static const ULONG PROPERTY_NULL = 0xFFFFFFFF; STGM_TRANSACTED | STGM_CONVERT | STGM_PRIORITY | STGM_NOSCRATCH | \ STGM_NOSNAPSHOT | STGM_DIRECT_SWMR | STGM_DELETEONRELEASE | STGM_SIMPLE) -/* - * These are signatures to detect the type of Document file. - */ -static const BYTE STORAGE_magic[8] ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1}; -static const BYTE STORAGE_oldmagic[8] ={0xd0,0xcf,0x11,0xe0,0x0e,0x11,0xfc,0x0d}; - /* * Forward declarations of all the structures used by the storage * module. */ typedef struct StorageBaseImpl StorageBaseImpl; typedef struct StorageImpl StorageImpl; -typedef struct StorageInternalImpl StorageInternalImpl; typedef struct BlockChainStream BlockChainStream; typedef struct SmallBlockChainStream SmallBlockChainStream; typedef struct IEnumSTATSTGImpl IEnumSTATSTGImpl; @@ -190,11 +184,12 @@ BigBlockFile* BIGBLOCKFILE_Construct(HANDLE hFile, ULONG blocksize, BOOL fileBased); void BIGBLOCKFILE_Destructor(LPBIGBLOCKFILE This); -void* BIGBLOCKFILE_GetBigBlock(LPBIGBLOCKFILE This, ULONG index); -void* BIGBLOCKFILE_GetROBigBlock(LPBIGBLOCKFILE This, ULONG index); -void BIGBLOCKFILE_ReleaseBigBlock(LPBIGBLOCKFILE This, void *pBlock); +void BIGBLOCKFILE_EnsureExists(LPBIGBLOCKFILE This, ULONG index); void BIGBLOCKFILE_SetSize(LPBIGBLOCKFILE This, ULARGE_INTEGER newSize); -ULARGE_INTEGER BIGBLOCKFILE_GetSize(LPBIGBLOCKFILE This); +HRESULT BIGBLOCKFILE_ReadAt(LPBIGBLOCKFILE This, ULARGE_INTEGER offset, + void* buffer, ULONG size, ULONG* bytesRead); +HRESULT BIGBLOCKFILE_WriteAt(LPBIGBLOCKFILE This, ULARGE_INTEGER offset, + void* buffer, const ULONG size, ULONG* bytesRead); /************************************************************************* * Ole Convert support @@ -219,6 +214,12 @@ struct StorageBaseImpl const IPropertySetStorageVtbl *pssVtbl; /* interface for adding a properties stream */ + /* + * Stream tracking list + */ + + struct list strmHead; + /* * Reference count of this object */ @@ -246,6 +247,12 @@ struct StorageBaseImpl DWORD openFlags; }; +/**************************************************************************** + * StorageBaseImpl stream list handlers + */ + +void StorageBaseImpl_AddStream(StorageBaseImpl * stg, StgStreamImpl * strm); +void StorageBaseImpl_RemoveStream(StorageBaseImpl * stg, StgStreamImpl * strm); /**************************************************************************** * Storage32Impl definitions. @@ -298,63 +305,6 @@ struct StorageImpl BigBlockFile* bigBlockFile; }; -void StorageImpl_Destroy( - StorageBaseImpl* This); - -HRESULT StorageImpl_Construct( - StorageImpl* This, - HANDLE hFile, - LPCOLESTR pwcsName, - ILockBytes* pLkbyt, - DWORD openFlags, - BOOL fileBased, - BOOL fileCreate); - -BOOL StorageImpl_ReadBigBlock( - StorageImpl* This, - ULONG blockIndex, - void* buffer); - -BOOL StorageImpl_WriteBigBlock( - StorageImpl* This, - ULONG blockIndex, - void* buffer); - -void* StorageImpl_GetROBigBlock( - StorageImpl* This, - ULONG blockIndex); - -void* StorageImpl_GetBigBlock( - StorageImpl* This, - ULONG blockIndex); - -void StorageImpl_ReleaseBigBlock( - StorageImpl* This, - void* pBigBlock); - -ULONG StorageImpl_GetNextFreeBigBlock( - StorageImpl* This); - -void StorageImpl_FreeBigBlock( - StorageImpl* This, - ULONG blockIndex); - -HRESULT StorageImpl_GetNextBlockInChain( - StorageImpl* This, - ULONG blockIndex, - ULONG* nextBlockIndex); - -void StorageImpl_SetNextBlockInChain( - StorageImpl* This, - ULONG blockIndex, - ULONG nextBlock); - -HRESULT StorageImpl_LoadFileHeader( - StorageImpl* This); - -void StorageImpl_SaveFileHeader( - StorageImpl* This); - BOOL StorageImpl_ReadProperty( StorageImpl* This, ULONG index, @@ -369,114 +319,10 @@ BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks( StorageImpl* This, SmallBlockChainStream** ppsbChain); -ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, - ULONG blockIndex); - -void Storage32Impl_AddBlockDepot(StorageImpl* This, - ULONG blockIndex); - -ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This); - -ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, - ULONG depotIndex); - -void Storage32Impl_SetExtDepotBlock(StorageImpl* This, - ULONG depotIndex, - ULONG blockIndex); -/**************************************************************************** - * Storage32InternalImpl definitions. - * - * Definition of the implementation structure for the IStorage32 interface. - * This one implements the IStorage32 interface for storage that are - * inside another storage. - */ -struct StorageInternalImpl -{ - struct StorageBaseImpl base; - - /* - * There is no specific data for this class. - */ -}; - -/* - * Method definitions for the Storage32InternalImpl class. - */ -StorageInternalImpl* StorageInternalImpl_Construct( - StorageImpl* ancestorStorage, - DWORD openFlags, - ULONG rootTropertyIndex); - -void StorageInternalImpl_Destroy( - StorageBaseImpl* This); - -HRESULT WINAPI StorageInternalImpl_Commit( - IStorage* iface, - DWORD grfCommitFlags); /* [in] */ - -HRESULT WINAPI StorageInternalImpl_Revert( - IStorage* iface); - - -/**************************************************************************** - * IEnumSTATSTGImpl definitions. - * - * Definition of the implementation structure for the IEnumSTATSTGImpl interface. - * This class allows iterating through the content of a storage and to find - * specific items inside it. - */ -struct IEnumSTATSTGImpl -{ - const IEnumSTATSTGVtbl *lpVtbl; /* Needs to be the first item in the struct - * since we want to cast this in an IEnumSTATSTG pointer */ - - LONG ref; /* Reference count */ - StorageImpl* parentStorage; /* Reference to the parent storage */ - ULONG firstPropertyNode; /* Index of the root of the storage to enumerate */ - - /* - * The current implementation of the IEnumSTATSTGImpl class uses a stack - * to walk the property sets to get the content of a storage. This stack - * is implemented by the following 3 data members - */ - ULONG stackSize; - ULONG stackMaxSize; - ULONG* stackToVisit; - -#define ENUMSTATSGT_SIZE_INCREMENT 10 -}; - -IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct( - StorageImpl* This, - ULONG firstPropertyNode); - -void IEnumSTATSTGImpl_Destroy( - IEnumSTATSTGImpl* This); - -void IEnumSTATSTGImpl_PushSearchNode( - IEnumSTATSTGImpl* This, - ULONG nodeToPush); - -ULONG IEnumSTATSTGImpl_PopSearchNode( - IEnumSTATSTGImpl* This, - BOOL remove); - -ULONG IEnumSTATSTGImpl_FindProperty( - IEnumSTATSTGImpl* This, - const OLECHAR* lpszPropName, - StgProperty* buffer); - -INT IEnumSTATSTGImpl_FindParentProperty( - IEnumSTATSTGImpl *This, - ULONG childProperty, - StgProperty *currentProperty, - ULONG *propertyId); - - /**************************************************************************** * StgStreamImpl definitions. * - * This class imlements the IStream32 inteface and represents a stream + * This class implements the IStream32 interface and represents a stream * located inside a storage object. */ struct StgStreamImpl @@ -484,6 +330,12 @@ struct StgStreamImpl const IStreamVtbl *lpVtbl; /* Needs to be the first item in the struct * since we want to cast this to an IStream pointer */ + /* + * We are an entry in the storage object's stream handler list + */ + + struct list StrmListEntry; + /* * Reference count */ @@ -598,17 +450,14 @@ BlockChainStream* BlockChainStream_Construct( void BlockChainStream_Destroy( BlockChainStream* This); -ULONG BlockChainStream_GetHeadOfChain( - BlockChainStream* This); - -BOOL BlockChainStream_ReadAt( +HRESULT BlockChainStream_ReadAt( BlockChainStream* This, ULARGE_INTEGER offset, ULONG size, void* buffer, ULONG* bytesRead); -BOOL BlockChainStream_WriteAt( +HRESULT BlockChainStream_WriteAt( BlockChainStream* This, ULARGE_INTEGER offset, ULONG size, @@ -619,12 +468,6 @@ BOOL BlockChainStream_SetSize( BlockChainStream* This, ULARGE_INTEGER newSize); -ULARGE_INTEGER BlockChainStream_GetSize( - BlockChainStream* This); - -ULONG BlockChainStream_GetCount( - BlockChainStream* This); - /**************************************************************************** * SmallBlockChainStream definitions. * @@ -647,26 +490,6 @@ SmallBlockChainStream* SmallBlockChainStream_Construct( void SmallBlockChainStream_Destroy( SmallBlockChainStream* This); -ULONG SmallBlockChainStream_GetHeadOfChain( - SmallBlockChainStream* This); - -HRESULT SmallBlockChainStream_GetNextBlockInChain( - SmallBlockChainStream* This, - ULONG blockIndex, - ULONG* nextBlockIndex); - -void SmallBlockChainStream_SetNextBlockInChain( - SmallBlockChainStream* This, - ULONG blockIndex, - ULONG nextBlock); - -void SmallBlockChainStream_FreeBlock( - SmallBlockChainStream* This, - ULONG blockIndex); - -ULONG SmallBlockChainStream_GetNextFreeBlock( - SmallBlockChainStream* This); - HRESULT SmallBlockChainStream_ReadAt( SmallBlockChainStream* This, ULARGE_INTEGER offset, @@ -674,7 +497,7 @@ HRESULT SmallBlockChainStream_ReadAt( void* buffer, ULONG* bytesRead); -BOOL SmallBlockChainStream_WriteAt( +HRESULT SmallBlockChainStream_WriteAt( SmallBlockChainStream* This, ULARGE_INTEGER offset, ULONG size, @@ -685,11 +508,5 @@ BOOL SmallBlockChainStream_SetSize( SmallBlockChainStream* This, ULARGE_INTEGER newSize); -ULARGE_INTEGER SmallBlockChainStream_GetSize( - SmallBlockChainStream* This); - -ULONG SmallBlockChainStream_GetCount( - SmallBlockChainStream* This); - #endif /* __STORAGE32_H__ */ diff --git a/reactos/dll/win32/ole32/stubmanager.c b/reactos/dll/win32/ole32/stubmanager.c index 413f4f3e426..76e07a21c3d 100644 --- a/reactos/dll/win32/ole32/stubmanager.c +++ b/reactos/dll/win32/ole32/stubmanager.c @@ -20,7 +20,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #define COBJMACROS @@ -35,9 +35,8 @@ #include "winbase.h" #include "winuser.h" #include "objbase.h" -#include "ole2.h" -#include "ole2ver.h" #include "rpc.h" + #include "wine/debug.h" #include "compobj_private.h" @@ -71,6 +70,23 @@ struct stub_manager *new_stub_manager(APARTMENT *apt, IUnknown *object) * and the caller will also hold a reference */ sm->refs = 2; + sm->oxid_info.dwPid = GetCurrentProcessId(); + sm->oxid_info.dwTid = GetCurrentThreadId(); + /* + * FIXME: this is a hack for marshalling IRemUnknown. In real + * DCOM, the IPID of the IRemUnknown interface is generated like + * any other and passed to the OXID resolver which then returns it + * when queried. We don't have an OXID resolver yet so instead we + * use a magic IPID reserved for IRemUnknown. + */ + sm->oxid_info.ipidRemUnknown.Data1 = 0xffffffff; + sm->oxid_info.ipidRemUnknown.Data2 = 0xffff; + sm->oxid_info.ipidRemUnknown.Data3 = 0xffff; + assert(sizeof(sm->oxid_info.ipidRemUnknown.Data4) == sizeof(apt->oxid)); + memcpy(&sm->oxid_info.ipidRemUnknown.Data4, &apt->oxid, sizeof(OXID)); + sm->oxid_info.dwAuthnHint = RPC_C_AUTHN_LEVEL_NONE; + sm->oxid_info.psa = NULL /* FIXME */; + /* yes, that's right, this starts at zero. that's zero EXTERNAL * refs, ie nobody has unmarshalled anything yet. we can't have * negative refs because the stub manager cannot be explicitly @@ -103,6 +119,7 @@ static void stub_manager_delete(struct stub_manager *m) stub_manager_delete_ifstub(m, ifstub); } + CoTaskMemFree(m->oxid_info.psa); IUnknown_Release(m->object); DEBUG_CLEAR_CRITSEC_NAME(&m->lock); @@ -205,7 +222,7 @@ ULONG stub_manager_int_addref(struct stub_manager *This) refs = ++This->refs; LeaveCriticalSection(&This->apt->cs); - TRACE("before %ld\n", refs - 1); + TRACE("before %d\n", refs - 1); return refs; } @@ -219,7 +236,7 @@ ULONG stub_manager_int_release(struct stub_manager *This) EnterCriticalSection(&apt->cs); refs = --This->refs; - TRACE("after %ld\n", refs); + TRACE("after %d\n", refs); /* remove from apartment so no other thread can access it... */ if (!refs) @@ -247,13 +264,13 @@ ULONG stub_manager_ext_addref(struct stub_manager *m, ULONG refs) LeaveCriticalSection(&m->lock); - TRACE("added %lu refs to %p (oid %s), rc is now %lu\n", refs, m, wine_dbgstr_longlong(m->oid), rc); + TRACE("added %u refs to %p (oid %s), rc is now %u\n", refs, m, wine_dbgstr_longlong(m->oid), rc); return rc; } /* remove some external references */ -ULONG stub_manager_ext_release(struct stub_manager *m, ULONG refs) +ULONG stub_manager_ext_release(struct stub_manager *m, ULONG refs, BOOL last_unlock_releases) { ULONG rc; @@ -265,9 +282,9 @@ ULONG stub_manager_ext_release(struct stub_manager *m, ULONG refs) LeaveCriticalSection(&m->lock); - TRACE("removed %lu refs from %p (oid %s), rc is now %lu\n", refs, m, wine_dbgstr_longlong(m->oid), rc); + TRACE("removed %u refs from %p (oid %s), rc is now %u\n", refs, m, wine_dbgstr_longlong(m->oid), rc); - if (rc == 0) + if (rc == 0 && last_unlock_releases) stub_manager_int_release(m); return rc; @@ -365,29 +382,41 @@ HRESULT ipid_to_stub_manager(const IPID *ipid, APARTMENT **stub_apt, struct stub return S_OK; } -/* gets the apartment and IRpcStubBuffer from an object. the caller must - * release the references to both objects */ -IRpcStubBuffer *ipid_to_apt_and_stubbuffer(const IPID *ipid, APARTMENT **stub_apt) +/* gets the apartment, stub and channel of an object. the caller must + * release the references to all objects (except iface) if the function + * returned success, otherwise no references are returned. */ +HRESULT ipid_get_dispatch_params(const IPID *ipid, APARTMENT **stub_apt, + IRpcStubBuffer **stub, IRpcChannelBuffer **chan, + IID *iid, IUnknown **iface) { - IRpcStubBuffer *ret = NULL; struct stub_manager *stubmgr; struct ifstub *ifstub; + APARTMENT *apt; HRESULT hr; - *stub_apt = NULL; - - hr = ipid_to_stub_manager(ipid, stub_apt, &stubmgr); - if (hr != S_OK) return NULL; + hr = ipid_to_stub_manager(ipid, &apt, &stubmgr); + if (hr != S_OK) return RPC_E_DISCONNECTED; ifstub = stub_manager_ipid_to_ifstub(stubmgr, ipid); if (ifstub) - ret = ifstub->stubbuffer; + { + *stub = ifstub->stubbuffer; + IRpcStubBuffer_AddRef(*stub); + *chan = ifstub->chan; + IRpcChannelBuffer_AddRef(*chan); + *stub_apt = apt; + *iid = ifstub->iid; + *iface = ifstub->iface; - if (ret) IRpcStubBuffer_AddRef(ret); - - stub_manager_int_release(stubmgr); - - return ret; + stub_manager_int_release(stubmgr); + return S_OK; + } + else + { + stub_manager_int_release(stubmgr); + apartment_release(apt); + return RPC_E_DISCONNECTED; + } } /* generates an ipid in the following format (similar to native version): @@ -417,6 +446,7 @@ static inline HRESULT generate_ipid(struct stub_manager *m, IPID *ipid) struct ifstub *stub_manager_new_ifstub(struct stub_manager *m, IRpcStubBuffer *sb, IUnknown *iptr, REFIID iid, MSHLFLAGS flags) { struct ifstub *stub; + HRESULT hr; TRACE("oid=%s, stubbuffer=%p, iptr=%p, iid=%s\n", wine_dbgstr_longlong(m->oid), sb, iptr, debugstr_guid(iid)); @@ -424,6 +454,13 @@ struct ifstub *stub_manager_new_ifstub(struct stub_manager *m, IRpcStubBuffer *s stub = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct ifstub)); if (!stub) return NULL; + hr = RPC_CreateServerChannel(&stub->chan); + if (hr != S_OK) + { + HeapFree(GetProcessHeap(), 0, stub); + return NULL; + } + stub->stubbuffer = sb; if (sb) IRpcStubBuffer_AddRef(sb); @@ -432,21 +469,10 @@ struct ifstub *stub_manager_new_ifstub(struct stub_manager *m, IRpcStubBuffer *s stub->flags = flags; stub->iid = *iid; - /* - * FIXME: this is a hack for marshalling IRemUnknown. In real - * DCOM, the IPID of the IRemUnknown interface is generated like - * any other and passed to the OXID resolver which then returns it - * when queried. We don't have an OXID resolver yet so instead we - * use a magic IPID reserved for IRemUnknown. - */ - if (IsEqualIID(iid, &IID_IRemUnknown)) - { - stub->ipid.Data1 = 0xffffffff; - stub->ipid.Data2 = 0xffff; - stub->ipid.Data3 = 0xffff; - assert(sizeof(stub->ipid.Data4) == sizeof(m->apt->oxid)); - memcpy(&stub->ipid.Data4, &m->apt->oxid, sizeof(OXID)); - } + /* FIXME: find a cleaner way of identifying that we are creating an ifstub + * for the remunknown interface */ + if (flags & MSHLFLAGSP_REMUNKNOWN) + stub->ipid = m->oxid_info.ipidRemUnknown; else generate_ipid(m, &stub->ipid); @@ -468,9 +494,10 @@ static void stub_manager_delete_ifstub(struct stub_manager *m, struct ifstub *if list_remove(&ifstub->entry); RPC_UnregisterInterface(&ifstub->iid); - + if (ifstub->stubbuffer) IUnknown_Release(ifstub->stubbuffer); IUnknown_Release(ifstub->iface); + IRpcChannelBuffer_Release(ifstub->chan); HeapFree(GetProcessHeap(), 0, ifstub); } @@ -516,10 +543,10 @@ void stub_manager_release_marshal_data(struct stub_manager *m, ULONG refs, const if (ifstub->flags & MSHLFLAGS_TABLEWEAK) refs = 0; - else + else if (ifstub->flags & MSHLFLAGS_TABLESTRONG) refs = 1; - stub_manager_ext_release(m, refs); + stub_manager_ext_release(m, refs, TRUE); } /* is an ifstub table marshaled? */ @@ -542,8 +569,6 @@ BOOL stub_manager_is_table_marshaled(struct stub_manager *m, const IPID *ipid) * interacts with stub managers. */ -const IID IID_IRemUnknown = { 0x00000131, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} }; - typedef struct rem_unknown { const IRemUnknownVtbl *lpVtbl; @@ -592,7 +617,7 @@ static ULONG WINAPI RemUnknown_AddRef(IRemUnknown *iface) refs = InterlockedIncrement(&This->refs); - TRACE("%p before: %ld\n", iface, refs-1); + TRACE("%p before: %d\n", iface, refs-1); return refs; } @@ -605,7 +630,7 @@ static ULONG WINAPI RemUnknown_Release(IRemUnknown *iface) if (!refs) HeapFree(GetProcessHeap(), 0, This); - TRACE("%p after: %ld\n", iface, refs); + TRACE("%p after: %d\n", iface, refs); return refs; } @@ -619,7 +644,7 @@ static HRESULT WINAPI RemUnknown_RemQueryInterface(IRemUnknown *iface, APARTMENT *apt; struct stub_manager *stubmgr; - TRACE("(%p)->(%s, %ld, %d, %p, %p)\n", iface, debugstr_guid(ripid), cRefs, cIids, iids, ppQIResults); + TRACE("(%p)->(%s, %d, %d, %p, %p)\n", iface, debugstr_guid(ripid), cRefs, cIids, iids, ppQIResults); hr = ipid_to_stub_manager(ripid, &apt, &stubmgr); if (hr != S_OK) return hr; @@ -701,7 +726,7 @@ static HRESULT WINAPI RemUnknown_RemRelease(IRemUnknown *iface, break; } - stub_manager_ext_release(stubmgr, InterfaceRefs[i].cPublicRefs); + stub_manager_ext_release(stubmgr, InterfaceRefs[i].cPublicRefs, TRUE); if (InterfaceRefs[i].cPrivateRefs) FIXME("Releasing %ld refs securely not implemented\n", InterfaceRefs[i].cPrivateRefs); @@ -723,7 +748,7 @@ static const IRemUnknownVtbl RemUnknown_Vtbl = }; /* starts the IRemUnknown listener for the current apartment */ -HRESULT start_apartment_remote_unknown() +HRESULT start_apartment_remote_unknown(void) { IRemUnknown *pRemUnknown; HRESULT hr = S_OK; @@ -738,7 +763,7 @@ HRESULT start_apartment_remote_unknown() { STDOBJREF stdobjref; /* dummy - not used */ /* register it with the stub manager */ - hr = marshal_object(apt, &stdobjref, &IID_IRemUnknown, (IUnknown *)pRemUnknown, MSHLFLAGS_NORMAL); + hr = marshal_object(apt, &stdobjref, &IID_IRemUnknown, (IUnknown *)pRemUnknown, MSHLFLAGS_NORMAL|MSHLFLAGSP_REMUNKNOWN); /* release our reference to the object as the stub manager will manage the life cycle for us */ IRemUnknown_Release(pRemUnknown); if (hr == S_OK) diff --git a/reactos/dll/win32/ole32/usrmarshal.c b/reactos/dll/win32/ole32/usrmarshal.c index 3bd46cb73e2..c1b55422bd3 100644 --- a/reactos/dll/win32/ole32/usrmarshal.c +++ b/reactos/dll/win32/ole32/usrmarshal.c @@ -15,9 +15,10 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include #include #include @@ -34,6 +35,8 @@ #include "ole2.h" #include "oleauto.h" #include "rpcproxy.h" + +#include "wine/unicode.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(ole); @@ -43,27 +46,64 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole); #define ALIGN_LENGTH(_Len, _Align) _Len = ALIGNED_LENGTH(_Len, _Align) #define ALIGN_POINTER(_Ptr, _Align) _Ptr = ALIGNED_POINTER(_Ptr, _Align) -static void dump_user_flags(unsigned long *pFlags) +#define USER_MARSHAL_PTR_PREFIX \ + ( (DWORD)'U' | ( (DWORD)'s' << 8 ) | \ + ( (DWORD)'e' << 16 ) | ( (DWORD)'r' << 24 ) ) + +static const char* debugstr_user_flags(ULONG *pFlags) { - if (HIWORD(*pFlags) == NDR_LOCAL_DATA_REPRESENTATION) - TRACE("MAKELONG(NDR_LOCAL_REPRESENTATION, "); - else - TRACE("MAKELONG(0x%04x, ", HIWORD(*pFlags)); + char buf[12]; + const char* loword; switch (LOWORD(*pFlags)) { - case MSHCTX_LOCAL: TRACE("MSHCTX_LOCAL)"); break; - case MSHCTX_NOSHAREDMEM: TRACE("MSHCTX_NOSHAREDMEM)"); break; - case MSHCTX_DIFFERENTMACHINE: TRACE("MSHCTX_DIFFERENTMACHINE)"); break; - case MSHCTX_INPROC: TRACE("MSHCTX_INPROC)"); break; - default: TRACE("%d)", LOWORD(*pFlags)); + case MSHCTX_LOCAL: + loword="MSHCTX_LOCAL"; + break; + case MSHCTX_NOSHAREDMEM: + loword="MSHCTX_NOSHAREDMEM"; + break; + case MSHCTX_DIFFERENTMACHINE: + loword="MSHCTX_DIFFERENTMACHINE"; + break; + case MSHCTX_INPROC: + loword="MSHCTX_INPROC"; + break; + default: + sprintf(buf, "%d", LOWORD(*pFlags)); + loword=buf; } + + if (HIWORD(*pFlags) == NDR_LOCAL_DATA_REPRESENTATION) + return wine_dbg_sprintf("MAKELONG(NDR_LOCAL_REPRESENTATION, %s)", loword); + else + return wine_dbg_sprintf("MAKELONG(0x%04x, %s)", HIWORD(*pFlags), loword); } -unsigned long __RPC_USER CLIPFORMAT_UserSize(unsigned long *pFlags, unsigned long StartingSize, CLIPFORMAT *pCF) +/****************************************************************************** + * CLIPFORMAT_UserSize [OLE32.@] + * + * Calculates the buffer size required to marshal a clip format. + * + * PARAMS + * pFlags [I] Flags. See notes. + * StartingSize [I] Starting size of the buffer. This value is added on to + * the buffer size required for the clip format. + * pCF [I] Clip format to size. + * + * RETURNS + * The buffer size required to marshal a clip format plus the starting size. + * + * NOTES + * Even though the function is documented to take a pointer to an unsigned + * long in pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which + * the first parameter is an unsigned long. + * This function is only intended to be called by the RPC runtime. + */ +ULONG __RPC_USER CLIPFORMAT_UserSize(ULONG *pFlags, ULONG StartingSize, CLIPFORMAT *pCF) { - unsigned long size = StartingSize; + ULONG size = StartingSize; - TRACE("("); dump_user_flags(pFlags); TRACE(", %ld, %p\n", StartingSize, pCF); + TRACE("(%s, %d, %p\n", debugstr_user_flags(pFlags), StartingSize, pCF); size += sizeof(userCLIPFORMAT); @@ -85,11 +125,30 @@ unsigned long __RPC_USER CLIPFORMAT_UserSize(unsigned long *pFlags, unsigned lon return size; } -unsigned char * __RPC_USER CLIPFORMAT_UserMarshal(unsigned long *pFlags, unsigned char *pBuffer, CLIPFORMAT *pCF) +/****************************************************************************** + * CLIPFORMAT_UserMarshal [OLE32.@] + * + * Marshals a clip format into a buffer. + * + * PARAMS + * pFlags [I] Flags. See notes. + * pBuffer [I] Buffer to marshal the clip format into. + * pCF [I] Clip format to marshal. + * + * RETURNS + * The end of the marshaled data in the buffer. + * + * NOTES + * Even though the function is documented to take a pointer to an unsigned + * long in pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which + * the first parameter is an unsigned long. + * This function is only intended to be called by the RPC runtime. + */ +unsigned char * __RPC_USER CLIPFORMAT_UserMarshal(ULONG *pFlags, unsigned char *pBuffer, CLIPFORMAT *pCF) { wireCLIPFORMAT wirecf = (wireCLIPFORMAT)pBuffer; - TRACE("("); dump_user_flags(pFlags); TRACE(", %p, &0x%04x\n", pBuffer, *pCF); + TRACE("(%s, %p, &0x%04x\n", debugstr_user_flags(pFlags), pBuffer, *pCF); wirecf->u.dwValue = *pCF; pBuffer += sizeof(*wirecf); @@ -123,11 +182,30 @@ unsigned char * __RPC_USER CLIPFORMAT_UserMarshal(unsigned long *pFlags, unsigne return pBuffer; } -unsigned char * __RPC_USER CLIPFORMAT_UserUnmarshal(unsigned long *pFlags, unsigned char *pBuffer, CLIPFORMAT *pCF) +/****************************************************************************** + * CLIPFORMAT_UserUnmarshal [OLE32.@] + * + * Unmarshals a clip format from a buffer. + * + * PARAMS + * pFlags [I] Flags. See notes. + * pBuffer [I] Buffer to marshal the clip format from. + * pCF [O] Address that receive the unmarshaled clip format. + * + * RETURNS + * The end of the marshaled data in the buffer. + * + * NOTES + * Even though the function is documented to take a pointer to an unsigned + * long in pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which + * the first parameter is an unsigned long. + * This function is only intended to be called by the RPC runtime. + */ +unsigned char * __RPC_USER CLIPFORMAT_UserUnmarshal(ULONG *pFlags, unsigned char *pBuffer, CLIPFORMAT *pCF) { wireCLIPFORMAT wirecf = (wireCLIPFORMAT)pBuffer; - TRACE("("); dump_user_flags(pFlags); TRACE(", %p, %p\n", pBuffer, pCF); + TRACE("(%s, %p, %p\n", debugstr_user_flags(pFlags), pBuffer, pCF); pBuffer += sizeof(*wirecf); if (wirecf->fContext == WDT_INPROC_CALL) @@ -158,13 +236,31 @@ unsigned char * __RPC_USER CLIPFORMAT_UserUnmarshal(unsigned long *pFlags, unsig return pBuffer; } -void __RPC_USER CLIPFORMAT_UserFree(unsigned long *pFlags, CLIPFORMAT *pCF) +/****************************************************************************** + * CLIPFORMAT_UserFree [OLE32.@] + * + * Frees an unmarshaled clip format. + * + * PARAMS + * pFlags [I] Flags. See notes. + * pCF [I] Clip format to free. + * + * RETURNS + * The end of the marshaled data in the buffer. + * + * NOTES + * Even though the function is documented to take a pointer to an unsigned + * long in pFlags, it actually takes a pointer to a USER_MARSHAL_CB + * structure, of which the first parameter is an unsigned long. + * This function is only intended to be called by the RPC runtime. + */ +void __RPC_USER CLIPFORMAT_UserFree(ULONG *pFlags, CLIPFORMAT *pCF) { /* there is no inverse of the RegisterClipboardFormat function, * so nothing to do */ } -static unsigned long __RPC_USER handle_UserSize(unsigned long *pFlags, unsigned long StartingSize, HANDLE *handle) +static ULONG __RPC_USER handle_UserSize(ULONG *pFlags, ULONG StartingSize, HANDLE *handle) { if (LOWORD(*pFlags) == MSHCTX_DIFFERENTMACHINE) { @@ -175,7 +271,7 @@ static unsigned long __RPC_USER handle_UserSize(unsigned long *pFlags, unsigned return StartingSize + sizeof(RemotableHandle); } -static unsigned char * __RPC_USER handle_UserMarshal(unsigned long *pFlags, unsigned char *pBuffer, HANDLE *handle) +static unsigned char * __RPC_USER handle_UserMarshal(ULONG *pFlags, unsigned char *pBuffer, HANDLE *handle) { RemotableHandle *remhandle = (RemotableHandle *)pBuffer; if (LOWORD(*pFlags) == MSHCTX_DIFFERENTMACHINE) @@ -189,7 +285,7 @@ static unsigned char * __RPC_USER handle_UserMarshal(unsigned long *pFlags, unsi return pBuffer + sizeof(RemotableHandle); } -static unsigned char * __RPC_USER handle_UserUnmarshal(unsigned long *pFlags, unsigned char *pBuffer, HANDLE *handle) +static unsigned char * __RPC_USER handle_UserUnmarshal(ULONG *pFlags, unsigned char *pBuffer, HANDLE *handle) { RemotableHandle *remhandle = (RemotableHandle *)pBuffer; if (remhandle->fContext != WDT_INPROC_CALL) @@ -198,45 +294,65 @@ static unsigned char * __RPC_USER handle_UserUnmarshal(unsigned long *pFlags, un return pBuffer + sizeof(RemotableHandle); } -static void __RPC_USER handle_UserFree(unsigned long *pFlags, HANDLE *phMenu) +static void __RPC_USER handle_UserFree(ULONG *pFlags, HANDLE *phMenu) { /* nothing to do */ } #define IMPL_WIREM_HANDLE(type) \ - unsigned long __RPC_USER type##_UserSize(unsigned long *pFlags, unsigned long StartingSize, type *handle) \ + ULONG __RPC_USER type##_UserSize(ULONG *pFlags, ULONG StartingSize, type *handle) \ { \ - TRACE("("); dump_user_flags(pFlags); TRACE(", %ld, %p\n", StartingSize, handle); \ + TRACE("(%s, %d, %p\n", debugstr_user_flags(pFlags), StartingSize, handle); \ return handle_UserSize(pFlags, StartingSize, (HANDLE *)handle); \ } \ \ - unsigned char * __RPC_USER type##_UserMarshal(unsigned long *pFlags, unsigned char *pBuffer, type *handle) \ + unsigned char * __RPC_USER type##_UserMarshal(ULONG *pFlags, unsigned char *pBuffer, type *handle) \ { \ - TRACE("("); dump_user_flags(pFlags); TRACE(", %p, &%p\n", pBuffer, *handle); \ + TRACE("(%s, %p, &%p\n", debugstr_user_flags(pFlags), pBuffer, *handle); \ return handle_UserMarshal(pFlags, pBuffer, (HANDLE *)handle); \ } \ \ - unsigned char * __RPC_USER type##_UserUnmarshal(unsigned long *pFlags, unsigned char *pBuffer, type *handle) \ + unsigned char * __RPC_USER type##_UserUnmarshal(ULONG *pFlags, unsigned char *pBuffer, type *handle) \ { \ - TRACE("("); dump_user_flags(pFlags); TRACE(", %p, %p\n", pBuffer, handle); \ + TRACE("(%s, %p, %p\n", debugstr_user_flags(pFlags), pBuffer, handle); \ return handle_UserUnmarshal(pFlags, pBuffer, (HANDLE *)handle); \ } \ \ - void __RPC_USER type##_UserFree(unsigned long *pFlags, type *handle) \ + void __RPC_USER type##_UserFree(ULONG *pFlags, type *handle) \ { \ - TRACE("("); dump_user_flags(pFlags); TRACE(", &%p\n", *handle); \ - return handle_UserFree(pFlags, (HANDLE *)handle); \ + TRACE("(%s, &%p\n", debugstr_user_flags(pFlags), *handle); \ + handle_UserFree(pFlags, (HANDLE *)handle); \ } IMPL_WIREM_HANDLE(HACCEL) IMPL_WIREM_HANDLE(HMENU) IMPL_WIREM_HANDLE(HWND) -unsigned long __RPC_USER HGLOBAL_UserSize(unsigned long *pFlags, unsigned long StartingSize, HGLOBAL *phGlobal) +/****************************************************************************** + * HGLOBAL_UserSize [OLE32.@] + * + * Calculates the buffer size required to marshal an HGLOBAL. + * + * PARAMS + * pFlags [I] Flags. See notes. + * StartingSize [I] Starting size of the buffer. This value is added on to + * the buffer size required for the clip format. + * phGlobal [I] HGLOBAL to size. + * + * RETURNS + * The buffer size required to marshal an HGLOBAL plus the starting size. + * + * NOTES + * Even though the function is documented to take a pointer to a ULONG in + * pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which + * the first parameter is a ULONG. + * This function is only intended to be called by the RPC runtime. + */ +ULONG __RPC_USER HGLOBAL_UserSize(ULONG *pFlags, ULONG StartingSize, HGLOBAL *phGlobal) { - unsigned long size = StartingSize; + ULONG size = StartingSize; - TRACE("("); dump_user_flags(pFlags); TRACE(", %ld, %p\n", StartingSize, phGlobal); + TRACE("(%s, %d, %p\n", debugstr_user_flags(pFlags), StartingSize, phGlobal); ALIGN_LENGTH(size, 3); @@ -252,16 +368,35 @@ unsigned long __RPC_USER HGLOBAL_UserSize(unsigned long *pFlags, unsigned long S SIZE_T ret; size += 3 * sizeof(ULONG); ret = GlobalSize(*phGlobal); - size += (unsigned long)ret; + size += (ULONG)ret; } } return size; } -unsigned char * __RPC_USER HGLOBAL_UserMarshal(unsigned long *pFlags, unsigned char *pBuffer, HGLOBAL *phGlobal) +/****************************************************************************** + * HGLOBAL_UserMarshal [OLE32.@] + * + * Marshals an HGLOBAL into a buffer. + * + * PARAMS + * pFlags [I] Flags. See notes. + * pBuffer [I] Buffer to marshal the clip format into. + * phGlobal [I] HGLOBAL to marshal. + * + * RETURNS + * The end of the marshaled data in the buffer. + * + * NOTES + * Even though the function is documented to take a pointer to a ULONG in + * pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which + * the first parameter is a ULONG. + * This function is only intended to be called by the RPC runtime. + */ +unsigned char * __RPC_USER HGLOBAL_UserMarshal(ULONG *pFlags, unsigned char *pBuffer, HGLOBAL *phGlobal) { - TRACE("("); dump_user_flags(pFlags); TRACE(", %p, &%p\n", pBuffer, *phGlobal); + TRACE("(%s, %p, &%p\n", debugstr_user_flags(pFlags), pBuffer, *phGlobal); ALIGN_POINTER(pBuffer, 3); @@ -302,11 +437,30 @@ unsigned char * __RPC_USER HGLOBAL_UserMarshal(unsigned long *pFlags, unsigned c return pBuffer; } -unsigned char * __RPC_USER HGLOBAL_UserUnmarshal(unsigned long *pFlags, unsigned char *pBuffer, HGLOBAL *phGlobal) +/****************************************************************************** + * HGLOBAL_UserUnmarshal [OLE32.@] + * + * Unmarshals an HGLOBAL from a buffer. + * + * PARAMS + * pFlags [I] Flags. See notes. + * pBuffer [I] Buffer to marshal the clip format from. + * phGlobal [O] Address that receive the unmarshaled HGLOBAL. + * + * RETURNS + * The end of the marshaled data in the buffer. + * + * NOTES + * Even though the function is documented to take a pointer to an ULONG in + * pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which + * the first parameter is an ULONG. + * This function is only intended to be called by the RPC runtime. + */ +unsigned char * __RPC_USER HGLOBAL_UserUnmarshal(ULONG *pFlags, unsigned char *pBuffer, HGLOBAL *phGlobal) { ULONG fContext; - TRACE("("); dump_user_flags(pFlags); TRACE(", %p, &%p\n", pBuffer, *phGlobal); + TRACE("(%s, %p, &%p\n", debugstr_user_flags(pFlags), pBuffer, *phGlobal); ALIGN_POINTER(pBuffer, 3); @@ -367,89 +521,553 @@ unsigned char * __RPC_USER HGLOBAL_UserUnmarshal(unsigned long *pFlags, unsigned return pBuffer; } -void __RPC_USER HGLOBAL_UserFree(unsigned long *pFlags, HGLOBAL *phGlobal) +/****************************************************************************** + * HGLOBAL_UserFree [OLE32.@] + * + * Frees an unmarshaled HGLOBAL. + * + * PARAMS + * pFlags [I] Flags. See notes. + * phGlobal [I] HGLOBAL to free. + * + * RETURNS + * The end of the marshaled data in the buffer. + * + * NOTES + * Even though the function is documented to take a pointer to a ULONG in + * pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of + * which the first parameter is a ULONG. + * This function is only intended to be called by the RPC runtime. + */ +void __RPC_USER HGLOBAL_UserFree(ULONG *pFlags, HGLOBAL *phGlobal) { - TRACE("("); dump_user_flags(pFlags); TRACE(", &%p\n", *phGlobal); + TRACE("(%s, &%p\n", debugstr_user_flags(pFlags), *phGlobal); if (LOWORD(*pFlags != MSHCTX_INPROC) && *phGlobal) GlobalFree(*phGlobal); } -unsigned long __RPC_USER HBITMAP_UserSize(unsigned long *pFlags, unsigned long StartingSize, HBITMAP *phBmp) +/****************************************************************************** + * HBITMAP_UserSize [OLE32.@] + * + * Calculates the buffer size required to marshal a bitmap. + * + * PARAMS + * pFlags [I] Flags. See notes. + * StartingSize [I] Starting size of the buffer. This value is added on to + * the buffer size required for the clip format. + * phBmp [I] Bitmap to size. + * + * RETURNS + * The buffer size required to marshal an bitmap plus the starting size. + * + * NOTES + * Even though the function is documented to take a pointer to a ULONG in + * pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which + * the first parameter is a ULONG. + * This function is only intended to be called by the RPC runtime. + */ +ULONG __RPC_USER HBITMAP_UserSize(ULONG *pFlags, ULONG StartingSize, HBITMAP *phBmp) { FIXME(":stub\n"); return StartingSize; } -unsigned char * __RPC_USER HBITMAP_UserMarshal(unsigned long *pFlags, unsigned char *pBuffer, HBITMAP *phBmp) +/****************************************************************************** +* HBITMAP_UserMarshal [OLE32.@] +* +* Marshals a bitmap into a buffer. +* +* PARAMS +* pFlags [I] Flags. See notes. +* pBuffer [I] Buffer to marshal the clip format into. +* phBmp [I] Bitmap to marshal. +* +* RETURNS +* The end of the marshaled data in the buffer. +* +* NOTES +* Even though the function is documented to take a pointer to a ULONG in +* pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which +* the first parameter is a ULONG. +* This function is only intended to be called by the RPC runtime. +*/ +unsigned char * __RPC_USER HBITMAP_UserMarshal(ULONG *pFlags, unsigned char *pBuffer, HBITMAP *phBmp) { FIXME(":stub\n"); return pBuffer; } -unsigned char * __RPC_USER HBITMAP_UserUnmarshal(unsigned long *pFlags, unsigned char *pBuffer, HBITMAP *phBmp) +/****************************************************************************** + * HBITMAP_UserUnmarshal [OLE32.@] + * + * Unmarshals a bitmap from a buffer. + * + * PARAMS + * pFlags [I] Flags. See notes. + * pBuffer [I] Buffer to marshal the clip format from. + * phBmp [O] Address that receive the unmarshaled bitmap. + * + * RETURNS + * The end of the marshaled data in the buffer. + * + * NOTES + * Even though the function is documented to take a pointer to an ULONG in + * pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which + * the first parameter is an ULONG. + * This function is only intended to be called by the RPC runtime. + */ +unsigned char * __RPC_USER HBITMAP_UserUnmarshal(ULONG *pFlags, unsigned char *pBuffer, HBITMAP *phBmp) { FIXME(":stub\n"); return pBuffer; } -void __RPC_USER HBITMAP_UserFree(unsigned long *pFlags, HBITMAP *phBmp) +/****************************************************************************** + * HBITMAP_UserFree [OLE32.@] + * + * Frees an unmarshaled bitmap. + * + * PARAMS + * pFlags [I] Flags. See notes. + * phBmp [I] Bitmap to free. + * + * RETURNS + * The end of the marshaled data in the buffer. + * + * NOTES + * Even though the function is documented to take a pointer to a ULONG in + * pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of + * which the first parameter is a ULONG. + * This function is only intended to be called by the RPC runtime. + */ +void __RPC_USER HBITMAP_UserFree(ULONG *pFlags, HBITMAP *phBmp) { FIXME(":stub\n"); } -unsigned long __RPC_USER HDC_UserSize(unsigned long *pFlags, unsigned long StartingSize, HDC *phdc) +/****************************************************************************** + * HDC_UserSize [OLE32.@] + * + * Calculates the buffer size required to marshal an HDC. + * + * PARAMS + * pFlags [I] Flags. See notes. + * StartingSize [I] Starting size of the buffer. This value is added on to + * the buffer size required for the clip format. + * phGlobal [I] HDC to size. + * + * RETURNS + * The buffer size required to marshal an HDC plus the starting size. + * + * NOTES + * Even though the function is documented to take a pointer to a ULONG in + * pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which + * the first parameter is a ULONG. + * This function is only intended to be called by the RPC runtime. + */ +ULONG __RPC_USER HDC_UserSize(ULONG *pFlags, ULONG StartingSize, HDC *phdc) { FIXME(":stub\n"); return StartingSize; } -unsigned char * __RPC_USER HDC_UserMarshal(unsigned long *pFlags, unsigned char *pBuffer, HDC *phdc) +/****************************************************************************** + * HDC_UserMarshal [OLE32.@] + * + * Marshals an HDC into a buffer. + * + * PARAMS + * pFlags [I] Flags. See notes. + * pBuffer [I] Buffer to marshal the clip format into. + * phdc [I] HDC to marshal. + * + * RETURNS + * The end of the marshaled data in the buffer. + * + * NOTES + * Even though the function is documented to take a pointer to a ULONG in + * pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which + * the first parameter is a ULONG. + * This function is only intended to be called by the RPC runtime. + */ +unsigned char * __RPC_USER HDC_UserMarshal(ULONG *pFlags, unsigned char *pBuffer, HDC *phdc) { FIXME(":stub\n"); return pBuffer; } -unsigned char * __RPC_USER HDC_UserUnmarshal(unsigned long *pFlags, unsigned char *pBuffer, HDC *phdc) +/****************************************************************************** + * HDC_UserUnmarshal [OLE32.@] + * + * Unmarshals an HDC from a buffer. + * + * PARAMS + * pFlags [I] Flags. See notes. + * pBuffer [I] Buffer to marshal the clip format from. + * phdc [O] Address that receive the unmarshaled HDC. + * + * RETURNS + * The end of the marshaled data in the buffer. + * + * NOTES + * Even though the function is documented to take a pointer to an ULONG in + * pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which + * the first parameter is an ULONG. + * This function is only intended to be called by the RPC runtime. + */ +unsigned char * __RPC_USER HDC_UserUnmarshal(ULONG *pFlags, unsigned char *pBuffer, HDC *phdc) { FIXME(":stub\n"); return pBuffer; } -void __RPC_USER HDC_UserFree(unsigned long *pFlags, HDC *phdc) +/****************************************************************************** + * HDC_UserFree [OLE32.@] + * + * Frees an unmarshaled HDC. + * + * PARAMS + * pFlags [I] Flags. See notes. + * phdc [I] HDC to free. + * + * RETURNS + * The end of the marshaled data in the buffer. + * + * NOTES + * Even though the function is documented to take a pointer to a ULONG in + * pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of + * which the first parameter is a ULONG. + * This function is only intended to be called by the RPC runtime. + */ +void __RPC_USER HDC_UserFree(ULONG *pFlags, HDC *phdc) { FIXME(":stub\n"); } -unsigned long __RPC_USER HPALETTE_UserSize(unsigned long *pFlags, unsigned long StartingSize, HPALETTE *phPal) +/****************************************************************************** + * HPALETTE_UserSize [OLE32.@] + * + * Calculates the buffer size required to marshal a palette. + * + * PARAMS + * pFlags [I] Flags. See notes. + * StartingSize [I] Starting size of the buffer. This value is added on to + * the buffer size required for the clip format. + * phPal [I] Palette to size. + * + * RETURNS + * The buffer size required to marshal a palette plus the starting size. + * + * NOTES + * Even though the function is documented to take a pointer to a ULONG in + * pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which + * the first parameter is a ULONG. + * This function is only intended to be called by the RPC runtime. + */ +ULONG __RPC_USER HPALETTE_UserSize(ULONG *pFlags, ULONG StartingSize, HPALETTE *phPal) { FIXME(":stub\n"); return StartingSize; } -unsigned char * __RPC_USER HPALETTE_UserMarshal(unsigned long *pFlags, unsigned char *pBuffer, HPALETTE *phPal) +/****************************************************************************** + * HPALETTE_UserMarshal [OLE32.@] + * + * Marshals a palette into a buffer. + * + * PARAMS + * pFlags [I] Flags. See notes. + * pBuffer [I] Buffer to marshal the clip format into. + * phPal [I] Palette to marshal. + * + * RETURNS + * The end of the marshaled data in the buffer. + * + * NOTES + * Even though the function is documented to take a pointer to a ULONG in + * pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which + * the first parameter is a ULONG. + * This function is only intended to be called by the RPC runtime. + */ +unsigned char * __RPC_USER HPALETTE_UserMarshal(ULONG *pFlags, unsigned char *pBuffer, HPALETTE *phPal) { FIXME(":stub\n"); return pBuffer; } -unsigned char * __RPC_USER HPALETTE_UserUnmarshal(unsigned long *pFlags, unsigned char *pBuffer, HPALETTE *phPal) +/****************************************************************************** + * HPALETTE_UserUnmarshal [OLE32.@] + * + * Unmarshals a palette from a buffer. + * + * PARAMS + * pFlags [I] Flags. See notes. + * pBuffer [I] Buffer to marshal the clip format from. + * phPal [O] Address that receive the unmarshaled palette. + * + * RETURNS + * The end of the marshaled data in the buffer. + * + * NOTES + * Even though the function is documented to take a pointer to an ULONG in + * pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which + * the first parameter is an ULONG. + * This function is only intended to be called by the RPC runtime. + */ +unsigned char * __RPC_USER HPALETTE_UserUnmarshal(ULONG *pFlags, unsigned char *pBuffer, HPALETTE *phPal) { FIXME(":stub\n"); return pBuffer; } -void __RPC_USER HPALETTE_UserFree(unsigned long *pFlags, HPALETTE *phPal) +/****************************************************************************** + * HPALETTE_UserFree [OLE32.@] + * + * Frees an unmarshaled palette. + * + * PARAMS + * pFlags [I] Flags. See notes. + * phPal [I] Palette to free. + * + * RETURNS + * The end of the marshaled data in the buffer. + * + * NOTES + * Even though the function is documented to take a pointer to a ULONG in + * pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of + * which the first parameter is a ULONG. + * This function is only intended to be called by the RPC runtime. + */ +void __RPC_USER HPALETTE_UserFree(ULONG *pFlags, HPALETTE *phPal) { FIXME(":stub\n"); } -unsigned long __RPC_USER HENHMETAFILE_UserSize(unsigned long *pFlags, unsigned long StartingSize, HENHMETAFILE *phEmf) +/****************************************************************************** + * HMETAFILE_UserSize [OLE32.@] + * + * Calculates the buffer size required to marshal a metafile. + * + * PARAMS + * pFlags [I] Flags. See notes. + * StartingSize [I] Starting size of the buffer. This value is added on to + * the buffer size required for the clip format. + * phmf [I] Metafile to size. + * + * RETURNS + * The buffer size required to marshal a metafile plus the starting size. + * + * NOTES + * Even though the function is documented to take a pointer to a ULONG in + * pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which + * the first parameter is a ULONG. + * This function is only intended to be called by the RPC runtime. + */ +ULONG __RPC_USER HMETAFILE_UserSize(ULONG *pFlags, ULONG StartingSize, HMETAFILE *phmf) { - unsigned long size = StartingSize; + ULONG size = StartingSize; - TRACE("("); dump_user_flags(pFlags); TRACE(", %ld, %p\n", StartingSize, *phEmf); + TRACE("(%s, %d, &%p\n", debugstr_user_flags(pFlags), StartingSize, *phmf); + + ALIGN_LENGTH(size, 3); + + size += sizeof(ULONG); + if (LOWORD(*pFlags) == MSHCTX_INPROC) + size += sizeof(ULONG_PTR); + else + { + size += sizeof(ULONG); + + if (*phmf) + { + UINT mfsize; + + size += 2 * sizeof(ULONG); + mfsize = GetMetaFileBitsEx(*phmf, 0, NULL); + size += mfsize; + } + } + + return size; +} + +/****************************************************************************** + * HMETAFILE_UserMarshal [OLE32.@] + * + * Marshals a metafile into a buffer. + * + * PARAMS + * pFlags [I] Flags. See notes. + * pBuffer [I] Buffer to marshal the clip format into. + * phEmf [I] Metafile to marshal. + * + * RETURNS + * The end of the marshaled data in the buffer. + * + * NOTES + * Even though the function is documented to take a pointer to a ULONG in + * pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which + * the first parameter is a ULONG. + * This function is only intended to be called by the RPC runtime. + */ +unsigned char * __RPC_USER HMETAFILE_UserMarshal(ULONG *pFlags, unsigned char *pBuffer, HMETAFILE *phmf) +{ + TRACE("(%s, %p, &%p\n", debugstr_user_flags(pFlags), pBuffer, *phmf); + + ALIGN_POINTER(pBuffer, 3); + + if (LOWORD(*pFlags) == MSHCTX_INPROC) + { + if (sizeof(*phmf) == 8) + *(ULONG *)pBuffer = WDT_INPROC64_CALL; + else + *(ULONG *)pBuffer = WDT_INPROC_CALL; + pBuffer += sizeof(ULONG); + *(HMETAFILE *)pBuffer = *phmf; + pBuffer += sizeof(HMETAFILE); + } + else + { + *(ULONG *)pBuffer = WDT_REMOTE_CALL; + pBuffer += sizeof(ULONG); + *(ULONG *)pBuffer = (ULONG)(ULONG_PTR)*phmf; + pBuffer += sizeof(ULONG); + + if (*phmf) + { + UINT mfsize = GetMetaFileBitsEx(*phmf, 0, NULL); + + *(ULONG *)pBuffer = mfsize; + pBuffer += sizeof(ULONG); + *(ULONG *)pBuffer = mfsize; + pBuffer += sizeof(ULONG); + GetMetaFileBitsEx(*phmf, mfsize, pBuffer); + pBuffer += mfsize; + } + } + + return pBuffer; +} + +/****************************************************************************** + * HMETAFILE_UserUnmarshal [OLE32.@] + * + * Unmarshals a metafile from a buffer. + * + * PARAMS + * pFlags [I] Flags. See notes. + * pBuffer [I] Buffer to marshal the clip format from. + * phmf [O] Address that receive the unmarshaled metafile. + * + * RETURNS + * The end of the marshaled data in the buffer. + * + * NOTES + * Even though the function is documented to take a pointer to an ULONG in + * pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which + * the first parameter is an ULONG. + * This function is only intended to be called by the RPC runtime. + */ +unsigned char * __RPC_USER HMETAFILE_UserUnmarshal(ULONG *pFlags, unsigned char *pBuffer, HMETAFILE *phmf) +{ + ULONG fContext; + + TRACE("(%s, %p, %p\n", debugstr_user_flags(pFlags), pBuffer, phmf); + + ALIGN_POINTER(pBuffer, 3); + + fContext = *(ULONG *)pBuffer; + pBuffer += sizeof(ULONG); + + if (((fContext == WDT_INPROC_CALL) && (sizeof(*phmf) < 8)) || + ((fContext == WDT_INPROC64_CALL) && (sizeof(*phmf) == 8))) + { + *phmf = *(HMETAFILE *)pBuffer; + pBuffer += sizeof(*phmf); + } + else if (fContext == WDT_REMOTE_CALL) + { + ULONG handle; + + handle = *(ULONG *)pBuffer; + pBuffer += sizeof(ULONG); + + if (handle) + { + ULONG size; + size = *(ULONG *)pBuffer; + pBuffer += sizeof(ULONG); + if (size != *(ULONG *)pBuffer) + { + RaiseException(RPC_X_BAD_STUB_DATA, 0, 0, NULL); + return pBuffer; + } + pBuffer += sizeof(ULONG); + *phmf = SetMetaFileBitsEx(size, pBuffer); + pBuffer += size; + } + else + *phmf = NULL; + } + else + RaiseException(RPC_S_INVALID_TAG, 0, 0, NULL); + + return pBuffer; +} + +/****************************************************************************** + * HMETAFILE_UserFree [OLE32.@] + * + * Frees an unmarshaled metafile. + * + * PARAMS + * pFlags [I] Flags. See notes. + * phmf [I] Metafile to free. + * + * RETURNS + * The end of the marshaled data in the buffer. + * + * NOTES + * Even though the function is documented to take a pointer to a ULONG in + * pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of + * which the first parameter is a ULONG. + * This function is only intended to be called by the RPC runtime. + */ +void __RPC_USER HMETAFILE_UserFree(ULONG *pFlags, HMETAFILE *phmf) +{ + TRACE("(%s, &%p\n", debugstr_user_flags(pFlags), *phmf); + + if (LOWORD(*pFlags) != MSHCTX_INPROC) + DeleteMetaFile(*phmf); +} + +/****************************************************************************** +* HENHMETAFILE_UserSize [OLE32.@] +* +* Calculates the buffer size required to marshal an enhanced metafile. +* +* PARAMS +* pFlags [I] Flags. See notes. +* StartingSize [I] Starting size of the buffer. This value is added on to +* the buffer size required for the clip format. +* phEmf [I] Enhanced metafile to size. +* +* RETURNS +* The buffer size required to marshal an enhanced metafile plus the starting size. +* +* NOTES +* Even though the function is documented to take a pointer to a ULONG in +* pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which +* the first parameter is a ULONG. +* This function is only intended to be called by the RPC runtime. +*/ +ULONG __RPC_USER HENHMETAFILE_UserSize(ULONG *pFlags, ULONG StartingSize, HENHMETAFILE *phEmf) +{ + ULONG size = StartingSize; + + TRACE("(%s, %d, %p\n", debugstr_user_flags(pFlags), StartingSize, *phEmf); size += sizeof(ULONG); if (LOWORD(*pFlags) == MSHCTX_INPROC) @@ -471,9 +1089,28 @@ unsigned long __RPC_USER HENHMETAFILE_UserSize(unsigned long *pFlags, unsigned l return size; } -unsigned char * __RPC_USER HENHMETAFILE_UserMarshal(unsigned long *pFlags, unsigned char *pBuffer, HENHMETAFILE *phEmf) +/****************************************************************************** + * HENHMETAFILE_UserMarshal [OLE32.@] + * + * Marshals an enhance metafile into a buffer. + * + * PARAMS + * pFlags [I] Flags. See notes. + * pBuffer [I] Buffer to marshal the clip format into. + * phEmf [I] Enhanced metafile to marshal. + * + * RETURNS + * The end of the marshaled data in the buffer. + * + * NOTES + * Even though the function is documented to take a pointer to a ULONG in + * pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which + * the first parameter is a ULONG. + * This function is only intended to be called by the RPC runtime. + */ +unsigned char * __RPC_USER HENHMETAFILE_UserMarshal(ULONG *pFlags, unsigned char *pBuffer, HENHMETAFILE *phEmf) { - TRACE("("); dump_user_flags(pFlags); TRACE(", %p, &%p\n", pBuffer, *phEmf); + TRACE("(%s, %p, &%p\n", debugstr_user_flags(pFlags), pBuffer, *phEmf); if (LOWORD(*pFlags) == MSHCTX_INPROC) { @@ -508,11 +1145,30 @@ unsigned char * __RPC_USER HENHMETAFILE_UserMarshal(unsigned long *pFlags, unsig return pBuffer; } -unsigned char * __RPC_USER HENHMETAFILE_UserUnmarshal(unsigned long *pFlags, unsigned char *pBuffer, HENHMETAFILE *phEmf) +/****************************************************************************** + * HENHMETAFILE_UserUnmarshal [OLE32.@] + * + * Unmarshals an enhanced metafile from a buffer. + * + * PARAMS + * pFlags [I] Flags. See notes. + * pBuffer [I] Buffer to marshal the clip format from. + * phEmf [O] Address that receive the unmarshaled enhanced metafile. + * + * RETURNS + * The end of the marshaled data in the buffer. + * + * NOTES + * Even though the function is documented to take a pointer to an ULONG in + * pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which + * the first parameter is an ULONG. + * This function is only intended to be called by the RPC runtime. + */ +unsigned char * __RPC_USER HENHMETAFILE_UserUnmarshal(ULONG *pFlags, unsigned char *pBuffer, HENHMETAFILE *phEmf) { ULONG fContext; - TRACE("("); dump_user_flags(pFlags); TRACE(", %p, %p\n", pBuffer, phEmf); + TRACE("(%s, %p, %p\n", debugstr_user_flags(pFlags), pBuffer, phEmf); fContext = *(ULONG *)pBuffer; pBuffer += sizeof(ULONG); @@ -553,19 +1209,253 @@ unsigned char * __RPC_USER HENHMETAFILE_UserUnmarshal(unsigned long *pFlags, uns return pBuffer; } -void __RPC_USER HENHMETAFILE_UserFree(unsigned long *pFlags, HENHMETAFILE *phEmf) +/****************************************************************************** + * HENHMETAFILE_UserFree [OLE32.@] + * + * Frees an unmarshaled enhanced metafile. + * + * PARAMS + * pFlags [I] Flags. See notes. + * phEmf [I] Enhanced metafile to free. + * + * RETURNS + * The end of the marshaled data in the buffer. + * + * NOTES + * Even though the function is documented to take a pointer to a ULONG in + * pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of + * which the first parameter is a ULONG. + * This function is only intended to be called by the RPC runtime. + */ +void __RPC_USER HENHMETAFILE_UserFree(ULONG *pFlags, HENHMETAFILE *phEmf) { - TRACE("("); dump_user_flags(pFlags); TRACE(", &%p\n", *phEmf); + TRACE("(%s, &%p\n", debugstr_user_flags(pFlags), *phEmf); if (LOWORD(*pFlags) != MSHCTX_INPROC) DeleteEnhMetaFile(*phEmf); } -unsigned long __RPC_USER STGMEDIUM_UserSize(unsigned long *pFlags, unsigned long StartingSize, STGMEDIUM *pStgMedium) +/****************************************************************************** + * HMETAFILEPICT_UserSize [OLE32.@] + * + * Calculates the buffer size required to marshal an metafile pict. + * + * PARAMS + * pFlags [I] Flags. See notes. + * StartingSize [I] Starting size of the buffer. This value is added on to + * the buffer size required for the clip format. + * phMfp [I] Metafile pict to size. + * + * RETURNS + * The buffer size required to marshal a metafile pict plus the starting size. + * + * NOTES + * Even though the function is documented to take a pointer to a ULONG in + * pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which + * the first parameter is a ULONG. + * This function is only intended to be called by the RPC runtime. + */ +ULONG __RPC_USER HMETAFILEPICT_UserSize(ULONG *pFlags, ULONG StartingSize, HMETAFILEPICT *phMfp) { - unsigned long size = StartingSize; + ULONG size = StartingSize; - TRACE("("); dump_user_flags(pFlags); TRACE(", %ld, %p\n", StartingSize, pStgMedium); + TRACE("(%s, %d, &%p)\n", debugstr_user_flags(pFlags), StartingSize, *phMfp); + + size += sizeof(ULONG); + size += sizeof(HMETAFILEPICT); + + if ((LOWORD(*pFlags) != MSHCTX_INPROC) && *phMfp) + { + METAFILEPICT *mfpict = GlobalLock(*phMfp); + + /* FIXME: raise an exception if mfpict is NULL? */ + size += FIELD_OFFSET(remoteMETAFILEPICT, hMF); + size += sizeof(ULONG); + + size = HMETAFILE_UserSize(pFlags, size, &mfpict->hMF); + + GlobalUnlock(*phMfp); + } + + return size; +} + +/****************************************************************************** + * HMETAFILEPICT_UserMarshal [OLE32.@] + * + * Marshals a metafile pict into a buffer. + * + * PARAMS + * pFlags [I] Flags. See notes. + * pBuffer [I] Buffer to marshal the clip format into. + * phMfp [I] Metafile pict to marshal. + * + * RETURNS + * The end of the marshaled data in the buffer. + * + * NOTES + * Even though the function is documented to take a pointer to a ULONG in + * pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which + * the first parameter is a ULONG. + * This function is only intended to be called by the RPC runtime. + */ +unsigned char * __RPC_USER HMETAFILEPICT_UserMarshal(ULONG *pFlags, unsigned char *pBuffer, HMETAFILEPICT *phMfp) +{ + TRACE("(%s, %p, &%p)\n", debugstr_user_flags(pFlags), pBuffer, *phMfp); + + if (LOWORD(*pFlags) == MSHCTX_INPROC) + *(ULONG *)pBuffer = WDT_INPROC_CALL; + else + *(ULONG *)pBuffer = WDT_REMOTE_CALL; + pBuffer += sizeof(ULONG); + + *(HMETAFILEPICT *)pBuffer = *phMfp; + pBuffer += sizeof(HMETAFILEPICT); + + if ((LOWORD(*pFlags) != MSHCTX_INPROC) && *phMfp) + { + METAFILEPICT *mfpict = GlobalLock(*phMfp); + remoteMETAFILEPICT * remmfpict = (remoteMETAFILEPICT *)pBuffer; + + /* FIXME: raise an exception if mfpict is NULL? */ + remmfpict->mm = mfpict->mm; + remmfpict->xExt = mfpict->xExt; + remmfpict->yExt = mfpict->yExt; + pBuffer += FIELD_OFFSET(remoteMETAFILEPICT, hMF); + *(ULONG *)pBuffer = USER_MARSHAL_PTR_PREFIX; + pBuffer += sizeof(ULONG); + + pBuffer = HMETAFILE_UserMarshal(pFlags, pBuffer, &mfpict->hMF); + + GlobalUnlock(*phMfp); + } + + return pBuffer; +} + +/****************************************************************************** + * HMETAFILEPICT_UserUnmarshal [OLE32.@] + * + * Unmarshals an metafile pict from a buffer. + * + * PARAMS + * pFlags [I] Flags. See notes. + * pBuffer [I] Buffer to marshal the clip format from. + * phMfp [O] Address that receive the unmarshaled metafile pict. + * + * RETURNS + * The end of the marshaled data in the buffer. + * + * NOTES + * Even though the function is documented to take a pointer to an ULONG in + * pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which + * the first parameter is an ULONG. + * This function is only intended to be called by the RPC runtime. + */ +unsigned char * __RPC_USER HMETAFILEPICT_UserUnmarshal(ULONG *pFlags, unsigned char *pBuffer, HMETAFILEPICT *phMfp) +{ + ULONG fContext; + + TRACE("(%s, %p, %p)\n", debugstr_user_flags(pFlags), pBuffer, phMfp); + + fContext = *(ULONG *)pBuffer; + pBuffer += sizeof(ULONG); + + if ((fContext == WDT_INPROC_CALL) || !*(HMETAFILEPICT *)pBuffer) + { + *phMfp = *(HMETAFILEPICT *)pBuffer; + pBuffer += sizeof(HMETAFILEPICT); + } + else + { + METAFILEPICT *mfpict; + const remoteMETAFILEPICT *remmfpict; + ULONG user_marshal_prefix; + + pBuffer += sizeof(HMETAFILEPICT); + remmfpict = (const remoteMETAFILEPICT *)pBuffer; + + *phMfp = GlobalAlloc(GMEM_MOVEABLE, sizeof(METAFILEPICT)); + if (!*phMfp) + RpcRaiseException(E_OUTOFMEMORY); + + mfpict = GlobalLock(*phMfp); + mfpict->mm = remmfpict->mm; + mfpict->xExt = remmfpict->xExt; + mfpict->yExt = remmfpict->yExt; + pBuffer += FIELD_OFFSET(remoteMETAFILEPICT, hMF); + user_marshal_prefix = *(ULONG *)pBuffer; + pBuffer += sizeof(ULONG); + + if (user_marshal_prefix != USER_MARSHAL_PTR_PREFIX) + RpcRaiseException(RPC_X_INVALID_TAG); + + pBuffer = HMETAFILE_UserUnmarshal(pFlags, pBuffer, &mfpict->hMF); + + GlobalUnlock(*phMfp); + } + + return pBuffer; +} + +/****************************************************************************** + * HMETAFILEPICT_UserFree [OLE32.@] + * + * Frees an unmarshaled metafile pict. + * + * PARAMS + * pFlags [I] Flags. See notes. + * phMfp [I] Metafile pict to free. + * + * RETURNS + * The end of the marshaled data in the buffer. + * + * NOTES + * Even though the function is documented to take a pointer to a ULONG in + * pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of + * which the first parameter is a ULONG. + * This function is only intended to be called by the RPC runtime. + */ +void __RPC_USER HMETAFILEPICT_UserFree(ULONG *pFlags, HMETAFILEPICT *phMfp) +{ + TRACE("(%s, &%p)\n", debugstr_user_flags(pFlags), *phMfp); + + if ((LOWORD(*pFlags) == MSHCTX_INPROC) && *phMfp) + { + METAFILEPICT *mfpict; + + mfpict = GlobalLock(*phMfp); + /* FIXME: raise an exception if mfpict is NULL? */ + + GlobalUnlock(*phMfp); + } +} + +/****************************************************************************** +* STGMEDIUM_UserSize [OLE32.@] +* +* Calculates the buffer size required to marshal an STGMEDIUM. +* +* PARAMS +* pFlags [I] Flags. See notes. +* StartingSize [I] Starting size of the buffer. This value is added on to +* the buffer size required for the clip format. +* pStgMedium [I] STGMEDIUM to size. +* +* RETURNS +* The buffer size required to marshal an STGMEDIUM plus the starting size. +* +* NOTES +* Even though the function is documented to take a pointer to a ULONG in +* pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which +* the first parameter is a ULONG. +* This function is only intended to be called by the RPC runtime. +*/ +ULONG __RPC_USER STGMEDIUM_UserSize(ULONG *pFlags, ULONG StartingSize, STGMEDIUM *pStgMedium) +{ + ULONG size = StartingSize; + + TRACE("(%s, %d, %p\n", debugstr_user_flags(pFlags), StartingSize, pStgMedium); ALIGN_LENGTH(size, 3); @@ -580,26 +1470,48 @@ unsigned long __RPC_USER STGMEDIUM_UserSize(unsigned long *pFlags, unsigned long break; case TYMED_HGLOBAL: TRACE("TYMED_HGLOBAL\n"); - size = HGLOBAL_UserSize(pFlags, size, &pStgMedium->u.hGlobal); + if (pStgMedium->u.hGlobal) + size = HGLOBAL_UserSize(pFlags, size, &pStgMedium->u.hGlobal); break; case TYMED_FILE: - FIXME("TYMED_FILE\n"); + TRACE("TYMED_FILE\n"); + if (pStgMedium->u.lpszFileName) + { + TRACE("file name is %s\n", debugstr_w(pStgMedium->u.lpszFileName)); + size += 3 * sizeof(DWORD) + + (strlenW(pStgMedium->u.lpszFileName) + 1) * sizeof(WCHAR); + } break; case TYMED_ISTREAM: - FIXME("TYMED_ISTREAM\n"); + TRACE("TYMED_ISTREAM\n"); + if (pStgMedium->u.pstm) + { + FIXME("not implemented for IStream %p\n", pStgMedium->u.pstm); + } break; case TYMED_ISTORAGE: - FIXME("TYMED_ISTORAGE\n"); + TRACE("TYMED_ISTORAGE\n"); + if (pStgMedium->u.pstg) + { + FIXME("not implemented for IStorage %p\n", pStgMedium->u.pstg); + } break; case TYMED_GDI: - FIXME("TYMED_GDI\n"); + TRACE("TYMED_GDI\n"); + if (pStgMedium->u.hBitmap) + { + FIXME("not implemented for GDI object %p\n", pStgMedium->u.hBitmap); + } break; case TYMED_MFPICT: - FIXME("TYMED_MFPICT\n"); + TRACE("TYMED_MFPICT\n"); + if (pStgMedium->u.hMetaFilePict) + size = HMETAFILEPICT_UserSize(pFlags, size, &pStgMedium->u.hMetaFilePict); break; case TYMED_ENHMF: TRACE("TYMED_ENHMF\n"); - size = HENHMETAFILE_UserSize(pFlags, size, &pStgMedium->u.hEnhMetaFile); + if (pStgMedium->u.hEnhMetaFile) + size = HENHMETAFILE_UserSize(pFlags, size, &pStgMedium->u.hEnhMetaFile); break; default: RaiseException(DV_E_TYMED, 0, 0, NULL); @@ -611,9 +1523,28 @@ unsigned long __RPC_USER STGMEDIUM_UserSize(unsigned long *pFlags, unsigned long return size; } -unsigned char * __RPC_USER STGMEDIUM_UserMarshal(unsigned long *pFlags, unsigned char *pBuffer, STGMEDIUM *pStgMedium) +/****************************************************************************** + * STGMEDIUM_UserMarshal [OLE32.@] + * + * Marshals a STGMEDIUM into a buffer. + * + * PARAMS + * pFlags [I] Flags. See notes. + * pBuffer [I] Buffer to marshal the clip format into. + * pCF [I] STGMEDIUM to marshal. + * + * RETURNS + * The end of the marshaled data in the buffer. + * + * NOTES + * Even though the function is documented to take a pointer to a ULONG in + * pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which + * the first parameter is a ULONG. + * This function is only intended to be called by the RPC runtime. + */ +unsigned char * __RPC_USER STGMEDIUM_UserMarshal(ULONG *pFlags, unsigned char *pBuffer, STGMEDIUM *pStgMedium) { - TRACE("("); dump_user_flags(pFlags); TRACE(", %p, %p\n", pBuffer, pStgMedium); + TRACE("(%s, %p, %p\n", debugstr_user_flags(pFlags), pBuffer, pStgMedium); ALIGN_POINTER(pBuffer, 3); @@ -634,26 +1565,59 @@ unsigned char * __RPC_USER STGMEDIUM_UserMarshal(unsigned long *pFlags, unsigned break; case TYMED_HGLOBAL: TRACE("TYMED_HGLOBAL\n"); - pBuffer = HGLOBAL_UserMarshal(pFlags, pBuffer, &pStgMedium->u.hGlobal); + if (pStgMedium->u.hGlobal) + pBuffer = HGLOBAL_UserMarshal(pFlags, pBuffer, &pStgMedium->u.hGlobal); break; case TYMED_FILE: - FIXME("TYMED_FILE\n"); + TRACE("TYMED_FILE\n"); + if (pStgMedium->u.lpszFileName) + { + DWORD len; + len = strlenW(pStgMedium->u.lpszFileName); + /* conformance */ + *(DWORD *)pBuffer = len + 1; + pBuffer += sizeof(DWORD); + /* offset */ + *(DWORD *)pBuffer = 0; + pBuffer += sizeof(DWORD); + /* variance */ + *(DWORD *)pBuffer = len + 1; + pBuffer += sizeof(DWORD); + + TRACE("file name is %s\n", debugstr_w(pStgMedium->u.lpszFileName)); + memcpy(pBuffer, pStgMedium->u.lpszFileName, (len + 1) * sizeof(WCHAR)); + } break; case TYMED_ISTREAM: - FIXME("TYMED_ISTREAM\n"); + TRACE("TYMED_ISTREAM\n"); + if (pStgMedium->u.pstm) + { + FIXME("not implemented for IStream %p\n", pStgMedium->u.pstm); + } break; case TYMED_ISTORAGE: - FIXME("TYMED_ISTORAGE\n"); + TRACE("TYMED_ISTORAGE\n"); + if (pStgMedium->u.pstg) + { + FIXME("not implemented for IStorage %p\n", pStgMedium->u.pstg); + } break; case TYMED_GDI: - FIXME("TYMED_GDI\n"); + TRACE("TYMED_GDI\n"); + if (pStgMedium->u.hBitmap) + { + FIXME("not implemented for GDI object %p\n", pStgMedium->u.hBitmap); + } break; case TYMED_MFPICT: - FIXME("TYMED_MFPICT\n"); + TRACE("TYMED_MFPICT\n"); + if (pStgMedium->u.hMetaFilePict) + pBuffer = HMETAFILEPICT_UserMarshal(pFlags, pBuffer, &pStgMedium->u.hMetaFilePict); break; case TYMED_ENHMF: TRACE("TYMED_ENHMF\n"); - pBuffer = HENHMETAFILE_UserMarshal(pFlags, pBuffer, &pStgMedium->u.hEnhMetaFile); + if (pStgMedium->u.hEnhMetaFile) + pBuffer = HENHMETAFILE_UserMarshal(pFlags, pBuffer, &pStgMedium->u.hEnhMetaFile); break; default: RaiseException(DV_E_TYMED, 0, 0, NULL); @@ -665,14 +1629,33 @@ unsigned char * __RPC_USER STGMEDIUM_UserMarshal(unsigned long *pFlags, unsigned return pBuffer; } -unsigned char * __RPC_USER STGMEDIUM_UserUnmarshal(unsigned long *pFlags, unsigned char *pBuffer, STGMEDIUM *pStgMedium) +/****************************************************************************** + * STGMEDIUM_UserUnmarshal [OLE32.@] + * + * Unmarshals a STGMEDIUM from a buffer. + * + * PARAMS + * pFlags [I] Flags. See notes. + * pBuffer [I] Buffer to marshal the clip format from. + * pStgMedium [O] Address that receive the unmarshaled STGMEDIUM. + * + * RETURNS + * The end of the marshaled data in the buffer. + * + * NOTES + * Even though the function is documented to take a pointer to an ULONG in + * pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which + * the first parameter is an ULONG. + * This function is only intended to be called by the RPC runtime. + */ +unsigned char * __RPC_USER STGMEDIUM_UserUnmarshal(ULONG *pFlags, unsigned char *pBuffer, STGMEDIUM *pStgMedium) { - DWORD content; + DWORD content = 0; DWORD releaseunk; ALIGN_POINTER(pBuffer, 3); - TRACE("("); dump_user_flags(pFlags); TRACE(", %p, %p\n", pBuffer, pStgMedium); + TRACE("(%s, %p, %p\n", debugstr_user_flags(pFlags), pBuffer, pStgMedium); pStgMedium->tymed = *(DWORD *)pBuffer; pBuffer += sizeof(DWORD); @@ -691,26 +1674,88 @@ unsigned char * __RPC_USER STGMEDIUM_UserUnmarshal(unsigned long *pFlags, unsign break; case TYMED_HGLOBAL: TRACE("TYMED_HGLOBAL\n"); - pBuffer = HGLOBAL_UserUnmarshal(pFlags, pBuffer, &pStgMedium->u.hGlobal); + if (content) + pBuffer = HGLOBAL_UserUnmarshal(pFlags, pBuffer, &pStgMedium->u.hGlobal); break; case TYMED_FILE: - FIXME("TYMED_FILE\n"); + TRACE("TYMED_FILE\n"); + if (content) + { + DWORD conformance; + DWORD variance; + conformance = *(DWORD *)pBuffer; + pBuffer += sizeof(DWORD); + if (*(DWORD *)pBuffer != 0) + { + ERR("invalid offset %d\n", *(DWORD *)pBuffer); + RpcRaiseException(RPC_S_INVALID_BOUND); + return NULL; + } + pBuffer += sizeof(DWORD); + variance = *(DWORD *)pBuffer; + pBuffer += sizeof(DWORD); + if (conformance != variance) + { + ERR("conformance (%d) and variance (%d) should be equal\n", + conformance, variance); + RpcRaiseException(RPC_S_INVALID_BOUND); + return NULL; + } + if (conformance > 0x7fffffff) + { + ERR("conformance 0x%x too large\n", conformance); + RpcRaiseException(RPC_S_INVALID_BOUND); + return NULL; + } + pStgMedium->u.lpszFileName = CoTaskMemAlloc(conformance * sizeof(WCHAR)); + if (!pStgMedium->u.lpszFileName) RpcRaiseException(ERROR_OUTOFMEMORY); + TRACE("unmarshalled file name is %s\n", debugstr_wn((const WCHAR *)pBuffer, variance)); + memcpy(pStgMedium->u.lpszFileName, pBuffer, variance * sizeof(WCHAR)); + pBuffer += variance * sizeof(WCHAR); + } + else + pStgMedium->u.lpszFileName = NULL; break; case TYMED_ISTREAM: - FIXME("TYMED_ISTREAM\n"); + TRACE("TYMED_ISTREAM\n"); + if (content) + { + FIXME("not implemented for IStream\n"); + } + else + pStgMedium->u.pstm = NULL; break; case TYMED_ISTORAGE: - FIXME("TYMED_ISTORAGE\n"); + TRACE("TYMED_ISTORAGE\n"); + if (content) + { + FIXME("not implemented for IStorage\n"); + } + else + pStgMedium->u.pstg = NULL; break; case TYMED_GDI: - FIXME("TYMED_GDI\n"); + TRACE("TYMED_GDI\n"); + if (content) + { + FIXME("not implemented for GDI object\n"); + } + else + pStgMedium->u.hBitmap = NULL; break; case TYMED_MFPICT: - FIXME("TYMED_MFPICT\n"); + TRACE("TYMED_MFPICT\n"); + if (content) + pBuffer = HMETAFILEPICT_UserUnmarshal(pFlags, pBuffer, &pStgMedium->u.hMetaFilePict); + else + pStgMedium->u.hMetaFilePict = NULL; break; case TYMED_ENHMF: TRACE("TYMED_ENHMF\n"); - pBuffer = HENHMETAFILE_UserUnmarshal(pFlags, pBuffer, &pStgMedium->u.hEnhMetaFile); + if (content) + pBuffer = HENHMETAFILE_UserUnmarshal(pFlags, pBuffer, &pStgMedium->u.hEnhMetaFile); + else + pStgMedium->u.hEnhMetaFile = NULL; break; default: RaiseException(DV_E_TYMED, 0, 0, NULL); @@ -723,78 +1768,96 @@ unsigned char * __RPC_USER STGMEDIUM_UserUnmarshal(unsigned long *pFlags, unsign return pBuffer; } -void __RPC_USER STGMEDIUM_UserFree(unsigned long *pFlags, STGMEDIUM *pStgMedium) +/****************************************************************************** + * STGMEDIUM_UserFree [OLE32.@] + * + * Frees an unmarshaled STGMEDIUM. + * + * PARAMS + * pFlags [I] Flags. See notes. + * pStgmedium [I] STGMEDIUM to free. + * + * RETURNS + * The end of the marshaled data in the buffer. + * + * NOTES + * Even though the function is documented to take a pointer to a ULONG in + * pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of + * which the first parameter is a ULONG. + * This function is only intended to be called by the RPC runtime. + */ +void __RPC_USER STGMEDIUM_UserFree(ULONG *pFlags, STGMEDIUM *pStgMedium) { - TRACE("("); dump_user_flags(pFlags); TRACE(", %p\n", pStgMedium); + TRACE("(%s, %p\n", debugstr_user_flags(pFlags), pStgMedium); ReleaseStgMedium(pStgMedium); } -unsigned long __RPC_USER ASYNC_STGMEDIUM_UserSize(unsigned long *pFlags, unsigned long StartingSize, ASYNC_STGMEDIUM *pStgMedium) +ULONG __RPC_USER ASYNC_STGMEDIUM_UserSize(ULONG *pFlags, ULONG StartingSize, ASYNC_STGMEDIUM *pStgMedium) { FIXME(":stub\n"); return StartingSize; } -unsigned char * __RPC_USER ASYNC_STGMEDIUM_UserMarshal( unsigned long *pFlags, unsigned char *pBuffer, ASYNC_STGMEDIUM *pStgMedium) +unsigned char * __RPC_USER ASYNC_STGMEDIUM_UserMarshal( ULONG *pFlags, unsigned char *pBuffer, ASYNC_STGMEDIUM *pStgMedium) { FIXME(":stub\n"); return pBuffer; } -unsigned char * __RPC_USER ASYNC_STGMEDIUM_UserUnmarshal(unsigned long *pFlags, unsigned char *pBuffer, ASYNC_STGMEDIUM *pStgMedium) +unsigned char * __RPC_USER ASYNC_STGMEDIUM_UserUnmarshal(ULONG *pFlags, unsigned char *pBuffer, ASYNC_STGMEDIUM *pStgMedium) { FIXME(":stub\n"); return pBuffer; } -void __RPC_USER ASYNC_STGMEDIUM_UserFree(unsigned long *pFlags, ASYNC_STGMEDIUM *pStgMedium) +void __RPC_USER ASYNC_STGMEDIUM_UserFree(ULONG *pFlags, ASYNC_STGMEDIUM *pStgMedium) { FIXME(":stub\n"); } -unsigned long __RPC_USER FLAG_STGMEDIUM_UserSize(unsigned long *pFlags, unsigned long StartingSize, FLAG_STGMEDIUM *pStgMedium) +ULONG __RPC_USER FLAG_STGMEDIUM_UserSize(ULONG *pFlags, ULONG StartingSize, FLAG_STGMEDIUM *pStgMedium) { FIXME(":stub\n"); return StartingSize; } -unsigned char * __RPC_USER FLAG_STGMEDIUM_UserMarshal( unsigned long *pFlags, unsigned char *pBuffer, FLAG_STGMEDIUM *pStgMedium) +unsigned char * __RPC_USER FLAG_STGMEDIUM_UserMarshal( ULONG *pFlags, unsigned char *pBuffer, FLAG_STGMEDIUM *pStgMedium) { FIXME(":stub\n"); return pBuffer; } -unsigned char * __RPC_USER FLAG_STGMEDIUM_UserUnmarshal(unsigned long *pFlags, unsigned char *pBuffer, FLAG_STGMEDIUM *pStgMedium) +unsigned char * __RPC_USER FLAG_STGMEDIUM_UserUnmarshal(ULONG *pFlags, unsigned char *pBuffer, FLAG_STGMEDIUM *pStgMedium) { FIXME(":stub\n"); return pBuffer; } -void __RPC_USER FLAG_STGMEDIUM_UserFree(unsigned long *pFlags, FLAG_STGMEDIUM *pStgMedium) +void __RPC_USER FLAG_STGMEDIUM_UserFree(ULONG *pFlags, FLAG_STGMEDIUM *pStgMedium) { FIXME(":stub\n"); } -unsigned long __RPC_USER SNB_UserSize(unsigned long *pFlags, unsigned long StartingSize, SNB *pSnb) +ULONG __RPC_USER SNB_UserSize(ULONG *pFlags, ULONG StartingSize, SNB *pSnb) { FIXME(":stub\n"); return StartingSize; } -unsigned char * __RPC_USER SNB_UserMarshal( unsigned long *pFlags, unsigned char *pBuffer, SNB *pSnb) +unsigned char * __RPC_USER SNB_UserMarshal( ULONG *pFlags, unsigned char *pBuffer, SNB *pSnb) { FIXME(":stub\n"); return pBuffer; } -unsigned char * __RPC_USER SNB_UserUnmarshal(unsigned long *pFlags, unsigned char *pBuffer, SNB *pSnb) +unsigned char * __RPC_USER SNB_UserUnmarshal(ULONG *pFlags, unsigned char *pBuffer, SNB *pSnb) { FIXME(":stub\n"); return pBuffer; } -void __RPC_USER SNB_UserFree(unsigned long *pFlags, SNB *pSnb) +void __RPC_USER SNB_UserFree(ULONG *pFlags, SNB *pSnb) { FIXME(":stub\n"); } diff --git a/reactos/dll/win32/ole32/version.rc b/reactos/dll/win32/ole32/version.rc index e498134858e..fb85adeba05 100644 --- a/reactos/dll/win32/ole32/version.rc +++ b/reactos/dll/win32/ole32/version.rc @@ -15,7 +15,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #define WINE_OLESELFREGISTER