From: Christoph von Wittich Date: Mon, 24 Aug 2009 10:51:15 +0000 (+0000) Subject: sync ole32 with wine 1.1.28 X-Git-Tag: ReactOS-0.3.11~983 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=eb6554487025b3feab88d40308861c507b89b435 sync ole32 with wine 1.1.28 svn path=/trunk/; revision=42905 --- diff --git a/reactos/dll/win32/ole32/clipboard.c b/reactos/dll/win32/ole32/clipboard.c index 1e72ec21217..7f19d1638a4 100644 --- a/reactos/dll/win32/ole32/clipboard.c +++ b/reactos/dll/win32/ole32/clipboard.c @@ -744,6 +744,30 @@ static HRESULT get_data_from_global(IDataObject *data, FORMATETC *fmt, HGLOBAL * return hr; } +static HRESULT get_data_from_enhmetafile(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem) +{ + HENHMETAFILE copy; + HRESULT hr; + FORMATETC mem_fmt; + STGMEDIUM med; + + *mem = NULL; + + mem_fmt = *fmt; + mem_fmt.tymed = TYMED_ENHMF; + + hr = IDataObject_GetData(data, &mem_fmt, &med); + if(FAILED(hr)) return hr; + + copy = CopyEnhMetaFileW(med.u.hEnhMetaFile, NULL); + if(copy) *mem = (HGLOBAL)copy; + else hr = E_FAIL; + + ReleaseStgMedium(&med); + + return hr; +} + /*********************************************************************** * render_format * @@ -773,6 +797,10 @@ static HRESULT render_format(IDataObject *data, LPFORMATETC fmt) { hr = get_data_from_global(data, fmt, &clip_data); } + else if(fmt->tymed & TYMED_ENHMF) + { + hr = get_data_from_enhmetafile(data, fmt, &clip_data); + } else { FIXME("Unhandled tymed %x\n", fmt->tymed); @@ -997,8 +1025,7 @@ static HRESULT get_priv_data(ole_priv_data **data) { char buf[100]; GetClipboardFormatNameA(cf, buf, sizeof(buf)); - TRACE("\tcf %04x %s\n", cf, buf); - ; + TRACE("cf %04x %s\n", cf, buf); } TRACE("count %d\n", count); size += count * sizeof(ret->entries[0]); @@ -1106,6 +1133,22 @@ static HRESULT get_stgmed_for_storage(HGLOBAL h, STGMEDIUM *med) return hr; } +/************************************************************************ + * get_stgmed_for_emf + * + * Returns a stg medium with an enhanced metafile based on the handle + */ +static HRESULT get_stgmed_for_emf(HENHMETAFILE hemf, STGMEDIUM *med) +{ + med->pUnkForRelease = NULL; + med->tymed = TYMED_NULL; + + med->u.hEnhMetaFile = CopyEnhMetaFileW(hemf, NULL); + if(!med->u.hEnhMetaFile) return E_OUTOFMEMORY; + med->tymed = TYMED_ENHMF; + return S_OK; +} + static inline BOOL string_off_equal(const DVTARGETDEVICE *t1, WORD off1, const DVTARGETDEVICE *t2, WORD off2) { const WCHAR *str1, *str2; @@ -1195,6 +1238,8 @@ static HRESULT WINAPI snapshot_GetData(IDataObject *iface, FORMATETC *fmt, hr = get_stgmed_for_global(h, med); else if(mask & TYMED_ISTREAM) hr = get_stgmed_for_stream(h, med); + else if(mask & TYMED_ENHMF) + hr = get_stgmed_for_emf((HENHMETAFILE)h, med); else { FIXME("Unhandled tymed - mask %x req tymed %x\n", mask, fmt->tymed); diff --git a/reactos/dll/win32/ole32/comcat.c b/reactos/dll/win32/ole32/comcat.c index cee1ebb7d68..b8060bdefca 100644 --- a/reactos/dll/win32/ole32/comcat.c +++ b/reactos/dll/win32/ole32/comcat.c @@ -278,7 +278,7 @@ static HRESULT WINAPI COMCAT_ICatRegister_QueryInterface( LPVOID *ppvObj) { ComCatMgrImpl *This = (ComCatMgrImpl *)iface; - TRACE("\n\tIID:\t%s\n",debugstr_guid(riid)); + TRACE("%s\n",debugstr_guid(riid)); if (ppvObj == NULL) return E_POINTER; @@ -515,7 +515,7 @@ static HRESULT WINAPI COMCAT_ICatInformation_GetCategoryDesc( HKEY key; HRESULT res; - TRACE("\n\tCATID:\t%s\n\tLCID:\t%X\n",debugstr_guid(rcatid), lcid); + TRACE("CATID: %s LCID: %x\n",debugstr_guid(rcatid), lcid); if (rcatid == NULL || ppszDesc == NULL) return E_INVALIDARG; @@ -596,12 +596,12 @@ static HRESULT WINAPI COMCAT_ICatInformation_IsClassOfCategories( if (WINE_TRACE_ON(ole)) { ULONG count; - TRACE("\n\tCLSID:\t%s\n\tImplemented %u\n",debugstr_guid(rclsid),cImplemented); + TRACE("CLSID: %s Implemented %u\n",debugstr_guid(rclsid),cImplemented); for (count = 0; count < cImplemented; ++count) - TRACE("\t\t%s\n",debugstr_guid(&rgcatidImpl[count])); - TRACE("\tRequired %u\n",cRequired); + TRACE(" %s\n",debugstr_guid(&rgcatidImpl[count])); + TRACE("Required %u\n",cRequired); for (count = 0; count < cRequired; ++count) - TRACE("\t\t%s\n",debugstr_guid(&rgcatidReq[count])); + TRACE(" %s\n",debugstr_guid(&rgcatidReq[count])); } if ((cImplemented && rgcatidImpl == NULL) || @@ -637,7 +637,7 @@ static HRESULT WINAPI COMCAT_ICatInformation_EnumImplCategoriesOfClass( 'n', 't', 'e', 'd', ' ', 'C', 'a', 't', 'e', 'g', 'o', 'r', 'i', 'e', 's', 0 }; - TRACE("\n\tCLSID:\t%s\n",debugstr_guid(rclsid)); + TRACE("%s\n",debugstr_guid(rclsid)); if (rclsid == NULL || ppenumCATID == NULL) return E_POINTER; @@ -659,7 +659,7 @@ static HRESULT WINAPI COMCAT_ICatInformation_EnumReqCategoriesOfClass( 'd', ' ', 'C', 'a', 't', 'e', 'g', 'o', 'r', 'i', 'e', 's', 0 }; - TRACE("\n\tCLSID:\t%s\n",debugstr_guid(rclsid)); + TRACE("%s\n",debugstr_guid(rclsid)); if (rclsid == NULL || ppenumCATID == NULL) return E_POINTER; @@ -719,7 +719,7 @@ static HRESULT WINAPI COMCAT_IClassFactory_QueryInterface( REFIID riid, LPVOID *ppvObj) { - TRACE("\n\tIID:\t%s\n",debugstr_guid(riid)); + TRACE("%s\n",debugstr_guid(riid)); if (ppvObj == NULL) return E_POINTER; @@ -760,7 +760,7 @@ static HRESULT WINAPI COMCAT_IClassFactory_CreateInstance( LPVOID *ppvObj) { HRESULT res; - TRACE("\n\tIID:\t%s\n",debugstr_guid(riid)); + TRACE("%s\n",debugstr_guid(riid)); if (ppvObj == NULL) return E_POINTER; @@ -834,7 +834,7 @@ static HRESULT WINAPI COMCAT_IEnumCATEGORYINFO_QueryInterface( REFIID riid, LPVOID *ppvObj) { - TRACE("\n\tIID:\t%s\n",debugstr_guid(riid)); + TRACE("%s\n",debugstr_guid(riid)); if (ppvObj == NULL) return E_POINTER; @@ -1017,7 +1017,7 @@ static HRESULT WINAPI COMCAT_CLSID_IEnumGUID_QueryInterface( REFIID riid, LPVOID *ppvObj) { - TRACE("\n\tIID:\t%s\n",debugstr_guid(riid)); + TRACE("%s\n",debugstr_guid(riid)); if (ppvObj == NULL) return E_POINTER; @@ -1203,7 +1203,7 @@ static HRESULT WINAPI COMCAT_CATID_IEnumGUID_QueryInterface( REFIID riid, LPVOID *ppvObj) { - TRACE("\n\tIID:\t%s\n",debugstr_guid(riid)); + TRACE("%s\n",debugstr_guid(riid)); if (ppvObj == NULL) return E_POINTER; diff --git a/reactos/dll/win32/ole32/compobj.c b/reactos/dll/win32/ole32/compobj.c index 154c18d67df..b2013cfbfa3 100644 --- a/reactos/dll/win32/ole32/compobj.c +++ b/reactos/dll/win32/ole32/compobj.c @@ -52,6 +52,7 @@ #include "winerror.h" #include "winreg.h" #include "winuser.h" +#define USE_COM_CONTEXT_DEF #include "objbase.h" #include "ole2.h" #include "ole2ver.h" @@ -71,11 +72,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole); * This section defines variables internal to the COM module. */ -static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid, - DWORD dwClsContext, LPUNKNOWN* ppUnk); -static void COM_RevokeAllClasses(const struct apartment *apt); -static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll, REFCLSID rclsid, REFIID riid, BOOL hostifnecessary, void **ppv); - static APARTMENT *MTA; /* protected by csApartment */ static APARTMENT *MainApartment; /* the first STA apartment */ static struct list apts = LIST_INIT( apts ); /* protected by csApartment */ @@ -182,61 +178,147 @@ struct apartment_loaded_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, - BOOL apartment_threaded, - REFCLSID rclsid, REFIID riid, void **ppv); -static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay); -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, BOOL free_entry); +/***************************************************************************** + * This section contains OpenDllList implementation + */ -static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen); +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_InitProcess( void ) +/* caller must ensure that library_name is not already in the open dll list */ +static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret) { - WNDCLASSW wclass; + OpenDll *entry; + int len; + HRESULT hr = S_OK; + HANDLE hLibrary; + DllCanUnloadNowFunc DllCanUnloadNow; + DllGetClassObjectFunc DllGetClassObject; - /* Dispatching to the correct thread in an apartment is done through - * window messages rather than RPC transports. When an interface is - * marshalled into another apartment in the same process, a window of the - * following class is created. The *caller* of CoMarshalInterface (i.e., the - * application) is responsible for pumping the message loop in that thread. - * The WM_USER messages which point to the RPCs are then dispatched to - * apartment_wndproc by the user's code from the apartment in which the - * interface was unmarshalled. - */ - memset(&wclass, 0, sizeof(wclass)); - wclass.lpfnWndProc = apartment_wndproc; - wclass.hInstance = hProxyDll; - wclass.lpszClassName = wszAptWinClass; - RegisterClassW(&wclass); + 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 = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow"); + /* Note: failing to find DllCanUnloadNow is not a failure */ + DllGetClassObject = (void *)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 ); + + *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 + { + HeapFree(GetProcessHeap(), 0, entry); + hr = E_OUTOFMEMORY; + FreeLibrary(hLibrary); + } + *ret = entry; + } + + LeaveCriticalSection( &csOpenDllList ); + + return hr; } -static void COMPOBJ_UninitProcess( void ) +/* pass FALSE for free_entry to release a reference without destroying the + * entry if it reaches zero or TRUE otherwise */ +static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry) { - UnregisterClassW(wszAptWinClass, hProxyDll); + if (!InterlockedDecrement(&entry->refs) && free_entry) + { + 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); + } } -static void COM_TlsDestroy(void) +/* frees memory associated with active dll list */ +static void COMPOBJ_DllList_Free(void) { - struct oletls *info = NtCurrentTeb()->ReservedForOle; - if (info) + OpenDll *entry, *cursor2; + EnterCriticalSection(&csOpenDllList); + LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry) { - if (info->apt) apartment_release(info->apt); - if (info->errorinfo) IErrorInfo_Release(info->errorinfo); - if (info->state) IUnknown_Release(info->state); - if (info->spy) IUnknown_Release(info->spy); - HeapFree(GetProcessHeap(), 0, info); - NtCurrentTeb()->ReservedForOle = NULL; + list_remove(&entry->entry); + + HeapFree(GetProcessHeap(), 0, entry->library_name); + HeapFree(GetProcessHeap(), 0, entry); } + LeaveCriticalSection(&csOpenDllList); } /****************************************************************************** * Manage apartments. */ +static DWORD apartment_addref(struct apartment *apt) +{ + DWORD refs = InterlockedIncrement(&apt->refs); + TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1); + return refs; +} + /* allocates memory and fills in the necessary fields for a new apartment * object. must be called inside apartment cs */ static APARTMENT *apartment_construct(DWORD model) @@ -335,11 +417,146 @@ static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model) return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED)); } -DWORD apartment_addref(struct apartment *apt) +static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass) { - DWORD refs = InterlockedIncrement(&apt->refs); - TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1); - return refs; + list_remove(&curClass->entry); + + if (curClass->runContext & CLSCTX_LOCAL_SERVER) + RPC_StopLocalServer(curClass->RpcRegistration); + + /* + * Release the reference to the class object. + */ + IUnknown_Release(curClass->classObject); + + if (curClass->pMarshaledData) + { + LARGE_INTEGER zero; + memset(&zero, 0, sizeof(zero)); + IStream_Seek(curClass->pMarshaledData, zero, STREAM_SEEK_SET, NULL); + CoReleaseMarshalData(curClass->pMarshaledData); + IStream_Release(curClass->pMarshaledData); + } + + HeapFree(GetProcessHeap(), 0, curClass); +} + +static void COM_RevokeAllClasses(const struct apartment *apt) +{ + RegisteredClass *curClass, *cursor; + + EnterCriticalSection( &csRegisteredClassList ); + + LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry) + { + if (curClass->apartment_id == apt->oxid) + COM_RevokeRegisteredClassObject(curClass); + } + + LeaveCriticalSection( &csRegisteredClassList ); +} + +/*********************************************************************** + * CoRevokeClassObject [OLE32.@] + * + * Removes a class object from the class registry. + * + * PARAMS + * dwRegister [I] Cookie returned from CoRegisterClassObject(). + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT code. + * + * NOTES + * Must be called from the same apartment that called CoRegisterClassObject(), + * otherwise it will fail with RPC_E_WRONG_THREAD. + * + * SEE ALSO + * CoRegisterClassObject + */ +HRESULT WINAPI CoRevokeClassObject( + DWORD dwRegister) +{ + HRESULT hr = E_INVALIDARG; + RegisteredClass *curClass; + APARTMENT *apt; + + TRACE("(%08x)\n",dwRegister); + + apt = COM_CurrentApt(); + if (!apt) + { + ERR("COM was not initialized\n"); + return CO_E_NOTINITIALIZED; + } + + EnterCriticalSection( &csRegisteredClassList ); + + LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry) + { + /* + * Check if we have a match on the cookie. + */ + if (curClass->dwCookie == dwRegister) + { + if (curClass->apartment_id == apt->oxid) + { + COM_RevokeRegisteredClassObject(curClass); + hr = S_OK; + } + else + { + ERR("called from wrong apartment, should be called from %s\n", + wine_dbgstr_longlong(curClass->apartment_id)); + hr = RPC_E_WRONG_THREAD; + } + break; + } + } + + LeaveCriticalSection( &csRegisteredClassList ); + + return hr; +} + +/* frees unused libraries loaded by apartment_getclassobject by calling the + * DLL's DllCanUnloadNow entry point */ +static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay) +{ + 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)) + { + DWORD real_delay = delay; + + if (real_delay == INFINITE) + { + /* DLLs that return multi-threaded objects aren't unloaded + * straight away to cope for programs that have races between + * last object destruction and threads in the DLLs that haven't + * finished, despite DllCanUnloadNow returning S_OK */ + if (entry->multi_threaded) + real_delay = 10 * 60 * 1000; /* 10 minutes */ + else + real_delay = 0; + } + + if (!real_delay || (entry->unload_time && (entry->unload_time < GetTickCount()))) + { + list_remove(&entry->entry); + COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE); + HeapFree(GetProcessHeap(), 0, entry); + } + else + entry->unload_time = GetTickCount() + real_delay; + } + else if (entry->unload_time) + entry->unload_time = 0; + } + LeaveCriticalSection(&apt->cs); } DWORD apartment_release(struct apartment *apt) @@ -502,21 +719,121 @@ static APARTMENT *apartment_find_multi_threaded(void) APARTMENT *result = NULL; struct list *cursor; - EnterCriticalSection(&csApartment); + EnterCriticalSection(&csApartment); + + LIST_FOR_EACH( cursor, &apts ) + { + struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry ); + if (apt->multi_threaded) + { + result = apt; + apartment_addref(result); + break; + } + } + + LeaveCriticalSection(&csApartment); + return result; +} + +/* gets the specified class object by loading the appropriate DLL, if + * necessary and calls the DllGetClassObject function for the DLL */ +static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath, + BOOL apartment_threaded, + REFCLSID rclsid, REFIID riid, void **ppv) +{ + static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0}; + HRESULT hr = S_OK; + BOOL found = FALSE; + struct apartment_loaded_dll *apartment_loaded_dll; + + if (!strcmpiW(dllpath, wszOle32)) + { + /* we don't need to control the lifetime of this dll, so use the local + * implementation of DllGetClassObject directly */ + TRACE("calling ole32!DllGetClassObject\n"); + hr = DllGetClassObject(rclsid, riid, ppv); + + if (hr != S_OK) + ERR("DllGetClassObject returned error 0x%08x\n", hr); + + return hr; + } + + 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)) + { + apartment_loaded_dll->unload_time = 0; + apartment_loaded_dll->multi_threaded = FALSE; + 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)) + { + /* one component being multi-threaded overrides any number of + * apartment-threaded components */ + if (!apartment_threaded) + apartment_loaded_dll->multi_threaded = TRUE; + + 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; +} - LIST_FOR_EACH( cursor, &apts ) - { - struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry ); - if (apt->multi_threaded) - { - result = apt; - apartment_addref(result); - break; - } - } +/*********************************************************************** + * COM_RegReadPath [internal] + * + * Reads a registry value and expands it when necessary + */ +static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen) +{ + DWORD ret; + HKEY key; + DWORD keytype; + WCHAR src[MAX_PATH]; + DWORD dwLength = dstlen * sizeof(WCHAR); - LeaveCriticalSection(&csApartment); - return result; + 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)) ret = ERROR_MORE_DATA; + } else { + lstrcpynW(dst, src, dstlen); + } + } + RegCloseKey (key); + } + return ret; } struct host_object_params @@ -781,246 +1098,44 @@ void apartment_joinmta(void) COM_CurrentInfo()->apt = MTA; } -/* gets the specified class object by loading the appropriate DLL, if - * necessary and calls the DllGetClassObject function for the DLL */ -static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath, - BOOL apartment_threaded, - REFCLSID rclsid, REFIID riid, void **ppv) -{ - static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0}; - HRESULT hr = S_OK; - BOOL found = FALSE; - struct apartment_loaded_dll *apartment_loaded_dll; - - if (!strcmpiW(dllpath, wszOle32)) - { - /* we don't need to control the lifetime of this dll, so use the local - * implementation of DllGetClassObject directly */ - TRACE("calling ole32!DllGetClassObject\n"); - hr = DllGetClassObject(rclsid, riid, ppv); - - if (hr != S_OK) - ERR("DllGetClassObject returned error 0x%08x\n", hr); - - return hr; - } - - 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)) - { - apartment_loaded_dll->unload_time = 0; - apartment_loaded_dll->multi_threaded = FALSE; - 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)) - { - /* one component being multi-threaded overrides any number of - * apartment-threaded components */ - if (!apartment_threaded) - apartment_loaded_dll->multi_threaded = TRUE; - - 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; -} - -/* frees unused libraries loaded by apartment_getclassobject by calling the - * DLL's DllCanUnloadNow entry point */ -static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay) -{ - 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)) - { - DWORD real_delay = delay; - - if (real_delay == INFINITE) - { - /* DLLs that return multi-threaded objects aren't unloaded - * straight away to cope for programs that have races between - * last object destruction and threads in the DLLs that haven't - * finished, despite DllCanUnloadNow returning S_OK */ - if (entry->multi_threaded) - real_delay = 10 * 60 * 1000; /* 10 minutes */ - else - real_delay = 0; - } - - if (!real_delay || (entry->unload_time && (entry->unload_time < GetTickCount()))) - { - list_remove(&entry->entry); - COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE); - HeapFree(GetProcessHeap(), 0, entry); - } - else - entry->unload_time = GetTickCount() + real_delay; - } - else if (entry->unload_time) - entry->unload_time = 0; - } - 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) +static void COMPOBJ_InitProcess( void ) { - 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 = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow"); - /* Note: failing to find DllCanUnloadNow is not a failure */ - DllGetClassObject = (void *)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 ); - - *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 - { - HeapFree(GetProcessHeap(), 0, entry); - hr = E_OUTOFMEMORY; - FreeLibrary(hLibrary); - } - *ret = entry; - } - - LeaveCriticalSection( &csOpenDllList ); - - return hr; -} + WNDCLASSW wclass; -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; + /* Dispatching to the correct thread in an apartment is done through + * window messages rather than RPC transports. When an interface is + * marshalled into another apartment in the same process, a window of the + * following class is created. The *caller* of CoMarshalInterface (i.e., the + * application) is responsible for pumping the message loop in that thread. + * The WM_USER messages which point to the RPCs are then dispatched to + * apartment_wndproc by the user's code from the apartment in which the + * interface was unmarshalled. + */ + memset(&wclass, 0, sizeof(wclass)); + wclass.lpfnWndProc = apartment_wndproc; + wclass.hInstance = hProxyDll; + wclass.lpszClassName = wszAptWinClass; + RegisterClassW(&wclass); } -/* pass FALSE for free_entry to release a reference without destroying the - * entry if it reaches zero or TRUE otherwise */ -static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry) +static void COMPOBJ_UninitProcess( void ) { - if (!InterlockedDecrement(&entry->refs) && free_entry) - { - 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); - } + UnregisterClassW(wszAptWinClass, hProxyDll); } -/* frees memory associated with active dll list */ -static void COMPOBJ_DllList_Free(void) +static void COM_TlsDestroy(void) { - OpenDll *entry, *cursor2; - EnterCriticalSection(&csOpenDllList); - LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry) + struct oletls *info = NtCurrentTeb()->ReservedForOle; + if (info) { - list_remove(&entry->entry); - - HeapFree(GetProcessHeap(), 0, entry->library_name); - HeapFree(GetProcessHeap(), 0, entry); + if (info->apt) apartment_release(info->apt); + if (info->errorinfo) IErrorInfo_Release(info->errorinfo); + if (info->state) IUnknown_Release(info->state); + if (info->spy) IUnknown_Release(info->spy); + if (info->context_token) IObjContext_Release(info->context_token); + HeapFree(GetProcessHeap(), 0, info); + NtCurrentTeb()->ReservedForOle = NULL; } - LeaveCriticalSection(&csOpenDllList); } /****************************************************************************** @@ -2031,135 +2146,6 @@ HRESULT WINAPI CoRegisterClassObject( return S_OK; } -static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass) -{ - list_remove(&curClass->entry); - - if (curClass->runContext & CLSCTX_LOCAL_SERVER) - RPC_StopLocalServer(curClass->RpcRegistration); - - /* - * Release the reference to the class object. - */ - IUnknown_Release(curClass->classObject); - - if (curClass->pMarshaledData) - { - LARGE_INTEGER zero; - memset(&zero, 0, sizeof(zero)); - IStream_Seek(curClass->pMarshaledData, zero, STREAM_SEEK_SET, NULL); - CoReleaseMarshalData(curClass->pMarshaledData); - IStream_Release(curClass->pMarshaledData); - } - - HeapFree(GetProcessHeap(), 0, curClass); -} - -static void COM_RevokeAllClasses(const struct apartment *apt) -{ - RegisteredClass *curClass, *cursor; - - EnterCriticalSection( &csRegisteredClassList ); - - LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry) - { - if (curClass->apartment_id == apt->oxid) - COM_RevokeRegisteredClassObject(curClass); - } - - LeaveCriticalSection( &csRegisteredClassList ); -} - -/*********************************************************************** - * CoRevokeClassObject [OLE32.@] - * - * Removes a class object from the class registry. - * - * PARAMS - * dwRegister [I] Cookie returned from CoRegisterClassObject(). - * - * RETURNS - * Success: S_OK. - * Failure: HRESULT code. - * - * NOTES - * Must be called from the same apartment that called CoRegisterClassObject(), - * otherwise it will fail with RPC_E_WRONG_THREAD. - * - * SEE ALSO - * CoRegisterClassObject - */ -HRESULT WINAPI CoRevokeClassObject( - DWORD dwRegister) -{ - HRESULT hr = E_INVALIDARG; - RegisteredClass *curClass; - APARTMENT *apt; - - TRACE("(%08x)\n",dwRegister); - - apt = COM_CurrentApt(); - if (!apt) - { - ERR("COM was not initialized\n"); - return CO_E_NOTINITIALIZED; - } - - EnterCriticalSection( &csRegisteredClassList ); - - LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry) - { - /* - * Check if we have a match on the cookie. - */ - if (curClass->dwCookie == dwRegister) - { - if (curClass->apartment_id == apt->oxid) - { - COM_RevokeRegisteredClassObject(curClass); - hr = S_OK; - } - else - { - ERR("called from wrong apartment, should be called from %s\n", - wine_dbgstr_longlong(curClass->apartment_id)); - hr = RPC_E_WRONG_THREAD; - } - break; - } - } - - LeaveCriticalSection( &csRegisteredClassList ); - - return hr; -} - -/*********************************************************************** - * COM_RegReadPath [internal] - * - * Reads a registry value and expands it when necessary - */ -static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen) -{ - DWORD ret; - HKEY key; - DWORD keytype; - WCHAR src[MAX_PATH]; - DWORD dwLength = dstlen * sizeof(WCHAR); - - 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)) ret = ERROR_MORE_DATA; - } else { - lstrcpynW(dst, src, dstlen); - } - } - RegCloseKey (key); - } - 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}; @@ -2265,7 +2251,7 @@ HRESULT WINAPI CoGetClassObject( APARTMENT *apt; BOOL release_apt = FALSE; - TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid)); + TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid)); if (!ppv) return E_INVALIDARG; @@ -2283,8 +2269,8 @@ HRESULT WINAPI CoGetClassObject( } if (pServerInfo) { - FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName)); - FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo); + FIXME("pServerInfo->name=%s pAuthInfo=%p\n", + debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo); } /* @@ -3748,6 +3734,7 @@ typedef struct Context { const IComThreadingInfoVtbl *lpVtbl; const IContextCallbackVtbl *lpCallbackVtbl; + const IObjContextVtbl *lpContextVtbl; LONG refs; APTTYPE apttype; } Context; @@ -3762,6 +3749,11 @@ static inline Context *impl_from_IContextCallback( IContextCallback *iface ) return (Context *)((char*)iface - FIELD_OFFSET(Context, lpCallbackVtbl)); } +static inline Context *impl_from_IObjContext( IObjContext *iface ) +{ + return (Context *)((char*)iface - FIELD_OFFSET(Context, lpContextVtbl)); +} + static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv) { *ppv = NULL; @@ -3770,10 +3762,15 @@ static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv) IsEqualIID(riid, &IID_IUnknown)) { *ppv = &iface->lpVtbl; - } else if (IsEqualIID(riid, &IID_IContextCallback)) + } + else if (IsEqualIID(riid, &IID_IContextCallback)) { *ppv = &iface->lpCallbackVtbl; } + else if (IsEqualIID(riid, &IID_IObjContext)) + { + *ppv = &iface->lpContextVtbl; + } if (*ppv) { @@ -3903,6 +3900,115 @@ static const IContextCallbackVtbl Context_Callback_Vtbl = Context_CC_ContextCallback }; +static HRESULT WINAPI Context_OC_QueryInterface(IObjContext *iface, REFIID riid, LPVOID *ppv) +{ + Context *This = impl_from_IObjContext(iface); + return Context_QueryInterface(This, riid, ppv); +} + +static ULONG WINAPI Context_OC_AddRef(IObjContext *iface) +{ + Context *This = impl_from_IObjContext(iface); + return Context_AddRef(This); +} + +static ULONG WINAPI Context_OC_Release(IObjContext *iface) +{ + Context *This = impl_from_IObjContext(iface); + return Context_Release(This); +} + +static HRESULT WINAPI Context_OC_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk) +{ + Context *This = impl_from_IObjContext(iface); + + FIXME("(%p/%p)->(%s, %x, %p)\n", This, iface, debugstr_guid(propid), flags, punk); + return E_NOTIMPL; +} + +static HRESULT WINAPI Context_OC_RemoveProperty(IObjContext *iface, REFGUID propid) +{ + Context *This = impl_from_IObjContext(iface); + + FIXME("(%p/%p)->(%s)\n", This, iface, debugstr_guid(propid)); + return E_NOTIMPL; +} + +static HRESULT WINAPI Context_OC_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk) +{ + Context *This = impl_from_IObjContext(iface); + + FIXME("(%p/%p)->(%s, %p, %p)\n", This, iface, debugstr_guid(propid), flags, punk); + return E_NOTIMPL; +} + +static HRESULT WINAPI Context_OC_EnumContextProps(IObjContext *iface, IEnumContextProps **props) +{ + Context *This = impl_from_IObjContext(iface); + + FIXME("(%p/%p)->(%p)\n", This, iface, props); + return E_NOTIMPL; +} + +static void WINAPI Context_OC_Reserved1(IObjContext *iface) +{ + Context *This = impl_from_IObjContext(iface); + FIXME("(%p/%p)\n", This, iface); +} + +static void WINAPI Context_OC_Reserved2(IObjContext *iface) +{ + Context *This = impl_from_IObjContext(iface); + FIXME("(%p/%p)\n", This, iface); +} + +static void WINAPI Context_OC_Reserved3(IObjContext *iface) +{ + Context *This = impl_from_IObjContext(iface); + FIXME("(%p/%p)\n", This, iface); +} + +static void WINAPI Context_OC_Reserved4(IObjContext *iface) +{ + Context *This = impl_from_IObjContext(iface); + FIXME("(%p/%p)\n", This, iface); +} + +static void WINAPI Context_OC_Reserved5(IObjContext *iface) +{ + Context *This = impl_from_IObjContext(iface); + FIXME("(%p/%p)\n", This, iface); +} + +static void WINAPI Context_OC_Reserved6(IObjContext *iface) +{ + Context *This = impl_from_IObjContext(iface); + FIXME("(%p/%p)\n", This, iface); +} + +static void WINAPI Context_OC_Reserved7(IObjContext *iface) +{ + Context *This = impl_from_IObjContext(iface); + FIXME("(%p/%p)\n", This, iface); +} + +static const IObjContextVtbl Context_Object_Vtbl = +{ + Context_OC_QueryInterface, + Context_OC_AddRef, + Context_OC_Release, + Context_OC_SetProperty, + Context_OC_RemoveProperty, + Context_OC_GetProperty, + Context_OC_EnumContextProps, + Context_OC_Reserved1, + Context_OC_Reserved2, + Context_OC_Reserved3, + Context_OC_Reserved4, + Context_OC_Reserved5, + Context_OC_Reserved6, + Context_OC_Reserved7 +}; /*********************************************************************** * CoGetObjectContext [OLE32.@] @@ -3928,8 +4034,12 @@ HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv) *ppv = NULL; if (!apt) { - ERR("apartment not initialised\n"); - return CO_E_NOTINITIALIZED; + if (!(apt = apartment_find_multi_threaded())) + { + ERR("apartment not initialised\n"); + return CO_E_NOTINITIALIZED; + } + apartment_release(apt); } context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context)); @@ -3938,6 +4048,7 @@ HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv) context->lpVtbl = &Context_Threading_Vtbl; context->lpCallbackVtbl = &Context_Callback_Vtbl; + context->lpContextVtbl = &Context_Object_Vtbl; context->refs = 1; if (apt->multi_threaded) context->apttype = APTTYPE_MTA; @@ -3959,12 +4070,40 @@ HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv) HRESULT WINAPI CoGetContextToken( ULONG_PTR *token ) { struct oletls *info = COM_CurrentInfo(); - static int calls; - if(!(calls++)) FIXME( "stub\n" ); + + TRACE("(%p)\n", token); + if (!info) return E_OUTOFMEMORY; - if (token) *token = info->context_token; - return E_NOTIMPL; + + if (!info->apt) + { + APARTMENT *apt; + if (!(apt = apartment_find_multi_threaded())) + { + ERR("apartment not initialised\n"); + return CO_E_NOTINITIALIZED; + } + apartment_release(apt); + } + + if (!token) + return E_POINTER; + + if (!info->context_token) + { + HRESULT hr; + IObjContext *ctx; + + hr = CoGetObjectContext(&IID_IObjContext, (void **)&ctx); + if (FAILED(hr)) return hr; + info->context_token = ctx; + } + + *token = (ULONG_PTR)info->context_token; + TRACE("apt->context_token=%p\n", info->context_token); + + return S_OK; } diff --git a/reactos/dll/win32/ole32/compobj_private.h b/reactos/dll/win32/ole32/compobj_private.h index a7c6dfa67ce..fb059349f8c 100644 --- a/reactos/dll/win32/ole32/compobj_private.h +++ b/reactos/dll/win32/ole32/compobj_private.h @@ -183,7 +183,7 @@ struct oletls LONG pending_call_count_client; /* number of client calls pending */ LONG pending_call_count_server; /* number of server calls pending */ DWORD unknown; - ULONG_PTR context_token; /* (+38h on x86) */ + IObjContext *context_token; /* (+38h on x86) */ IUnknown *call_state; /* current call context (+3Ch on x86) */ DWORD unknown2[46]; IUnknown *cancel_object; /* cancel object set by CoSetCancelObject (+F8h on x86) */ @@ -203,7 +203,6 @@ HRESULT FTMarshalCF_Create(REFIID riid, LPVOID *ppv); /* Stub Manager */ -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, BOOL tableweak); @@ -253,7 +252,6 @@ void OLEDD_UnInitialize(void); APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref); APARTMENT *apartment_findfromtid(DWORD tid); -DWORD apartment_addref(struct apartment *apt); DWORD apartment_release(struct apartment *apt); HRESULT apartment_disconnectproxies(struct apartment *apt); void apartment_disconnectobject(struct apartment *apt, void *object); diff --git a/reactos/dll/win32/ole32/defaulthandler.c b/reactos/dll/win32/ole32/defaulthandler.c index b85002ad52b..4102d50845b 100644 --- a/reactos/dll/win32/ole32/defaulthandler.c +++ b/reactos/dll/win32/ole32/defaulthandler.c @@ -137,6 +137,11 @@ struct DefaultHandler /* storage passed to Load or InitNew */ IStorage *storage; enum storage_state storage_state; + + /* optional class factory for object */ + IClassFactory *pCFObject; + /* TRUE if acting as an inproc server instead of an inproc handler */ + BOOL inproc_server; }; typedef struct DefaultHandler DefaultHandler; @@ -223,6 +228,12 @@ static HRESULT WINAPI DefaultHandler_NDIUnknown_QueryInterface( if (FAILED(hr)) FIXME("interface %s not implemented by data cache\n", debugstr_guid(riid)); return hr; } + else if (This->inproc_server && This->pOleDelegate) + { + HRESULT hr = IUnknown_QueryInterface(This->pOleDelegate, riid, ppvObject); + if (SUCCEEDED(hr)) + return hr; + } /* Check that we obtained an interface. */ if (*ppvObject == NULL) @@ -1901,7 +1912,9 @@ static const IPersistStorageVtbl DefaultHandler_IPersistStorage_VTable = */ static DefaultHandler* DefaultHandler_Construct( REFCLSID clsid, - LPUNKNOWN pUnkOuter) + LPUNKNOWN pUnkOuter, + DWORD flags, + IClassFactory *pCF) { DefaultHandler* This = NULL; HRESULT hr; @@ -1918,6 +1931,8 @@ static DefaultHandler* DefaultHandler_Construct( This->lpvtblIAdviseSink = &DefaultHandler_IAdviseSink_VTable; This->lpvtblIPersistStorage = &DefaultHandler_IPersistStorage_VTable; + This->inproc_server = (flags & EMBDHLP_INPROC_SERVER) ? TRUE : FALSE; + /* * Start with one reference count. The caller of this function * must release the interface pointer when it is done. @@ -1964,6 +1979,30 @@ static DefaultHandler* DefaultHandler_Construct( This->storage = NULL; This->storage_state = storage_state_uninitialised; + if (This->inproc_server && !(flags & EMBDHLP_DELAYCREATE)) + { + HRESULT hr; + This->pCFObject = NULL; + if (pCF) + hr = IClassFactory_CreateInstance(pCF, NULL, &IID_IOleObject, (void **)&This->pOleDelegate); + else + hr = CoCreateInstance(&This->clsid, NULL, CLSCTX_INPROC_SERVER, + &IID_IOleObject, (void **)&This->pOleDelegate); + if (SUCCEEDED(hr)) + hr = IOleObject_QueryInterface(This->pOleDelegate, &IID_IPersistStorage, (void **)&This->pPSDelegate); + if (SUCCEEDED(hr)) + hr = IOleObject_QueryInterface(This->pOleDelegate, &IID_IDataObject, (void **)&This->pDataDelegate); + if (SUCCEEDED(hr)) + This->object_state = object_state_running; + if (FAILED(hr)) + WARN("object creation failed with error %08x\n", hr); + } + else + { + This->pCFObject = pCF; + if (pCF) IClassFactory_AddRef(pCF); + } + return This; } @@ -2011,22 +2050,30 @@ static void DefaultHandler_Destroy( This->storage = NULL; } + if (This->pCFObject) + { + IClassFactory_Release(This->pCFObject); + This->pCFObject = NULL; + } + HeapFree(GetProcessHeap(), 0, This); } /****************************************************************************** - * OleCreateDefaultHandler [OLE32.@] + * OleCreateEmbeddingHelper [OLE32.@] */ -HRESULT WINAPI OleCreateDefaultHandler( +HRESULT WINAPI OleCreateEmbeddingHelper( REFCLSID clsid, LPUNKNOWN pUnkOuter, + DWORD flags, + IClassFactory *pCF, REFIID riid, LPVOID* ppvObj) { DefaultHandler* newHandler = NULL; HRESULT hr = S_OK; - TRACE("(%s, %p, %s, %p)\n", debugstr_guid(clsid), pUnkOuter, debugstr_guid(riid), ppvObj); + TRACE("(%s, %p, %08x, %p, %s, %p)\n", debugstr_guid(clsid), pUnkOuter, flags, pCF, debugstr_guid(riid), ppvObj); if (!ppvObj) return E_POINTER; @@ -2045,7 +2092,7 @@ HRESULT WINAPI OleCreateDefaultHandler( /* * Try to construct a new instance of the class. */ - newHandler = DefaultHandler_Construct(clsid, pUnkOuter); + newHandler = DefaultHandler_Construct(clsid, pUnkOuter, flags, pCF); if (!newHandler) return E_OUTOFMEMORY; @@ -2063,3 +2110,15 @@ HRESULT WINAPI OleCreateDefaultHandler( return hr; } + + +/****************************************************************************** + * OleCreateDefaultHandler [OLE32.@] + */ +HRESULT WINAPI OleCreateDefaultHandler(REFCLSID clsid, LPUNKNOWN pUnkOuter, + REFIID riid, LPVOID* ppvObj) +{ + TRACE("(%s, %p, %s, %p)\n", debugstr_guid(clsid), pUnkOuter,debugstr_guid(riid), ppvObj); + return OleCreateEmbeddingHelper(clsid, pUnkOuter, EMBDHLP_INPROC_HANDLER | EMBDHLP_CREATENOW, + NULL, riid, ppvObj); +} diff --git a/reactos/dll/win32/ole32/errorinfo.c b/reactos/dll/win32/ole32/errorinfo.c index 64b81ff4dd2..f69635bc493 100644 --- a/reactos/dll/win32/ole32/errorinfo.c +++ b/reactos/dll/win32/ole32/errorinfo.c @@ -191,7 +191,7 @@ static HRESULT WINAPI IErrorInfoImpl_QueryInterface( VOID** ppvoid) { ErrorInfoImpl *This = impl_from_IErrorInfo(iface); - TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvoid); + TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppvoid); *ppvoid = NULL; diff --git a/reactos/dll/win32/ole32/ftmarshal.c b/reactos/dll/win32/ole32/ftmarshal.c index f82410efe31..13802854fa6 100644 --- a/reactos/dll/win32/ole32/ftmarshal.c +++ b/reactos/dll/win32/ole32/ftmarshal.c @@ -110,7 +110,7 @@ FTMarshalImpl_QueryInterface (LPMARSHAL iface, REFIID riid, LPVOID * ppv) FTMarshalImpl *This = impl_from_IMarshal(iface); - TRACE ("(%p)->(\n\tIID:\t%s,%p)\n", This, debugstr_guid (riid), ppv); + TRACE ("(%p)->(%s,%p)\n", This, debugstr_guid (riid), ppv); return IUnknown_QueryInterface (This->pUnkOuter, riid, ppv); } diff --git a/reactos/dll/win32/ole32/marshal.c b/reactos/dll/win32/ole32/marshal.c index 006615320fc..3703de9f2b8 100644 --- a/reactos/dll/win32/ole32/marshal.c +++ b/reactos/dll/win32/ole32/marshal.c @@ -431,7 +431,7 @@ static HRESULT WINAPI Proxy_MarshalInterface( if (SUCCEEDED(hr)) { - TRACE("writing stdobjref:\n\tflags = %04x\n\tcPublicRefs = %d\n\toxid = %s\n\toid = %s\n\tipid = %s\n", + TRACE("writing stdobjref: flags = %04x cPublicRefs = %d oxid = %s oid = %s ipid = %s\n", stdobjref.flags, stdobjref.cPublicRefs, wine_dbgstr_longlong(stdobjref.oxid), wine_dbgstr_longlong(stdobjref.oid), @@ -1239,7 +1239,7 @@ static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt, assert(apt); - TRACE("stdobjref:\n\tflags = %04x\n\tcPublicRefs = %d\n\toxid = %s\n\toid = %s\n\tipid = %s\n", + TRACE("stdobjref: flags = %04x cPublicRefs = %d oxid = %s oid = %s ipid = %s\n", stdobjref->flags, stdobjref->cPublicRefs, wine_dbgstr_longlong(stdobjref->oxid), wine_dbgstr_longlong(stdobjref->oid), diff --git a/reactos/dll/win32/ole32/ole2.c b/reactos/dll/win32/ole32/ole2.c index fe00066921e..3b87aacd6a6 100644 --- a/reactos/dll/win32/ole32/ole2.c +++ b/reactos/dll/win32/ole32/ole2.c @@ -570,7 +570,7 @@ HRESULT WINAPI OleQueryLinkFromData( IDataObject* pSrcDataObject) { FIXME("(%p),stub!\n", pSrcDataObject); - return S_OK; + return S_FALSE; } /*********************************************************************** diff --git a/reactos/dll/win32/ole32/ole32.spec b/reactos/dll/win32/ole32/ole32.spec index b9e5c4c3a79..97f2f3d3aac 100644 --- a/reactos/dll/win32/ole32/ole32.spec +++ b/reactos/dll/win32/ole32/ole32.spec @@ -180,7 +180,7 @@ @ stub OleConvertOLESTREAMToIStorageEx @ stdcall OleCreate(ptr ptr long ptr ptr ptr ptr) @ stdcall OleCreateDefaultHandler(ptr ptr ptr ptr) -@ stub OleCreateEmbeddingHelper +@ stdcall OleCreateEmbeddingHelper(ptr ptr long ptr ptr ptr) @ stub OleCreateEx @ stdcall OleCreateFromData(ptr ptr long ptr ptr ptr ptr) @ stdcall OleCreateFromDataEx(ptr ptr long long long ptr ptr ptr ptr ptr ptr ptr) diff --git a/reactos/dll/win32/ole32/stg_prop.c b/reactos/dll/win32/ole32/stg_prop.c index 381e0799e24..9bf9481b738 100644 --- a/reactos/dll/win32/ole32/stg_prop.c +++ b/reactos/dll/win32/ole32/stg_prop.c @@ -1477,6 +1477,25 @@ static void PropertyStorage_MakePropertyIdOffset(DWORD propid, DWORD dwOffset, offsetof(PROPERTYIDOFFSET, dwOffset), dwOffset); } +static inline HRESULT PropertStorage_WriteWStringToStream(IStream *stm, + LPCWSTR str, DWORD len, DWORD *written) +{ +#ifdef WORDS_BIGENDIAN + WCHAR *leStr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + HRESULT hr; + + if (!leStr) + return E_OUTOFMEMORY; + memcpy(leStr, str, len * sizeof(WCHAR)); + PropertyStorage_ByteSwapString(leStr, len); + hr = IStream_Write(stm, leStr, len, written); + HeapFree(GetProcessHeap(), 0, leStr); + return hr; +#else + return IStream_Write(stm, str, len, written); +#endif +} + struct DictionaryClosure { HRESULT hr; @@ -1508,15 +1527,11 @@ static BOOL PropertyStorage_DictionaryWriter(const void *key, if (FAILED(c->hr)) goto end; c->bytesWritten += sizeof(DWORD); - /* Rather than allocate a copy, I'll swap the string to little-endian - * in-place, write it, then swap it back. - */ - PropertyStorage_ByteSwapString(key, keyLen); - c->hr = IStream_Write(This->stm, key, keyLen, &count); - PropertyStorage_ByteSwapString(key, keyLen); + c->hr = PropertStorage_WriteWStringToStream(This->stm, key, keyLen, + &count); if (FAILED(c->hr)) goto end; - c->bytesWritten += keyLen; + c->bytesWritten += keyLen * sizeof(WCHAR); if (keyLen % sizeof(DWORD)) { c->hr = IStream_Write(This->stm, &pad, diff --git a/reactos/dll/win32/ole32/stg_stream.c b/reactos/dll/win32/ole32/stg_stream.c index 9acd4145191..36486f98a5c 100644 --- a/reactos/dll/win32/ole32/stg_stream.c +++ b/reactos/dll/win32/ole32/stg_stream.c @@ -232,6 +232,7 @@ static void StgStreamImpl_OpenBlockChain( { This->smallBlockChain = SmallBlockChainStream_Construct( This->parentStorage->ancestorStorage, + NULL, This->ownerProperty); } else @@ -536,8 +537,6 @@ static HRESULT WINAPI StgStreamImpl_Seek( * * It will change the size of a stream. * - * TODO: Switch from small blocks to big blocks and vice versa. - * * See the documentation of IStream for more info. */ static HRESULT WINAPI StgStreamImpl_SetSize( @@ -591,6 +590,7 @@ static HRESULT WINAPI StgStreamImpl_SetSize( { This->smallBlockChain = SmallBlockChainStream_Construct( This->parentStorage->ancestorStorage, + NULL, This->ownerProperty); } else @@ -624,6 +624,19 @@ static HRESULT WINAPI StgStreamImpl_SetSize( &This->smallBlockChain); } } + else if ( (This->bigBlockChain!=0) && + (curProperty.size.u.LowPart >= LIMIT_TO_USE_SMALL_BLOCK) ) + { + if (libNewSize.u.LowPart < LIMIT_TO_USE_SMALL_BLOCK) + { + /* + * Transform the big block chain into a small block chain + */ + This->smallBlockChain = Storage32Impl_BigBlocksToSmallBlocks( + This->parentStorage->ancestorStorage, + &This->bigBlockChain); + } + } if (This->smallBlockChain!=0) { diff --git a/reactos/dll/win32/ole32/storage32.c b/reactos/dll/win32/ole32/storage32.c index 212c1ff965f..4a27317dd84 100644 --- a/reactos/dll/win32/ole32/storage32.c +++ b/reactos/dll/win32/ole32/storage32.c @@ -104,6 +104,7 @@ static ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This); static ULONG BlockChainStream_GetCount(BlockChainStream* This); static ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This); +static ULONG SmallBlockChainStream_GetHeadOfChain(SmallBlockChainStream* This); static BOOL StorageImpl_WriteDWordToBigBlock( StorageImpl* This, ULONG blockIndex, ULONG offset, DWORD value); static BOOL StorageImpl_ReadDWordFromBigBlock( StorageImpl* This, @@ -3586,9 +3587,13 @@ BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks( } while (cbTotalRead.QuadPart < size.QuadPart); HeapFree(GetProcessHeap(),0,buffer); + size.u.HighPart = 0; + size.u.LowPart = 0; + if (FAILED(resRead) || FAILED(resWrite)) { ERR("conversion failed: resRead = 0x%08x, resWrite = 0x%08x\n", resRead, resWrite); + BlockChainStream_SetSize(bbTempChain, size); BlockChainStream_Destroy(bbTempChain); return NULL; } @@ -3597,8 +3602,6 @@ BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks( * Destroy the small block chain. */ propertyIndex = (*ppsbChain)->ownerPropertyIndex; - size.u.HighPart = 0; - size.u.LowPart = 0; SmallBlockChainStream_SetSize(*ppsbChain, size); SmallBlockChainStream_Destroy(*ppsbChain); *ppsbChain = 0; @@ -3625,6 +3628,86 @@ BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks( return bigBlockChain; } +/****************************************************************************** + * Storage32Impl_BigBlocksToSmallBlocks + * + * This method will convert a big block chain to a small block chain. + * The big block chain will be destroyed on success. + */ +SmallBlockChainStream* Storage32Impl_BigBlocksToSmallBlocks( + StorageImpl* This, + BlockChainStream** ppbbChain) +{ + ULARGE_INTEGER size, offset, cbTotalRead; + ULONG cbRead, cbWritten, propertyIndex, sbHeadOfChain = BLOCK_END_OF_CHAIN; + HRESULT resWrite = S_OK, resRead; + StgProperty chainProperty; + BYTE* buffer; + SmallBlockChainStream* sbTempChain; + + TRACE("%p %p\n", This, ppbbChain); + + sbTempChain = SmallBlockChainStream_Construct(This, &sbHeadOfChain, + PROPERTY_NULL); + + if(!sbTempChain) + return NULL; + + size = BlockChainStream_GetSize(*ppbbChain); + SmallBlockChainStream_SetSize(sbTempChain, size); + + offset.u.HighPart = 0; + offset.u.LowPart = 0; + cbTotalRead.QuadPart = 0; + buffer = HeapAlloc(GetProcessHeap(), 0, This->bigBlockSize); + do + { + resRead = BlockChainStream_ReadAt(*ppbbChain, offset, + This->bigBlockSize, buffer, &cbRead); + + if(FAILED(resRead)) + break; + + if(cbRead > 0) + { + cbTotalRead.QuadPart += cbRead; + + resWrite = SmallBlockChainStream_WriteAt(sbTempChain, offset, + cbRead, buffer, &cbWritten); + + if(FAILED(resWrite)) + break; + + offset.u.LowPart += This->bigBlockSize; + } + }while(cbTotalRead.QuadPart < size.QuadPart); + HeapFree(GetProcessHeap(), 0, buffer); + + size.u.HighPart = 0; + size.u.LowPart = 0; + + if(FAILED(resRead) || FAILED(resWrite)) + { + ERR("conversion failed: resRead = 0x%08x, resWrite = 0x%08x\n", resRead, resWrite); + SmallBlockChainStream_SetSize(sbTempChain, size); + SmallBlockChainStream_Destroy(sbTempChain); + return NULL; + } + + /* destroy the original big block chain */ + propertyIndex = (*ppbbChain)->ownerPropertyIndex; + BlockChainStream_SetSize(*ppbbChain, size); + BlockChainStream_Destroy(*ppbbChain); + *ppbbChain = NULL; + + StorageImpl_ReadProperty(This, propertyIndex, &chainProperty); + chainProperty.startingBlock = sbHeadOfChain; + StorageImpl_WriteProperty(This, propertyIndex, &chainProperty); + + SmallBlockChainStream_Destroy(sbTempChain); + return SmallBlockChainStream_Construct(This, NULL, propertyIndex); +} + static void StorageInternalImpl_Destroy( StorageBaseImpl *iface) { StorageInternalImpl* This = (StorageInternalImpl*) iface; @@ -4577,7 +4660,6 @@ HRESULT BlockChainStream_ReadAt(BlockChainStream* This, * BlockChainStream_WriteAt * * Writes the specified number of bytes to this chain at the specified offset. - * bytesWritten may be NULL. * Will fail if not all specified number of bytes have been written. */ HRESULT BlockChainStream_WriteAt(BlockChainStream* This, @@ -4929,6 +5011,7 @@ static ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This) SmallBlockChainStream* SmallBlockChainStream_Construct( StorageImpl* parentStorage, + ULONG* headOfStreamPlaceHolder, ULONG propertyIndex) { SmallBlockChainStream* newStream; @@ -4936,6 +5019,7 @@ SmallBlockChainStream* SmallBlockChainStream_Construct( newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream)); newStream->parentStorage = parentStorage; + newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder; newStream->ownerPropertyIndex = propertyIndex; return newStream; @@ -4958,6 +5042,9 @@ static ULONG SmallBlockChainStream_GetHeadOfChain( StgProperty chainProperty; BOOL readSuccessful; + if (This->headOfStreamPlaceHolder != NULL) + return *(This->headOfStreamPlaceHolder); + if (This->ownerPropertyIndex) { readSuccessful = StorageImpl_ReadProperty( @@ -5320,7 +5407,6 @@ HRESULT SmallBlockChainStream_ReadAt( * SmallBlockChainStream_WriteAt * * Writes the specified number of bytes to this chain at the specified offset. - * bytesWritten may be NULL. * Will fail if not all specified number of bytes have been written. */ HRESULT SmallBlockChainStream_WriteAt( @@ -5360,9 +5446,6 @@ HRESULT SmallBlockChainStream_WriteAt( /* * Start writing the buffer. - * - * Here, I'm casting away the constness on the buffer variable - * This is OK since we don't intend to modify that buffer. */ *bytesWritten = 0; bufferWalker = buffer; @@ -5509,26 +5592,32 @@ static BOOL SmallBlockChainStream_Enlarge( blockIndex = SmallBlockChainStream_GetHeadOfChain(This); /* - * Empty chain + * Empty chain. Create the head. */ if (blockIndex == BLOCK_END_OF_CHAIN) { + blockIndex = SmallBlockChainStream_GetNextFreeBlock(This); + SmallBlockChainStream_SetNextBlockInChain( + This, + blockIndex, + BLOCK_END_OF_CHAIN); - StgProperty chainProp; - - StorageImpl_ReadProperty(This->parentStorage, This->ownerPropertyIndex, - &chainProp); + if (This->headOfStreamPlaceHolder != NULL) + { + *(This->headOfStreamPlaceHolder) = blockIndex; + } + else + { + StgProperty chainProp; - chainProp.startingBlock = SmallBlockChainStream_GetNextFreeBlock(This); + StorageImpl_ReadProperty(This->parentStorage, This->ownerPropertyIndex, + &chainProp); - StorageImpl_WriteProperty(This->parentStorage, This->ownerPropertyIndex, - &chainProp); + chainProp.startingBlock = blockIndex; - blockIndex = chainProp.startingBlock; - SmallBlockChainStream_SetNextBlockInChain( - This, - blockIndex, - BLOCK_END_OF_CHAIN); + StorageImpl_WriteProperty(This->parentStorage, This->ownerPropertyIndex, + &chainProp); + } } currentBlock = blockIndex; @@ -5603,6 +5692,32 @@ BOOL SmallBlockChainStream_SetSize( return TRUE; } +/****************************************************************************** + * SmallBlockChainStream_GetCount + * + * Returns the number of small blocks that comprises this chain. + * This is not the size of the stream as the last block may not be full! + * + */ +static 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_GetSize * @@ -5612,6 +5727,17 @@ static ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This) { StgProperty chainProperty; + if(This->headOfStreamPlaceHolder != NULL) + { + ULARGE_INTEGER result; + result.u.HighPart = 0; + + result.u.LowPart = SmallBlockChainStream_GetCount(This) * + This->parentStorage->smallBlockSize; + + return result; + } + StorageImpl_ReadProperty( This->parentStorage, This->ownerPropertyIndex, diff --git a/reactos/dll/win32/ole32/storage32.h b/reactos/dll/win32/ole32/storage32.h index 4be0631eb7a..fc4af325552 100644 --- a/reactos/dll/win32/ole32/storage32.h +++ b/reactos/dll/win32/ole32/storage32.h @@ -306,6 +306,10 @@ BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks( StorageImpl* This, SmallBlockChainStream** ppsbChain); +SmallBlockChainStream* Storage32Impl_BigBlocksToSmallBlocks( + StorageImpl* This, + BlockChainStream** ppbbChain); + /**************************************************************************** * StgStreamImpl definitions. * @@ -464,14 +468,16 @@ struct SmallBlockChainStream { StorageImpl* parentStorage; ULONG ownerPropertyIndex; + ULONG* headOfStreamPlaceHolder; }; /* * Methods of the SmallBlockChainStream class. */ SmallBlockChainStream* SmallBlockChainStream_Construct( - StorageImpl* parentStorage, - ULONG propertyIndex); + StorageImpl* parentStorage, + ULONG* headOfStreamPlaceHolder, + ULONG propertyIndex); void SmallBlockChainStream_Destroy( SmallBlockChainStream* This); diff --git a/reactos/dll/win32/ole32/stubmanager.c b/reactos/dll/win32/ole32/stubmanager.c index 0aa80fa15a8..12813c6a5d7 100644 --- a/reactos/dll/win32/ole32/stubmanager.c +++ b/reactos/dll/win32/ole32/stubmanager.c @@ -42,8 +42,129 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole); -static void stub_manager_delete_ifstub(struct stub_manager *m, struct ifstub *ifstub); -static struct ifstub *stub_manager_ipid_to_ifstub(struct stub_manager *m, const IPID *ipid); + +/* generates an ipid in the following format (similar to native version): + * Data1 = apartment-local ipid counter + * Data2 = apartment creator thread ID + * Data3 = process ID + * Data4 = random value + */ +static inline HRESULT generate_ipid(struct stub_manager *m, IPID *ipid) +{ + HRESULT hr; + hr = UuidCreate(ipid); + if (FAILED(hr)) + { + ERR("couldn't create IPID for stub manager %p\n", m); + UuidCreateNil(ipid); + return hr; + } + + ipid->Data1 = InterlockedIncrement(&m->apt->ipidc); + ipid->Data2 = (USHORT)m->apt->tid; + ipid->Data3 = (USHORT)GetCurrentProcessId(); + return S_OK; +} + +/* registers a new interface stub COM object with the stub manager and returns registration record */ +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)); + + 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); + + IUnknown_AddRef(iptr); + stub->iface = iptr; + stub->flags = flags; + stub->iid = *iid; + + /* 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); + + EnterCriticalSection(&m->lock); + list_add_head(&m->ifstubs, &stub->entry); + /* every normal marshal is counted so we don't allow more than we should */ + if (flags & MSHLFLAGS_NORMAL) m->norm_refs++; + LeaveCriticalSection(&m->lock); + + TRACE("ifstub %p created with ipid %s\n", stub, debugstr_guid(&stub->ipid)); + + return stub; +} + +static void stub_manager_delete_ifstub(struct stub_manager *m, struct ifstub *ifstub) +{ + TRACE("m=%p, m->oid=%s, ipid=%s\n", m, wine_dbgstr_longlong(m->oid), debugstr_guid(&ifstub->ipid)); + + 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); +} + +static struct ifstub *stub_manager_ipid_to_ifstub(struct stub_manager *m, const IPID *ipid) +{ + struct list *cursor; + struct ifstub *result = NULL; + + EnterCriticalSection(&m->lock); + LIST_FOR_EACH( cursor, &m->ifstubs ) + { + struct ifstub *ifstub = LIST_ENTRY( cursor, struct ifstub, entry ); + + if (IsEqualGUID(ipid, &ifstub->ipid)) + { + result = ifstub; + break; + } + } + LeaveCriticalSection(&m->lock); + + return result; +} + +struct ifstub *stub_manager_find_ifstub(struct stub_manager *m, REFIID iid, MSHLFLAGS flags) +{ + struct ifstub *result = NULL; + struct ifstub *ifstub; + + EnterCriticalSection(&m->lock); + LIST_FOR_EACH_ENTRY( ifstub, &m->ifstubs, struct ifstub, entry ) + { + if (IsEqualIID(iid, &ifstub->iid) && (ifstub->flags == flags)) + { + result = ifstub; + break; + } + } + LeaveCriticalSection(&m->lock); + + return result; +} /* creates a new stub manager and adds it into the apartment. caller must * release stub manager when it is no longer required. the apartment and @@ -129,6 +250,44 @@ static void stub_manager_delete(struct stub_manager *m) HeapFree(GetProcessHeap(), 0, m); } +/* increments the internal refcount */ +static ULONG stub_manager_int_addref(struct stub_manager *This) +{ + ULONG refs; + + EnterCriticalSection(&This->apt->cs); + refs = ++This->refs; + LeaveCriticalSection(&This->apt->cs); + + TRACE("before %d\n", refs - 1); + + return refs; +} + +/* decrements the internal refcount */ +ULONG stub_manager_int_release(struct stub_manager *This) +{ + ULONG refs; + APARTMENT *apt = This->apt; + + EnterCriticalSection(&apt->cs); + refs = --This->refs; + + TRACE("after %d\n", refs); + + /* remove from apartment so no other thread can access it... */ + if (!refs) + list_remove(&This->entry); + + LeaveCriticalSection(&apt->cs); + + /* ... so now we can delete it without being inside the apartment critsec */ + if (!refs) + stub_manager_delete(This); + + return refs; +} + /* gets the stub manager associated with an object - caller must have * a reference to the apartment while a reference to the stub manager is held. * it must also call release on the stub manager when it is no longer needed */ @@ -214,44 +373,6 @@ struct stub_manager *get_stub_manager(APARTMENT *apt, OID oid) return result; } -/* increments the internal refcount */ -ULONG stub_manager_int_addref(struct stub_manager *This) -{ - ULONG refs; - - EnterCriticalSection(&This->apt->cs); - refs = ++This->refs; - LeaveCriticalSection(&This->apt->cs); - - TRACE("before %d\n", refs - 1); - - return refs; -} - -/* decrements the internal refcount */ -ULONG stub_manager_int_release(struct stub_manager *This) -{ - ULONG refs; - APARTMENT *apt = This->apt; - - EnterCriticalSection(&apt->cs); - refs = --This->refs; - - TRACE("after %d\n", refs); - - /* remove from apartment so no other thread can access it... */ - if (!refs) - list_remove(&This->entry); - - LeaveCriticalSection(&apt->cs); - - /* ... so now we can delete it without being inside the apartment critsec */ - if (!refs) - stub_manager_delete(This); - - return refs; -} - /* add some external references (ie from a client that unmarshaled an ifptr) */ ULONG stub_manager_ext_addref(struct stub_manager *m, ULONG refs, BOOL tableweak) { @@ -297,46 +418,6 @@ ULONG stub_manager_ext_release(struct stub_manager *m, ULONG refs, BOOL tablewea return rc; } -static struct ifstub *stub_manager_ipid_to_ifstub(struct stub_manager *m, const IPID *ipid) -{ - struct list *cursor; - struct ifstub *result = NULL; - - EnterCriticalSection(&m->lock); - LIST_FOR_EACH( cursor, &m->ifstubs ) - { - struct ifstub *ifstub = LIST_ENTRY( cursor, struct ifstub, entry ); - - if (IsEqualGUID(ipid, &ifstub->ipid)) - { - result = ifstub; - break; - } - } - LeaveCriticalSection(&m->lock); - - return result; -} - -struct ifstub *stub_manager_find_ifstub(struct stub_manager *m, REFIID iid, MSHLFLAGS flags) -{ - struct ifstub *result = NULL; - struct ifstub *ifstub; - - EnterCriticalSection(&m->lock); - LIST_FOR_EACH_ENTRY( ifstub, &m->ifstubs, struct ifstub, entry ) - { - if (IsEqualIID(iid, &ifstub->iid) && (ifstub->flags == flags)) - { - result = ifstub; - break; - } - } - LeaveCriticalSection(&m->lock); - - return result; -} - /* gets the stub manager associated with an ipid - caller must have * a reference to the apartment while a reference to the stub manager is held. * it must also call release on the stub manager when it is no longer needed */ @@ -426,89 +507,6 @@ HRESULT ipid_get_dispatch_params(const IPID *ipid, APARTMENT **stub_apt, } } -/* generates an ipid in the following format (similar to native version): - * Data1 = apartment-local ipid counter - * Data2 = apartment creator thread ID - * Data3 = process ID - * Data4 = random value - */ -static inline HRESULT generate_ipid(struct stub_manager *m, IPID *ipid) -{ - HRESULT hr; - hr = UuidCreate(ipid); - if (FAILED(hr)) - { - ERR("couldn't create IPID for stub manager %p\n", m); - UuidCreateNil(ipid); - return hr; - } - - ipid->Data1 = InterlockedIncrement(&m->apt->ipidc); - ipid->Data2 = (USHORT)m->apt->tid; - ipid->Data3 = (USHORT)GetCurrentProcessId(); - return S_OK; -} - -/* registers a new interface stub COM object with the stub manager and returns registration record */ -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)); - - 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); - - IUnknown_AddRef(iptr); - stub->iface = iptr; - stub->flags = flags; - stub->iid = *iid; - - /* 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); - - EnterCriticalSection(&m->lock); - list_add_head(&m->ifstubs, &stub->entry); - /* every normal marshal is counted so we don't allow more than we should */ - if (flags & MSHLFLAGS_NORMAL) m->norm_refs++; - LeaveCriticalSection(&m->lock); - - TRACE("ifstub %p created with ipid %s\n", stub, debugstr_guid(&stub->ipid)); - - return stub; -} - -static void stub_manager_delete_ifstub(struct stub_manager *m, struct ifstub *ifstub) -{ - TRACE("m=%p, m->oid=%s, ipid=%s\n", m, wine_dbgstr_longlong(m->oid), debugstr_guid(&ifstub->ipid)); - - 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); -} - /* returns TRUE if it is possible to unmarshal, FALSE otherwise. */ BOOL stub_manager_notify_unmarshal(struct stub_manager *m, const IPID *ipid) {