* - Implement the OXID resolver so we don't need magic endpoint names for
* clients and servers to meet up
*
- * - Make all ole interface marshaling use NDR to be wire compatible with
- * native DCOM
- *
*/
#include "config.h"
#include "winerror.h"
#include "winreg.h"
#include "winuser.h"
+#define USE_COM_CONTEXT_DEF
#include "objbase.h"
#include "ole2.h"
#include "ole2ver.h"
+#include "ctxtcall.h"
+#include "dde.h"
+#include "initguid.h"
#include "compobj_private.h"
+#include "moniker.h"
#include "wine/unicode.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(ole);
-HINSTANCE OLE32_hInstance = 0; /* FIXME: make static ... */
-
#define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
/****************************************************************************
* This section defines variables internal to the COM module.
- *
- * TODO: Most of these things will have to be made thread-safe.
*/
-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, 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 */
* objects.
*
* TODO: Make this data structure aware of inter-process communication. This
- * means that parts of this will be exported to the Wine Server.
+ * means that parts of this will be exported to rpcss.
*/
typedef struct tagRegisteredClass
{
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 (ie 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
- * COM_AptWndProc 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 = OLE32_hInstance;
- 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, OLE32_hInstance);
+ 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);
- 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)
}
LeaveCriticalSection(&csApartment);
+
+ if (apt->main)
+ apartment_createwindowifneeded(apt);
}
else
{
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);
-DWORD apartment_release(struct apartment *apt)
-{
- DWORD ret;
+ if (curClass->runContext & CLSCTX_LOCAL_SERVER)
+ RPC_StopLocalServer(curClass->RpcRegistration);
- EnterCriticalSection(&csApartment);
+ /*
+ * Release the reference to the class object.
+ */
+ IUnknown_Release(curClass->classObject);
- ret = InterlockedDecrement(&apt->refs);
- TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
- /* destruction stuff that needs to happen under csApartment CS */
- if (ret == 0)
+ if (curClass->pMarshaledData)
{
- if (apt == MTA) MTA = NULL;
- else if (apt == MainApartment) MainApartment = NULL;
- list_remove(&apt->entry);
+ LARGE_INTEGER zero;
+ memset(&zero, 0, sizeof(zero));
+ IStream_Seek(curClass->pMarshaledData, zero, STREAM_SEEK_SET, NULL);
+ CoReleaseMarshalData(curClass->pMarshaledData);
+ IStream_Release(curClass->pMarshaledData);
}
- LeaveCriticalSection(&csApartment);
+ HeapFree(GetProcessHeap(), 0, curClass);
+}
- if (ret == 0)
- {
- struct list *cursor, *cursor2;
+static void COM_RevokeAllClasses(const struct apartment *apt)
+{
+ RegisteredClass *curClass, *cursor;
- TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
+ EnterCriticalSection( &csRegisteredClassList );
- /* Release the references to the registered class objects */
- COM_RevokeAllClasses(apt);
+ LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
+ {
+ if (curClass->apartment_id == apt->oxid)
+ COM_RevokeRegisteredClassObject(curClass);
+ }
- /* no locking is needed for this apartment, because no other thread
- * can access it at this point */
+ LeaveCriticalSection( &csRegisteredClassList );
+}
- apartment_disconnectproxies(apt);
+/******************************************************************************
+ * Implementation of the manual reset event object. (CLSID_ManualResetEvent)
+ */
- if (apt->win) DestroyWindow(apt->win);
- if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0);
+typedef struct ManualResetEvent {
+ ISynchronize ISynchronize_iface;
+ LONG ref;
+ HANDLE event;
+} MREImpl;
- LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
- {
- struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
- /* release the implicit reference given by the fact that the
- * stub has external references (it must do since it is in the
- * stub manager list in the apartment and all non-apartment users
- * must have a ref on the apartment and so it cannot be destroyed).
- */
- stub_manager_int_release(stubmgr);
- }
+static inline MREImpl *impl_from_ISynchronize(ISynchronize *iface)
+{
+ return CONTAINING_RECORD(iface, MREImpl, ISynchronize_iface);
+}
- LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->psclsids)
- {
- struct registered_psclsid *registered_psclsid =
- LIST_ENTRY(cursor, struct registered_psclsid, entry);
+static HRESULT WINAPI ISynchronize_fnQueryInterface(ISynchronize *iface, REFIID riid, void **ppv)
+{
+ MREImpl *This = impl_from_ISynchronize(iface);
+ TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppv);
- list_remove(®istered_psclsid->entry);
- HeapFree(GetProcessHeap(), 0, registered_psclsid);
- }
+ *ppv = NULL;
+ if(IsEqualGUID(riid, &IID_IUnknown) ||
+ IsEqualGUID(riid, &IID_ISynchronize))
+ *ppv = This;
+ else
+ ERR("Unknown interface %s requested.\n", debugstr_guid(riid));
- /* if this assert fires, then another thread took a reference to a
- * stub manager without taking a reference to the containing
- * apartment, which it must do. */
- assert(list_empty(&apt->stubmgrs));
+ if(*ppv)
+ {
+ IUnknown_AddRef((IUnknown*)*ppv);
+ return S_OK;
+ }
- if (apt->filter) IUnknown_Release(apt->filter);
+ return E_NOINTERFACE;
+}
- /* free as many unused libraries as possible... */
- apartment_freeunusedlibraries(apt, 0);
+static ULONG WINAPI ISynchronize_fnAddRef(ISynchronize *iface)
+{
+ MREImpl *This = impl_from_ISynchronize(iface);
+ LONG ref = InterlockedIncrement(&This->ref);
+ TRACE("%p - ref %d\n", This, ref);
- /* ... and free the memory for the apartment loaded dll entry and
- * release the dll list reference without freeing the library for the
- * rest */
- while ((cursor = list_head(&apt->loaded_dlls)))
- {
- struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
- COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE);
- list_remove(cursor);
- HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
- }
+ return ref;
+}
- DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
- DeleteCriticalSection(&apt->cs);
+static ULONG WINAPI ISynchronize_fnRelease(ISynchronize *iface)
+{
+ MREImpl *This = impl_from_ISynchronize(iface);
+ LONG ref = InterlockedDecrement(&This->ref);
+ TRACE("%p - ref %d\n", This, ref);
- HeapFree(GetProcessHeap(), 0, apt);
+ if(!ref)
+ {
+ CloseHandle(This->event);
+ HeapFree(GetProcessHeap(), 0, This);
}
- return ret;
+ return ref;
}
-/* The given OXID must be local to this process:
- *
- * The ref parameter is here mostly to ensure people remember that
- * they get one, you should normally take a ref for thread safety.
+static HRESULT WINAPI ISynchronize_fnWait(ISynchronize *iface, DWORD dwFlags, DWORD dwMilliseconds)
+{
+ MREImpl *This = impl_from_ISynchronize(iface);
+ UINT index;
+ TRACE("%p (%08x, %08x)\n", This, dwFlags, dwMilliseconds);
+ return CoWaitForMultipleHandles(dwFlags, dwMilliseconds, 1, &This->event, &index);
+}
+
+static HRESULT WINAPI ISynchronize_fnSignal(ISynchronize *iface)
+{
+ MREImpl *This = impl_from_ISynchronize(iface);
+ TRACE("%p\n", This);
+ SetEvent(This->event);
+ return S_OK;
+}
+
+static HRESULT WINAPI ISynchronize_fnReset(ISynchronize *iface)
+{
+ MREImpl *This = impl_from_ISynchronize(iface);
+ TRACE("%p\n", This);
+ ResetEvent(This->event);
+ return S_OK;
+}
+
+static ISynchronizeVtbl vt_ISynchronize = {
+ ISynchronize_fnQueryInterface,
+ ISynchronize_fnAddRef,
+ ISynchronize_fnRelease,
+ ISynchronize_fnWait,
+ ISynchronize_fnSignal,
+ ISynchronize_fnReset
+};
+
+static HRESULT ManualResetEvent_Construct(IUnknown *punkouter, REFIID iid, void **ppv)
+{
+ MREImpl *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MREImpl));
+ HRESULT hr;
+
+ if(punkouter)
+ FIXME("Aggregation not implemented.\n");
+
+ This->ref = 1;
+ This->ISynchronize_iface.lpVtbl = &vt_ISynchronize;
+ This->event = CreateEventW(NULL, TRUE, FALSE, NULL);
+
+ hr = ISynchronize_QueryInterface(&This->ISynchronize_iface, iid, ppv);
+ ISynchronize_Release(&This->ISynchronize_iface);
+ return hr;
+}
+
+/***********************************************************************
+ * 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)
+{
+ DWORD ret;
+
+ EnterCriticalSection(&csApartment);
+
+ ret = InterlockedDecrement(&apt->refs);
+ TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
+ /* destruction stuff that needs to happen under csApartment CS */
+ if (ret == 0)
+ {
+ if (apt == MTA) MTA = NULL;
+ else if (apt == MainApartment) MainApartment = NULL;
+ list_remove(&apt->entry);
+ }
+
+ LeaveCriticalSection(&csApartment);
+
+ if (ret == 0)
+ {
+ struct list *cursor, *cursor2;
+
+ TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
+
+ /* Release the references to the registered class objects */
+ COM_RevokeAllClasses(apt);
+
+ /* no locking is needed for this apartment, because no other thread
+ * can access it at this point */
+
+ apartment_disconnectproxies(apt);
+
+ if (apt->win) DestroyWindow(apt->win);
+ if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0);
+
+ LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
+ {
+ struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
+ /* release the implicit reference given by the fact that the
+ * stub has external references (it must do since it is in the
+ * stub manager list in the apartment and all non-apartment users
+ * must have a ref on the apartment and so it cannot be destroyed).
+ */
+ stub_manager_int_release(stubmgr);
+ }
+
+ LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->psclsids)
+ {
+ struct registered_psclsid *registered_psclsid =
+ LIST_ENTRY(cursor, struct registered_psclsid, entry);
+
+ list_remove(®istered_psclsid->entry);
+ HeapFree(GetProcessHeap(), 0, registered_psclsid);
+ }
+
+ /* if this assert fires, then another thread took a reference to a
+ * stub manager without taking a reference to the containing
+ * apartment, which it must do. */
+ assert(list_empty(&apt->stubmgrs));
+
+ if (apt->filter) IUnknown_Release(apt->filter);
+
+ /* free as many unused libraries as possible... */
+ apartment_freeunusedlibraries(apt, 0);
+
+ /* ... and free the memory for the apartment loaded dll entry and
+ * release the dll list reference without freeing the library for the
+ * rest */
+ while ((cursor = list_head(&apt->loaded_dlls)))
+ {
+ struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
+ COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE);
+ list_remove(cursor);
+ HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
+ }
+
+ DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
+ DeleteCriticalSection(&apt->cs);
+
+ HeapFree(GetProcessHeap(), 0, apt);
+ }
+
+ return ret;
+}
+
+/* The given OXID must be local to this process:
+ *
+ * The ref parameter is here mostly to ensure people remember that
+ * they get one, you should normally take a ref for thread safety.
*/
APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
{
break;
}
}
- LeaveCriticalSection(&csApartment);
+ LeaveCriticalSection(&csApartment);
+
+ return result;
+}
+
+/* gets the main apartment if it exists. The caller must
+ * release the reference from the apartment as soon as the apartment pointer
+ * is no longer required. */
+static APARTMENT *apartment_findmain(void)
+{
+ APARTMENT *result;
+
+ EnterCriticalSection(&csApartment);
+
+ result = MainApartment;
+ if (result) apartment_addref(result);
+
+ LeaveCriticalSection(&csApartment);
+
+ return result;
+}
+
+/* gets the multi-threaded apartment if it exists. The caller must
+ * release the reference from the apartment as soon as the apartment pointer
+ * is no longer required. */
+static APARTMENT *apartment_find_multi_threaded(void)
+{
+ APARTMENT *result = NULL;
+ struct list *cursor;
+
+ 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 result;
+ return hr;
}
-/* gets the main apartment if it exists. The caller must
- * release the reference from the apartment as soon as the apartment pointer
- * is no longer required. */
-static APARTMENT *apartment_findmain(void)
+/***********************************************************************
+ * 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)
{
- APARTMENT *result;
-
- EnterCriticalSection(&csApartment);
-
- result = MainApartment;
- if (result) apartment_addref(result);
-
- LeaveCriticalSection(&csApartment);
+ DWORD ret;
+ HKEY key;
+ DWORD keytype;
+ WCHAR src[MAX_PATH];
+ DWORD dwLength = dstlen * sizeof(WCHAR);
- 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 {
+ const WCHAR *quote_start;
+ quote_start = strchrW(src, '\"');
+ if (quote_start) {
+ const WCHAR *quote_end = strchrW(quote_start + 1, '\"');
+ if (quote_end) {
+ memmove(src, quote_start + 1,
+ (quote_end - quote_start - 1) * sizeof(WCHAR));
+ src[quote_end - quote_start - 1] = '\0';
+ }
+ }
+ lstrcpynW(dst, src, dstlen);
+ }
+ }
+ RegCloseKey (key);
+ }
+ return ret;
}
struct host_object_params
HWND apartment_hwnd;
};
+/* thread for hosting an object to allow an object to appear to be created in
+ * an apartment with an incompatible threading model */
static DWORD CALLBACK apartment_hostobject_thread(LPVOID p)
{
struct host_thread_params *params = p;
{
if (!msg.hwnd && (msg.message == DM_HOSTOBJECT))
{
- struct host_object_params *params = (struct host_object_params *)msg.lParam;
- params->hr = apartment_hostobject(apt, params);
- SetEvent(params->event);
+ struct host_object_params *obj_params = (struct host_object_params *)msg.lParam;
+ obj_params->hr = apartment_hostobject(apt, obj_params);
+ SetEvent(obj_params->event);
}
else
{
return S_OK;
}
-static HRESULT apartment_hostobject_in_hostapt(struct apartment *apt, BOOL multi_threaded, BOOL main_apartment, HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
+/* finds or creates a host apartment, creates the object inside it and returns
+ * a proxy to it so that the object can be used in the apartment of the
+ * caller of this function */
+static HRESULT apartment_hostobject_in_hostapt(
+ struct apartment *apt, BOOL multi_threaded, BOOL main_apartment,
+ HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
{
struct host_object_params params;
HWND apartment_hwnd = NULL;
return hr;
}
+/* create a window for the apartment or return the current one if one has
+ * already been created */
HRESULT apartment_createwindowifneeded(struct apartment *apt)
{
if (apt->multi_threaded)
{
HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0,
0, 0, 0, 0,
- 0, 0, OLE32_hInstance, NULL);
+ HWND_MESSAGE, 0, hProxyDll, NULL);
if (!hwnd)
{
ERR("CreateWindow failed with error %d\n", GetLastError());
return S_OK;
}
+/* retrieves the window for the main- or apartment-threaded apartment */
HWND apartment_getwindow(const struct apartment *apt)
{
assert(!apt->multi_threaded);
COM_CurrentInfo()->apt = MTA;
}
-static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
- BOOL apartment_threaded,
- REFCLSID rclsid, REFIID riid, void **ppv)
+static void COMPOBJ_InitProcess( void )
{
- 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);
+ WNDCLASSW wclass;
- if (hr != S_OK)
- ERR("DllGetClassObject returned error 0x%08x\n", hr);
- }
+ /* 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);
+}
- return hr;
+static void COMPOBJ_UninitProcess( void )
+{
+ UnregisterClassW(wszAptWinClass, hProxyDll);
}
-static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
+static void COM_TlsDestroy(void)
{
- struct apartment_loaded_dll *entry, *next;
- EnterCriticalSection(&apt->cs);
- LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
+ struct oletls *info = NtCurrentTeb()->ReservedForOle;
+ if (info)
{
- if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
- {
- DWORD real_delay = delay;
-
- if (real_delay == INFINITE)
- {
- 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;
+ 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(&apt->cs);
}
-/*****************************************************************************
- * This section contains OpenDllList implementation
+/******************************************************************************
+ * CoBuildVersion [OLE32.@]
+ *
+ * Gets the build version of the DLL.
+ *
+ * PARAMS
+ *
+ * RETURNS
+ * Current build version, hiword is majornumber, loword is minornumber
*/
-
-/* caller must ensure that library_name is not already in the open dll list */
-static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
+DWORD WINAPI CoBuildVersion(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
- {
- hr = E_OUTOFMEMORY;
- FreeLibrary(hLibrary);
- }
- *ret = entry;
- }
+ TRACE("Returning version %d, build %d.\n", rmm, rup);
+ return (rmm<<16)+rup;
+}
- LeaveCriticalSection( &csOpenDllList );
+/******************************************************************************
+ * CoRegisterInitializeSpy [OLE32.@]
+ *
+ * Add a Spy that watches CoInitializeEx calls
+ *
+ * PARAMS
+ * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
+ * cookie [II] cookie receiver
+ *
+ * RETURNS
+ * Success: S_OK if not already initialized, S_FALSE otherwise.
+ * Failure: HRESULT code.
+ *
+ * SEE ALSO
+ * CoInitializeEx
+ */
+HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
+{
+ struct oletls *info = COM_CurrentInfo();
+ HRESULT hr;
- return hr;
-}
+ TRACE("(%p, %p)\n", spy, cookie);
-static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
-{
- OpenDll *ptr;
- OpenDll *ret = NULL;
- EnterCriticalSection(&csOpenDllList);
- LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
+ if (!spy || !cookie || !info)
{
- if (!strcmpiW(library_name, ptr->library_name) &&
- (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
- {
- ret = ptr;
- break;
- }
+ if (!info)
+ WARN("Could not allocate tls\n");
+ return E_INVALIDARG;
}
- LeaveCriticalSection(&csOpenDllList);
- return ret;
-}
-/* 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)
-{
- if (!InterlockedDecrement(&entry->refs) && free_entry)
+ if (info->spy)
{
- EnterCriticalSection(&csOpenDllList);
- list_remove(&entry->entry);
- LeaveCriticalSection(&csOpenDllList);
-
- TRACE("freeing %p\n", entry->library);
- FreeLibrary(entry->library);
+ FIXME("Already registered?\n");
+ return E_UNEXPECTED;
+ }
- HeapFree(GetProcessHeap(), 0, entry->library_name);
- HeapFree(GetProcessHeap(), 0, entry);
+ hr = IUnknown_QueryInterface(spy, &IID_IInitializeSpy, (void **) &info->spy);
+ if (SUCCEEDED(hr))
+ {
+ cookie->QuadPart = (DWORD_PTR)spy;
+ return S_OK;
}
+ return hr;
}
/******************************************************************************
- * CoBuildVersion [OLE32.@]
- * CoBuildVersion [COMPOBJ.1]
+ * CoRevokeInitializeSpy [OLE32.@]
*
- * Gets the build version of the DLL.
+ * Remove a spy that previously watched CoInitializeEx calls
*
* PARAMS
+ * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
*
* RETURNS
- * Current build version, hiword is majornumber, loword is minornumber
+ * Success: S_OK if a spy is removed
+ * Failure: E_INVALIDARG
+ *
+ * SEE ALSO
+ * CoInitializeEx
*/
-DWORD WINAPI CoBuildVersion(void)
+HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
{
- TRACE("Returning version %d, build %d.\n", rmm, rup);
- return (rmm<<16)+rup;
+ struct oletls *info = COM_CurrentInfo();
+ TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart));
+
+ if (!info || !info->spy || cookie.QuadPart != (DWORD_PTR)info->spy)
+ return E_INVALIDARG;
+
+ IUnknown_Release(info->spy);
+ info->spy = NULL;
+ return S_OK;
}
+
/******************************************************************************
* CoInitialize [OLE32.@]
*
*/
HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
{
+ struct oletls *info = COM_CurrentInfo();
HRESULT hr = S_OK;
APARTMENT *apt;
RunningObjectTableImpl_Initialize();
}
- if (!(apt = COM_CurrentInfo()->apt))
+ if (info->spy)
+ IInitializeSpy_PreInitialize(info->spy, dwCoInit, info->inits);
+
+ if (!(apt = info->apt))
{
apt = apartment_get_or_create(dwCoInit);
if (!apt) return E_OUTOFMEMORY;
else
hr = S_FALSE;
- COM_CurrentInfo()->inits++;
+ info->inits++;
+
+ if (info->spy)
+ IInitializeSpy_PostInitialize(info->spy, hr, dwCoInit, info->inits);
return hr;
}
/* will only happen on OOM */
if (!info) return;
+ if (info->spy)
+ IInitializeSpy_PreUninitialize(info->spy, info->inits);
+
/* sanity check */
if (!info->inits)
{
ERR("Mismatched CoUninitialize\n");
+
+ if (info->spy)
+ IInitializeSpy_PostUninitialize(info->spy, info->inits);
return;
}
ERR( "CoUninitialize() - not CoInitialized.\n" );
InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
}
+ if (info->spy)
+ IInitializeSpy_PostUninitialize(info->spy, info->inits);
}
/******************************************************************************
/******************************************************************************
* CoCreateGuid [OLE32.@]
- * CoCreateGuid [COMPOBJ.73]
*
* Simply forwards to UuidCreate in RPCRT4.
*
*/
HRESULT WINAPI CoCreateGuid(GUID *pguid)
{
- return UuidCreate(pguid);
+ DWORD status = UuidCreate(pguid);
+ if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
+ return HRESULT_FROM_WIN32( status );
+}
+
+static inline BOOL is_valid_hex(WCHAR c)
+{
+ if (!(((c >= '0') && (c <= '9')) ||
+ ((c >= 'a') && (c <= 'f')) ||
+ ((c >= 'A') && (c <= 'F'))))
+ return FALSE;
+ return TRUE;
}
/******************************************************************************
* SEE ALSO
* StringFromCLSID
*/
-static HRESULT WINAPI __CLSIDFromString(LPCWSTR s, CLSID *id)
+static HRESULT __CLSIDFromString(LPCWSTR s, LPCLSID id)
{
int i;
BYTE table[256];
- if (!s) {
+ if (!s || s[0]!='{') {
memset( id, 0, sizeof (CLSID) );
- return S_OK;
- }
-
- /* validate the CLSID string */
- if (strlenW(s) != 38)
+ if(!s) return S_OK;
return CO_E_CLASSSTRING;
-
- if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
- return CO_E_CLASSSTRING;
-
- for (i=1; i<37; i++) {
- if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
- if (!(((s[i] >= '0') && (s[i] <= '9')) ||
- ((s[i] >= 'a') && (s[i] <= 'f')) ||
- ((s[i] >= 'A') && (s[i] <= 'F'))))
- return CO_E_CLASSSTRING;
}
TRACE("%s -> %p\n", debugstr_w(s), id);
/* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
- id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
- table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
- id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
- id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
-
- /* these are just sequential bytes */
- id->Data4[0] = table[s[20]] << 4 | table[s[21]];
- id->Data4[1] = table[s[22]] << 4 | table[s[23]];
- id->Data4[2] = table[s[25]] << 4 | table[s[26]];
- id->Data4[3] = table[s[27]] << 4 | table[s[28]];
- id->Data4[4] = table[s[29]] << 4 | table[s[30]];
- id->Data4[5] = table[s[31]] << 4 | table[s[32]];
- id->Data4[6] = table[s[33]] << 4 | table[s[34]];
- id->Data4[7] = table[s[35]] << 4 | table[s[36]];
+ id->Data1 = 0;
+ for (i = 1; i < 9; i++) {
+ if (!is_valid_hex(s[i])) return CO_E_CLASSSTRING;
+ id->Data1 = (id->Data1 << 4) | table[s[i]];
+ }
+ if (s[9]!='-') return CO_E_CLASSSTRING;
+
+ id->Data2 = 0;
+ for (i = 10; i < 14; i++) {
+ if (!is_valid_hex(s[i])) return CO_E_CLASSSTRING;
+ id->Data2 = (id->Data2 << 4) | table[s[i]];
+ }
+ if (s[14]!='-') return CO_E_CLASSSTRING;
- return S_OK;
+ id->Data3 = 0;
+ for (i = 15; i < 19; i++) {
+ if (!is_valid_hex(s[i])) return CO_E_CLASSSTRING;
+ id->Data3 = (id->Data3 << 4) | table[s[i]];
+ }
+ if (s[19]!='-') return CO_E_CLASSSTRING;
+
+ for (i = 20; i < 37; i+=2) {
+ if (i == 24) {
+ if (s[i]!='-') return CO_E_CLASSSTRING;
+ i++;
+ }
+ if (!is_valid_hex(s[i]) || !is_valid_hex(s[i+1])) return CO_E_CLASSSTRING;
+ id->Data4[(i-20)/2] = table[s[i]] << 4 | table[s[i+1]];
+ }
+
+ if (s[37] == '}' && s[38] == '\0')
+ return S_OK;
+
+ return CO_E_CLASSSTRING;
}
/*****************************************************************************/
-HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
+HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id )
{
HRESULT ret;
ret = __CLSIDFromString(idstr, id);
if(ret != S_OK) { /* It appears a ProgID is also valid */
- ret = CLSIDFromProgID(idstr, id);
+ CLSID tmp_id;
+ ret = CLSIDFromProgID(idstr, &tmp_id);
+ if(SUCCEEDED(ret))
+ *id = tmp_id;
}
return ret;
}
-/* Converts a GUID into the respective string representation. */
-HRESULT WINE_StringFromCLSID(
- const CLSID *id, /* [in] GUID to be converted */
- LPSTR idstr /* [out] pointer to buffer to contain converted guid */
-) {
- static const char hex[] = "0123456789ABCDEF";
- char *s;
- int i;
-
- if (!id)
- { ERR("called with id=Null\n");
- *idstr = 0x00;
- return E_FAIL;
- }
-
- sprintf(idstr, "{%08X-%04X-%04X-%02X%02X-",
- id->Data1, id->Data2, id->Data3,
- id->Data4[0], id->Data4[1]);
- s = &idstr[25];
-
- /* 6 hex bytes */
- for (i = 2; i < 8; i++) {
- *s++ = hex[id->Data4[i]>>4];
- *s++ = hex[id->Data4[i] & 0xf];
- }
-
- *s++ = '}';
- *s++ = '\0';
-
- TRACE("%p->%s\n", id, idstr);
-
- return S_OK;
-}
-
/******************************************************************************
* StringFromCLSID [OLE32.@]
*/
HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
{
- char buf[80];
- HRESULT ret;
- LPMALLOC mllc;
-
- if ((ret = CoGetMalloc(0,&mllc)))
- return ret;
+ HRESULT ret;
+ LPMALLOC mllc;
- ret=WINE_StringFromCLSID(id,buf);
- if (!ret) {
- DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
- *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
- MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
- }
- return ret;
+ if ((ret = CoGetMalloc(0,&mllc))) return ret;
+ if (!(*idstr = IMalloc_Alloc( mllc, CHARS_IN_GUID * sizeof(WCHAR) ))) return E_OUTOFMEMORY;
+ StringFromGUID2( id, *idstr, CHARS_IN_GUID );
+ return S_OK;
}
/******************************************************************************
* StringFromGUID2 [OLE32.@]
- * StringFromGUID2 [COMPOBJ.76]
*
* Modified version of StringFromCLSID that allows you to specify max
* buffer size.
*/
INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
{
- char xguid[80];
-
- if (WINE_StringFromCLSID(id,xguid))
- return 0;
- return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
+ static const WCHAR formatW[] = { '{','%','0','8','X','-','%','0','4','X','-',
+ '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
+ '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
+ '%','0','2','X','%','0','2','X','}',0 };
+ if (!id || cmax < CHARS_IN_GUID) return 0;
+ sprintfW( str, formatW, id->Data1, id->Data2, id->Data3,
+ id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
+ id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
+ return CHARS_IN_GUID;
}
/* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
return CO_E_CLASSSTRING;
}
RegCloseKey(xhkey);
- return CLSIDFromString(buf2,clsid);
+ return __CLSIDFromString(buf2,clsid);
}
}
RegCloseKey(hkey);
- /* We have the CLSid we want back from the registry as a string, so
- lets convert it into a CLSID structure */
+ /* We have the CLSID we want back from the registry as a string, so
+ let's convert it into a CLSID structure */
if (CLSIDFromString(value, pclsid) != NOERROR)
return REGDB_E_IIDNOTREG;
HRESULT hr = S_FALSE;
RegisteredClass *curClass;
- /*
- * Sanity check
- */
- assert(ppUnk!=0);
-
EnterCriticalSection( &csRegisteredClassList );
LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
DWORD flags,
LPDWORD lpdwRegister)
{
+ static LONG next_cookie;
RegisteredClass* newClass;
LPUNKNOWN foundObject;
HRESULT hr;
newClass->pMarshaledData = NULL;
newClass->RpcRegistration = NULL;
- /*
- * Use the address of the chain node as the cookie since we are sure it's
- * unique. FIXME: not on 64-bit platforms.
- */
- newClass->dwCookie = (DWORD)newClass;
+ if (!(newClass->dwCookie = InterlockedIncrement( &next_cookie )))
+ newClass->dwCookie = InterlockedIncrement( &next_cookie );
/*
* Since we're making a copy of the object pointer, we have to increase its
FIXME("Failed to create stream on hglobal, %x\n", hr);
return hr;
}
- hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
+ hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IUnknown,
newClass->classObject, MSHCTX_LOCAL, NULL,
MSHLFLAGS_TABLESTRONG);
if (hr) {
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);
- }
-
- 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};
}
static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll,
- REFCLSID rclsid, REFIID riid, void **ppv)
+ REFCLSID rclsid, REFIID riid,
+ BOOL hostifnecessary, void **ppv)
{
- static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
- static const WCHAR wszFree[] = {'F','r','e','e',0};
- static const WCHAR wszBoth[] = {'B','o','t','h',0};
WCHAR dllpath[MAX_PATH+1];
- WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
+ BOOL apartment_threaded;
- get_threading_model(hkeydll, threading_model, ARRAYSIZE(threading_model));
- /* "Apartment" */
- if (!strcmpiW(threading_model, wszApartment))
- {
- if (apt->multi_threaded)
- return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, hkeydll, rclsid, riid, ppv);
- }
- /* "Free" */
- else if (!strcmpiW(threading_model, wszFree))
- {
- if (!apt->multi_threaded)
- return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, hkeydll, rclsid, riid, ppv);
- }
- /* everything except "Apartment", "Free" and "Both" */
- else if (strcmpiW(threading_model, wszBoth))
+ if (hostifnecessary)
{
- /* everything else is main-threaded */
- if (threading_model[0])
- FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n",
- debugstr_w(threading_model), debugstr_guid(rclsid));
-
- if (apt->multi_threaded || !apt->main)
- return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, hkeydll, rclsid, riid, ppv);
+ static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
+ static const WCHAR wszFree[] = {'F','r','e','e',0};
+ static const WCHAR wszBoth[] = {'B','o','t','h',0};
+ WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
+
+ get_threading_model(hkeydll, threading_model, ARRAYSIZE(threading_model));
+ /* "Apartment" */
+ if (!strcmpiW(threading_model, wszApartment))
+ {
+ apartment_threaded = TRUE;
+ if (apt->multi_threaded)
+ return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, hkeydll, rclsid, riid, ppv);
+ }
+ /* "Free" */
+ else if (!strcmpiW(threading_model, wszFree))
+ {
+ apartment_threaded = FALSE;
+ if (!apt->multi_threaded)
+ return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, hkeydll, rclsid, riid, ppv);
+ }
+ /* everything except "Apartment", "Free" and "Both" */
+ else if (strcmpiW(threading_model, wszBoth))
+ {
+ apartment_threaded = TRUE;
+ /* everything else is main-threaded */
+ if (threading_model[0])
+ FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n",
+ debugstr_w(threading_model), debugstr_guid(rclsid));
+
+ if (apt->multi_threaded || !apt->main)
+ return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, hkeydll, rclsid, riid, ppv);
+ }
+ else
+ apartment_threaded = FALSE;
}
+ else
+ apartment_threaded = !apt->multi_threaded;
if (COM_RegReadPath(hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
{
return REGDB_E_CLASSNOTREG;
}
- return apartment_getclassobject(apt, dllpath,
- !strcmpiW(threading_model, wszApartment),
+ return apartment_getclassobject(apt, dllpath, apartment_threaded,
rclsid, riid, ppv);
}
LPUNKNOWN regClassObject;
HRESULT hres = E_UNEXPECTED;
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;
*ppv = NULL;
- apt = COM_CurrentApt();
- if (!apt)
+ if (!(apt = COM_CurrentApt()))
{
- ERR("apartment not initialised\n");
- return CO_E_NOTINITIALIZED;
+ if (!(apt = apartment_find_multi_threaded()))
+ {
+ ERR("apartment not initialised\n");
+ return CO_E_NOTINITIALIZED;
+ }
+ release_apt = TRUE;
}
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);
}
/*
* is good since we are not returning it in the "out" parameter.
*/
IUnknown_Release(regClassObject);
-
+ if (release_apt) apartment_release(apt);
return hres;
}
HKEY hkey;
if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
+ {
+ if (release_apt) apartment_release(apt);
return FTMarshalCF_Create(iid, ppv);
+ }
hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
if (FAILED(hres))
if (SUCCEEDED(hres))
{
- hres = get_inproc_class_object(apt, hkey, rclsid, iid, ppv);
+ hres = get_inproc_class_object(apt, hkey, rclsid, iid,
+ !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
RegCloseKey(hkey);
}
/* return if we got a class, otherwise fall through to one of the
* other types */
if (SUCCEEDED(hres))
+ {
+ if (release_apt) apartment_release(apt);
return hres;
+ }
}
/* Next try in-process handler */
if (SUCCEEDED(hres))
{
- hres = get_inproc_class_object(apt, hkey, rclsid, iid, ppv);
+ hres = get_inproc_class_object(apt, hkey, rclsid, iid,
+ !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
RegCloseKey(hkey);
}
/* return if we got a class, otherwise fall through to one of the
* other types */
if (SUCCEEDED(hres))
+ {
+ if (release_apt) apartment_release(apt);
return hres;
+ }
}
+ if (release_apt) apartment_release(apt);
/* Next try out of process */
if (CLSCTX_LOCAL_SERVER & dwClsContext)
if (CLSCTX_REMOTE_SERVER & dwClsContext)
{
FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
- hres = E_NOINTERFACE;
+ hres = REGDB_E_CLASSNOTREG;
}
if (FAILED(hres))
{
HRESULT hres;
LPCLASSFACTORY lpclf = 0;
+ APARTMENT *apt;
TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
*/
*ppv = 0;
- if (!COM_CurrentApt())
+ if (!(apt = COM_CurrentApt()))
{
+ if (!(apt = apartment_find_multi_threaded()))
+ {
ERR("apartment not initialised\n");
return CO_E_NOTINITIALIZED;
+ }
+ apartment_release(apt);
}
/*
return S_OK;
}
+ if (IsEqualCLSID(rclsid, &CLSID_ManualResetEvent))
+ return ManualResetEvent_Construct(pUnkOuter, iid, ppv);
+
/*
* Get a class factory to construct the object we want.
*/
hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
IClassFactory_Release(lpclf);
if(FAILED(hres))
- FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
- debugstr_guid(iid), debugstr_guid(rclsid),hres);
+ {
+ if (hres == CLASS_E_NOAGGREGATION && pUnkOuter)
+ FIXME("Class %s does not support aggregation\n", debugstr_guid(rclsid));
+ else
+ FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n", debugstr_guid(iid), debugstr_guid(rclsid),hres);
+ }
return hres;
}
/***********************************************************************
* CoFreeUnusedLibraries [OLE32.@]
- * CoFreeUnusedLibraries [COMPOBJ.17]
*
* Frees any unused libraries. Unused are identified as those that return
* S_OK from their DllCanUnloadNow function.
/***********************************************************************
* CoFileTimeNow [OLE32.@]
- * CoFileTimeNow [COMPOBJ.82]
*
* Retrieves the current time in FILETIME format.
*
if (stubmgr)
{
if (fLock)
- stub_manager_ext_addref(stubmgr, 1);
+ stub_manager_ext_addref(stubmgr, 1, FALSE);
else
- stub_manager_ext_release(stubmgr, 1, fLastUnlockReleases);
+ stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
stub_manager_int_release(stubmgr);
if (stubmgr)
{
- stub_manager_ext_addref(stubmgr, 1);
+ stub_manager_ext_addref(stubmgr, 1, FALSE);
stub_manager_int_release(stubmgr);
}
if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
{
if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
- !CLSIDFromString(auto_treat_as, &id))
+ CLSIDFromString(auto_treat_as, &id) == S_OK)
{
if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
{
HRESULT res = S_OK;
LONG len = sizeof(szClsidNew);
- FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
- memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
+ TRACE("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
+ *clsidNew = *clsidOld; /* copy over old value */
res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
if (FAILED(res))
+ {
+ res = S_FALSE;
goto done;
+ }
if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
{
res = S_FALSE;
/******************************************************************************
* CoGetCurrentProcess [OLE32.@]
- * CoGetCurrentProcess [COMPOBJ.34]
*
* Gets the current process ID.
*
*/
HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
{
- FIXME("(%s, %p): stub\n", debugstr_guid(riid), ppv);
+ struct oletls *info = COM_CurrentInfo();
- *ppv = NULL;
- return E_NOINTERFACE;
+ TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
+
+ if (!info)
+ return E_OUTOFMEMORY;
+
+ if (!info->call_state)
+ return RPC_E_CALL_COMPLETE;
+
+ return IUnknown_QueryInterface(info->call_state, riid, ppv);
+}
+
+/***********************************************************************
+ * CoSwitchCallContext [OLE32.@]
+ *
+ * Switches the context of the currently executing server call in the current
+ * thread.
+ *
+ * PARAMS
+ * pObject [I] Pointer to new context object
+ * ppOldObject [O] Pointer to memory that will receive old context object pointer
+ *
+ * RETURNS
+ * Success: S_OK.
+ * Failure: HRESULT code.
+ */
+HRESULT WINAPI CoSwitchCallContext(IUnknown *pObject, IUnknown **ppOldObject)
+{
+ struct oletls *info = COM_CurrentInfo();
+
+ TRACE("(%p, %p)\n", pObject, ppOldObject);
+
+ if (!info)
+ return E_OUTOFMEMORY;
+
+ *ppOldObject = info->call_state;
+ info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */
+
+ return S_OK;
}
/***********************************************************************
/* first try to retrieve messages for incoming COM calls to the apartment window */
return PeekMessageW(msg, apt->win, WM_USER, WM_APP - 1, PM_REMOVE|PM_NOYIELD) ||
/* next retrieve other messages necessary for the app to remain responsive */
- PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_POSTMESSAGE|PM_REMOVE|PM_NOYIELD);
+ PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE|PM_NOYIELD) ||
+ PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD);
}
/***********************************************************************
DWORD now = GetTickCount();
DWORD res;
- if ((dwTimeout != INFINITE) && (start_time + dwTimeout >= now))
+ if (now - start_time > dwTimeout)
{
hr = RPC_S_CALLPENDING;
break;
if (message_loop)
{
- DWORD wait_flags = (dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0 |
- (dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0;
+ DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
+ ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
TRACE("waiting for rpc completion or window message\n");
(dwFlags & COWAIT_ALERTABLE) ? TRUE : FALSE);
}
- if ((res >= WAIT_OBJECT_0) && (res < WAIT_OBJECT_0 + cHandles))
- {
- /* handle signaled, store index */
- *lpdwindex = (res - WAIT_OBJECT_0);
- break;
- }
- else if (res == WAIT_TIMEOUT)
+ switch (res)
{
+ case WAIT_TIMEOUT:
hr = RPC_S_CALLPENDING;
break;
- }
- else
- {
- ERR("Unexpected wait termination: %d, %d\n", res, GetLastError());
- hr = E_UNEXPECTED;
+ case WAIT_FAILED:
+ hr = HRESULT_FROM_WIN32( GetLastError() );
+ break;
+ default:
+ *lpdwindex = res;
break;
}
+ break;
}
TRACE("-- 0x%08x\n", hr);
return hr;
/***********************************************************************
* CoGetObject [OLE32.@]
*
- * Gets the object named by coverting the name to a moniker and binding to it.
+ * Gets the object named by converting the name to a moniker and binding to it.
*
* PARAMS
* pszName [I] String representing the object.
return RPC_RegisterChannelHook(guidExtension, pChannelHook);
}
+typedef struct Context
+{
+ IComThreadingInfo IComThreadingInfo_iface;
+ IContextCallback IContextCallback_iface;
+ IObjContext IObjContext_iface;
+ LONG refs;
+ APTTYPE apttype;
+} Context;
+
+static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface )
+{
+ return CONTAINING_RECORD(iface, Context, IComThreadingInfo_iface);
+}
+
+static inline Context *impl_from_IContextCallback( IContextCallback *iface )
+{
+ return CONTAINING_RECORD(iface, Context, IContextCallback_iface);
+}
+
+static inline Context *impl_from_IObjContext( IObjContext *iface )
+{
+ return CONTAINING_RECORD(iface, Context, IObjContext_iface);
+}
+
+static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv)
+{
+ *ppv = NULL;
+
+ if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
+ IsEqualIID(riid, &IID_IUnknown))
+ {
+ *ppv = &iface->IComThreadingInfo_iface;
+ }
+ else if (IsEqualIID(riid, &IID_IContextCallback))
+ {
+ *ppv = &iface->IContextCallback_iface;
+ }
+ else if (IsEqualIID(riid, &IID_IObjContext))
+ {
+ *ppv = &iface->IObjContext_iface;
+ }
+
+ if (*ppv)
+ {
+ IUnknown_AddRef((IUnknown*)*ppv);
+ return S_OK;
+ }
+
+ FIXME("interface not implemented %s\n", debugstr_guid(riid));
+ return E_NOINTERFACE;
+}
+
+static ULONG Context_AddRef(Context *This)
+{
+ return InterlockedIncrement(&This->refs);
+}
+
+static ULONG Context_Release(Context *This)
+{
+ ULONG refs = InterlockedDecrement(&This->refs);
+ if (!refs)
+ HeapFree(GetProcessHeap(), 0, This);
+ return refs;
+}
+
+static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv)
+{
+ Context *This = impl_from_IComThreadingInfo(iface);
+ return Context_QueryInterface(This, riid, ppv);
+}
+
+static ULONG WINAPI Context_CTI_AddRef(IComThreadingInfo *iface)
+{
+ Context *This = impl_from_IComThreadingInfo(iface);
+ return Context_AddRef(This);
+}
+
+static ULONG WINAPI Context_CTI_Release(IComThreadingInfo *iface)
+{
+ Context *This = impl_from_IComThreadingInfo(iface);
+ return Context_Release(This);
+}
+
+static HRESULT WINAPI Context_CTI_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
+{
+ Context *This = impl_from_IComThreadingInfo(iface);
+
+ TRACE("(%p)\n", apttype);
+
+ *apttype = This->apttype;
+ return S_OK;
+}
+
+static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
+{
+ Context *This = impl_from_IComThreadingInfo(iface);
+
+ TRACE("(%p)\n", thdtype);
+
+ switch (This->apttype)
+ {
+ case APTTYPE_STA:
+ case APTTYPE_MAINSTA:
+ *thdtype = THDTYPE_PROCESSMESSAGES;
+ break;
+ default:
+ *thdtype = THDTYPE_BLOCKMESSAGES;
+ break;
+ }
+ return S_OK;
+}
+
+static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
+{
+ FIXME("(%p): stub\n", logical_thread_id);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
+{
+ FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
+ return E_NOTIMPL;
+}
+
+static const IComThreadingInfoVtbl Context_Threading_Vtbl =
+{
+ Context_CTI_QueryInterface,
+ Context_CTI_AddRef,
+ Context_CTI_Release,
+ Context_CTI_GetCurrentApartmentType,
+ Context_CTI_GetCurrentThreadType,
+ Context_CTI_GetCurrentLogicalThreadId,
+ Context_CTI_SetCurrentLogicalThreadId
+};
+
+static HRESULT WINAPI Context_CC_QueryInterface(IContextCallback *iface, REFIID riid, LPVOID *ppv)
+{
+ Context *This = impl_from_IContextCallback(iface);
+ return Context_QueryInterface(This, riid, ppv);
+}
+
+static ULONG WINAPI Context_CC_AddRef(IContextCallback *iface)
+{
+ Context *This = impl_from_IContextCallback(iface);
+ return Context_AddRef(This);
+}
+
+static ULONG WINAPI Context_CC_Release(IContextCallback *iface)
+{
+ Context *This = impl_from_IContextCallback(iface);
+ return Context_Release(This);
+}
+
+static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback,
+ ComCallData *param, REFIID riid, int method, IUnknown *punk)
+{
+ Context *This = impl_from_IContextCallback(iface);
+
+ FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk);
+ return E_NOTIMPL;
+}
+
+static const IContextCallbackVtbl Context_Callback_Vtbl =
+{
+ Context_CC_QueryInterface,
+ Context_CC_AddRef,
+ Context_CC_Release,
+ 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.@]
+ *
+ * Retrieves an object associated with the current context (i.e. apartment).
+ *
+ * PARAMS
+ * riid [I] ID of the interface of the object to retrieve.
+ * ppv [O] Address where object will be stored on return.
+ *
+ * RETURNS
+ * Success: S_OK.
+ * Failure: HRESULT code.
+ */
+HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
+{
+ APARTMENT *apt = COM_CurrentApt();
+ Context *context;
+ HRESULT hr;
+
+ TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
+
+ *ppv = NULL;
+ if (!apt)
+ {
+ if (!(apt = apartment_find_multi_threaded()))
+ {
+ ERR("apartment not initialised\n");
+ return CO_E_NOTINITIALIZED;
+ }
+ apartment_release(apt);
+ }
+
+ context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
+ if (!context)
+ return E_OUTOFMEMORY;
+
+ context->IComThreadingInfo_iface.lpVtbl = &Context_Threading_Vtbl;
+ context->IContextCallback_iface.lpVtbl = &Context_Callback_Vtbl;
+ context->IObjContext_iface.lpVtbl = &Context_Object_Vtbl;
+ context->refs = 1;
+ if (apt->multi_threaded)
+ context->apttype = APTTYPE_MTA;
+ else if (apt->main)
+ context->apttype = APTTYPE_MAINSTA;
+ else
+ context->apttype = APTTYPE_STA;
+
+ hr = IUnknown_QueryInterface((IUnknown *)&context->IComThreadingInfo_iface, riid, ppv);
+ IUnknown_Release((IUnknown *)&context->IComThreadingInfo_iface);
+
+ return hr;
+}
+
+
+/***********************************************************************
+ * CoGetContextToken [OLE32.@]
+ */
+HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
+{
+ struct oletls *info = COM_CurrentInfo();
+
+ TRACE("(%p)\n", token);
+
+ if (!info)
+ return E_OUTOFMEMORY;
+
+ 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;
+}
+
+HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
+{
+ static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
+ HKEY hkey;
+ HRESULT hres;
+
+ hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
+ if (SUCCEEDED(hres))
+ {
+ WCHAR dllpath[MAX_PATH+1];
+
+ if (COM_RegReadPath(hkey, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) == ERROR_SUCCESS)
+ {
+ static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
+ if (!strcmpiW(dllpath, wszOle32))
+ {
+ RegCloseKey(hkey);
+ return HandlerCF_Create(rclsid, riid, ppv);
+ }
+ }
+ else
+ WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath));
+ RegCloseKey(hkey);
+ }
+
+ return CLASS_E_CLASSNOTAVAILABLE;
+}
+
/***********************************************************************
* DllMain (OLE32.@)
*/
switch(fdwReason) {
case DLL_PROCESS_ATTACH:
- OLE32_hInstance = hinstDLL;
+ hProxyDll = hinstDLL;
COMPOBJ_InitProcess();
- if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1);
break;
case DLL_PROCESS_DETACH:
- if (TRACE_ON(ole)) CoRevokeMallocSpy();
- OLEDD_UnInitialize();
COMPOBJ_UninitProcess();
RPC_UnregisterAllChannelHooks();
- OLE32_hInstance = 0;
+ COMPOBJ_DllList_Free();
break;
case DLL_THREAD_DETACH:
return TRUE;
}
-/* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */
+/***********************************************************************
+ * DllRegisterServer (OLE32.@)
+ */
+HRESULT WINAPI DllRegisterServer(void)
+{
+ return OLE32_DllRegisterServer();
+}
+
+/***********************************************************************
+ * DllUnregisterServer (OLE32.@)
+ */
+HRESULT WINAPI DllUnregisterServer(void)
+{
+ return OLE32_DllUnregisterServer();
+}