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
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
41 * - Use & interpret ORPCTHIS & ORPCTHAT.
54 #define NONAMELESSUNION
55 #define NONAMELESSSTRUCT
67 #include "wine/unicode.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 =
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
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;
123 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
124 struct tagRegisteredClass* nextClass;
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 {
151 struct tagOpenDll *next;
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[] = {'W','I','N','E','_','O','L','E','3','2','_','A','P','T','_','C','L','A','S','S',0};
166 static LRESULT CALLBACK COM_AptWndProc(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 void COMPOBJ_InitProcess( void )
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
184 memset(&wclass, 0, sizeof(wclass));
185 wclass.lpfnWndProc = COM_AptWndProc;
186 wclass.hInstance = OLE32_hInstance;
187 wclass.lpszClassName = wszAptWinClass;
188 RegisterClassW(&wclass);
191 void COMPOBJ_UninitProcess( void )
193 UnregisterClassW(wszAptWinClass, OLE32_hInstance);
196 void COM_TlsDestroy()
198 struct oletls *info = NtCurrentTeb()->ReservedForOle;
201 if (info->apt) COM_ApartmentRelease(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 /******************************************************************************
213 /* allocates memory and fills in the necessary fields for a new apartment
215 static APARTMENT *apartment_construct(DWORD model)
219 TRACE("creating new apartment, model=%ld\n", model);
221 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
222 apt->tid = GetCurrentThreadId();
223 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
224 GetCurrentProcess(), &apt->thread,
225 THREAD_ALL_ACCESS, FALSE, 0);
227 list_init(&apt->proxies);
228 list_init(&apt->stubmgrs);
231 apt->remunk_exported = FALSE;
233 InitializeCriticalSection(&apt->cs);
237 if (model & COINIT_APARTMENTTHREADED)
239 /* FIXME: should be randomly generated by in an RPC call to rpcss */
240 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
241 apt->win = CreateWindowW(wszAptWinClass, NULL, 0,
243 0, 0, OLE32_hInstance, NULL);
247 /* FIXME: should be randomly generated by in an RPC call to rpcss */
248 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
251 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
253 /* the locking here is not currently needed for the MTA case, but it
254 * doesn't hurt and makes the code simpler */
255 EnterCriticalSection(&csApartment);
256 list_add_head(&apts, &apt->entry);
257 LeaveCriticalSection(&csApartment);
262 /* gets and existing apartment if one exists or otherwise creates an apartment
263 * structure which stores OLE apartment-local information and stores a pointer
264 * to it in the thread-local storage */
265 static APARTMENT *get_or_create_apartment(DWORD model)
267 APARTMENT *apt = COM_CurrentApt();
271 if (model & COINIT_APARTMENTTHREADED)
273 apt = apartment_construct(model);
274 COM_CurrentInfo()->apt = apt;
278 EnterCriticalSection(&csApartment);
280 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
281 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
285 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
286 COM_ApartmentAddRef(MTA);
289 MTA = apartment_construct(model);
292 COM_CurrentInfo()->apt = apt;
294 LeaveCriticalSection(&csApartment);
301 DWORD COM_ApartmentAddRef(struct apartment *apt)
303 DWORD refs = InterlockedIncrement(&apt->refs);
304 TRACE("%s: before = %ld\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
308 DWORD COM_ApartmentRelease(struct apartment *apt)
312 EnterCriticalSection(&csApartment);
314 ret = InterlockedDecrement(&apt->refs);
315 TRACE("%s: after = %ld\n", wine_dbgstr_longlong(apt->oxid), ret);
316 /* destruction stuff that needs to happen under csApartment CS */
319 if (apt == MTA) MTA = NULL;
320 list_remove(&apt->entry);
323 LeaveCriticalSection(&csApartment);
327 struct list *cursor, *cursor2;
329 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
331 MARSHAL_Disconnect_Proxies(apt);
333 if (apt->win) DestroyWindow(apt->win);
335 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
337 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
338 /* release the implicit reference given by the fact that the
339 * stub has external references (it must do since it is in the
340 * stub manager list in the apartment and all non-apartment users
341 * must have a ref on the apartment and so it cannot be destroyed).
343 stub_manager_int_release(stubmgr);
346 /* if this assert fires, then another thread took a reference to a
347 * stub manager without taking a reference to the containing
348 * apartment, which it must do. */
349 assert(list_empty(&apt->stubmgrs));
351 if (apt->filter) IUnknown_Release(apt->filter);
353 DeleteCriticalSection(&apt->cs);
354 CloseHandle(apt->thread);
355 HeapFree(GetProcessHeap(), 0, apt);
361 /* The given OXID must be local to this process: you cannot use
362 * apartment windows to send RPCs to other processes. This all needs
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 *COM_ApartmentFromOXID(OXID oxid, BOOL ref)
370 APARTMENT *result = NULL;
373 EnterCriticalSection(&csApartment);
374 LIST_FOR_EACH( cursor, &apts )
376 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
377 if (apt->oxid == oxid)
380 if (ref) COM_ApartmentAddRef(result);
384 LeaveCriticalSection(&csApartment);
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 *COM_ApartmentFromTID(DWORD tid)
394 APARTMENT *result = NULL;
397 EnterCriticalSection(&csApartment);
398 LIST_FOR_EACH( cursor, &apts )
400 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
404 COM_ApartmentAddRef(result);
408 LeaveCriticalSection(&csApartment);
413 HWND COM_GetApartmentWin(OXID oxid, BOOL ref)
417 apt = COM_ApartmentFromOXID(oxid, ref);
418 if (!apt) return NULL;
423 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
428 return RPC_ExecuteCall((RPCOLEMESSAGE *)wParam, (IRpcStubBuffer *)lParam);
430 return DefWindowProcW(hWnd, msg, wParam, lParam);
434 /*****************************************************************************
435 * This section contains OpenDllList implemantation
438 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
445 EnterCriticalSection( &csOpenDllList );
447 if (openDllList == NULL) {
448 /* empty list -- add first node */
449 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
450 openDllList->hLibrary=hLibrary;
451 openDllList->next = NULL;
453 /* search for this dll */
455 for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
456 if (ptr->hLibrary == hLibrary) {
462 /* dll not found, add it */
464 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
465 openDllList->hLibrary = hLibrary;
466 openDllList->next = tmp;
470 LeaveCriticalSection( &csOpenDllList );
473 static void COMPOBJ_DllList_FreeUnused(int Timeout)
475 OpenDll *curr, *next, *prev = NULL;
476 typedef HRESULT(*DllCanUnloadNowFunc)(void);
477 DllCanUnloadNowFunc DllCanUnloadNow;
481 EnterCriticalSection( &csOpenDllList );
483 for (curr = openDllList; curr != NULL; ) {
484 DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
486 if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
489 TRACE("freeing %p\n", curr->hLibrary);
490 FreeLibrary(curr->hLibrary);
492 HeapFree(GetProcessHeap(), 0, curr);
493 if (curr == openDllList) {
506 LeaveCriticalSection( &csOpenDllList );
509 /******************************************************************************
510 * CoBuildVersion [OLE32.@]
511 * CoBuildVersion [COMPOBJ.1]
513 * Gets the build version of the DLL.
518 * Current build version, hiword is majornumber, loword is minornumber
520 DWORD WINAPI CoBuildVersion(void)
522 TRACE("Returning version %d, build %d.\n", rmm, rup);
523 return (rmm<<16)+rup;
526 /******************************************************************************
527 * CoInitialize [OLE32.@]
529 * Initializes the COM libraries by calling CoInitializeEx with
530 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
533 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
536 * Success: S_OK if not already initialized, S_FALSE otherwise.
537 * Failure: HRESULT code.
542 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
545 * Just delegate to the newer method.
547 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
550 /******************************************************************************
551 * CoInitializeEx [OLE32.@]
553 * Initializes the COM libraries.
556 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
557 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
560 * S_OK if successful,
561 * S_FALSE if this function was called already.
562 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
567 * The behavior used to set the IMalloc used for memory management is
569 * The dwCoInit parameter must specify of of the following apartment
571 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
572 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
573 * The parameter may also specify zero or more of the following flags:
574 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
575 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
580 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
585 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
587 if (lpReserved!=NULL)
589 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
593 * Check the lock count. If this is the first time going through the initialize
594 * process, we have to initialize the libraries.
596 * And crank-up that lock count.
598 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
601 * Initialize the various COM libraries and data structures.
603 TRACE("() - Initializing the COM libraries\n");
605 /* we may need to defer this until after apartment initialisation */
606 RunningObjectTableImpl_Initialize();
609 if (!(apt = COM_CurrentInfo()->apt))
611 apt = get_or_create_apartment(dwCoInit);
612 if (!apt) return E_OUTOFMEMORY;
614 else if (dwCoInit != apt->model)
616 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
617 code then we are probably using the wrong threading model to implement that API. */
618 ERR("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit);
619 return RPC_E_CHANGED_MODE;
624 COM_CurrentInfo()->inits++;
629 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
630 pending RPCs are ignored. Non-COM messages are discarded at this point.
632 void COM_FlushMessageQueue(void)
635 APARTMENT *apt = COM_CurrentApt();
637 if (!apt || !apt->win) return;
639 TRACE("Flushing STA message queue\n");
641 while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE))
643 if (message.hwnd != apt->win)
645 WARN("discarding message 0x%x for window %p\n", message.message, message.hwnd);
649 TranslateMessage(&message);
650 DispatchMessageA(&message);
654 /***********************************************************************
655 * CoUninitialize [OLE32.@]
657 * This method will decrement the refcount on the current apartment, freeing
658 * the resources associated with it if it is the last thread in the apartment.
659 * If the last apartment is freed, the function will additionally release
660 * any COM resources associated with the process.
670 void WINAPI CoUninitialize(void)
672 struct oletls * info = COM_CurrentInfo();
677 /* will only happen on OOM */
683 ERR("Mismatched CoUninitialize\n");
689 COM_ApartmentRelease(info->apt);
694 * Decrease the reference count.
695 * If we are back to 0 locks on the COM library, make sure we free
696 * all the associated data structures.
698 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
701 TRACE("() - Releasing the COM libraries\n");
703 RunningObjectTableImpl_UnInitialize();
705 /* Release the references to the registered class objects */
706 COM_RevokeAllClasses();
708 /* This will free the loaded COM Dlls */
709 CoFreeAllLibraries();
711 /* This ensures we deal with any pending RPCs */
712 COM_FlushMessageQueue();
714 else if (lCOMRefCnt<1) {
715 ERR( "CoUninitialize() - not CoInitialized.\n" );
716 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
720 /******************************************************************************
721 * CoDisconnectObject [OLE32.@]
722 * CoDisconnectObject [COMPOBJ.15]
724 * Disconnects all connections to this object from remote processes. Dispatches
725 * pending RPCs while blocking new RPCs from occurring, and then calls
726 * IMarshal::DisconnectObject on the given object.
728 * Typically called when the object server is forced to shut down, for instance by
732 * lpUnk [I] The object whose stub should be disconnected.
733 * reserved [I] Reserved. Should be set to 0.
737 * Failure: HRESULT code.
740 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
742 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
748 TRACE("(%p, 0x%08lx)\n", lpUnk, reserved);
750 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
753 hr = IMarshal_DisconnectObject(marshal, reserved);
754 IMarshal_Release(marshal);
758 apt = COM_CurrentApt();
760 return CO_E_NOTINITIALIZED;
762 apartment_disconnect_object(apt, lpUnk);
764 /* Note: native is pretty broken here because it just silently
765 * fails, without returning an appropriate error code if the object was
766 * not found, making apps think that the object was disconnected, when
767 * it actually wasn't */
772 /******************************************************************************
773 * CoCreateGuid [OLE32.@]
775 * Simply forwards to UuidCreate in RPCRT4.
778 * pguid [O] Points to the GUID to initialize.
782 * Failure: HRESULT code.
787 HRESULT WINAPI CoCreateGuid(GUID *pguid)
789 return UuidCreate(pguid);
792 /******************************************************************************
793 * CLSIDFromString [OLE32.@]
794 * IIDFromString [OLE32.@]
796 * Converts a unique identifier from its string representation into
800 * idstr [I] The string representation of the GUID.
801 * id [O] GUID converted from the string.
805 * CO_E_CLASSSTRING if idstr is not a valid CLSID
809 * In Windows, if idstr is not a valid CLSID string then it gets
810 * treated as a ProgID. Wine currently doesn't do this. If idstr is
811 * NULL it's treated as an all-zero GUID.
816 HRESULT WINAPI __CLSIDFromStringA(LPCSTR idstr, CLSID *id)
818 const BYTE *s = (const BYTE *) idstr;
823 s = "{00000000-0000-0000-0000-000000000000}";
824 else { /* validate the CLSID string */
827 return CO_E_CLASSSTRING;
829 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
830 return CO_E_CLASSSTRING;
832 for (i=1; i<37; i++) {
833 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
834 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
835 ((s[i] >= 'a') && (s[i] <= 'f')) ||
836 ((s[i] >= 'A') && (s[i] <= 'F'))))
837 return CO_E_CLASSSTRING;
841 TRACE("%s -> %p\n", s, id);
843 /* quick lookup table */
844 memset(table, 0, 256);
846 for (i = 0; i < 10; i++) {
849 for (i = 0; i < 6; i++) {
850 table['A' + i] = i+10;
851 table['a' + i] = i+10;
854 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
856 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
857 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
858 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
859 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
861 /* these are just sequential bytes */
862 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
863 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
864 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
865 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
866 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
867 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
868 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
869 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
874 /*****************************************************************************/
876 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
881 if (!WideCharToMultiByte( CP_ACP, 0, idstr, -1, xid, sizeof(xid), NULL, NULL ))
882 return CO_E_CLASSSTRING;
885 ret = __CLSIDFromStringA(xid,id);
886 if(ret != S_OK) { /* It appears a ProgID is also valid */
887 ret = CLSIDFromProgID(idstr, id);
892 /* Converts a GUID into the respective string representation. */
893 HRESULT WINE_StringFromCLSID(
894 const CLSID *id, /* [in] GUID to be converted */
895 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
897 static const char *hex = "0123456789ABCDEF";
902 { ERR("called with id=Null\n");
907 sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
908 id->Data1, id->Data2, id->Data3,
909 id->Data4[0], id->Data4[1]);
913 for (i = 2; i < 8; i++) {
914 *s++ = hex[id->Data4[i]>>4];
915 *s++ = hex[id->Data4[i] & 0xf];
921 TRACE("%p->%s\n", id, idstr);
927 /******************************************************************************
928 * StringFromCLSID [OLE32.@]
929 * StringFromIID [OLE32.@]
931 * Converts a GUID into the respective string representation.
932 * The target string is allocated using the OLE IMalloc.
935 * id [I] the GUID to be converted.
936 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
943 * StringFromGUID2, CLSIDFromString
945 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
951 if ((ret = CoGetMalloc(0,&mllc)))
954 ret=WINE_StringFromCLSID(id,buf);
956 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
957 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
958 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
963 /******************************************************************************
964 * StringFromGUID2 [OLE32.@]
965 * StringFromGUID2 [COMPOBJ.76]
967 * Modified version of StringFromCLSID that allows you to specify max
971 * id [I] GUID to convert to string.
972 * str [O] Buffer where the result will be stored.
973 * cmax [I] Size of the buffer in characters.
976 * Success: The length of the resulting string in characters.
979 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
983 if (WINE_StringFromCLSID(id,xguid))
985 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
988 /******************************************************************************
989 * ProgIDFromCLSID [OLE32.@]
991 * Converts a class id into the respective program ID.
994 * clsid [I] Class ID, as found in registry.
995 * lplpszProgID [O] Associated ProgID.
1000 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1002 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *lplpszProgID)
1004 char strCLSID[50], *buf, *buf2;
1010 WINE_StringFromCLSID(clsid, strCLSID);
1012 buf = HeapAlloc(GetProcessHeap(), 0, strlen(strCLSID)+14);
1013 sprintf(buf,"CLSID\\%s\\ProgID", strCLSID);
1014 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
1015 ret = REGDB_E_CLASSNOTREG;
1017 HeapFree(GetProcessHeap(), 0, buf);
1021 buf2 = HeapAlloc(GetProcessHeap(), 0, 255);
1023 if (RegQueryValueA(xhkey, NULL, buf2, &buf2len))
1024 ret = REGDB_E_CLASSNOTREG;
1028 if (CoGetMalloc(0,&mllc))
1029 ret = E_OUTOFMEMORY;
1032 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf2, -1, NULL, 0 );
1033 *lplpszProgID = IMalloc_Alloc(mllc, len * sizeof(WCHAR) );
1034 MultiByteToWideChar( CP_ACP, 0, buf2, -1, *lplpszProgID, len );
1037 HeapFree(GetProcessHeap(), 0, buf2);
1044 HRESULT WINAPI CLSIDFromProgID16(
1045 LPCOLESTR16 progid, /* [in] program id as found in registry */
1046 LPCLSID riid /* [out] associated CLSID */
1053 buf = HeapAlloc(GetProcessHeap(),0,strlen(progid)+8);
1054 sprintf(buf,"%s\\CLSID",progid);
1055 if ((err=RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&xhkey))) {
1056 HeapFree(GetProcessHeap(),0,buf);
1057 return CO_E_CLASSSTRING;
1059 HeapFree(GetProcessHeap(),0,buf);
1060 buf2len = sizeof(buf2);
1061 if ((err=RegQueryValueA(xhkey,NULL,buf2,&buf2len))) {
1063 return CO_E_CLASSSTRING;
1066 return __CLSIDFromStringA(buf2,riid);
1069 /******************************************************************************
1070 * CLSIDFromProgID [OLE32.@]
1071 * CLSIDFromProgID [COMPOBJ.61]
1073 * Converts a program id into the respective GUID.
1076 * progid [I] Unicode program ID, as found in registry.
1077 * riid [O] Associated CLSID.
1081 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1083 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID riid)
1085 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1087 DWORD buf2len = sizeof(buf2);
1090 WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1091 strcpyW( buf, progid );
1092 strcatW( buf, clsidW );
1093 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1095 HeapFree(GetProcessHeap(),0,buf);
1096 return CO_E_CLASSSTRING;
1098 HeapFree(GetProcessHeap(),0,buf);
1100 if (RegQueryValueA(xhkey,NULL,buf2,&buf2len))
1103 return CO_E_CLASSSTRING;
1106 return __CLSIDFromStringA(buf2,riid);
1111 /*****************************************************************************
1112 * CoGetPSClsid [OLE32.@]
1114 * Retrieves the CLSID of the proxy/stub factory that implements
1115 * IPSFactoryBuffer for the specified interface.
1118 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1119 * pclsid [O] Where to store returned proxy/stub CLSID.
1124 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1128 * The standard marshaller activates the object with the CLSID
1129 * returned and uses the CreateProxy and CreateStub methods on its
1130 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1133 * CoGetPSClsid determines this CLSID by searching the
1134 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1135 * in the registry and any interface id registered by
1136 * CoRegisterPSClsid within the current process.
1140 * We only search the registry, not ids registered with
1141 * CoRegisterPSClsid.
1142 * Also, native returns S_OK for interfaces with an key in HKCR\Interface, but
1143 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1144 * considered a bug in native unless an application depends on this (unlikely).
1146 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1148 char *buf, buf2[40];
1152 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1154 /* Get the input iid as a string */
1155 WINE_StringFromCLSID(riid, buf2);
1156 /* Allocate memory for the registry key we will construct.
1157 (length of iid string plus constant length of static text */
1158 buf = HeapAlloc(GetProcessHeap(), 0, strlen(buf2)+27);
1160 return E_OUTOFMEMORY;
1162 /* Construct the registry key we want */
1163 sprintf(buf,"Interface\\%s\\ProxyStubClsid32", buf2);
1165 /* Open the key.. */
1166 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
1168 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1169 HeapFree(GetProcessHeap(),0,buf);
1170 return REGDB_E_IIDNOTREG;
1172 HeapFree(GetProcessHeap(),0,buf);
1174 /* ... Once we have the key, query the registry to get the
1175 value of CLSID as a string, and convert it into a
1176 proper CLSID structure to be passed back to the app */
1177 buf2len = sizeof(buf2);
1178 if ( (RegQueryValueA(xhkey,NULL,buf2,&buf2len)) )
1181 return REGDB_E_IIDNOTREG;
1185 /* We have the CLSid we want back from the registry as a string, so
1186 lets convert it into a CLSID structure */
1187 if ( (__CLSIDFromStringA(buf2,pclsid)) != NOERROR)
1188 return REGDB_E_IIDNOTREG;
1190 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1196 /***********************************************************************
1197 * WriteClassStm (OLE32.@)
1199 * Writes a CLSID to a stream.
1202 * pStm [I] Stream to write to.
1203 * rclsid [I] CLSID to write.
1207 * Failure: HRESULT code.
1209 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
1211 TRACE("(%p,%p)\n",pStm,rclsid);
1214 return E_INVALIDARG;
1216 return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
1219 /***********************************************************************
1220 * ReadClassStm (OLE32.@)
1222 * Reads a CLSID from a stream.
1225 * pStm [I] Stream to read from.
1226 * rclsid [O] CLSID to read.
1230 * Failure: HRESULT code.
1232 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
1237 TRACE("(%p,%p)\n",pStm,pclsid);
1240 return E_INVALIDARG;
1242 res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
1247 if (nbByte != sizeof(CLSID))
1255 * COM_GetRegisteredClassObject
1257 * This internal method is used to scan the registered class list to
1258 * find a class object.
1261 * rclsid Class ID of the class to find.
1262 * dwClsContext Class context to match.
1263 * ppv [out] returns a pointer to the class object. Complying
1264 * to normal COM usage, this method will increase the
1265 * reference count on this object.
1267 static HRESULT COM_GetRegisteredClassObject(
1272 HRESULT hr = S_FALSE;
1273 RegisteredClass* curClass;
1275 EnterCriticalSection( &csRegisteredClassList );
1283 * Iterate through the whole list and try to match the class ID.
1285 curClass = firstRegisteredClass;
1287 while (curClass != 0)
1290 * Check if we have a match on the class ID.
1292 if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
1295 * Since we don't do out-of process or DCOM just right away, let's ignore the
1300 * We have a match, return the pointer to the class object.
1302 *ppUnk = curClass->classObject;
1304 IUnknown_AddRef(curClass->classObject);
1311 * Step to the next class in the list.
1313 curClass = curClass->nextClass;
1317 LeaveCriticalSection( &csRegisteredClassList );
1319 * If we get to here, we haven't found our class.
1324 /******************************************************************************
1325 * CoRegisterClassObject [OLE32.@]
1327 * Registers the class object for a given class ID. Servers housed in EXE
1328 * files use this method instead of exporting DllGetClassObject to allow
1329 * other code to connect to their objects.
1332 * rclsid [I] CLSID of the object to register.
1333 * pUnk [I] IUnknown of the object.
1334 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1335 * flags [I] REGCLS flags indicating how connections are made.
1336 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1340 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1341 * CO_E_OBJISREG if the object is already registered. We should not return this.
1344 * CoRevokeClassObject, CoGetClassObject
1347 * MSDN claims that multiple interface registrations are legal, but we
1348 * can't do that with our current implementation.
1350 HRESULT WINAPI CoRegisterClassObject(
1355 LPDWORD lpdwRegister)
1357 RegisteredClass* newClass;
1358 LPUNKNOWN foundObject;
1361 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1362 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1364 if ( (lpdwRegister==0) || (pUnk==0) )
1365 return E_INVALIDARG;
1367 if (!COM_CurrentApt())
1369 ERR("COM was not initialized\n");
1370 return CO_E_NOTINITIALIZED;
1376 * First, check if the class is already registered.
1377 * If it is, this should cause an error.
1379 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1381 IUnknown_Release(foundObject);
1382 return CO_E_OBJISREG;
1385 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1386 if ( newClass == NULL )
1387 return E_OUTOFMEMORY;
1389 EnterCriticalSection( &csRegisteredClassList );
1391 newClass->classIdentifier = *rclsid;
1392 newClass->runContext = dwClsContext;
1393 newClass->connectFlags = flags;
1395 * Use the address of the chain node as the cookie since we are sure it's
1396 * unique. FIXME: not on 64-bit platforms.
1398 newClass->dwCookie = (DWORD)newClass;
1399 newClass->nextClass = firstRegisteredClass;
1402 * Since we're making a copy of the object pointer, we have to increase its
1405 newClass->classObject = pUnk;
1406 IUnknown_AddRef(newClass->classObject);
1408 firstRegisteredClass = newClass;
1409 LeaveCriticalSection( &csRegisteredClassList );
1411 *lpdwRegister = newClass->dwCookie;
1413 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1414 IClassFactory *classfac;
1416 hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory,
1417 (LPVOID*)&classfac);
1420 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
1422 FIXME("Failed to create stream on hglobal, %lx\n", hr);
1423 IUnknown_Release(classfac);
1426 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
1427 (LPVOID)classfac, MSHCTX_LOCAL, NULL,
1428 MSHLFLAGS_TABLESTRONG);
1430 FIXME("CoMarshalInterface failed, %lx!\n",hr);
1431 IUnknown_Release(classfac);
1435 IUnknown_Release(classfac);
1437 RPC_StartLocalServer(&newClass->classIdentifier, newClass->pMarshaledData);
1442 /***********************************************************************
1443 * CoRevokeClassObject [OLE32.@]
1445 * Removes a class object from the class registry.
1448 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1452 * Failure: HRESULT code.
1455 * CoRegisterClassObject
1457 HRESULT WINAPI CoRevokeClassObject(
1460 HRESULT hr = E_INVALIDARG;
1461 RegisteredClass** prevClassLink;
1462 RegisteredClass* curClass;
1464 TRACE("(%08lx)\n",dwRegister);
1466 EnterCriticalSection( &csRegisteredClassList );
1469 * Iterate through the whole list and try to match the cookie.
1471 curClass = firstRegisteredClass;
1472 prevClassLink = &firstRegisteredClass;
1474 while (curClass != 0)
1477 * Check if we have a match on the cookie.
1479 if (curClass->dwCookie == dwRegister)
1482 * Remove the class from the chain.
1484 *prevClassLink = curClass->nextClass;
1487 * Release the reference to the class object.
1489 IUnknown_Release(curClass->classObject);
1491 if (curClass->pMarshaledData)
1494 memset(&zero, 0, sizeof(zero));
1495 /* FIXME: stop local server thread */
1496 IStream_Seek(curClass->pMarshaledData, zero, SEEK_SET, NULL);
1497 CoReleaseMarshalData(curClass->pMarshaledData);
1501 * Free the memory used by the chain node.
1503 HeapFree(GetProcessHeap(), 0, curClass);
1510 * Step to the next class in the list.
1512 prevClassLink = &(curClass->nextClass);
1513 curClass = curClass->nextClass;
1517 LeaveCriticalSection( &csRegisteredClassList );
1519 * If we get to here, we haven't found our class.
1524 /***********************************************************************
1525 * compobj_RegReadPath [internal]
1527 * Reads a registry value and expands it when necessary
1529 HRESULT compobj_RegReadPath(char * keyname, char * valuename, char * dst, DWORD dstlen)
1535 DWORD dwLength = dstlen;
1537 if((hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1538 if( (hres = RegQueryValueExA(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1539 if (keytype == REG_EXPAND_SZ) {
1540 if (dstlen <= ExpandEnvironmentStringsA(src, dst, dstlen)) hres = ERROR_MORE_DATA;
1542 lstrcpynA(dst, src, dstlen);
1550 /***********************************************************************
1551 * CoGetClassObject [COMPOBJ.7]
1552 * CoGetClassObject [OLE32.@]
1554 * FIXME. If request allows of several options and there is a failure
1555 * with one (other than not being registered) do we try the
1556 * others or return failure? (E.g. inprocess is registered but
1557 * the DLL is not found but the server version works)
1559 HRESULT WINAPI CoGetClassObject(
1560 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1561 REFIID iid, LPVOID *ppv
1563 LPUNKNOWN regClassObject;
1564 HRESULT hres = E_UNEXPECTED;
1567 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1568 DllGetClassObjectFunc DllGetClassObject;
1570 WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
1572 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1575 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1576 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1580 * First, try and see if we can't match the class ID with one of the
1581 * registered classes.
1583 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, ®ClassObject))
1586 * Get the required interface from the retrieved pointer.
1588 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1591 * Since QI got another reference on the pointer, we want to release the
1592 * one we already have. If QI was unsuccessful, this will release the object. This
1593 * is good since we are not returning it in the "out" parameter.
1595 IUnknown_Release(regClassObject);
1600 /* first try: in-process */
1601 if ((CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER) & dwClsContext) {
1602 char keyname[MAX_PATH];
1603 char dllpath[MAX_PATH+1];
1605 sprintf(keyname,"CLSID\\%s\\InprocServer32",xclsid);
1607 if ( compobj_RegReadPath(keyname, NULL, dllpath, sizeof(dllpath)) != ERROR_SUCCESS) {
1608 /* failure: CLSID is not found in registry */
1609 WARN("class %s not registered inproc\n", xclsid);
1610 hres = REGDB_E_CLASSNOTREG;
1612 if ((hLibrary = LoadLibraryExA(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) {
1613 /* failure: DLL could not be loaded */
1614 ERR("couldn't load InprocServer32 dll %s\n", dllpath);
1615 hres = E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1616 } else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject"))) {
1617 /* failure: the dll did not export DllGetClassObject */
1618 ERR("couldn't find function DllGetClassObject in %s\n", dllpath);
1619 FreeLibrary( hLibrary );
1620 hres = CO_E_DLLNOTFOUND;
1622 /* OK: get the ClassObject */
1623 COMPOBJ_DLLList_Add( hLibrary );
1624 return DllGetClassObject(rclsid, iid, ppv);
1629 /* Next try out of process */
1630 if (CLSCTX_LOCAL_SERVER & dwClsContext)
1632 return RPC_GetLocalClassObject(rclsid,iid,ppv);
1635 /* Finally try remote: this requires networked DCOM (a lot of work) */
1636 if (CLSCTX_REMOTE_SERVER & dwClsContext)
1638 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1639 hres = E_NOINTERFACE;
1644 /***********************************************************************
1645 * CoResumeClassObjects (OLE32.@)
1647 * Resumes all class objects registered with REGCLS_SUSPENDED.
1651 * Failure: HRESULT code.
1653 HRESULT WINAPI CoResumeClassObjects(void)
1659 /***********************************************************************
1660 * GetClassFile (OLE32.@)
1662 * This function supplies the CLSID associated with the given filename.
1664 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1668 int nbElm, length, i;
1670 LPOLESTR *pathDec=0,absFile=0,progId=0;
1672 static const WCHAR bkslashW[] = {'\\',0};
1673 static const WCHAR dotW[] = {'.',0};
1675 TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1677 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1678 if((StgIsStorageFile(filePathName))==S_OK){
1680 res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1683 res=ReadClassStg(pstg,pclsid);
1685 IStorage_Release(pstg);
1689 /* if the file is not a storage object then attemps to match various bits in the file against a
1690 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1693 for(i=0;i<nFileTypes;i++)
1695 for(i=0;j<nPatternsForType;j++){
1700 pat=ReadPatternFromRegistry(i,j);
1701 hFile=CreateFileW(filePathName,,,,,,hFile);
1702 SetFilePosition(hFile,pat.offset);
1703 ReadFile(hFile,buf,pat.size,&r,NULL);
1704 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1706 *pclsid=ReadCLSIDFromRegistry(i);
1712 /* if the above strategies fail then search for the extension key in the registry */
1714 /* get the last element (absolute file) in the path name */
1715 nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1716 absFile=pathDec[nbElm-1];
1718 /* failed if the path represente a directory and not an absolute file name*/
1719 if (!lstrcmpW(absFile, bkslashW))
1720 return MK_E_INVALIDEXTENSION;
1722 /* get the extension of the file */
1724 length=lstrlenW(absFile);
1725 for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1728 if (!extension || !lstrcmpW(extension, dotW))
1729 return MK_E_INVALIDEXTENSION;
1731 res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1733 /* get the progId associated to the extension */
1734 progId = CoTaskMemAlloc(sizeProgId);
1735 res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1737 if (res==ERROR_SUCCESS)
1738 /* return the clsid associated to the progId */
1739 res= CLSIDFromProgID(progId,pclsid);
1741 for(i=0; pathDec[i]!=NULL;i++)
1742 CoTaskMemFree(pathDec[i]);
1743 CoTaskMemFree(pathDec);
1745 CoTaskMemFree(progId);
1747 if (res==ERROR_SUCCESS)
1750 return MK_E_INVALIDEXTENSION;
1752 /***********************************************************************
1753 * CoCreateInstance [COMPOBJ.13]
1754 * CoCreateInstance [OLE32.@]
1756 HRESULT WINAPI CoCreateInstance(
1758 LPUNKNOWN pUnkOuter,
1764 LPCLASSFACTORY lpclf = 0;
1766 if (!COM_CurrentApt()) return CO_E_NOTINITIALIZED;
1775 * Initialize the "out" parameter
1780 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1781 * Rather than create a class factory, we can just check for it here
1783 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
1784 if (StdGlobalInterfaceTableInstance == NULL)
1785 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
1786 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
1787 if (hres) return hres;
1789 TRACE("Retrieved GIT (%p)\n", *ppv);
1794 * Get a class factory to construct the object we want.
1796 hres = CoGetClassObject(rclsid,
1803 FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n",
1804 debugstr_guid(rclsid),hres);
1809 * Create the object and don't forget to release the factory
1811 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
1812 IClassFactory_Release(lpclf);
1814 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1815 debugstr_guid(iid), debugstr_guid(rclsid),hres);
1820 /***********************************************************************
1821 * CoCreateInstanceEx [OLE32.@]
1823 HRESULT WINAPI CoCreateInstanceEx(
1825 LPUNKNOWN pUnkOuter,
1827 COSERVERINFO* pServerInfo,
1831 IUnknown* pUnk = NULL;
1834 ULONG successCount = 0;
1839 if ( (cmq==0) || (pResults==NULL))
1840 return E_INVALIDARG;
1842 if (pServerInfo!=NULL)
1843 FIXME("() non-NULL pServerInfo not supported!\n");
1846 * Initialize all the "out" parameters.
1848 for (index = 0; index < cmq; index++)
1850 pResults[index].pItf = NULL;
1851 pResults[index].hr = E_NOINTERFACE;
1855 * Get the object and get its IUnknown pointer.
1857 hr = CoCreateInstance(rclsid,
1867 * Then, query for all the interfaces requested.
1869 for (index = 0; index < cmq; index++)
1871 pResults[index].hr = IUnknown_QueryInterface(pUnk,
1872 pResults[index].pIID,
1873 (VOID**)&(pResults[index].pItf));
1875 if (pResults[index].hr == S_OK)
1880 * Release our temporary unknown pointer.
1882 IUnknown_Release(pUnk);
1884 if (successCount == 0)
1885 return E_NOINTERFACE;
1887 if (successCount!=cmq)
1888 return CO_S_NOTALLINTERFACES;
1893 /***********************************************************************
1894 * CoLoadLibrary (OLE32.@)
1899 * lpszLibName [I] Path to library.
1900 * bAutoFree [I] Whether the library should automatically be freed.
1903 * Success: Handle to loaded library.
1907 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1909 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
1911 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
1913 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
1916 /***********************************************************************
1917 * CoFreeLibrary [OLE32.@]
1919 * Unloads a library from memory.
1922 * hLibrary [I] Handle to library to unload.
1928 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1930 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
1932 FreeLibrary(hLibrary);
1936 /***********************************************************************
1937 * CoFreeAllLibraries [OLE32.@]
1939 * Function for backwards compatibility only. Does nothing.
1945 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
1947 void WINAPI CoFreeAllLibraries(void)
1953 /***********************************************************************
1954 * CoFreeUnusedLibraries [OLE32.@]
1955 * CoFreeUnusedLibraries [COMPOBJ.17]
1957 * Frees any unused libraries. Unused are identified as those that return
1958 * S_OK from their DllCanUnloadNow function.
1964 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
1966 void WINAPI CoFreeUnusedLibraries(void)
1968 /* FIXME: Calls to CoFreeUnusedLibraries from any thread always route
1969 * through the main apartment's thread to call DllCanUnloadNow */
1970 COMPOBJ_DllList_FreeUnused(0);
1973 /***********************************************************************
1974 * CoFileTimeNow [OLE32.@]
1975 * CoFileTimeNow [COMPOBJ.82]
1977 * Retrieves the current time in FILETIME format.
1980 * lpFileTime [O] The current time.
1985 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
1987 GetSystemTimeAsFileTime( lpFileTime );
1991 static void COM_RevokeAllClasses()
1993 EnterCriticalSection( &csRegisteredClassList );
1995 while (firstRegisteredClass!=0)
1997 CoRevokeClassObject(firstRegisteredClass->dwCookie);
2000 LeaveCriticalSection( &csRegisteredClassList );
2003 /******************************************************************************
2004 * CoLockObjectExternal [OLE32.@]
2006 * Increments or decrements the external reference count of a stub object.
2009 * pUnk [I] Stub object.
2010 * fLock [I] If TRUE then increments the external ref-count,
2011 * otherwise decrements.
2012 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2013 * calling CoDisconnectObject.
2017 * Failure: HRESULT code.
2019 HRESULT WINAPI CoLockObjectExternal(
2022 BOOL fLastUnlockReleases)
2024 struct stub_manager *stubmgr;
2025 struct apartment *apt;
2027 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2028 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2030 apt = COM_CurrentApt();
2031 if (!apt) return CO_E_NOTINITIALIZED;
2033 stubmgr = get_stub_manager_from_object(apt, pUnk);
2038 stub_manager_ext_addref(stubmgr, 1);
2040 stub_manager_ext_release(stubmgr, 1);
2042 stub_manager_int_release(stubmgr);
2048 WARN("stub object not found %p\n", pUnk);
2049 /* Note: native is pretty broken here because it just silently
2050 * fails, without returning an appropriate error code, making apps
2051 * think that the object was disconnected, when it actually wasn't */
2056 /***********************************************************************
2057 * CoInitializeWOW (OLE32.@)
2059 * WOW equivalent of CoInitialize?
2068 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2070 FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
2074 /***********************************************************************
2075 * CoGetState [OLE32.@]
2077 * Retrieves the thread state object previously stored by CoSetState().
2080 * ppv [I] Address where pointer to object will be stored.
2084 * Failure: E_OUTOFMEMORY.
2087 * Crashes on all invalid ppv addresses, including NULL.
2088 * If the function returns a non-NULL object then the caller must release its
2089 * reference on the object when the object is no longer required.
2094 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2096 struct oletls *info = COM_CurrentInfo();
2097 if (!info) return E_OUTOFMEMORY;
2103 IUnknown_AddRef(info->state);
2105 TRACE("apt->state=%p\n", info->state);
2111 /***********************************************************************
2112 * CoSetState [OLE32.@]
2114 * Sets the thread state object.
2117 * pv [I] Pointer to state object to be stored.
2120 * The system keeps a reference on the object while the object stored.
2124 * Failure: E_OUTOFMEMORY.
2126 HRESULT WINAPI CoSetState(IUnknown * pv)
2128 struct oletls *info = COM_CurrentInfo();
2129 if (!info) return E_OUTOFMEMORY;
2131 if (pv) IUnknown_AddRef(pv);
2135 TRACE("-- release %p now\n", info->state);
2136 IUnknown_Release(info->state);
2145 /******************************************************************************
2146 * OleGetAutoConvert [OLE32.@]
2148 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2156 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2157 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2159 res = REGDB_E_CLASSNOTREG;
2163 /* we can just query for the default value of AutoConvertTo key like that,
2164 without opening the AutoConvertTo key and querying for NULL (default) */
2165 if (RegQueryValueA(hkey,"AutoConvertTo",buf,&len))
2167 res = REGDB_E_KEYMISSING;
2170 MultiByteToWideChar( CP_ACP, 0, buf, -1, wbuf, sizeof(wbuf)/sizeof(WCHAR) );
2171 CLSIDFromString(wbuf,pClsidNew);
2173 if (hkey) RegCloseKey(hkey);
2177 /******************************************************************************
2178 * CoTreatAsClass [OLE32.@]
2180 * Sets the TreatAs value of a class.
2183 * clsidOld [I] Class to set TreatAs value on.
2184 * clsidNew [I] The class the clsidOld should be treated as.
2188 * Failure: HRESULT code.
2193 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2197 char szClsidNew[39];
2199 char auto_treat_as[39];
2200 LONG auto_treat_as_size = sizeof(auto_treat_as);
2203 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2204 WINE_StringFromCLSID(clsidNew, szClsidNew);
2205 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2207 res = REGDB_E_CLASSNOTREG;
2210 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2212 if (!RegQueryValueA(hkey, "AutoTreatAs", auto_treat_as, &auto_treat_as_size) &&
2213 !__CLSIDFromStringA(auto_treat_as, &id))
2215 if (RegSetValueA(hkey, "TreatAs", REG_SZ, auto_treat_as, strlen(auto_treat_as)+1))
2217 res = REGDB_E_WRITEREGDB;
2223 RegDeleteKeyA(hkey, "TreatAs");
2227 else if (RegSetValueA(hkey, "TreatAs", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
2229 res = REGDB_E_WRITEREGDB;
2234 if (hkey) RegCloseKey(hkey);
2238 /******************************************************************************
2239 * CoGetTreatAsClass [OLE32.@]
2241 * Gets the TreatAs value of a class.
2244 * clsidOld [I] Class to get the TreatAs value of.
2245 * clsidNew [I] The class the clsidOld should be treated as.
2249 * Failure: HRESULT code.
2254 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2257 char buf[200], szClsidNew[200];
2259 LONG len = sizeof(szClsidNew);
2261 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2262 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2263 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2265 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2267 res = REGDB_E_CLASSNOTREG;
2270 if (RegQueryValueA(hkey, "TreatAs", szClsidNew, &len))
2275 res = __CLSIDFromStringA(szClsidNew,clsidNew);
2277 FIXME("Failed CLSIDFromStringA(%s), hres %lx?\n",szClsidNew,res);
2279 if (hkey) RegCloseKey(hkey);
2284 /******************************************************************************
2285 * CoGetCurrentProcess [OLE32.@]
2286 * CoGetCurrentProcess [COMPOBJ.34]
2288 * Gets the current process ID.
2291 * The current process ID.
2294 * Is DWORD really the correct return type for this function?
2296 DWORD WINAPI CoGetCurrentProcess(void)
2298 return GetCurrentProcessId();
2301 /******************************************************************************
2302 * CoRegisterMessageFilter [OLE32.@]
2304 * Registers a message filter.
2307 * lpMessageFilter [I] Pointer to interface.
2308 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2312 * Failure: HRESULT code.
2314 HRESULT WINAPI CoRegisterMessageFilter(
2315 LPMESSAGEFILTER lpMessageFilter,
2316 LPMESSAGEFILTER *lplpMessageFilter)
2319 if (lplpMessageFilter) {
2320 *lplpMessageFilter = NULL;
2325 /***********************************************************************
2326 * CoIsOle1Class [OLE32.@]
2328 * Determines whether the specified class an OLE v1 class.
2331 * clsid [I] Class to test.
2334 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
2336 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
2338 FIXME("%s\n", debugstr_guid(clsid));
2342 /***********************************************************************
2343 * IsEqualGUID [OLE32.@]
2345 * Compares two Unique Identifiers.
2348 * rguid1 [I] The first GUID to compare.
2349 * rguid2 [I] The other GUID to compare.
2355 BOOL WINAPI IsEqualGUID(
2359 return !memcmp(rguid1,rguid2,sizeof(GUID));
2362 /***********************************************************************
2363 * CoInitializeSecurity [OLE32.@]
2365 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2366 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2367 void* pReserved1, DWORD dwAuthnLevel,
2368 DWORD dwImpLevel, void* pReserved2,
2369 DWORD dwCapabilities, void* pReserved3)
2371 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
2372 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2373 dwCapabilities, pReserved3);
2377 /***********************************************************************
2378 * CoSuspendClassObjects [OLE32.@]
2380 * Suspends all registered class objects to prevent further requests coming in
2381 * for those objects.
2385 * Failure: HRESULT code.
2387 HRESULT WINAPI CoSuspendClassObjects(void)
2393 /***********************************************************************
2394 * CoAddRefServerProcess [OLE32.@]
2396 * Helper function for incrementing the reference count of a local-server
2400 * New reference count.
2402 ULONG WINAPI CoAddRefServerProcess(void)
2408 /***********************************************************************
2409 * CoReleaseServerProcess [OLE32.@]
2411 * Helper function for decrementing the reference count of a local-server
2415 * New reference count.
2417 ULONG WINAPI CoReleaseServerProcess(void)
2423 /***********************************************************************
2424 * CoQueryProxyBlanket [OLE32.@]
2426 * Retrieves the security settings being used by a proxy.
2429 * pProxy [I] Pointer to the proxy object.
2430 * pAuthnSvc [O] The type of authentication service.
2431 * pAuthzSvc [O] The type of authorization service.
2432 * ppServerPrincName [O] Optional. The server prinicple name.
2433 * pAuthnLevel [O] The authentication level.
2434 * pImpLevel [O] The impersonation level.
2435 * ppAuthInfo [O] Information specific to the authorization/authentication service.
2436 * pCapabilities [O] Flags affecting the security behaviour.
2440 * Failure: HRESULT code.
2443 * CoCopyProxy, CoSetProxyBlanket.
2445 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
2446 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
2447 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
2449 IClientSecurity *pCliSec;
2452 TRACE("%p\n", pProxy);
2454 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2457 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
2458 pAuthzSvc, ppServerPrincName,
2459 pAuthnLevel, pImpLevel, ppAuthInfo,
2461 IClientSecurity_Release(pCliSec);
2464 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2468 /***********************************************************************
2469 * CoSetProxyBlanket [OLE32.@]
2471 * Sets the security settings for a proxy.
2474 * pProxy [I] Pointer to the proxy object.
2475 * AuthnSvc [I] The type of authentication service.
2476 * AuthzSvc [I] The type of authorization service.
2477 * pServerPrincName [I] The server prinicple name.
2478 * AuthnLevel [I] The authentication level.
2479 * ImpLevel [I] The impersonation level.
2480 * pAuthInfo [I] Information specific to the authorization/authentication service.
2481 * Capabilities [I] Flags affecting the security behaviour.
2485 * Failure: HRESULT code.
2488 * CoQueryProxyBlanket, CoCopyProxy.
2490 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
2491 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
2492 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
2494 IClientSecurity *pCliSec;
2497 TRACE("%p\n", pProxy);
2499 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2502 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
2503 AuthzSvc, pServerPrincName,
2504 AuthnLevel, ImpLevel, pAuthInfo,
2506 IClientSecurity_Release(pCliSec);
2509 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2513 /***********************************************************************
2514 * CoCopyProxy [OLE32.@]
2519 * pProxy [I] Pointer to the proxy object.
2520 * ppCopy [O] Copy of the proxy.
2524 * Failure: HRESULT code.
2527 * CoQueryProxyBlanket, CoSetProxyBlanket.
2529 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
2531 IClientSecurity *pCliSec;
2534 TRACE("%p\n", pProxy);
2536 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2539 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
2540 IClientSecurity_Release(pCliSec);
2543 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);