- Extend COM_OpenKeyForCLSID to open a subkey and return an HRESULT.
[wine.git] / dlls / ole32 / compobj.c
blob91fe4198daec9241140523cdba082aabcdefd37b
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 * - Pump the message loop during RPC calls.
37 * - Call IMessageFilter functions.
39 * - Make all ole interface marshaling use NDR to be wire compatible with
40 * native DCOM
41 * - Use & interpret ORPCTHIS & ORPCTHAT.
45 #include "config.h"
47 #include <stdlib.h>
48 #include <stdarg.h>
49 #include <stdio.h>
50 #include <string.h>
51 #include <assert.h>
53 #define COBJMACROS
54 #define NONAMELESSUNION
55 #define NONAMELESSSTRUCT
57 #include "windef.h"
58 #include "winbase.h"
59 #include "winerror.h"
60 #include "winreg.h"
61 #include "winuser.h"
62 #include "objbase.h"
63 #include "ole2.h"
64 #include "ole2ver.h"
66 #include "compobj_private.h"
68 #include "wine/unicode.h"
69 #include "wine/debug.h"
71 WINE_DEFAULT_DEBUG_CHANNEL(ole);
73 HINSTANCE OLE32_hInstance = 0; /* FIXME: make static ... */
75 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
77 /****************************************************************************
78 * This section defines variables internal to the COM module.
80 * TODO: Most of these things will have to be made thread-safe.
83 static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk);
84 static void COM_RevokeAllClasses(void);
86 const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
88 APARTMENT *MTA; /* protected by csApartment */
89 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
91 static CRITICAL_SECTION csApartment;
92 static CRITICAL_SECTION_DEBUG critsect_debug =
94 0, 0, &csApartment,
95 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
96 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
98 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
101 * This lock count counts the number of times CoInitialize is called. It is
102 * decreased every time CoUninitialize is called. When it hits 0, the COM
103 * libraries are freed
105 static LONG s_COMLockCount = 0;
108 * This linked list contains the list of registered class objects. These
109 * are mostly used to register the factories for out-of-proc servers of OLE
110 * objects.
112 * TODO: Make this data structure aware of inter-process communication. This
113 * means that parts of this will be exported to the Wine Server.
115 typedef struct tagRegisteredClass
117 CLSID classIdentifier;
118 LPUNKNOWN classObject;
119 DWORD runContext;
120 DWORD connectFlags;
121 DWORD dwCookie;
122 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
123 struct tagRegisteredClass* nextClass;
124 } RegisteredClass;
126 static RegisteredClass* firstRegisteredClass = NULL;
128 static CRITICAL_SECTION csRegisteredClassList;
129 static CRITICAL_SECTION_DEBUG class_cs_debug =
131 0, 0, &csRegisteredClassList,
132 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
133 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
135 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
137 /*****************************************************************************
138 * This section contains OpenDllList definitions
140 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
141 * other functions that do LoadLibrary _without_ giving back a HMODULE.
142 * Without this list these handles would never be freed.
144 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
145 * next unload-call but not before 600 sec.
148 typedef struct tagOpenDll {
149 HINSTANCE hLibrary;
150 struct tagOpenDll *next;
151 } OpenDll;
153 static OpenDll *openDllList = NULL; /* linked list of open dlls */
155 static CRITICAL_SECTION csOpenDllList;
156 static CRITICAL_SECTION_DEBUG dll_cs_debug =
158 0, 0, &csOpenDllList,
159 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
160 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
162 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
164 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',' ',
165 '0','x','#','#','#','#','#','#','#','#',' ',0};
166 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
168 static void COMPOBJ_DLLList_Add(HANDLE hLibrary);
169 static void COMPOBJ_DllList_FreeUnused(int Timeout);
171 static void COMPOBJ_InitProcess( void )
173 WNDCLASSW wclass;
175 /* Dispatching to the correct thread in an apartment is done through
176 * window messages rather than RPC transports. When an interface is
177 * marshalled into another apartment in the same process, a window of the
178 * following class is created. The *caller* of CoMarshalInterface (ie the
179 * application) is responsible for pumping the message loop in that thread.
180 * The WM_USER messages which point to the RPCs are then dispatched to
181 * COM_AptWndProc by the user's code from the apartment in which the interface
182 * was unmarshalled.
184 memset(&wclass, 0, sizeof(wclass));
185 wclass.lpfnWndProc = apartment_wndproc;
186 wclass.hInstance = OLE32_hInstance;
187 wclass.lpszClassName = wszAptWinClass;
188 RegisterClassW(&wclass);
191 static void COMPOBJ_UninitProcess( void )
193 UnregisterClassW(wszAptWinClass, OLE32_hInstance);
196 static void COM_TlsDestroy(void)
198 struct oletls *info = NtCurrentTeb()->ReservedForOle;
199 if (info)
201 if (info->apt) apartment_release(info->apt);
202 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
203 if (info->state) IUnknown_Release(info->state);
204 HeapFree(GetProcessHeap(), 0, info);
205 NtCurrentTeb()->ReservedForOle = NULL;
209 /******************************************************************************
210 * Manage apartments.
213 /* allocates memory and fills in the necessary fields for a new apartment
214 * object */
215 static APARTMENT *apartment_construct(DWORD model)
217 APARTMENT *apt;
219 TRACE("creating new apartment, model=%ld\n", model);
221 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
222 apt->tid = GetCurrentThreadId();
224 list_init(&apt->proxies);
225 list_init(&apt->stubmgrs);
226 apt->ipidc = 0;
227 apt->refs = 1;
228 apt->remunk_exported = FALSE;
229 apt->oidc = 1;
230 InitializeCriticalSection(&apt->cs);
231 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
233 apt->model = model;
235 if (model & COINIT_APARTMENTTHREADED)
237 /* FIXME: should be randomly generated by in an RPC call to rpcss */
238 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
239 apt->win = CreateWindowW(wszAptWinClass, NULL, 0,
240 0, 0, 0, 0,
241 0, 0, OLE32_hInstance, NULL);
243 else
245 /* FIXME: should be randomly generated by in an RPC call to rpcss */
246 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
249 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
251 /* the locking here is not currently needed for the MTA case, but it
252 * doesn't hurt and makes the code simpler */
253 EnterCriticalSection(&csApartment);
254 list_add_head(&apts, &apt->entry);
255 LeaveCriticalSection(&csApartment);
257 return apt;
260 /* gets and existing apartment if one exists or otherwise creates an apartment
261 * structure which stores OLE apartment-local information and stores a pointer
262 * to it in the thread-local storage */
263 static APARTMENT *apartment_get_or_create(DWORD model)
265 APARTMENT *apt = COM_CurrentApt();
267 if (!apt)
269 if (model & COINIT_APARTMENTTHREADED)
271 apt = apartment_construct(model);
272 COM_CurrentInfo()->apt = apt;
274 else
276 EnterCriticalSection(&csApartment);
278 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
279 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
280 * in a process */
281 if (MTA)
283 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
284 apartment_addref(MTA);
286 else
287 MTA = apartment_construct(model);
289 apt = MTA;
290 COM_CurrentInfo()->apt = apt;
292 LeaveCriticalSection(&csApartment);
296 return apt;
299 DWORD apartment_addref(struct apartment *apt)
301 DWORD refs = InterlockedIncrement(&apt->refs);
302 TRACE("%s: before = %ld\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
303 return refs;
306 DWORD apartment_release(struct apartment *apt)
308 DWORD ret;
310 EnterCriticalSection(&csApartment);
312 ret = InterlockedDecrement(&apt->refs);
313 TRACE("%s: after = %ld\n", wine_dbgstr_longlong(apt->oxid), ret);
314 /* destruction stuff that needs to happen under csApartment CS */
315 if (ret == 0)
317 if (apt == MTA) MTA = NULL;
318 list_remove(&apt->entry);
321 LeaveCriticalSection(&csApartment);
323 if (ret == 0)
325 struct list *cursor, *cursor2;
327 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
329 /* no locking is needed for this apartment, because no other thread
330 * can access it at this point */
332 apartment_disconnectproxies(apt);
334 if (apt->win) DestroyWindow(apt->win);
336 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
338 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
339 /* release the implicit reference given by the fact that the
340 * stub has external references (it must do since it is in the
341 * stub manager list in the apartment and all non-apartment users
342 * must have a ref on the apartment and so it cannot be destroyed).
344 stub_manager_int_release(stubmgr);
347 /* if this assert fires, then another thread took a reference to a
348 * stub manager without taking a reference to the containing
349 * apartment, which it must do. */
350 assert(list_empty(&apt->stubmgrs));
352 if (apt->filter) IUnknown_Release(apt->filter);
354 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
355 DeleteCriticalSection(&apt->cs);
357 HeapFree(GetProcessHeap(), 0, apt);
360 return ret;
363 /* The given OXID must be local to this process:
365 * The ref parameter is here mostly to ensure people remember that
366 * they get one, you should normally take a ref for thread safety.
368 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
370 APARTMENT *result = NULL;
371 struct list *cursor;
373 EnterCriticalSection(&csApartment);
374 LIST_FOR_EACH( cursor, &apts )
376 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
377 if (apt->oxid == oxid)
379 result = apt;
380 if (ref) apartment_addref(result);
381 break;
384 LeaveCriticalSection(&csApartment);
386 return result;
389 /* gets the apartment which has a given creator thread ID. The caller must
390 * release the reference from the apartment as soon as the apartment pointer
391 * is no longer required. */
392 APARTMENT *apartment_findfromtid(DWORD tid)
394 APARTMENT *result = NULL;
395 struct list *cursor;
397 EnterCriticalSection(&csApartment);
398 LIST_FOR_EACH( cursor, &apts )
400 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
401 if (apt->tid == tid)
403 result = apt;
404 apartment_addref(result);
405 break;
408 LeaveCriticalSection(&csApartment);
410 return result;
413 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
415 switch (msg)
417 case DM_EXECUTERPC:
418 RPC_ExecuteCall((struct dispatch_params *)lParam);
419 return 0;
420 default:
421 return DefWindowProcW(hWnd, msg, wParam, lParam);
425 /*****************************************************************************
426 * This section contains OpenDllList implemantation
429 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
431 OpenDll *ptr;
432 OpenDll *tmp;
434 TRACE("\n");
436 EnterCriticalSection( &csOpenDllList );
438 if (openDllList == NULL) {
439 /* empty list -- add first node */
440 openDllList = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
441 openDllList->hLibrary=hLibrary;
442 openDllList->next = NULL;
443 } else {
444 /* search for this dll */
445 int found = FALSE;
446 for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
447 if (ptr->hLibrary == hLibrary) {
448 found = TRUE;
449 break;
452 if (!found) {
453 /* dll not found, add it */
454 tmp = openDllList;
455 openDllList = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
456 openDllList->hLibrary = hLibrary;
457 openDllList->next = tmp;
461 LeaveCriticalSection( &csOpenDllList );
464 static void COMPOBJ_DllList_FreeUnused(int Timeout)
466 OpenDll *curr, *next, *prev = NULL;
467 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
468 DllCanUnloadNowFunc DllCanUnloadNow;
470 TRACE("\n");
472 EnterCriticalSection( &csOpenDllList );
474 for (curr = openDllList; curr != NULL; ) {
475 DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
477 if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
478 next = curr->next;
480 TRACE("freeing %p\n", curr->hLibrary);
481 FreeLibrary(curr->hLibrary);
483 HeapFree(GetProcessHeap(), 0, curr);
484 if (curr == openDllList) {
485 openDllList = next;
486 } else {
487 prev->next = next;
490 curr = next;
491 } else {
492 prev = curr;
493 curr = curr->next;
497 LeaveCriticalSection( &csOpenDllList );
500 /******************************************************************************
501 * CoBuildVersion [OLE32.@]
502 * CoBuildVersion [COMPOBJ.1]
504 * Gets the build version of the DLL.
506 * PARAMS
508 * RETURNS
509 * Current build version, hiword is majornumber, loword is minornumber
511 DWORD WINAPI CoBuildVersion(void)
513 TRACE("Returning version %d, build %d.\n", rmm, rup);
514 return (rmm<<16)+rup;
517 /******************************************************************************
518 * CoInitialize [OLE32.@]
520 * Initializes the COM libraries by calling CoInitializeEx with
521 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
523 * PARAMS
524 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
526 * RETURNS
527 * Success: S_OK if not already initialized, S_FALSE otherwise.
528 * Failure: HRESULT code.
530 * SEE ALSO
531 * CoInitializeEx
533 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
536 * Just delegate to the newer method.
538 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
541 /******************************************************************************
542 * CoInitializeEx [OLE32.@]
544 * Initializes the COM libraries.
546 * PARAMS
547 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
548 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
550 * RETURNS
551 * S_OK if successful,
552 * S_FALSE if this function was called already.
553 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
554 * threading model.
556 * NOTES
558 * The behavior used to set the IMalloc used for memory management is
559 * obsolete.
560 * The dwCoInit parameter must specify of of the following apartment
561 * threading models:
562 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
563 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
564 * The parameter may also specify zero or more of the following flags:
565 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
566 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
568 * SEE ALSO
569 * CoUninitialize
571 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
573 HRESULT hr = S_OK;
574 APARTMENT *apt;
576 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
578 if (lpReserved!=NULL)
580 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
584 * Check the lock count. If this is the first time going through the initialize
585 * process, we have to initialize the libraries.
587 * And crank-up that lock count.
589 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
592 * Initialize the various COM libraries and data structures.
594 TRACE("() - Initializing the COM libraries\n");
596 /* we may need to defer this until after apartment initialisation */
597 RunningObjectTableImpl_Initialize();
600 if (!(apt = COM_CurrentInfo()->apt))
602 apt = apartment_get_or_create(dwCoInit);
603 if (!apt) return E_OUTOFMEMORY;
605 else if (dwCoInit != apt->model)
607 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
608 code then we are probably using the wrong threading model to implement that API. */
609 ERR("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit);
610 return RPC_E_CHANGED_MODE;
612 else
613 hr = S_FALSE;
615 COM_CurrentInfo()->inits++;
617 return hr;
620 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
621 pending RPCs are ignored. Non-COM messages are discarded at this point.
623 static void COM_FlushMessageQueue(void)
625 MSG message;
626 APARTMENT *apt = COM_CurrentApt();
628 if (!apt || !apt->win) return;
630 TRACE("Flushing STA message queue\n");
632 while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE))
634 if (message.hwnd != apt->win)
636 WARN("discarding message 0x%x for window %p\n", message.message, message.hwnd);
637 continue;
640 TranslateMessage(&message);
641 DispatchMessageA(&message);
645 /***********************************************************************
646 * CoUninitialize [OLE32.@]
648 * This method will decrement the refcount on the current apartment, freeing
649 * the resources associated with it if it is the last thread in the apartment.
650 * If the last apartment is freed, the function will additionally release
651 * any COM resources associated with the process.
653 * PARAMS
655 * RETURNS
656 * Nothing.
658 * SEE ALSO
659 * CoInitializeEx
661 void WINAPI CoUninitialize(void)
663 struct oletls * info = COM_CurrentInfo();
664 LONG lCOMRefCnt;
666 TRACE("()\n");
668 /* will only happen on OOM */
669 if (!info) return;
671 /* sanity check */
672 if (!info->inits)
674 ERR("Mismatched CoUninitialize\n");
675 return;
678 if (!--info->inits)
680 apartment_release(info->apt);
681 info->apt = NULL;
685 * Decrease the reference count.
686 * If we are back to 0 locks on the COM library, make sure we free
687 * all the associated data structures.
689 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
690 if (lCOMRefCnt==1)
692 TRACE("() - Releasing the COM libraries\n");
694 RunningObjectTableImpl_UnInitialize();
696 /* Release the references to the registered class objects */
697 COM_RevokeAllClasses();
699 /* This will free the loaded COM Dlls */
700 CoFreeAllLibraries();
702 /* This ensures we deal with any pending RPCs */
703 COM_FlushMessageQueue();
705 else if (lCOMRefCnt<1) {
706 ERR( "CoUninitialize() - not CoInitialized.\n" );
707 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
711 /******************************************************************************
712 * CoDisconnectObject [OLE32.@]
713 * CoDisconnectObject [COMPOBJ.15]
715 * Disconnects all connections to this object from remote processes. Dispatches
716 * pending RPCs while blocking new RPCs from occurring, and then calls
717 * IMarshal::DisconnectObject on the given object.
719 * Typically called when the object server is forced to shut down, for instance by
720 * the user.
722 * PARAMS
723 * lpUnk [I] The object whose stub should be disconnected.
724 * reserved [I] Reserved. Should be set to 0.
726 * RETURNS
727 * Success: S_OK.
728 * Failure: HRESULT code.
730 * SEE ALSO
731 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
733 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
735 HRESULT hr;
736 IMarshal *marshal;
737 APARTMENT *apt;
739 TRACE("(%p, 0x%08lx)\n", lpUnk, reserved);
741 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
742 if (hr == S_OK)
744 hr = IMarshal_DisconnectObject(marshal, reserved);
745 IMarshal_Release(marshal);
746 return hr;
749 apt = COM_CurrentApt();
750 if (!apt)
751 return CO_E_NOTINITIALIZED;
753 apartment_disconnectobject(apt, lpUnk);
755 /* Note: native is pretty broken here because it just silently
756 * fails, without returning an appropriate error code if the object was
757 * not found, making apps think that the object was disconnected, when
758 * it actually wasn't */
760 return S_OK;
763 /******************************************************************************
764 * CoCreateGuid [OLE32.@]
766 * Simply forwards to UuidCreate in RPCRT4.
768 * PARAMS
769 * pguid [O] Points to the GUID to initialize.
771 * RETURNS
772 * Success: S_OK.
773 * Failure: HRESULT code.
775 * SEE ALSO
776 * UuidCreate
778 HRESULT WINAPI CoCreateGuid(GUID *pguid)
780 return UuidCreate(pguid);
783 /******************************************************************************
784 * CLSIDFromString [OLE32.@]
785 * IIDFromString [OLE32.@]
787 * Converts a unique identifier from its string representation into
788 * the GUID struct.
790 * PARAMS
791 * idstr [I] The string representation of the GUID.
792 * id [O] GUID converted from the string.
794 * RETURNS
795 * S_OK on success
796 * CO_E_CLASSSTRING if idstr is not a valid CLSID
798 * BUGS
800 * In Windows, if idstr is not a valid CLSID string then it gets
801 * treated as a ProgID. Wine currently doesn't do this. If idstr is
802 * NULL it's treated as an all-zero GUID.
804 * SEE ALSO
805 * StringFromCLSID
807 HRESULT WINAPI __CLSIDFromStringA(LPCSTR idstr, CLSID *id)
809 const BYTE *s;
810 int i;
811 BYTE table[256];
813 if (!idstr) {
814 memset( id, 0, sizeof (CLSID) );
815 return S_OK;
818 /* validate the CLSID string */
819 if (strlen(idstr) != 38)
820 return CO_E_CLASSSTRING;
822 s = (const BYTE *) idstr;
823 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
824 return CO_E_CLASSSTRING;
826 for (i=1; i<37; i++) {
827 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
828 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
829 ((s[i] >= 'a') && (s[i] <= 'f')) ||
830 ((s[i] >= 'A') && (s[i] <= 'F'))))
831 return CO_E_CLASSSTRING;
834 TRACE("%s -> %p\n", s, id);
836 /* quick lookup table */
837 memset(table, 0, 256);
839 for (i = 0; i < 10; i++) {
840 table['0' + i] = i;
842 for (i = 0; i < 6; i++) {
843 table['A' + i] = i+10;
844 table['a' + i] = i+10;
847 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
849 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
850 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
851 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
852 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
854 /* these are just sequential bytes */
855 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
856 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
857 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
858 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
859 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
860 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
861 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
862 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
864 return S_OK;
867 /*****************************************************************************/
869 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
871 char xid[40];
872 HRESULT ret;
874 if (!WideCharToMultiByte( CP_ACP, 0, idstr, -1, xid, sizeof(xid), NULL, NULL ))
875 return CO_E_CLASSSTRING;
878 ret = __CLSIDFromStringA(xid,id);
879 if(ret != S_OK) { /* It appears a ProgID is also valid */
880 ret = CLSIDFromProgID(idstr, id);
882 return ret;
885 /* Converts a GUID into the respective string representation. */
886 HRESULT WINE_StringFromCLSID(
887 const CLSID *id, /* [in] GUID to be converted */
888 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
890 static const char *hex = "0123456789ABCDEF";
891 char *s;
892 int i;
894 if (!id)
895 { ERR("called with id=Null\n");
896 *idstr = 0x00;
897 return E_FAIL;
900 sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
901 id->Data1, id->Data2, id->Data3,
902 id->Data4[0], id->Data4[1]);
903 s = &idstr[25];
905 /* 6 hex bytes */
906 for (i = 2; i < 8; i++) {
907 *s++ = hex[id->Data4[i]>>4];
908 *s++ = hex[id->Data4[i] & 0xf];
911 *s++ = '}';
912 *s++ = '\0';
914 TRACE("%p->%s\n", id, idstr);
916 return S_OK;
920 /******************************************************************************
921 * StringFromCLSID [OLE32.@]
922 * StringFromIID [OLE32.@]
924 * Converts a GUID into the respective string representation.
925 * The target string is allocated using the OLE IMalloc.
927 * PARAMS
928 * id [I] the GUID to be converted.
929 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
931 * RETURNS
932 * S_OK
933 * E_FAIL
935 * SEE ALSO
936 * StringFromGUID2, CLSIDFromString
938 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
940 char buf[80];
941 HRESULT ret;
942 LPMALLOC mllc;
944 if ((ret = CoGetMalloc(0,&mllc)))
945 return ret;
947 ret=WINE_StringFromCLSID(id,buf);
948 if (!ret) {
949 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
950 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
951 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
953 return ret;
956 /******************************************************************************
957 * StringFromGUID2 [OLE32.@]
958 * StringFromGUID2 [COMPOBJ.76]
960 * Modified version of StringFromCLSID that allows you to specify max
961 * buffer size.
963 * PARAMS
964 * id [I] GUID to convert to string.
965 * str [O] Buffer where the result will be stored.
966 * cmax [I] Size of the buffer in characters.
968 * RETURNS
969 * Success: The length of the resulting string in characters.
970 * Failure: 0.
972 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
974 char xguid[80];
976 if (WINE_StringFromCLSID(id,xguid))
977 return 0;
978 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
981 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
982 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
984 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
985 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
986 LONG res;
987 HKEY key;
989 strcpyW(path, wszCLSIDSlash);
990 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
991 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, keyname ? KEY_READ : access, &key);
992 if (res == ERROR_FILE_NOT_FOUND)
993 return REGDB_E_CLASSNOTREG;
994 else if (res != ERROR_SUCCESS)
995 return REGDB_E_READREGDB;
997 if (!keyname)
999 *subkey = key;
1000 return S_OK;
1003 res = RegOpenKeyExW(key, keyname, 0, access, subkey);
1004 RegCloseKey(key);
1005 if (res == ERROR_FILE_NOT_FOUND)
1006 return REGDB_E_KEYMISSING;
1007 else if (res != ERROR_SUCCESS)
1008 return REGDB_E_READREGDB;
1010 return S_OK;
1013 /******************************************************************************
1014 * ProgIDFromCLSID [OLE32.@]
1016 * Converts a class id into the respective program ID.
1018 * PARAMS
1019 * clsid [I] Class ID, as found in registry.
1020 * lplpszProgID [O] Associated ProgID.
1022 * RETURNS
1023 * S_OK
1024 * E_OUTOFMEMORY
1025 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1027 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *lplpszProgID)
1029 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
1030 HKEY hkey;
1031 HRESULT ret;
1032 LONG progidlen = 0;
1034 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
1035 if (FAILED(ret))
1036 return ret;
1038 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1039 ret = REGDB_E_CLASSNOTREG;
1041 if (ret == S_OK)
1043 *lplpszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
1044 if (*lplpszProgID)
1046 if (RegQueryValueW(hkey, NULL, *lplpszProgID, &progidlen))
1047 ret = REGDB_E_CLASSNOTREG;
1049 else
1050 ret = E_OUTOFMEMORY;
1053 RegCloseKey(hkey);
1054 return ret;
1057 /******************************************************************************
1058 * CLSIDFromProgID [OLE32.@]
1060 * Converts a program id into the respective GUID.
1062 * PARAMS
1063 * progid [I] Unicode program ID, as found in registry.
1064 * riid [O] Associated CLSID.
1066 * RETURNS
1067 * Success: S_OK
1068 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1070 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID riid)
1072 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1073 WCHAR buf2[CHARS_IN_GUID];
1074 LONG buf2len = sizeof(buf2);
1075 HKEY xhkey;
1077 WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1078 strcpyW( buf, progid );
1079 strcatW( buf, clsidW );
1080 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1082 HeapFree(GetProcessHeap(),0,buf);
1083 return CO_E_CLASSSTRING;
1085 HeapFree(GetProcessHeap(),0,buf);
1087 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
1089 RegCloseKey(xhkey);
1090 return CO_E_CLASSSTRING;
1092 RegCloseKey(xhkey);
1093 return CLSIDFromString(buf2,riid);
1097 /*****************************************************************************
1098 * CoGetPSClsid [OLE32.@]
1100 * Retrieves the CLSID of the proxy/stub factory that implements
1101 * IPSFactoryBuffer for the specified interface.
1103 * PARAMS
1104 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1105 * pclsid [O] Where to store returned proxy/stub CLSID.
1107 * RETURNS
1108 * S_OK
1109 * E_OUTOFMEMORY
1110 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1112 * NOTES
1114 * The standard marshaller activates the object with the CLSID
1115 * returned and uses the CreateProxy and CreateStub methods on its
1116 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1117 * given object.
1119 * CoGetPSClsid determines this CLSID by searching the
1120 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1121 * in the registry and any interface id registered by
1122 * CoRegisterPSClsid within the current process.
1124 * BUGS
1126 * We only search the registry, not ids registered with
1127 * CoRegisterPSClsid.
1128 * Also, native returns S_OK for interfaces with a key in HKCR\Interface, but
1129 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1130 * considered a bug in native unless an application depends on this (unlikely).
1132 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1134 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
1135 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
1136 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
1137 WCHAR value[CHARS_IN_GUID];
1138 LONG len;
1139 HKEY hkey;
1141 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1143 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
1144 strcpyW(path, wszInterface);
1145 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
1146 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
1148 /* Open the key.. */
1149 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &hkey))
1151 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1152 return REGDB_E_IIDNOTREG;
1155 /* ... Once we have the key, query the registry to get the
1156 value of CLSID as a string, and convert it into a
1157 proper CLSID structure to be passed back to the app */
1158 len = sizeof(value);
1159 if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
1161 RegCloseKey(hkey);
1162 return REGDB_E_IIDNOTREG;
1164 RegCloseKey(hkey);
1166 /* We have the CLSid we want back from the registry as a string, so
1167 lets convert it into a CLSID structure */
1168 if (CLSIDFromString(value, pclsid) != NOERROR)
1169 return REGDB_E_IIDNOTREG;
1171 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1172 return S_OK;
1177 /***********************************************************************
1178 * WriteClassStm (OLE32.@)
1180 * Writes a CLSID to a stream.
1182 * PARAMS
1183 * pStm [I] Stream to write to.
1184 * rclsid [I] CLSID to write.
1186 * RETURNS
1187 * Success: S_OK.
1188 * Failure: HRESULT code.
1190 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
1192 TRACE("(%p,%p)\n",pStm,rclsid);
1194 if (rclsid==NULL)
1195 return E_INVALIDARG;
1197 return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
1200 /***********************************************************************
1201 * ReadClassStm (OLE32.@)
1203 * Reads a CLSID from a stream.
1205 * PARAMS
1206 * pStm [I] Stream to read from.
1207 * rclsid [O] CLSID to read.
1209 * RETURNS
1210 * Success: S_OK.
1211 * Failure: HRESULT code.
1213 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
1215 ULONG nbByte;
1216 HRESULT res;
1218 TRACE("(%p,%p)\n",pStm,pclsid);
1220 if (pclsid==NULL)
1221 return E_INVALIDARG;
1223 res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
1225 if (FAILED(res))
1226 return res;
1228 if (nbByte != sizeof(CLSID))
1229 return S_FALSE;
1230 else
1231 return S_OK;
1235 /***
1236 * COM_GetRegisteredClassObject
1238 * This internal method is used to scan the registered class list to
1239 * find a class object.
1241 * Params:
1242 * rclsid Class ID of the class to find.
1243 * dwClsContext Class context to match.
1244 * ppv [out] returns a pointer to the class object. Complying
1245 * to normal COM usage, this method will increase the
1246 * reference count on this object.
1248 static HRESULT COM_GetRegisteredClassObject(
1249 REFCLSID rclsid,
1250 DWORD dwClsContext,
1251 LPUNKNOWN* ppUnk)
1253 HRESULT hr = S_FALSE;
1254 RegisteredClass* curClass;
1256 EnterCriticalSection( &csRegisteredClassList );
1259 * Sanity check
1261 assert(ppUnk!=0);
1264 * Iterate through the whole list and try to match the class ID.
1266 curClass = firstRegisteredClass;
1268 while (curClass != 0)
1271 * Check if we have a match on the class ID.
1273 if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
1276 * Since we don't do out-of process or DCOM just right away, let's ignore the
1277 * class context.
1281 * We have a match, return the pointer to the class object.
1283 *ppUnk = curClass->classObject;
1285 IUnknown_AddRef(curClass->classObject);
1287 hr = S_OK;
1288 goto end;
1292 * Step to the next class in the list.
1294 curClass = curClass->nextClass;
1297 end:
1298 LeaveCriticalSection( &csRegisteredClassList );
1300 * If we get to here, we haven't found our class.
1302 return hr;
1305 /******************************************************************************
1306 * CoRegisterClassObject [OLE32.@]
1308 * Registers the class object for a given class ID. Servers housed in EXE
1309 * files use this method instead of exporting DllGetClassObject to allow
1310 * other code to connect to their objects.
1312 * PARAMS
1313 * rclsid [I] CLSID of the object to register.
1314 * pUnk [I] IUnknown of the object.
1315 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1316 * flags [I] REGCLS flags indicating how connections are made.
1317 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1319 * RETURNS
1320 * S_OK on success,
1321 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1322 * CO_E_OBJISREG if the object is already registered. We should not return this.
1324 * SEE ALSO
1325 * CoRevokeClassObject, CoGetClassObject
1327 * BUGS
1328 * MSDN claims that multiple interface registrations are legal, but we
1329 * can't do that with our current implementation.
1331 HRESULT WINAPI CoRegisterClassObject(
1332 REFCLSID rclsid,
1333 LPUNKNOWN pUnk,
1334 DWORD dwClsContext,
1335 DWORD flags,
1336 LPDWORD lpdwRegister)
1338 RegisteredClass* newClass;
1339 LPUNKNOWN foundObject;
1340 HRESULT hr;
1342 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1343 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1345 if ( (lpdwRegister==0) || (pUnk==0) )
1346 return E_INVALIDARG;
1348 if (!COM_CurrentApt())
1350 ERR("COM was not initialized\n");
1351 return CO_E_NOTINITIALIZED;
1354 *lpdwRegister = 0;
1357 * First, check if the class is already registered.
1358 * If it is, this should cause an error.
1360 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1361 if (hr == S_OK) {
1362 if (flags & REGCLS_MULTIPLEUSE) {
1363 if (dwClsContext & CLSCTX_LOCAL_SERVER)
1364 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
1365 IUnknown_Release(foundObject);
1366 return hr;
1368 IUnknown_Release(foundObject);
1369 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
1370 return CO_E_OBJISREG;
1373 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1374 if ( newClass == NULL )
1375 return E_OUTOFMEMORY;
1377 EnterCriticalSection( &csRegisteredClassList );
1379 newClass->classIdentifier = *rclsid;
1380 newClass->runContext = dwClsContext;
1381 newClass->connectFlags = flags;
1382 newClass->pMarshaledData = NULL;
1385 * Use the address of the chain node as the cookie since we are sure it's
1386 * unique. FIXME: not on 64-bit platforms.
1388 newClass->dwCookie = (DWORD)newClass;
1389 newClass->nextClass = firstRegisteredClass;
1392 * Since we're making a copy of the object pointer, we have to increase its
1393 * reference count.
1395 newClass->classObject = pUnk;
1396 IUnknown_AddRef(newClass->classObject);
1398 firstRegisteredClass = newClass;
1399 LeaveCriticalSection( &csRegisteredClassList );
1401 *lpdwRegister = newClass->dwCookie;
1403 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1404 IClassFactory *classfac;
1406 hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory,
1407 (LPVOID*)&classfac);
1408 if (hr) return hr;
1410 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
1411 if (hr) {
1412 FIXME("Failed to create stream on hglobal, %lx\n", hr);
1413 IUnknown_Release(classfac);
1414 return hr;
1416 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
1417 (LPVOID)classfac, MSHCTX_LOCAL, NULL,
1418 MSHLFLAGS_TABLESTRONG);
1419 if (hr) {
1420 FIXME("CoMarshalInterface failed, %lx!\n",hr);
1421 IUnknown_Release(classfac);
1422 return hr;
1425 IUnknown_Release(classfac);
1427 RPC_StartLocalServer(&newClass->classIdentifier, newClass->pMarshaledData);
1429 return S_OK;
1432 /***********************************************************************
1433 * CoRevokeClassObject [OLE32.@]
1435 * Removes a class object from the class registry.
1437 * PARAMS
1438 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1440 * RETURNS
1441 * Success: S_OK.
1442 * Failure: HRESULT code.
1444 * SEE ALSO
1445 * CoRegisterClassObject
1447 HRESULT WINAPI CoRevokeClassObject(
1448 DWORD dwRegister)
1450 HRESULT hr = E_INVALIDARG;
1451 RegisteredClass** prevClassLink;
1452 RegisteredClass* curClass;
1454 TRACE("(%08lx)\n",dwRegister);
1456 EnterCriticalSection( &csRegisteredClassList );
1459 * Iterate through the whole list and try to match the cookie.
1461 curClass = firstRegisteredClass;
1462 prevClassLink = &firstRegisteredClass;
1464 while (curClass != 0)
1467 * Check if we have a match on the cookie.
1469 if (curClass->dwCookie == dwRegister)
1472 * Remove the class from the chain.
1474 *prevClassLink = curClass->nextClass;
1477 * Release the reference to the class object.
1479 IUnknown_Release(curClass->classObject);
1481 if (curClass->pMarshaledData)
1483 LARGE_INTEGER zero;
1484 memset(&zero, 0, sizeof(zero));
1485 /* FIXME: stop local server thread */
1486 IStream_Seek(curClass->pMarshaledData, zero, SEEK_SET, NULL);
1487 CoReleaseMarshalData(curClass->pMarshaledData);
1491 * Free the memory used by the chain node.
1493 HeapFree(GetProcessHeap(), 0, curClass);
1495 hr = S_OK;
1496 goto end;
1500 * Step to the next class in the list.
1502 prevClassLink = &(curClass->nextClass);
1503 curClass = curClass->nextClass;
1506 end:
1507 LeaveCriticalSection( &csRegisteredClassList );
1509 * If we get to here, we haven't found our class.
1511 return hr;
1514 /***********************************************************************
1515 * COM_RegReadPath [internal]
1517 * Reads a registry value and expands it when necessary
1519 HRESULT COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
1521 HRESULT hres;
1522 HKEY key;
1523 DWORD keytype;
1524 WCHAR src[MAX_PATH];
1525 DWORD dwLength = dstlen * sizeof(WCHAR);
1527 if((hres = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1528 if( (hres = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1529 if (keytype == REG_EXPAND_SZ) {
1530 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) hres = ERROR_MORE_DATA;
1531 } else {
1532 lstrcpynW(dst, src, dstlen);
1535 RegCloseKey (key);
1537 return hres;
1540 static HRESULT get_inproc_class_object(HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
1542 HINSTANCE hLibrary;
1543 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1544 DllGetClassObjectFunc DllGetClassObject;
1545 WCHAR dllpath[MAX_PATH+1];
1547 if (COM_RegReadPath(hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
1549 /* failure: CLSID is not found in registry */
1550 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
1551 return REGDB_E_CLASSNOTREG;
1554 if ((hLibrary = LoadLibraryExW(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0)
1556 /* failure: DLL could not be loaded */
1557 ERR("couldn't load InprocServer32 dll %s\n", debugstr_w(dllpath));
1558 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1561 if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject")))
1563 /* failure: the dll did not export DllGetClassObject */
1564 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(dllpath));
1565 FreeLibrary( hLibrary );
1566 return CO_E_DLLNOTFOUND;
1569 /* OK: get the ClassObject */
1570 COMPOBJ_DLLList_Add( hLibrary );
1571 return DllGetClassObject(rclsid, riid, ppv);
1574 /***********************************************************************
1575 * CoGetClassObject [OLE32.@]
1577 * FIXME. If request allows of several options and there is a failure
1578 * with one (other than not being registered) do we try the
1579 * others or return failure? (E.g. inprocess is registered but
1580 * the DLL is not found but the server version works)
1582 HRESULT WINAPI CoGetClassObject(
1583 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1584 REFIID iid, LPVOID *ppv)
1586 LPUNKNOWN regClassObject;
1587 HRESULT hres = E_UNEXPECTED;
1589 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1591 if (pServerInfo) {
1592 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1593 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1597 * First, try and see if we can't match the class ID with one of the
1598 * registered classes.
1600 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, &regClassObject))
1602 /* Get the required interface from the retrieved pointer. */
1603 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1606 * Since QI got another reference on the pointer, we want to release the
1607 * one we already have. If QI was unsuccessful, this will release the object. This
1608 * is good since we are not returning it in the "out" parameter.
1610 IUnknown_Release(regClassObject);
1612 return hres;
1615 /* first try: in-process */
1616 if ((CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER) & dwClsContext)
1618 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
1619 HKEY hkey;
1621 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
1622 if (FAILED(hres))
1624 if (hres == REGDB_E_CLASSNOTREG)
1625 ERR("class %s not registered\n", debugstr_guid(rclsid));
1626 else
1627 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
1630 if (SUCCEEDED(hres))
1632 hres = get_inproc_class_object(hkey, rclsid, iid, ppv);
1633 RegCloseKey(hkey);
1636 /* return if we got a class, otherwise fall through to one of the
1637 * other types */
1638 if (SUCCEEDED(hres))
1639 return hres;
1642 /* Next try out of process */
1643 if (CLSCTX_LOCAL_SERVER & dwClsContext)
1645 return RPC_GetLocalClassObject(rclsid,iid,ppv);
1648 /* Finally try remote: this requires networked DCOM (a lot of work) */
1649 if (CLSCTX_REMOTE_SERVER & dwClsContext)
1651 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1652 hres = E_NOINTERFACE;
1655 return hres;
1658 /***********************************************************************
1659 * CoResumeClassObjects (OLE32.@)
1661 * Resumes all class objects registered with REGCLS_SUSPENDED.
1663 * RETURNS
1664 * Success: S_OK.
1665 * Failure: HRESULT code.
1667 HRESULT WINAPI CoResumeClassObjects(void)
1669 FIXME("stub\n");
1670 return S_OK;
1673 /***********************************************************************
1674 * GetClassFile (OLE32.@)
1676 * This function supplies the CLSID associated with the given filename.
1678 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1680 IStorage *pstg=0;
1681 HRESULT res;
1682 int nbElm, length, i;
1683 LONG sizeProgId;
1684 LPOLESTR *pathDec=0,absFile=0,progId=0;
1685 LPWSTR extension;
1686 static const WCHAR bkslashW[] = {'\\',0};
1687 static const WCHAR dotW[] = {'.',0};
1689 TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1691 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1692 if((StgIsStorageFile(filePathName))==S_OK){
1694 res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1696 if (SUCCEEDED(res))
1697 res=ReadClassStg(pstg,pclsid);
1699 IStorage_Release(pstg);
1701 return res;
1703 /* if the file is not a storage object then attemps to match various bits in the file against a
1704 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1705 this case
1707 for(i=0;i<nFileTypes;i++)
1709 for(i=0;j<nPatternsForType;j++){
1711 PATTERN pat;
1712 HANDLE hFile;
1714 pat=ReadPatternFromRegistry(i,j);
1715 hFile=CreateFileW(filePathName,,,,,,hFile);
1716 SetFilePosition(hFile,pat.offset);
1717 ReadFile(hFile,buf,pat.size,&r,NULL);
1718 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1720 *pclsid=ReadCLSIDFromRegistry(i);
1721 return S_OK;
1726 /* if the above strategies fail then search for the extension key in the registry */
1728 /* get the last element (absolute file) in the path name */
1729 nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1730 absFile=pathDec[nbElm-1];
1732 /* failed if the path represente a directory and not an absolute file name*/
1733 if (!lstrcmpW(absFile, bkslashW))
1734 return MK_E_INVALIDEXTENSION;
1736 /* get the extension of the file */
1737 extension = NULL;
1738 length=lstrlenW(absFile);
1739 for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1740 /* nothing */;
1742 if (!extension || !lstrcmpW(extension, dotW))
1743 return MK_E_INVALIDEXTENSION;
1745 res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1747 /* get the progId associated to the extension */
1748 progId = CoTaskMemAlloc(sizeProgId);
1749 res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1751 if (res==ERROR_SUCCESS)
1752 /* return the clsid associated to the progId */
1753 res= CLSIDFromProgID(progId,pclsid);
1755 for(i=0; pathDec[i]!=NULL;i++)
1756 CoTaskMemFree(pathDec[i]);
1757 CoTaskMemFree(pathDec);
1759 CoTaskMemFree(progId);
1761 if (res==ERROR_SUCCESS)
1762 return res;
1764 return MK_E_INVALIDEXTENSION;
1767 /***********************************************************************
1768 * CoCreateInstance [OLE32.@]
1770 HRESULT WINAPI CoCreateInstance(
1771 REFCLSID rclsid,
1772 LPUNKNOWN pUnkOuter,
1773 DWORD dwClsContext,
1774 REFIID iid,
1775 LPVOID *ppv)
1777 HRESULT hres;
1778 LPCLASSFACTORY lpclf = 0;
1780 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08lx, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
1781 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
1783 if (!COM_CurrentApt()) return CO_E_NOTINITIALIZED;
1786 * Sanity check
1788 if (ppv==0)
1789 return E_POINTER;
1792 * Initialize the "out" parameter
1794 *ppv = 0;
1797 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1798 * Rather than create a class factory, we can just check for it here
1800 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
1801 if (StdGlobalInterfaceTableInstance == NULL)
1802 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
1803 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
1804 if (hres) return hres;
1806 TRACE("Retrieved GIT (%p)\n", *ppv);
1807 return S_OK;
1811 * Get a class factory to construct the object we want.
1813 hres = CoGetClassObject(rclsid,
1814 dwClsContext,
1815 NULL,
1816 &IID_IClassFactory,
1817 (LPVOID)&lpclf);
1819 if (FAILED(hres)) {
1820 FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n",
1821 debugstr_guid(rclsid),hres);
1822 return hres;
1826 * Create the object and don't forget to release the factory
1828 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
1829 IClassFactory_Release(lpclf);
1830 if(FAILED(hres))
1831 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1832 debugstr_guid(iid), debugstr_guid(rclsid),hres);
1834 return hres;
1837 /***********************************************************************
1838 * CoCreateInstanceEx [OLE32.@]
1840 HRESULT WINAPI CoCreateInstanceEx(
1841 REFCLSID rclsid,
1842 LPUNKNOWN pUnkOuter,
1843 DWORD dwClsContext,
1844 COSERVERINFO* pServerInfo,
1845 ULONG cmq,
1846 MULTI_QI* pResults)
1848 IUnknown* pUnk = NULL;
1849 HRESULT hr;
1850 ULONG index;
1851 ULONG successCount = 0;
1854 * Sanity check
1856 if ( (cmq==0) || (pResults==NULL))
1857 return E_INVALIDARG;
1859 if (pServerInfo!=NULL)
1860 FIXME("() non-NULL pServerInfo not supported!\n");
1863 * Initialize all the "out" parameters.
1865 for (index = 0; index < cmq; index++)
1867 pResults[index].pItf = NULL;
1868 pResults[index].hr = E_NOINTERFACE;
1872 * Get the object and get its IUnknown pointer.
1874 hr = CoCreateInstance(rclsid,
1875 pUnkOuter,
1876 dwClsContext,
1877 &IID_IUnknown,
1878 (VOID**)&pUnk);
1880 if (hr)
1881 return hr;
1884 * Then, query for all the interfaces requested.
1886 for (index = 0; index < cmq; index++)
1888 pResults[index].hr = IUnknown_QueryInterface(pUnk,
1889 pResults[index].pIID,
1890 (VOID**)&(pResults[index].pItf));
1892 if (pResults[index].hr == S_OK)
1893 successCount++;
1897 * Release our temporary unknown pointer.
1899 IUnknown_Release(pUnk);
1901 if (successCount == 0)
1902 return E_NOINTERFACE;
1904 if (successCount!=cmq)
1905 return CO_S_NOTALLINTERFACES;
1907 return S_OK;
1910 /***********************************************************************
1911 * CoLoadLibrary (OLE32.@)
1913 * Loads a library.
1915 * PARAMS
1916 * lpszLibName [I] Path to library.
1917 * bAutoFree [I] Whether the library should automatically be freed.
1919 * RETURNS
1920 * Success: Handle to loaded library.
1921 * Failure: NULL.
1923 * SEE ALSO
1924 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1926 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
1928 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
1930 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
1933 /***********************************************************************
1934 * CoFreeLibrary [OLE32.@]
1936 * Unloads a library from memory.
1938 * PARAMS
1939 * hLibrary [I] Handle to library to unload.
1941 * RETURNS
1942 * Nothing
1944 * SEE ALSO
1945 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1947 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
1949 FreeLibrary(hLibrary);
1953 /***********************************************************************
1954 * CoFreeAllLibraries [OLE32.@]
1956 * Function for backwards compatibility only. Does nothing.
1958 * RETURNS
1959 * Nothing.
1961 * SEE ALSO
1962 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
1964 void WINAPI CoFreeAllLibraries(void)
1966 /* NOP */
1970 /***********************************************************************
1971 * CoFreeUnusedLibraries [OLE32.@]
1972 * CoFreeUnusedLibraries [COMPOBJ.17]
1974 * Frees any unused libraries. Unused are identified as those that return
1975 * S_OK from their DllCanUnloadNow function.
1977 * RETURNS
1978 * Nothing.
1980 * SEE ALSO
1981 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
1983 void WINAPI CoFreeUnusedLibraries(void)
1985 /* FIXME: Calls to CoFreeUnusedLibraries from any thread always route
1986 * through the main apartment's thread to call DllCanUnloadNow */
1987 COMPOBJ_DllList_FreeUnused(0);
1990 /***********************************************************************
1991 * CoFileTimeNow [OLE32.@]
1992 * CoFileTimeNow [COMPOBJ.82]
1994 * Retrieves the current time in FILETIME format.
1996 * PARAMS
1997 * lpFileTime [O] The current time.
1999 * RETURNS
2000 * S_OK.
2002 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
2004 GetSystemTimeAsFileTime( lpFileTime );
2005 return S_OK;
2008 static void COM_RevokeAllClasses()
2010 EnterCriticalSection( &csRegisteredClassList );
2012 while (firstRegisteredClass!=0)
2014 CoRevokeClassObject(firstRegisteredClass->dwCookie);
2017 LeaveCriticalSection( &csRegisteredClassList );
2020 /******************************************************************************
2021 * CoLockObjectExternal [OLE32.@]
2023 * Increments or decrements the external reference count of a stub object.
2025 * PARAMS
2026 * pUnk [I] Stub object.
2027 * fLock [I] If TRUE then increments the external ref-count,
2028 * otherwise decrements.
2029 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2030 * calling CoDisconnectObject.
2032 * RETURNS
2033 * Success: S_OK.
2034 * Failure: HRESULT code.
2036 HRESULT WINAPI CoLockObjectExternal(
2037 LPUNKNOWN pUnk,
2038 BOOL fLock,
2039 BOOL fLastUnlockReleases)
2041 struct stub_manager *stubmgr;
2042 struct apartment *apt;
2044 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2045 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2047 apt = COM_CurrentApt();
2048 if (!apt) return CO_E_NOTINITIALIZED;
2050 stubmgr = get_stub_manager_from_object(apt, pUnk);
2052 if (stubmgr)
2054 if (fLock)
2055 stub_manager_ext_addref(stubmgr, 1);
2056 else
2057 stub_manager_ext_release(stubmgr, 1);
2059 stub_manager_int_release(stubmgr);
2061 return S_OK;
2063 else
2065 WARN("stub object not found %p\n", pUnk);
2066 /* Note: native is pretty broken here because it just silently
2067 * fails, without returning an appropriate error code, making apps
2068 * think that the object was disconnected, when it actually wasn't */
2069 return S_OK;
2073 /***********************************************************************
2074 * CoInitializeWOW (OLE32.@)
2076 * WOW equivalent of CoInitialize?
2078 * PARAMS
2079 * x [I] Unknown.
2080 * y [I] Unknown.
2082 * RETURNS
2083 * Unknown.
2085 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2087 FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
2088 return 0;
2091 /***********************************************************************
2092 * CoGetState [OLE32.@]
2094 * Retrieves the thread state object previously stored by CoSetState().
2096 * PARAMS
2097 * ppv [I] Address where pointer to object will be stored.
2099 * RETURNS
2100 * Success: S_OK.
2101 * Failure: E_OUTOFMEMORY.
2103 * NOTES
2104 * Crashes on all invalid ppv addresses, including NULL.
2105 * If the function returns a non-NULL object then the caller must release its
2106 * reference on the object when the object is no longer required.
2108 * SEE ALSO
2109 * CoSetState().
2111 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2113 struct oletls *info = COM_CurrentInfo();
2114 if (!info) return E_OUTOFMEMORY;
2116 *ppv = NULL;
2118 if (info->state)
2120 IUnknown_AddRef(info->state);
2121 *ppv = info->state;
2122 TRACE("apt->state=%p\n", info->state);
2125 return S_OK;
2128 /***********************************************************************
2129 * CoSetState [OLE32.@]
2131 * Sets the thread state object.
2133 * PARAMS
2134 * pv [I] Pointer to state object to be stored.
2136 * NOTES
2137 * The system keeps a reference on the object while the object stored.
2139 * RETURNS
2140 * Success: S_OK.
2141 * Failure: E_OUTOFMEMORY.
2143 HRESULT WINAPI CoSetState(IUnknown * pv)
2145 struct oletls *info = COM_CurrentInfo();
2146 if (!info) return E_OUTOFMEMORY;
2148 if (pv) IUnknown_AddRef(pv);
2150 if (info->state)
2152 TRACE("-- release %p now\n", info->state);
2153 IUnknown_Release(info->state);
2156 info->state = pv;
2158 return S_OK;
2162 /******************************************************************************
2163 * OleGetAutoConvert [OLE32.@]
2165 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2167 static const WCHAR wszAutoConvertTo[] = {'A','u','t','o','C','o','n','v','e','r','t','T','o',0};
2168 HKEY hkey = NULL;
2169 WCHAR buf[CHARS_IN_GUID];
2170 LONG len;
2171 HRESULT res = S_OK;
2173 res = COM_OpenKeyForCLSID(clsidOld, wszAutoConvertTo, KEY_READ, &hkey);
2174 if (FAILED(res))
2175 goto done;
2177 len = sizeof(buf);
2178 if (RegQueryValueW(hkey, NULL, buf, &len))
2180 res = REGDB_E_KEYMISSING;
2181 goto done;
2183 res = CLSIDFromString(buf, pClsidNew);
2184 done:
2185 if (hkey) RegCloseKey(hkey);
2186 return res;
2189 /******************************************************************************
2190 * CoTreatAsClass [OLE32.@]
2192 * Sets the TreatAs value of a class.
2194 * PARAMS
2195 * clsidOld [I] Class to set TreatAs value on.
2196 * clsidNew [I] The class the clsidOld should be treated as.
2198 * RETURNS
2199 * Success: S_OK.
2200 * Failure: HRESULT code.
2202 * SEE ALSO
2203 * CoGetTreatAsClass
2205 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2207 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
2208 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2209 HKEY hkey = NULL;
2210 WCHAR szClsidNew[CHARS_IN_GUID];
2211 HRESULT res = S_OK;
2212 WCHAR auto_treat_as[CHARS_IN_GUID];
2213 LONG auto_treat_as_size = sizeof(auto_treat_as);
2214 CLSID id;
2216 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
2217 if (FAILED(res))
2218 goto done;
2219 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2221 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
2222 !CLSIDFromString(auto_treat_as, &id))
2224 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
2226 res = REGDB_E_WRITEREGDB;
2227 goto done;
2230 else
2232 RegDeleteKeyW(hkey, wszTreatAs);
2233 goto done;
2236 else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
2237 !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
2239 res = REGDB_E_WRITEREGDB;
2240 goto done;
2243 done:
2244 if (hkey) RegCloseKey(hkey);
2245 return res;
2248 /******************************************************************************
2249 * CoGetTreatAsClass [OLE32.@]
2251 * Gets the TreatAs value of a class.
2253 * PARAMS
2254 * clsidOld [I] Class to get the TreatAs value of.
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 * CoSetTreatAsClass
2264 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2266 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2267 HKEY hkey = NULL;
2268 WCHAR szClsidNew[CHARS_IN_GUID];
2269 HRESULT res = S_OK;
2270 LONG len = sizeof(szClsidNew);
2272 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2273 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2275 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
2276 if (FAILED(res))
2277 goto done;
2278 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
2280 res = S_FALSE;
2281 goto done;
2283 res = CLSIDFromString(szClsidNew,clsidNew);
2284 if (FAILED(res))
2285 ERR("Failed CLSIDFromStringA(%s), hres 0x%08lx\n", debugstr_w(szClsidNew), res);
2286 done:
2287 if (hkey) RegCloseKey(hkey);
2288 return res;
2291 /******************************************************************************
2292 * CoGetCurrentProcess [OLE32.@]
2293 * CoGetCurrentProcess [COMPOBJ.34]
2295 * Gets the current process ID.
2297 * RETURNS
2298 * The current process ID.
2300 * NOTES
2301 * Is DWORD really the correct return type for this function?
2303 DWORD WINAPI CoGetCurrentProcess(void)
2305 return GetCurrentProcessId();
2308 /******************************************************************************
2309 * CoRegisterMessageFilter [OLE32.@]
2311 * Registers a message filter.
2313 * PARAMS
2314 * lpMessageFilter [I] Pointer to interface.
2315 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2317 * RETURNS
2318 * Success: S_OK.
2319 * Failure: HRESULT code.
2321 HRESULT WINAPI CoRegisterMessageFilter(
2322 LPMESSAGEFILTER lpMessageFilter,
2323 LPMESSAGEFILTER *lplpMessageFilter)
2325 FIXME("stub\n");
2326 if (lplpMessageFilter) {
2327 *lplpMessageFilter = NULL;
2329 return S_OK;
2332 /***********************************************************************
2333 * CoIsOle1Class [OLE32.@]
2335 * Determines whether the specified class an OLE v1 class.
2337 * PARAMS
2338 * clsid [I] Class to test.
2340 * RETURNS
2341 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
2343 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
2345 FIXME("%s\n", debugstr_guid(clsid));
2346 return FALSE;
2349 /***********************************************************************
2350 * IsEqualGUID [OLE32.@]
2352 * Compares two Unique Identifiers.
2354 * PARAMS
2355 * rguid1 [I] The first GUID to compare.
2356 * rguid2 [I] The other GUID to compare.
2358 * RETURNS
2359 * TRUE if equal
2361 #undef IsEqualGUID
2362 BOOL WINAPI IsEqualGUID(
2363 REFGUID rguid1,
2364 REFGUID rguid2)
2366 return !memcmp(rguid1,rguid2,sizeof(GUID));
2369 /***********************************************************************
2370 * CoInitializeSecurity [OLE32.@]
2372 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2373 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2374 void* pReserved1, DWORD dwAuthnLevel,
2375 DWORD dwImpLevel, void* pReserved2,
2376 DWORD dwCapabilities, void* pReserved3)
2378 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
2379 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2380 dwCapabilities, pReserved3);
2381 return S_OK;
2384 /***********************************************************************
2385 * CoSuspendClassObjects [OLE32.@]
2387 * Suspends all registered class objects to prevent further requests coming in
2388 * for those objects.
2390 * RETURNS
2391 * Success: S_OK.
2392 * Failure: HRESULT code.
2394 HRESULT WINAPI CoSuspendClassObjects(void)
2396 FIXME("\n");
2397 return S_OK;
2400 /***********************************************************************
2401 * CoAddRefServerProcess [OLE32.@]
2403 * Helper function for incrementing the reference count of a local-server
2404 * process.
2406 * RETURNS
2407 * New reference count.
2409 ULONG WINAPI CoAddRefServerProcess(void)
2411 FIXME("\n");
2412 return 2;
2415 /***********************************************************************
2416 * CoReleaseServerProcess [OLE32.@]
2418 * Helper function for decrementing the reference count of a local-server
2419 * process.
2421 * RETURNS
2422 * New reference count.
2424 ULONG WINAPI CoReleaseServerProcess(void)
2426 FIXME("\n");
2427 return 1;
2430 /***********************************************************************
2431 * CoIsHandlerConnected [OLE32.@]
2433 * Determines whether a proxy is connected to a remote stub.
2435 * PARAMS
2436 * pUnk [I] Pointer to object that may or may not be connected.
2438 * RETURNS
2439 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
2440 * FALSE otherwise.
2442 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
2444 FIXME("%p\n", pUnk);
2446 return TRUE;
2449 /***********************************************************************
2450 * CoAllowSetForegroundWindow [OLE32.@]
2453 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
2455 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
2456 return S_OK;
2459 /***********************************************************************
2460 * CoQueryProxyBlanket [OLE32.@]
2462 * Retrieves the security settings being used by a proxy.
2464 * PARAMS
2465 * pProxy [I] Pointer to the proxy object.
2466 * pAuthnSvc [O] The type of authentication service.
2467 * pAuthzSvc [O] The type of authorization service.
2468 * ppServerPrincName [O] Optional. The server prinicple name.
2469 * pAuthnLevel [O] The authentication level.
2470 * pImpLevel [O] The impersonation level.
2471 * ppAuthInfo [O] Information specific to the authorization/authentication service.
2472 * pCapabilities [O] Flags affecting the security behaviour.
2474 * RETURNS
2475 * Success: S_OK.
2476 * Failure: HRESULT code.
2478 * SEE ALSO
2479 * CoCopyProxy, CoSetProxyBlanket.
2481 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
2482 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
2483 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
2485 IClientSecurity *pCliSec;
2486 HRESULT hr;
2488 TRACE("%p\n", pProxy);
2490 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2491 if (SUCCEEDED(hr))
2493 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
2494 pAuthzSvc, ppServerPrincName,
2495 pAuthnLevel, pImpLevel, ppAuthInfo,
2496 pCapabilities);
2497 IClientSecurity_Release(pCliSec);
2500 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2501 return hr;
2504 /***********************************************************************
2505 * CoSetProxyBlanket [OLE32.@]
2507 * Sets the security settings for a proxy.
2509 * PARAMS
2510 * pProxy [I] Pointer to the proxy object.
2511 * AuthnSvc [I] The type of authentication service.
2512 * AuthzSvc [I] The type of authorization service.
2513 * pServerPrincName [I] The server prinicple name.
2514 * AuthnLevel [I] The authentication level.
2515 * ImpLevel [I] The impersonation level.
2516 * pAuthInfo [I] Information specific to the authorization/authentication service.
2517 * Capabilities [I] Flags affecting the security behaviour.
2519 * RETURNS
2520 * Success: S_OK.
2521 * Failure: HRESULT code.
2523 * SEE ALSO
2524 * CoQueryProxyBlanket, CoCopyProxy.
2526 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
2527 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
2528 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
2530 IClientSecurity *pCliSec;
2531 HRESULT hr;
2533 TRACE("%p\n", pProxy);
2535 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2536 if (SUCCEEDED(hr))
2538 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
2539 AuthzSvc, pServerPrincName,
2540 AuthnLevel, ImpLevel, pAuthInfo,
2541 Capabilities);
2542 IClientSecurity_Release(pCliSec);
2545 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2546 return hr;
2549 /***********************************************************************
2550 * CoCopyProxy [OLE32.@]
2552 * Copies a proxy.
2554 * PARAMS
2555 * pProxy [I] Pointer to the proxy object.
2556 * ppCopy [O] Copy of the proxy.
2558 * RETURNS
2559 * Success: S_OK.
2560 * Failure: HRESULT code.
2562 * SEE ALSO
2563 * CoQueryProxyBlanket, CoSetProxyBlanket.
2565 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
2567 IClientSecurity *pCliSec;
2568 HRESULT hr;
2570 TRACE("%p\n", pProxy);
2572 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2573 if (SUCCEEDED(hr))
2575 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
2576 IClientSecurity_Release(pCliSec);
2579 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2580 return hr;
2584 /***********************************************************************
2585 * CoWaitForMultipleHandles [OLE32.@]
2587 * Waits for one or more handles to become signaled.
2589 * PARAMS
2590 * dwFlags [I] Flags. See notes.
2591 * dwTimeout [I] Timeout in milliseconds.
2592 * cHandles [I] Number of handles pointed to by pHandles.
2593 * pHandles [I] Handles to wait for.
2594 * lpdwindex [O] Index of handle that was signaled.
2596 * RETURNS
2597 * Success: S_OK.
2598 * Failure: RPC_S_CALLPENDING on timeout.
2600 * NOTES
2602 * The dwFlags parameter can be zero or more of the following:
2603 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
2604 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
2606 * SEE ALSO
2607 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
2609 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
2610 ULONG cHandles, const HANDLE* pHandles, LPDWORD lpdwindex)
2612 HRESULT hr = S_OK;
2613 DWORD wait_flags = (dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0 |
2614 (dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0;
2615 DWORD start_time = GetTickCount();
2617 TRACE("(0x%08lx, 0x%08lx, %ld, %p, %p)\n", dwFlags, dwTimeout, cHandles,
2618 pHandles, lpdwindex);
2620 while (TRUE)
2622 DWORD now = GetTickCount();
2623 DWORD res;
2625 if ((dwTimeout != INFINITE) && (start_time + dwTimeout >= now))
2627 hr = RPC_S_CALLPENDING;
2628 break;
2631 TRACE("waiting for rpc completion or window message\n");
2633 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
2634 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
2635 QS_ALLINPUT, wait_flags);
2637 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
2639 MSG msg;
2640 while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
2642 /* FIXME: filter the messages here */
2643 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
2644 TranslateMessage(&msg);
2645 DispatchMessageW(&msg);
2646 if (msg.message == WM_QUIT)
2648 TRACE("resending WM_QUIT to outer message loop\n");
2649 PostQuitMessage(msg.wParam);
2650 goto done;
2654 else if ((res >= WAIT_OBJECT_0) && (res < WAIT_OBJECT_0 + cHandles))
2656 /* handle signaled, store index */
2657 *lpdwindex = (res - WAIT_OBJECT_0);
2658 break;
2660 else if (res == WAIT_TIMEOUT)
2662 hr = RPC_S_CALLPENDING;
2663 break;
2665 else
2667 ERR("Unexpected wait termination: %ld, %ld\n", res, GetLastError());
2668 hr = E_UNEXPECTED;
2669 break;
2672 done:
2673 TRACE("-- 0x%08lx\n", hr);
2674 return hr;
2677 /***********************************************************************
2678 * DllMain (OLE32.@)
2680 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
2682 TRACE("%p 0x%lx %p\n", hinstDLL, fdwReason, fImpLoad);
2684 switch(fdwReason) {
2685 case DLL_PROCESS_ATTACH:
2686 OLE32_hInstance = hinstDLL;
2687 COMPOBJ_InitProcess();
2688 if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1);
2689 break;
2691 case DLL_PROCESS_DETACH:
2692 if (TRACE_ON(ole)) CoRevokeMallocSpy();
2693 COMPOBJ_UninitProcess();
2694 OLE32_hInstance = 0;
2695 break;
2697 case DLL_THREAD_DETACH:
2698 COM_TlsDestroy();
2699 break;
2701 return TRUE;
2704 /* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */