mirror of
https://github.com/reactos/wine.git
synced 2024-11-29 14:40:56 +00:00
3328ad6eb9
As per the rules for memory in RPC, the memory pointer to by object will be used during unmarshalling and previously it was uninitialised. (Thanks to Dan Kegel and his Valgrind runs for reporting this.)
1658 lines
48 KiB
C
1658 lines
48 KiB
C
/*
|
|
* Monikers
|
|
*
|
|
* 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
|
|
* 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
|
|
*
|
|
* TODO:
|
|
* - IRunningObjectTable should work interprocess, but currently doesn't.
|
|
* Native (on Win2k at least) uses an undocumented RPC interface, IROT, to
|
|
* communicate with RPCSS which contains the table of marshalled data.
|
|
*/
|
|
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
|
|
#define COBJMACROS
|
|
|
|
#include "winerror.h"
|
|
#include "windef.h"
|
|
#include "winbase.h"
|
|
#include "winuser.h"
|
|
#include "wtypes.h"
|
|
#include "ole2.h"
|
|
|
|
#include "wine/list.h"
|
|
#include "wine/debug.h"
|
|
#include "wine/unicode.h"
|
|
#include "wine/exception.h"
|
|
|
|
#include "compobj_private.h"
|
|
#include "moniker.h"
|
|
#include "irot.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
|
|
|
|
static LONG WINAPI rpc_filter(EXCEPTION_POINTERS *__eptr)
|
|
{
|
|
switch (GetExceptionCode())
|
|
{
|
|
case EXCEPTION_ACCESS_VIOLATION:
|
|
case EXCEPTION_ILLEGAL_INSTRUCTION:
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
default:
|
|
return EXCEPTION_EXECUTE_HANDLER;
|
|
}
|
|
}
|
|
|
|
/* define the structure of the running object table elements */
|
|
struct rot_entry
|
|
{
|
|
struct list entry;
|
|
InterfaceData* object; /* marshaled running object*/
|
|
MonikerComparisonData* moniker_data; /* moniker comparison data that identifies this object */
|
|
DWORD cookie; /* cookie identifying this object */
|
|
FILETIME last_modified;
|
|
};
|
|
|
|
/* define the RunningObjectTableImpl structure */
|
|
typedef struct RunningObjectTableImpl
|
|
{
|
|
const IRunningObjectTableVtbl *lpVtbl;
|
|
LONG ref;
|
|
|
|
struct list rot; /* list of ROT entries */
|
|
CRITICAL_SECTION lock;
|
|
} RunningObjectTableImpl;
|
|
|
|
static RunningObjectTableImpl* runningObjectTableInstance = NULL;
|
|
static IrotHandle irot_handle;
|
|
|
|
/* define the EnumMonikerImpl structure */
|
|
typedef struct EnumMonikerImpl
|
|
{
|
|
const IEnumMonikerVtbl *lpVtbl;
|
|
LONG ref;
|
|
|
|
InterfaceList *moniker_list;
|
|
ULONG pos;
|
|
} EnumMonikerImpl;
|
|
|
|
|
|
/* IEnumMoniker Local functions*/
|
|
static HRESULT WINAPI EnumMonikerImpl_CreateEnumROTMoniker(InterfaceList *moniker_list,
|
|
ULONG pos, IEnumMoniker **ppenumMoniker);
|
|
|
|
static IrotHandle get_irot_handle(void)
|
|
{
|
|
if (!irot_handle)
|
|
{
|
|
RPC_STATUS status;
|
|
RPC_WSTR binding;
|
|
IrotHandle new_handle;
|
|
unsigned short ncacn_np[] = IROT_PROTSEQ;
|
|
unsigned short endpoint[] = IROT_ENDPOINT;
|
|
status = RpcStringBindingComposeW(NULL, ncacn_np, NULL, endpoint, NULL, &binding);
|
|
if (status == RPC_S_OK)
|
|
{
|
|
status = RpcBindingFromStringBindingW(binding, &new_handle);
|
|
RpcStringFreeW(&binding);
|
|
}
|
|
if (status != RPC_S_OK)
|
|
return NULL;
|
|
if (InterlockedCompareExchangePointer(&irot_handle, new_handle, NULL))
|
|
/* another thread beat us to it */
|
|
RpcBindingFree(&new_handle);
|
|
}
|
|
return irot_handle;
|
|
}
|
|
|
|
static BOOL start_rpcss(void)
|
|
{
|
|
PROCESS_INFORMATION pi;
|
|
STARTUPINFOW si;
|
|
static WCHAR cmd[6];
|
|
static const WCHAR rpcss[] = {'r','p','c','s','s',0};
|
|
BOOL rslt;
|
|
|
|
TRACE("\n");
|
|
|
|
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
|
|
ZeroMemory(&si, sizeof(STARTUPINFOA));
|
|
si.cb = sizeof(STARTUPINFOA);
|
|
|
|
memcpy(cmd, rpcss, sizeof(rpcss));
|
|
|
|
rslt = CreateProcessW(
|
|
NULL, /* executable */
|
|
cmd, /* command line */
|
|
NULL, /* process security attributes */
|
|
NULL, /* primary thread security attributes */
|
|
FALSE, /* inherit handles */
|
|
0, /* creation flags */
|
|
NULL, /* use parent's environment */
|
|
NULL, /* use parent's current directory */
|
|
&si, /* STARTUPINFO pointer */
|
|
&pi /* PROCESS_INFORMATION */
|
|
);
|
|
|
|
if (rslt)
|
|
{
|
|
CloseHandle(pi.hProcess);
|
|
CloseHandle(pi.hThread);
|
|
Sleep(100);
|
|
}
|
|
|
|
return rslt;
|
|
}
|
|
|
|
static HRESULT create_stream_on_mip_ro(const InterfaceData *mip, IStream **stream)
|
|
{
|
|
HGLOBAL hglobal = GlobalAlloc(0, mip->ulCntData);
|
|
void *pv = GlobalLock(hglobal);
|
|
memcpy(pv, mip->abData, mip->ulCntData);
|
|
GlobalUnlock(hglobal);
|
|
return CreateStreamOnHGlobal(hglobal, TRUE, stream);
|
|
}
|
|
|
|
static inline void rot_entry_delete(struct rot_entry *rot_entry)
|
|
{
|
|
if (rot_entry->cookie)
|
|
{
|
|
InterfaceData *object = NULL;
|
|
InterfaceData *moniker = NULL;
|
|
__TRY
|
|
{
|
|
IrotRevoke(get_irot_handle(), rot_entry->cookie, &object, &moniker);
|
|
}
|
|
__EXCEPT(rpc_filter)
|
|
{
|
|
}
|
|
__ENDTRY
|
|
MIDL_user_free(object);
|
|
if (moniker)
|
|
{
|
|
IStream *stream;
|
|
HRESULT hr;
|
|
hr = create_stream_on_mip_ro(moniker, &stream);
|
|
if (hr == S_OK)
|
|
{
|
|
CoReleaseMarshalData(stream);
|
|
IUnknown_Release(stream);
|
|
}
|
|
}
|
|
MIDL_user_free(moniker);
|
|
}
|
|
if (rot_entry->object)
|
|
{
|
|
IStream *stream;
|
|
HRESULT hr;
|
|
hr = create_stream_on_mip_ro(rot_entry->object, &stream);
|
|
if (hr == S_OK)
|
|
{
|
|
CoReleaseMarshalData(stream);
|
|
IUnknown_Release(stream);
|
|
}
|
|
}
|
|
HeapFree(GetProcessHeap(), 0, rot_entry->object);
|
|
HeapFree(GetProcessHeap(), 0, rot_entry->moniker_data);
|
|
HeapFree(GetProcessHeap(), 0, rot_entry);
|
|
}
|
|
|
|
/* moniker_data must be freed with HeapFree when no longer in use */
|
|
static HRESULT get_moniker_comparison_data(IMoniker *pMoniker, MonikerComparisonData **moniker_data)
|
|
{
|
|
HRESULT hr;
|
|
IROTData *pROTData = NULL;
|
|
hr = IMoniker_QueryInterface(pMoniker, &IID_IROTData, (void *)&pROTData);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ULONG size = MAX_COMPARISON_DATA;
|
|
*moniker_data = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(MonikerComparisonData, abData[size]));
|
|
if (!*moniker_data)
|
|
{
|
|
IROTData_Release(pROTData);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
hr = IROTData_GetComparisonData(pROTData, (*moniker_data)->abData, size, &size);
|
|
IROTData_Release(pROTData);
|
|
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;
|
|
}
|
|
else
|
|
{
|
|
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(MonikerComparisonData, 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));
|
|
CoTaskMemFree(pszDisplayName);
|
|
}
|
|
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
|
|
*/
|
|
static HRESULT WINAPI
|
|
RunningObjectTableImpl_QueryInterface(IRunningObjectTable* iface,
|
|
REFIID riid,void** ppvObject)
|
|
{
|
|
RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;
|
|
|
|
TRACE("(%p,%p,%p)\n",This,riid,ppvObject);
|
|
|
|
/* validate arguments */
|
|
|
|
if (ppvObject==0)
|
|
return E_INVALIDARG;
|
|
|
|
*ppvObject = 0;
|
|
|
|
if (IsEqualIID(&IID_IUnknown, riid) ||
|
|
IsEqualIID(&IID_IRunningObjectTable, riid))
|
|
*ppvObject = (IRunningObjectTable*)This;
|
|
|
|
if ((*ppvObject)==0)
|
|
return E_NOINTERFACE;
|
|
|
|
IRunningObjectTable_AddRef(iface);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* RunningObjectTable_AddRef
|
|
*/
|
|
static ULONG WINAPI
|
|
RunningObjectTableImpl_AddRef(IRunningObjectTable* iface)
|
|
{
|
|
RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;
|
|
|
|
TRACE("(%p)\n",This);
|
|
|
|
return InterlockedIncrement(&This->ref);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* RunningObjectTable_Initialize
|
|
*/
|
|
static HRESULT WINAPI
|
|
RunningObjectTableImpl_Destroy(void)
|
|
{
|
|
struct list *cursor, *cursor2;
|
|
IrotHandle old_handle;
|
|
|
|
TRACE("()\n");
|
|
|
|
if (runningObjectTableInstance==NULL)
|
|
return E_INVALIDARG;
|
|
|
|
/* free the ROT table memory */
|
|
LIST_FOR_EACH_SAFE(cursor, cursor2, &runningObjectTableInstance->rot)
|
|
{
|
|
struct rot_entry *rot_entry = LIST_ENTRY(cursor, struct rot_entry, entry);
|
|
list_remove(&rot_entry->entry);
|
|
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;
|
|
|
|
old_handle = irot_handle;
|
|
irot_handle = NULL;
|
|
if (old_handle)
|
|
RpcBindingFree(&old_handle);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* RunningObjectTable_Release
|
|
*/
|
|
static ULONG WINAPI
|
|
RunningObjectTableImpl_Release(IRunningObjectTable* iface)
|
|
{
|
|
RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;
|
|
ULONG ref;
|
|
|
|
TRACE("(%p)\n",This);
|
|
|
|
ref = InterlockedDecrement(&This->ref);
|
|
|
|
/* uninitialize ROT structure if there's no more references to it */
|
|
if (ref == 0)
|
|
{
|
|
struct list *cursor, *cursor2;
|
|
LIST_FOR_EACH_SAFE(cursor, cursor2, &This->rot)
|
|
{
|
|
struct rot_entry *rot_entry = LIST_ENTRY(cursor, struct rot_entry, entry);
|
|
list_remove(&rot_entry->entry);
|
|
rot_entry_delete(rot_entry);
|
|
}
|
|
/* RunningObjectTable data structure will be not destroyed here ! the destruction will be done only
|
|
* when RunningObjectTableImpl_UnInitialize function is called
|
|
*/
|
|
}
|
|
|
|
return ref;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* RunningObjectTable_Register
|
|
*
|
|
* PARAMS
|
|
* grfFlags [in] Registration options
|
|
* punkObject [in] the object being registered
|
|
* pmkObjectName [in] the moniker of the object being registered
|
|
* pdwRegister [in] the value identifying the registration
|
|
*/
|
|
static HRESULT WINAPI
|
|
RunningObjectTableImpl_Register(IRunningObjectTable* iface, DWORD grfFlags,
|
|
IUnknown *punkObject, IMoniker *pmkObjectName, DWORD *pdwRegister)
|
|
{
|
|
RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;
|
|
struct rot_entry *rot_entry;
|
|
HRESULT hr = S_OK;
|
|
IStream *pStream = NULL;
|
|
DWORD mshlflags;
|
|
IBindCtx *pbc;
|
|
InterfaceData *moniker = NULL;
|
|
|
|
TRACE("(%p,%d,%p,%p,%p)\n",This,grfFlags,punkObject,pmkObjectName,pdwRegister);
|
|
|
|
if (grfFlags & ~(ROTFLAGS_REGISTRATIONKEEPSALIVE|ROTFLAGS_ALLOWANYCLIENT))
|
|
{
|
|
ERR("Invalid grfFlags: 0x%08x\n", grfFlags & ~(ROTFLAGS_REGISTRATIONKEEPSALIVE|ROTFLAGS_ALLOWANYCLIENT));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (punkObject==NULL || pmkObjectName==NULL || pdwRegister==NULL)
|
|
return E_INVALIDARG;
|
|
|
|
rot_entry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*rot_entry));
|
|
if (!rot_entry)
|
|
return E_OUTOFMEMORY;
|
|
|
|
/* marshal object */
|
|
hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
|
|
if (hr != S_OK)
|
|
{
|
|
rot_entry_delete(rot_entry);
|
|
return hr;
|
|
}
|
|
mshlflags = (grfFlags & ROTFLAGS_REGISTRATIONKEEPSALIVE) ? MSHLFLAGS_TABLESTRONG : MSHLFLAGS_TABLEWEAK;
|
|
hr = CoMarshalInterface(pStream, &IID_IUnknown, punkObject, MSHCTX_LOCAL | MSHCTX_NOSHAREDMEM, NULL, mshlflags);
|
|
/* FIXME: a cleaner way would be to create an IStream class that writes
|
|
* directly to an MInterfacePointer */
|
|
if (hr == S_OK)
|
|
{
|
|
HGLOBAL hglobal;
|
|
hr = GetHGlobalFromStream(pStream, &hglobal);
|
|
if (hr == S_OK)
|
|
{
|
|
SIZE_T size = GlobalSize(hglobal);
|
|
const void *pv = GlobalLock(hglobal);
|
|
rot_entry->object = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(MInterfacePointer, abData[size]));
|
|
rot_entry->object->ulCntData = size;
|
|
memcpy(&rot_entry->object->abData, pv, size);
|
|
GlobalUnlock(hglobal);
|
|
}
|
|
}
|
|
IStream_Release(pStream);
|
|
if (hr != S_OK)
|
|
{
|
|
rot_entry_delete(rot_entry);
|
|
return hr;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
|
|
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);
|
|
/* FIXME: a cleaner way would be to create an IStream class that writes
|
|
* directly to an MInterfacePointer */
|
|
if (hr == S_OK)
|
|
{
|
|
HGLOBAL hglobal;
|
|
hr = GetHGlobalFromStream(pStream, &hglobal);
|
|
if (hr == S_OK)
|
|
{
|
|
SIZE_T size = GlobalSize(hglobal);
|
|
const void *pv = GlobalLock(hglobal);
|
|
moniker = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(InterfaceData, abData[size]));
|
|
moniker->ulCntData = size;
|
|
memcpy(&moniker->abData, pv, size);
|
|
GlobalUnlock(hglobal);
|
|
}
|
|
}
|
|
IStream_Release(pStream);
|
|
IMoniker_Release(pmkObjectName);
|
|
if (hr != S_OK)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, moniker);
|
|
rot_entry_delete(rot_entry);
|
|
return hr;
|
|
}
|
|
|
|
|
|
while (TRUE)
|
|
{
|
|
__TRY
|
|
{
|
|
hr = IrotRegister(get_irot_handle(), rot_entry->moniker_data, rot_entry->object, moniker, &rot_entry->last_modified, grfFlags, &rot_entry->cookie);
|
|
}
|
|
__EXCEPT(rpc_filter)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetExceptionCode());
|
|
}
|
|
__ENDTRY
|
|
if (hr == HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE))
|
|
{
|
|
if (start_rpcss())
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
HeapFree(GetProcessHeap(), 0, moniker);
|
|
if (FAILED(hr))
|
|
{
|
|
rot_entry_delete(rot_entry);
|
|
return hr;
|
|
}
|
|
|
|
/* gives a registration identifier to the registered object*/
|
|
*pdwRegister = rot_entry->cookie;
|
|
|
|
EnterCriticalSection(&This->lock);
|
|
list_add_tail(&This->rot, &rot_entry->entry);
|
|
LeaveCriticalSection(&This->lock);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* RunningObjectTable_Revoke
|
|
*
|
|
* PARAMS
|
|
* dwRegister [in] Value identifying registration to be revoked
|
|
*/
|
|
static HRESULT WINAPI
|
|
RunningObjectTableImpl_Revoke( IRunningObjectTable* iface, DWORD dwRegister)
|
|
{
|
|
RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;
|
|
struct rot_entry *rot_entry;
|
|
|
|
TRACE("(%p,%d)\n",This,dwRegister);
|
|
|
|
EnterCriticalSection(&This->lock);
|
|
LIST_FOR_EACH_ENTRY(rot_entry, &This->rot, struct rot_entry, entry)
|
|
{
|
|
if (rot_entry->cookie == dwRegister)
|
|
{
|
|
list_remove(&rot_entry->entry);
|
|
LeaveCriticalSection(&This->lock);
|
|
|
|
rot_entry_delete(rot_entry);
|
|
return S_OK;
|
|
}
|
|
}
|
|
LeaveCriticalSection(&This->lock);
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* RunningObjectTable_IsRunning
|
|
*
|
|
* PARAMS
|
|
* pmkObjectName [in] moniker of the object whose status is desired
|
|
*/
|
|
static HRESULT WINAPI
|
|
RunningObjectTableImpl_IsRunning( IRunningObjectTable* iface, IMoniker *pmkObjectName)
|
|
{
|
|
RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;
|
|
MonikerComparisonData *moniker_data;
|
|
HRESULT hr;
|
|
const struct rot_entry *rot_entry;
|
|
|
|
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;
|
|
|
|
hr = S_FALSE;
|
|
EnterCriticalSection(&This->lock);
|
|
LIST_FOR_EACH_ENTRY(rot_entry, &This->rot, const struct rot_entry, entry)
|
|
{
|
|
if ((rot_entry->moniker_data->ulCntData == moniker_data->ulCntData) &&
|
|
!memcmp(&moniker_data->abData, &rot_entry->moniker_data->abData, moniker_data->ulCntData))
|
|
{
|
|
hr = S_OK;
|
|
break;
|
|
}
|
|
}
|
|
LeaveCriticalSection(&This->lock);
|
|
|
|
if (hr == S_FALSE)
|
|
{
|
|
while (TRUE)
|
|
{
|
|
__TRY
|
|
{
|
|
hr = IrotIsRunning(get_irot_handle(), moniker_data);
|
|
}
|
|
__EXCEPT(rpc_filter)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetExceptionCode());
|
|
}
|
|
__ENDTRY
|
|
if (hr == HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE))
|
|
{
|
|
if (start_rpcss())
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
HeapFree(GetProcessHeap(), 0, moniker_data);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* RunningObjectTable_GetObject
|
|
*
|
|
* PARAMS
|
|
* pmkObjectName [in] Pointer to the moniker on the object
|
|
* ppunkObject [out] variable that receives the IUnknown interface pointer
|
|
*/
|
|
static HRESULT WINAPI
|
|
RunningObjectTableImpl_GetObject( IRunningObjectTable* iface,
|
|
IMoniker *pmkObjectName, IUnknown **ppunkObject)
|
|
{
|
|
RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;
|
|
MonikerComparisonData *moniker_data;
|
|
InterfaceData *object = NULL;
|
|
IrotCookie cookie;
|
|
HRESULT hr;
|
|
struct rot_entry *rot_entry;
|
|
|
|
TRACE("(%p,%p,%p)\n",This,pmkObjectName,ppunkObject);
|
|
|
|
if (ppunkObject == NULL)
|
|
return E_POINTER;
|
|
|
|
*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;
|
|
|
|
EnterCriticalSection(&This->lock);
|
|
LIST_FOR_EACH_ENTRY(rot_entry, &This->rot, struct rot_entry, entry)
|
|
{
|
|
if ((rot_entry->moniker_data->ulCntData == 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);
|
|
if (hr == S_OK)
|
|
{
|
|
hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)ppunkObject);
|
|
IStream_Release(pStream);
|
|
}
|
|
|
|
LeaveCriticalSection(&This->lock);
|
|
HeapFree(GetProcessHeap(), 0, moniker_data);
|
|
|
|
return hr;
|
|
}
|
|
}
|
|
LeaveCriticalSection(&This->lock);
|
|
|
|
TRACE("moniker unavailable locally, calling SCM\n");
|
|
|
|
while (TRUE)
|
|
{
|
|
__TRY
|
|
{
|
|
hr = IrotGetObject(get_irot_handle(), moniker_data, &object, &cookie);
|
|
}
|
|
__EXCEPT(rpc_filter)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetExceptionCode());
|
|
}
|
|
__ENDTRY
|
|
if (hr == HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE))
|
|
{
|
|
if (start_rpcss())
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IStream *pStream;
|
|
hr = create_stream_on_mip_ro(object, &pStream);
|
|
if (hr == S_OK)
|
|
{
|
|
hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)ppunkObject);
|
|
IStream_Release(pStream);
|
|
}
|
|
}
|
|
else
|
|
WARN("Moniker unavailable, IrotGetObject returned 0x%08x\n", hr);
|
|
|
|
HeapFree(GetProcessHeap(), 0, moniker_data);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* RunningObjectTable_NoteChangeTime
|
|
*
|
|
* PARAMS
|
|
* dwRegister [in] Value identifying registration being updated
|
|
* pfiletime [in] Pointer to structure containing object's last change time
|
|
*/
|
|
static HRESULT WINAPI
|
|
RunningObjectTableImpl_NoteChangeTime(IRunningObjectTable* iface,
|
|
DWORD dwRegister, FILETIME *pfiletime)
|
|
{
|
|
RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;
|
|
struct rot_entry *rot_entry;
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
TRACE("(%p,%d,%p)\n",This,dwRegister,pfiletime);
|
|
|
|
EnterCriticalSection(&This->lock);
|
|
LIST_FOR_EACH_ENTRY(rot_entry, &This->rot, struct rot_entry, entry)
|
|
{
|
|
if (rot_entry->cookie == dwRegister)
|
|
{
|
|
rot_entry->last_modified = *pfiletime;
|
|
LeaveCriticalSection(&This->lock);
|
|
|
|
while (TRUE)
|
|
{
|
|
__TRY
|
|
{
|
|
hr = IrotNoteChangeTime(get_irot_handle(), dwRegister, pfiletime);
|
|
}
|
|
__EXCEPT(rpc_filter)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetExceptionCode());
|
|
}
|
|
__ENDTRY
|
|
if (hr == HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE))
|
|
{
|
|
if (start_rpcss())
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
LeaveCriticalSection(&This->lock);
|
|
|
|
TRACE("-- 0x08%x\n", hr);
|
|
return hr;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* RunningObjectTable_GetTimeOfLastChange
|
|
*
|
|
* PARAMS
|
|
* pmkObjectName [in] moniker of the object whose status is desired
|
|
* pfiletime [out] structure that receives object's last change time
|
|
*/
|
|
static HRESULT WINAPI
|
|
RunningObjectTableImpl_GetTimeOfLastChange(IRunningObjectTable* iface,
|
|
IMoniker *pmkObjectName, FILETIME *pfiletime)
|
|
{
|
|
HRESULT hr = MK_E_UNAVAILABLE;
|
|
RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;
|
|
MonikerComparisonData *moniker_data;
|
|
const struct rot_entry *rot_entry;
|
|
|
|
TRACE("(%p,%p,%p)\n",This,pmkObjectName,pfiletime);
|
|
|
|
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;
|
|
|
|
hr = MK_E_UNAVAILABLE;
|
|
|
|
EnterCriticalSection(&This->lock);
|
|
LIST_FOR_EACH_ENTRY(rot_entry, &This->rot, const struct rot_entry, entry)
|
|
{
|
|
if ((rot_entry->moniker_data->ulCntData == moniker_data->ulCntData) &&
|
|
!memcmp(&moniker_data->abData, &rot_entry->moniker_data->abData, moniker_data->ulCntData))
|
|
{
|
|
*pfiletime = rot_entry->last_modified;
|
|
hr = S_OK;
|
|
break;
|
|
}
|
|
}
|
|
LeaveCriticalSection(&This->lock);
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
while (TRUE)
|
|
{
|
|
__TRY
|
|
{
|
|
hr = IrotGetTimeOfLastChange(get_irot_handle(), moniker_data, pfiletime);
|
|
}
|
|
__EXCEPT(rpc_filter)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetExceptionCode());
|
|
}
|
|
__ENDTRY
|
|
if (hr == HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE))
|
|
{
|
|
if (start_rpcss())
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
HeapFree(GetProcessHeap(), 0, moniker_data);
|
|
|
|
TRACE("-- 0x%08x\n", hr);
|
|
return hr;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* RunningObjectTable_EnumRunning
|
|
*
|
|
* PARAMS
|
|
* ppenumMoniker [out] receives the IEnumMoniker interface pointer
|
|
*/
|
|
static HRESULT WINAPI
|
|
RunningObjectTableImpl_EnumRunning(IRunningObjectTable* iface,
|
|
IEnumMoniker **ppenumMoniker)
|
|
{
|
|
RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;
|
|
InterfaceList *interface_list = NULL;
|
|
HRESULT hr;
|
|
|
|
TRACE("(%p, %p)\n", This, ppenumMoniker);
|
|
|
|
*ppenumMoniker = NULL;
|
|
|
|
while (TRUE)
|
|
{
|
|
__TRY
|
|
{
|
|
hr = IrotEnumRunning(get_irot_handle(), &interface_list);
|
|
}
|
|
__EXCEPT(rpc_filter)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetExceptionCode());
|
|
}
|
|
__ENDTRY
|
|
if (hr == HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE))
|
|
{
|
|
if (start_rpcss())
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
hr = EnumMonikerImpl_CreateEnumROTMoniker(interface_list,
|
|
0, ppenumMoniker);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/* Virtual function table for the IRunningObjectTable class. */
|
|
static const IRunningObjectTableVtbl VT_RunningObjectTableImpl =
|
|
{
|
|
RunningObjectTableImpl_QueryInterface,
|
|
RunningObjectTableImpl_AddRef,
|
|
RunningObjectTableImpl_Release,
|
|
RunningObjectTableImpl_Register,
|
|
RunningObjectTableImpl_Revoke,
|
|
RunningObjectTableImpl_IsRunning,
|
|
RunningObjectTableImpl_GetObject,
|
|
RunningObjectTableImpl_NoteChangeTime,
|
|
RunningObjectTableImpl_GetTimeOfLastChange,
|
|
RunningObjectTableImpl_EnumRunning
|
|
};
|
|
|
|
/***********************************************************************
|
|
* RunningObjectTable_Initialize
|
|
*/
|
|
HRESULT WINAPI RunningObjectTableImpl_Initialize(void)
|
|
{
|
|
TRACE("\n");
|
|
|
|
/* create the unique instance of the RunningObjectTableImpl structure */
|
|
runningObjectTableInstance = HeapAlloc(GetProcessHeap(), 0, sizeof(RunningObjectTableImpl));
|
|
|
|
if (!runningObjectTableInstance)
|
|
return E_OUTOFMEMORY;
|
|
|
|
/* initialize the virtual table function */
|
|
runningObjectTableInstance->lpVtbl = &VT_RunningObjectTableImpl;
|
|
|
|
/* the initial reference is set to "1" ! because if set to "0" it will be not practis when */
|
|
/* the ROT referred many times not in the same time (all the objects in the ROT will */
|
|
/* be removed every time the ROT is removed ) */
|
|
runningObjectTableInstance->ref = 1;
|
|
|
|
list_init(&runningObjectTableInstance->rot);
|
|
InitializeCriticalSection(&runningObjectTableInstance->lock);
|
|
DEBUG_SET_CRITSEC_NAME(&runningObjectTableInstance->lock, "RunningObjectTableImpl.lock");
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* RunningObjectTable_UnInitialize
|
|
*/
|
|
HRESULT WINAPI RunningObjectTableImpl_UnInitialize(void)
|
|
{
|
|
TRACE("\n");
|
|
|
|
if (runningObjectTableInstance==NULL)
|
|
return E_POINTER;
|
|
|
|
RunningObjectTableImpl_Release((IRunningObjectTable*)runningObjectTableInstance);
|
|
|
|
RunningObjectTableImpl_Destroy();
|
|
|
|
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<nFileTypes;i++)
|
|
|
|
for(i=0;j<nPatternsForType;j++){
|
|
|
|
PATTERN pat;
|
|
HANDLE hFile;
|
|
|
|
pat=ReadPatternFromRegistry(i,j);
|
|
hFile=CreateFileW(filePathName,,,,,,hFile);
|
|
SetFilePosition(hFile,pat.offset);
|
|
ReadFile(hFile,buf,pat.size,&r,NULL);
|
|
if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
|
|
|
|
*pclsid=ReadCLSIDFromRegistry(i);
|
|
return S_OK;
|
|
}
|
|
}
|
|
*/
|
|
|
|
/* if the above strategies fail then search for the extension key in the registry */
|
|
|
|
/* get the last element (absolute file) in the path name */
|
|
nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
|
|
absFile=pathDec[nbElm-1];
|
|
|
|
/* failed if the path represente a directory and not an absolute file name*/
|
|
if (!lstrcmpW(absFile, bkslashW))
|
|
return MK_E_INVALIDEXTENSION;
|
|
|
|
/* get the extension of the file */
|
|
extension = NULL;
|
|
length=lstrlenW(absFile);
|
|
for(i = length-1; (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
|
|
*/
|
|
static HRESULT WINAPI EnumMonikerImpl_QueryInterface(IEnumMoniker* iface,REFIID riid,void** ppvObject)
|
|
{
|
|
EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
|
|
|
|
TRACE("(%p,%p,%p)\n",This,riid,ppvObject);
|
|
|
|
/* validate arguments */
|
|
if (ppvObject == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
*ppvObject = NULL;
|
|
|
|
if (IsEqualIID(&IID_IUnknown, riid))
|
|
*ppvObject = (IEnumMoniker*)This;
|
|
else
|
|
if (IsEqualIID(&IID_IEnumMoniker, riid))
|
|
*ppvObject = (IEnumMoniker*)This;
|
|
|
|
if ((*ppvObject)==NULL)
|
|
return E_NOINTERFACE;
|
|
|
|
IEnumMoniker_AddRef(iface);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* EnumMoniker_AddRef
|
|
*/
|
|
static ULONG WINAPI EnumMonikerImpl_AddRef(IEnumMoniker* iface)
|
|
{
|
|
EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
|
|
|
|
TRACE("(%p)\n",This);
|
|
|
|
return InterlockedIncrement(&This->ref);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* EnumMoniker_release
|
|
*/
|
|
static ULONG WINAPI EnumMonikerImpl_Release(IEnumMoniker* iface)
|
|
{
|
|
EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
|
|
ULONG ref;
|
|
|
|
TRACE("(%p)\n",This);
|
|
|
|
ref = InterlockedDecrement(&This->ref);
|
|
|
|
/* uninitialize rot structure if there's no more reference to it*/
|
|
if (ref == 0)
|
|
{
|
|
ULONG i;
|
|
|
|
TRACE("(%p) Deleting\n",This);
|
|
|
|
for (i = 0; i < This->moniker_list->size; i++)
|
|
HeapFree(GetProcessHeap(), 0, This->moniker_list->interfaces[i]);
|
|
HeapFree(GetProcessHeap(), 0, This->moniker_list);
|
|
HeapFree(GetProcessHeap(), 0, This);
|
|
}
|
|
|
|
return ref;
|
|
}
|
|
/***********************************************************************
|
|
* EnmumMoniker_Next
|
|
*/
|
|
static HRESULT WINAPI EnumMonikerImpl_Next(IEnumMoniker* iface, ULONG celt, IMoniker** rgelt, ULONG * pceltFetched)
|
|
{
|
|
ULONG i;
|
|
EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
|
|
HRESULT hr = S_OK;
|
|
|
|
TRACE("(%p) TabCurrentPos %d Tablastindx %d\n", This, This->pos, This->moniker_list->size);
|
|
|
|
/* retrieve the requested number of moniker from the current position */
|
|
for(i = 0; (This->pos < This->moniker_list->size) && (i < celt); i++)
|
|
{
|
|
IStream *stream;
|
|
hr = create_stream_on_mip_ro(This->moniker_list->interfaces[This->pos++], &stream);
|
|
if (hr != S_OK) break;
|
|
hr = CoUnmarshalInterface(stream, &IID_IMoniker, (void **)&rgelt[i]);
|
|
IStream_Release(stream);
|
|
if (hr != S_OK) break;
|
|
}
|
|
|
|
if (pceltFetched != NULL)
|
|
*pceltFetched= i;
|
|
|
|
if (hr != S_OK)
|
|
return hr;
|
|
|
|
if (i == celt)
|
|
return S_OK;
|
|
else
|
|
return S_FALSE;
|
|
|
|
}
|
|
|
|
/***********************************************************************
|
|
* EnmumMoniker_Skip
|
|
*/
|
|
static HRESULT WINAPI EnumMonikerImpl_Skip(IEnumMoniker* iface, ULONG celt)
|
|
{
|
|
EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
|
|
|
|
TRACE("(%p)\n",This);
|
|
|
|
if (This->pos + celt >= This->moniker_list->size)
|
|
return S_FALSE;
|
|
|
|
This->pos += celt;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* EnmumMoniker_Reset
|
|
*/
|
|
static HRESULT WINAPI EnumMonikerImpl_Reset(IEnumMoniker* iface)
|
|
{
|
|
EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
|
|
|
|
This->pos = 0; /* set back to start of list */
|
|
|
|
TRACE("(%p)\n",This);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* EnmumMoniker_Clone
|
|
*/
|
|
static HRESULT WINAPI EnumMonikerImpl_Clone(IEnumMoniker* iface, IEnumMoniker ** ppenum)
|
|
{
|
|
EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
|
|
InterfaceList *moniker_list;
|
|
ULONG i;
|
|
|
|
TRACE("(%p)\n",This);
|
|
|
|
*ppenum = NULL;
|
|
|
|
moniker_list = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(InterfaceList, interfaces[This->moniker_list->size]));
|
|
if (!moniker_list)
|
|
return E_OUTOFMEMORY;
|
|
|
|
moniker_list->size = This->moniker_list->size;
|
|
for (i = 0; i < This->moniker_list->size; i++)
|
|
{
|
|
SIZE_T size = FIELD_OFFSET(InterfaceData, abData[This->moniker_list->interfaces[i]->ulCntData]);
|
|
moniker_list->interfaces[i] = HeapAlloc(GetProcessHeap(), 0, size);
|
|
if (!moniker_list->interfaces[i])
|
|
{
|
|
ULONG end = i;
|
|
for (i = 0; i < end; i++)
|
|
HeapFree(GetProcessHeap(), 0, moniker_list->interfaces[i]);
|
|
HeapFree(GetProcessHeap(), 0, moniker_list);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
memcpy(moniker_list->interfaces[i], This->moniker_list->interfaces[i], size);
|
|
}
|
|
|
|
/* copy the enum structure */
|
|
return EnumMonikerImpl_CreateEnumROTMoniker(moniker_list, This->pos, ppenum);
|
|
}
|
|
|
|
/* Virtual function table for the IEnumMoniker class. */
|
|
static const IEnumMonikerVtbl VT_EnumMonikerImpl =
|
|
{
|
|
EnumMonikerImpl_QueryInterface,
|
|
EnumMonikerImpl_AddRef,
|
|
EnumMonikerImpl_Release,
|
|
EnumMonikerImpl_Next,
|
|
EnumMonikerImpl_Skip,
|
|
EnumMonikerImpl_Reset,
|
|
EnumMonikerImpl_Clone
|
|
};
|
|
|
|
/***********************************************************************
|
|
* EnumMonikerImpl_CreateEnumROTMoniker
|
|
* Used by EnumRunning to create the structure and EnumClone
|
|
* to copy the structure
|
|
*/
|
|
static HRESULT WINAPI EnumMonikerImpl_CreateEnumROTMoniker(InterfaceList *moniker_list,
|
|
ULONG current_pos,
|
|
IEnumMoniker **ppenumMoniker)
|
|
{
|
|
EnumMonikerImpl* This = NULL;
|
|
|
|
if (!ppenumMoniker)
|
|
return E_INVALIDARG;
|
|
|
|
This = HeapAlloc(GetProcessHeap(), 0, sizeof(EnumMonikerImpl));
|
|
if (!This) return E_OUTOFMEMORY;
|
|
|
|
TRACE("(%p)\n", This);
|
|
|
|
/* initialize the virtual table function */
|
|
This->lpVtbl = &VT_EnumMonikerImpl;
|
|
|
|
/* the initial reference is set to "1" */
|
|
This->ref = 1; /* set the ref count to one */
|
|
This->pos = current_pos; /* Set the list start posn */
|
|
This->moniker_list = moniker_list;
|
|
|
|
*ppenumMoniker = (IEnumMoniker*)This;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/* Shared implementation of moniker marshaler based on saving and loading of
|
|
* monikers */
|
|
|
|
typedef struct MonikerMarshal
|
|
{
|
|
const IUnknownVtbl *lpVtbl;
|
|
const IMarshalVtbl *lpVtblMarshal;
|
|
|
|
LONG ref;
|
|
IMoniker *moniker;
|
|
} MonikerMarshal;
|
|
|
|
static inline MonikerMarshal *impl_from_IMarshal( IMarshal *iface )
|
|
{
|
|
return (MonikerMarshal *)((char*)iface - FIELD_OFFSET(MonikerMarshal, lpVtblMarshal));
|
|
}
|
|
|
|
static HRESULT WINAPI MonikerMarshalInner_QueryInterface(IUnknown *iface, REFIID riid, LPVOID *ppv)
|
|
{
|
|
MonikerMarshal *This = (MonikerMarshal *)iface;
|
|
TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
|
|
*ppv = NULL;
|
|
if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IMarshal, riid))
|
|
{
|
|
*ppv = &This->lpVtblMarshal;
|
|
IUnknown_AddRef((IUnknown *)&This->lpVtblMarshal);
|
|
return S_OK;
|
|
}
|
|
FIXME("No interface for %s\n", debugstr_guid(riid));
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
static ULONG WINAPI MonikerMarshalInner_AddRef(IUnknown *iface)
|
|
{
|
|
MonikerMarshal *This = (MonikerMarshal *)iface;
|
|
return InterlockedIncrement(&This->ref);
|
|
}
|
|
|
|
static ULONG WINAPI MonikerMarshalInner_Release(IUnknown *iface)
|
|
{
|
|
MonikerMarshal *This = (MonikerMarshal *)iface;
|
|
ULONG ref = InterlockedDecrement(&This->ref);
|
|
|
|
if (!ref) HeapFree(GetProcessHeap(), 0, This);
|
|
return ref;
|
|
}
|
|
|
|
static const IUnknownVtbl VT_MonikerMarshalInner =
|
|
{
|
|
MonikerMarshalInner_QueryInterface,
|
|
MonikerMarshalInner_AddRef,
|
|
MonikerMarshalInner_Release
|
|
};
|
|
|
|
static HRESULT WINAPI MonikerMarshal_QueryInterface(IMarshal *iface, REFIID riid, LPVOID *ppv)
|
|
{
|
|
MonikerMarshal *This = impl_from_IMarshal(iface);
|
|
return IMoniker_QueryInterface(This->moniker, riid, ppv);
|
|
}
|
|
|
|
static ULONG WINAPI MonikerMarshal_AddRef(IMarshal *iface)
|
|
{
|
|
MonikerMarshal *This = impl_from_IMarshal(iface);
|
|
return IMoniker_AddRef(This->moniker);
|
|
}
|
|
|
|
static ULONG WINAPI MonikerMarshal_Release(IMarshal *iface)
|
|
{
|
|
MonikerMarshal *This = impl_from_IMarshal(iface);
|
|
return IMoniker_Release(This->moniker);
|
|
}
|
|
|
|
static HRESULT WINAPI MonikerMarshal_GetUnmarshalClass(
|
|
LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext,
|
|
void* pvDestContext, DWORD mshlflags, CLSID* pCid)
|
|
{
|
|
MonikerMarshal *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->moniker, pCid);
|
|
}
|
|
|
|
static HRESULT WINAPI MonikerMarshal_GetMarshalSizeMax(
|
|
LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext,
|
|
void* pvDestContext, DWORD mshlflags, DWORD* pSize)
|
|
{
|
|
MonikerMarshal *This = impl_from_IMarshal(iface);
|
|
HRESULT hr;
|
|
ULARGE_INTEGER size;
|
|
|
|
TRACE("(%s, %p, %x, %p, %x, %p)\n", debugstr_guid(riid), pv,
|
|
dwDestContext, pvDestContext, mshlflags, pSize);
|
|
|
|
hr = IMoniker_GetSizeMax(This->moniker, &size);
|
|
if (hr == S_OK)
|
|
*pSize = (DWORD)size.QuadPart;
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI MonikerMarshal_MarshalInterface(LPMARSHAL iface, IStream *pStm,
|
|
REFIID riid, void* pv, DWORD dwDestContext,
|
|
void* pvDestContext, DWORD mshlflags)
|
|
{
|
|
MonikerMarshal *This = impl_from_IMarshal(iface);
|
|
|
|
TRACE("(%p, %s, %p, %x, %p, %x)\n", pStm, debugstr_guid(riid), pv,
|
|
dwDestContext, pvDestContext, mshlflags);
|
|
|
|
return IMoniker_Save(This->moniker, pStm, FALSE);
|
|
}
|
|
|
|
static HRESULT WINAPI MonikerMarshal_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, void **ppv)
|
|
{
|
|
MonikerMarshal *This = impl_from_IMarshal(iface);
|
|
HRESULT hr;
|
|
|
|
TRACE("(%p, %s, %p)\n", pStm, debugstr_guid(riid), ppv);
|
|
|
|
hr = IMoniker_Load(This->moniker, pStm);
|
|
if (hr == S_OK)
|
|
hr = IMoniker_QueryInterface(This->moniker, riid, ppv);
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI MonikerMarshal_ReleaseMarshalData(LPMARSHAL iface, IStream *pStm)
|
|
{
|
|
TRACE("()\n");
|
|
/* can't release a state-based marshal as nothing on server side to
|
|
* release */
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI MonikerMarshal_DisconnectObject(LPMARSHAL iface, DWORD dwReserved)
|
|
{
|
|
TRACE("()\n");
|
|
/* can't disconnect a state-based marshal as nothing on server side to
|
|
* disconnect from */
|
|
return S_OK;
|
|
}
|
|
|
|
static const IMarshalVtbl VT_MonikerMarshal =
|
|
{
|
|
MonikerMarshal_QueryInterface,
|
|
MonikerMarshal_AddRef,
|
|
MonikerMarshal_Release,
|
|
MonikerMarshal_GetUnmarshalClass,
|
|
MonikerMarshal_GetMarshalSizeMax,
|
|
MonikerMarshal_MarshalInterface,
|
|
MonikerMarshal_UnmarshalInterface,
|
|
MonikerMarshal_ReleaseMarshalData,
|
|
MonikerMarshal_DisconnectObject
|
|
};
|
|
|
|
HRESULT MonikerMarshal_Create(IMoniker *inner, IUnknown **outer)
|
|
{
|
|
MonikerMarshal *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
|
|
if (!This) return E_OUTOFMEMORY;
|
|
|
|
This->lpVtbl = &VT_MonikerMarshalInner;
|
|
This->lpVtblMarshal = &VT_MonikerMarshal;
|
|
This->ref = 1;
|
|
This->moniker = inner;
|
|
|
|
*outer = (IUnknown *)&This->lpVtbl;
|
|
return S_OK;
|
|
}
|
|
|
|
void * __RPC_USER MIDL_user_allocate(size_t size)
|
|
{
|
|
return HeapAlloc(GetProcessHeap(), 0, size);
|
|
}
|
|
|
|
void __RPC_USER MIDL_user_free(void *p)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, p);
|
|
}
|