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[] = {'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 )
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
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;
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 /******************************************************************************
214 /* allocates memory and fills in the necessary fields for a new apartment
216 static APARTMENT *apartment_construct(DWORD model)
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);
232 apt->remunk_exported = FALSE;
234 InitializeCriticalSection(&apt->cs);
235 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
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,
245 0, 0, OLE32_hInstance, NULL);
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);
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();
273 if (model & COINIT_APARTMENTTHREADED)
275 apt = apartment_construct(model);
276 COM_CurrentInfo()->apt = apt;
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
287 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
288 apartment_addref(MTA);
291 MTA = apartment_construct(model);
294 COM_CurrentInfo()->apt = apt;
296 LeaveCriticalSection(&csApartment);
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);
310 DWORD apartment_release(struct apartment *apt)
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 */
321 if (apt == MTA) MTA = NULL;
322 list_remove(&apt->entry);
325 LeaveCriticalSection(&csApartment);
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);
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;
378 EnterCriticalSection(&csApartment);
379 LIST_FOR_EACH( cursor, &apts )
381 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
382 if (apt->oxid == oxid)
385 if (ref) apartment_addref(result);
389 LeaveCriticalSection(&csApartment);
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;
402 EnterCriticalSection(&csApartment);
403 LIST_FOR_EACH( cursor, &apts )
405 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
409 apartment_addref(result);
413 LeaveCriticalSection(&csApartment);
418 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
423 return RPC_ExecuteCall((struct dispatch_params *)lParam);
425 return DefWindowProcW(hWnd, msg, wParam, lParam);
429 /*****************************************************************************
430 * This section contains OpenDllList implemantation
433 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
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;
448 /* search for this dll */
450 for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
451 if (ptr->hLibrary == hLibrary) {
457 /* dll not found, add it */
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;
476 EnterCriticalSection( &csOpenDllList );
478 for (curr = openDllList; curr != NULL; ) {
479 DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
481 if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
484 TRACE("freeing %p\n", curr->hLibrary);
485 FreeLibrary(curr->hLibrary);
487 HeapFree(GetProcessHeap(), 0, curr);
488 if (curr == openDllList) {
501 LeaveCriticalSection( &csOpenDllList );
504 /******************************************************************************
505 * CoBuildVersion [OLE32.@]
506 * CoBuildVersion [COMPOBJ.1]
508 * Gets the build version of the DLL.
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.
528 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
531 * Success: S_OK if not already initialized, S_FALSE otherwise.
532 * Failure: HRESULT code.
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.
551 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
552 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
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
562 * The behavior used to set the IMalloc used for memory management is
564 * The dwCoInit parameter must specify of of the following apartment
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.
575 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
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;
619 COM_CurrentInfo()->inits++;
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)
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);
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.
665 void WINAPI CoUninitialize(void)
667 struct oletls * info = COM_CurrentInfo();
672 /* will only happen on OOM */
678 ERR("Mismatched CoUninitialize\n");
684 apartment_release(info->apt);
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);
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
727 * lpUnk [I] The object whose stub should be disconnected.
728 * reserved [I] Reserved. Should be set to 0.
732 * Failure: HRESULT code.
735 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
737 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
743 TRACE("(%p, 0x%08lx)\n", lpUnk, reserved);
745 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
748 hr = IMarshal_DisconnectObject(marshal, reserved);
749 IMarshal_Release(marshal);
753 apt = COM_CurrentApt();
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 */
767 /******************************************************************************
768 * CoCreateGuid [OLE32.@]
770 * Simply forwards to UuidCreate in RPCRT4.
773 * pguid [O] Points to the GUID to initialize.
777 * Failure: HRESULT code.
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
795 * idstr [I] The string representation of the GUID.
796 * id [O] GUID converted from the string.
800 * CO_E_CLASSSTRING if idstr is not a valid CLSID
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.
811 HRESULT WINAPI __CLSIDFromStringA(LPCSTR idstr, CLSID *id)
813 const BYTE *s = (const BYTE *) idstr;
818 s = "{00000000-0000-0000-0000-000000000000}";
819 else { /* validate the CLSID string */
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++) {
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]];
869 /*****************************************************************************/
871 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
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);
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";
897 { ERR("called with id=Null\n");
902 sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
903 id->Data1, id->Data2, id->Data3,
904 id->Data4[0], id->Data4[1]);
908 for (i = 2; i < 8; i++) {
909 *s++ = hex[id->Data4[i]>>4];
910 *s++ = hex[id->Data4[i] & 0xf];
916 TRACE("%p->%s\n", id, idstr);
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.
930 * id [I] the GUID to be converted.
931 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
938 * StringFromGUID2, CLSIDFromString
940 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
946 if ((ret = CoGetMalloc(0,&mllc)))
949 ret=WINE_StringFromCLSID(id,buf);
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 );
958 /******************************************************************************
959 * StringFromGUID2 [OLE32.@]
960 * StringFromGUID2 [COMPOBJ.76]
962 * Modified version of StringFromCLSID that allows you to specify max
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.
971 * Success: The length of the resulting string in characters.
974 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
978 if (WINE_StringFromCLSID(id,xguid))
980 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
983 /******************************************************************************
984 * ProgIDFromCLSID [OLE32.@]
986 * Converts a class id into the respective program ID.
989 * clsid [I] Class ID, as found in registry.
990 * lplpszProgID [O] Associated ProgID.
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;
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);
1016 buf2 = HeapAlloc(GetProcessHeap(), 0, 255);
1018 if (RegQueryValueA(xhkey, NULL, buf2, &buf2len))
1019 ret = REGDB_E_CLASSNOTREG;
1023 if (CoGetMalloc(0,&mllc))
1024 ret = E_OUTOFMEMORY;
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);
1039 HRESULT WINAPI CLSIDFromProgID16(
1040 LPCOLESTR16 progid, /* [in] program id as found in registry */
1041 LPCLSID riid /* [out] associated CLSID */
1048 buf = HeapAlloc(GetProcessHeap(),0,strlen(progid)+8);
1049 sprintf(buf,"%s\\CLSID",progid);
1050 if ((err=RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&xhkey))) {
1051 HeapFree(GetProcessHeap(),0,buf);
1052 return CO_E_CLASSSTRING;
1054 HeapFree(GetProcessHeap(),0,buf);
1055 buf2len = sizeof(buf2);
1056 if ((err=RegQueryValueA(xhkey,NULL,buf2,&buf2len))) {
1058 return CO_E_CLASSSTRING;
1061 return __CLSIDFromStringA(buf2,riid);
1064 /******************************************************************************
1065 * CLSIDFromProgID [OLE32.@]
1066 * CLSIDFromProgID [COMPOBJ.61]
1068 * Converts a program id into the respective GUID.
1071 * progid [I] Unicode program ID, as found in registry.
1072 * riid [O] Associated CLSID.
1076 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1078 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID riid)
1080 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1082 DWORD buf2len = sizeof(buf2);
1085 WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1086 strcpyW( buf, progid );
1087 strcatW( buf, clsidW );
1088 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1090 HeapFree(GetProcessHeap(),0,buf);
1091 return CO_E_CLASSSTRING;
1093 HeapFree(GetProcessHeap(),0,buf);
1095 if (RegQueryValueA(xhkey,NULL,buf2,&buf2len))
1098 return CO_E_CLASSSTRING;
1101 return __CLSIDFromStringA(buf2,riid);
1106 /*****************************************************************************
1107 * CoGetPSClsid [OLE32.@]
1109 * Retrieves the CLSID of the proxy/stub factory that implements
1110 * IPSFactoryBuffer for the specified interface.
1113 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1114 * pclsid [O] Where to store returned proxy/stub CLSID.
1119 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1123 * The standard marshaller activates the object with the CLSID
1124 * returned and uses the CreateProxy and CreateStub methods on its
1125 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1128 * CoGetPSClsid determines this CLSID by searching the
1129 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1130 * in the registry and any interface id registered by
1131 * CoRegisterPSClsid within the current process.
1135 * We only search the registry, not ids registered with
1136 * CoRegisterPSClsid.
1137 * Also, native returns S_OK for interfaces with an key in HKCR\Interface, but
1138 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1139 * considered a bug in native unless an application depends on this (unlikely).
1141 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1143 char *buf, buf2[40];
1147 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1149 /* Get the input iid as a string */
1150 WINE_StringFromCLSID(riid, buf2);
1151 /* Allocate memory for the registry key we will construct.
1152 (length of iid string plus constant length of static text */
1153 buf = HeapAlloc(GetProcessHeap(), 0, strlen(buf2)+27);
1155 return E_OUTOFMEMORY;
1157 /* Construct the registry key we want */
1158 sprintf(buf,"Interface\\%s\\ProxyStubClsid32", buf2);
1160 /* Open the key.. */
1161 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
1163 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1164 HeapFree(GetProcessHeap(),0,buf);
1165 return REGDB_E_IIDNOTREG;
1167 HeapFree(GetProcessHeap(),0,buf);
1169 /* ... Once we have the key, query the registry to get the
1170 value of CLSID as a string, and convert it into a
1171 proper CLSID structure to be passed back to the app */
1172 buf2len = sizeof(buf2);
1173 if ( (RegQueryValueA(xhkey,NULL,buf2,&buf2len)) )
1176 return REGDB_E_IIDNOTREG;
1180 /* We have the CLSid we want back from the registry as a string, so
1181 lets convert it into a CLSID structure */
1182 if ( (__CLSIDFromStringA(buf2,pclsid)) != NOERROR)
1183 return REGDB_E_IIDNOTREG;
1185 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1191 /***********************************************************************
1192 * WriteClassStm (OLE32.@)
1194 * Writes a CLSID to a stream.
1197 * pStm [I] Stream to write to.
1198 * rclsid [I] CLSID to write.
1202 * Failure: HRESULT code.
1204 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
1206 TRACE("(%p,%p)\n",pStm,rclsid);
1209 return E_INVALIDARG;
1211 return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
1214 /***********************************************************************
1215 * ReadClassStm (OLE32.@)
1217 * Reads a CLSID from a stream.
1220 * pStm [I] Stream to read from.
1221 * rclsid [O] CLSID to read.
1225 * Failure: HRESULT code.
1227 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
1232 TRACE("(%p,%p)\n",pStm,pclsid);
1235 return E_INVALIDARG;
1237 res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
1242 if (nbByte != sizeof(CLSID))
1250 * COM_GetRegisteredClassObject
1252 * This internal method is used to scan the registered class list to
1253 * find a class object.
1256 * rclsid Class ID of the class to find.
1257 * dwClsContext Class context to match.
1258 * ppv [out] returns a pointer to the class object. Complying
1259 * to normal COM usage, this method will increase the
1260 * reference count on this object.
1262 static HRESULT COM_GetRegisteredClassObject(
1267 HRESULT hr = S_FALSE;
1268 RegisteredClass* curClass;
1270 EnterCriticalSection( &csRegisteredClassList );
1278 * Iterate through the whole list and try to match the class ID.
1280 curClass = firstRegisteredClass;
1282 while (curClass != 0)
1285 * Check if we have a match on the class ID.
1287 if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
1290 * Since we don't do out-of process or DCOM just right away, let's ignore the
1295 * We have a match, return the pointer to the class object.
1297 *ppUnk = curClass->classObject;
1299 IUnknown_AddRef(curClass->classObject);
1306 * Step to the next class in the list.
1308 curClass = curClass->nextClass;
1312 LeaveCriticalSection( &csRegisteredClassList );
1314 * If we get to here, we haven't found our class.
1319 /******************************************************************************
1320 * CoRegisterClassObject [OLE32.@]
1322 * Registers the class object for a given class ID. Servers housed in EXE
1323 * files use this method instead of exporting DllGetClassObject to allow
1324 * other code to connect to their objects.
1327 * rclsid [I] CLSID of the object to register.
1328 * pUnk [I] IUnknown of the object.
1329 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1330 * flags [I] REGCLS flags indicating how connections are made.
1331 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1335 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1336 * CO_E_OBJISREG if the object is already registered. We should not return this.
1339 * CoRevokeClassObject, CoGetClassObject
1342 * MSDN claims that multiple interface registrations are legal, but we
1343 * can't do that with our current implementation.
1345 HRESULT WINAPI CoRegisterClassObject(
1350 LPDWORD lpdwRegister)
1352 RegisteredClass* newClass;
1353 LPUNKNOWN foundObject;
1356 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1357 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1359 if ( (lpdwRegister==0) || (pUnk==0) )
1360 return E_INVALIDARG;
1362 if (!COM_CurrentApt())
1364 ERR("COM was not initialized\n");
1365 return CO_E_NOTINITIALIZED;
1371 * First, check if the class is already registered.
1372 * If it is, this should cause an error.
1374 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1376 IUnknown_Release(foundObject);
1377 return CO_E_OBJISREG;
1380 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1381 if ( newClass == NULL )
1382 return E_OUTOFMEMORY;
1384 EnterCriticalSection( &csRegisteredClassList );
1386 newClass->classIdentifier = *rclsid;
1387 newClass->runContext = dwClsContext;
1388 newClass->connectFlags = flags;
1390 * Use the address of the chain node as the cookie since we are sure it's
1391 * unique. FIXME: not on 64-bit platforms.
1393 newClass->dwCookie = (DWORD)newClass;
1394 newClass->nextClass = firstRegisteredClass;
1397 * Since we're making a copy of the object pointer, we have to increase its
1400 newClass->classObject = pUnk;
1401 IUnknown_AddRef(newClass->classObject);
1403 firstRegisteredClass = newClass;
1404 LeaveCriticalSection( &csRegisteredClassList );
1406 *lpdwRegister = newClass->dwCookie;
1408 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1409 IClassFactory *classfac;
1411 hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory,
1412 (LPVOID*)&classfac);
1415 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
1417 FIXME("Failed to create stream on hglobal, %lx\n", hr);
1418 IUnknown_Release(classfac);
1421 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
1422 (LPVOID)classfac, MSHCTX_LOCAL, NULL,
1423 MSHLFLAGS_TABLESTRONG);
1425 FIXME("CoMarshalInterface failed, %lx!\n",hr);
1426 IUnknown_Release(classfac);
1430 IUnknown_Release(classfac);
1432 RPC_StartLocalServer(&newClass->classIdentifier, newClass->pMarshaledData);
1437 /***********************************************************************
1438 * CoRevokeClassObject [OLE32.@]
1440 * Removes a class object from the class registry.
1443 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1447 * Failure: HRESULT code.
1450 * CoRegisterClassObject
1452 HRESULT WINAPI CoRevokeClassObject(
1455 HRESULT hr = E_INVALIDARG;
1456 RegisteredClass** prevClassLink;
1457 RegisteredClass* curClass;
1459 TRACE("(%08lx)\n",dwRegister);
1461 EnterCriticalSection( &csRegisteredClassList );
1464 * Iterate through the whole list and try to match the cookie.
1466 curClass = firstRegisteredClass;
1467 prevClassLink = &firstRegisteredClass;
1469 while (curClass != 0)
1472 * Check if we have a match on the cookie.
1474 if (curClass->dwCookie == dwRegister)
1477 * Remove the class from the chain.
1479 *prevClassLink = curClass->nextClass;
1482 * Release the reference to the class object.
1484 IUnknown_Release(curClass->classObject);
1486 if (curClass->pMarshaledData)
1489 memset(&zero, 0, sizeof(zero));
1490 /* FIXME: stop local server thread */
1491 IStream_Seek(curClass->pMarshaledData, zero, SEEK_SET, NULL);
1492 CoReleaseMarshalData(curClass->pMarshaledData);
1496 * Free the memory used by the chain node.
1498 HeapFree(GetProcessHeap(), 0, curClass);
1505 * Step to the next class in the list.
1507 prevClassLink = &(curClass->nextClass);
1508 curClass = curClass->nextClass;
1512 LeaveCriticalSection( &csRegisteredClassList );
1514 * If we get to here, we haven't found our class.
1519 /***********************************************************************
1520 * compobj_RegReadPath [internal]
1522 * Reads a registry value and expands it when necessary
1524 HRESULT compobj_RegReadPath(char * keyname, char * valuename, char * dst, DWORD dstlen)
1530 DWORD dwLength = dstlen;
1532 if((hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1533 if( (hres = RegQueryValueExA(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1534 if (keytype == REG_EXPAND_SZ) {
1535 if (dstlen <= ExpandEnvironmentStringsA(src, dst, dstlen)) hres = ERROR_MORE_DATA;
1537 lstrcpynA(dst, src, dstlen);
1545 /***********************************************************************
1546 * CoGetClassObject [COMPOBJ.7]
1547 * CoGetClassObject [OLE32.@]
1549 * FIXME. If request allows of several options and there is a failure
1550 * with one (other than not being registered) do we try the
1551 * others or return failure? (E.g. inprocess is registered but
1552 * the DLL is not found but the server version works)
1554 HRESULT WINAPI CoGetClassObject(
1555 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1556 REFIID iid, LPVOID *ppv
1558 LPUNKNOWN regClassObject;
1559 HRESULT hres = E_UNEXPECTED;
1562 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1563 DllGetClassObjectFunc DllGetClassObject;
1565 WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
1567 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1570 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1571 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1575 * First, try and see if we can't match the class ID with one of the
1576 * registered classes.
1578 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, ®ClassObject))
1581 * Get the required interface from the retrieved pointer.
1583 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1586 * Since QI got another reference on the pointer, we want to release the
1587 * one we already have. If QI was unsuccessful, this will release the object. This
1588 * is good since we are not returning it in the "out" parameter.
1590 IUnknown_Release(regClassObject);
1595 /* first try: in-process */
1596 if ((CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER) & dwClsContext) {
1597 char keyname[MAX_PATH];
1598 char dllpath[MAX_PATH+1];
1600 sprintf(keyname,"CLSID\\%s\\InprocServer32",xclsid);
1602 if ( compobj_RegReadPath(keyname, NULL, dllpath, sizeof(dllpath)) != ERROR_SUCCESS) {
1603 /* failure: CLSID is not found in registry */
1604 WARN("class %s not registered inproc\n", xclsid);
1605 hres = REGDB_E_CLASSNOTREG;
1607 if ((hLibrary = LoadLibraryExA(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) {
1608 /* failure: DLL could not be loaded */
1609 ERR("couldn't load InprocServer32 dll %s\n", dllpath);
1610 hres = E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1611 } else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject"))) {
1612 /* failure: the dll did not export DllGetClassObject */
1613 ERR("couldn't find function DllGetClassObject in %s\n", dllpath);
1614 FreeLibrary( hLibrary );
1615 hres = CO_E_DLLNOTFOUND;
1617 /* OK: get the ClassObject */
1618 COMPOBJ_DLLList_Add( hLibrary );
1619 return DllGetClassObject(rclsid, iid, ppv);
1624 /* Next try out of process */
1625 if (CLSCTX_LOCAL_SERVER & dwClsContext)
1627 return RPC_GetLocalClassObject(rclsid,iid,ppv);
1630 /* Finally try remote: this requires networked DCOM (a lot of work) */
1631 if (CLSCTX_REMOTE_SERVER & dwClsContext)
1633 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1634 hres = E_NOINTERFACE;
1639 /***********************************************************************
1640 * CoResumeClassObjects (OLE32.@)
1642 * Resumes all class objects registered with REGCLS_SUSPENDED.
1646 * Failure: HRESULT code.
1648 HRESULT WINAPI CoResumeClassObjects(void)
1654 /***********************************************************************
1655 * GetClassFile (OLE32.@)
1657 * This function supplies the CLSID associated with the given filename.
1659 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1663 int nbElm, length, i;
1665 LPOLESTR *pathDec=0,absFile=0,progId=0;
1667 static const WCHAR bkslashW[] = {'\\',0};
1668 static const WCHAR dotW[] = {'.',0};
1670 TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1672 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1673 if((StgIsStorageFile(filePathName))==S_OK){
1675 res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1678 res=ReadClassStg(pstg,pclsid);
1680 IStorage_Release(pstg);
1684 /* if the file is not a storage object then attemps to match various bits in the file against a
1685 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1688 for(i=0;i<nFileTypes;i++)
1690 for(i=0;j<nPatternsForType;j++){
1695 pat=ReadPatternFromRegistry(i,j);
1696 hFile=CreateFileW(filePathName,,,,,,hFile);
1697 SetFilePosition(hFile,pat.offset);
1698 ReadFile(hFile,buf,pat.size,&r,NULL);
1699 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1701 *pclsid=ReadCLSIDFromRegistry(i);
1707 /* if the above strategies fail then search for the extension key in the registry */
1709 /* get the last element (absolute file) in the path name */
1710 nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1711 absFile=pathDec[nbElm-1];
1713 /* failed if the path represente a directory and not an absolute file name*/
1714 if (!lstrcmpW(absFile, bkslashW))
1715 return MK_E_INVALIDEXTENSION;
1717 /* get the extension of the file */
1719 length=lstrlenW(absFile);
1720 for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1723 if (!extension || !lstrcmpW(extension, dotW))
1724 return MK_E_INVALIDEXTENSION;
1726 res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1728 /* get the progId associated to the extension */
1729 progId = CoTaskMemAlloc(sizeProgId);
1730 res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1732 if (res==ERROR_SUCCESS)
1733 /* return the clsid associated to the progId */
1734 res= CLSIDFromProgID(progId,pclsid);
1736 for(i=0; pathDec[i]!=NULL;i++)
1737 CoTaskMemFree(pathDec[i]);
1738 CoTaskMemFree(pathDec);
1740 CoTaskMemFree(progId);
1742 if (res==ERROR_SUCCESS)
1745 return MK_E_INVALIDEXTENSION;
1747 /***********************************************************************
1748 * CoCreateInstance [COMPOBJ.13]
1749 * CoCreateInstance [OLE32.@]
1751 HRESULT WINAPI CoCreateInstance(
1753 LPUNKNOWN pUnkOuter,
1759 LPCLASSFACTORY lpclf = 0;
1761 if (!COM_CurrentApt()) return CO_E_NOTINITIALIZED;
1770 * Initialize the "out" parameter
1775 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1776 * Rather than create a class factory, we can just check for it here
1778 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
1779 if (StdGlobalInterfaceTableInstance == NULL)
1780 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
1781 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
1782 if (hres) return hres;
1784 TRACE("Retrieved GIT (%p)\n", *ppv);
1789 * Get a class factory to construct the object we want.
1791 hres = CoGetClassObject(rclsid,
1798 FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n",
1799 debugstr_guid(rclsid),hres);
1804 * Create the object and don't forget to release the factory
1806 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
1807 IClassFactory_Release(lpclf);
1809 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1810 debugstr_guid(iid), debugstr_guid(rclsid),hres);
1815 /***********************************************************************
1816 * CoCreateInstanceEx [OLE32.@]
1818 HRESULT WINAPI CoCreateInstanceEx(
1820 LPUNKNOWN pUnkOuter,
1822 COSERVERINFO* pServerInfo,
1826 IUnknown* pUnk = NULL;
1829 ULONG successCount = 0;
1834 if ( (cmq==0) || (pResults==NULL))
1835 return E_INVALIDARG;
1837 if (pServerInfo!=NULL)
1838 FIXME("() non-NULL pServerInfo not supported!\n");
1841 * Initialize all the "out" parameters.
1843 for (index = 0; index < cmq; index++)
1845 pResults[index].pItf = NULL;
1846 pResults[index].hr = E_NOINTERFACE;
1850 * Get the object and get its IUnknown pointer.
1852 hr = CoCreateInstance(rclsid,
1862 * Then, query for all the interfaces requested.
1864 for (index = 0; index < cmq; index++)
1866 pResults[index].hr = IUnknown_QueryInterface(pUnk,
1867 pResults[index].pIID,
1868 (VOID**)&(pResults[index].pItf));
1870 if (pResults[index].hr == S_OK)
1875 * Release our temporary unknown pointer.
1877 IUnknown_Release(pUnk);
1879 if (successCount == 0)
1880 return E_NOINTERFACE;
1882 if (successCount!=cmq)
1883 return CO_S_NOTALLINTERFACES;
1888 /***********************************************************************
1889 * CoLoadLibrary (OLE32.@)
1894 * lpszLibName [I] Path to library.
1895 * bAutoFree [I] Whether the library should automatically be freed.
1898 * Success: Handle to loaded library.
1902 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1904 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
1906 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
1908 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
1911 /***********************************************************************
1912 * CoFreeLibrary [OLE32.@]
1914 * Unloads a library from memory.
1917 * hLibrary [I] Handle to library to unload.
1923 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1925 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
1927 FreeLibrary(hLibrary);
1931 /***********************************************************************
1932 * CoFreeAllLibraries [OLE32.@]
1934 * Function for backwards compatibility only. Does nothing.
1940 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
1942 void WINAPI CoFreeAllLibraries(void)
1948 /***********************************************************************
1949 * CoFreeUnusedLibraries [OLE32.@]
1950 * CoFreeUnusedLibraries [COMPOBJ.17]
1952 * Frees any unused libraries. Unused are identified as those that return
1953 * S_OK from their DllCanUnloadNow function.
1959 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
1961 void WINAPI CoFreeUnusedLibraries(void)
1963 /* FIXME: Calls to CoFreeUnusedLibraries from any thread always route
1964 * through the main apartment's thread to call DllCanUnloadNow */
1965 COMPOBJ_DllList_FreeUnused(0);
1968 /***********************************************************************
1969 * CoFileTimeNow [OLE32.@]
1970 * CoFileTimeNow [COMPOBJ.82]
1972 * Retrieves the current time in FILETIME format.
1975 * lpFileTime [O] The current time.
1980 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
1982 GetSystemTimeAsFileTime( lpFileTime );
1986 static void COM_RevokeAllClasses()
1988 EnterCriticalSection( &csRegisteredClassList );
1990 while (firstRegisteredClass!=0)
1992 CoRevokeClassObject(firstRegisteredClass->dwCookie);
1995 LeaveCriticalSection( &csRegisteredClassList );
1998 /******************************************************************************
1999 * CoLockObjectExternal [OLE32.@]
2001 * Increments or decrements the external reference count of a stub object.
2004 * pUnk [I] Stub object.
2005 * fLock [I] If TRUE then increments the external ref-count,
2006 * otherwise decrements.
2007 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2008 * calling CoDisconnectObject.
2012 * Failure: HRESULT code.
2014 HRESULT WINAPI CoLockObjectExternal(
2017 BOOL fLastUnlockReleases)
2019 struct stub_manager *stubmgr;
2020 struct apartment *apt;
2022 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2023 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2025 apt = COM_CurrentApt();
2026 if (!apt) return CO_E_NOTINITIALIZED;
2028 stubmgr = get_stub_manager_from_object(apt, pUnk);
2033 stub_manager_ext_addref(stubmgr, 1);
2035 stub_manager_ext_release(stubmgr, 1);
2037 stub_manager_int_release(stubmgr);
2043 WARN("stub object not found %p\n", pUnk);
2044 /* Note: native is pretty broken here because it just silently
2045 * fails, without returning an appropriate error code, making apps
2046 * think that the object was disconnected, when it actually wasn't */
2051 /***********************************************************************
2052 * CoInitializeWOW (OLE32.@)
2054 * WOW equivalent of CoInitialize?
2063 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2065 FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
2069 /***********************************************************************
2070 * CoGetState [OLE32.@]
2072 * Retrieves the thread state object previously stored by CoSetState().
2075 * ppv [I] Address where pointer to object will be stored.
2079 * Failure: E_OUTOFMEMORY.
2082 * Crashes on all invalid ppv addresses, including NULL.
2083 * If the function returns a non-NULL object then the caller must release its
2084 * reference on the object when the object is no longer required.
2089 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2091 struct oletls *info = COM_CurrentInfo();
2092 if (!info) return E_OUTOFMEMORY;
2098 IUnknown_AddRef(info->state);
2100 TRACE("apt->state=%p\n", info->state);
2106 /***********************************************************************
2107 * CoSetState [OLE32.@]
2109 * Sets the thread state object.
2112 * pv [I] Pointer to state object to be stored.
2115 * The system keeps a reference on the object while the object stored.
2119 * Failure: E_OUTOFMEMORY.
2121 HRESULT WINAPI CoSetState(IUnknown * pv)
2123 struct oletls *info = COM_CurrentInfo();
2124 if (!info) return E_OUTOFMEMORY;
2126 if (pv) IUnknown_AddRef(pv);
2130 TRACE("-- release %p now\n", info->state);
2131 IUnknown_Release(info->state);
2140 /******************************************************************************
2141 * OleGetAutoConvert [OLE32.@]
2143 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2151 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2152 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2154 res = REGDB_E_CLASSNOTREG;
2158 /* we can just query for the default value of AutoConvertTo key like that,
2159 without opening the AutoConvertTo key and querying for NULL (default) */
2160 if (RegQueryValueA(hkey,"AutoConvertTo",buf,&len))
2162 res = REGDB_E_KEYMISSING;
2165 MultiByteToWideChar( CP_ACP, 0, buf, -1, wbuf, sizeof(wbuf)/sizeof(WCHAR) );
2166 CLSIDFromString(wbuf,pClsidNew);
2168 if (hkey) RegCloseKey(hkey);
2172 /******************************************************************************
2173 * CoTreatAsClass [OLE32.@]
2175 * Sets the TreatAs value of a class.
2178 * clsidOld [I] Class to set TreatAs value on.
2179 * clsidNew [I] The class the clsidOld should be treated as.
2183 * Failure: HRESULT code.
2188 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2192 char szClsidNew[39];
2194 char auto_treat_as[39];
2195 LONG auto_treat_as_size = sizeof(auto_treat_as);
2198 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2199 WINE_StringFromCLSID(clsidNew, szClsidNew);
2200 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2202 res = REGDB_E_CLASSNOTREG;
2205 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2207 if (!RegQueryValueA(hkey, "AutoTreatAs", auto_treat_as, &auto_treat_as_size) &&
2208 !__CLSIDFromStringA(auto_treat_as, &id))
2210 if (RegSetValueA(hkey, "TreatAs", REG_SZ, auto_treat_as, strlen(auto_treat_as)+1))
2212 res = REGDB_E_WRITEREGDB;
2218 RegDeleteKeyA(hkey, "TreatAs");
2222 else if (RegSetValueA(hkey, "TreatAs", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
2224 res = REGDB_E_WRITEREGDB;
2229 if (hkey) RegCloseKey(hkey);
2233 /******************************************************************************
2234 * CoGetTreatAsClass [OLE32.@]
2236 * Gets the TreatAs value of a class.
2239 * clsidOld [I] Class to get the TreatAs value of.
2240 * clsidNew [I] The class the clsidOld should be treated as.
2244 * Failure: HRESULT code.
2249 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2252 char buf[200], szClsidNew[200];
2254 LONG len = sizeof(szClsidNew);
2256 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2257 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2258 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2260 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2262 res = REGDB_E_CLASSNOTREG;
2265 if (RegQueryValueA(hkey, "TreatAs", szClsidNew, &len))
2270 res = __CLSIDFromStringA(szClsidNew,clsidNew);
2272 FIXME("Failed CLSIDFromStringA(%s), hres %lx?\n",szClsidNew,res);
2274 if (hkey) RegCloseKey(hkey);
2279 /******************************************************************************
2280 * CoGetCurrentProcess [OLE32.@]
2281 * CoGetCurrentProcess [COMPOBJ.34]
2283 * Gets the current process ID.
2286 * The current process ID.
2289 * Is DWORD really the correct return type for this function?
2291 DWORD WINAPI CoGetCurrentProcess(void)
2293 return GetCurrentProcessId();
2296 /******************************************************************************
2297 * CoRegisterMessageFilter [OLE32.@]
2299 * Registers a message filter.
2302 * lpMessageFilter [I] Pointer to interface.
2303 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2307 * Failure: HRESULT code.
2309 HRESULT WINAPI CoRegisterMessageFilter(
2310 LPMESSAGEFILTER lpMessageFilter,
2311 LPMESSAGEFILTER *lplpMessageFilter)
2314 if (lplpMessageFilter) {
2315 *lplpMessageFilter = NULL;
2320 /***********************************************************************
2321 * CoIsOle1Class [OLE32.@]
2323 * Determines whether the specified class an OLE v1 class.
2326 * clsid [I] Class to test.
2329 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
2331 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
2333 FIXME("%s\n", debugstr_guid(clsid));
2337 /***********************************************************************
2338 * IsEqualGUID [OLE32.@]
2340 * Compares two Unique Identifiers.
2343 * rguid1 [I] The first GUID to compare.
2344 * rguid2 [I] The other GUID to compare.
2350 BOOL WINAPI IsEqualGUID(
2354 return !memcmp(rguid1,rguid2,sizeof(GUID));
2357 /***********************************************************************
2358 * CoInitializeSecurity [OLE32.@]
2360 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2361 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2362 void* pReserved1, DWORD dwAuthnLevel,
2363 DWORD dwImpLevel, void* pReserved2,
2364 DWORD dwCapabilities, void* pReserved3)
2366 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
2367 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2368 dwCapabilities, pReserved3);
2372 /***********************************************************************
2373 * CoSuspendClassObjects [OLE32.@]
2375 * Suspends all registered class objects to prevent further requests coming in
2376 * for those objects.
2380 * Failure: HRESULT code.
2382 HRESULT WINAPI CoSuspendClassObjects(void)
2388 /***********************************************************************
2389 * CoAddRefServerProcess [OLE32.@]
2391 * Helper function for incrementing the reference count of a local-server
2395 * New reference count.
2397 ULONG WINAPI CoAddRefServerProcess(void)
2403 /***********************************************************************
2404 * CoReleaseServerProcess [OLE32.@]
2406 * Helper function for decrementing the reference count of a local-server
2410 * New reference count.
2412 ULONG WINAPI CoReleaseServerProcess(void)
2418 /***********************************************************************
2419 * CoQueryProxyBlanket [OLE32.@]
2421 * Retrieves the security settings being used by a proxy.
2424 * pProxy [I] Pointer to the proxy object.
2425 * pAuthnSvc [O] The type of authentication service.
2426 * pAuthzSvc [O] The type of authorization service.
2427 * ppServerPrincName [O] Optional. The server prinicple name.
2428 * pAuthnLevel [O] The authentication level.
2429 * pImpLevel [O] The impersonation level.
2430 * ppAuthInfo [O] Information specific to the authorization/authentication service.
2431 * pCapabilities [O] Flags affecting the security behaviour.
2435 * Failure: HRESULT code.
2438 * CoCopyProxy, CoSetProxyBlanket.
2440 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
2441 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
2442 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
2444 IClientSecurity *pCliSec;
2447 TRACE("%p\n", pProxy);
2449 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2452 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
2453 pAuthzSvc, ppServerPrincName,
2454 pAuthnLevel, pImpLevel, ppAuthInfo,
2456 IClientSecurity_Release(pCliSec);
2459 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2463 /***********************************************************************
2464 * CoSetProxyBlanket [OLE32.@]
2466 * Sets the security settings for a proxy.
2469 * pProxy [I] Pointer to the proxy object.
2470 * AuthnSvc [I] The type of authentication service.
2471 * AuthzSvc [I] The type of authorization service.
2472 * pServerPrincName [I] The server prinicple name.
2473 * AuthnLevel [I] The authentication level.
2474 * ImpLevel [I] The impersonation level.
2475 * pAuthInfo [I] Information specific to the authorization/authentication service.
2476 * Capabilities [I] Flags affecting the security behaviour.
2480 * Failure: HRESULT code.
2483 * CoQueryProxyBlanket, CoCopyProxy.
2485 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
2486 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
2487 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
2489 IClientSecurity *pCliSec;
2492 TRACE("%p\n", pProxy);
2494 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2497 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
2498 AuthzSvc, pServerPrincName,
2499 AuthnLevel, ImpLevel, pAuthInfo,
2501 IClientSecurity_Release(pCliSec);
2504 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2508 /***********************************************************************
2509 * CoCopyProxy [OLE32.@]
2514 * pProxy [I] Pointer to the proxy object.
2515 * ppCopy [O] Copy of the proxy.
2519 * Failure: HRESULT code.
2522 * CoQueryProxyBlanket, CoSetProxyBlanket.
2524 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
2526 IClientSecurity *pCliSec;
2529 TRACE("%p\n", pProxy);
2531 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2534 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
2535 IClientSecurity_Release(pCliSec);
2538 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2543 /***********************************************************************
2544 * CoWaitForMultipleHandles [OLE32.@]
2546 * Waits for one or more handles to become signaled.
2549 * dwFlags [I] Flags. See notes.
2550 * dwTimeout [I] Timeout in milliseconds.
2551 * cHandles [I] Number of handles pointed to by pHandles.
2552 * pHandles [I] Handles to wait for.
2553 * lpdwindex [O] Index of handle that was signaled.
2557 * Failure: RPC_S_CALLPENDING on timeout.
2561 * The dwFlags parameter can be zero or more of the following:
2562 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
2563 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
2566 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
2568 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
2569 ULONG cHandles, const HANDLE* pHandles, LPDWORD lpdwindex)
2572 DWORD wait_flags = (dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0 |
2573 (dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0;
2574 DWORD start_time = GetTickCount();
2576 TRACE("(0x%08lx, 0x%08lx, %ld, %p, %p)\n", dwFlags, dwTimeout, cHandles,
2577 pHandles, lpdwindex);
2581 DWORD now = GetTickCount();
2584 if ((dwTimeout != INFINITE) && (start_time + dwTimeout >= now))
2586 hr = RPC_S_CALLPENDING;
2590 TRACE("waiting for rpc completion or window message\n");
2592 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
2593 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
2594 QS_ALLINPUT, wait_flags);
2596 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
2599 while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
2601 /* FIXME: filter the messages here */
2602 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
2603 TranslateMessage(&msg);
2604 DispatchMessageW(&msg);
2607 else if ((res >= WAIT_OBJECT_0) && (res < WAIT_OBJECT_0 + cHandles))
2609 /* handle signaled, store index */
2610 *lpdwindex = (res - WAIT_OBJECT_0);
2613 else if (res == WAIT_TIMEOUT)
2615 hr = RPC_S_CALLPENDING;
2620 ERR("Unexpected wait termination: %ld, %ld\n", res, GetLastError());
2625 TRACE("-- 0x%08lx\n", hr);