Correct and complete some api documentation.
[wine/multimedia.git] / dlls / ole32 / compobj.c
blob300e13ef5c60e2761debe71c72857a01cb1c3176
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 "winuser.h"
60 #include "objbase.h"
61 #include "ole2.h"
62 #include "ole2ver.h"
63 #include "rpc.h"
64 #include "winerror.h"
65 #include "winreg.h"
66 #include "wownt32.h"
67 #include "wine/unicode.h"
68 #include "objbase.h"
69 #include "ole32_main.h"
70 #include "compobj_private.h"
72 #include "wine/debug.h"
74 WINE_DEFAULT_DEBUG_CHANNEL(ole);
76 typedef LPCSTR LPCOLESTR16;
78 /****************************************************************************
79 * This section defines variables internal to the COM module.
81 * TODO: Most of these things will have to be made thread-safe.
84 static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk);
85 static void COM_RevokeAllClasses(void);
87 const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
89 APARTMENT *MTA; /* protected by csApartment */
90 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
92 static CRITICAL_SECTION csApartment;
93 static CRITICAL_SECTION_DEBUG critsect_debug =
95 0, 0, &csApartment,
96 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
97 0, 0, { 0, (DWORD)(__FILE__ ": csApartment") }
99 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
102 * This lock count counts the number of times CoInitialize is called. It is
103 * decreased every time CoUninitialize is called. When it hits 0, the COM
104 * libraries are freed
106 static LONG s_COMLockCount = 0;
109 * This linked list contains the list of registered class objects. These
110 * are mostly used to register the factories for out-of-proc servers of OLE
111 * objects.
113 * TODO: Make this data structure aware of inter-process communication. This
114 * means that parts of this will be exported to the Wine Server.
116 typedef struct tagRegisteredClass
118 CLSID classIdentifier;
119 LPUNKNOWN classObject;
120 DWORD runContext;
121 DWORD connectFlags;
122 DWORD dwCookie;
123 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
124 struct tagRegisteredClass* nextClass;
125 } RegisteredClass;
127 static RegisteredClass* firstRegisteredClass = NULL;
129 static CRITICAL_SECTION csRegisteredClassList;
130 static CRITICAL_SECTION_DEBUG class_cs_debug =
132 0, 0, &csRegisteredClassList,
133 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
134 0, 0, { 0, (DWORD)(__FILE__ ": csRegisteredClassList") }
136 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
138 /*****************************************************************************
139 * This section contains OpenDllList definitions
141 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
142 * other functions that do LoadLibrary _without_ giving back a HMODULE.
143 * Without this list these handles would never be freed.
145 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
146 * next unload-call but not before 600 sec.
149 typedef struct tagOpenDll {
150 HINSTANCE hLibrary;
151 struct tagOpenDll *next;
152 } OpenDll;
154 static OpenDll *openDllList = NULL; /* linked list of open dlls */
156 static CRITICAL_SECTION csOpenDllList;
157 static CRITICAL_SECTION_DEBUG dll_cs_debug =
159 0, 0, &csOpenDllList,
160 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
161 0, 0, { 0, (DWORD)(__FILE__ ": csOpenDllList") }
163 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
165 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',' ',
166 '0','x','#','#','#','#','#','#','#','#',' ',0};
167 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
169 static void COMPOBJ_DLLList_Add(HANDLE hLibrary);
170 static void COMPOBJ_DllList_FreeUnused(int Timeout);
172 void COMPOBJ_InitProcess( void )
174 WNDCLASSW wclass;
176 /* Dispatching to the correct thread in an apartment is done through
177 * window messages rather than RPC transports. When an interface is
178 * marshalled into another apartment in the same process, a window of the
179 * following class is created. The *caller* of CoMarshalInterface (ie the
180 * application) is responsible for pumping the message loop in that thread.
181 * The WM_USER messages which point to the RPCs are then dispatched to
182 * COM_AptWndProc by the user's code from the apartment in which the interface
183 * was unmarshalled.
185 memset(&wclass, 0, sizeof(wclass));
186 wclass.lpfnWndProc = apartment_wndproc;
187 wclass.hInstance = OLE32_hInstance;
188 wclass.lpszClassName = wszAptWinClass;
189 RegisterClassW(&wclass);
192 void COMPOBJ_UninitProcess( void )
194 UnregisterClassW(wszAptWinClass, OLE32_hInstance);
197 void COM_TlsDestroy()
199 struct oletls *info = NtCurrentTeb()->ReservedForOle;
200 if (info)
202 if (info->apt) apartment_release(info->apt);
203 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
204 if (info->state) IUnknown_Release(info->state);
205 HeapFree(GetProcessHeap(), 0, info);
206 NtCurrentTeb()->ReservedForOle = NULL;
210 /******************************************************************************
211 * Manage apartments.
214 /* allocates memory and fills in the necessary fields for a new apartment
215 * object */
216 static APARTMENT *apartment_construct(DWORD model)
218 APARTMENT *apt;
220 TRACE("creating new apartment, model=%ld\n", model);
222 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
223 apt->tid = GetCurrentThreadId();
224 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
225 GetCurrentProcess(), &apt->thread,
226 THREAD_ALL_ACCESS, FALSE, 0);
228 list_init(&apt->proxies);
229 list_init(&apt->stubmgrs);
230 apt->ipidc = 0;
231 apt->refs = 1;
232 apt->remunk_exported = FALSE;
233 apt->oidc = 1;
234 InitializeCriticalSection(&apt->cs);
235 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
237 apt->model = model;
239 if (model & COINIT_APARTMENTTHREADED)
241 /* FIXME: should be randomly generated by in an RPC call to rpcss */
242 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
243 apt->win = CreateWindowW(wszAptWinClass, NULL, 0,
244 0, 0, 0, 0,
245 0, 0, OLE32_hInstance, NULL);
247 else
249 /* FIXME: should be randomly generated by in an RPC call to rpcss */
250 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
253 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
255 /* the locking here is not currently needed for the MTA case, but it
256 * doesn't hurt and makes the code simpler */
257 EnterCriticalSection(&csApartment);
258 list_add_head(&apts, &apt->entry);
259 LeaveCriticalSection(&csApartment);
261 return apt;
264 /* gets and existing apartment if one exists or otherwise creates an apartment
265 * structure which stores OLE apartment-local information and stores a pointer
266 * to it in the thread-local storage */
267 static APARTMENT *apartment_get_or_create(DWORD model)
269 APARTMENT *apt = COM_CurrentApt();
271 if (!apt)
273 if (model & COINIT_APARTMENTTHREADED)
275 apt = apartment_construct(model);
276 COM_CurrentInfo()->apt = apt;
278 else
280 EnterCriticalSection(&csApartment);
282 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
283 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
284 * in a process */
285 if (MTA)
287 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
288 apartment_addref(MTA);
290 else
291 MTA = apartment_construct(model);
293 apt = MTA;
294 COM_CurrentInfo()->apt = apt;
296 LeaveCriticalSection(&csApartment);
300 return apt;
303 DWORD apartment_addref(struct apartment *apt)
305 DWORD refs = InterlockedIncrement(&apt->refs);
306 TRACE("%s: before = %ld\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
307 return refs;
310 DWORD apartment_release(struct apartment *apt)
312 DWORD ret;
314 EnterCriticalSection(&csApartment);
316 ret = InterlockedDecrement(&apt->refs);
317 TRACE("%s: after = %ld\n", wine_dbgstr_longlong(apt->oxid), ret);
318 /* destruction stuff that needs to happen under csApartment CS */
319 if (ret == 0)
321 if (apt == MTA) MTA = NULL;
322 list_remove(&apt->entry);
325 LeaveCriticalSection(&csApartment);
327 if (ret == 0)
329 struct list *cursor, *cursor2;
331 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
333 /* no locking is needed for this apartment, because no other thread
334 * can access it at this point */
336 apartment_disconnectproxies(apt);
338 if (apt->win) DestroyWindow(apt->win);
340 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
342 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
343 /* release the implicit reference given by the fact that the
344 * stub has external references (it must do since it is in the
345 * stub manager list in the apartment and all non-apartment users
346 * must have a ref on the apartment and so it cannot be destroyed).
348 stub_manager_int_release(stubmgr);
351 /* if this assert fires, then another thread took a reference to a
352 * stub manager without taking a reference to the containing
353 * apartment, which it must do. */
354 assert(list_empty(&apt->stubmgrs));
356 if (apt->filter) IUnknown_Release(apt->filter);
358 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
359 DeleteCriticalSection(&apt->cs);
360 CloseHandle(apt->thread);
362 HeapFree(GetProcessHeap(), 0, apt);
365 return ret;
368 /* The given OXID must be local to this process:
370 * The ref parameter is here mostly to ensure people remember that
371 * they get one, you should normally take a ref for thread safety.
373 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
375 APARTMENT *result = NULL;
376 struct list *cursor;
378 EnterCriticalSection(&csApartment);
379 LIST_FOR_EACH( cursor, &apts )
381 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
382 if (apt->oxid == oxid)
384 result = apt;
385 if (ref) apartment_addref(result);
386 break;
389 LeaveCriticalSection(&csApartment);
391 return result;
394 /* gets the apartment which has a given creator thread ID. The caller must
395 * release the reference from the apartment as soon as the apartment pointer
396 * is no longer required. */
397 APARTMENT *apartment_findfromtid(DWORD tid)
399 APARTMENT *result = NULL;
400 struct list *cursor;
402 EnterCriticalSection(&csApartment);
403 LIST_FOR_EACH( cursor, &apts )
405 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
406 if (apt->tid == tid)
408 result = apt;
409 apartment_addref(result);
410 break;
413 LeaveCriticalSection(&csApartment);
415 return result;
418 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
420 switch (msg)
422 case DM_EXECUTERPC:
423 return RPC_ExecuteCall((struct dispatch_params *)lParam);
424 default:
425 return DefWindowProcW(hWnd, msg, wParam, lParam);
429 /*****************************************************************************
430 * This section contains OpenDllList implemantation
433 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
435 OpenDll *ptr;
436 OpenDll *tmp;
438 TRACE("\n");
440 EnterCriticalSection( &csOpenDllList );
442 if (openDllList == NULL) {
443 /* empty list -- add first node */
444 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
445 openDllList->hLibrary=hLibrary;
446 openDllList->next = NULL;
447 } else {
448 /* search for this dll */
449 int found = FALSE;
450 for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
451 if (ptr->hLibrary == hLibrary) {
452 found = TRUE;
453 break;
456 if (!found) {
457 /* dll not found, add it */
458 tmp = openDllList;
459 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
460 openDllList->hLibrary = hLibrary;
461 openDllList->next = tmp;
465 LeaveCriticalSection( &csOpenDllList );
468 static void COMPOBJ_DllList_FreeUnused(int Timeout)
470 OpenDll *curr, *next, *prev = NULL;
471 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
472 DllCanUnloadNowFunc DllCanUnloadNow;
474 TRACE("\n");
476 EnterCriticalSection( &csOpenDllList );
478 for (curr = openDllList; curr != NULL; ) {
479 DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
481 if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
482 next = curr->next;
484 TRACE("freeing %p\n", curr->hLibrary);
485 FreeLibrary(curr->hLibrary);
487 HeapFree(GetProcessHeap(), 0, curr);
488 if (curr == openDllList) {
489 openDllList = next;
490 } else {
491 prev->next = next;
494 curr = next;
495 } else {
496 prev = curr;
497 curr = curr->next;
501 LeaveCriticalSection( &csOpenDllList );
504 /******************************************************************************
505 * CoBuildVersion [OLE32.@]
506 * CoBuildVersion [COMPOBJ.1]
508 * Gets the build version of the DLL.
510 * PARAMS
512 * RETURNS
513 * Current build version, hiword is majornumber, loword is minornumber
515 DWORD WINAPI CoBuildVersion(void)
517 TRACE("Returning version %d, build %d.\n", rmm, rup);
518 return (rmm<<16)+rup;
521 /******************************************************************************
522 * CoInitialize [OLE32.@]
524 * Initializes the COM libraries by calling CoInitializeEx with
525 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
527 * PARAMS
528 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
530 * RETURNS
531 * Success: S_OK if not already initialized, S_FALSE otherwise.
532 * Failure: HRESULT code.
534 * SEE ALSO
535 * CoInitializeEx
537 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
540 * Just delegate to the newer method.
542 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
545 /******************************************************************************
546 * CoInitializeEx [OLE32.@]
548 * Initializes the COM libraries.
550 * PARAMS
551 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
552 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
554 * RETURNS
555 * S_OK if successful,
556 * S_FALSE if this function was called already.
557 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
558 * threading model.
560 * NOTES
562 * The behavior used to set the IMalloc used for memory management is
563 * obsolete.
564 * The dwCoInit parameter must specify of of the following apartment
565 * threading models:
566 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
567 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
568 * The parameter may also specify zero or more of the following flags:
569 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
570 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
572 * SEE ALSO
573 * CoUninitialize
575 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
577 HRESULT hr = S_OK;
578 APARTMENT *apt;
580 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
582 if (lpReserved!=NULL)
584 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
588 * Check the lock count. If this is the first time going through the initialize
589 * process, we have to initialize the libraries.
591 * And crank-up that lock count.
593 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
596 * Initialize the various COM libraries and data structures.
598 TRACE("() - Initializing the COM libraries\n");
600 /* we may need to defer this until after apartment initialisation */
601 RunningObjectTableImpl_Initialize();
604 if (!(apt = COM_CurrentInfo()->apt))
606 apt = apartment_get_or_create(dwCoInit);
607 if (!apt) return E_OUTOFMEMORY;
609 else if (dwCoInit != apt->model)
611 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
612 code then we are probably using the wrong threading model to implement that API. */
613 ERR("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit);
614 return RPC_E_CHANGED_MODE;
616 else
617 hr = S_FALSE;
619 COM_CurrentInfo()->inits++;
621 return hr;
624 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
625 pending RPCs are ignored. Non-COM messages are discarded at this point.
627 void COM_FlushMessageQueue(void)
629 MSG message;
630 APARTMENT *apt = COM_CurrentApt();
632 if (!apt || !apt->win) return;
634 TRACE("Flushing STA message queue\n");
636 while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE))
638 if (message.hwnd != apt->win)
640 WARN("discarding message 0x%x for window %p\n", message.message, message.hwnd);
641 continue;
644 TranslateMessage(&message);
645 DispatchMessageA(&message);
649 /***********************************************************************
650 * CoUninitialize [OLE32.@]
652 * This method will decrement the refcount on the current apartment, freeing
653 * the resources associated with it if it is the last thread in the apartment.
654 * If the last apartment is freed, the function will additionally release
655 * any COM resources associated with the process.
657 * PARAMS
659 * RETURNS
660 * Nothing.
662 * SEE ALSO
663 * CoInitializeEx
665 void WINAPI CoUninitialize(void)
667 struct oletls * info = COM_CurrentInfo();
668 LONG lCOMRefCnt;
670 TRACE("()\n");
672 /* will only happen on OOM */
673 if (!info) return;
675 /* sanity check */
676 if (!info->inits)
678 ERR("Mismatched CoUninitialize\n");
679 return;
682 if (!--info->inits)
684 apartment_release(info->apt);
685 info->apt = NULL;
689 * Decrease the reference count.
690 * If we are back to 0 locks on the COM library, make sure we free
691 * all the associated data structures.
693 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
694 if (lCOMRefCnt==1)
696 TRACE("() - Releasing the COM libraries\n");
698 RunningObjectTableImpl_UnInitialize();
700 /* Release the references to the registered class objects */
701 COM_RevokeAllClasses();
703 /* This will free the loaded COM Dlls */
704 CoFreeAllLibraries();
706 /* This ensures we deal with any pending RPCs */
707 COM_FlushMessageQueue();
709 else if (lCOMRefCnt<1) {
710 ERR( "CoUninitialize() - not CoInitialized.\n" );
711 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
715 /******************************************************************************
716 * CoDisconnectObject [OLE32.@]
717 * CoDisconnectObject [COMPOBJ.15]
719 * Disconnects all connections to this object from remote processes. Dispatches
720 * pending RPCs while blocking new RPCs from occurring, and then calls
721 * IMarshal::DisconnectObject on the given object.
723 * Typically called when the object server is forced to shut down, for instance by
724 * the user.
726 * PARAMS
727 * lpUnk [I] The object whose stub should be disconnected.
728 * reserved [I] Reserved. Should be set to 0.
730 * RETURNS
731 * Success: S_OK.
732 * Failure: HRESULT code.
734 * SEE ALSO
735 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
737 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
739 HRESULT hr;
740 IMarshal *marshal;
741 APARTMENT *apt;
743 TRACE("(%p, 0x%08lx)\n", lpUnk, reserved);
745 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
746 if (hr == S_OK)
748 hr = IMarshal_DisconnectObject(marshal, reserved);
749 IMarshal_Release(marshal);
750 return hr;
753 apt = COM_CurrentApt();
754 if (!apt)
755 return CO_E_NOTINITIALIZED;
757 apartment_disconnectobject(apt, lpUnk);
759 /* Note: native is pretty broken here because it just silently
760 * fails, without returning an appropriate error code if the object was
761 * not found, making apps think that the object was disconnected, when
762 * it actually wasn't */
764 return S_OK;
767 /******************************************************************************
768 * CoCreateGuid [OLE32.@]
770 * Simply forwards to UuidCreate in RPCRT4.
772 * PARAMS
773 * pguid [O] Points to the GUID to initialize.
775 * RETURNS
776 * Success: S_OK.
777 * Failure: HRESULT code.
779 * SEE ALSO
780 * UuidCreate
782 HRESULT WINAPI CoCreateGuid(GUID *pguid)
784 return UuidCreate(pguid);
787 /******************************************************************************
788 * CLSIDFromString [OLE32.@]
789 * IIDFromString [OLE32.@]
791 * Converts a unique identifier from its string representation into
792 * the GUID struct.
794 * PARAMS
795 * idstr [I] The string representation of the GUID.
796 * id [O] GUID converted from the string.
798 * RETURNS
799 * S_OK on success
800 * CO_E_CLASSSTRING if idstr is not a valid CLSID
802 * BUGS
804 * In Windows, if idstr is not a valid CLSID string then it gets
805 * treated as a ProgID. Wine currently doesn't do this. If idstr is
806 * NULL it's treated as an all-zero GUID.
808 * SEE ALSO
809 * StringFromCLSID
811 HRESULT WINAPI __CLSIDFromStringA(LPCSTR idstr, CLSID *id)
813 const BYTE *s = (const BYTE *) idstr;
814 int i;
815 BYTE table[256];
817 if (!s)
818 s = "{00000000-0000-0000-0000-000000000000}";
819 else { /* validate the CLSID string */
821 if (strlen(s) != 38)
822 return CO_E_CLASSSTRING;
824 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
825 return CO_E_CLASSSTRING;
827 for (i=1; i<37; i++) {
828 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
829 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
830 ((s[i] >= 'a') && (s[i] <= 'f')) ||
831 ((s[i] >= 'A') && (s[i] <= 'F'))))
832 return CO_E_CLASSSTRING;
836 TRACE("%s -> %p\n", s, id);
838 /* quick lookup table */
839 memset(table, 0, 256);
841 for (i = 0; i < 10; i++) {
842 table['0' + i] = i;
844 for (i = 0; i < 6; i++) {
845 table['A' + i] = i+10;
846 table['a' + i] = i+10;
849 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
851 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
852 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
853 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
854 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
856 /* these are just sequential bytes */
857 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
858 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
859 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
860 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
861 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
862 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
863 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
864 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
866 return S_OK;
869 /*****************************************************************************/
871 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
873 char xid[40];
874 HRESULT ret;
876 if (!WideCharToMultiByte( CP_ACP, 0, idstr, -1, xid, sizeof(xid), NULL, NULL ))
877 return CO_E_CLASSSTRING;
880 ret = __CLSIDFromStringA(xid,id);
881 if(ret != S_OK) { /* It appears a ProgID is also valid */
882 ret = CLSIDFromProgID(idstr, id);
884 return ret;
887 /* Converts a GUID into the respective string representation. */
888 HRESULT WINE_StringFromCLSID(
889 const CLSID *id, /* [in] GUID to be converted */
890 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
892 static const char *hex = "0123456789ABCDEF";
893 char *s;
894 int i;
896 if (!id)
897 { ERR("called with id=Null\n");
898 *idstr = 0x00;
899 return E_FAIL;
902 sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
903 id->Data1, id->Data2, id->Data3,
904 id->Data4[0], id->Data4[1]);
905 s = &idstr[25];
907 /* 6 hex bytes */
908 for (i = 2; i < 8; i++) {
909 *s++ = hex[id->Data4[i]>>4];
910 *s++ = hex[id->Data4[i] & 0xf];
913 *s++ = '}';
914 *s++ = '\0';
916 TRACE("%p->%s\n", id, idstr);
918 return S_OK;
922 /******************************************************************************
923 * StringFromCLSID [OLE32.@]
924 * StringFromIID [OLE32.@]
926 * Converts a GUID into the respective string representation.
927 * The target string is allocated using the OLE IMalloc.
929 * PARAMS
930 * id [I] the GUID to be converted.
931 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
933 * RETURNS
934 * S_OK
935 * E_FAIL
937 * SEE ALSO
938 * StringFromGUID2, CLSIDFromString
940 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
942 char buf[80];
943 HRESULT ret;
944 LPMALLOC mllc;
946 if ((ret = CoGetMalloc(0,&mllc)))
947 return ret;
949 ret=WINE_StringFromCLSID(id,buf);
950 if (!ret) {
951 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
952 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
953 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
955 return ret;
958 /******************************************************************************
959 * StringFromGUID2 [OLE32.@]
960 * StringFromGUID2 [COMPOBJ.76]
962 * Modified version of StringFromCLSID that allows you to specify max
963 * buffer size.
965 * PARAMS
966 * id [I] GUID to convert to string.
967 * str [O] Buffer where the result will be stored.
968 * cmax [I] Size of the buffer in characters.
970 * RETURNS
971 * Success: The length of the resulting string in characters.
972 * Failure: 0.
974 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
976 char xguid[80];
978 if (WINE_StringFromCLSID(id,xguid))
979 return 0;
980 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
983 /******************************************************************************
984 * ProgIDFromCLSID [OLE32.@]
986 * Converts a class id into the respective program ID.
988 * PARAMS
989 * clsid [I] Class ID, as found in registry.
990 * lplpszProgID [O] Associated ProgID.
992 * RETURNS
993 * S_OK
994 * E_OUTOFMEMORY
995 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
997 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *lplpszProgID)
999 char strCLSID[50], *buf, *buf2;
1000 DWORD buf2len;
1001 HKEY xhkey;
1002 LPMALLOC mllc;
1003 HRESULT ret = S_OK;
1005 WINE_StringFromCLSID(clsid, strCLSID);
1007 buf = HeapAlloc(GetProcessHeap(), 0, strlen(strCLSID)+14);
1008 sprintf(buf,"CLSID\\%s\\ProgID", strCLSID);
1009 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
1010 ret = REGDB_E_CLASSNOTREG;
1012 HeapFree(GetProcessHeap(), 0, buf);
1014 if (ret == S_OK)
1016 buf2 = HeapAlloc(GetProcessHeap(), 0, 255);
1017 buf2len = 255;
1018 if (RegQueryValueA(xhkey, NULL, buf2, &buf2len))
1019 ret = REGDB_E_CLASSNOTREG;
1021 if (ret == S_OK)
1023 if (CoGetMalloc(0,&mllc))
1024 ret = E_OUTOFMEMORY;
1025 else
1027 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf2, -1, NULL, 0 );
1028 *lplpszProgID = IMalloc_Alloc(mllc, len * sizeof(WCHAR) );
1029 MultiByteToWideChar( CP_ACP, 0, buf2, -1, *lplpszProgID, len );
1032 HeapFree(GetProcessHeap(), 0, buf2);
1035 RegCloseKey(xhkey);
1036 return ret;
1039 /******************************************************************************
1040 * CLSIDFromProgID [COMPOBJ.61]
1042 * Converts a program ID into the respective GUID.
1044 * PARAMS
1045 * progid [I] program id as found in registry
1046 * riid [O] associated CLSID
1048 * RETURNS
1049 * Success: S_OK
1050 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1052 HRESULT WINAPI CLSIDFromProgID16(LPCOLESTR16 progid, LPCLSID riid)
1054 char *buf,buf2[80];
1055 DWORD buf2len;
1056 HRESULT err;
1057 HKEY xhkey;
1059 buf = HeapAlloc(GetProcessHeap(),0,strlen(progid)+8);
1060 sprintf(buf,"%s\\CLSID",progid);
1061 if ((err=RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&xhkey))) {
1062 HeapFree(GetProcessHeap(),0,buf);
1063 return CO_E_CLASSSTRING;
1065 HeapFree(GetProcessHeap(),0,buf);
1066 buf2len = sizeof(buf2);
1067 if ((err=RegQueryValueA(xhkey,NULL,buf2,&buf2len))) {
1068 RegCloseKey(xhkey);
1069 return CO_E_CLASSSTRING;
1071 RegCloseKey(xhkey);
1072 return __CLSIDFromStringA(buf2,riid);
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 char buf2[80];
1092 DWORD 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 (RegQueryValueA(xhkey,NULL,buf2,&buf2len))
1107 RegCloseKey(xhkey);
1108 return CO_E_CLASSSTRING;
1110 RegCloseKey(xhkey);
1111 return __CLSIDFromStringA(buf2,riid);
1116 /*****************************************************************************
1117 * CoGetPSClsid [OLE32.@]
1119 * Retrieves the CLSID of the proxy/stub factory that implements
1120 * IPSFactoryBuffer for the specified interface.
1122 * PARAMS
1123 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1124 * pclsid [O] Where to store returned proxy/stub CLSID.
1126 * RETURNS
1127 * S_OK
1128 * E_OUTOFMEMORY
1129 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1131 * NOTES
1133 * The standard marshaller activates the object with the CLSID
1134 * returned and uses the CreateProxy and CreateStub methods on its
1135 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1136 * given object.
1138 * CoGetPSClsid determines this CLSID by searching the
1139 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1140 * in the registry and any interface id registered by
1141 * CoRegisterPSClsid within the current process.
1143 * BUGS
1145 * We only search the registry, not ids registered with
1146 * CoRegisterPSClsid.
1147 * Also, native returns S_OK for interfaces with an key in HKCR\Interface, but
1148 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1149 * considered a bug in native unless an application depends on this (unlikely).
1151 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1153 char *buf, buf2[40];
1154 DWORD buf2len;
1155 HKEY xhkey;
1157 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1159 /* Get the input iid as a string */
1160 WINE_StringFromCLSID(riid, buf2);
1161 /* Allocate memory for the registry key we will construct.
1162 (length of iid string plus constant length of static text */
1163 buf = HeapAlloc(GetProcessHeap(), 0, strlen(buf2)+27);
1164 if (buf == NULL)
1165 return E_OUTOFMEMORY;
1167 /* Construct the registry key we want */
1168 sprintf(buf,"Interface\\%s\\ProxyStubClsid32", buf2);
1170 /* Open the key.. */
1171 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
1173 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1174 HeapFree(GetProcessHeap(),0,buf);
1175 return REGDB_E_IIDNOTREG;
1177 HeapFree(GetProcessHeap(),0,buf);
1179 /* ... Once we have the key, query the registry to get the
1180 value of CLSID as a string, and convert it into a
1181 proper CLSID structure to be passed back to the app */
1182 buf2len = sizeof(buf2);
1183 if ( (RegQueryValueA(xhkey,NULL,buf2,&buf2len)) )
1185 RegCloseKey(xhkey);
1186 return REGDB_E_IIDNOTREG;
1188 RegCloseKey(xhkey);
1190 /* We have the CLSid we want back from the registry as a string, so
1191 lets convert it into a CLSID structure */
1192 if ( (__CLSIDFromStringA(buf2,pclsid)) != NOERROR)
1193 return REGDB_E_IIDNOTREG;
1195 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1196 return S_OK;
1201 /***********************************************************************
1202 * WriteClassStm (OLE32.@)
1204 * Writes a CLSID to a stream.
1206 * PARAMS
1207 * pStm [I] Stream to write to.
1208 * rclsid [I] CLSID to write.
1210 * RETURNS
1211 * Success: S_OK.
1212 * Failure: HRESULT code.
1214 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
1216 TRACE("(%p,%p)\n",pStm,rclsid);
1218 if (rclsid==NULL)
1219 return E_INVALIDARG;
1221 return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
1224 /***********************************************************************
1225 * ReadClassStm (OLE32.@)
1227 * Reads a CLSID from a stream.
1229 * PARAMS
1230 * pStm [I] Stream to read from.
1231 * rclsid [O] CLSID to read.
1233 * RETURNS
1234 * Success: S_OK.
1235 * Failure: HRESULT code.
1237 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
1239 ULONG nbByte;
1240 HRESULT res;
1242 TRACE("(%p,%p)\n",pStm,pclsid);
1244 if (pclsid==NULL)
1245 return E_INVALIDARG;
1247 res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
1249 if (FAILED(res))
1250 return res;
1252 if (nbByte != sizeof(CLSID))
1253 return S_FALSE;
1254 else
1255 return S_OK;
1259 /***
1260 * COM_GetRegisteredClassObject
1262 * This internal method is used to scan the registered class list to
1263 * find a class object.
1265 * Params:
1266 * rclsid Class ID of the class to find.
1267 * dwClsContext Class context to match.
1268 * ppv [out] returns a pointer to the class object. Complying
1269 * to normal COM usage, this method will increase the
1270 * reference count on this object.
1272 static HRESULT COM_GetRegisteredClassObject(
1273 REFCLSID rclsid,
1274 DWORD dwClsContext,
1275 LPUNKNOWN* ppUnk)
1277 HRESULT hr = S_FALSE;
1278 RegisteredClass* curClass;
1280 EnterCriticalSection( &csRegisteredClassList );
1283 * Sanity check
1285 assert(ppUnk!=0);
1288 * Iterate through the whole list and try to match the class ID.
1290 curClass = firstRegisteredClass;
1292 while (curClass != 0)
1295 * Check if we have a match on the class ID.
1297 if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
1300 * Since we don't do out-of process or DCOM just right away, let's ignore the
1301 * class context.
1305 * We have a match, return the pointer to the class object.
1307 *ppUnk = curClass->classObject;
1309 IUnknown_AddRef(curClass->classObject);
1311 hr = S_OK;
1312 goto end;
1316 * Step to the next class in the list.
1318 curClass = curClass->nextClass;
1321 end:
1322 LeaveCriticalSection( &csRegisteredClassList );
1324 * If we get to here, we haven't found our class.
1326 return hr;
1329 /******************************************************************************
1330 * CoRegisterClassObject [OLE32.@]
1332 * Registers the class object for a given class ID. Servers housed in EXE
1333 * files use this method instead of exporting DllGetClassObject to allow
1334 * other code to connect to their objects.
1336 * PARAMS
1337 * rclsid [I] CLSID of the object to register.
1338 * pUnk [I] IUnknown of the object.
1339 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1340 * flags [I] REGCLS flags indicating how connections are made.
1341 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1343 * RETURNS
1344 * S_OK on success,
1345 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1346 * CO_E_OBJISREG if the object is already registered. We should not return this.
1348 * SEE ALSO
1349 * CoRevokeClassObject, CoGetClassObject
1351 * BUGS
1352 * MSDN claims that multiple interface registrations are legal, but we
1353 * can't do that with our current implementation.
1355 HRESULT WINAPI CoRegisterClassObject(
1356 REFCLSID rclsid,
1357 LPUNKNOWN pUnk,
1358 DWORD dwClsContext,
1359 DWORD flags,
1360 LPDWORD lpdwRegister)
1362 RegisteredClass* newClass;
1363 LPUNKNOWN foundObject;
1364 HRESULT hr;
1366 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1367 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1369 if ( (lpdwRegister==0) || (pUnk==0) )
1370 return E_INVALIDARG;
1372 if (!COM_CurrentApt())
1374 ERR("COM was not initialized\n");
1375 return CO_E_NOTINITIALIZED;
1378 *lpdwRegister = 0;
1381 * First, check if the class is already registered.
1382 * If it is, this should cause an error.
1384 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1385 if (hr == S_OK) {
1386 IUnknown_Release(foundObject);
1387 return CO_E_OBJISREG;
1390 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1391 if ( newClass == NULL )
1392 return E_OUTOFMEMORY;
1394 EnterCriticalSection( &csRegisteredClassList );
1396 newClass->classIdentifier = *rclsid;
1397 newClass->runContext = dwClsContext;
1398 newClass->connectFlags = flags;
1400 * Use the address of the chain node as the cookie since we are sure it's
1401 * unique. FIXME: not on 64-bit platforms.
1403 newClass->dwCookie = (DWORD)newClass;
1404 newClass->nextClass = firstRegisteredClass;
1407 * Since we're making a copy of the object pointer, we have to increase its
1408 * reference count.
1410 newClass->classObject = pUnk;
1411 IUnknown_AddRef(newClass->classObject);
1413 firstRegisteredClass = newClass;
1414 LeaveCriticalSection( &csRegisteredClassList );
1416 *lpdwRegister = newClass->dwCookie;
1418 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1419 IClassFactory *classfac;
1421 hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory,
1422 (LPVOID*)&classfac);
1423 if (hr) return hr;
1425 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
1426 if (hr) {
1427 FIXME("Failed to create stream on hglobal, %lx\n", hr);
1428 IUnknown_Release(classfac);
1429 return hr;
1431 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
1432 (LPVOID)classfac, MSHCTX_LOCAL, NULL,
1433 MSHLFLAGS_TABLESTRONG);
1434 if (hr) {
1435 FIXME("CoMarshalInterface failed, %lx!\n",hr);
1436 IUnknown_Release(classfac);
1437 return hr;
1440 IUnknown_Release(classfac);
1442 RPC_StartLocalServer(&newClass->classIdentifier, newClass->pMarshaledData);
1444 return S_OK;
1447 /***********************************************************************
1448 * CoRevokeClassObject [OLE32.@]
1450 * Removes a class object from the class registry.
1452 * PARAMS
1453 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1455 * RETURNS
1456 * Success: S_OK.
1457 * Failure: HRESULT code.
1459 * SEE ALSO
1460 * CoRegisterClassObject
1462 HRESULT WINAPI CoRevokeClassObject(
1463 DWORD dwRegister)
1465 HRESULT hr = E_INVALIDARG;
1466 RegisteredClass** prevClassLink;
1467 RegisteredClass* curClass;
1469 TRACE("(%08lx)\n",dwRegister);
1471 EnterCriticalSection( &csRegisteredClassList );
1474 * Iterate through the whole list and try to match the cookie.
1476 curClass = firstRegisteredClass;
1477 prevClassLink = &firstRegisteredClass;
1479 while (curClass != 0)
1482 * Check if we have a match on the cookie.
1484 if (curClass->dwCookie == dwRegister)
1487 * Remove the class from the chain.
1489 *prevClassLink = curClass->nextClass;
1492 * Release the reference to the class object.
1494 IUnknown_Release(curClass->classObject);
1496 if (curClass->pMarshaledData)
1498 LARGE_INTEGER zero;
1499 memset(&zero, 0, sizeof(zero));
1500 /* FIXME: stop local server thread */
1501 IStream_Seek(curClass->pMarshaledData, zero, SEEK_SET, NULL);
1502 CoReleaseMarshalData(curClass->pMarshaledData);
1506 * Free the memory used by the chain node.
1508 HeapFree(GetProcessHeap(), 0, curClass);
1510 hr = S_OK;
1511 goto end;
1515 * Step to the next class in the list.
1517 prevClassLink = &(curClass->nextClass);
1518 curClass = curClass->nextClass;
1521 end:
1522 LeaveCriticalSection( &csRegisteredClassList );
1524 * If we get to here, we haven't found our class.
1526 return hr;
1529 /***********************************************************************
1530 * compobj_RegReadPath [internal]
1532 * Reads a registry value and expands it when necessary
1534 HRESULT compobj_RegReadPath(char * keyname, char * valuename, char * dst, DWORD dstlen)
1536 HRESULT hres;
1537 HKEY key;
1538 DWORD keytype;
1539 char src[MAX_PATH];
1540 DWORD dwLength = dstlen;
1542 if((hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1543 if( (hres = RegQueryValueExA(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1544 if (keytype == REG_EXPAND_SZ) {
1545 if (dstlen <= ExpandEnvironmentStringsA(src, dst, dstlen)) hres = ERROR_MORE_DATA;
1546 } else {
1547 lstrcpynA(dst, src, dstlen);
1550 RegCloseKey (key);
1552 return hres;
1555 /***********************************************************************
1556 * CoGetClassObject [COMPOBJ.7]
1557 * CoGetClassObject [OLE32.@]
1559 * FIXME. If request allows of several options and there is a failure
1560 * with one (other than not being registered) do we try the
1561 * others or return failure? (E.g. inprocess is registered but
1562 * the DLL is not found but the server version works)
1564 HRESULT WINAPI CoGetClassObject(
1565 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1566 REFIID iid, LPVOID *ppv
1568 LPUNKNOWN regClassObject;
1569 HRESULT hres = E_UNEXPECTED;
1570 char xclsid[80];
1571 HINSTANCE hLibrary;
1572 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1573 DllGetClassObjectFunc DllGetClassObject;
1575 WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
1577 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1579 if (pServerInfo) {
1580 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1581 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1585 * First, try and see if we can't match the class ID with one of the
1586 * registered classes.
1588 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, &regClassObject))
1591 * Get the required interface from the retrieved pointer.
1593 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1596 * Since QI got another reference on the pointer, we want to release the
1597 * one we already have. If QI was unsuccessful, this will release the object. This
1598 * is good since we are not returning it in the "out" parameter.
1600 IUnknown_Release(regClassObject);
1602 return hres;
1605 /* first try: in-process */
1606 if ((CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER) & dwClsContext) {
1607 char keyname[MAX_PATH];
1608 char dllpath[MAX_PATH+1];
1610 sprintf(keyname,"CLSID\\%s\\InprocServer32",xclsid);
1612 if ( compobj_RegReadPath(keyname, NULL, dllpath, sizeof(dllpath)) != ERROR_SUCCESS) {
1613 /* failure: CLSID is not found in registry */
1614 WARN("class %s not registered inproc\n", xclsid);
1615 hres = REGDB_E_CLASSNOTREG;
1616 } else {
1617 if ((hLibrary = LoadLibraryExA(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) {
1618 /* failure: DLL could not be loaded */
1619 ERR("couldn't load InprocServer32 dll %s\n", dllpath);
1620 hres = E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1621 } else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject"))) {
1622 /* failure: the dll did not export DllGetClassObject */
1623 ERR("couldn't find function DllGetClassObject in %s\n", dllpath);
1624 FreeLibrary( hLibrary );
1625 hres = CO_E_DLLNOTFOUND;
1626 } else {
1627 /* OK: get the ClassObject */
1628 COMPOBJ_DLLList_Add( hLibrary );
1629 return DllGetClassObject(rclsid, iid, ppv);
1634 /* Next try out of process */
1635 if (CLSCTX_LOCAL_SERVER & dwClsContext)
1637 return RPC_GetLocalClassObject(rclsid,iid,ppv);
1640 /* Finally try remote: this requires networked DCOM (a lot of work) */
1641 if (CLSCTX_REMOTE_SERVER & dwClsContext)
1643 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1644 hres = E_NOINTERFACE;
1647 return hres;
1649 /***********************************************************************
1650 * CoResumeClassObjects (OLE32.@)
1652 * Resumes all class objects registered with REGCLS_SUSPENDED.
1654 * RETURNS
1655 * Success: S_OK.
1656 * Failure: HRESULT code.
1658 HRESULT WINAPI CoResumeClassObjects(void)
1660 FIXME("stub\n");
1661 return S_OK;
1664 /***********************************************************************
1665 * GetClassFile (OLE32.@)
1667 * This function supplies the CLSID associated with the given filename.
1669 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1671 IStorage *pstg=0;
1672 HRESULT res;
1673 int nbElm, length, i;
1674 LONG sizeProgId;
1675 LPOLESTR *pathDec=0,absFile=0,progId=0;
1676 LPWSTR extension;
1677 static const WCHAR bkslashW[] = {'\\',0};
1678 static const WCHAR dotW[] = {'.',0};
1680 TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1682 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1683 if((StgIsStorageFile(filePathName))==S_OK){
1685 res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1687 if (SUCCEEDED(res))
1688 res=ReadClassStg(pstg,pclsid);
1690 IStorage_Release(pstg);
1692 return res;
1694 /* if the file is not a storage object then attemps to match various bits in the file against a
1695 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1696 this case
1698 for(i=0;i<nFileTypes;i++)
1700 for(i=0;j<nPatternsForType;j++){
1702 PATTERN pat;
1703 HANDLE hFile;
1705 pat=ReadPatternFromRegistry(i,j);
1706 hFile=CreateFileW(filePathName,,,,,,hFile);
1707 SetFilePosition(hFile,pat.offset);
1708 ReadFile(hFile,buf,pat.size,&r,NULL);
1709 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1711 *pclsid=ReadCLSIDFromRegistry(i);
1712 return S_OK;
1717 /* if the above strategies fail then search for the extension key in the registry */
1719 /* get the last element (absolute file) in the path name */
1720 nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1721 absFile=pathDec[nbElm-1];
1723 /* failed if the path represente a directory and not an absolute file name*/
1724 if (!lstrcmpW(absFile, bkslashW))
1725 return MK_E_INVALIDEXTENSION;
1727 /* get the extension of the file */
1728 extension = NULL;
1729 length=lstrlenW(absFile);
1730 for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1731 /* nothing */;
1733 if (!extension || !lstrcmpW(extension, dotW))
1734 return MK_E_INVALIDEXTENSION;
1736 res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1738 /* get the progId associated to the extension */
1739 progId = CoTaskMemAlloc(sizeProgId);
1740 res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1742 if (res==ERROR_SUCCESS)
1743 /* return the clsid associated to the progId */
1744 res= CLSIDFromProgID(progId,pclsid);
1746 for(i=0; pathDec[i]!=NULL;i++)
1747 CoTaskMemFree(pathDec[i]);
1748 CoTaskMemFree(pathDec);
1750 CoTaskMemFree(progId);
1752 if (res==ERROR_SUCCESS)
1753 return res;
1755 return MK_E_INVALIDEXTENSION;
1757 /***********************************************************************
1758 * CoCreateInstance [COMPOBJ.13]
1759 * CoCreateInstance [OLE32.@]
1761 HRESULT WINAPI CoCreateInstance(
1762 REFCLSID rclsid,
1763 LPUNKNOWN pUnkOuter,
1764 DWORD dwClsContext,
1765 REFIID iid,
1766 LPVOID *ppv)
1768 HRESULT hres;
1769 LPCLASSFACTORY lpclf = 0;
1771 if (!COM_CurrentApt()) return CO_E_NOTINITIALIZED;
1774 * Sanity check
1776 if (ppv==0)
1777 return E_POINTER;
1780 * Initialize the "out" parameter
1782 *ppv = 0;
1785 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1786 * Rather than create a class factory, we can just check for it here
1788 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
1789 if (StdGlobalInterfaceTableInstance == NULL)
1790 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
1791 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
1792 if (hres) return hres;
1794 TRACE("Retrieved GIT (%p)\n", *ppv);
1795 return S_OK;
1799 * Get a class factory to construct the object we want.
1801 hres = CoGetClassObject(rclsid,
1802 dwClsContext,
1803 NULL,
1804 &IID_IClassFactory,
1805 (LPVOID)&lpclf);
1807 if (FAILED(hres)) {
1808 FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n",
1809 debugstr_guid(rclsid),hres);
1810 return hres;
1814 * Create the object and don't forget to release the factory
1816 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
1817 IClassFactory_Release(lpclf);
1818 if(FAILED(hres))
1819 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1820 debugstr_guid(iid), debugstr_guid(rclsid),hres);
1822 return hres;
1825 /***********************************************************************
1826 * CoCreateInstanceEx [OLE32.@]
1828 HRESULT WINAPI CoCreateInstanceEx(
1829 REFCLSID rclsid,
1830 LPUNKNOWN pUnkOuter,
1831 DWORD dwClsContext,
1832 COSERVERINFO* pServerInfo,
1833 ULONG cmq,
1834 MULTI_QI* pResults)
1836 IUnknown* pUnk = NULL;
1837 HRESULT hr;
1838 ULONG index;
1839 ULONG successCount = 0;
1842 * Sanity check
1844 if ( (cmq==0) || (pResults==NULL))
1845 return E_INVALIDARG;
1847 if (pServerInfo!=NULL)
1848 FIXME("() non-NULL pServerInfo not supported!\n");
1851 * Initialize all the "out" parameters.
1853 for (index = 0; index < cmq; index++)
1855 pResults[index].pItf = NULL;
1856 pResults[index].hr = E_NOINTERFACE;
1860 * Get the object and get its IUnknown pointer.
1862 hr = CoCreateInstance(rclsid,
1863 pUnkOuter,
1864 dwClsContext,
1865 &IID_IUnknown,
1866 (VOID**)&pUnk);
1868 if (hr)
1869 return hr;
1872 * Then, query for all the interfaces requested.
1874 for (index = 0; index < cmq; index++)
1876 pResults[index].hr = IUnknown_QueryInterface(pUnk,
1877 pResults[index].pIID,
1878 (VOID**)&(pResults[index].pItf));
1880 if (pResults[index].hr == S_OK)
1881 successCount++;
1885 * Release our temporary unknown pointer.
1887 IUnknown_Release(pUnk);
1889 if (successCount == 0)
1890 return E_NOINTERFACE;
1892 if (successCount!=cmq)
1893 return CO_S_NOTALLINTERFACES;
1895 return S_OK;
1898 /***********************************************************************
1899 * CoLoadLibrary (OLE32.@)
1901 * Loads a library.
1903 * PARAMS
1904 * lpszLibName [I] Path to library.
1905 * bAutoFree [I] Whether the library should automatically be freed.
1907 * RETURNS
1908 * Success: Handle to loaded library.
1909 * Failure: NULL.
1911 * SEE ALSO
1912 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1914 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
1916 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
1918 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
1921 /***********************************************************************
1922 * CoFreeLibrary [OLE32.@]
1924 * Unloads a library from memory.
1926 * PARAMS
1927 * hLibrary [I] Handle to library to unload.
1929 * RETURNS
1930 * Nothing
1932 * SEE ALSO
1933 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1935 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
1937 FreeLibrary(hLibrary);
1941 /***********************************************************************
1942 * CoFreeAllLibraries [OLE32.@]
1944 * Function for backwards compatibility only. Does nothing.
1946 * RETURNS
1947 * Nothing.
1949 * SEE ALSO
1950 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
1952 void WINAPI CoFreeAllLibraries(void)
1954 /* NOP */
1958 /***********************************************************************
1959 * CoFreeUnusedLibraries [OLE32.@]
1960 * CoFreeUnusedLibraries [COMPOBJ.17]
1962 * Frees any unused libraries. Unused are identified as those that return
1963 * S_OK from their DllCanUnloadNow function.
1965 * RETURNS
1966 * Nothing.
1968 * SEE ALSO
1969 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
1971 void WINAPI CoFreeUnusedLibraries(void)
1973 /* FIXME: Calls to CoFreeUnusedLibraries from any thread always route
1974 * through the main apartment's thread to call DllCanUnloadNow */
1975 COMPOBJ_DllList_FreeUnused(0);
1978 /***********************************************************************
1979 * CoFileTimeNow [OLE32.@]
1980 * CoFileTimeNow [COMPOBJ.82]
1982 * Retrieves the current time in FILETIME format.
1984 * PARAMS
1985 * lpFileTime [O] The current time.
1987 * RETURNS
1988 * S_OK.
1990 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
1992 GetSystemTimeAsFileTime( lpFileTime );
1993 return S_OK;
1996 static void COM_RevokeAllClasses()
1998 EnterCriticalSection( &csRegisteredClassList );
2000 while (firstRegisteredClass!=0)
2002 CoRevokeClassObject(firstRegisteredClass->dwCookie);
2005 LeaveCriticalSection( &csRegisteredClassList );
2008 /******************************************************************************
2009 * CoLockObjectExternal [OLE32.@]
2011 * Increments or decrements the external reference count of a stub object.
2013 * PARAMS
2014 * pUnk [I] Stub object.
2015 * fLock [I] If TRUE then increments the external ref-count,
2016 * otherwise decrements.
2017 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2018 * calling CoDisconnectObject.
2020 * RETURNS
2021 * Success: S_OK.
2022 * Failure: HRESULT code.
2024 HRESULT WINAPI CoLockObjectExternal(
2025 LPUNKNOWN pUnk,
2026 BOOL fLock,
2027 BOOL fLastUnlockReleases)
2029 struct stub_manager *stubmgr;
2030 struct apartment *apt;
2032 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2033 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2035 apt = COM_CurrentApt();
2036 if (!apt) return CO_E_NOTINITIALIZED;
2038 stubmgr = get_stub_manager_from_object(apt, pUnk);
2040 if (stubmgr)
2042 if (fLock)
2043 stub_manager_ext_addref(stubmgr, 1);
2044 else
2045 stub_manager_ext_release(stubmgr, 1);
2047 stub_manager_int_release(stubmgr);
2049 return S_OK;
2051 else
2053 WARN("stub object not found %p\n", pUnk);
2054 /* Note: native is pretty broken here because it just silently
2055 * fails, without returning an appropriate error code, making apps
2056 * think that the object was disconnected, when it actually wasn't */
2057 return S_OK;
2061 /***********************************************************************
2062 * CoInitializeWOW (OLE32.@)
2064 * WOW equivalent of CoInitialize?
2066 * PARAMS
2067 * x [I] Unknown.
2068 * y [I] Unknown.
2070 * RETURNS
2071 * Unknown.
2073 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2075 FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
2076 return 0;
2079 /***********************************************************************
2080 * CoGetState [OLE32.@]
2082 * Retrieves the thread state object previously stored by CoSetState().
2084 * PARAMS
2085 * ppv [I] Address where pointer to object will be stored.
2087 * RETURNS
2088 * Success: S_OK.
2089 * Failure: E_OUTOFMEMORY.
2091 * NOTES
2092 * Crashes on all invalid ppv addresses, including NULL.
2093 * If the function returns a non-NULL object then the caller must release its
2094 * reference on the object when the object is no longer required.
2096 * SEE ALSO
2097 * CoSetState().
2099 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2101 struct oletls *info = COM_CurrentInfo();
2102 if (!info) return E_OUTOFMEMORY;
2104 *ppv = NULL;
2106 if (info->state)
2108 IUnknown_AddRef(info->state);
2109 *ppv = info->state;
2110 TRACE("apt->state=%p\n", info->state);
2113 return S_OK;
2116 /***********************************************************************
2117 * CoSetState [OLE32.@]
2119 * Sets the thread state object.
2121 * PARAMS
2122 * pv [I] Pointer to state object to be stored.
2124 * NOTES
2125 * The system keeps a reference on the object while the object stored.
2127 * RETURNS
2128 * Success: S_OK.
2129 * Failure: E_OUTOFMEMORY.
2131 HRESULT WINAPI CoSetState(IUnknown * pv)
2133 struct oletls *info = COM_CurrentInfo();
2134 if (!info) return E_OUTOFMEMORY;
2136 if (pv) IUnknown_AddRef(pv);
2138 if (info->state)
2140 TRACE("-- release %p now\n", info->state);
2141 IUnknown_Release(info->state);
2144 info->state = pv;
2146 return S_OK;
2150 /******************************************************************************
2151 * OleGetAutoConvert [OLE32.@]
2153 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2155 HKEY hkey = 0;
2156 char buf[200];
2157 WCHAR wbuf[200];
2158 DWORD len;
2159 HRESULT res = S_OK;
2161 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2162 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2164 res = REGDB_E_CLASSNOTREG;
2165 goto done;
2167 len = 200;
2168 /* we can just query for the default value of AutoConvertTo key like that,
2169 without opening the AutoConvertTo key and querying for NULL (default) */
2170 if (RegQueryValueA(hkey,"AutoConvertTo",buf,&len))
2172 res = REGDB_E_KEYMISSING;
2173 goto done;
2175 MultiByteToWideChar( CP_ACP, 0, buf, -1, wbuf, sizeof(wbuf)/sizeof(WCHAR) );
2176 CLSIDFromString(wbuf,pClsidNew);
2177 done:
2178 if (hkey) RegCloseKey(hkey);
2179 return res;
2182 /******************************************************************************
2183 * CoTreatAsClass [OLE32.@]
2185 * Sets the TreatAs value of a class.
2187 * PARAMS
2188 * clsidOld [I] Class to set TreatAs value on.
2189 * clsidNew [I] The class the clsidOld should be treated as.
2191 * RETURNS
2192 * Success: S_OK.
2193 * Failure: HRESULT code.
2195 * SEE ALSO
2196 * CoGetTreatAsClass
2198 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2200 HKEY hkey = 0;
2201 char buf[47];
2202 char szClsidNew[39];
2203 HRESULT res = S_OK;
2204 char auto_treat_as[39];
2205 LONG auto_treat_as_size = sizeof(auto_treat_as);
2206 CLSID id;
2208 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2209 WINE_StringFromCLSID(clsidNew, szClsidNew);
2210 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2212 res = REGDB_E_CLASSNOTREG;
2213 goto done;
2215 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2217 if (!RegQueryValueA(hkey, "AutoTreatAs", auto_treat_as, &auto_treat_as_size) &&
2218 !__CLSIDFromStringA(auto_treat_as, &id))
2220 if (RegSetValueA(hkey, "TreatAs", REG_SZ, auto_treat_as, strlen(auto_treat_as)+1))
2222 res = REGDB_E_WRITEREGDB;
2223 goto done;
2226 else
2228 RegDeleteKeyA(hkey, "TreatAs");
2229 goto done;
2232 else if (RegSetValueA(hkey, "TreatAs", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
2234 res = REGDB_E_WRITEREGDB;
2235 goto done;
2238 done:
2239 if (hkey) RegCloseKey(hkey);
2240 return res;
2243 /******************************************************************************
2244 * CoGetTreatAsClass [OLE32.@]
2246 * Gets the TreatAs value of a class.
2248 * PARAMS
2249 * clsidOld [I] Class to get the TreatAs value of.
2250 * clsidNew [I] The class the clsidOld should be treated as.
2252 * RETURNS
2253 * Success: S_OK.
2254 * Failure: HRESULT code.
2256 * SEE ALSO
2257 * CoSetTreatAsClass
2259 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2261 HKEY hkey = 0;
2262 char buf[200], szClsidNew[200];
2263 HRESULT res = S_OK;
2264 LONG len = sizeof(szClsidNew);
2266 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2267 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2268 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2270 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2272 res = REGDB_E_CLASSNOTREG;
2273 goto done;
2275 if (RegQueryValueA(hkey, "TreatAs", szClsidNew, &len))
2277 res = S_FALSE;
2278 goto done;
2280 res = __CLSIDFromStringA(szClsidNew,clsidNew);
2281 if (FAILED(res))
2282 FIXME("Failed CLSIDFromStringA(%s), hres %lx?\n",szClsidNew,res);
2283 done:
2284 if (hkey) RegCloseKey(hkey);
2285 return res;
2289 /******************************************************************************
2290 * CoGetCurrentProcess [OLE32.@]
2291 * CoGetCurrentProcess [COMPOBJ.34]
2293 * Gets the current process ID.
2295 * RETURNS
2296 * The current process ID.
2298 * NOTES
2299 * Is DWORD really the correct return type for this function?
2301 DWORD WINAPI CoGetCurrentProcess(void)
2303 return GetCurrentProcessId();
2306 /******************************************************************************
2307 * CoRegisterMessageFilter [OLE32.@]
2309 * Registers a message filter.
2311 * PARAMS
2312 * lpMessageFilter [I] Pointer to interface.
2313 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2315 * RETURNS
2316 * Success: S_OK.
2317 * Failure: HRESULT code.
2319 HRESULT WINAPI CoRegisterMessageFilter(
2320 LPMESSAGEFILTER lpMessageFilter,
2321 LPMESSAGEFILTER *lplpMessageFilter)
2323 FIXME("stub\n");
2324 if (lplpMessageFilter) {
2325 *lplpMessageFilter = NULL;
2327 return S_OK;
2330 /***********************************************************************
2331 * CoIsOle1Class [OLE32.@]
2333 * Determines whether the specified class an OLE v1 class.
2335 * PARAMS
2336 * clsid [I] Class to test.
2338 * RETURNS
2339 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
2341 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
2343 FIXME("%s\n", debugstr_guid(clsid));
2344 return FALSE;
2347 /***********************************************************************
2348 * IsEqualGUID [OLE32.@]
2350 * Compares two Unique Identifiers.
2352 * PARAMS
2353 * rguid1 [I] The first GUID to compare.
2354 * rguid2 [I] The other GUID to compare.
2356 * RETURNS
2357 * TRUE if equal
2359 #undef IsEqualGUID
2360 BOOL WINAPI IsEqualGUID(
2361 REFGUID rguid1,
2362 REFGUID rguid2)
2364 return !memcmp(rguid1,rguid2,sizeof(GUID));
2367 /***********************************************************************
2368 * CoInitializeSecurity [OLE32.@]
2370 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2371 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2372 void* pReserved1, DWORD dwAuthnLevel,
2373 DWORD dwImpLevel, void* pReserved2,
2374 DWORD dwCapabilities, void* pReserved3)
2376 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
2377 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2378 dwCapabilities, pReserved3);
2379 return S_OK;
2382 /***********************************************************************
2383 * CoSuspendClassObjects [OLE32.@]
2385 * Suspends all registered class objects to prevent further requests coming in
2386 * for those objects.
2388 * RETURNS
2389 * Success: S_OK.
2390 * Failure: HRESULT code.
2392 HRESULT WINAPI CoSuspendClassObjects(void)
2394 FIXME("\n");
2395 return S_OK;
2398 /***********************************************************************
2399 * CoAddRefServerProcess [OLE32.@]
2401 * Helper function for incrementing the reference count of a local-server
2402 * process.
2404 * RETURNS
2405 * New reference count.
2407 ULONG WINAPI CoAddRefServerProcess(void)
2409 FIXME("\n");
2410 return 2;
2413 /***********************************************************************
2414 * CoReleaseServerProcess [OLE32.@]
2416 * Helper function for decrementing the reference count of a local-server
2417 * process.
2419 * RETURNS
2420 * New reference count.
2422 ULONG WINAPI CoReleaseServerProcess(void)
2424 FIXME("\n");
2425 return 1;
2428 /***********************************************************************
2429 * CoQueryProxyBlanket [OLE32.@]
2431 * Retrieves the security settings being used by a proxy.
2433 * PARAMS
2434 * pProxy [I] Pointer to the proxy object.
2435 * pAuthnSvc [O] The type of authentication service.
2436 * pAuthzSvc [O] The type of authorization service.
2437 * ppServerPrincName [O] Optional. The server prinicple name.
2438 * pAuthnLevel [O] The authentication level.
2439 * pImpLevel [O] The impersonation level.
2440 * ppAuthInfo [O] Information specific to the authorization/authentication service.
2441 * pCapabilities [O] Flags affecting the security behaviour.
2443 * RETURNS
2444 * Success: S_OK.
2445 * Failure: HRESULT code.
2447 * SEE ALSO
2448 * CoCopyProxy, CoSetProxyBlanket.
2450 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
2451 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
2452 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
2454 IClientSecurity *pCliSec;
2455 HRESULT hr;
2457 TRACE("%p\n", pProxy);
2459 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2460 if (SUCCEEDED(hr))
2462 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
2463 pAuthzSvc, ppServerPrincName,
2464 pAuthnLevel, pImpLevel, ppAuthInfo,
2465 pCapabilities);
2466 IClientSecurity_Release(pCliSec);
2469 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2470 return hr;
2473 /***********************************************************************
2474 * CoSetProxyBlanket [OLE32.@]
2476 * Sets the security settings for a proxy.
2478 * PARAMS
2479 * pProxy [I] Pointer to the proxy object.
2480 * AuthnSvc [I] The type of authentication service.
2481 * AuthzSvc [I] The type of authorization service.
2482 * pServerPrincName [I] The server prinicple name.
2483 * AuthnLevel [I] The authentication level.
2484 * ImpLevel [I] The impersonation level.
2485 * pAuthInfo [I] Information specific to the authorization/authentication service.
2486 * Capabilities [I] Flags affecting the security behaviour.
2488 * RETURNS
2489 * Success: S_OK.
2490 * Failure: HRESULT code.
2492 * SEE ALSO
2493 * CoQueryProxyBlanket, CoCopyProxy.
2495 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
2496 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
2497 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
2499 IClientSecurity *pCliSec;
2500 HRESULT hr;
2502 TRACE("%p\n", pProxy);
2504 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2505 if (SUCCEEDED(hr))
2507 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
2508 AuthzSvc, pServerPrincName,
2509 AuthnLevel, ImpLevel, pAuthInfo,
2510 Capabilities);
2511 IClientSecurity_Release(pCliSec);
2514 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2515 return hr;
2518 /***********************************************************************
2519 * CoCopyProxy [OLE32.@]
2521 * Copies a proxy.
2523 * PARAMS
2524 * pProxy [I] Pointer to the proxy object.
2525 * ppCopy [O] Copy of the proxy.
2527 * RETURNS
2528 * Success: S_OK.
2529 * Failure: HRESULT code.
2531 * SEE ALSO
2532 * CoQueryProxyBlanket, CoSetProxyBlanket.
2534 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
2536 IClientSecurity *pCliSec;
2537 HRESULT hr;
2539 TRACE("%p\n", pProxy);
2541 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2542 if (SUCCEEDED(hr))
2544 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
2545 IClientSecurity_Release(pCliSec);
2548 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2549 return hr;
2553 /***********************************************************************
2554 * CoWaitForMultipleHandles [OLE32.@]
2556 * Waits for one or more handles to become signaled.
2558 * PARAMS
2559 * dwFlags [I] Flags. See notes.
2560 * dwTimeout [I] Timeout in milliseconds.
2561 * cHandles [I] Number of handles pointed to by pHandles.
2562 * pHandles [I] Handles to wait for.
2563 * lpdwindex [O] Index of handle that was signaled.
2565 * RETURNS
2566 * Success: S_OK.
2567 * Failure: RPC_S_CALLPENDING on timeout.
2569 * NOTES
2571 * The dwFlags parameter can be zero or more of the following:
2572 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
2573 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
2575 * SEE ALSO
2576 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
2578 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
2579 ULONG cHandles, const HANDLE* pHandles, LPDWORD lpdwindex)
2581 HRESULT hr = S_OK;
2582 DWORD wait_flags = (dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0 |
2583 (dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0;
2584 DWORD start_time = GetTickCount();
2586 TRACE("(0x%08lx, 0x%08lx, %ld, %p, %p)\n", dwFlags, dwTimeout, cHandles,
2587 pHandles, lpdwindex);
2589 while (TRUE)
2591 DWORD now = GetTickCount();
2592 DWORD res;
2594 if ((dwTimeout != INFINITE) && (start_time + dwTimeout >= now))
2596 hr = RPC_S_CALLPENDING;
2597 break;
2600 TRACE("waiting for rpc completion or window message\n");
2602 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
2603 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
2604 QS_ALLINPUT, wait_flags);
2606 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
2608 MSG msg;
2609 while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
2611 /* FIXME: filter the messages here */
2612 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
2613 TranslateMessage(&msg);
2614 DispatchMessageW(&msg);
2617 else if ((res >= WAIT_OBJECT_0) && (res < WAIT_OBJECT_0 + cHandles))
2619 /* handle signaled, store index */
2620 *lpdwindex = (res - WAIT_OBJECT_0);
2621 break;
2623 else if (res == WAIT_TIMEOUT)
2625 hr = RPC_S_CALLPENDING;
2626 break;
2628 else
2630 ERR("Unexpected wait termination: %ld, %ld\n", res, GetLastError());
2631 hr = E_UNEXPECTED;
2632 break;
2635 TRACE("-- 0x%08lx\n", hr);
2636 return hr;