/* * 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 #include #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; 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= 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); }