ole32: Fixed typo in debug statement.
[wine/multimedia.git] / dlls / ole32 / compobj.c
blob56c8db87cf6b5a788f255d064e040aa7710598f5
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
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 * Note
26 * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED
27 * Therefore do not test against COINIT_MULTITHREADED
29 * TODO list: (items bunched together depend on each other)
31 * - Implement the service control manager (in rpcss) to keep track
32 * of registered class objects: ISCM::ServerRegisterClsid et al
33 * - Implement the OXID resolver so we don't need magic endpoint names for
34 * clients and servers to meet up
36 * - Call IMessageFilter functions.
38 * - Make all ole interface marshaling use NDR to be wire compatible with
39 * native DCOM
40 * - Use & interpret ORPCTHIS & ORPCTHAT.
44 #include "config.h"
46 #include <stdlib.h>
47 #include <stdarg.h>
48 #include <stdio.h>
49 #include <string.h>
50 #include <assert.h>
52 #define COBJMACROS
53 #define NONAMELESSUNION
54 #define NONAMELESSSTRUCT
56 #include "windef.h"
57 #include "winbase.h"
58 #include "winerror.h"
59 #include "winreg.h"
60 #include "winuser.h"
61 #include "objbase.h"
62 #include "ole2.h"
63 #include "ole2ver.h"
65 #include "compobj_private.h"
67 #include "wine/unicode.h"
68 #include "wine/debug.h"
70 WINE_DEFAULT_DEBUG_CHANNEL(ole);
72 HINSTANCE OLE32_hInstance = 0; /* FIXME: make static ... */
74 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
76 /****************************************************************************
77 * This section defines variables internal to the COM module.
79 * TODO: Most of these things will have to be made thread-safe.
82 static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk);
83 static void COM_RevokeAllClasses(void);
85 const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
87 APARTMENT *MTA; /* protected by csApartment */
88 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
90 static CRITICAL_SECTION csApartment;
91 static CRITICAL_SECTION_DEBUG critsect_debug =
93 0, 0, &csApartment,
94 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
95 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
97 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
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;
107 * This linked list contains the list of registered class objects. These
108 * are mostly used to register the factories for out-of-proc servers of OLE
109 * objects.
111 * TODO: Make this data structure aware of inter-process communication. This
112 * means that parts of this will be exported to the Wine Server.
114 typedef struct tagRegisteredClass
116 CLSID classIdentifier;
117 LPUNKNOWN classObject;
118 DWORD runContext;
119 DWORD connectFlags;
120 DWORD dwCookie;
121 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
122 struct tagRegisteredClass* nextClass;
123 } RegisteredClass;
125 static RegisteredClass* firstRegisteredClass = NULL;
127 static CRITICAL_SECTION csRegisteredClassList;
128 static CRITICAL_SECTION_DEBUG class_cs_debug =
130 0, 0, &csRegisteredClassList,
131 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
132 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
134 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
136 /*****************************************************************************
137 * This section contains OpenDllList definitions
139 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
140 * other functions that do LoadLibrary _without_ giving back a HMODULE.
141 * Without this list these handles would never be freed.
143 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
144 * next unload-call but not before 600 sec.
147 typedef struct tagOpenDll {
148 HINSTANCE hLibrary;
149 struct tagOpenDll *next;
150 } OpenDll;
152 static OpenDll *openDllList = NULL; /* linked list of open dlls */
154 static CRITICAL_SECTION csOpenDllList;
155 static CRITICAL_SECTION_DEBUG dll_cs_debug =
157 0, 0, &csOpenDllList,
158 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
159 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
161 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
163 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',' ',
164 '0','x','#','#','#','#','#','#','#','#',' ',0};
165 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
167 static void COMPOBJ_DLLList_Add(HANDLE hLibrary);
168 static void COMPOBJ_DllList_FreeUnused(int Timeout);
170 static void COMPOBJ_InitProcess( void )
172 WNDCLASSW wclass;
174 /* Dispatching to the correct thread in an apartment is done through
175 * window messages rather than RPC transports. When an interface is
176 * marshalled into another apartment in the same process, a window of the
177 * following class is created. The *caller* of CoMarshalInterface (ie the
178 * application) is responsible for pumping the message loop in that thread.
179 * The WM_USER messages which point to the RPCs are then dispatched to
180 * COM_AptWndProc by the user's code from the apartment in which the interface
181 * was unmarshalled.
183 memset(&wclass, 0, sizeof(wclass));
184 wclass.lpfnWndProc = apartment_wndproc;
185 wclass.hInstance = OLE32_hInstance;
186 wclass.lpszClassName = wszAptWinClass;
187 RegisterClassW(&wclass);
190 static void COMPOBJ_UninitProcess( void )
192 UnregisterClassW(wszAptWinClass, OLE32_hInstance);
195 static void COM_TlsDestroy(void)
197 struct oletls *info = NtCurrentTeb()->ReservedForOle;
198 if (info)
200 if (info->apt) apartment_release(info->apt);
201 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
202 if (info->state) IUnknown_Release(info->state);
203 HeapFree(GetProcessHeap(), 0, info);
204 NtCurrentTeb()->ReservedForOle = NULL;
208 /******************************************************************************
209 * Manage apartments.
212 /* allocates memory and fills in the necessary fields for a new apartment
213 * object */
214 static APARTMENT *apartment_construct(DWORD model)
216 APARTMENT *apt;
218 TRACE("creating new apartment, model=%ld\n", model);
220 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
221 apt->tid = GetCurrentThreadId();
223 list_init(&apt->proxies);
224 list_init(&apt->stubmgrs);
225 apt->ipidc = 0;
226 apt->refs = 1;
227 apt->remunk_exported = FALSE;
228 apt->oidc = 1;
229 InitializeCriticalSection(&apt->cs);
230 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
232 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
234 if (apt->multi_threaded)
236 /* FIXME: should be randomly generated by in an RPC call to rpcss */
237 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
239 else
241 /* FIXME: should be randomly generated by in an RPC call to rpcss */
242 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
245 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
247 /* the locking here is not currently needed for the MTA case, but it
248 * doesn't hurt and makes the code simpler */
249 EnterCriticalSection(&csApartment);
250 list_add_head(&apts, &apt->entry);
251 LeaveCriticalSection(&csApartment);
253 return apt;
256 /* gets and existing apartment if one exists or otherwise creates an apartment
257 * structure which stores OLE apartment-local information and stores a pointer
258 * to it in the thread-local storage */
259 static APARTMENT *apartment_get_or_create(DWORD model)
261 APARTMENT *apt = COM_CurrentApt();
263 if (!apt)
265 if (model & COINIT_APARTMENTTHREADED)
267 apt = apartment_construct(model);
268 COM_CurrentInfo()->apt = apt;
270 else
272 EnterCriticalSection(&csApartment);
274 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
275 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
276 * in a process */
277 if (MTA)
279 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
280 apartment_addref(MTA);
282 else
283 MTA = apartment_construct(model);
285 apt = MTA;
286 COM_CurrentInfo()->apt = apt;
288 LeaveCriticalSection(&csApartment);
292 return apt;
295 static inline BOOL apartment_is_model(APARTMENT *apt, DWORD model)
297 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
300 DWORD apartment_addref(struct apartment *apt)
302 DWORD refs = InterlockedIncrement(&apt->refs);
303 TRACE("%s: before = %ld\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
304 return refs;
307 DWORD apartment_release(struct apartment *apt)
309 DWORD ret;
311 EnterCriticalSection(&csApartment);
313 ret = InterlockedDecrement(&apt->refs);
314 TRACE("%s: after = %ld\n", wine_dbgstr_longlong(apt->oxid), ret);
315 /* destruction stuff that needs to happen under csApartment CS */
316 if (ret == 0)
318 if (apt == MTA) MTA = NULL;
319 list_remove(&apt->entry);
322 LeaveCriticalSection(&csApartment);
324 if (ret == 0)
326 struct list *cursor, *cursor2;
328 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
330 /* no locking is needed for this apartment, because no other thread
331 * can access it at this point */
333 apartment_disconnectproxies(apt);
335 if (apt->win) DestroyWindow(apt->win);
337 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
339 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
340 /* release the implicit reference given by the fact that the
341 * stub has external references (it must do since it is in the
342 * stub manager list in the apartment and all non-apartment users
343 * must have a ref on the apartment and so it cannot be destroyed).
345 stub_manager_int_release(stubmgr);
348 /* if this assert fires, then another thread took a reference to a
349 * stub manager without taking a reference to the containing
350 * apartment, which it must do. */
351 assert(list_empty(&apt->stubmgrs));
353 if (apt->filter) IUnknown_Release(apt->filter);
355 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
356 DeleteCriticalSection(&apt->cs);
358 HeapFree(GetProcessHeap(), 0, apt);
361 return ret;
364 /* The given OXID must be local to this process:
366 * The ref parameter is here mostly to ensure people remember that
367 * they get one, you should normally take a ref for thread safety.
369 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
371 APARTMENT *result = NULL;
372 struct list *cursor;
374 EnterCriticalSection(&csApartment);
375 LIST_FOR_EACH( cursor, &apts )
377 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
378 if (apt->oxid == oxid)
380 result = apt;
381 if (ref) apartment_addref(result);
382 break;
385 LeaveCriticalSection(&csApartment);
387 return result;
390 /* gets the apartment which has a given creator thread ID. The caller must
391 * release the reference from the apartment as soon as the apartment pointer
392 * is no longer required. */
393 APARTMENT *apartment_findfromtid(DWORD tid)
395 APARTMENT *result = NULL;
396 struct list *cursor;
398 EnterCriticalSection(&csApartment);
399 LIST_FOR_EACH( cursor, &apts )
401 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
402 if (apt->tid == tid)
404 result = apt;
405 apartment_addref(result);
406 break;
409 LeaveCriticalSection(&csApartment);
411 return result;
414 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
416 switch (msg)
418 case DM_EXECUTERPC:
419 RPC_ExecuteCall((struct dispatch_params *)lParam);
420 return 0;
421 default:
422 return DefWindowProcW(hWnd, msg, wParam, lParam);
426 HRESULT apartment_createwindowifneeded(struct apartment *apt)
428 if (apt->multi_threaded)
429 return S_OK;
431 if (!apt->win)
433 HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0,
434 0, 0, 0, 0,
435 0, 0, OLE32_hInstance, NULL);
436 if (!hwnd)
438 ERR("CreateWindow failed with error %ld\n", GetLastError());
439 return HRESULT_FROM_WIN32(GetLastError());
441 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
442 /* someone beat us to it */
443 DestroyWindow(hwnd);
446 return S_OK;
449 HWND apartment_getwindow(struct apartment *apt)
451 assert(!apt->multi_threaded);
452 return apt->win;
455 void apartment_joinmta(void)
457 apartment_addref(MTA);
458 COM_CurrentInfo()->apt = MTA;
461 /*****************************************************************************
462 * This section contains OpenDllList implemantation
465 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
467 OpenDll *ptr;
468 OpenDll *tmp;
470 TRACE("\n");
472 EnterCriticalSection( &csOpenDllList );
474 if (openDllList == NULL) {
475 /* empty list -- add first node */
476 openDllList = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
477 openDllList->hLibrary=hLibrary;
478 openDllList->next = NULL;
479 } else {
480 /* search for this dll */
481 int found = FALSE;
482 for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
483 if (ptr->hLibrary == hLibrary) {
484 found = TRUE;
485 break;
488 if (!found) {
489 /* dll not found, add it */
490 tmp = openDllList;
491 openDllList = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
492 openDllList->hLibrary = hLibrary;
493 openDllList->next = tmp;
497 LeaveCriticalSection( &csOpenDllList );
500 static void COMPOBJ_DllList_FreeUnused(int Timeout)
502 OpenDll *curr, *next, *prev = NULL;
503 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
504 DllCanUnloadNowFunc DllCanUnloadNow;
506 TRACE("\n");
508 EnterCriticalSection( &csOpenDllList );
510 for (curr = openDllList; curr != NULL; ) {
511 DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
513 if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
514 next = curr->next;
516 TRACE("freeing %p\n", curr->hLibrary);
517 FreeLibrary(curr->hLibrary);
519 HeapFree(GetProcessHeap(), 0, curr);
520 if (curr == openDllList) {
521 openDllList = next;
522 } else {
523 prev->next = next;
526 curr = next;
527 } else {
528 prev = curr;
529 curr = curr->next;
533 LeaveCriticalSection( &csOpenDllList );
536 /******************************************************************************
537 * CoBuildVersion [OLE32.@]
538 * CoBuildVersion [COMPOBJ.1]
540 * Gets the build version of the DLL.
542 * PARAMS
544 * RETURNS
545 * Current build version, hiword is majornumber, loword is minornumber
547 DWORD WINAPI CoBuildVersion(void)
549 TRACE("Returning version %d, build %d.\n", rmm, rup);
550 return (rmm<<16)+rup;
553 /******************************************************************************
554 * CoInitialize [OLE32.@]
556 * Initializes the COM libraries by calling CoInitializeEx with
557 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
559 * PARAMS
560 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
562 * RETURNS
563 * Success: S_OK if not already initialized, S_FALSE otherwise.
564 * Failure: HRESULT code.
566 * SEE ALSO
567 * CoInitializeEx
569 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
572 * Just delegate to the newer method.
574 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
577 /******************************************************************************
578 * CoInitializeEx [OLE32.@]
580 * Initializes the COM libraries.
582 * PARAMS
583 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
584 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
586 * RETURNS
587 * S_OK if successful,
588 * S_FALSE if this function was called already.
589 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
590 * threading model.
592 * NOTES
594 * The behavior used to set the IMalloc used for memory management is
595 * obsolete.
596 * The dwCoInit parameter must specify of of the following apartment
597 * threading models:
598 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
599 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
600 * The parameter may also specify zero or more of the following flags:
601 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
602 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
604 * SEE ALSO
605 * CoUninitialize
607 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
609 HRESULT hr = S_OK;
610 APARTMENT *apt;
612 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
614 if (lpReserved!=NULL)
616 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
620 * Check the lock count. If this is the first time going through the initialize
621 * process, we have to initialize the libraries.
623 * And crank-up that lock count.
625 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
628 * Initialize the various COM libraries and data structures.
630 TRACE("() - Initializing the COM libraries\n");
632 /* we may need to defer this until after apartment initialisation */
633 RunningObjectTableImpl_Initialize();
636 if (!(apt = COM_CurrentInfo()->apt))
638 apt = apartment_get_or_create(dwCoInit);
639 if (!apt) return E_OUTOFMEMORY;
641 else if (!apartment_is_model(apt, dwCoInit))
643 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
644 code then we are probably using the wrong threading model to implement that API. */
645 ERR("Attempt to change threading model of this apartment from %s to %s\n",
646 apt->multi_threaded ? "multi-threaded" : "apartment threaded",
647 dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
648 return RPC_E_CHANGED_MODE;
650 else
651 hr = S_FALSE;
653 COM_CurrentInfo()->inits++;
655 return hr;
658 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
659 pending RPCs are ignored. Non-COM messages are discarded at this point.
661 static void COM_FlushMessageQueue(void)
663 MSG message;
664 APARTMENT *apt = COM_CurrentApt();
666 if (!apt || !apt->win) return;
668 TRACE("Flushing STA message queue\n");
670 while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE))
672 if (message.hwnd != apt->win)
674 WARN("discarding message 0x%x for window %p\n", message.message, message.hwnd);
675 continue;
678 TranslateMessage(&message);
679 DispatchMessageA(&message);
683 /***********************************************************************
684 * CoUninitialize [OLE32.@]
686 * This method will decrement the refcount on the current apartment, freeing
687 * the resources associated with it if it is the last thread in the apartment.
688 * If the last apartment is freed, the function will additionally release
689 * any COM resources associated with the process.
691 * PARAMS
693 * RETURNS
694 * Nothing.
696 * SEE ALSO
697 * CoInitializeEx
699 void WINAPI CoUninitialize(void)
701 struct oletls * info = COM_CurrentInfo();
702 LONG lCOMRefCnt;
704 TRACE("()\n");
706 /* will only happen on OOM */
707 if (!info) return;
709 /* sanity check */
710 if (!info->inits)
712 ERR("Mismatched CoUninitialize\n");
713 return;
716 if (!--info->inits)
718 apartment_release(info->apt);
719 info->apt = NULL;
723 * Decrease the reference count.
724 * If we are back to 0 locks on the COM library, make sure we free
725 * all the associated data structures.
727 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
728 if (lCOMRefCnt==1)
730 TRACE("() - Releasing the COM libraries\n");
732 RunningObjectTableImpl_UnInitialize();
734 /* Release the references to the registered class objects */
735 COM_RevokeAllClasses();
737 /* This will free the loaded COM Dlls */
738 CoFreeAllLibraries();
740 /* This ensures we deal with any pending RPCs */
741 COM_FlushMessageQueue();
743 else if (lCOMRefCnt<1) {
744 ERR( "CoUninitialize() - not CoInitialized.\n" );
745 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
749 /******************************************************************************
750 * CoDisconnectObject [OLE32.@]
751 * CoDisconnectObject [COMPOBJ.15]
753 * Disconnects all connections to this object from remote processes. Dispatches
754 * pending RPCs while blocking new RPCs from occurring, and then calls
755 * IMarshal::DisconnectObject on the given object.
757 * Typically called when the object server is forced to shut down, for instance by
758 * the user.
760 * PARAMS
761 * lpUnk [I] The object whose stub should be disconnected.
762 * reserved [I] Reserved. Should be set to 0.
764 * RETURNS
765 * Success: S_OK.
766 * Failure: HRESULT code.
768 * SEE ALSO
769 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
771 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
773 HRESULT hr;
774 IMarshal *marshal;
775 APARTMENT *apt;
777 TRACE("(%p, 0x%08lx)\n", lpUnk, reserved);
779 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
780 if (hr == S_OK)
782 hr = IMarshal_DisconnectObject(marshal, reserved);
783 IMarshal_Release(marshal);
784 return hr;
787 apt = COM_CurrentApt();
788 if (!apt)
789 return CO_E_NOTINITIALIZED;
791 apartment_disconnectobject(apt, lpUnk);
793 /* Note: native is pretty broken here because it just silently
794 * fails, without returning an appropriate error code if the object was
795 * not found, making apps think that the object was disconnected, when
796 * it actually wasn't */
798 return S_OK;
801 /******************************************************************************
802 * CoCreateGuid [OLE32.@]
804 * Simply forwards to UuidCreate in RPCRT4.
806 * PARAMS
807 * pguid [O] Points to the GUID to initialize.
809 * RETURNS
810 * Success: S_OK.
811 * Failure: HRESULT code.
813 * SEE ALSO
814 * UuidCreate
816 HRESULT WINAPI CoCreateGuid(GUID *pguid)
818 return UuidCreate(pguid);
821 /******************************************************************************
822 * CLSIDFromString [OLE32.@]
823 * IIDFromString [OLE32.@]
825 * Converts a unique identifier from its string representation into
826 * the GUID struct.
828 * PARAMS
829 * idstr [I] The string representation of the GUID.
830 * id [O] GUID converted from the string.
832 * RETURNS
833 * S_OK on success
834 * CO_E_CLASSSTRING if idstr is not a valid CLSID
836 * SEE ALSO
837 * StringFromCLSID
839 static HRESULT WINAPI __CLSIDFromString(LPCWSTR s, CLSID *id)
841 int i;
842 BYTE table[256];
844 if (!s) {
845 memset( id, 0, sizeof (CLSID) );
846 return S_OK;
849 /* validate the CLSID string */
850 if (strlenW(s) != 38)
851 return CO_E_CLASSSTRING;
853 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
854 return CO_E_CLASSSTRING;
856 for (i=1; i<37; i++) {
857 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
858 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
859 ((s[i] >= 'a') && (s[i] <= 'f')) ||
860 ((s[i] >= 'A') && (s[i] <= 'F'))))
861 return CO_E_CLASSSTRING;
864 TRACE("%s -> %p\n", debugstr_w(s), id);
866 /* quick lookup table */
867 memset(table, 0, 256);
869 for (i = 0; i < 10; i++) {
870 table['0' + i] = i;
872 for (i = 0; i < 6; i++) {
873 table['A' + i] = i+10;
874 table['a' + i] = i+10;
877 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
879 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
880 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
881 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
882 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
884 /* these are just sequential bytes */
885 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
886 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
887 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
888 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
889 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
890 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
891 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
892 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
894 return S_OK;
897 /*****************************************************************************/
899 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
901 HRESULT ret;
903 ret = __CLSIDFromString(idstr, id);
904 if(ret != S_OK) { /* It appears a ProgID is also valid */
905 ret = CLSIDFromProgID(idstr, id);
907 return ret;
910 /* Converts a GUID into the respective string representation. */
911 HRESULT WINE_StringFromCLSID(
912 const CLSID *id, /* [in] GUID to be converted */
913 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
915 static const char *hex = "0123456789ABCDEF";
916 char *s;
917 int i;
919 if (!id)
920 { ERR("called with id=Null\n");
921 *idstr = 0x00;
922 return E_FAIL;
925 sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
926 id->Data1, id->Data2, id->Data3,
927 id->Data4[0], id->Data4[1]);
928 s = &idstr[25];
930 /* 6 hex bytes */
931 for (i = 2; i < 8; i++) {
932 *s++ = hex[id->Data4[i]>>4];
933 *s++ = hex[id->Data4[i] & 0xf];
936 *s++ = '}';
937 *s++ = '\0';
939 TRACE("%p->%s\n", id, idstr);
941 return S_OK;
945 /******************************************************************************
946 * StringFromCLSID [OLE32.@]
947 * StringFromIID [OLE32.@]
949 * Converts a GUID into the respective string representation.
950 * The target string is allocated using the OLE IMalloc.
952 * PARAMS
953 * id [I] the GUID to be converted.
954 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
956 * RETURNS
957 * S_OK
958 * E_FAIL
960 * SEE ALSO
961 * StringFromGUID2, CLSIDFromString
963 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
965 char buf[80];
966 HRESULT ret;
967 LPMALLOC mllc;
969 if ((ret = CoGetMalloc(0,&mllc)))
970 return ret;
972 ret=WINE_StringFromCLSID(id,buf);
973 if (!ret) {
974 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
975 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
976 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
978 return ret;
981 /******************************************************************************
982 * StringFromGUID2 [OLE32.@]
983 * StringFromGUID2 [COMPOBJ.76]
985 * Modified version of StringFromCLSID that allows you to specify max
986 * buffer size.
988 * PARAMS
989 * id [I] GUID to convert to string.
990 * str [O] Buffer where the result will be stored.
991 * cmax [I] Size of the buffer in characters.
993 * RETURNS
994 * Success: The length of the resulting string in characters.
995 * Failure: 0.
997 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
999 char xguid[80];
1001 if (WINE_StringFromCLSID(id,xguid))
1002 return 0;
1003 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
1006 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
1007 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
1009 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1010 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
1011 LONG res;
1012 HKEY key;
1014 strcpyW(path, wszCLSIDSlash);
1015 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
1016 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, keyname ? KEY_READ : access, &key);
1017 if (res == ERROR_FILE_NOT_FOUND)
1018 return REGDB_E_CLASSNOTREG;
1019 else if (res != ERROR_SUCCESS)
1020 return REGDB_E_READREGDB;
1022 if (!keyname)
1024 *subkey = key;
1025 return S_OK;
1028 res = RegOpenKeyExW(key, keyname, 0, access, subkey);
1029 RegCloseKey(key);
1030 if (res == ERROR_FILE_NOT_FOUND)
1031 return REGDB_E_KEYMISSING;
1032 else if (res != ERROR_SUCCESS)
1033 return REGDB_E_READREGDB;
1035 return S_OK;
1038 /******************************************************************************
1039 * ProgIDFromCLSID [OLE32.@]
1041 * Converts a class id into the respective program ID.
1043 * PARAMS
1044 * clsid [I] Class ID, as found in registry.
1045 * lplpszProgID [O] Associated ProgID.
1047 * RETURNS
1048 * S_OK
1049 * E_OUTOFMEMORY
1050 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1052 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *lplpszProgID)
1054 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
1055 HKEY hkey;
1056 HRESULT ret;
1057 LONG progidlen = 0;
1059 *lplpszProgID = NULL;
1060 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
1061 if (FAILED(ret))
1062 return ret;
1064 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1065 ret = REGDB_E_CLASSNOTREG;
1067 if (ret == S_OK)
1069 *lplpszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
1070 if (*lplpszProgID)
1072 if (RegQueryValueW(hkey, NULL, *lplpszProgID, &progidlen))
1073 ret = REGDB_E_CLASSNOTREG;
1075 else
1076 ret = E_OUTOFMEMORY;
1079 RegCloseKey(hkey);
1080 return ret;
1083 /******************************************************************************
1084 * CLSIDFromProgID [OLE32.@]
1086 * Converts a program id into the respective GUID.
1088 * PARAMS
1089 * progid [I] Unicode program ID, as found in registry.
1090 * riid [O] Associated CLSID.
1092 * RETURNS
1093 * Success: S_OK
1094 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1096 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID riid)
1098 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1099 WCHAR buf2[CHARS_IN_GUID];
1100 LONG buf2len = sizeof(buf2);
1101 HKEY xhkey;
1103 WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1104 strcpyW( buf, progid );
1105 strcatW( buf, clsidW );
1106 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1108 HeapFree(GetProcessHeap(),0,buf);
1109 return CO_E_CLASSSTRING;
1111 HeapFree(GetProcessHeap(),0,buf);
1113 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
1115 RegCloseKey(xhkey);
1116 return CO_E_CLASSSTRING;
1118 RegCloseKey(xhkey);
1119 return CLSIDFromString(buf2,riid);
1123 /*****************************************************************************
1124 * CoGetPSClsid [OLE32.@]
1126 * Retrieves the CLSID of the proxy/stub factory that implements
1127 * IPSFactoryBuffer for the specified interface.
1129 * PARAMS
1130 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1131 * pclsid [O] Where to store returned proxy/stub CLSID.
1133 * RETURNS
1134 * S_OK
1135 * E_OUTOFMEMORY
1136 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1138 * NOTES
1140 * The standard marshaller activates the object with the CLSID
1141 * returned and uses the CreateProxy and CreateStub methods on its
1142 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1143 * given object.
1145 * CoGetPSClsid determines this CLSID by searching the
1146 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1147 * in the registry and any interface id registered by
1148 * CoRegisterPSClsid within the current process.
1150 * BUGS
1152 * We only search the registry, not ids registered with
1153 * CoRegisterPSClsid.
1154 * Also, native returns S_OK for interfaces with a key in HKCR\Interface, but
1155 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1156 * considered a bug in native unless an application depends on this (unlikely).
1158 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1160 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
1161 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
1162 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
1163 WCHAR value[CHARS_IN_GUID];
1164 LONG len;
1165 HKEY hkey;
1167 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1169 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
1170 strcpyW(path, wszInterface);
1171 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
1172 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
1174 /* Open the key.. */
1175 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &hkey))
1177 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1178 return REGDB_E_IIDNOTREG;
1181 /* ... Once we have the key, query the registry to get the
1182 value of CLSID as a string, and convert it into a
1183 proper CLSID structure to be passed back to the app */
1184 len = sizeof(value);
1185 if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
1187 RegCloseKey(hkey);
1188 return REGDB_E_IIDNOTREG;
1190 RegCloseKey(hkey);
1192 /* We have the CLSid we want back from the registry as a string, so
1193 lets convert it into a CLSID structure */
1194 if (CLSIDFromString(value, pclsid) != NOERROR)
1195 return REGDB_E_IIDNOTREG;
1197 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1198 return S_OK;
1203 /***********************************************************************
1204 * WriteClassStm (OLE32.@)
1206 * Writes a CLSID to a stream.
1208 * PARAMS
1209 * pStm [I] Stream to write to.
1210 * rclsid [I] CLSID to write.
1212 * RETURNS
1213 * Success: S_OK.
1214 * Failure: HRESULT code.
1216 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
1218 TRACE("(%p,%p)\n",pStm,rclsid);
1220 if (rclsid==NULL)
1221 return E_INVALIDARG;
1223 return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
1226 /***********************************************************************
1227 * ReadClassStm (OLE32.@)
1229 * Reads a CLSID from a stream.
1231 * PARAMS
1232 * pStm [I] Stream to read from.
1233 * rclsid [O] CLSID to read.
1235 * RETURNS
1236 * Success: S_OK.
1237 * Failure: HRESULT code.
1239 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
1241 ULONG nbByte;
1242 HRESULT res;
1244 TRACE("(%p,%p)\n",pStm,pclsid);
1246 if (pclsid==NULL)
1247 return E_INVALIDARG;
1249 res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
1251 if (FAILED(res))
1252 return res;
1254 if (nbByte != sizeof(CLSID))
1255 return S_FALSE;
1256 else
1257 return S_OK;
1261 /***
1262 * COM_GetRegisteredClassObject
1264 * This internal method is used to scan the registered class list to
1265 * find a class object.
1267 * Params:
1268 * rclsid Class ID of the class to find.
1269 * dwClsContext Class context to match.
1270 * ppv [out] returns a pointer to the class object. Complying
1271 * to normal COM usage, this method will increase the
1272 * reference count on this object.
1274 static HRESULT COM_GetRegisteredClassObject(
1275 REFCLSID rclsid,
1276 DWORD dwClsContext,
1277 LPUNKNOWN* ppUnk)
1279 HRESULT hr = S_FALSE;
1280 RegisteredClass* curClass;
1282 EnterCriticalSection( &csRegisteredClassList );
1285 * Sanity check
1287 assert(ppUnk!=0);
1290 * Iterate through the whole list and try to match the class ID.
1292 curClass = firstRegisteredClass;
1294 while (curClass != 0)
1297 * Check if we have a match on the class ID.
1299 if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
1302 * Since we don't do out-of process or DCOM just right away, let's ignore the
1303 * class context.
1307 * We have a match, return the pointer to the class object.
1309 *ppUnk = curClass->classObject;
1311 IUnknown_AddRef(curClass->classObject);
1313 hr = S_OK;
1314 goto end;
1318 * Step to the next class in the list.
1320 curClass = curClass->nextClass;
1323 end:
1324 LeaveCriticalSection( &csRegisteredClassList );
1326 * If we get to here, we haven't found our class.
1328 return hr;
1331 /******************************************************************************
1332 * CoRegisterClassObject [OLE32.@]
1334 * Registers the class object for a given class ID. Servers housed in EXE
1335 * files use this method instead of exporting DllGetClassObject to allow
1336 * other code to connect to their objects.
1338 * PARAMS
1339 * rclsid [I] CLSID of the object to register.
1340 * pUnk [I] IUnknown of the object.
1341 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1342 * flags [I] REGCLS flags indicating how connections are made.
1343 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1345 * RETURNS
1346 * S_OK on success,
1347 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1348 * CO_E_OBJISREG if the object is already registered. We should not return this.
1350 * SEE ALSO
1351 * CoRevokeClassObject, CoGetClassObject
1353 * BUGS
1354 * MSDN claims that multiple interface registrations are legal, but we
1355 * can't do that with our current implementation.
1357 HRESULT WINAPI CoRegisterClassObject(
1358 REFCLSID rclsid,
1359 LPUNKNOWN pUnk,
1360 DWORD dwClsContext,
1361 DWORD flags,
1362 LPDWORD lpdwRegister)
1364 RegisteredClass* newClass;
1365 LPUNKNOWN foundObject;
1366 HRESULT hr;
1368 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1369 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1371 if ( (lpdwRegister==0) || (pUnk==0) )
1372 return E_INVALIDARG;
1374 if (!COM_CurrentApt())
1376 ERR("COM was not initialized\n");
1377 return CO_E_NOTINITIALIZED;
1380 *lpdwRegister = 0;
1383 * First, check if the class is already registered.
1384 * If it is, this should cause an error.
1386 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1387 if (hr == S_OK) {
1388 if (flags & REGCLS_MULTIPLEUSE) {
1389 if (dwClsContext & CLSCTX_LOCAL_SERVER)
1390 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
1391 IUnknown_Release(foundObject);
1392 return hr;
1394 IUnknown_Release(foundObject);
1395 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
1396 return CO_E_OBJISREG;
1399 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1400 if ( newClass == NULL )
1401 return E_OUTOFMEMORY;
1403 EnterCriticalSection( &csRegisteredClassList );
1405 newClass->classIdentifier = *rclsid;
1406 newClass->runContext = dwClsContext;
1407 newClass->connectFlags = flags;
1408 newClass->pMarshaledData = NULL;
1411 * Use the address of the chain node as the cookie since we are sure it's
1412 * unique. FIXME: not on 64-bit platforms.
1414 newClass->dwCookie = (DWORD)newClass;
1415 newClass->nextClass = firstRegisteredClass;
1418 * Since we're making a copy of the object pointer, we have to increase its
1419 * reference count.
1421 newClass->classObject = pUnk;
1422 IUnknown_AddRef(newClass->classObject);
1424 firstRegisteredClass = newClass;
1425 LeaveCriticalSection( &csRegisteredClassList );
1427 *lpdwRegister = newClass->dwCookie;
1429 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1430 IClassFactory *classfac;
1432 hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory,
1433 (LPVOID*)&classfac);
1434 if (hr) return hr;
1436 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
1437 if (hr) {
1438 FIXME("Failed to create stream on hglobal, %lx\n", hr);
1439 IUnknown_Release(classfac);
1440 return hr;
1442 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
1443 (LPVOID)classfac, MSHCTX_LOCAL, NULL,
1444 MSHLFLAGS_TABLESTRONG);
1445 if (hr) {
1446 FIXME("CoMarshalInterface failed, %lx!\n",hr);
1447 IUnknown_Release(classfac);
1448 return hr;
1451 IUnknown_Release(classfac);
1453 RPC_StartLocalServer(&newClass->classIdentifier, newClass->pMarshaledData);
1455 return S_OK;
1458 /***********************************************************************
1459 * CoRevokeClassObject [OLE32.@]
1461 * Removes a class object from the class registry.
1463 * PARAMS
1464 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1466 * RETURNS
1467 * Success: S_OK.
1468 * Failure: HRESULT code.
1470 * SEE ALSO
1471 * CoRegisterClassObject
1473 HRESULT WINAPI CoRevokeClassObject(
1474 DWORD dwRegister)
1476 HRESULT hr = E_INVALIDARG;
1477 RegisteredClass** prevClassLink;
1478 RegisteredClass* curClass;
1480 TRACE("(%08lx)\n",dwRegister);
1482 EnterCriticalSection( &csRegisteredClassList );
1485 * Iterate through the whole list and try to match the cookie.
1487 curClass = firstRegisteredClass;
1488 prevClassLink = &firstRegisteredClass;
1490 while (curClass != 0)
1493 * Check if we have a match on the cookie.
1495 if (curClass->dwCookie == dwRegister)
1498 * Remove the class from the chain.
1500 *prevClassLink = curClass->nextClass;
1503 * Release the reference to the class object.
1505 IUnknown_Release(curClass->classObject);
1507 if (curClass->pMarshaledData)
1509 LARGE_INTEGER zero;
1510 memset(&zero, 0, sizeof(zero));
1511 /* FIXME: stop local server thread */
1512 IStream_Seek(curClass->pMarshaledData, zero, SEEK_SET, NULL);
1513 CoReleaseMarshalData(curClass->pMarshaledData);
1517 * Free the memory used by the chain node.
1519 HeapFree(GetProcessHeap(), 0, curClass);
1521 hr = S_OK;
1522 goto end;
1526 * Step to the next class in the list.
1528 prevClassLink = &(curClass->nextClass);
1529 curClass = curClass->nextClass;
1532 end:
1533 LeaveCriticalSection( &csRegisteredClassList );
1535 * If we get to here, we haven't found our class.
1537 return hr;
1540 /***********************************************************************
1541 * COM_RegReadPath [internal]
1543 * Reads a registry value and expands it when necessary
1545 HRESULT COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
1547 HRESULT hres;
1548 HKEY key;
1549 DWORD keytype;
1550 WCHAR src[MAX_PATH];
1551 DWORD dwLength = dstlen * sizeof(WCHAR);
1553 if((hres = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1554 if( (hres = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1555 if (keytype == REG_EXPAND_SZ) {
1556 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) hres = ERROR_MORE_DATA;
1557 } else {
1558 lstrcpynW(dst, src, dstlen);
1561 RegCloseKey (key);
1563 return hres;
1566 static HRESULT get_inproc_class_object(HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
1568 HINSTANCE hLibrary;
1569 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1570 DllGetClassObjectFunc DllGetClassObject;
1571 WCHAR dllpath[MAX_PATH+1];
1573 if (COM_RegReadPath(hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
1575 /* failure: CLSID is not found in registry */
1576 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
1577 return REGDB_E_CLASSNOTREG;
1580 if ((hLibrary = LoadLibraryExW(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0)
1582 /* failure: DLL could not be loaded */
1583 ERR("couldn't load in-process dll %s\n", debugstr_w(dllpath));
1584 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1587 if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject")))
1589 /* failure: the dll did not export DllGetClassObject */
1590 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(dllpath));
1591 FreeLibrary( hLibrary );
1592 return CO_E_DLLNOTFOUND;
1595 /* OK: get the ClassObject */
1596 COMPOBJ_DLLList_Add( hLibrary );
1597 return DllGetClassObject(rclsid, riid, ppv);
1600 /***********************************************************************
1601 * CoGetClassObject [OLE32.@]
1603 * FIXME. If request allows of several options and there is a failure
1604 * with one (other than not being registered) do we try the
1605 * others or return failure? (E.g. inprocess is registered but
1606 * the DLL is not found but the server version works)
1608 HRESULT WINAPI CoGetClassObject(
1609 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1610 REFIID iid, LPVOID *ppv)
1612 LPUNKNOWN regClassObject;
1613 HRESULT hres = E_UNEXPECTED;
1615 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1617 if (pServerInfo) {
1618 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1619 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1623 * First, try and see if we can't match the class ID with one of the
1624 * registered classes.
1626 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, &regClassObject))
1628 /* Get the required interface from the retrieved pointer. */
1629 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1632 * Since QI got another reference on the pointer, we want to release the
1633 * one we already have. If QI was unsuccessful, this will release the object. This
1634 * is good since we are not returning it in the "out" parameter.
1636 IUnknown_Release(regClassObject);
1638 return hres;
1641 /* First try in-process server */
1642 if (CLSCTX_INPROC_SERVER & dwClsContext)
1644 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
1645 HKEY hkey;
1647 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
1648 if (FAILED(hres))
1650 if (hres == REGDB_E_CLASSNOTREG)
1651 ERR("class %s not registered\n", debugstr_guid(rclsid));
1652 else
1653 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
1656 if (SUCCEEDED(hres))
1658 hres = get_inproc_class_object(hkey, rclsid, iid, ppv);
1659 RegCloseKey(hkey);
1662 /* return if we got a class, otherwise fall through to one of the
1663 * other types */
1664 if (SUCCEEDED(hres))
1665 return hres;
1668 /* Next try in-process handler */
1669 if (CLSCTX_INPROC_HANDLER & dwClsContext)
1671 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
1672 HKEY hkey;
1674 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
1675 if (FAILED(hres))
1677 if (hres == REGDB_E_CLASSNOTREG)
1678 ERR("class %s not registered\n", debugstr_guid(rclsid));
1679 else
1680 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
1683 if (SUCCEEDED(hres))
1685 hres = get_inproc_class_object(hkey, rclsid, iid, ppv);
1686 RegCloseKey(hkey);
1689 /* return if we got a class, otherwise fall through to one of the
1690 * other types */
1691 if (SUCCEEDED(hres))
1692 return hres;
1695 /* Next try out of process */
1696 if (CLSCTX_LOCAL_SERVER & dwClsContext)
1698 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
1699 if (SUCCEEDED(hres))
1700 return hres;
1703 /* Finally try remote: this requires networked DCOM (a lot of work) */
1704 if (CLSCTX_REMOTE_SERVER & dwClsContext)
1706 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1707 hres = E_NOINTERFACE;
1710 if (FAILED(hres))
1711 ERR("no class object %s could be created for context 0x%lx\n",
1712 debugstr_guid(rclsid), dwClsContext);
1713 return hres;
1716 /***********************************************************************
1717 * CoResumeClassObjects (OLE32.@)
1719 * Resumes all class objects registered with REGCLS_SUSPENDED.
1721 * RETURNS
1722 * Success: S_OK.
1723 * Failure: HRESULT code.
1725 HRESULT WINAPI CoResumeClassObjects(void)
1727 FIXME("stub\n");
1728 return S_OK;
1731 /***********************************************************************
1732 * GetClassFile (OLE32.@)
1734 * This function supplies the CLSID associated with the given filename.
1736 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1738 IStorage *pstg=0;
1739 HRESULT res;
1740 int nbElm, length, i;
1741 LONG sizeProgId;
1742 LPOLESTR *pathDec=0,absFile=0,progId=0;
1743 LPWSTR extension;
1744 static const WCHAR bkslashW[] = {'\\',0};
1745 static const WCHAR dotW[] = {'.',0};
1747 TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1749 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1750 if((StgIsStorageFile(filePathName))==S_OK){
1752 res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1754 if (SUCCEEDED(res))
1755 res=ReadClassStg(pstg,pclsid);
1757 IStorage_Release(pstg);
1759 return res;
1761 /* if the file is not a storage object then attemps to match various bits in the file against a
1762 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1763 this case
1765 for(i=0;i<nFileTypes;i++)
1767 for(i=0;j<nPatternsForType;j++){
1769 PATTERN pat;
1770 HANDLE hFile;
1772 pat=ReadPatternFromRegistry(i,j);
1773 hFile=CreateFileW(filePathName,,,,,,hFile);
1774 SetFilePosition(hFile,pat.offset);
1775 ReadFile(hFile,buf,pat.size,&r,NULL);
1776 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1778 *pclsid=ReadCLSIDFromRegistry(i);
1779 return S_OK;
1784 /* if the above strategies fail then search for the extension key in the registry */
1786 /* get the last element (absolute file) in the path name */
1787 nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1788 absFile=pathDec[nbElm-1];
1790 /* failed if the path represente a directory and not an absolute file name*/
1791 if (!lstrcmpW(absFile, bkslashW))
1792 return MK_E_INVALIDEXTENSION;
1794 /* get the extension of the file */
1795 extension = NULL;
1796 length=lstrlenW(absFile);
1797 for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1798 /* nothing */;
1800 if (!extension || !lstrcmpW(extension, dotW))
1801 return MK_E_INVALIDEXTENSION;
1803 res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1805 /* get the progId associated to the extension */
1806 progId = CoTaskMemAlloc(sizeProgId);
1807 res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1809 if (res==ERROR_SUCCESS)
1810 /* return the clsid associated to the progId */
1811 res= CLSIDFromProgID(progId,pclsid);
1813 for(i=0; pathDec[i]!=NULL;i++)
1814 CoTaskMemFree(pathDec[i]);
1815 CoTaskMemFree(pathDec);
1817 CoTaskMemFree(progId);
1819 if (res==ERROR_SUCCESS)
1820 return res;
1822 return MK_E_INVALIDEXTENSION;
1825 /***********************************************************************
1826 * CoCreateInstance [OLE32.@]
1828 HRESULT WINAPI CoCreateInstance(
1829 REFCLSID rclsid,
1830 LPUNKNOWN pUnkOuter,
1831 DWORD dwClsContext,
1832 REFIID iid,
1833 LPVOID *ppv)
1835 HRESULT hres;
1836 LPCLASSFACTORY lpclf = 0;
1838 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08lx, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
1839 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
1842 * Sanity check
1844 if (ppv==0)
1845 return E_POINTER;
1848 * Initialize the "out" parameter
1850 *ppv = 0;
1852 if (!COM_CurrentApt())
1854 ERR("apartment not initialised\n");
1855 return CO_E_NOTINITIALIZED;
1859 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1860 * Rather than create a class factory, we can just check for it here
1862 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
1863 if (StdGlobalInterfaceTableInstance == NULL)
1864 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
1865 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
1866 if (hres) return hres;
1868 TRACE("Retrieved GIT (%p)\n", *ppv);
1869 return S_OK;
1873 * Get a class factory to construct the object we want.
1875 hres = CoGetClassObject(rclsid,
1876 dwClsContext,
1877 NULL,
1878 &IID_IClassFactory,
1879 (LPVOID)&lpclf);
1881 if (FAILED(hres))
1882 return hres;
1885 * Create the object and don't forget to release the factory
1887 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
1888 IClassFactory_Release(lpclf);
1889 if(FAILED(hres))
1890 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1891 debugstr_guid(iid), debugstr_guid(rclsid),hres);
1893 return hres;
1896 /***********************************************************************
1897 * CoCreateInstanceEx [OLE32.@]
1899 HRESULT WINAPI CoCreateInstanceEx(
1900 REFCLSID rclsid,
1901 LPUNKNOWN pUnkOuter,
1902 DWORD dwClsContext,
1903 COSERVERINFO* pServerInfo,
1904 ULONG cmq,
1905 MULTI_QI* pResults)
1907 IUnknown* pUnk = NULL;
1908 HRESULT hr;
1909 ULONG index;
1910 ULONG successCount = 0;
1913 * Sanity check
1915 if ( (cmq==0) || (pResults==NULL))
1916 return E_INVALIDARG;
1918 if (pServerInfo!=NULL)
1919 FIXME("() non-NULL pServerInfo not supported!\n");
1922 * Initialize all the "out" parameters.
1924 for (index = 0; index < cmq; index++)
1926 pResults[index].pItf = NULL;
1927 pResults[index].hr = E_NOINTERFACE;
1931 * Get the object and get its IUnknown pointer.
1933 hr = CoCreateInstance(rclsid,
1934 pUnkOuter,
1935 dwClsContext,
1936 &IID_IUnknown,
1937 (VOID**)&pUnk);
1939 if (hr)
1940 return hr;
1943 * Then, query for all the interfaces requested.
1945 for (index = 0; index < cmq; index++)
1947 pResults[index].hr = IUnknown_QueryInterface(pUnk,
1948 pResults[index].pIID,
1949 (VOID**)&(pResults[index].pItf));
1951 if (pResults[index].hr == S_OK)
1952 successCount++;
1956 * Release our temporary unknown pointer.
1958 IUnknown_Release(pUnk);
1960 if (successCount == 0)
1961 return E_NOINTERFACE;
1963 if (successCount!=cmq)
1964 return CO_S_NOTALLINTERFACES;
1966 return S_OK;
1969 /***********************************************************************
1970 * CoLoadLibrary (OLE32.@)
1972 * Loads a library.
1974 * PARAMS
1975 * lpszLibName [I] Path to library.
1976 * bAutoFree [I] Whether the library should automatically be freed.
1978 * RETURNS
1979 * Success: Handle to loaded library.
1980 * Failure: NULL.
1982 * SEE ALSO
1983 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1985 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
1987 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
1989 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
1992 /***********************************************************************
1993 * CoFreeLibrary [OLE32.@]
1995 * Unloads a library from memory.
1997 * PARAMS
1998 * hLibrary [I] Handle to library to unload.
2000 * RETURNS
2001 * Nothing
2003 * SEE ALSO
2004 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2006 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
2008 FreeLibrary(hLibrary);
2012 /***********************************************************************
2013 * CoFreeAllLibraries [OLE32.@]
2015 * Function for backwards compatibility only. Does nothing.
2017 * RETURNS
2018 * Nothing.
2020 * SEE ALSO
2021 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2023 void WINAPI CoFreeAllLibraries(void)
2025 /* NOP */
2029 /***********************************************************************
2030 * CoFreeUnusedLibraries [OLE32.@]
2031 * CoFreeUnusedLibraries [COMPOBJ.17]
2033 * Frees any unused libraries. Unused are identified as those that return
2034 * S_OK from their DllCanUnloadNow function.
2036 * RETURNS
2037 * Nothing.
2039 * SEE ALSO
2040 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2042 void WINAPI CoFreeUnusedLibraries(void)
2044 /* FIXME: Calls to CoFreeUnusedLibraries from any thread always route
2045 * through the main apartment's thread to call DllCanUnloadNow */
2046 COMPOBJ_DllList_FreeUnused(0);
2049 /***********************************************************************
2050 * CoFileTimeNow [OLE32.@]
2051 * CoFileTimeNow [COMPOBJ.82]
2053 * Retrieves the current time in FILETIME format.
2055 * PARAMS
2056 * lpFileTime [O] The current time.
2058 * RETURNS
2059 * S_OK.
2061 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
2063 GetSystemTimeAsFileTime( lpFileTime );
2064 return S_OK;
2067 static void COM_RevokeAllClasses()
2069 EnterCriticalSection( &csRegisteredClassList );
2071 while (firstRegisteredClass!=0)
2073 CoRevokeClassObject(firstRegisteredClass->dwCookie);
2076 LeaveCriticalSection( &csRegisteredClassList );
2079 /******************************************************************************
2080 * CoLockObjectExternal [OLE32.@]
2082 * Increments or decrements the external reference count of a stub object.
2084 * PARAMS
2085 * pUnk [I] Stub object.
2086 * fLock [I] If TRUE then increments the external ref-count,
2087 * otherwise decrements.
2088 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2089 * calling CoDisconnectObject.
2091 * RETURNS
2092 * Success: S_OK.
2093 * Failure: HRESULT code.
2095 HRESULT WINAPI CoLockObjectExternal(
2096 LPUNKNOWN pUnk,
2097 BOOL fLock,
2098 BOOL fLastUnlockReleases)
2100 struct stub_manager *stubmgr;
2101 struct apartment *apt;
2103 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2104 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2106 apt = COM_CurrentApt();
2107 if (!apt) return CO_E_NOTINITIALIZED;
2109 stubmgr = get_stub_manager_from_object(apt, pUnk);
2111 if (stubmgr)
2113 if (fLock)
2114 stub_manager_ext_addref(stubmgr, 1);
2115 else
2116 stub_manager_ext_release(stubmgr, 1);
2118 stub_manager_int_release(stubmgr);
2120 return S_OK;
2122 else
2124 WARN("stub object not found %p\n", pUnk);
2125 /* Note: native is pretty broken here because it just silently
2126 * fails, without returning an appropriate error code, making apps
2127 * think that the object was disconnected, when it actually wasn't */
2128 return S_OK;
2132 /***********************************************************************
2133 * CoInitializeWOW (OLE32.@)
2135 * WOW equivalent of CoInitialize?
2137 * PARAMS
2138 * x [I] Unknown.
2139 * y [I] Unknown.
2141 * RETURNS
2142 * Unknown.
2144 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2146 FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
2147 return 0;
2150 /***********************************************************************
2151 * CoGetState [OLE32.@]
2153 * Retrieves the thread state object previously stored by CoSetState().
2155 * PARAMS
2156 * ppv [I] Address where pointer to object will be stored.
2158 * RETURNS
2159 * Success: S_OK.
2160 * Failure: E_OUTOFMEMORY.
2162 * NOTES
2163 * Crashes on all invalid ppv addresses, including NULL.
2164 * If the function returns a non-NULL object then the caller must release its
2165 * reference on the object when the object is no longer required.
2167 * SEE ALSO
2168 * CoSetState().
2170 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2172 struct oletls *info = COM_CurrentInfo();
2173 if (!info) return E_OUTOFMEMORY;
2175 *ppv = NULL;
2177 if (info->state)
2179 IUnknown_AddRef(info->state);
2180 *ppv = info->state;
2181 TRACE("apt->state=%p\n", info->state);
2184 return S_OK;
2187 /***********************************************************************
2188 * CoSetState [OLE32.@]
2190 * Sets the thread state object.
2192 * PARAMS
2193 * pv [I] Pointer to state object to be stored.
2195 * NOTES
2196 * The system keeps a reference on the object while the object stored.
2198 * RETURNS
2199 * Success: S_OK.
2200 * Failure: E_OUTOFMEMORY.
2202 HRESULT WINAPI CoSetState(IUnknown * pv)
2204 struct oletls *info = COM_CurrentInfo();
2205 if (!info) return E_OUTOFMEMORY;
2207 if (pv) IUnknown_AddRef(pv);
2209 if (info->state)
2211 TRACE("-- release %p now\n", info->state);
2212 IUnknown_Release(info->state);
2215 info->state = pv;
2217 return S_OK;
2221 /******************************************************************************
2222 * OleGetAutoConvert [OLE32.@]
2224 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2226 static const WCHAR wszAutoConvertTo[] = {'A','u','t','o','C','o','n','v','e','r','t','T','o',0};
2227 HKEY hkey = NULL;
2228 WCHAR buf[CHARS_IN_GUID];
2229 LONG len;
2230 HRESULT res = S_OK;
2232 res = COM_OpenKeyForCLSID(clsidOld, wszAutoConvertTo, KEY_READ, &hkey);
2233 if (FAILED(res))
2234 goto done;
2236 len = sizeof(buf);
2237 if (RegQueryValueW(hkey, NULL, buf, &len))
2239 res = REGDB_E_KEYMISSING;
2240 goto done;
2242 res = CLSIDFromString(buf, pClsidNew);
2243 done:
2244 if (hkey) RegCloseKey(hkey);
2245 return res;
2248 /******************************************************************************
2249 * CoTreatAsClass [OLE32.@]
2251 * Sets the TreatAs value of a class.
2253 * PARAMS
2254 * clsidOld [I] Class to set TreatAs value on.
2255 * clsidNew [I] The class the clsidOld should be treated as.
2257 * RETURNS
2258 * Success: S_OK.
2259 * Failure: HRESULT code.
2261 * SEE ALSO
2262 * CoGetTreatAsClass
2264 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2266 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
2267 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2268 HKEY hkey = NULL;
2269 WCHAR szClsidNew[CHARS_IN_GUID];
2270 HRESULT res = S_OK;
2271 WCHAR auto_treat_as[CHARS_IN_GUID];
2272 LONG auto_treat_as_size = sizeof(auto_treat_as);
2273 CLSID id;
2275 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
2276 if (FAILED(res))
2277 goto done;
2278 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2280 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
2281 !CLSIDFromString(auto_treat_as, &id))
2283 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
2285 res = REGDB_E_WRITEREGDB;
2286 goto done;
2289 else
2291 RegDeleteKeyW(hkey, wszTreatAs);
2292 goto done;
2295 else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
2296 !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
2298 res = REGDB_E_WRITEREGDB;
2299 goto done;
2302 done:
2303 if (hkey) RegCloseKey(hkey);
2304 return res;
2307 /******************************************************************************
2308 * CoGetTreatAsClass [OLE32.@]
2310 * Gets the TreatAs value of a class.
2312 * PARAMS
2313 * clsidOld [I] Class to get the TreatAs value of.
2314 * clsidNew [I] The class the clsidOld should be treated as.
2316 * RETURNS
2317 * Success: S_OK.
2318 * Failure: HRESULT code.
2320 * SEE ALSO
2321 * CoSetTreatAsClass
2323 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2325 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2326 HKEY hkey = NULL;
2327 WCHAR szClsidNew[CHARS_IN_GUID];
2328 HRESULT res = S_OK;
2329 LONG len = sizeof(szClsidNew);
2331 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2332 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2334 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
2335 if (FAILED(res))
2336 goto done;
2337 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
2339 res = S_FALSE;
2340 goto done;
2342 res = CLSIDFromString(szClsidNew,clsidNew);
2343 if (FAILED(res))
2344 ERR("Failed CLSIDFromStringA(%s), hres 0x%08lx\n", debugstr_w(szClsidNew), res);
2345 done:
2346 if (hkey) RegCloseKey(hkey);
2347 return res;
2350 /******************************************************************************
2351 * CoGetCurrentProcess [OLE32.@]
2352 * CoGetCurrentProcess [COMPOBJ.34]
2354 * Gets the current process ID.
2356 * RETURNS
2357 * The current process ID.
2359 * NOTES
2360 * Is DWORD really the correct return type for this function?
2362 DWORD WINAPI CoGetCurrentProcess(void)
2364 return GetCurrentProcessId();
2367 /******************************************************************************
2368 * CoRegisterMessageFilter [OLE32.@]
2370 * Registers a message filter.
2372 * PARAMS
2373 * lpMessageFilter [I] Pointer to interface.
2374 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2376 * RETURNS
2377 * Success: S_OK.
2378 * Failure: HRESULT code.
2380 HRESULT WINAPI CoRegisterMessageFilter(
2381 LPMESSAGEFILTER lpMessageFilter,
2382 LPMESSAGEFILTER *lplpMessageFilter)
2384 FIXME("stub\n");
2385 if (lplpMessageFilter) {
2386 *lplpMessageFilter = NULL;
2388 return S_OK;
2391 /***********************************************************************
2392 * CoIsOle1Class [OLE32.@]
2394 * Determines whether the specified class an OLE v1 class.
2396 * PARAMS
2397 * clsid [I] Class to test.
2399 * RETURNS
2400 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
2402 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
2404 FIXME("%s\n", debugstr_guid(clsid));
2405 return FALSE;
2408 /***********************************************************************
2409 * IsEqualGUID [OLE32.@]
2411 * Compares two Unique Identifiers.
2413 * PARAMS
2414 * rguid1 [I] The first GUID to compare.
2415 * rguid2 [I] The other GUID to compare.
2417 * RETURNS
2418 * TRUE if equal
2420 #undef IsEqualGUID
2421 BOOL WINAPI IsEqualGUID(
2422 REFGUID rguid1,
2423 REFGUID rguid2)
2425 return !memcmp(rguid1,rguid2,sizeof(GUID));
2428 /***********************************************************************
2429 * CoInitializeSecurity [OLE32.@]
2431 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2432 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2433 void* pReserved1, DWORD dwAuthnLevel,
2434 DWORD dwImpLevel, void* pReserved2,
2435 DWORD dwCapabilities, void* pReserved3)
2437 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
2438 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2439 dwCapabilities, pReserved3);
2440 return S_OK;
2443 /***********************************************************************
2444 * CoSuspendClassObjects [OLE32.@]
2446 * Suspends all registered class objects to prevent further requests coming in
2447 * for those objects.
2449 * RETURNS
2450 * Success: S_OK.
2451 * Failure: HRESULT code.
2453 HRESULT WINAPI CoSuspendClassObjects(void)
2455 FIXME("\n");
2456 return S_OK;
2459 /***********************************************************************
2460 * CoAddRefServerProcess [OLE32.@]
2462 * Helper function for incrementing the reference count of a local-server
2463 * process.
2465 * RETURNS
2466 * New reference count.
2468 ULONG WINAPI CoAddRefServerProcess(void)
2470 FIXME("\n");
2471 return 2;
2474 /***********************************************************************
2475 * CoReleaseServerProcess [OLE32.@]
2477 * Helper function for decrementing the reference count of a local-server
2478 * process.
2480 * RETURNS
2481 * New reference count.
2483 ULONG WINAPI CoReleaseServerProcess(void)
2485 FIXME("\n");
2486 return 1;
2489 /***********************************************************************
2490 * CoIsHandlerConnected [OLE32.@]
2492 * Determines whether a proxy is connected to a remote stub.
2494 * PARAMS
2495 * pUnk [I] Pointer to object that may or may not be connected.
2497 * RETURNS
2498 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
2499 * FALSE otherwise.
2501 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
2503 FIXME("%p\n", pUnk);
2505 return TRUE;
2508 /***********************************************************************
2509 * CoAllowSetForegroundWindow [OLE32.@]
2512 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
2514 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
2515 return S_OK;
2518 /***********************************************************************
2519 * CoQueryProxyBlanket [OLE32.@]
2521 * Retrieves the security settings being used by a proxy.
2523 * PARAMS
2524 * pProxy [I] Pointer to the proxy object.
2525 * pAuthnSvc [O] The type of authentication service.
2526 * pAuthzSvc [O] The type of authorization service.
2527 * ppServerPrincName [O] Optional. The server prinicple name.
2528 * pAuthnLevel [O] The authentication level.
2529 * pImpLevel [O] The impersonation level.
2530 * ppAuthInfo [O] Information specific to the authorization/authentication service.
2531 * pCapabilities [O] Flags affecting the security behaviour.
2533 * RETURNS
2534 * Success: S_OK.
2535 * Failure: HRESULT code.
2537 * SEE ALSO
2538 * CoCopyProxy, CoSetProxyBlanket.
2540 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
2541 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
2542 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
2544 IClientSecurity *pCliSec;
2545 HRESULT hr;
2547 TRACE("%p\n", pProxy);
2549 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2550 if (SUCCEEDED(hr))
2552 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
2553 pAuthzSvc, ppServerPrincName,
2554 pAuthnLevel, pImpLevel, ppAuthInfo,
2555 pCapabilities);
2556 IClientSecurity_Release(pCliSec);
2559 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2560 return hr;
2563 /***********************************************************************
2564 * CoSetProxyBlanket [OLE32.@]
2566 * Sets the security settings for a proxy.
2568 * PARAMS
2569 * pProxy [I] Pointer to the proxy object.
2570 * AuthnSvc [I] The type of authentication service.
2571 * AuthzSvc [I] The type of authorization service.
2572 * pServerPrincName [I] The server prinicple name.
2573 * AuthnLevel [I] The authentication level.
2574 * ImpLevel [I] The impersonation level.
2575 * pAuthInfo [I] Information specific to the authorization/authentication service.
2576 * Capabilities [I] Flags affecting the security behaviour.
2578 * RETURNS
2579 * Success: S_OK.
2580 * Failure: HRESULT code.
2582 * SEE ALSO
2583 * CoQueryProxyBlanket, CoCopyProxy.
2585 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
2586 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
2587 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
2589 IClientSecurity *pCliSec;
2590 HRESULT hr;
2592 TRACE("%p\n", pProxy);
2594 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2595 if (SUCCEEDED(hr))
2597 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
2598 AuthzSvc, pServerPrincName,
2599 AuthnLevel, ImpLevel, pAuthInfo,
2600 Capabilities);
2601 IClientSecurity_Release(pCliSec);
2604 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2605 return hr;
2608 /***********************************************************************
2609 * CoCopyProxy [OLE32.@]
2611 * Copies a proxy.
2613 * PARAMS
2614 * pProxy [I] Pointer to the proxy object.
2615 * ppCopy [O] Copy of the proxy.
2617 * RETURNS
2618 * Success: S_OK.
2619 * Failure: HRESULT code.
2621 * SEE ALSO
2622 * CoQueryProxyBlanket, CoSetProxyBlanket.
2624 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
2626 IClientSecurity *pCliSec;
2627 HRESULT hr;
2629 TRACE("%p\n", pProxy);
2631 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2632 if (SUCCEEDED(hr))
2634 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
2635 IClientSecurity_Release(pCliSec);
2638 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2639 return hr;
2643 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
2645 /* first try to retrieve messages for incoming COM calls to the apartment window */
2646 return PeekMessageW(msg, apt->win, WM_USER, WM_APP - 1, PM_REMOVE|PM_NOYIELD) ||
2647 /* next retrieve other messages necessary for the app to remain responsive */
2648 PeekMessageW(msg, NULL, 0, WM_USER - 1, PM_REMOVE|PM_NOYIELD);
2651 /***********************************************************************
2652 * CoWaitForMultipleHandles [OLE32.@]
2654 * Waits for one or more handles to become signaled.
2656 * PARAMS
2657 * dwFlags [I] Flags. See notes.
2658 * dwTimeout [I] Timeout in milliseconds.
2659 * cHandles [I] Number of handles pointed to by pHandles.
2660 * pHandles [I] Handles to wait for.
2661 * lpdwindex [O] Index of handle that was signaled.
2663 * RETURNS
2664 * Success: S_OK.
2665 * Failure: RPC_S_CALLPENDING on timeout.
2667 * NOTES
2669 * The dwFlags parameter can be zero or more of the following:
2670 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
2671 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
2673 * SEE ALSO
2674 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
2676 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
2677 ULONG cHandles, const HANDLE* pHandles, LPDWORD lpdwindex)
2679 HRESULT hr = S_OK;
2680 DWORD start_time = GetTickCount();
2681 APARTMENT *apt = COM_CurrentApt();
2682 BOOL message_loop = apt && !apt->multi_threaded;
2684 TRACE("(0x%08lx, 0x%08lx, %ld, %p, %p)\n", dwFlags, dwTimeout, cHandles,
2685 pHandles, lpdwindex);
2687 while (TRUE)
2689 DWORD now = GetTickCount();
2690 DWORD res;
2692 if ((dwTimeout != INFINITE) && (start_time + dwTimeout >= now))
2694 hr = RPC_S_CALLPENDING;
2695 break;
2698 if (message_loop)
2700 DWORD wait_flags = (dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0 |
2701 (dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0;
2703 TRACE("waiting for rpc completion or window message\n");
2705 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
2706 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
2707 QS_ALLINPUT, wait_flags);
2709 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
2711 MSG msg;
2712 while (COM_PeekMessage(apt, &msg))
2714 /* FIXME: filter the messages here */
2715 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
2716 TranslateMessage(&msg);
2717 DispatchMessageW(&msg);
2718 if (msg.message == WM_QUIT)
2720 TRACE("resending WM_QUIT to outer message loop\n");
2721 PostQuitMessage(msg.wParam);
2722 /* no longer need to process messages */
2723 message_loop = FALSE;
2724 break;
2727 continue;
2730 else
2732 TRACE("waiting for rpc completion\n");
2734 res = WaitForMultipleObjectsEx(cHandles, pHandles,
2735 (dwFlags & COWAIT_WAITALL) ? TRUE : FALSE,
2736 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
2737 (dwFlags & COWAIT_ALERTABLE) ? TRUE : FALSE);
2740 if ((res >= WAIT_OBJECT_0) && (res < WAIT_OBJECT_0 + cHandles))
2742 /* handle signaled, store index */
2743 *lpdwindex = (res - WAIT_OBJECT_0);
2744 break;
2746 else if (res == WAIT_TIMEOUT)
2748 hr = RPC_S_CALLPENDING;
2749 break;
2751 else
2753 ERR("Unexpected wait termination: %ld, %ld\n", res, GetLastError());
2754 hr = E_UNEXPECTED;
2755 break;
2758 TRACE("-- 0x%08lx\n", hr);
2759 return hr;
2762 /***********************************************************************
2763 * DllMain (OLE32.@)
2765 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
2767 TRACE("%p 0x%lx %p\n", hinstDLL, fdwReason, fImpLoad);
2769 switch(fdwReason) {
2770 case DLL_PROCESS_ATTACH:
2771 OLE32_hInstance = hinstDLL;
2772 COMPOBJ_InitProcess();
2773 if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1);
2774 break;
2776 case DLL_PROCESS_DETACH:
2777 if (TRACE_ON(ole)) CoRevokeMallocSpy();
2778 COMPOBJ_UninitProcess();
2779 OLE32_hInstance = 0;
2780 break;
2782 case DLL_THREAD_DETACH:
2783 COM_TlsDestroy();
2784 break;
2786 return TRUE;
2789 /* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */