ole: Update the COM todo list.
[wine.git] / dlls / ole32 / compobj.c
blob80ecd11f78e49d333841f27c8c240408059aed61
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->model = model;
234 if (model & COINIT_APARTMENTTHREADED)
236 /* FIXME: should be randomly generated by in an RPC call to rpcss */
237 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
239 else
241 /* FIXME: should be randomly generated by in an RPC call to rpcss */
242 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
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 DWORD apartment_addref(struct apartment *apt)
297 DWORD refs = InterlockedIncrement(&apt->refs);
298 TRACE("%s: before = %ld\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
299 return refs;
302 DWORD apartment_release(struct apartment *apt)
304 DWORD ret;
306 EnterCriticalSection(&csApartment);
308 ret = InterlockedDecrement(&apt->refs);
309 TRACE("%s: after = %ld\n", wine_dbgstr_longlong(apt->oxid), ret);
310 /* destruction stuff that needs to happen under csApartment CS */
311 if (ret == 0)
313 if (apt == MTA) MTA = NULL;
314 list_remove(&apt->entry);
317 LeaveCriticalSection(&csApartment);
319 if (ret == 0)
321 struct list *cursor, *cursor2;
323 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
325 /* no locking is needed for this apartment, because no other thread
326 * can access it at this point */
328 apartment_disconnectproxies(apt);
330 if (apt->win) DestroyWindow(apt->win);
332 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
334 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
335 /* release the implicit reference given by the fact that the
336 * stub has external references (it must do since it is in the
337 * stub manager list in the apartment and all non-apartment users
338 * must have a ref on the apartment and so it cannot be destroyed).
340 stub_manager_int_release(stubmgr);
343 /* if this assert fires, then another thread took a reference to a
344 * stub manager without taking a reference to the containing
345 * apartment, which it must do. */
346 assert(list_empty(&apt->stubmgrs));
348 if (apt->filter) IUnknown_Release(apt->filter);
350 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
351 DeleteCriticalSection(&apt->cs);
353 HeapFree(GetProcessHeap(), 0, apt);
356 return ret;
359 /* The given OXID must be local to this process:
361 * The ref parameter is here mostly to ensure people remember that
362 * they get one, you should normally take a ref for thread safety.
364 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
366 APARTMENT *result = NULL;
367 struct list *cursor;
369 EnterCriticalSection(&csApartment);
370 LIST_FOR_EACH( cursor, &apts )
372 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
373 if (apt->oxid == oxid)
375 result = apt;
376 if (ref) apartment_addref(result);
377 break;
380 LeaveCriticalSection(&csApartment);
382 return result;
385 /* gets the apartment which has a given creator thread ID. The caller must
386 * release the reference from the apartment as soon as the apartment pointer
387 * is no longer required. */
388 APARTMENT *apartment_findfromtid(DWORD tid)
390 APARTMENT *result = NULL;
391 struct list *cursor;
393 EnterCriticalSection(&csApartment);
394 LIST_FOR_EACH( cursor, &apts )
396 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
397 if (apt->tid == tid)
399 result = apt;
400 apartment_addref(result);
401 break;
404 LeaveCriticalSection(&csApartment);
406 return result;
409 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
411 switch (msg)
413 case DM_EXECUTERPC:
414 RPC_ExecuteCall((struct dispatch_params *)lParam);
415 return 0;
416 default:
417 return DefWindowProcW(hWnd, msg, wParam, lParam);
421 HRESULT apartment_createwindowifneeded(struct apartment *apt)
423 if (!(apt->model & COINIT_APARTMENTTHREADED))
424 return S_OK;
426 if (!apt->win)
428 HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0,
429 0, 0, 0, 0,
430 0, 0, OLE32_hInstance, NULL);
431 if (!hwnd)
433 ERR("CreateWindow failed with error %ld\n", GetLastError());
434 return HRESULT_FROM_WIN32(GetLastError());
436 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
437 /* someone beat us to it */
438 DestroyWindow(hwnd);
441 return S_OK;
444 HWND apartment_getwindow(struct apartment *apt)
446 assert(apt->model & COINIT_APARTMENTTHREADED);
447 return apt->win;
450 void apartment_joinmta(void)
452 apartment_addref(MTA);
453 COM_CurrentInfo()->apt = MTA;
456 /*****************************************************************************
457 * This section contains OpenDllList implemantation
460 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
462 OpenDll *ptr;
463 OpenDll *tmp;
465 TRACE("\n");
467 EnterCriticalSection( &csOpenDllList );
469 if (openDllList == NULL) {
470 /* empty list -- add first node */
471 openDllList = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
472 openDllList->hLibrary=hLibrary;
473 openDllList->next = NULL;
474 } else {
475 /* search for this dll */
476 int found = FALSE;
477 for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
478 if (ptr->hLibrary == hLibrary) {
479 found = TRUE;
480 break;
483 if (!found) {
484 /* dll not found, add it */
485 tmp = openDllList;
486 openDllList = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
487 openDllList->hLibrary = hLibrary;
488 openDllList->next = tmp;
492 LeaveCriticalSection( &csOpenDllList );
495 static void COMPOBJ_DllList_FreeUnused(int Timeout)
497 OpenDll *curr, *next, *prev = NULL;
498 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
499 DllCanUnloadNowFunc DllCanUnloadNow;
501 TRACE("\n");
503 EnterCriticalSection( &csOpenDllList );
505 for (curr = openDllList; curr != NULL; ) {
506 DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
508 if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
509 next = curr->next;
511 TRACE("freeing %p\n", curr->hLibrary);
512 FreeLibrary(curr->hLibrary);
514 HeapFree(GetProcessHeap(), 0, curr);
515 if (curr == openDllList) {
516 openDllList = next;
517 } else {
518 prev->next = next;
521 curr = next;
522 } else {
523 prev = curr;
524 curr = curr->next;
528 LeaveCriticalSection( &csOpenDllList );
531 /******************************************************************************
532 * CoBuildVersion [OLE32.@]
533 * CoBuildVersion [COMPOBJ.1]
535 * Gets the build version of the DLL.
537 * PARAMS
539 * RETURNS
540 * Current build version, hiword is majornumber, loword is minornumber
542 DWORD WINAPI CoBuildVersion(void)
544 TRACE("Returning version %d, build %d.\n", rmm, rup);
545 return (rmm<<16)+rup;
548 /******************************************************************************
549 * CoInitialize [OLE32.@]
551 * Initializes the COM libraries by calling CoInitializeEx with
552 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
554 * PARAMS
555 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
557 * RETURNS
558 * Success: S_OK if not already initialized, S_FALSE otherwise.
559 * Failure: HRESULT code.
561 * SEE ALSO
562 * CoInitializeEx
564 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
567 * Just delegate to the newer method.
569 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
572 /******************************************************************************
573 * CoInitializeEx [OLE32.@]
575 * Initializes the COM libraries.
577 * PARAMS
578 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
579 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
581 * RETURNS
582 * S_OK if successful,
583 * S_FALSE if this function was called already.
584 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
585 * threading model.
587 * NOTES
589 * The behavior used to set the IMalloc used for memory management is
590 * obsolete.
591 * The dwCoInit parameter must specify of of the following apartment
592 * threading models:
593 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
594 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
595 * The parameter may also specify zero or more of the following flags:
596 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
597 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
599 * SEE ALSO
600 * CoUninitialize
602 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
604 HRESULT hr = S_OK;
605 APARTMENT *apt;
607 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
609 if (lpReserved!=NULL)
611 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
615 * Check the lock count. If this is the first time going through the initialize
616 * process, we have to initialize the libraries.
618 * And crank-up that lock count.
620 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
623 * Initialize the various COM libraries and data structures.
625 TRACE("() - Initializing the COM libraries\n");
627 /* we may need to defer this until after apartment initialisation */
628 RunningObjectTableImpl_Initialize();
631 if (!(apt = COM_CurrentInfo()->apt))
633 apt = apartment_get_or_create(dwCoInit);
634 if (!apt) return E_OUTOFMEMORY;
636 else if (dwCoInit != apt->model)
638 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
639 code then we are probably using the wrong threading model to implement that API. */
640 ERR("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit);
641 return RPC_E_CHANGED_MODE;
643 else
644 hr = S_FALSE;
646 COM_CurrentInfo()->inits++;
648 return hr;
651 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
652 pending RPCs are ignored. Non-COM messages are discarded at this point.
654 static void COM_FlushMessageQueue(void)
656 MSG message;
657 APARTMENT *apt = COM_CurrentApt();
659 if (!apt || !apt->win) return;
661 TRACE("Flushing STA message queue\n");
663 while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE))
665 if (message.hwnd != apt->win)
667 WARN("discarding message 0x%x for window %p\n", message.message, message.hwnd);
668 continue;
671 TranslateMessage(&message);
672 DispatchMessageA(&message);
676 /***********************************************************************
677 * CoUninitialize [OLE32.@]
679 * This method will decrement the refcount on the current apartment, freeing
680 * the resources associated with it if it is the last thread in the apartment.
681 * If the last apartment is freed, the function will additionally release
682 * any COM resources associated with the process.
684 * PARAMS
686 * RETURNS
687 * Nothing.
689 * SEE ALSO
690 * CoInitializeEx
692 void WINAPI CoUninitialize(void)
694 struct oletls * info = COM_CurrentInfo();
695 LONG lCOMRefCnt;
697 TRACE("()\n");
699 /* will only happen on OOM */
700 if (!info) return;
702 /* sanity check */
703 if (!info->inits)
705 ERR("Mismatched CoUninitialize\n");
706 return;
709 if (!--info->inits)
711 apartment_release(info->apt);
712 info->apt = NULL;
716 * Decrease the reference count.
717 * If we are back to 0 locks on the COM library, make sure we free
718 * all the associated data structures.
720 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
721 if (lCOMRefCnt==1)
723 TRACE("() - Releasing the COM libraries\n");
725 RunningObjectTableImpl_UnInitialize();
727 /* Release the references to the registered class objects */
728 COM_RevokeAllClasses();
730 /* This will free the loaded COM Dlls */
731 CoFreeAllLibraries();
733 /* This ensures we deal with any pending RPCs */
734 COM_FlushMessageQueue();
736 else if (lCOMRefCnt<1) {
737 ERR( "CoUninitialize() - not CoInitialized.\n" );
738 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
742 /******************************************************************************
743 * CoDisconnectObject [OLE32.@]
744 * CoDisconnectObject [COMPOBJ.15]
746 * Disconnects all connections to this object from remote processes. Dispatches
747 * pending RPCs while blocking new RPCs from occurring, and then calls
748 * IMarshal::DisconnectObject on the given object.
750 * Typically called when the object server is forced to shut down, for instance by
751 * the user.
753 * PARAMS
754 * lpUnk [I] The object whose stub should be disconnected.
755 * reserved [I] Reserved. Should be set to 0.
757 * RETURNS
758 * Success: S_OK.
759 * Failure: HRESULT code.
761 * SEE ALSO
762 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
764 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
766 HRESULT hr;
767 IMarshal *marshal;
768 APARTMENT *apt;
770 TRACE("(%p, 0x%08lx)\n", lpUnk, reserved);
772 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
773 if (hr == S_OK)
775 hr = IMarshal_DisconnectObject(marshal, reserved);
776 IMarshal_Release(marshal);
777 return hr;
780 apt = COM_CurrentApt();
781 if (!apt)
782 return CO_E_NOTINITIALIZED;
784 apartment_disconnectobject(apt, lpUnk);
786 /* Note: native is pretty broken here because it just silently
787 * fails, without returning an appropriate error code if the object was
788 * not found, making apps think that the object was disconnected, when
789 * it actually wasn't */
791 return S_OK;
794 /******************************************************************************
795 * CoCreateGuid [OLE32.@]
797 * Simply forwards to UuidCreate in RPCRT4.
799 * PARAMS
800 * pguid [O] Points to the GUID to initialize.
802 * RETURNS
803 * Success: S_OK.
804 * Failure: HRESULT code.
806 * SEE ALSO
807 * UuidCreate
809 HRESULT WINAPI CoCreateGuid(GUID *pguid)
811 return UuidCreate(pguid);
814 /******************************************************************************
815 * CLSIDFromString [OLE32.@]
816 * IIDFromString [OLE32.@]
818 * Converts a unique identifier from its string representation into
819 * the GUID struct.
821 * PARAMS
822 * idstr [I] The string representation of the GUID.
823 * id [O] GUID converted from the string.
825 * RETURNS
826 * S_OK on success
827 * CO_E_CLASSSTRING if idstr is not a valid CLSID
829 * SEE ALSO
830 * StringFromCLSID
832 static HRESULT WINAPI __CLSIDFromString(LPCWSTR s, CLSID *id)
834 int i;
835 BYTE table[256];
837 if (!s) {
838 memset( id, 0, sizeof (CLSID) );
839 return S_OK;
842 /* validate the CLSID string */
843 if (strlenW(s) != 38)
844 return CO_E_CLASSSTRING;
846 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
847 return CO_E_CLASSSTRING;
849 for (i=1; i<37; i++) {
850 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
851 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
852 ((s[i] >= 'a') && (s[i] <= 'f')) ||
853 ((s[i] >= 'A') && (s[i] <= 'F'))))
854 return CO_E_CLASSSTRING;
857 TRACE("%s -> %p\n", debugstr_w(s), id);
859 /* quick lookup table */
860 memset(table, 0, 256);
862 for (i = 0; i < 10; i++) {
863 table['0' + i] = i;
865 for (i = 0; i < 6; i++) {
866 table['A' + i] = i+10;
867 table['a' + i] = i+10;
870 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
872 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
873 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
874 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
875 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
877 /* these are just sequential bytes */
878 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
879 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
880 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
881 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
882 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
883 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
884 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
885 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
887 return S_OK;
890 /*****************************************************************************/
892 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
894 HRESULT ret;
896 ret = __CLSIDFromString(idstr, id);
897 if(ret != S_OK) { /* It appears a ProgID is also valid */
898 ret = CLSIDFromProgID(idstr, id);
900 return ret;
903 /* Converts a GUID into the respective string representation. */
904 HRESULT WINE_StringFromCLSID(
905 const CLSID *id, /* [in] GUID to be converted */
906 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
908 static const char *hex = "0123456789ABCDEF";
909 char *s;
910 int i;
912 if (!id)
913 { ERR("called with id=Null\n");
914 *idstr = 0x00;
915 return E_FAIL;
918 sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
919 id->Data1, id->Data2, id->Data3,
920 id->Data4[0], id->Data4[1]);
921 s = &idstr[25];
923 /* 6 hex bytes */
924 for (i = 2; i < 8; i++) {
925 *s++ = hex[id->Data4[i]>>4];
926 *s++ = hex[id->Data4[i] & 0xf];
929 *s++ = '}';
930 *s++ = '\0';
932 TRACE("%p->%s\n", id, idstr);
934 return S_OK;
938 /******************************************************************************
939 * StringFromCLSID [OLE32.@]
940 * StringFromIID [OLE32.@]
942 * Converts a GUID into the respective string representation.
943 * The target string is allocated using the OLE IMalloc.
945 * PARAMS
946 * id [I] the GUID to be converted.
947 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
949 * RETURNS
950 * S_OK
951 * E_FAIL
953 * SEE ALSO
954 * StringFromGUID2, CLSIDFromString
956 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
958 char buf[80];
959 HRESULT ret;
960 LPMALLOC mllc;
962 if ((ret = CoGetMalloc(0,&mllc)))
963 return ret;
965 ret=WINE_StringFromCLSID(id,buf);
966 if (!ret) {
967 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
968 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
969 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
971 return ret;
974 /******************************************************************************
975 * StringFromGUID2 [OLE32.@]
976 * StringFromGUID2 [COMPOBJ.76]
978 * Modified version of StringFromCLSID that allows you to specify max
979 * buffer size.
981 * PARAMS
982 * id [I] GUID to convert to string.
983 * str [O] Buffer where the result will be stored.
984 * cmax [I] Size of the buffer in characters.
986 * RETURNS
987 * Success: The length of the resulting string in characters.
988 * Failure: 0.
990 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
992 char xguid[80];
994 if (WINE_StringFromCLSID(id,xguid))
995 return 0;
996 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
999 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
1000 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
1002 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1003 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
1004 LONG res;
1005 HKEY key;
1007 strcpyW(path, wszCLSIDSlash);
1008 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
1009 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, keyname ? KEY_READ : access, &key);
1010 if (res == ERROR_FILE_NOT_FOUND)
1011 return REGDB_E_CLASSNOTREG;
1012 else if (res != ERROR_SUCCESS)
1013 return REGDB_E_READREGDB;
1015 if (!keyname)
1017 *subkey = key;
1018 return S_OK;
1021 res = RegOpenKeyExW(key, keyname, 0, access, subkey);
1022 RegCloseKey(key);
1023 if (res == ERROR_FILE_NOT_FOUND)
1024 return REGDB_E_KEYMISSING;
1025 else if (res != ERROR_SUCCESS)
1026 return REGDB_E_READREGDB;
1028 return S_OK;
1031 /******************************************************************************
1032 * ProgIDFromCLSID [OLE32.@]
1034 * Converts a class id into the respective program ID.
1036 * PARAMS
1037 * clsid [I] Class ID, as found in registry.
1038 * lplpszProgID [O] Associated ProgID.
1040 * RETURNS
1041 * S_OK
1042 * E_OUTOFMEMORY
1043 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1045 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *lplpszProgID)
1047 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
1048 HKEY hkey;
1049 HRESULT ret;
1050 LONG progidlen = 0;
1052 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
1053 if (FAILED(ret))
1054 return ret;
1056 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1057 ret = REGDB_E_CLASSNOTREG;
1059 if (ret == S_OK)
1061 *lplpszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
1062 if (*lplpszProgID)
1064 if (RegQueryValueW(hkey, NULL, *lplpszProgID, &progidlen))
1065 ret = REGDB_E_CLASSNOTREG;
1067 else
1068 ret = E_OUTOFMEMORY;
1071 RegCloseKey(hkey);
1072 return ret;
1075 /******************************************************************************
1076 * CLSIDFromProgID [OLE32.@]
1078 * Converts a program id into the respective GUID.
1080 * PARAMS
1081 * progid [I] Unicode program ID, as found in registry.
1082 * riid [O] Associated CLSID.
1084 * RETURNS
1085 * Success: S_OK
1086 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1088 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID riid)
1090 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1091 WCHAR buf2[CHARS_IN_GUID];
1092 LONG buf2len = sizeof(buf2);
1093 HKEY xhkey;
1095 WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1096 strcpyW( buf, progid );
1097 strcatW( buf, clsidW );
1098 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1100 HeapFree(GetProcessHeap(),0,buf);
1101 return CO_E_CLASSSTRING;
1103 HeapFree(GetProcessHeap(),0,buf);
1105 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
1107 RegCloseKey(xhkey);
1108 return CO_E_CLASSSTRING;
1110 RegCloseKey(xhkey);
1111 return CLSIDFromString(buf2,riid);
1115 /*****************************************************************************
1116 * CoGetPSClsid [OLE32.@]
1118 * Retrieves the CLSID of the proxy/stub factory that implements
1119 * IPSFactoryBuffer for the specified interface.
1121 * PARAMS
1122 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1123 * pclsid [O] Where to store returned proxy/stub CLSID.
1125 * RETURNS
1126 * S_OK
1127 * E_OUTOFMEMORY
1128 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1130 * NOTES
1132 * The standard marshaller activates the object with the CLSID
1133 * returned and uses the CreateProxy and CreateStub methods on its
1134 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1135 * given object.
1137 * CoGetPSClsid determines this CLSID by searching the
1138 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1139 * in the registry and any interface id registered by
1140 * CoRegisterPSClsid within the current process.
1142 * BUGS
1144 * We only search the registry, not ids registered with
1145 * CoRegisterPSClsid.
1146 * Also, native returns S_OK for interfaces with a key in HKCR\Interface, but
1147 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1148 * considered a bug in native unless an application depends on this (unlikely).
1150 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1152 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
1153 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
1154 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
1155 WCHAR value[CHARS_IN_GUID];
1156 LONG len;
1157 HKEY hkey;
1159 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1161 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
1162 strcpyW(path, wszInterface);
1163 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
1164 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
1166 /* Open the key.. */
1167 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &hkey))
1169 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1170 return REGDB_E_IIDNOTREG;
1173 /* ... Once we have the key, query the registry to get the
1174 value of CLSID as a string, and convert it into a
1175 proper CLSID structure to be passed back to the app */
1176 len = sizeof(value);
1177 if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
1179 RegCloseKey(hkey);
1180 return REGDB_E_IIDNOTREG;
1182 RegCloseKey(hkey);
1184 /* We have the CLSid we want back from the registry as a string, so
1185 lets convert it into a CLSID structure */
1186 if (CLSIDFromString(value, pclsid) != NOERROR)
1187 return REGDB_E_IIDNOTREG;
1189 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1190 return S_OK;
1195 /***********************************************************************
1196 * WriteClassStm (OLE32.@)
1198 * Writes a CLSID to a stream.
1200 * PARAMS
1201 * pStm [I] Stream to write to.
1202 * rclsid [I] CLSID to write.
1204 * RETURNS
1205 * Success: S_OK.
1206 * Failure: HRESULT code.
1208 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
1210 TRACE("(%p,%p)\n",pStm,rclsid);
1212 if (rclsid==NULL)
1213 return E_INVALIDARG;
1215 return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
1218 /***********************************************************************
1219 * ReadClassStm (OLE32.@)
1221 * Reads a CLSID from a stream.
1223 * PARAMS
1224 * pStm [I] Stream to read from.
1225 * rclsid [O] CLSID to read.
1227 * RETURNS
1228 * Success: S_OK.
1229 * Failure: HRESULT code.
1231 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
1233 ULONG nbByte;
1234 HRESULT res;
1236 TRACE("(%p,%p)\n",pStm,pclsid);
1238 if (pclsid==NULL)
1239 return E_INVALIDARG;
1241 res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
1243 if (FAILED(res))
1244 return res;
1246 if (nbByte != sizeof(CLSID))
1247 return S_FALSE;
1248 else
1249 return S_OK;
1253 /***
1254 * COM_GetRegisteredClassObject
1256 * This internal method is used to scan the registered class list to
1257 * find a class object.
1259 * Params:
1260 * rclsid Class ID of the class to find.
1261 * dwClsContext Class context to match.
1262 * ppv [out] returns a pointer to the class object. Complying
1263 * to normal COM usage, this method will increase the
1264 * reference count on this object.
1266 static HRESULT COM_GetRegisteredClassObject(
1267 REFCLSID rclsid,
1268 DWORD dwClsContext,
1269 LPUNKNOWN* ppUnk)
1271 HRESULT hr = S_FALSE;
1272 RegisteredClass* curClass;
1274 EnterCriticalSection( &csRegisteredClassList );
1277 * Sanity check
1279 assert(ppUnk!=0);
1282 * Iterate through the whole list and try to match the class ID.
1284 curClass = firstRegisteredClass;
1286 while (curClass != 0)
1289 * Check if we have a match on the class ID.
1291 if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
1294 * Since we don't do out-of process or DCOM just right away, let's ignore the
1295 * class context.
1299 * We have a match, return the pointer to the class object.
1301 *ppUnk = curClass->classObject;
1303 IUnknown_AddRef(curClass->classObject);
1305 hr = S_OK;
1306 goto end;
1310 * Step to the next class in the list.
1312 curClass = curClass->nextClass;
1315 end:
1316 LeaveCriticalSection( &csRegisteredClassList );
1318 * If we get to here, we haven't found our class.
1320 return hr;
1323 /******************************************************************************
1324 * CoRegisterClassObject [OLE32.@]
1326 * Registers the class object for a given class ID. Servers housed in EXE
1327 * files use this method instead of exporting DllGetClassObject to allow
1328 * other code to connect to their objects.
1330 * PARAMS
1331 * rclsid [I] CLSID of the object to register.
1332 * pUnk [I] IUnknown of the object.
1333 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1334 * flags [I] REGCLS flags indicating how connections are made.
1335 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1337 * RETURNS
1338 * S_OK on success,
1339 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1340 * CO_E_OBJISREG if the object is already registered. We should not return this.
1342 * SEE ALSO
1343 * CoRevokeClassObject, CoGetClassObject
1345 * BUGS
1346 * MSDN claims that multiple interface registrations are legal, but we
1347 * can't do that with our current implementation.
1349 HRESULT WINAPI CoRegisterClassObject(
1350 REFCLSID rclsid,
1351 LPUNKNOWN pUnk,
1352 DWORD dwClsContext,
1353 DWORD flags,
1354 LPDWORD lpdwRegister)
1356 RegisteredClass* newClass;
1357 LPUNKNOWN foundObject;
1358 HRESULT hr;
1360 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1361 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1363 if ( (lpdwRegister==0) || (pUnk==0) )
1364 return E_INVALIDARG;
1366 if (!COM_CurrentApt())
1368 ERR("COM was not initialized\n");
1369 return CO_E_NOTINITIALIZED;
1372 *lpdwRegister = 0;
1375 * First, check if the class is already registered.
1376 * If it is, this should cause an error.
1378 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1379 if (hr == S_OK) {
1380 if (flags & REGCLS_MULTIPLEUSE) {
1381 if (dwClsContext & CLSCTX_LOCAL_SERVER)
1382 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
1383 IUnknown_Release(foundObject);
1384 return hr;
1386 IUnknown_Release(foundObject);
1387 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
1388 return CO_E_OBJISREG;
1391 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1392 if ( newClass == NULL )
1393 return E_OUTOFMEMORY;
1395 EnterCriticalSection( &csRegisteredClassList );
1397 newClass->classIdentifier = *rclsid;
1398 newClass->runContext = dwClsContext;
1399 newClass->connectFlags = flags;
1400 newClass->pMarshaledData = NULL;
1403 * Use the address of the chain node as the cookie since we are sure it's
1404 * unique. FIXME: not on 64-bit platforms.
1406 newClass->dwCookie = (DWORD)newClass;
1407 newClass->nextClass = firstRegisteredClass;
1410 * Since we're making a copy of the object pointer, we have to increase its
1411 * reference count.
1413 newClass->classObject = pUnk;
1414 IUnknown_AddRef(newClass->classObject);
1416 firstRegisteredClass = newClass;
1417 LeaveCriticalSection( &csRegisteredClassList );
1419 *lpdwRegister = newClass->dwCookie;
1421 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1422 IClassFactory *classfac;
1424 hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory,
1425 (LPVOID*)&classfac);
1426 if (hr) return hr;
1428 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
1429 if (hr) {
1430 FIXME("Failed to create stream on hglobal, %lx\n", hr);
1431 IUnknown_Release(classfac);
1432 return hr;
1434 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
1435 (LPVOID)classfac, MSHCTX_LOCAL, NULL,
1436 MSHLFLAGS_TABLESTRONG);
1437 if (hr) {
1438 FIXME("CoMarshalInterface failed, %lx!\n",hr);
1439 IUnknown_Release(classfac);
1440 return hr;
1443 IUnknown_Release(classfac);
1445 RPC_StartLocalServer(&newClass->classIdentifier, newClass->pMarshaledData);
1447 return S_OK;
1450 /***********************************************************************
1451 * CoRevokeClassObject [OLE32.@]
1453 * Removes a class object from the class registry.
1455 * PARAMS
1456 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1458 * RETURNS
1459 * Success: S_OK.
1460 * Failure: HRESULT code.
1462 * SEE ALSO
1463 * CoRegisterClassObject
1465 HRESULT WINAPI CoRevokeClassObject(
1466 DWORD dwRegister)
1468 HRESULT hr = E_INVALIDARG;
1469 RegisteredClass** prevClassLink;
1470 RegisteredClass* curClass;
1472 TRACE("(%08lx)\n",dwRegister);
1474 EnterCriticalSection( &csRegisteredClassList );
1477 * Iterate through the whole list and try to match the cookie.
1479 curClass = firstRegisteredClass;
1480 prevClassLink = &firstRegisteredClass;
1482 while (curClass != 0)
1485 * Check if we have a match on the cookie.
1487 if (curClass->dwCookie == dwRegister)
1490 * Remove the class from the chain.
1492 *prevClassLink = curClass->nextClass;
1495 * Release the reference to the class object.
1497 IUnknown_Release(curClass->classObject);
1499 if (curClass->pMarshaledData)
1501 LARGE_INTEGER zero;
1502 memset(&zero, 0, sizeof(zero));
1503 /* FIXME: stop local server thread */
1504 IStream_Seek(curClass->pMarshaledData, zero, SEEK_SET, NULL);
1505 CoReleaseMarshalData(curClass->pMarshaledData);
1509 * Free the memory used by the chain node.
1511 HeapFree(GetProcessHeap(), 0, curClass);
1513 hr = S_OK;
1514 goto end;
1518 * Step to the next class in the list.
1520 prevClassLink = &(curClass->nextClass);
1521 curClass = curClass->nextClass;
1524 end:
1525 LeaveCriticalSection( &csRegisteredClassList );
1527 * If we get to here, we haven't found our class.
1529 return hr;
1532 /***********************************************************************
1533 * COM_RegReadPath [internal]
1535 * Reads a registry value and expands it when necessary
1537 HRESULT COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
1539 HRESULT hres;
1540 HKEY key;
1541 DWORD keytype;
1542 WCHAR src[MAX_PATH];
1543 DWORD dwLength = dstlen * sizeof(WCHAR);
1545 if((hres = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1546 if( (hres = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1547 if (keytype == REG_EXPAND_SZ) {
1548 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) hres = ERROR_MORE_DATA;
1549 } else {
1550 lstrcpynW(dst, src, dstlen);
1553 RegCloseKey (key);
1555 return hres;
1558 static HRESULT get_inproc_class_object(HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
1560 HINSTANCE hLibrary;
1561 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1562 DllGetClassObjectFunc DllGetClassObject;
1563 WCHAR dllpath[MAX_PATH+1];
1565 if (COM_RegReadPath(hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
1567 /* failure: CLSID is not found in registry */
1568 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
1569 return REGDB_E_CLASSNOTREG;
1572 if ((hLibrary = LoadLibraryExW(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0)
1574 /* failure: DLL could not be loaded */
1575 ERR("couldn't load in-process dll %s\n", debugstr_w(dllpath));
1576 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1579 if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject")))
1581 /* failure: the dll did not export DllGetClassObject */
1582 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(dllpath));
1583 FreeLibrary( hLibrary );
1584 return CO_E_DLLNOTFOUND;
1587 /* OK: get the ClassObject */
1588 COMPOBJ_DLLList_Add( hLibrary );
1589 return DllGetClassObject(rclsid, riid, ppv);
1592 /***********************************************************************
1593 * CoGetClassObject [OLE32.@]
1595 * FIXME. If request allows of several options and there is a failure
1596 * with one (other than not being registered) do we try the
1597 * others or return failure? (E.g. inprocess is registered but
1598 * the DLL is not found but the server version works)
1600 HRESULT WINAPI CoGetClassObject(
1601 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1602 REFIID iid, LPVOID *ppv)
1604 LPUNKNOWN regClassObject;
1605 HRESULT hres = E_UNEXPECTED;
1607 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1609 if (pServerInfo) {
1610 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1611 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1615 * First, try and see if we can't match the class ID with one of the
1616 * registered classes.
1618 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, &regClassObject))
1620 /* Get the required interface from the retrieved pointer. */
1621 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1624 * Since QI got another reference on the pointer, we want to release the
1625 * one we already have. If QI was unsuccessful, this will release the object. This
1626 * is good since we are not returning it in the "out" parameter.
1628 IUnknown_Release(regClassObject);
1630 return hres;
1633 /* First try in-process server */
1634 if (CLSCTX_INPROC_SERVER & dwClsContext)
1636 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
1637 HKEY hkey;
1639 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
1640 if (FAILED(hres))
1642 if (hres == REGDB_E_CLASSNOTREG)
1643 ERR("class %s not registered\n", debugstr_guid(rclsid));
1644 else
1645 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
1648 if (SUCCEEDED(hres))
1650 hres = get_inproc_class_object(hkey, rclsid, iid, ppv);
1651 RegCloseKey(hkey);
1654 /* return if we got a class, otherwise fall through to one of the
1655 * other types */
1656 if (SUCCEEDED(hres))
1657 return hres;
1660 /* Next try in-process handler */
1661 if (CLSCTX_INPROC_HANDLER & dwClsContext)
1663 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
1664 HKEY hkey;
1666 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
1667 if (FAILED(hres))
1669 if (hres == REGDB_E_CLASSNOTREG)
1670 ERR("class %s not registered\n", debugstr_guid(rclsid));
1671 else
1672 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
1675 if (SUCCEEDED(hres))
1677 hres = get_inproc_class_object(hkey, rclsid, iid, ppv);
1678 RegCloseKey(hkey);
1681 /* return if we got a class, otherwise fall through to one of the
1682 * other types */
1683 if (SUCCEEDED(hres))
1684 return hres;
1687 /* Next try out of process */
1688 if (CLSCTX_LOCAL_SERVER & dwClsContext)
1690 return RPC_GetLocalClassObject(rclsid,iid,ppv);
1693 /* Finally try remote: this requires networked DCOM (a lot of work) */
1694 if (CLSCTX_REMOTE_SERVER & dwClsContext)
1696 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1697 hres = E_NOINTERFACE;
1700 if (FAILED(hres))
1701 ERR("no class object %s could be created for for context 0x%lx\n",
1702 debugstr_guid(rclsid), dwClsContext);
1703 return hres;
1706 /***********************************************************************
1707 * CoResumeClassObjects (OLE32.@)
1709 * Resumes all class objects registered with REGCLS_SUSPENDED.
1711 * RETURNS
1712 * Success: S_OK.
1713 * Failure: HRESULT code.
1715 HRESULT WINAPI CoResumeClassObjects(void)
1717 FIXME("stub\n");
1718 return S_OK;
1721 /***********************************************************************
1722 * GetClassFile (OLE32.@)
1724 * This function supplies the CLSID associated with the given filename.
1726 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1728 IStorage *pstg=0;
1729 HRESULT res;
1730 int nbElm, length, i;
1731 LONG sizeProgId;
1732 LPOLESTR *pathDec=0,absFile=0,progId=0;
1733 LPWSTR extension;
1734 static const WCHAR bkslashW[] = {'\\',0};
1735 static const WCHAR dotW[] = {'.',0};
1737 TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1739 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1740 if((StgIsStorageFile(filePathName))==S_OK){
1742 res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1744 if (SUCCEEDED(res))
1745 res=ReadClassStg(pstg,pclsid);
1747 IStorage_Release(pstg);
1749 return res;
1751 /* if the file is not a storage object then attemps to match various bits in the file against a
1752 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1753 this case
1755 for(i=0;i<nFileTypes;i++)
1757 for(i=0;j<nPatternsForType;j++){
1759 PATTERN pat;
1760 HANDLE hFile;
1762 pat=ReadPatternFromRegistry(i,j);
1763 hFile=CreateFileW(filePathName,,,,,,hFile);
1764 SetFilePosition(hFile,pat.offset);
1765 ReadFile(hFile,buf,pat.size,&r,NULL);
1766 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1768 *pclsid=ReadCLSIDFromRegistry(i);
1769 return S_OK;
1774 /* if the above strategies fail then search for the extension key in the registry */
1776 /* get the last element (absolute file) in the path name */
1777 nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1778 absFile=pathDec[nbElm-1];
1780 /* failed if the path represente a directory and not an absolute file name*/
1781 if (!lstrcmpW(absFile, bkslashW))
1782 return MK_E_INVALIDEXTENSION;
1784 /* get the extension of the file */
1785 extension = NULL;
1786 length=lstrlenW(absFile);
1787 for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1788 /* nothing */;
1790 if (!extension || !lstrcmpW(extension, dotW))
1791 return MK_E_INVALIDEXTENSION;
1793 res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1795 /* get the progId associated to the extension */
1796 progId = CoTaskMemAlloc(sizeProgId);
1797 res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1799 if (res==ERROR_SUCCESS)
1800 /* return the clsid associated to the progId */
1801 res= CLSIDFromProgID(progId,pclsid);
1803 for(i=0; pathDec[i]!=NULL;i++)
1804 CoTaskMemFree(pathDec[i]);
1805 CoTaskMemFree(pathDec);
1807 CoTaskMemFree(progId);
1809 if (res==ERROR_SUCCESS)
1810 return res;
1812 return MK_E_INVALIDEXTENSION;
1815 /***********************************************************************
1816 * CoCreateInstance [OLE32.@]
1818 HRESULT WINAPI CoCreateInstance(
1819 REFCLSID rclsid,
1820 LPUNKNOWN pUnkOuter,
1821 DWORD dwClsContext,
1822 REFIID iid,
1823 LPVOID *ppv)
1825 HRESULT hres;
1826 LPCLASSFACTORY lpclf = 0;
1828 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08lx, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
1829 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
1831 if (!COM_CurrentApt()) return CO_E_NOTINITIALIZED;
1834 * Sanity check
1836 if (ppv==0)
1837 return E_POINTER;
1840 * Initialize the "out" parameter
1842 *ppv = 0;
1845 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1846 * Rather than create a class factory, we can just check for it here
1848 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
1849 if (StdGlobalInterfaceTableInstance == NULL)
1850 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
1851 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
1852 if (hres) return hres;
1854 TRACE("Retrieved GIT (%p)\n", *ppv);
1855 return S_OK;
1859 * Get a class factory to construct the object we want.
1861 hres = CoGetClassObject(rclsid,
1862 dwClsContext,
1863 NULL,
1864 &IID_IClassFactory,
1865 (LPVOID)&lpclf);
1867 if (FAILED(hres)) {
1868 FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n",
1869 debugstr_guid(rclsid),hres);
1870 return hres;
1874 * Create the object and don't forget to release the factory
1876 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
1877 IClassFactory_Release(lpclf);
1878 if(FAILED(hres))
1879 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1880 debugstr_guid(iid), debugstr_guid(rclsid),hres);
1882 return hres;
1885 /***********************************************************************
1886 * CoCreateInstanceEx [OLE32.@]
1888 HRESULT WINAPI CoCreateInstanceEx(
1889 REFCLSID rclsid,
1890 LPUNKNOWN pUnkOuter,
1891 DWORD dwClsContext,
1892 COSERVERINFO* pServerInfo,
1893 ULONG cmq,
1894 MULTI_QI* pResults)
1896 IUnknown* pUnk = NULL;
1897 HRESULT hr;
1898 ULONG index;
1899 ULONG successCount = 0;
1902 * Sanity check
1904 if ( (cmq==0) || (pResults==NULL))
1905 return E_INVALIDARG;
1907 if (pServerInfo!=NULL)
1908 FIXME("() non-NULL pServerInfo not supported!\n");
1911 * Initialize all the "out" parameters.
1913 for (index = 0; index < cmq; index++)
1915 pResults[index].pItf = NULL;
1916 pResults[index].hr = E_NOINTERFACE;
1920 * Get the object and get its IUnknown pointer.
1922 hr = CoCreateInstance(rclsid,
1923 pUnkOuter,
1924 dwClsContext,
1925 &IID_IUnknown,
1926 (VOID**)&pUnk);
1928 if (hr)
1929 return hr;
1932 * Then, query for all the interfaces requested.
1934 for (index = 0; index < cmq; index++)
1936 pResults[index].hr = IUnknown_QueryInterface(pUnk,
1937 pResults[index].pIID,
1938 (VOID**)&(pResults[index].pItf));
1940 if (pResults[index].hr == S_OK)
1941 successCount++;
1945 * Release our temporary unknown pointer.
1947 IUnknown_Release(pUnk);
1949 if (successCount == 0)
1950 return E_NOINTERFACE;
1952 if (successCount!=cmq)
1953 return CO_S_NOTALLINTERFACES;
1955 return S_OK;
1958 /***********************************************************************
1959 * CoLoadLibrary (OLE32.@)
1961 * Loads a library.
1963 * PARAMS
1964 * lpszLibName [I] Path to library.
1965 * bAutoFree [I] Whether the library should automatically be freed.
1967 * RETURNS
1968 * Success: Handle to loaded library.
1969 * Failure: NULL.
1971 * SEE ALSO
1972 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1974 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
1976 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
1978 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
1981 /***********************************************************************
1982 * CoFreeLibrary [OLE32.@]
1984 * Unloads a library from memory.
1986 * PARAMS
1987 * hLibrary [I] Handle to library to unload.
1989 * RETURNS
1990 * Nothing
1992 * SEE ALSO
1993 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1995 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
1997 FreeLibrary(hLibrary);
2001 /***********************************************************************
2002 * CoFreeAllLibraries [OLE32.@]
2004 * Function for backwards compatibility only. Does nothing.
2006 * RETURNS
2007 * Nothing.
2009 * SEE ALSO
2010 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2012 void WINAPI CoFreeAllLibraries(void)
2014 /* NOP */
2018 /***********************************************************************
2019 * CoFreeUnusedLibraries [OLE32.@]
2020 * CoFreeUnusedLibraries [COMPOBJ.17]
2022 * Frees any unused libraries. Unused are identified as those that return
2023 * S_OK from their DllCanUnloadNow function.
2025 * RETURNS
2026 * Nothing.
2028 * SEE ALSO
2029 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2031 void WINAPI CoFreeUnusedLibraries(void)
2033 /* FIXME: Calls to CoFreeUnusedLibraries from any thread always route
2034 * through the main apartment's thread to call DllCanUnloadNow */
2035 COMPOBJ_DllList_FreeUnused(0);
2038 /***********************************************************************
2039 * CoFileTimeNow [OLE32.@]
2040 * CoFileTimeNow [COMPOBJ.82]
2042 * Retrieves the current time in FILETIME format.
2044 * PARAMS
2045 * lpFileTime [O] The current time.
2047 * RETURNS
2048 * S_OK.
2050 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
2052 GetSystemTimeAsFileTime( lpFileTime );
2053 return S_OK;
2056 static void COM_RevokeAllClasses()
2058 EnterCriticalSection( &csRegisteredClassList );
2060 while (firstRegisteredClass!=0)
2062 CoRevokeClassObject(firstRegisteredClass->dwCookie);
2065 LeaveCriticalSection( &csRegisteredClassList );
2068 /******************************************************************************
2069 * CoLockObjectExternal [OLE32.@]
2071 * Increments or decrements the external reference count of a stub object.
2073 * PARAMS
2074 * pUnk [I] Stub object.
2075 * fLock [I] If TRUE then increments the external ref-count,
2076 * otherwise decrements.
2077 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2078 * calling CoDisconnectObject.
2080 * RETURNS
2081 * Success: S_OK.
2082 * Failure: HRESULT code.
2084 HRESULT WINAPI CoLockObjectExternal(
2085 LPUNKNOWN pUnk,
2086 BOOL fLock,
2087 BOOL fLastUnlockReleases)
2089 struct stub_manager *stubmgr;
2090 struct apartment *apt;
2092 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2093 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2095 apt = COM_CurrentApt();
2096 if (!apt) return CO_E_NOTINITIALIZED;
2098 stubmgr = get_stub_manager_from_object(apt, pUnk);
2100 if (stubmgr)
2102 if (fLock)
2103 stub_manager_ext_addref(stubmgr, 1);
2104 else
2105 stub_manager_ext_release(stubmgr, 1);
2107 stub_manager_int_release(stubmgr);
2109 return S_OK;
2111 else
2113 WARN("stub object not found %p\n", pUnk);
2114 /* Note: native is pretty broken here because it just silently
2115 * fails, without returning an appropriate error code, making apps
2116 * think that the object was disconnected, when it actually wasn't */
2117 return S_OK;
2121 /***********************************************************************
2122 * CoInitializeWOW (OLE32.@)
2124 * WOW equivalent of CoInitialize?
2126 * PARAMS
2127 * x [I] Unknown.
2128 * y [I] Unknown.
2130 * RETURNS
2131 * Unknown.
2133 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2135 FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
2136 return 0;
2139 /***********************************************************************
2140 * CoGetState [OLE32.@]
2142 * Retrieves the thread state object previously stored by CoSetState().
2144 * PARAMS
2145 * ppv [I] Address where pointer to object will be stored.
2147 * RETURNS
2148 * Success: S_OK.
2149 * Failure: E_OUTOFMEMORY.
2151 * NOTES
2152 * Crashes on all invalid ppv addresses, including NULL.
2153 * If the function returns a non-NULL object then the caller must release its
2154 * reference on the object when the object is no longer required.
2156 * SEE ALSO
2157 * CoSetState().
2159 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2161 struct oletls *info = COM_CurrentInfo();
2162 if (!info) return E_OUTOFMEMORY;
2164 *ppv = NULL;
2166 if (info->state)
2168 IUnknown_AddRef(info->state);
2169 *ppv = info->state;
2170 TRACE("apt->state=%p\n", info->state);
2173 return S_OK;
2176 /***********************************************************************
2177 * CoSetState [OLE32.@]
2179 * Sets the thread state object.
2181 * PARAMS
2182 * pv [I] Pointer to state object to be stored.
2184 * NOTES
2185 * The system keeps a reference on the object while the object stored.
2187 * RETURNS
2188 * Success: S_OK.
2189 * Failure: E_OUTOFMEMORY.
2191 HRESULT WINAPI CoSetState(IUnknown * pv)
2193 struct oletls *info = COM_CurrentInfo();
2194 if (!info) return E_OUTOFMEMORY;
2196 if (pv) IUnknown_AddRef(pv);
2198 if (info->state)
2200 TRACE("-- release %p now\n", info->state);
2201 IUnknown_Release(info->state);
2204 info->state = pv;
2206 return S_OK;
2210 /******************************************************************************
2211 * OleGetAutoConvert [OLE32.@]
2213 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2215 static const WCHAR wszAutoConvertTo[] = {'A','u','t','o','C','o','n','v','e','r','t','T','o',0};
2216 HKEY hkey = NULL;
2217 WCHAR buf[CHARS_IN_GUID];
2218 LONG len;
2219 HRESULT res = S_OK;
2221 res = COM_OpenKeyForCLSID(clsidOld, wszAutoConvertTo, KEY_READ, &hkey);
2222 if (FAILED(res))
2223 goto done;
2225 len = sizeof(buf);
2226 if (RegQueryValueW(hkey, NULL, buf, &len))
2228 res = REGDB_E_KEYMISSING;
2229 goto done;
2231 res = CLSIDFromString(buf, pClsidNew);
2232 done:
2233 if (hkey) RegCloseKey(hkey);
2234 return res;
2237 /******************************************************************************
2238 * CoTreatAsClass [OLE32.@]
2240 * Sets the TreatAs value of a class.
2242 * PARAMS
2243 * clsidOld [I] Class to set TreatAs value on.
2244 * clsidNew [I] The class the clsidOld should be treated as.
2246 * RETURNS
2247 * Success: S_OK.
2248 * Failure: HRESULT code.
2250 * SEE ALSO
2251 * CoGetTreatAsClass
2253 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2255 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
2256 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2257 HKEY hkey = NULL;
2258 WCHAR szClsidNew[CHARS_IN_GUID];
2259 HRESULT res = S_OK;
2260 WCHAR auto_treat_as[CHARS_IN_GUID];
2261 LONG auto_treat_as_size = sizeof(auto_treat_as);
2262 CLSID id;
2264 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
2265 if (FAILED(res))
2266 goto done;
2267 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2269 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
2270 !CLSIDFromString(auto_treat_as, &id))
2272 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
2274 res = REGDB_E_WRITEREGDB;
2275 goto done;
2278 else
2280 RegDeleteKeyW(hkey, wszTreatAs);
2281 goto done;
2284 else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
2285 !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
2287 res = REGDB_E_WRITEREGDB;
2288 goto done;
2291 done:
2292 if (hkey) RegCloseKey(hkey);
2293 return res;
2296 /******************************************************************************
2297 * CoGetTreatAsClass [OLE32.@]
2299 * Gets the TreatAs value of a class.
2301 * PARAMS
2302 * clsidOld [I] Class to get the TreatAs value of.
2303 * clsidNew [I] The class the clsidOld should be treated as.
2305 * RETURNS
2306 * Success: S_OK.
2307 * Failure: HRESULT code.
2309 * SEE ALSO
2310 * CoSetTreatAsClass
2312 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2314 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2315 HKEY hkey = NULL;
2316 WCHAR szClsidNew[CHARS_IN_GUID];
2317 HRESULT res = S_OK;
2318 LONG len = sizeof(szClsidNew);
2320 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2321 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2323 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
2324 if (FAILED(res))
2325 goto done;
2326 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
2328 res = S_FALSE;
2329 goto done;
2331 res = CLSIDFromString(szClsidNew,clsidNew);
2332 if (FAILED(res))
2333 ERR("Failed CLSIDFromStringA(%s), hres 0x%08lx\n", debugstr_w(szClsidNew), res);
2334 done:
2335 if (hkey) RegCloseKey(hkey);
2336 return res;
2339 /******************************************************************************
2340 * CoGetCurrentProcess [OLE32.@]
2341 * CoGetCurrentProcess [COMPOBJ.34]
2343 * Gets the current process ID.
2345 * RETURNS
2346 * The current process ID.
2348 * NOTES
2349 * Is DWORD really the correct return type for this function?
2351 DWORD WINAPI CoGetCurrentProcess(void)
2353 return GetCurrentProcessId();
2356 /******************************************************************************
2357 * CoRegisterMessageFilter [OLE32.@]
2359 * Registers a message filter.
2361 * PARAMS
2362 * lpMessageFilter [I] Pointer to interface.
2363 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2365 * RETURNS
2366 * Success: S_OK.
2367 * Failure: HRESULT code.
2369 HRESULT WINAPI CoRegisterMessageFilter(
2370 LPMESSAGEFILTER lpMessageFilter,
2371 LPMESSAGEFILTER *lplpMessageFilter)
2373 FIXME("stub\n");
2374 if (lplpMessageFilter) {
2375 *lplpMessageFilter = NULL;
2377 return S_OK;
2380 /***********************************************************************
2381 * CoIsOle1Class [OLE32.@]
2383 * Determines whether the specified class an OLE v1 class.
2385 * PARAMS
2386 * clsid [I] Class to test.
2388 * RETURNS
2389 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
2391 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
2393 FIXME("%s\n", debugstr_guid(clsid));
2394 return FALSE;
2397 /***********************************************************************
2398 * IsEqualGUID [OLE32.@]
2400 * Compares two Unique Identifiers.
2402 * PARAMS
2403 * rguid1 [I] The first GUID to compare.
2404 * rguid2 [I] The other GUID to compare.
2406 * RETURNS
2407 * TRUE if equal
2409 #undef IsEqualGUID
2410 BOOL WINAPI IsEqualGUID(
2411 REFGUID rguid1,
2412 REFGUID rguid2)
2414 return !memcmp(rguid1,rguid2,sizeof(GUID));
2417 /***********************************************************************
2418 * CoInitializeSecurity [OLE32.@]
2420 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2421 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2422 void* pReserved1, DWORD dwAuthnLevel,
2423 DWORD dwImpLevel, void* pReserved2,
2424 DWORD dwCapabilities, void* pReserved3)
2426 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
2427 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2428 dwCapabilities, pReserved3);
2429 return S_OK;
2432 /***********************************************************************
2433 * CoSuspendClassObjects [OLE32.@]
2435 * Suspends all registered class objects to prevent further requests coming in
2436 * for those objects.
2438 * RETURNS
2439 * Success: S_OK.
2440 * Failure: HRESULT code.
2442 HRESULT WINAPI CoSuspendClassObjects(void)
2444 FIXME("\n");
2445 return S_OK;
2448 /***********************************************************************
2449 * CoAddRefServerProcess [OLE32.@]
2451 * Helper function for incrementing the reference count of a local-server
2452 * process.
2454 * RETURNS
2455 * New reference count.
2457 ULONG WINAPI CoAddRefServerProcess(void)
2459 FIXME("\n");
2460 return 2;
2463 /***********************************************************************
2464 * CoReleaseServerProcess [OLE32.@]
2466 * Helper function for decrementing the reference count of a local-server
2467 * process.
2469 * RETURNS
2470 * New reference count.
2472 ULONG WINAPI CoReleaseServerProcess(void)
2474 FIXME("\n");
2475 return 1;
2478 /***********************************************************************
2479 * CoIsHandlerConnected [OLE32.@]
2481 * Determines whether a proxy is connected to a remote stub.
2483 * PARAMS
2484 * pUnk [I] Pointer to object that may or may not be connected.
2486 * RETURNS
2487 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
2488 * FALSE otherwise.
2490 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
2492 FIXME("%p\n", pUnk);
2494 return TRUE;
2497 /***********************************************************************
2498 * CoAllowSetForegroundWindow [OLE32.@]
2501 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
2503 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
2504 return S_OK;
2507 /***********************************************************************
2508 * CoQueryProxyBlanket [OLE32.@]
2510 * Retrieves the security settings being used by a proxy.
2512 * PARAMS
2513 * pProxy [I] Pointer to the proxy object.
2514 * pAuthnSvc [O] The type of authentication service.
2515 * pAuthzSvc [O] The type of authorization service.
2516 * ppServerPrincName [O] Optional. The server prinicple name.
2517 * pAuthnLevel [O] The authentication level.
2518 * pImpLevel [O] The impersonation level.
2519 * ppAuthInfo [O] Information specific to the authorization/authentication service.
2520 * pCapabilities [O] Flags affecting the security behaviour.
2522 * RETURNS
2523 * Success: S_OK.
2524 * Failure: HRESULT code.
2526 * SEE ALSO
2527 * CoCopyProxy, CoSetProxyBlanket.
2529 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
2530 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
2531 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
2533 IClientSecurity *pCliSec;
2534 HRESULT hr;
2536 TRACE("%p\n", pProxy);
2538 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2539 if (SUCCEEDED(hr))
2541 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
2542 pAuthzSvc, ppServerPrincName,
2543 pAuthnLevel, pImpLevel, ppAuthInfo,
2544 pCapabilities);
2545 IClientSecurity_Release(pCliSec);
2548 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2549 return hr;
2552 /***********************************************************************
2553 * CoSetProxyBlanket [OLE32.@]
2555 * Sets the security settings for a proxy.
2557 * PARAMS
2558 * pProxy [I] Pointer to the proxy object.
2559 * AuthnSvc [I] The type of authentication service.
2560 * AuthzSvc [I] The type of authorization service.
2561 * pServerPrincName [I] The server prinicple name.
2562 * AuthnLevel [I] The authentication level.
2563 * ImpLevel [I] The impersonation level.
2564 * pAuthInfo [I] Information specific to the authorization/authentication service.
2565 * Capabilities [I] Flags affecting the security behaviour.
2567 * RETURNS
2568 * Success: S_OK.
2569 * Failure: HRESULT code.
2571 * SEE ALSO
2572 * CoQueryProxyBlanket, CoCopyProxy.
2574 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
2575 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
2576 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
2578 IClientSecurity *pCliSec;
2579 HRESULT hr;
2581 TRACE("%p\n", pProxy);
2583 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2584 if (SUCCEEDED(hr))
2586 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
2587 AuthzSvc, pServerPrincName,
2588 AuthnLevel, ImpLevel, pAuthInfo,
2589 Capabilities);
2590 IClientSecurity_Release(pCliSec);
2593 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2594 return hr;
2597 /***********************************************************************
2598 * CoCopyProxy [OLE32.@]
2600 * Copies a proxy.
2602 * PARAMS
2603 * pProxy [I] Pointer to the proxy object.
2604 * ppCopy [O] Copy of the proxy.
2606 * RETURNS
2607 * Success: S_OK.
2608 * Failure: HRESULT code.
2610 * SEE ALSO
2611 * CoQueryProxyBlanket, CoSetProxyBlanket.
2613 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
2615 IClientSecurity *pCliSec;
2616 HRESULT hr;
2618 TRACE("%p\n", pProxy);
2620 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2621 if (SUCCEEDED(hr))
2623 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
2624 IClientSecurity_Release(pCliSec);
2627 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2628 return hr;
2632 /***********************************************************************
2633 * CoWaitForMultipleHandles [OLE32.@]
2635 * Waits for one or more handles to become signaled.
2637 * PARAMS
2638 * dwFlags [I] Flags. See notes.
2639 * dwTimeout [I] Timeout in milliseconds.
2640 * cHandles [I] Number of handles pointed to by pHandles.
2641 * pHandles [I] Handles to wait for.
2642 * lpdwindex [O] Index of handle that was signaled.
2644 * RETURNS
2645 * Success: S_OK.
2646 * Failure: RPC_S_CALLPENDING on timeout.
2648 * NOTES
2650 * The dwFlags parameter can be zero or more of the following:
2651 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
2652 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
2654 * SEE ALSO
2655 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
2657 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
2658 ULONG cHandles, const HANDLE* pHandles, LPDWORD lpdwindex)
2660 HRESULT hr = S_OK;
2661 DWORD wait_flags = (dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0 |
2662 (dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0;
2663 DWORD start_time = GetTickCount();
2665 TRACE("(0x%08lx, 0x%08lx, %ld, %p, %p)\n", dwFlags, dwTimeout, cHandles,
2666 pHandles, lpdwindex);
2668 while (TRUE)
2670 DWORD now = GetTickCount();
2671 DWORD res;
2673 if ((dwTimeout != INFINITE) && (start_time + dwTimeout >= now))
2675 hr = RPC_S_CALLPENDING;
2676 break;
2679 TRACE("waiting for rpc completion or window message\n");
2681 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
2682 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
2683 QS_ALLINPUT, wait_flags);
2685 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
2687 MSG msg;
2688 while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
2690 /* FIXME: filter the messages here */
2691 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
2692 TranslateMessage(&msg);
2693 DispatchMessageW(&msg);
2694 if (msg.message == WM_QUIT)
2696 TRACE("resending WM_QUIT to outer message loop\n");
2697 PostQuitMessage(msg.wParam);
2698 goto done;
2702 else if ((res >= WAIT_OBJECT_0) && (res < WAIT_OBJECT_0 + cHandles))
2704 /* handle signaled, store index */
2705 *lpdwindex = (res - WAIT_OBJECT_0);
2706 break;
2708 else if (res == WAIT_TIMEOUT)
2710 hr = RPC_S_CALLPENDING;
2711 break;
2713 else
2715 ERR("Unexpected wait termination: %ld, %ld\n", res, GetLastError());
2716 hr = E_UNEXPECTED;
2717 break;
2720 done:
2721 TRACE("-- 0x%08lx\n", hr);
2722 return hr;
2725 /***********************************************************************
2726 * DllMain (OLE32.@)
2728 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
2730 TRACE("%p 0x%lx %p\n", hinstDLL, fdwReason, fImpLoad);
2732 switch(fdwReason) {
2733 case DLL_PROCESS_ATTACH:
2734 OLE32_hInstance = hinstDLL;
2735 COMPOBJ_InitProcess();
2736 if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1);
2737 break;
2739 case DLL_PROCESS_DETACH:
2740 if (TRACE_ON(ole)) CoRevokeMallocSpy();
2741 COMPOBJ_UninitProcess();
2742 OLE32_hInstance = 0;
2743 break;
2745 case DLL_THREAD_DETACH:
2746 COM_TlsDestroy();
2747 break;
2749 return TRUE;
2752 /* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */