ole32: Update comments in compobj.c.
[wine/wine64.git] / dlls / ole32 / compobj.c
blob37907eccca181327d5ac79152db20e4733391e06
1 /*
2 * COMPOBJ library
4 * Copyright 1995 Martin von Loewis
5 * Copyright 1998 Justin Bradford
6 * Copyright 1999 Francis Beaudet
7 * Copyright 1999 Sylvain St-Germain
8 * Copyright 2002 Marcus Meissner
9 * Copyright 2004 Mike Hearn
10 * Copyright 2005-2006 Robert Shearman (for CodeWeavers)
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 * Note
27 * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED
28 * Therefore do not test against COINIT_MULTITHREADED
30 * TODO list: (items bunched together depend on each other)
32 * - Implement the service control manager (in rpcss) to keep track
33 * of registered class objects: ISCM::ServerRegisterClsid et al
34 * - Implement the OXID resolver so we don't need magic endpoint names for
35 * clients and servers to meet up
39 #include "config.h"
41 #include <stdarg.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <assert.h>
46 #define COBJMACROS
47 #define NONAMELESSUNION
48 #define NONAMELESSSTRUCT
50 #include "windef.h"
51 #include "winbase.h"
52 #include "winerror.h"
53 #include "winreg.h"
54 #include "winuser.h"
55 #include "objbase.h"
56 #include "ole2.h"
57 #include "ole2ver.h"
59 #include "compobj_private.h"
61 #include "wine/unicode.h"
62 #include "wine/debug.h"
64 WINE_DEFAULT_DEBUG_CHANNEL(ole);
66 HINSTANCE OLE32_hInstance = 0;
68 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
70 /****************************************************************************
71 * This section defines variables internal to the COM module.
74 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
75 DWORD dwClsContext, LPUNKNOWN* ppUnk);
76 static void COM_RevokeAllClasses(const struct apartment *apt);
77 static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll, REFCLSID rclsid, REFIID riid, BOOL hostifnecessary, void **ppv);
79 static APARTMENT *MTA; /* protected by csApartment */
80 static APARTMENT *MainApartment; /* the first STA apartment */
81 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
83 static CRITICAL_SECTION csApartment;
84 static CRITICAL_SECTION_DEBUG critsect_debug =
86 0, 0, &csApartment,
87 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
88 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
90 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
92 struct registered_psclsid
94 struct list entry;
95 IID iid;
96 CLSID clsid;
100 * This lock count counts the number of times CoInitialize is called. It is
101 * decreased every time CoUninitialize is called. When it hits 0, the COM
102 * libraries are freed
104 static LONG s_COMLockCount = 0;
105 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
106 static LONG s_COMServerProcessReferences = 0;
109 * This linked list contains the list of registered class objects. These
110 * are mostly used to register the factories for out-of-proc servers of OLE
111 * objects.
113 * TODO: Make this data structure aware of inter-process communication. This
114 * means that parts of this will be exported to rpcss.
116 typedef struct tagRegisteredClass
118 struct list entry;
119 CLSID classIdentifier;
120 OXID apartment_id;
121 LPUNKNOWN classObject;
122 DWORD runContext;
123 DWORD connectFlags;
124 DWORD dwCookie;
125 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
126 void *RpcRegistration;
127 } RegisteredClass;
129 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList);
131 static CRITICAL_SECTION csRegisteredClassList;
132 static CRITICAL_SECTION_DEBUG class_cs_debug =
134 0, 0, &csRegisteredClassList,
135 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
136 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
138 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
140 /*****************************************************************************
141 * This section contains OpenDllList definitions
143 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
144 * other functions that do LoadLibrary _without_ giving back a HMODULE.
145 * Without this list these handles would never be freed.
147 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
148 * next unload-call but not before 600 sec.
151 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
152 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
154 typedef struct tagOpenDll
156 LONG refs;
157 LPWSTR library_name;
158 HANDLE library;
159 DllGetClassObjectFunc DllGetClassObject;
160 DllCanUnloadNowFunc DllCanUnloadNow;
161 struct list entry;
162 } OpenDll;
164 static struct list openDllList = LIST_INIT(openDllList);
166 static CRITICAL_SECTION csOpenDllList;
167 static CRITICAL_SECTION_DEBUG dll_cs_debug =
169 0, 0, &csOpenDllList,
170 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
171 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
173 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
175 struct apartment_loaded_dll
177 struct list entry;
178 OpenDll *dll;
179 DWORD unload_time;
180 BOOL multi_threaded;
183 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',' ',
184 '0','x','#','#','#','#','#','#','#','#',' ',0};
185 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
186 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
187 BOOL apartment_threaded,
188 REFCLSID rclsid, REFIID riid, void **ppv);
189 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay);
191 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret);
192 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name);
193 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry);
195 static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen);
197 static void COMPOBJ_InitProcess( void )
199 WNDCLASSW wclass;
201 /* Dispatching to the correct thread in an apartment is done through
202 * window messages rather than RPC transports. When an interface is
203 * marshalled into another apartment in the same process, a window of the
204 * following class is created. The *caller* of CoMarshalInterface (i.e., the
205 * application) is responsible for pumping the message loop in that thread.
206 * The WM_USER messages which point to the RPCs are then dispatched to
207 * apartment_wndproc by the user's code from the apartment in which the
208 * interface was unmarshalled.
210 memset(&wclass, 0, sizeof(wclass));
211 wclass.lpfnWndProc = apartment_wndproc;
212 wclass.hInstance = OLE32_hInstance;
213 wclass.lpszClassName = wszAptWinClass;
214 RegisterClassW(&wclass);
217 static void COMPOBJ_UninitProcess( void )
219 UnregisterClassW(wszAptWinClass, OLE32_hInstance);
222 static void COM_TlsDestroy(void)
224 struct oletls *info = NtCurrentTeb()->ReservedForOle;
225 if (info)
227 if (info->apt) apartment_release(info->apt);
228 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
229 if (info->state) IUnknown_Release(info->state);
230 HeapFree(GetProcessHeap(), 0, info);
231 NtCurrentTeb()->ReservedForOle = NULL;
235 /******************************************************************************
236 * Manage apartments.
239 /* allocates memory and fills in the necessary fields for a new apartment
240 * object. must be called inside apartment cs */
241 static APARTMENT *apartment_construct(DWORD model)
243 APARTMENT *apt;
245 TRACE("creating new apartment, model=%d\n", model);
247 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
248 apt->tid = GetCurrentThreadId();
250 list_init(&apt->proxies);
251 list_init(&apt->stubmgrs);
252 list_init(&apt->psclsids);
253 list_init(&apt->loaded_dlls);
254 apt->ipidc = 0;
255 apt->refs = 1;
256 apt->remunk_exported = FALSE;
257 apt->oidc = 1;
258 InitializeCriticalSection(&apt->cs);
259 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
261 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
263 if (apt->multi_threaded)
265 /* FIXME: should be randomly generated by in an RPC call to rpcss */
266 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
268 else
270 /* FIXME: should be randomly generated by in an RPC call to rpcss */
271 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
274 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
276 list_add_head(&apts, &apt->entry);
278 return apt;
281 /* gets and existing apartment if one exists or otherwise creates an apartment
282 * structure which stores OLE apartment-local information and stores a pointer
283 * to it in the thread-local storage */
284 static APARTMENT *apartment_get_or_create(DWORD model)
286 APARTMENT *apt = COM_CurrentApt();
288 if (!apt)
290 if (model & COINIT_APARTMENTTHREADED)
292 EnterCriticalSection(&csApartment);
294 apt = apartment_construct(model);
295 if (!MainApartment)
297 MainApartment = apt;
298 apt->main = TRUE;
299 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
302 LeaveCriticalSection(&csApartment);
304 if (apt->main)
305 apartment_createwindowifneeded(apt);
307 else
309 EnterCriticalSection(&csApartment);
311 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
312 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
313 * in a process */
314 if (MTA)
316 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
317 apartment_addref(MTA);
319 else
320 MTA = apartment_construct(model);
322 apt = MTA;
324 LeaveCriticalSection(&csApartment);
326 COM_CurrentInfo()->apt = apt;
329 return apt;
332 static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model)
334 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
337 DWORD apartment_addref(struct apartment *apt)
339 DWORD refs = InterlockedIncrement(&apt->refs);
340 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
341 return refs;
344 DWORD apartment_release(struct apartment *apt)
346 DWORD ret;
348 EnterCriticalSection(&csApartment);
350 ret = InterlockedDecrement(&apt->refs);
351 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
352 /* destruction stuff that needs to happen under csApartment CS */
353 if (ret == 0)
355 if (apt == MTA) MTA = NULL;
356 else if (apt == MainApartment) MainApartment = NULL;
357 list_remove(&apt->entry);
360 LeaveCriticalSection(&csApartment);
362 if (ret == 0)
364 struct list *cursor, *cursor2;
366 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
368 /* Release the references to the registered class objects */
369 COM_RevokeAllClasses(apt);
371 /* no locking is needed for this apartment, because no other thread
372 * can access it at this point */
374 apartment_disconnectproxies(apt);
376 if (apt->win) DestroyWindow(apt->win);
377 if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0);
379 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
381 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
382 /* release the implicit reference given by the fact that the
383 * stub has external references (it must do since it is in the
384 * stub manager list in the apartment and all non-apartment users
385 * must have a ref on the apartment and so it cannot be destroyed).
387 stub_manager_int_release(stubmgr);
390 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->psclsids)
392 struct registered_psclsid *registered_psclsid =
393 LIST_ENTRY(cursor, struct registered_psclsid, entry);
395 list_remove(&registered_psclsid->entry);
396 HeapFree(GetProcessHeap(), 0, registered_psclsid);
399 /* if this assert fires, then another thread took a reference to a
400 * stub manager without taking a reference to the containing
401 * apartment, which it must do. */
402 assert(list_empty(&apt->stubmgrs));
404 if (apt->filter) IUnknown_Release(apt->filter);
406 /* free as many unused libraries as possible... */
407 apartment_freeunusedlibraries(apt, 0);
409 /* ... and free the memory for the apartment loaded dll entry and
410 * release the dll list reference without freeing the library for the
411 * rest */
412 while ((cursor = list_head(&apt->loaded_dlls)))
414 struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
415 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE);
416 list_remove(cursor);
417 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
420 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
421 DeleteCriticalSection(&apt->cs);
423 HeapFree(GetProcessHeap(), 0, apt);
426 return ret;
429 /* The given OXID must be local to this process:
431 * The ref parameter is here mostly to ensure people remember that
432 * they get one, you should normally take a ref for thread safety.
434 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
436 APARTMENT *result = NULL;
437 struct list *cursor;
439 EnterCriticalSection(&csApartment);
440 LIST_FOR_EACH( cursor, &apts )
442 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
443 if (apt->oxid == oxid)
445 result = apt;
446 if (ref) apartment_addref(result);
447 break;
450 LeaveCriticalSection(&csApartment);
452 return result;
455 /* gets the apartment which has a given creator thread ID. The caller must
456 * release the reference from the apartment as soon as the apartment pointer
457 * is no longer required. */
458 APARTMENT *apartment_findfromtid(DWORD tid)
460 APARTMENT *result = NULL;
461 struct list *cursor;
463 EnterCriticalSection(&csApartment);
464 LIST_FOR_EACH( cursor, &apts )
466 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
467 if (apt->tid == tid)
469 result = apt;
470 apartment_addref(result);
471 break;
474 LeaveCriticalSection(&csApartment);
476 return result;
479 /* gets the main apartment if it exists. The caller must
480 * release the reference from the apartment as soon as the apartment pointer
481 * is no longer required. */
482 static APARTMENT *apartment_findmain(void)
484 APARTMENT *result;
486 EnterCriticalSection(&csApartment);
488 result = MainApartment;
489 if (result) apartment_addref(result);
491 LeaveCriticalSection(&csApartment);
493 return result;
496 struct host_object_params
498 HKEY hkeydll;
499 CLSID clsid; /* clsid of object to marshal */
500 IID iid; /* interface to marshal */
501 HANDLE event; /* event signalling when ready for multi-threaded case */
502 HRESULT hr; /* result for multi-threaded case */
503 IStream *stream; /* stream that the object will be marshaled into */
504 BOOL apartment_threaded; /* is the component purely apartment-threaded? */
507 static HRESULT apartment_hostobject(struct apartment *apt,
508 const struct host_object_params *params)
510 IUnknown *object;
511 HRESULT hr;
512 static const LARGE_INTEGER llZero;
513 WCHAR dllpath[MAX_PATH+1];
515 TRACE("clsid %s, iid %s\n", debugstr_guid(&params->clsid), debugstr_guid(&params->iid));
517 if (COM_RegReadPath(params->hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
519 /* failure: CLSID is not found in registry */
520 WARN("class %s not registered inproc\n", debugstr_guid(&params->clsid));
521 return REGDB_E_CLASSNOTREG;
524 hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded,
525 &params->clsid, &params->iid, (void **)&object);
526 if (FAILED(hr))
527 return hr;
529 hr = CoMarshalInterface(params->stream, &params->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
530 if (FAILED(hr))
531 IUnknown_Release(object);
532 IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
534 return hr;
537 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
539 switch (msg)
541 case DM_EXECUTERPC:
542 RPC_ExecuteCall((struct dispatch_params *)lParam);
543 return 0;
544 case DM_HOSTOBJECT:
545 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam);
546 default:
547 return DefWindowProcW(hWnd, msg, wParam, lParam);
551 struct host_thread_params
553 COINIT threading_model;
554 HANDLE ready_event;
555 HWND apartment_hwnd;
558 /* thread for hosting an object to allow an object to appear to be created in
559 * an apartment with an incompatible threading model */
560 static DWORD CALLBACK apartment_hostobject_thread(LPVOID p)
562 struct host_thread_params *params = p;
563 MSG msg;
564 HRESULT hr;
565 struct apartment *apt;
567 TRACE("\n");
569 hr = CoInitializeEx(NULL, params->threading_model);
570 if (FAILED(hr)) return hr;
572 apt = COM_CurrentApt();
573 if (params->threading_model == COINIT_APARTMENTTHREADED)
575 apartment_createwindowifneeded(apt);
576 params->apartment_hwnd = apartment_getwindow(apt);
578 else
579 params->apartment_hwnd = NULL;
581 /* force the message queue to be created before signaling parent thread */
582 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
584 SetEvent(params->ready_event);
585 params = NULL; /* can't touch params after here as it may be invalid */
587 while (GetMessageW(&msg, NULL, 0, 0))
589 if (!msg.hwnd && (msg.message == DM_HOSTOBJECT))
591 struct host_object_params *obj_params = (struct host_object_params *)msg.lParam;
592 obj_params->hr = apartment_hostobject(apt, obj_params);
593 SetEvent(obj_params->event);
595 else
597 TranslateMessage(&msg);
598 DispatchMessageW(&msg);
602 TRACE("exiting\n");
604 CoUninitialize();
606 return S_OK;
609 /* finds or creates a host apartment, creates the object inside it and returns
610 * a proxy to it so that the object can be used in the apartment of the
611 * caller of this function */
612 static HRESULT apartment_hostobject_in_hostapt(
613 struct apartment *apt, BOOL multi_threaded, BOOL main_apartment,
614 HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
616 struct host_object_params params;
617 HWND apartment_hwnd = NULL;
618 DWORD apartment_tid = 0;
619 HRESULT hr;
621 if (!multi_threaded && main_apartment)
623 APARTMENT *host_apt = apartment_findmain();
624 if (host_apt)
626 apartment_hwnd = apartment_getwindow(host_apt);
627 apartment_release(host_apt);
631 if (!apartment_hwnd)
633 EnterCriticalSection(&apt->cs);
635 if (!apt->host_apt_tid)
637 struct host_thread_params thread_params;
638 HANDLE handles[2];
639 DWORD wait_value;
641 thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED;
642 handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
643 thread_params.apartment_hwnd = NULL;
644 handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid);
645 if (!handles[1])
647 CloseHandle(handles[0]);
648 LeaveCriticalSection(&apt->cs);
649 return E_OUTOFMEMORY;
651 wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
652 CloseHandle(handles[0]);
653 CloseHandle(handles[1]);
654 if (wait_value == WAIT_OBJECT_0)
655 apt->host_apt_hwnd = thread_params.apartment_hwnd;
656 else
658 LeaveCriticalSection(&apt->cs);
659 return E_OUTOFMEMORY;
663 if (multi_threaded || !main_apartment)
665 apartment_hwnd = apt->host_apt_hwnd;
666 apartment_tid = apt->host_apt_tid;
669 LeaveCriticalSection(&apt->cs);
672 /* another thread may have become the main apartment in the time it took
673 * us to create the thread for the host apartment */
674 if (!apartment_hwnd && !multi_threaded && main_apartment)
676 APARTMENT *host_apt = apartment_findmain();
677 if (host_apt)
679 apartment_hwnd = apartment_getwindow(host_apt);
680 apartment_release(host_apt);
684 params.hkeydll = hkeydll;
685 params.clsid = *rclsid;
686 params.iid = *riid;
687 hr = CreateStreamOnHGlobal(NULL, TRUE, &params.stream);
688 if (FAILED(hr))
689 return hr;
690 params.apartment_threaded = !multi_threaded;
691 if (multi_threaded)
693 params.hr = S_OK;
694 params.event = CreateEventW(NULL, FALSE, FALSE, NULL);
695 if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)&params))
696 hr = E_OUTOFMEMORY;
697 else
699 WaitForSingleObject(params.event, INFINITE);
700 hr = params.hr;
702 CloseHandle(params.event);
704 else
706 if (!apartment_hwnd)
708 ERR("host apartment didn't create window\n");
709 hr = E_OUTOFMEMORY;
711 else
712 hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)&params);
714 if (SUCCEEDED(hr))
715 hr = CoUnmarshalInterface(params.stream, riid, ppv);
716 IStream_Release(params.stream);
717 return hr;
720 /* create a window for the apartment or return the current one if one has
721 * already been created */
722 HRESULT apartment_createwindowifneeded(struct apartment *apt)
724 if (apt->multi_threaded)
725 return S_OK;
727 if (!apt->win)
729 HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0,
730 0, 0, 0, 0,
731 HWND_MESSAGE, 0, OLE32_hInstance, NULL);
732 if (!hwnd)
734 ERR("CreateWindow failed with error %d\n", GetLastError());
735 return HRESULT_FROM_WIN32(GetLastError());
737 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
738 /* someone beat us to it */
739 DestroyWindow(hwnd);
742 return S_OK;
745 /* retrieves the window for the main- or apartment-threaded apartment */
746 HWND apartment_getwindow(const struct apartment *apt)
748 assert(!apt->multi_threaded);
749 return apt->win;
752 void apartment_joinmta(void)
754 apartment_addref(MTA);
755 COM_CurrentInfo()->apt = MTA;
758 /* gets the specified class object by loading the appropriate DLL, if
759 * necessary and calls the DllGetClassObject function for the DLL */
760 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
761 BOOL apartment_threaded,
762 REFCLSID rclsid, REFIID riid, void **ppv)
764 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
765 HRESULT hr = S_OK;
766 BOOL found = FALSE;
767 struct apartment_loaded_dll *apartment_loaded_dll;
769 if (!strcmpiW(dllpath, wszOle32))
771 /* we don't need to control the lifetime of this dll, so use the local
772 * implementation of DllGetClassObject directly */
773 TRACE("calling ole32!DllGetClassObject\n");
774 hr = DllGetClassObject(rclsid, riid, ppv);
776 if (hr != S_OK)
777 ERR("DllGetClassObject returned error 0x%08x\n", hr);
779 return hr;
782 EnterCriticalSection(&apt->cs);
784 LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
785 if (!strcmpiW(dllpath, apartment_loaded_dll->dll->library_name))
787 TRACE("found %s already loaded\n", debugstr_w(dllpath));
788 found = TRUE;
789 break;
792 if (!found)
794 apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll));
795 if (!apartment_loaded_dll)
796 hr = E_OUTOFMEMORY;
797 if (SUCCEEDED(hr))
799 apartment_loaded_dll->unload_time = 0;
800 apartment_loaded_dll->multi_threaded = FALSE;
801 hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll );
802 if (FAILED(hr))
803 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
805 if (SUCCEEDED(hr))
807 TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
808 list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry);
812 LeaveCriticalSection(&apt->cs);
814 if (SUCCEEDED(hr))
816 /* one component being multi-threaded overrides any number of
817 * apartment-threaded components */
818 if (!apartment_threaded)
819 apartment_loaded_dll->multi_threaded = TRUE;
821 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
822 /* OK: get the ClassObject */
823 hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv);
825 if (hr != S_OK)
826 ERR("DllGetClassObject returned error 0x%08x\n", hr);
829 return hr;
832 /* frees unused libraries loaded by apartment_getclassobject by calling the
833 * DLL's DllCanUnloadNow entry point */
834 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
836 struct apartment_loaded_dll *entry, *next;
837 EnterCriticalSection(&apt->cs);
838 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
840 if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
842 DWORD real_delay = delay;
844 if (real_delay == INFINITE)
846 /* DLLs that return multi-threaded objects aren't unloaded
847 * straight away to cope for programs that have races between
848 * last object destruction and threads in the DLLs that haven't
849 * finished, despite DllCanUnloadNow returning S_OK */
850 if (entry->multi_threaded)
851 real_delay = 10 * 60 * 1000; /* 10 minutes */
852 else
853 real_delay = 0;
856 if (!real_delay || (entry->unload_time && (entry->unload_time < GetTickCount())))
858 list_remove(&entry->entry);
859 COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE);
860 HeapFree(GetProcessHeap(), 0, entry);
862 else
863 entry->unload_time = GetTickCount() + real_delay;
865 else if (entry->unload_time)
866 entry->unload_time = 0;
868 LeaveCriticalSection(&apt->cs);
871 /*****************************************************************************
872 * This section contains OpenDllList implementation
875 /* caller must ensure that library_name is not already in the open dll list */
876 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
878 OpenDll *entry;
879 int len;
880 HRESULT hr = S_OK;
881 HANDLE hLibrary;
882 DllCanUnloadNowFunc DllCanUnloadNow;
883 DllGetClassObjectFunc DllGetClassObject;
885 TRACE("\n");
887 *ret = COMPOBJ_DllList_Get(library_name);
888 if (*ret) return S_OK;
890 /* do this outside the csOpenDllList to avoid creating a lock dependency on
891 * the loader lock */
892 hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
893 if (!hLibrary)
895 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
896 /* failure: DLL could not be loaded */
897 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
900 DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow");
901 /* Note: failing to find DllCanUnloadNow is not a failure */
902 DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject");
903 if (!DllGetClassObject)
905 /* failure: the dll did not export DllGetClassObject */
906 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
907 FreeLibrary(hLibrary);
908 return CO_E_DLLNOTFOUND;
911 EnterCriticalSection( &csOpenDllList );
913 *ret = COMPOBJ_DllList_Get(library_name);
914 if (*ret)
916 /* another caller to this function already added the dll while we
917 * weren't in the critical section */
918 FreeLibrary(hLibrary);
920 else
922 len = strlenW(library_name);
923 entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
924 if (entry)
925 entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
926 if (entry && entry->library_name)
928 memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR));
929 entry->library = hLibrary;
930 entry->refs = 1;
931 entry->DllCanUnloadNow = DllCanUnloadNow;
932 entry->DllGetClassObject = DllGetClassObject;
933 list_add_tail(&openDllList, &entry->entry);
935 else
937 hr = E_OUTOFMEMORY;
938 FreeLibrary(hLibrary);
940 *ret = entry;
943 LeaveCriticalSection( &csOpenDllList );
945 return hr;
948 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
950 OpenDll *ptr;
951 OpenDll *ret = NULL;
952 EnterCriticalSection(&csOpenDllList);
953 LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
955 if (!strcmpiW(library_name, ptr->library_name) &&
956 (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
958 ret = ptr;
959 break;
962 LeaveCriticalSection(&csOpenDllList);
963 return ret;
966 /* pass FALSE for free_entry to release a reference without destroying the
967 * entry if it reaches zero or TRUE otherwise */
968 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry)
970 if (!InterlockedDecrement(&entry->refs) && free_entry)
972 EnterCriticalSection(&csOpenDllList);
973 list_remove(&entry->entry);
974 LeaveCriticalSection(&csOpenDllList);
976 TRACE("freeing %p\n", entry->library);
977 FreeLibrary(entry->library);
979 HeapFree(GetProcessHeap(), 0, entry->library_name);
980 HeapFree(GetProcessHeap(), 0, entry);
984 /* frees memory associated with active dll list */
985 static void COMPOBJ_DllList_Free(void)
987 OpenDll *entry, *cursor2;
988 EnterCriticalSection(&csOpenDllList);
989 LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry)
991 list_remove(&entry->entry);
993 HeapFree(GetProcessHeap(), 0, entry->library_name);
994 HeapFree(GetProcessHeap(), 0, entry);
996 LeaveCriticalSection(&csOpenDllList);
999 /******************************************************************************
1000 * CoBuildVersion [OLE32.@]
1001 * CoBuildVersion [COMPOBJ.1]
1003 * Gets the build version of the DLL.
1005 * PARAMS
1007 * RETURNS
1008 * Current build version, hiword is majornumber, loword is minornumber
1010 DWORD WINAPI CoBuildVersion(void)
1012 TRACE("Returning version %d, build %d.\n", rmm, rup);
1013 return (rmm<<16)+rup;
1016 /******************************************************************************
1017 * CoInitialize [OLE32.@]
1019 * Initializes the COM libraries by calling CoInitializeEx with
1020 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1022 * PARAMS
1023 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1025 * RETURNS
1026 * Success: S_OK if not already initialized, S_FALSE otherwise.
1027 * Failure: HRESULT code.
1029 * SEE ALSO
1030 * CoInitializeEx
1032 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
1035 * Just delegate to the newer method.
1037 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
1040 /******************************************************************************
1041 * CoInitializeEx [OLE32.@]
1043 * Initializes the COM libraries.
1045 * PARAMS
1046 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1047 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1049 * RETURNS
1050 * S_OK if successful,
1051 * S_FALSE if this function was called already.
1052 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1053 * threading model.
1055 * NOTES
1057 * The behavior used to set the IMalloc used for memory management is
1058 * obsolete.
1059 * The dwCoInit parameter must specify one of the following apartment
1060 * threading models:
1061 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1062 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1063 * The parameter may also specify zero or more of the following flags:
1064 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1065 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1067 * SEE ALSO
1068 * CoUninitialize
1070 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
1072 HRESULT hr = S_OK;
1073 APARTMENT *apt;
1075 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
1077 if (lpReserved!=NULL)
1079 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
1083 * Check the lock count. If this is the first time going through the initialize
1084 * process, we have to initialize the libraries.
1086 * And crank-up that lock count.
1088 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
1091 * Initialize the various COM libraries and data structures.
1093 TRACE("() - Initializing the COM libraries\n");
1095 /* we may need to defer this until after apartment initialisation */
1096 RunningObjectTableImpl_Initialize();
1099 if (!(apt = COM_CurrentInfo()->apt))
1101 apt = apartment_get_or_create(dwCoInit);
1102 if (!apt) return E_OUTOFMEMORY;
1104 else if (!apartment_is_model(apt, dwCoInit))
1106 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1107 code then we are probably using the wrong threading model to implement that API. */
1108 ERR("Attempt to change threading model of this apartment from %s to %s\n",
1109 apt->multi_threaded ? "multi-threaded" : "apartment threaded",
1110 dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
1111 return RPC_E_CHANGED_MODE;
1113 else
1114 hr = S_FALSE;
1116 COM_CurrentInfo()->inits++;
1118 return hr;
1121 /***********************************************************************
1122 * CoUninitialize [OLE32.@]
1124 * This method will decrement the refcount on the current apartment, freeing
1125 * the resources associated with it if it is the last thread in the apartment.
1126 * If the last apartment is freed, the function will additionally release
1127 * any COM resources associated with the process.
1129 * PARAMS
1131 * RETURNS
1132 * Nothing.
1134 * SEE ALSO
1135 * CoInitializeEx
1137 void WINAPI CoUninitialize(void)
1139 struct oletls * info = COM_CurrentInfo();
1140 LONG lCOMRefCnt;
1142 TRACE("()\n");
1144 /* will only happen on OOM */
1145 if (!info) return;
1147 /* sanity check */
1148 if (!info->inits)
1150 ERR("Mismatched CoUninitialize\n");
1151 return;
1154 if (!--info->inits)
1156 apartment_release(info->apt);
1157 info->apt = NULL;
1161 * Decrease the reference count.
1162 * If we are back to 0 locks on the COM library, make sure we free
1163 * all the associated data structures.
1165 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
1166 if (lCOMRefCnt==1)
1168 TRACE("() - Releasing the COM libraries\n");
1170 RunningObjectTableImpl_UnInitialize();
1172 else if (lCOMRefCnt<1) {
1173 ERR( "CoUninitialize() - not CoInitialized.\n" );
1174 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
1178 /******************************************************************************
1179 * CoDisconnectObject [OLE32.@]
1181 * Disconnects all connections to this object from remote processes. Dispatches
1182 * pending RPCs while blocking new RPCs from occurring, and then calls
1183 * IMarshal::DisconnectObject on the given object.
1185 * Typically called when the object server is forced to shut down, for instance by
1186 * the user.
1188 * PARAMS
1189 * lpUnk [I] The object whose stub should be disconnected.
1190 * reserved [I] Reserved. Should be set to 0.
1192 * RETURNS
1193 * Success: S_OK.
1194 * Failure: HRESULT code.
1196 * SEE ALSO
1197 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
1199 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
1201 HRESULT hr;
1202 IMarshal *marshal;
1203 APARTMENT *apt;
1205 TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
1207 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
1208 if (hr == S_OK)
1210 hr = IMarshal_DisconnectObject(marshal, reserved);
1211 IMarshal_Release(marshal);
1212 return hr;
1215 apt = COM_CurrentApt();
1216 if (!apt)
1217 return CO_E_NOTINITIALIZED;
1219 apartment_disconnectobject(apt, lpUnk);
1221 /* Note: native is pretty broken here because it just silently
1222 * fails, without returning an appropriate error code if the object was
1223 * not found, making apps think that the object was disconnected, when
1224 * it actually wasn't */
1226 return S_OK;
1229 /******************************************************************************
1230 * CoCreateGuid [OLE32.@]
1231 * CoCreateGuid [COMPOBJ.73]
1233 * Simply forwards to UuidCreate in RPCRT4.
1235 * PARAMS
1236 * pguid [O] Points to the GUID to initialize.
1238 * RETURNS
1239 * Success: S_OK.
1240 * Failure: HRESULT code.
1242 * SEE ALSO
1243 * UuidCreate
1245 HRESULT WINAPI CoCreateGuid(GUID *pguid)
1247 DWORD status = UuidCreate(pguid);
1248 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
1249 return HRESULT_FROM_WIN32( status );
1252 /******************************************************************************
1253 * CLSIDFromString [OLE32.@]
1254 * IIDFromString [OLE32.@]
1256 * Converts a unique identifier from its string representation into
1257 * the GUID struct.
1259 * PARAMS
1260 * idstr [I] The string representation of the GUID.
1261 * id [O] GUID converted from the string.
1263 * RETURNS
1264 * S_OK on success
1265 * CO_E_CLASSSTRING if idstr is not a valid CLSID
1267 * SEE ALSO
1268 * StringFromCLSID
1270 static HRESULT WINAPI __CLSIDFromString(LPCWSTR s, CLSID *id)
1272 int i;
1273 BYTE table[256];
1275 if (!s) {
1276 memset( id, 0, sizeof (CLSID) );
1277 return S_OK;
1280 /* validate the CLSID string */
1281 if (strlenW(s) != 38)
1282 return CO_E_CLASSSTRING;
1284 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
1285 return CO_E_CLASSSTRING;
1287 for (i=1; i<37; i++) {
1288 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
1289 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
1290 ((s[i] >= 'a') && (s[i] <= 'f')) ||
1291 ((s[i] >= 'A') && (s[i] <= 'F'))))
1292 return CO_E_CLASSSTRING;
1295 TRACE("%s -> %p\n", debugstr_w(s), id);
1297 /* quick lookup table */
1298 memset(table, 0, 256);
1300 for (i = 0; i < 10; i++) {
1301 table['0' + i] = i;
1303 for (i = 0; i < 6; i++) {
1304 table['A' + i] = i+10;
1305 table['a' + i] = i+10;
1308 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
1310 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
1311 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
1312 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
1313 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
1315 /* these are just sequential bytes */
1316 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
1317 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
1318 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
1319 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
1320 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
1321 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
1322 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
1323 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
1325 return S_OK;
1328 /*****************************************************************************/
1330 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
1332 HRESULT ret;
1334 if (!id)
1335 return E_INVALIDARG;
1337 ret = __CLSIDFromString(idstr, id);
1338 if(ret != S_OK) { /* It appears a ProgID is also valid */
1339 ret = CLSIDFromProgID(idstr, id);
1341 return ret;
1344 /* Converts a GUID into the respective string representation. */
1345 HRESULT WINE_StringFromCLSID(
1346 const CLSID *id, /* [in] GUID to be converted */
1347 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
1349 static const char hex[] = "0123456789ABCDEF";
1350 char *s;
1351 int i;
1353 if (!id)
1354 { ERR("called with id=Null\n");
1355 *idstr = 0x00;
1356 return E_FAIL;
1359 sprintf(idstr, "{%08X-%04X-%04X-%02X%02X-",
1360 id->Data1, id->Data2, id->Data3,
1361 id->Data4[0], id->Data4[1]);
1362 s = &idstr[25];
1364 /* 6 hex bytes */
1365 for (i = 2; i < 8; i++) {
1366 *s++ = hex[id->Data4[i]>>4];
1367 *s++ = hex[id->Data4[i] & 0xf];
1370 *s++ = '}';
1371 *s++ = '\0';
1373 TRACE("%p->%s\n", id, idstr);
1375 return S_OK;
1379 /******************************************************************************
1380 * StringFromCLSID [OLE32.@]
1381 * StringFromIID [OLE32.@]
1383 * Converts a GUID into the respective string representation.
1384 * The target string is allocated using the OLE IMalloc.
1386 * PARAMS
1387 * id [I] the GUID to be converted.
1388 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
1390 * RETURNS
1391 * S_OK
1392 * E_FAIL
1394 * SEE ALSO
1395 * StringFromGUID2, CLSIDFromString
1397 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
1399 char buf[80];
1400 HRESULT ret;
1401 LPMALLOC mllc;
1403 if ((ret = CoGetMalloc(0,&mllc)))
1404 return ret;
1406 ret=WINE_StringFromCLSID(id,buf);
1407 if (ret == S_OK) {
1408 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
1409 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
1410 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
1412 return ret;
1415 /******************************************************************************
1416 * StringFromGUID2 [OLE32.@]
1417 * StringFromGUID2 [COMPOBJ.76]
1419 * Modified version of StringFromCLSID that allows you to specify max
1420 * buffer size.
1422 * PARAMS
1423 * id [I] GUID to convert to string.
1424 * str [O] Buffer where the result will be stored.
1425 * cmax [I] Size of the buffer in characters.
1427 * RETURNS
1428 * Success: The length of the resulting string in characters.
1429 * Failure: 0.
1431 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
1433 char xguid[80];
1435 if (WINE_StringFromCLSID(id,xguid))
1436 return 0;
1437 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
1440 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
1441 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
1443 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1444 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
1445 LONG res;
1446 HKEY key;
1448 strcpyW(path, wszCLSIDSlash);
1449 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
1450 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, keyname ? KEY_READ : access, &key);
1451 if (res == ERROR_FILE_NOT_FOUND)
1452 return REGDB_E_CLASSNOTREG;
1453 else if (res != ERROR_SUCCESS)
1454 return REGDB_E_READREGDB;
1456 if (!keyname)
1458 *subkey = key;
1459 return S_OK;
1462 res = RegOpenKeyExW(key, keyname, 0, access, subkey);
1463 RegCloseKey(key);
1464 if (res == ERROR_FILE_NOT_FOUND)
1465 return REGDB_E_KEYMISSING;
1466 else if (res != ERROR_SUCCESS)
1467 return REGDB_E_READREGDB;
1469 return S_OK;
1472 /* open HKCR\\AppId\\{string form of appid clsid} key */
1473 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
1475 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
1476 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
1477 DWORD res;
1478 WCHAR buf[CHARS_IN_GUID];
1479 WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID];
1480 DWORD size;
1481 HKEY hkey;
1482 DWORD type;
1483 HRESULT hr;
1485 /* read the AppID value under the class's key */
1486 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
1487 if (FAILED(hr))
1488 return hr;
1490 size = sizeof(buf);
1491 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
1492 RegCloseKey(hkey);
1493 if (res == ERROR_FILE_NOT_FOUND)
1494 return REGDB_E_KEYMISSING;
1495 else if (res != ERROR_SUCCESS || type!=REG_SZ)
1496 return REGDB_E_READREGDB;
1498 strcpyW(keyname, szAppIdKey);
1499 strcatW(keyname, buf);
1500 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, access, subkey);
1501 if (res == ERROR_FILE_NOT_FOUND)
1502 return REGDB_E_KEYMISSING;
1503 else if (res != ERROR_SUCCESS)
1504 return REGDB_E_READREGDB;
1506 return S_OK;
1509 /******************************************************************************
1510 * ProgIDFromCLSID [OLE32.@]
1512 * Converts a class id into the respective program ID.
1514 * PARAMS
1515 * clsid [I] Class ID, as found in registry.
1516 * ppszProgID [O] Associated ProgID.
1518 * RETURNS
1519 * S_OK
1520 * E_OUTOFMEMORY
1521 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1523 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
1525 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
1526 HKEY hkey;
1527 HRESULT ret;
1528 LONG progidlen = 0;
1530 if (!ppszProgID)
1532 ERR("ppszProgId isn't optional\n");
1533 return E_INVALIDARG;
1536 *ppszProgID = NULL;
1537 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
1538 if (FAILED(ret))
1539 return ret;
1541 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1542 ret = REGDB_E_CLASSNOTREG;
1544 if (ret == S_OK)
1546 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
1547 if (*ppszProgID)
1549 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen))
1550 ret = REGDB_E_CLASSNOTREG;
1552 else
1553 ret = E_OUTOFMEMORY;
1556 RegCloseKey(hkey);
1557 return ret;
1560 /******************************************************************************
1561 * CLSIDFromProgID [OLE32.@]
1563 * Converts a program id into the respective GUID.
1565 * PARAMS
1566 * progid [I] Unicode program ID, as found in registry.
1567 * clsid [O] Associated CLSID.
1569 * RETURNS
1570 * Success: S_OK
1571 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1573 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
1575 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1576 WCHAR buf2[CHARS_IN_GUID];
1577 LONG buf2len = sizeof(buf2);
1578 HKEY xhkey;
1579 WCHAR *buf;
1581 if (!progid || !clsid)
1583 ERR("neither progid (%p) nor clsid (%p) are optional\n", progid, clsid);
1584 return E_INVALIDARG;
1587 /* initialise clsid in case of failure */
1588 memset(clsid, 0, sizeof(*clsid));
1590 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1591 strcpyW( buf, progid );
1592 strcatW( buf, clsidW );
1593 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1595 HeapFree(GetProcessHeap(),0,buf);
1596 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
1597 return CO_E_CLASSSTRING;
1599 HeapFree(GetProcessHeap(),0,buf);
1601 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
1603 RegCloseKey(xhkey);
1604 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
1605 return CO_E_CLASSSTRING;
1607 RegCloseKey(xhkey);
1608 return CLSIDFromString(buf2,clsid);
1612 /*****************************************************************************
1613 * CoGetPSClsid [OLE32.@]
1615 * Retrieves the CLSID of the proxy/stub factory that implements
1616 * IPSFactoryBuffer for the specified interface.
1618 * PARAMS
1619 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1620 * pclsid [O] Where to store returned proxy/stub CLSID.
1622 * RETURNS
1623 * S_OK
1624 * E_OUTOFMEMORY
1625 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1627 * NOTES
1629 * The standard marshaller activates the object with the CLSID
1630 * returned and uses the CreateProxy and CreateStub methods on its
1631 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1632 * given object.
1634 * CoGetPSClsid determines this CLSID by searching the
1635 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1636 * in the registry and any interface id registered by
1637 * CoRegisterPSClsid within the current process.
1639 * BUGS
1641 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
1642 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1643 * considered a bug in native unless an application depends on this (unlikely).
1645 * SEE ALSO
1646 * CoRegisterPSClsid.
1648 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1650 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
1651 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
1652 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
1653 WCHAR value[CHARS_IN_GUID];
1654 LONG len;
1655 HKEY hkey;
1656 APARTMENT *apt = COM_CurrentApt();
1657 struct registered_psclsid *registered_psclsid;
1659 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1661 if (!apt)
1663 ERR("apartment not initialised\n");
1664 return CO_E_NOTINITIALIZED;
1667 if (!pclsid)
1669 ERR("pclsid isn't optional\n");
1670 return E_INVALIDARG;
1673 EnterCriticalSection(&apt->cs);
1675 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1676 if (IsEqualIID(&registered_psclsid->iid, riid))
1678 *pclsid = registered_psclsid->clsid;
1679 LeaveCriticalSection(&apt->cs);
1680 return S_OK;
1683 LeaveCriticalSection(&apt->cs);
1685 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
1686 strcpyW(path, wszInterface);
1687 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
1688 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
1690 /* Open the key.. */
1691 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &hkey))
1693 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1694 return REGDB_E_IIDNOTREG;
1697 /* ... Once we have the key, query the registry to get the
1698 value of CLSID as a string, and convert it into a
1699 proper CLSID structure to be passed back to the app */
1700 len = sizeof(value);
1701 if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
1703 RegCloseKey(hkey);
1704 return REGDB_E_IIDNOTREG;
1706 RegCloseKey(hkey);
1708 /* We have the CLSID we want back from the registry as a string, so
1709 let's convert it into a CLSID structure */
1710 if (CLSIDFromString(value, pclsid) != NOERROR)
1711 return REGDB_E_IIDNOTREG;
1713 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1714 return S_OK;
1717 /*****************************************************************************
1718 * CoRegisterPSClsid [OLE32.@]
1720 * Register a proxy/stub CLSID for the given interface in the current process
1721 * only.
1723 * PARAMS
1724 * riid [I] Interface whose proxy/stub CLSID is to be registered.
1725 * rclsid [I] CLSID of the proxy/stub.
1727 * RETURNS
1728 * Success: S_OK
1729 * Failure: E_OUTOFMEMORY
1731 * NOTES
1733 * This function does not add anything to the registry and the effects are
1734 * limited to the lifetime of the current process.
1736 * SEE ALSO
1737 * CoGetPSClsid.
1739 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
1741 APARTMENT *apt = COM_CurrentApt();
1742 struct registered_psclsid *registered_psclsid;
1744 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
1746 if (!apt)
1748 ERR("apartment not initialised\n");
1749 return CO_E_NOTINITIALIZED;
1752 EnterCriticalSection(&apt->cs);
1754 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1755 if (IsEqualIID(&registered_psclsid->iid, riid))
1757 registered_psclsid->clsid = *rclsid;
1758 LeaveCriticalSection(&apt->cs);
1759 return S_OK;
1762 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
1763 if (!registered_psclsid)
1765 LeaveCriticalSection(&apt->cs);
1766 return E_OUTOFMEMORY;
1769 registered_psclsid->iid = *riid;
1770 registered_psclsid->clsid = *rclsid;
1771 list_add_head(&apt->psclsids, &registered_psclsid->entry);
1773 LeaveCriticalSection(&apt->cs);
1775 return S_OK;
1779 /***
1780 * COM_GetRegisteredClassObject
1782 * This internal method is used to scan the registered class list to
1783 * find a class object.
1785 * Params:
1786 * rclsid Class ID of the class to find.
1787 * dwClsContext Class context to match.
1788 * ppv [out] returns a pointer to the class object. Complying
1789 * to normal COM usage, this method will increase the
1790 * reference count on this object.
1792 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
1793 DWORD dwClsContext, LPUNKNOWN* ppUnk)
1795 HRESULT hr = S_FALSE;
1796 RegisteredClass *curClass;
1798 EnterCriticalSection( &csRegisteredClassList );
1800 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
1803 * Check if we have a match on the class ID and context.
1805 if ((apt->oxid == curClass->apartment_id) &&
1806 (dwClsContext & curClass->runContext) &&
1807 IsEqualGUID(&(curClass->classIdentifier), rclsid))
1810 * We have a match, return the pointer to the class object.
1812 *ppUnk = curClass->classObject;
1814 IUnknown_AddRef(curClass->classObject);
1816 hr = S_OK;
1817 break;
1821 LeaveCriticalSection( &csRegisteredClassList );
1823 return hr;
1826 /******************************************************************************
1827 * CoRegisterClassObject [OLE32.@]
1829 * Registers the class object for a given class ID. Servers housed in EXE
1830 * files use this method instead of exporting DllGetClassObject to allow
1831 * other code to connect to their objects.
1833 * PARAMS
1834 * rclsid [I] CLSID of the object to register.
1835 * pUnk [I] IUnknown of the object.
1836 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1837 * flags [I] REGCLS flags indicating how connections are made.
1838 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1840 * RETURNS
1841 * S_OK on success,
1842 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1843 * CO_E_OBJISREG if the object is already registered. We should not return this.
1845 * SEE ALSO
1846 * CoRevokeClassObject, CoGetClassObject
1848 * NOTES
1849 * In-process objects are only registered for the current apartment.
1850 * CoGetClassObject() and CoCreateInstance() will not return objects registered
1851 * in other apartments.
1853 * BUGS
1854 * MSDN claims that multiple interface registrations are legal, but we
1855 * can't do that with our current implementation.
1857 HRESULT WINAPI CoRegisterClassObject(
1858 REFCLSID rclsid,
1859 LPUNKNOWN pUnk,
1860 DWORD dwClsContext,
1861 DWORD flags,
1862 LPDWORD lpdwRegister)
1864 RegisteredClass* newClass;
1865 LPUNKNOWN foundObject;
1866 HRESULT hr;
1867 APARTMENT *apt;
1869 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
1870 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1872 if ( (lpdwRegister==0) || (pUnk==0) )
1873 return E_INVALIDARG;
1875 apt = COM_CurrentApt();
1876 if (!apt)
1878 ERR("COM was not initialized\n");
1879 return CO_E_NOTINITIALIZED;
1882 *lpdwRegister = 0;
1884 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
1885 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
1886 if (flags & REGCLS_MULTIPLEUSE)
1887 dwClsContext |= CLSCTX_INPROC_SERVER;
1890 * First, check if the class is already registered.
1891 * If it is, this should cause an error.
1893 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
1894 if (hr == S_OK) {
1895 if (flags & REGCLS_MULTIPLEUSE) {
1896 if (dwClsContext & CLSCTX_LOCAL_SERVER)
1897 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
1898 IUnknown_Release(foundObject);
1899 return hr;
1901 IUnknown_Release(foundObject);
1902 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
1903 return CO_E_OBJISREG;
1906 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1907 if ( newClass == NULL )
1908 return E_OUTOFMEMORY;
1910 newClass->classIdentifier = *rclsid;
1911 newClass->apartment_id = apt->oxid;
1912 newClass->runContext = dwClsContext;
1913 newClass->connectFlags = flags;
1914 newClass->pMarshaledData = NULL;
1915 newClass->RpcRegistration = NULL;
1918 * Use the address of the chain node as the cookie since we are sure it's
1919 * unique. FIXME: not on 64-bit platforms.
1921 newClass->dwCookie = (DWORD)newClass;
1924 * Since we're making a copy of the object pointer, we have to increase its
1925 * reference count.
1927 newClass->classObject = pUnk;
1928 IUnknown_AddRef(newClass->classObject);
1930 EnterCriticalSection( &csRegisteredClassList );
1931 list_add_tail(&RegisteredClassList, &newClass->entry);
1932 LeaveCriticalSection( &csRegisteredClassList );
1934 *lpdwRegister = newClass->dwCookie;
1936 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1937 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
1938 if (hr) {
1939 FIXME("Failed to create stream on hglobal, %x\n", hr);
1940 return hr;
1942 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
1943 newClass->classObject, MSHCTX_LOCAL, NULL,
1944 MSHLFLAGS_TABLESTRONG);
1945 if (hr) {
1946 FIXME("CoMarshalInterface failed, %x!\n",hr);
1947 return hr;
1950 hr = RPC_StartLocalServer(&newClass->classIdentifier,
1951 newClass->pMarshaledData,
1952 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
1953 &newClass->RpcRegistration);
1955 return S_OK;
1958 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
1960 list_remove(&curClass->entry);
1962 if (curClass->runContext & CLSCTX_LOCAL_SERVER)
1963 RPC_StopLocalServer(curClass->RpcRegistration);
1966 * Release the reference to the class object.
1968 IUnknown_Release(curClass->classObject);
1970 if (curClass->pMarshaledData)
1972 LARGE_INTEGER zero;
1973 memset(&zero, 0, sizeof(zero));
1974 IStream_Seek(curClass->pMarshaledData, zero, STREAM_SEEK_SET, NULL);
1975 CoReleaseMarshalData(curClass->pMarshaledData);
1976 IStream_Release(curClass->pMarshaledData);
1979 HeapFree(GetProcessHeap(), 0, curClass);
1982 static void COM_RevokeAllClasses(const struct apartment *apt)
1984 RegisteredClass *curClass, *cursor;
1986 EnterCriticalSection( &csRegisteredClassList );
1988 LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
1990 if (curClass->apartment_id == apt->oxid)
1991 COM_RevokeRegisteredClassObject(curClass);
1994 LeaveCriticalSection( &csRegisteredClassList );
1997 /***********************************************************************
1998 * CoRevokeClassObject [OLE32.@]
2000 * Removes a class object from the class registry.
2002 * PARAMS
2003 * dwRegister [I] Cookie returned from CoRegisterClassObject().
2005 * RETURNS
2006 * Success: S_OK.
2007 * Failure: HRESULT code.
2009 * NOTES
2010 * Must be called from the same apartment that called CoRegisterClassObject(),
2011 * otherwise it will fail with RPC_E_WRONG_THREAD.
2013 * SEE ALSO
2014 * CoRegisterClassObject
2016 HRESULT WINAPI CoRevokeClassObject(
2017 DWORD dwRegister)
2019 HRESULT hr = E_INVALIDARG;
2020 RegisteredClass *curClass;
2021 APARTMENT *apt;
2023 TRACE("(%08x)\n",dwRegister);
2025 apt = COM_CurrentApt();
2026 if (!apt)
2028 ERR("COM was not initialized\n");
2029 return CO_E_NOTINITIALIZED;
2032 EnterCriticalSection( &csRegisteredClassList );
2034 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
2037 * Check if we have a match on the cookie.
2039 if (curClass->dwCookie == dwRegister)
2041 if (curClass->apartment_id == apt->oxid)
2043 COM_RevokeRegisteredClassObject(curClass);
2044 hr = S_OK;
2046 else
2048 ERR("called from wrong apartment, should be called from %s\n",
2049 wine_dbgstr_longlong(curClass->apartment_id));
2050 hr = RPC_E_WRONG_THREAD;
2052 break;
2056 LeaveCriticalSection( &csRegisteredClassList );
2058 return hr;
2061 /***********************************************************************
2062 * COM_RegReadPath [internal]
2064 * Reads a registry value and expands it when necessary
2066 static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
2068 DWORD ret;
2069 HKEY key;
2070 DWORD keytype;
2071 WCHAR src[MAX_PATH];
2072 DWORD dwLength = dstlen * sizeof(WCHAR);
2074 if((ret = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
2075 if( (ret = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
2076 if (keytype == REG_EXPAND_SZ) {
2077 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
2078 } else {
2079 lstrcpynW(dst, src, dstlen);
2082 RegCloseKey (key);
2084 return ret;
2087 static void get_threading_model(HKEY key, LPWSTR value, DWORD len)
2089 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2090 DWORD keytype;
2091 DWORD ret;
2092 DWORD dwLength = len * sizeof(WCHAR);
2094 ret = RegQueryValueExW(key, wszThreadingModel, NULL, &keytype, (LPBYTE)value, &dwLength);
2095 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
2096 value[0] = '\0';
2099 static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll,
2100 REFCLSID rclsid, REFIID riid,
2101 BOOL hostifnecessary, void **ppv)
2103 WCHAR dllpath[MAX_PATH+1];
2104 BOOL apartment_threaded;
2106 if (hostifnecessary)
2108 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
2109 static const WCHAR wszFree[] = {'F','r','e','e',0};
2110 static const WCHAR wszBoth[] = {'B','o','t','h',0};
2111 WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
2113 get_threading_model(hkeydll, threading_model, ARRAYSIZE(threading_model));
2114 /* "Apartment" */
2115 if (!strcmpiW(threading_model, wszApartment))
2117 apartment_threaded = TRUE;
2118 if (apt->multi_threaded)
2119 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, hkeydll, rclsid, riid, ppv);
2121 /* "Free" */
2122 else if (!strcmpiW(threading_model, wszFree))
2124 apartment_threaded = FALSE;
2125 if (!apt->multi_threaded)
2126 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, hkeydll, rclsid, riid, ppv);
2128 /* everything except "Apartment", "Free" and "Both" */
2129 else if (strcmpiW(threading_model, wszBoth))
2131 apartment_threaded = TRUE;
2132 /* everything else is main-threaded */
2133 if (threading_model[0])
2134 FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n",
2135 debugstr_w(threading_model), debugstr_guid(rclsid));
2137 if (apt->multi_threaded || !apt->main)
2138 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, hkeydll, rclsid, riid, ppv);
2140 else
2141 apartment_threaded = FALSE;
2143 else
2144 apartment_threaded = !apt->multi_threaded;
2146 if (COM_RegReadPath(hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
2148 /* failure: CLSID is not found in registry */
2149 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
2150 return REGDB_E_CLASSNOTREG;
2153 return apartment_getclassobject(apt, dllpath, apartment_threaded,
2154 rclsid, riid, ppv);
2157 /***********************************************************************
2158 * CoGetClassObject [OLE32.@]
2160 * Creates an object of the specified class.
2162 * PARAMS
2163 * rclsid [I] Class ID to create an instance of.
2164 * dwClsContext [I] Flags to restrict the location of the created instance.
2165 * pServerInfo [I] Optional. Details for connecting to a remote server.
2166 * iid [I] The ID of the interface of the instance to return.
2167 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2169 * RETURNS
2170 * Success: S_OK
2171 * Failure: HRESULT code.
2173 * NOTES
2174 * The dwClsContext parameter can be one or more of the following:
2175 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2176 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2177 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2178 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2180 * SEE ALSO
2181 * CoCreateInstance()
2183 HRESULT WINAPI CoGetClassObject(
2184 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
2185 REFIID iid, LPVOID *ppv)
2187 LPUNKNOWN regClassObject;
2188 HRESULT hres = E_UNEXPECTED;
2189 APARTMENT *apt;
2191 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
2193 if (!ppv)
2194 return E_INVALIDARG;
2196 *ppv = NULL;
2198 apt = COM_CurrentApt();
2199 if (!apt)
2201 ERR("apartment not initialised\n");
2202 return CO_E_NOTINITIALIZED;
2205 if (pServerInfo) {
2206 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
2207 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
2211 * First, try and see if we can't match the class ID with one of the
2212 * registered classes.
2214 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
2215 &regClassObject))
2217 /* Get the required interface from the retrieved pointer. */
2218 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
2221 * Since QI got another reference on the pointer, we want to release the
2222 * one we already have. If QI was unsuccessful, this will release the object. This
2223 * is good since we are not returning it in the "out" parameter.
2225 IUnknown_Release(regClassObject);
2227 return hres;
2230 /* First try in-process server */
2231 if (CLSCTX_INPROC_SERVER & dwClsContext)
2233 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
2234 HKEY hkey;
2236 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
2237 return FTMarshalCF_Create(iid, ppv);
2239 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
2240 if (FAILED(hres))
2242 if (hres == REGDB_E_CLASSNOTREG)
2243 ERR("class %s not registered\n", debugstr_guid(rclsid));
2244 else if (hres == REGDB_E_KEYMISSING)
2246 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
2247 hres = REGDB_E_CLASSNOTREG;
2251 if (SUCCEEDED(hres))
2253 hres = get_inproc_class_object(apt, hkey, rclsid, iid,
2254 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2255 RegCloseKey(hkey);
2258 /* return if we got a class, otherwise fall through to one of the
2259 * other types */
2260 if (SUCCEEDED(hres))
2261 return hres;
2264 /* Next try in-process handler */
2265 if (CLSCTX_INPROC_HANDLER & dwClsContext)
2267 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
2268 HKEY hkey;
2270 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
2271 if (FAILED(hres))
2273 if (hres == REGDB_E_CLASSNOTREG)
2274 ERR("class %s not registered\n", debugstr_guid(rclsid));
2275 else if (hres == REGDB_E_KEYMISSING)
2277 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
2278 hres = REGDB_E_CLASSNOTREG;
2282 if (SUCCEEDED(hres))
2284 hres = get_inproc_class_object(apt, hkey, rclsid, iid,
2285 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2286 RegCloseKey(hkey);
2289 /* return if we got a class, otherwise fall through to one of the
2290 * other types */
2291 if (SUCCEEDED(hres))
2292 return hres;
2295 /* Next try out of process */
2296 if (CLSCTX_LOCAL_SERVER & dwClsContext)
2298 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
2299 if (SUCCEEDED(hres))
2300 return hres;
2303 /* Finally try remote: this requires networked DCOM (a lot of work) */
2304 if (CLSCTX_REMOTE_SERVER & dwClsContext)
2306 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
2307 hres = E_NOINTERFACE;
2310 if (FAILED(hres))
2311 ERR("no class object %s could be created for context 0x%x\n",
2312 debugstr_guid(rclsid), dwClsContext);
2313 return hres;
2316 /***********************************************************************
2317 * CoResumeClassObjects (OLE32.@)
2319 * Resumes all class objects registered with REGCLS_SUSPENDED.
2321 * RETURNS
2322 * Success: S_OK.
2323 * Failure: HRESULT code.
2325 HRESULT WINAPI CoResumeClassObjects(void)
2327 FIXME("stub\n");
2328 return S_OK;
2331 /***********************************************************************
2332 * CoCreateInstance [OLE32.@]
2334 * Creates an instance of the specified class.
2336 * PARAMS
2337 * rclsid [I] Class ID to create an instance of.
2338 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
2339 * dwClsContext [I] Flags to restrict the location of the created instance.
2340 * iid [I] The ID of the interface of the instance to return.
2341 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
2343 * RETURNS
2344 * Success: S_OK
2345 * Failure: HRESULT code.
2347 * NOTES
2348 * The dwClsContext parameter can be one or more of the following:
2349 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2350 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2351 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2352 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2354 * Aggregation is the concept of deferring the IUnknown of an object to another
2355 * object. This allows a separate object to behave as though it was part of
2356 * the object and to allow this the pUnkOuter parameter can be set. Note that
2357 * not all objects support having an outer of unknown.
2359 * SEE ALSO
2360 * CoGetClassObject()
2362 HRESULT WINAPI CoCreateInstance(
2363 REFCLSID rclsid,
2364 LPUNKNOWN pUnkOuter,
2365 DWORD dwClsContext,
2366 REFIID iid,
2367 LPVOID *ppv)
2369 HRESULT hres;
2370 LPCLASSFACTORY lpclf = 0;
2372 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
2373 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
2376 * Sanity check
2378 if (ppv==0)
2379 return E_POINTER;
2382 * Initialize the "out" parameter
2384 *ppv = 0;
2386 if (!COM_CurrentApt())
2388 ERR("apartment not initialised\n");
2389 return CO_E_NOTINITIALIZED;
2393 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
2394 * Rather than create a class factory, we can just check for it here
2396 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
2397 if (StdGlobalInterfaceTableInstance == NULL)
2398 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
2399 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
2400 if (hres) return hres;
2402 TRACE("Retrieved GIT (%p)\n", *ppv);
2403 return S_OK;
2407 * Get a class factory to construct the object we want.
2409 hres = CoGetClassObject(rclsid,
2410 dwClsContext,
2411 NULL,
2412 &IID_IClassFactory,
2413 (LPVOID)&lpclf);
2415 if (FAILED(hres))
2416 return hres;
2419 * Create the object and don't forget to release the factory
2421 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
2422 IClassFactory_Release(lpclf);
2423 if(FAILED(hres))
2425 if (hres == CLASS_E_NOAGGREGATION && pUnkOuter)
2426 FIXME("Class %s does not support aggregation\n", debugstr_guid(rclsid));
2427 else
2428 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n", debugstr_guid(iid), debugstr_guid(rclsid),hres);
2431 return hres;
2434 /***********************************************************************
2435 * CoCreateInstanceEx [OLE32.@]
2437 HRESULT WINAPI CoCreateInstanceEx(
2438 REFCLSID rclsid,
2439 LPUNKNOWN pUnkOuter,
2440 DWORD dwClsContext,
2441 COSERVERINFO* pServerInfo,
2442 ULONG cmq,
2443 MULTI_QI* pResults)
2445 IUnknown* pUnk = NULL;
2446 HRESULT hr;
2447 ULONG index;
2448 ULONG successCount = 0;
2451 * Sanity check
2453 if ( (cmq==0) || (pResults==NULL))
2454 return E_INVALIDARG;
2456 if (pServerInfo!=NULL)
2457 FIXME("() non-NULL pServerInfo not supported!\n");
2460 * Initialize all the "out" parameters.
2462 for (index = 0; index < cmq; index++)
2464 pResults[index].pItf = NULL;
2465 pResults[index].hr = E_NOINTERFACE;
2469 * Get the object and get its IUnknown pointer.
2471 hr = CoCreateInstance(rclsid,
2472 pUnkOuter,
2473 dwClsContext,
2474 &IID_IUnknown,
2475 (VOID**)&pUnk);
2477 if (hr)
2478 return hr;
2481 * Then, query for all the interfaces requested.
2483 for (index = 0; index < cmq; index++)
2485 pResults[index].hr = IUnknown_QueryInterface(pUnk,
2486 pResults[index].pIID,
2487 (VOID**)&(pResults[index].pItf));
2489 if (pResults[index].hr == S_OK)
2490 successCount++;
2494 * Release our temporary unknown pointer.
2496 IUnknown_Release(pUnk);
2498 if (successCount == 0)
2499 return E_NOINTERFACE;
2501 if (successCount!=cmq)
2502 return CO_S_NOTALLINTERFACES;
2504 return S_OK;
2507 /***********************************************************************
2508 * CoLoadLibrary (OLE32.@)
2510 * Loads a library.
2512 * PARAMS
2513 * lpszLibName [I] Path to library.
2514 * bAutoFree [I] Whether the library should automatically be freed.
2516 * RETURNS
2517 * Success: Handle to loaded library.
2518 * Failure: NULL.
2520 * SEE ALSO
2521 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2523 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
2525 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
2527 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
2530 /***********************************************************************
2531 * CoFreeLibrary [OLE32.@]
2533 * Unloads a library from memory.
2535 * PARAMS
2536 * hLibrary [I] Handle to library to unload.
2538 * RETURNS
2539 * Nothing
2541 * SEE ALSO
2542 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2544 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
2546 FreeLibrary(hLibrary);
2550 /***********************************************************************
2551 * CoFreeAllLibraries [OLE32.@]
2553 * Function for backwards compatibility only. Does nothing.
2555 * RETURNS
2556 * Nothing.
2558 * SEE ALSO
2559 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2561 void WINAPI CoFreeAllLibraries(void)
2563 /* NOP */
2566 /***********************************************************************
2567 * CoFreeUnusedLibrariesEx [OLE32.@]
2569 * Frees any previously unused libraries whose delay has expired and marks
2570 * currently unused libraries for unloading. Unused are identified as those that
2571 * return S_OK from their DllCanUnloadNow function.
2573 * PARAMS
2574 * dwUnloadDelay [I] Unload delay in milliseconds.
2575 * dwReserved [I] Reserved. Set to 0.
2577 * RETURNS
2578 * Nothing.
2580 * SEE ALSO
2581 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2583 void WINAPI CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved)
2585 struct apartment *apt = COM_CurrentApt();
2586 if (!apt)
2588 ERR("apartment not initialised\n");
2589 return;
2592 apartment_freeunusedlibraries(apt, dwUnloadDelay);
2595 /***********************************************************************
2596 * CoFreeUnusedLibraries [OLE32.@]
2597 * CoFreeUnusedLibraries [COMPOBJ.17]
2599 * Frees any unused libraries. Unused are identified as those that return
2600 * S_OK from their DllCanUnloadNow function.
2602 * RETURNS
2603 * Nothing.
2605 * SEE ALSO
2606 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2608 void WINAPI CoFreeUnusedLibraries(void)
2610 CoFreeUnusedLibrariesEx(INFINITE, 0);
2613 /***********************************************************************
2614 * CoFileTimeNow [OLE32.@]
2615 * CoFileTimeNow [COMPOBJ.82]
2617 * Retrieves the current time in FILETIME format.
2619 * PARAMS
2620 * lpFileTime [O] The current time.
2622 * RETURNS
2623 * S_OK.
2625 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
2627 GetSystemTimeAsFileTime( lpFileTime );
2628 return S_OK;
2631 /******************************************************************************
2632 * CoLockObjectExternal [OLE32.@]
2634 * Increments or decrements the external reference count of a stub object.
2636 * PARAMS
2637 * pUnk [I] Stub object.
2638 * fLock [I] If TRUE then increments the external ref-count,
2639 * otherwise decrements.
2640 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2641 * calling CoDisconnectObject.
2643 * RETURNS
2644 * Success: S_OK.
2645 * Failure: HRESULT code.
2647 * NOTES
2648 * If fLock is TRUE and an object is passed in that doesn't have a stub
2649 * manager then a new stub manager is created for the object.
2651 HRESULT WINAPI CoLockObjectExternal(
2652 LPUNKNOWN pUnk,
2653 BOOL fLock,
2654 BOOL fLastUnlockReleases)
2656 struct stub_manager *stubmgr;
2657 struct apartment *apt;
2659 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2660 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2662 apt = COM_CurrentApt();
2663 if (!apt) return CO_E_NOTINITIALIZED;
2665 stubmgr = get_stub_manager_from_object(apt, pUnk);
2667 if (stubmgr)
2669 if (fLock)
2670 stub_manager_ext_addref(stubmgr, 1, FALSE);
2671 else
2672 stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
2674 stub_manager_int_release(stubmgr);
2676 return S_OK;
2678 else if (fLock)
2680 stubmgr = new_stub_manager(apt, pUnk);
2682 if (stubmgr)
2684 stub_manager_ext_addref(stubmgr, 1, FALSE);
2685 stub_manager_int_release(stubmgr);
2688 return S_OK;
2690 else
2692 WARN("stub object not found %p\n", pUnk);
2693 /* Note: native is pretty broken here because it just silently
2694 * fails, without returning an appropriate error code, making apps
2695 * think that the object was disconnected, when it actually wasn't */
2696 return S_OK;
2700 /***********************************************************************
2701 * CoInitializeWOW (OLE32.@)
2703 * WOW equivalent of CoInitialize?
2705 * PARAMS
2706 * x [I] Unknown.
2707 * y [I] Unknown.
2709 * RETURNS
2710 * Unknown.
2712 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2714 FIXME("(0x%08x,0x%08x),stub!\n",x,y);
2715 return 0;
2718 /***********************************************************************
2719 * CoGetState [OLE32.@]
2721 * Retrieves the thread state object previously stored by CoSetState().
2723 * PARAMS
2724 * ppv [I] Address where pointer to object will be stored.
2726 * RETURNS
2727 * Success: S_OK.
2728 * Failure: E_OUTOFMEMORY.
2730 * NOTES
2731 * Crashes on all invalid ppv addresses, including NULL.
2732 * If the function returns a non-NULL object then the caller must release its
2733 * reference on the object when the object is no longer required.
2735 * SEE ALSO
2736 * CoSetState().
2738 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2740 struct oletls *info = COM_CurrentInfo();
2741 if (!info) return E_OUTOFMEMORY;
2743 *ppv = NULL;
2745 if (info->state)
2747 IUnknown_AddRef(info->state);
2748 *ppv = info->state;
2749 TRACE("apt->state=%p\n", info->state);
2752 return S_OK;
2755 /***********************************************************************
2756 * CoSetState [OLE32.@]
2758 * Sets the thread state object.
2760 * PARAMS
2761 * pv [I] Pointer to state object to be stored.
2763 * NOTES
2764 * The system keeps a reference on the object while the object stored.
2766 * RETURNS
2767 * Success: S_OK.
2768 * Failure: E_OUTOFMEMORY.
2770 HRESULT WINAPI CoSetState(IUnknown * pv)
2772 struct oletls *info = COM_CurrentInfo();
2773 if (!info) return E_OUTOFMEMORY;
2775 if (pv) IUnknown_AddRef(pv);
2777 if (info->state)
2779 TRACE("-- release %p now\n", info->state);
2780 IUnknown_Release(info->state);
2783 info->state = pv;
2785 return S_OK;
2789 /******************************************************************************
2790 * CoTreatAsClass [OLE32.@]
2792 * Sets the TreatAs value of a class.
2794 * PARAMS
2795 * clsidOld [I] Class to set TreatAs value on.
2796 * clsidNew [I] The class the clsidOld should be treated as.
2798 * RETURNS
2799 * Success: S_OK.
2800 * Failure: HRESULT code.
2802 * SEE ALSO
2803 * CoGetTreatAsClass
2805 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2807 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
2808 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2809 HKEY hkey = NULL;
2810 WCHAR szClsidNew[CHARS_IN_GUID];
2811 HRESULT res = S_OK;
2812 WCHAR auto_treat_as[CHARS_IN_GUID];
2813 LONG auto_treat_as_size = sizeof(auto_treat_as);
2814 CLSID id;
2816 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
2817 if (FAILED(res))
2818 goto done;
2819 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2821 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
2822 CLSIDFromString(auto_treat_as, &id) == S_OK)
2824 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
2826 res = REGDB_E_WRITEREGDB;
2827 goto done;
2830 else
2832 RegDeleteKeyW(hkey, wszTreatAs);
2833 goto done;
2836 else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
2837 !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
2839 res = REGDB_E_WRITEREGDB;
2840 goto done;
2843 done:
2844 if (hkey) RegCloseKey(hkey);
2845 return res;
2848 /******************************************************************************
2849 * CoGetTreatAsClass [OLE32.@]
2851 * Gets the TreatAs value of a class.
2853 * PARAMS
2854 * clsidOld [I] Class to get the TreatAs value of.
2855 * clsidNew [I] The class the clsidOld should be treated as.
2857 * RETURNS
2858 * Success: S_OK.
2859 * Failure: HRESULT code.
2861 * SEE ALSO
2862 * CoSetTreatAsClass
2864 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2866 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2867 HKEY hkey = NULL;
2868 WCHAR szClsidNew[CHARS_IN_GUID];
2869 HRESULT res = S_OK;
2870 LONG len = sizeof(szClsidNew);
2872 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2873 *clsidNew = *clsidOld; /* copy over old value */
2875 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
2876 if (FAILED(res))
2877 goto done;
2878 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
2880 res = S_FALSE;
2881 goto done;
2883 res = CLSIDFromString(szClsidNew,clsidNew);
2884 if (FAILED(res))
2885 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
2886 done:
2887 if (hkey) RegCloseKey(hkey);
2888 return res;
2891 /******************************************************************************
2892 * CoGetCurrentProcess [OLE32.@]
2893 * CoGetCurrentProcess [COMPOBJ.34]
2895 * Gets the current process ID.
2897 * RETURNS
2898 * The current process ID.
2900 * NOTES
2901 * Is DWORD really the correct return type for this function?
2903 DWORD WINAPI CoGetCurrentProcess(void)
2905 return GetCurrentProcessId();
2908 /******************************************************************************
2909 * CoRegisterMessageFilter [OLE32.@]
2911 * Registers a message filter.
2913 * PARAMS
2914 * lpMessageFilter [I] Pointer to interface.
2915 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2917 * RETURNS
2918 * Success: S_OK.
2919 * Failure: HRESULT code.
2921 * NOTES
2922 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
2923 * lpMessageFilter removes the message filter.
2925 * If lplpMessageFilter is not NULL the previous message filter will be
2926 * returned in the memory pointer to this parameter and the caller is
2927 * responsible for releasing the object.
2929 * The current thread be in an apartment otherwise the function will crash.
2931 HRESULT WINAPI CoRegisterMessageFilter(
2932 LPMESSAGEFILTER lpMessageFilter,
2933 LPMESSAGEFILTER *lplpMessageFilter)
2935 struct apartment *apt;
2936 IMessageFilter *lpOldMessageFilter;
2938 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
2940 apt = COM_CurrentApt();
2942 /* can't set a message filter in a multi-threaded apartment */
2943 if (!apt || apt->multi_threaded)
2945 WARN("can't set message filter in MTA or uninitialized apt\n");
2946 return CO_E_NOT_SUPPORTED;
2949 if (lpMessageFilter)
2950 IMessageFilter_AddRef(lpMessageFilter);
2952 EnterCriticalSection(&apt->cs);
2954 lpOldMessageFilter = apt->filter;
2955 apt->filter = lpMessageFilter;
2957 LeaveCriticalSection(&apt->cs);
2959 if (lplpMessageFilter)
2960 *lplpMessageFilter = lpOldMessageFilter;
2961 else if (lpOldMessageFilter)
2962 IMessageFilter_Release(lpOldMessageFilter);
2964 return S_OK;
2967 /***********************************************************************
2968 * CoIsOle1Class [OLE32.@]
2970 * Determines whether the specified class an OLE v1 class.
2972 * PARAMS
2973 * clsid [I] Class to test.
2975 * RETURNS
2976 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
2978 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
2980 FIXME("%s\n", debugstr_guid(clsid));
2981 return FALSE;
2984 /***********************************************************************
2985 * IsEqualGUID [OLE32.@]
2987 * Compares two Unique Identifiers.
2989 * PARAMS
2990 * rguid1 [I] The first GUID to compare.
2991 * rguid2 [I] The other GUID to compare.
2993 * RETURNS
2994 * TRUE if equal
2996 #undef IsEqualGUID
2997 BOOL WINAPI IsEqualGUID(
2998 REFGUID rguid1,
2999 REFGUID rguid2)
3001 return !memcmp(rguid1,rguid2,sizeof(GUID));
3004 /***********************************************************************
3005 * CoInitializeSecurity [OLE32.@]
3007 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
3008 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
3009 void* pReserved1, DWORD dwAuthnLevel,
3010 DWORD dwImpLevel, void* pReserved2,
3011 DWORD dwCapabilities, void* pReserved3)
3013 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
3014 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
3015 dwCapabilities, pReserved3);
3016 return S_OK;
3019 /***********************************************************************
3020 * CoSuspendClassObjects [OLE32.@]
3022 * Suspends all registered class objects to prevent further requests coming in
3023 * for those objects.
3025 * RETURNS
3026 * Success: S_OK.
3027 * Failure: HRESULT code.
3029 HRESULT WINAPI CoSuspendClassObjects(void)
3031 FIXME("\n");
3032 return S_OK;
3035 /***********************************************************************
3036 * CoAddRefServerProcess [OLE32.@]
3038 * Helper function for incrementing the reference count of a local-server
3039 * process.
3041 * RETURNS
3042 * New reference count.
3044 * SEE ALSO
3045 * CoReleaseServerProcess().
3047 ULONG WINAPI CoAddRefServerProcess(void)
3049 ULONG refs;
3051 TRACE("\n");
3053 EnterCriticalSection(&csRegisteredClassList);
3054 refs = ++s_COMServerProcessReferences;
3055 LeaveCriticalSection(&csRegisteredClassList);
3057 TRACE("refs before: %d\n", refs - 1);
3059 return refs;
3062 /***********************************************************************
3063 * CoReleaseServerProcess [OLE32.@]
3065 * Helper function for decrementing the reference count of a local-server
3066 * process.
3068 * RETURNS
3069 * New reference count.
3071 * NOTES
3072 * When reference count reaches 0, this function suspends all registered
3073 * classes so no new connections are accepted.
3075 * SEE ALSO
3076 * CoAddRefServerProcess(), CoSuspendClassObjects().
3078 ULONG WINAPI CoReleaseServerProcess(void)
3080 ULONG refs;
3082 TRACE("\n");
3084 EnterCriticalSection(&csRegisteredClassList);
3086 refs = --s_COMServerProcessReferences;
3087 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
3089 LeaveCriticalSection(&csRegisteredClassList);
3091 TRACE("refs after: %d\n", refs);
3093 return refs;
3096 /***********************************************************************
3097 * CoIsHandlerConnected [OLE32.@]
3099 * Determines whether a proxy is connected to a remote stub.
3101 * PARAMS
3102 * pUnk [I] Pointer to object that may or may not be connected.
3104 * RETURNS
3105 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
3106 * FALSE otherwise.
3108 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
3110 FIXME("%p\n", pUnk);
3112 return TRUE;
3115 /***********************************************************************
3116 * CoAllowSetForegroundWindow [OLE32.@]
3119 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
3121 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
3122 return S_OK;
3125 /***********************************************************************
3126 * CoQueryProxyBlanket [OLE32.@]
3128 * Retrieves the security settings being used by a proxy.
3130 * PARAMS
3131 * pProxy [I] Pointer to the proxy object.
3132 * pAuthnSvc [O] The type of authentication service.
3133 * pAuthzSvc [O] The type of authorization service.
3134 * ppServerPrincName [O] Optional. The server prinicple name.
3135 * pAuthnLevel [O] The authentication level.
3136 * pImpLevel [O] The impersonation level.
3137 * ppAuthInfo [O] Information specific to the authorization/authentication service.
3138 * pCapabilities [O] Flags affecting the security behaviour.
3140 * RETURNS
3141 * Success: S_OK.
3142 * Failure: HRESULT code.
3144 * SEE ALSO
3145 * CoCopyProxy, CoSetProxyBlanket.
3147 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
3148 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
3149 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
3151 IClientSecurity *pCliSec;
3152 HRESULT hr;
3154 TRACE("%p\n", pProxy);
3156 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3157 if (SUCCEEDED(hr))
3159 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
3160 pAuthzSvc, ppServerPrincName,
3161 pAuthnLevel, pImpLevel, ppAuthInfo,
3162 pCapabilities);
3163 IClientSecurity_Release(pCliSec);
3166 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3167 return hr;
3170 /***********************************************************************
3171 * CoSetProxyBlanket [OLE32.@]
3173 * Sets the security settings for a proxy.
3175 * PARAMS
3176 * pProxy [I] Pointer to the proxy object.
3177 * AuthnSvc [I] The type of authentication service.
3178 * AuthzSvc [I] The type of authorization service.
3179 * pServerPrincName [I] The server prinicple name.
3180 * AuthnLevel [I] The authentication level.
3181 * ImpLevel [I] The impersonation level.
3182 * pAuthInfo [I] Information specific to the authorization/authentication service.
3183 * Capabilities [I] Flags affecting the security behaviour.
3185 * RETURNS
3186 * Success: S_OK.
3187 * Failure: HRESULT code.
3189 * SEE ALSO
3190 * CoQueryProxyBlanket, CoCopyProxy.
3192 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
3193 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
3194 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
3196 IClientSecurity *pCliSec;
3197 HRESULT hr;
3199 TRACE("%p\n", pProxy);
3201 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3202 if (SUCCEEDED(hr))
3204 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
3205 AuthzSvc, pServerPrincName,
3206 AuthnLevel, ImpLevel, pAuthInfo,
3207 Capabilities);
3208 IClientSecurity_Release(pCliSec);
3211 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3212 return hr;
3215 /***********************************************************************
3216 * CoCopyProxy [OLE32.@]
3218 * Copies a proxy.
3220 * PARAMS
3221 * pProxy [I] Pointer to the proxy object.
3222 * ppCopy [O] Copy of the proxy.
3224 * RETURNS
3225 * Success: S_OK.
3226 * Failure: HRESULT code.
3228 * SEE ALSO
3229 * CoQueryProxyBlanket, CoSetProxyBlanket.
3231 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
3233 IClientSecurity *pCliSec;
3234 HRESULT hr;
3236 TRACE("%p\n", pProxy);
3238 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3239 if (SUCCEEDED(hr))
3241 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
3242 IClientSecurity_Release(pCliSec);
3245 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3246 return hr;
3250 /***********************************************************************
3251 * CoGetCallContext [OLE32.@]
3253 * Gets the context of the currently executing server call in the current
3254 * thread.
3256 * PARAMS
3257 * riid [I] Context interface to return.
3258 * ppv [O] Pointer to memory that will receive the context on return.
3260 * RETURNS
3261 * Success: S_OK.
3262 * Failure: HRESULT code.
3264 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
3266 FIXME("(%s, %p): stub\n", debugstr_guid(riid), ppv);
3268 *ppv = NULL;
3269 return E_NOINTERFACE;
3272 /***********************************************************************
3273 * CoQueryClientBlanket [OLE32.@]
3275 * Retrieves the authentication information about the client of the currently
3276 * executing server call in the current thread.
3278 * PARAMS
3279 * pAuthnSvc [O] Optional. The type of authentication service.
3280 * pAuthzSvc [O] Optional. The type of authorization service.
3281 * pServerPrincName [O] Optional. The server prinicple name.
3282 * pAuthnLevel [O] Optional. The authentication level.
3283 * pImpLevel [O] Optional. The impersonation level.
3284 * pPrivs [O] Optional. Information about the privileges of the client.
3285 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
3287 * RETURNS
3288 * Success: S_OK.
3289 * Failure: HRESULT code.
3291 * SEE ALSO
3292 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
3294 HRESULT WINAPI CoQueryClientBlanket(
3295 DWORD *pAuthnSvc,
3296 DWORD *pAuthzSvc,
3297 OLECHAR **pServerPrincName,
3298 DWORD *pAuthnLevel,
3299 DWORD *pImpLevel,
3300 RPC_AUTHZ_HANDLE *pPrivs,
3301 DWORD *pCapabilities)
3303 IServerSecurity *pSrvSec;
3304 HRESULT hr;
3306 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
3307 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
3308 pPrivs, pCapabilities);
3310 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3311 if (SUCCEEDED(hr))
3313 hr = IServerSecurity_QueryBlanket(
3314 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
3315 pImpLevel, pPrivs, pCapabilities);
3316 IServerSecurity_Release(pSrvSec);
3319 return hr;
3322 /***********************************************************************
3323 * CoImpersonateClient [OLE32.@]
3325 * Impersonates the client of the currently executing server call in the
3326 * current thread.
3328 * PARAMS
3329 * None.
3331 * RETURNS
3332 * Success: S_OK.
3333 * Failure: HRESULT code.
3335 * NOTES
3336 * If this function fails then the current thread will not be impersonating
3337 * the client and all actions will take place on behalf of the server.
3338 * Therefore, it is important to check the return value from this function.
3340 * SEE ALSO
3341 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
3343 HRESULT WINAPI CoImpersonateClient(void)
3345 IServerSecurity *pSrvSec;
3346 HRESULT hr;
3348 TRACE("\n");
3350 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3351 if (SUCCEEDED(hr))
3353 hr = IServerSecurity_ImpersonateClient(pSrvSec);
3354 IServerSecurity_Release(pSrvSec);
3357 return hr;
3360 /***********************************************************************
3361 * CoRevertToSelf [OLE32.@]
3363 * Ends the impersonation of the client of the currently executing server
3364 * call in the current thread.
3366 * PARAMS
3367 * None.
3369 * RETURNS
3370 * Success: S_OK.
3371 * Failure: HRESULT code.
3373 * SEE ALSO
3374 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
3376 HRESULT WINAPI CoRevertToSelf(void)
3378 IServerSecurity *pSrvSec;
3379 HRESULT hr;
3381 TRACE("\n");
3383 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3384 if (SUCCEEDED(hr))
3386 hr = IServerSecurity_RevertToSelf(pSrvSec);
3387 IServerSecurity_Release(pSrvSec);
3390 return hr;
3393 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
3395 /* first try to retrieve messages for incoming COM calls to the apartment window */
3396 return PeekMessageW(msg, apt->win, WM_USER, WM_APP - 1, PM_REMOVE|PM_NOYIELD) ||
3397 /* next retrieve other messages necessary for the app to remain responsive */
3398 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_POSTMESSAGE|PM_REMOVE|PM_NOYIELD);
3401 /***********************************************************************
3402 * CoWaitForMultipleHandles [OLE32.@]
3404 * Waits for one or more handles to become signaled.
3406 * PARAMS
3407 * dwFlags [I] Flags. See notes.
3408 * dwTimeout [I] Timeout in milliseconds.
3409 * cHandles [I] Number of handles pointed to by pHandles.
3410 * pHandles [I] Handles to wait for.
3411 * lpdwindex [O] Index of handle that was signaled.
3413 * RETURNS
3414 * Success: S_OK.
3415 * Failure: RPC_S_CALLPENDING on timeout.
3417 * NOTES
3419 * The dwFlags parameter can be zero or more of the following:
3420 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
3421 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
3423 * SEE ALSO
3424 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
3426 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
3427 ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
3429 HRESULT hr = S_OK;
3430 DWORD start_time = GetTickCount();
3431 APARTMENT *apt = COM_CurrentApt();
3432 BOOL message_loop = apt && !apt->multi_threaded;
3434 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
3435 pHandles, lpdwindex);
3437 while (TRUE)
3439 DWORD now = GetTickCount();
3440 DWORD res;
3442 if (now - start_time > dwTimeout)
3444 hr = RPC_S_CALLPENDING;
3445 break;
3448 if (message_loop)
3450 DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
3451 ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
3453 TRACE("waiting for rpc completion or window message\n");
3455 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
3456 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3457 QS_ALLINPUT, wait_flags);
3459 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
3461 MSG msg;
3463 /* call message filter */
3465 if (COM_CurrentApt()->filter)
3467 PENDINGTYPE pendingtype =
3468 COM_CurrentInfo()->pending_call_count_server ?
3469 PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
3470 DWORD be_handled = IMessageFilter_MessagePending(
3471 COM_CurrentApt()->filter, 0 /* FIXME */,
3472 now - start_time, pendingtype);
3473 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
3474 switch (be_handled)
3476 case PENDINGMSG_CANCELCALL:
3477 WARN("call canceled\n");
3478 hr = RPC_E_CALL_CANCELED;
3479 break;
3480 case PENDINGMSG_WAITNOPROCESS:
3481 case PENDINGMSG_WAITDEFPROCESS:
3482 default:
3483 /* FIXME: MSDN is very vague about the difference
3484 * between WAITNOPROCESS and WAITDEFPROCESS - there
3485 * appears to be none, so it is possibly a left-over
3486 * from the 16-bit world. */
3487 break;
3491 /* note: using "if" here instead of "while" might seem less
3492 * efficient, but only if we are optimising for quick delivery
3493 * of pending messages, rather than quick completion of the
3494 * COM call */
3495 if (COM_PeekMessage(apt, &msg))
3497 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
3498 TranslateMessage(&msg);
3499 DispatchMessageW(&msg);
3500 if (msg.message == WM_QUIT)
3502 TRACE("resending WM_QUIT to outer message loop\n");
3503 PostQuitMessage(msg.wParam);
3504 /* no longer need to process messages */
3505 message_loop = FALSE;
3508 continue;
3511 else
3513 TRACE("waiting for rpc completion\n");
3515 res = WaitForMultipleObjectsEx(cHandles, pHandles,
3516 (dwFlags & COWAIT_WAITALL) ? TRUE : FALSE,
3517 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3518 (dwFlags & COWAIT_ALERTABLE) ? TRUE : FALSE);
3521 if (res < WAIT_OBJECT_0 + cHandles)
3523 /* handle signaled, store index */
3524 *lpdwindex = (res - WAIT_OBJECT_0);
3525 break;
3527 else if (res == WAIT_TIMEOUT)
3529 hr = RPC_S_CALLPENDING;
3530 break;
3532 else
3534 ERR("Unexpected wait termination: %d, %d\n", res, GetLastError());
3535 hr = E_UNEXPECTED;
3536 break;
3539 TRACE("-- 0x%08x\n", hr);
3540 return hr;
3544 /***********************************************************************
3545 * CoGetObject [OLE32.@]
3547 * Gets the object named by converting the name to a moniker and binding to it.
3549 * PARAMS
3550 * pszName [I] String representing the object.
3551 * pBindOptions [I] Parameters affecting the binding to the named object.
3552 * riid [I] Interface to bind to on the objecct.
3553 * ppv [O] On output, the interface riid of the object represented
3554 * by pszName.
3556 * RETURNS
3557 * Success: S_OK.
3558 * Failure: HRESULT code.
3560 * SEE ALSO
3561 * MkParseDisplayName.
3563 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
3564 REFIID riid, void **ppv)
3566 IBindCtx *pbc;
3567 HRESULT hr;
3569 *ppv = NULL;
3571 hr = CreateBindCtx(0, &pbc);
3572 if (SUCCEEDED(hr))
3574 if (pBindOptions)
3575 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
3577 if (SUCCEEDED(hr))
3579 ULONG chEaten;
3580 IMoniker *pmk;
3582 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
3583 if (SUCCEEDED(hr))
3585 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
3586 IMoniker_Release(pmk);
3590 IBindCtx_Release(pbc);
3592 return hr;
3595 /***********************************************************************
3596 * CoRegisterChannelHook [OLE32.@]
3598 * Registers a process-wide hook that is called during ORPC calls.
3600 * PARAMS
3601 * guidExtension [I] GUID of the channel hook to register.
3602 * pChannelHook [I] Channel hook object to register.
3604 * RETURNS
3605 * Success: S_OK.
3606 * Failure: HRESULT code.
3608 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
3610 TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
3612 return RPC_RegisterChannelHook(guidExtension, pChannelHook);
3615 typedef struct Context
3617 const IComThreadingInfoVtbl *lpVtbl;
3618 LONG refs;
3619 APTTYPE apttype;
3620 } Context;
3622 static HRESULT WINAPI Context_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv)
3624 *ppv = NULL;
3626 if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
3627 IsEqualIID(riid, &IID_IUnknown))
3629 *ppv = iface;
3630 IUnknown_AddRef(iface);
3631 return S_OK;
3634 FIXME("interface not implemented %s\n", debugstr_guid(riid));
3635 return E_NOINTERFACE;
3638 static ULONG WINAPI Context_AddRef(IComThreadingInfo *iface)
3640 Context *This = (Context *)iface;
3641 return InterlockedIncrement(&This->refs);
3644 static ULONG WINAPI Context_Release(IComThreadingInfo *iface)
3646 Context *This = (Context *)iface;
3647 ULONG refs = InterlockedDecrement(&This->refs);
3648 if (!refs)
3649 HeapFree(GetProcessHeap(), 0, This);
3650 return refs;
3653 static HRESULT WINAPI Context_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
3655 Context *This = (Context *)iface;
3657 TRACE("(%p)\n", apttype);
3659 *apttype = This->apttype;
3660 return S_OK;
3663 static HRESULT WINAPI Context_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
3665 Context *This = (Context *)iface;
3667 TRACE("(%p)\n", thdtype);
3669 switch (This->apttype)
3671 case APTTYPE_STA:
3672 case APTTYPE_MAINSTA:
3673 *thdtype = THDTYPE_PROCESSMESSAGES;
3674 break;
3675 default:
3676 *thdtype = THDTYPE_BLOCKMESSAGES;
3677 break;
3679 return S_OK;
3682 static HRESULT WINAPI Context_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
3684 FIXME("(%p): stub\n", logical_thread_id);
3685 return E_NOTIMPL;
3688 static HRESULT WINAPI Context_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
3690 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
3691 return E_NOTIMPL;
3694 static const IComThreadingInfoVtbl Context_Threading_Vtbl =
3696 Context_QueryInterface,
3697 Context_AddRef,
3698 Context_Release,
3699 Context_GetCurrentApartmentType,
3700 Context_GetCurrentThreadType,
3701 Context_GetCurrentLogicalThreadId,
3702 Context_SetCurrentLogicalThreadId
3705 /***********************************************************************
3706 * CoGetObjectContext [OLE32.@]
3708 * Retrieves an object associated with the current context (i.e. apartment).
3710 * PARAMS
3711 * riid [I] ID of the interface of the object to retrieve.
3712 * ppv [O] Address where object will be stored on return.
3714 * RETURNS
3715 * Success: S_OK.
3716 * Failure: HRESULT code.
3718 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
3720 APARTMENT *apt = COM_CurrentApt();
3721 Context *context;
3722 HRESULT hr;
3724 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
3726 *ppv = NULL;
3727 if (!apt)
3729 ERR("apartment not initialised\n");
3730 return CO_E_NOTINITIALIZED;
3733 context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
3734 if (!context)
3735 return E_OUTOFMEMORY;
3737 context->lpVtbl = &Context_Threading_Vtbl;
3738 context->refs = 1;
3739 if (apt->multi_threaded)
3740 context->apttype = APTTYPE_MTA;
3741 else if (apt->main)
3742 context->apttype = APTTYPE_MAINSTA;
3743 else
3744 context->apttype = APTTYPE_STA;
3746 hr = IUnknown_QueryInterface((IUnknown *)&context->lpVtbl, riid, ppv);
3747 IUnknown_Release((IUnknown *)&context->lpVtbl);
3749 return hr;
3753 /***********************************************************************
3754 * CoGetContextToken [OLE32.@]
3756 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
3758 static int calls;
3759 if(!(calls++)) FIXME( "stub\n" );
3760 if (token) *token = 0;
3761 return E_NOTIMPL;
3765 /***********************************************************************
3766 * DllMain (OLE32.@)
3768 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
3770 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad);
3772 switch(fdwReason) {
3773 case DLL_PROCESS_ATTACH:
3774 OLE32_hInstance = hinstDLL;
3775 COMPOBJ_InitProcess();
3776 if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1);
3777 break;
3779 case DLL_PROCESS_DETACH:
3780 if (TRACE_ON(ole)) CoRevokeMallocSpy();
3781 OLEDD_UnInitialize();
3782 COMPOBJ_UninitProcess();
3783 RPC_UnregisterAllChannelHooks();
3784 COMPOBJ_DllList_Free();
3785 OLE32_hInstance = 0;
3786 break;
3788 case DLL_THREAD_DETACH:
3789 COM_TlsDestroy();
3790 break;
3792 return TRUE;
3795 /* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */