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 pipe names for
34 * clients and servers to meet up
35 * - Flip our marshalling on top of the RPC runtime transport API,
36 * so we no longer use named pipes to communicate
38 * - Make all ole interface marshaling use NDR to be wire compatible with
40 * - Use & interpret ORPCTHIS & ORPCTHAT.
53 #define NONAMELESSUNION
54 #define NONAMELESSSTRUCT
66 #include "wine/unicode.h"
68 #include "ole32_main.h"
69 #include "compobj_private.h"
71 #include "wine/debug.h"
73 WINE_DEFAULT_DEBUG_CHANNEL(ole);
75 typedef LPCSTR LPCOLESTR16;
77 /****************************************************************************
78 * This section defines variables internal to the COM module.
80 * TODO: Most of these things will have to be made thread-safe.
83 static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk);
84 static void COM_RevokeAllClasses(void);
86 const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
88 APARTMENT *MTA; /* protected by csApartment */
89 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
91 static CRITICAL_SECTION csApartment;
92 static CRITICAL_SECTION_DEBUG critsect_debug =
95 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
96 0, 0, { 0, (DWORD)(__FILE__ ": csApartment") }
98 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
101 * This lock count counts the number of times CoInitialize is called. It is
102 * decreased every time CoUninitialize is called. When it hits 0, the COM
103 * libraries are freed
105 static LONG s_COMLockCount = 0;
108 * This linked list contains the list of registered class objects. These
109 * are mostly used to register the factories for out-of-proc servers of OLE
112 * TODO: Make this data structure aware of inter-process communication. This
113 * means that parts of this will be exported to the Wine Server.
115 typedef struct tagRegisteredClass
117 CLSID classIdentifier;
118 LPUNKNOWN classObject;
122 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
123 struct tagRegisteredClass* nextClass;
126 static RegisteredClass* firstRegisteredClass = NULL;
128 static CRITICAL_SECTION csRegisteredClassList;
129 static CRITICAL_SECTION_DEBUG class_cs_debug =
131 0, 0, &csRegisteredClassList,
132 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
133 0, 0, { 0, (DWORD)(__FILE__ ": csRegisteredClassList") }
135 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
137 /*****************************************************************************
138 * This section contains OpenDllList definitions
140 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
141 * other functions that do LoadLibrary _without_ giving back a HMODULE.
142 * Without this list these handles would never be freed.
144 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
145 * next unload-call but not before 600 sec.
148 typedef struct tagOpenDll {
150 struct tagOpenDll *next;
153 static OpenDll *openDllList = NULL; /* linked list of open dlls */
155 static CRITICAL_SECTION csOpenDllList;
156 static CRITICAL_SECTION_DEBUG dll_cs_debug =
158 0, 0, &csOpenDllList,
159 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
160 0, 0, { 0, (DWORD)(__FILE__ ": csOpenDllList") }
162 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
164 static const WCHAR wszAptWinClass[] = {'W','I','N','E','_','O','L','E','3','2','_','A','P','T','_','C','L','A','S','S',0};
165 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
167 static void COMPOBJ_DLLList_Add(HANDLE hLibrary);
168 static void COMPOBJ_DllList_FreeUnused(int Timeout);
170 void COMPOBJ_InitProcess( void )
174 /* Dispatching to the correct thread in an apartment is done through
175 * window messages rather than RPC transports. When an interface is
176 * marshalled into another apartment in the same process, a window of the
177 * following class is created. The *caller* of CoMarshalInterface (ie the
178 * application) is responsible for pumping the message loop in that thread.
179 * The WM_USER messages which point to the RPCs are then dispatched to
180 * COM_AptWndProc by the user's code from the apartment in which the interface
183 memset(&wclass, 0, sizeof(wclass));
184 wclass.lpfnWndProc = COM_AptWndProc;
185 wclass.hInstance = OLE32_hInstance;
186 wclass.lpszClassName = wszAptWinClass;
187 RegisterClassW(&wclass);
190 void COMPOBJ_UninitProcess( void )
192 UnregisterClassW(wszAptWinClass, OLE32_hInstance);
195 void COM_TlsDestroy()
197 struct oletls *info = NtCurrentTeb()->ReservedForOle;
200 if (info->apt) COM_ApartmentRelease(info->apt);
201 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
202 if (info->state) IUnknown_Release(info->state);
203 HeapFree(GetProcessHeap(), 0, info);
204 NtCurrentTeb()->ReservedForOle = NULL;
208 /******************************************************************************
212 /* allocates memory and fills in the necessary fields for a new apartment
214 static APARTMENT *apartment_construct(DWORD model)
218 TRACE("creating new apartment, model=%ld\n", model);
220 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
221 apt->tid = GetCurrentThreadId();
222 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
223 GetCurrentProcess(), &apt->thread,
224 THREAD_ALL_ACCESS, FALSE, 0);
226 list_init(&apt->proxies);
227 list_init(&apt->stubmgrs);
230 apt->remunk_exported = FALSE;
232 InitializeCriticalSection(&apt->cs);
236 if (model & COINIT_APARTMENTTHREADED)
238 /* FIXME: should be randomly generated by in an RPC call to rpcss */
239 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
240 apt->win = CreateWindowW(wszAptWinClass, NULL, 0,
242 0, 0, OLE32_hInstance, NULL);
246 /* FIXME: should be randomly generated by in an RPC call to rpcss */
247 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
250 apt->shutdown_event = CreateEventW(NULL, TRUE, FALSE, NULL);
252 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
254 /* the locking here is not currently needed for the MTA case, but it
255 * doesn't hurt and makes the code simpler */
256 EnterCriticalSection(&csApartment);
257 list_add_head(&apts, &apt->entry);
258 LeaveCriticalSection(&csApartment);
263 /* gets and existing apartment if one exists or otherwise creates an apartment
264 * structure which stores OLE apartment-local information and stores a pointer
265 * to it in the thread-local storage */
266 static APARTMENT *get_or_create_apartment(DWORD model)
268 APARTMENT *apt = COM_CurrentApt();
272 if (model & COINIT_APARTMENTTHREADED)
274 apt = apartment_construct(model);
275 COM_CurrentInfo()->apt = apt;
279 EnterCriticalSection(&csApartment);
281 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
282 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
286 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
287 COM_ApartmentAddRef(MTA);
290 MTA = apartment_construct(model);
293 COM_CurrentInfo()->apt = apt;
295 LeaveCriticalSection(&csApartment);
302 DWORD COM_ApartmentAddRef(struct apartment *apt)
304 DWORD refs = InterlockedIncrement(&apt->refs);
305 TRACE("%s: before = %ld\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
309 DWORD COM_ApartmentRelease(struct apartment *apt)
313 EnterCriticalSection(&csApartment);
315 ret = InterlockedDecrement(&apt->refs);
316 TRACE("%s: after = %ld\n", wine_dbgstr_longlong(apt->oxid), ret);
317 /* destruction stuff that needs to happen under csApartment CS */
320 if (apt == MTA) MTA = NULL;
321 list_remove(&apt->entry);
324 LeaveCriticalSection(&csApartment);
328 struct list *cursor, *cursor2;
330 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
332 MARSHAL_Disconnect_Proxies(apt);
334 if (apt->win) DestroyWindow(apt->win);
336 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
338 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
339 /* release the implicit reference given by the fact that the
340 * stub has external references (it must do since it is in the
341 * stub manager list in the apartment and all non-apartment users
342 * must have a ref on the apartment and so it cannot be destroyed).
344 stub_manager_int_release(stubmgr);
347 /* if this assert fires, then another thread took a reference to a
348 * stub manager without taking a reference to the containing
349 * apartment, which it must do. */
350 assert(list_empty(&apt->stubmgrs));
352 if (apt->filter) IUnknown_Release(apt->filter);
354 DeleteCriticalSection(&apt->cs);
355 SetEvent(apt->shutdown_event);
356 CloseHandle(apt->shutdown_event);
357 CloseHandle(apt->thread);
358 HeapFree(GetProcessHeap(), 0, apt);
364 /* The given OXID must be local to this process: you cannot use
365 * apartment windows to send RPCs to other processes. This all needs
368 * The ref parameter is here mostly to ensure people remember that
369 * they get one, you should normally take a ref for thread safety.
371 APARTMENT *COM_ApartmentFromOXID(OXID oxid, BOOL ref)
373 APARTMENT *result = NULL;
376 EnterCriticalSection(&csApartment);
377 LIST_FOR_EACH( cursor, &apts )
379 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
380 if (apt->oxid == oxid)
383 if (ref) COM_ApartmentAddRef(result);
387 LeaveCriticalSection(&csApartment);
392 /* gets the apartment which has a given creator thread ID. The caller must
393 * release the reference from the apartment as soon as the apartment pointer
394 * is no longer required. */
395 APARTMENT *COM_ApartmentFromTID(DWORD tid)
397 APARTMENT *result = NULL;
400 EnterCriticalSection(&csApartment);
401 LIST_FOR_EACH( cursor, &apts )
403 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
407 COM_ApartmentAddRef(result);
411 LeaveCriticalSection(&csApartment);
416 HWND COM_GetApartmentWin(OXID oxid, BOOL ref)
420 apt = COM_ApartmentFromOXID(oxid, ref);
421 if (!apt) return NULL;
426 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
431 return RPC_ExecuteCall((RPCOLEMESSAGE *)wParam, (IRpcStubBuffer *)lParam);
433 return DefWindowProcW(hWnd, msg, wParam, lParam);
437 /*****************************************************************************
438 * This section contains OpenDllList implemantation
441 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
448 EnterCriticalSection( &csOpenDllList );
450 if (openDllList == NULL) {
451 /* empty list -- add first node */
452 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
453 openDllList->hLibrary=hLibrary;
454 openDllList->next = NULL;
456 /* search for this dll */
458 for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
459 if (ptr->hLibrary == hLibrary) {
465 /* dll not found, add it */
467 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
468 openDllList->hLibrary = hLibrary;
469 openDllList->next = tmp;
473 LeaveCriticalSection( &csOpenDllList );
476 static void COMPOBJ_DllList_FreeUnused(int Timeout)
478 OpenDll *curr, *next, *prev = NULL;
479 typedef HRESULT(*DllCanUnloadNowFunc)(void);
480 DllCanUnloadNowFunc DllCanUnloadNow;
484 EnterCriticalSection( &csOpenDllList );
486 for (curr = openDllList; curr != NULL; ) {
487 DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
489 if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
492 TRACE("freeing %p\n", curr->hLibrary);
493 FreeLibrary(curr->hLibrary);
495 HeapFree(GetProcessHeap(), 0, curr);
496 if (curr == openDllList) {
509 LeaveCriticalSection( &csOpenDllList );
512 /******************************************************************************
513 * CoBuildVersion [OLE32.@]
514 * CoBuildVersion [COMPOBJ.1]
516 * Gets the build version of the DLL.
521 * Current build version, hiword is majornumber, loword is minornumber
523 DWORD WINAPI CoBuildVersion(void)
525 TRACE("Returning version %d, build %d.\n", rmm, rup);
526 return (rmm<<16)+rup;
529 /******************************************************************************
530 * CoInitialize [OLE32.@]
532 * Initializes the COM libraries by calling CoInitializeEx with
533 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
536 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
539 * Success: S_OK if not already initialized, S_FALSE otherwise.
540 * Failure: HRESULT code.
545 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
548 * Just delegate to the newer method.
550 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
553 /******************************************************************************
554 * CoInitializeEx [OLE32.@]
556 * Initializes the COM libraries.
559 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
560 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
563 * S_OK if successful,
564 * S_FALSE if this function was called already.
565 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
570 * The behavior used to set the IMalloc used for memory management is
572 * The dwCoInit parameter must specify of of the following apartment
574 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
575 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
576 * The parameter may also specify zero or more of the following flags:
577 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
578 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
583 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
588 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
590 if (lpReserved!=NULL)
592 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
596 * Check the lock count. If this is the first time going through the initialize
597 * process, we have to initialize the libraries.
599 * And crank-up that lock count.
601 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
604 * Initialize the various COM libraries and data structures.
606 TRACE("() - Initializing the COM libraries\n");
608 /* we may need to defer this until after apartment initialisation */
609 RunningObjectTableImpl_Initialize();
612 if (!(apt = COM_CurrentInfo()->apt))
614 apt = get_or_create_apartment(dwCoInit);
615 if (!apt) return E_OUTOFMEMORY;
617 else if (dwCoInit != apt->model)
619 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
620 code then we are probably using the wrong threading model to implement that API. */
621 ERR("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit);
622 return RPC_E_CHANGED_MODE;
627 COM_CurrentInfo()->inits++;
632 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
633 pending RPCs are ignored. Non-COM messages are discarded at this point.
635 void COM_FlushMessageQueue(void)
638 APARTMENT *apt = COM_CurrentApt();
640 if (!apt || !apt->win) return;
642 TRACE("Flushing STA message queue\n");
644 while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE))
646 if (message.hwnd != apt->win)
648 WARN("discarding message 0x%x for window %p\n", message.message, message.hwnd);
652 TranslateMessage(&message);
653 DispatchMessageA(&message);
657 /***********************************************************************
658 * CoUninitialize [OLE32.@]
660 * This method will decrement the refcount on the current apartment, freeing
661 * the resources associated with it if it is the last thread in the apartment.
662 * If the last apartment is freed, the function will additionally release
663 * any COM resources associated with the process.
673 void WINAPI CoUninitialize(void)
675 struct oletls * info = COM_CurrentInfo();
680 /* will only happen on OOM */
686 ERR("Mismatched CoUninitialize\n");
692 COM_ApartmentRelease(info->apt);
697 * Decrease the reference count.
698 * If we are back to 0 locks on the COM library, make sure we free
699 * all the associated data structures.
701 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
704 TRACE("() - Releasing the COM libraries\n");
706 RunningObjectTableImpl_UnInitialize();
708 /* Release the references to the registered class objects */
709 COM_RevokeAllClasses();
711 /* This will free the loaded COM Dlls */
712 CoFreeAllLibraries();
714 /* This ensures we deal with any pending RPCs */
715 COM_FlushMessageQueue();
717 else if (lCOMRefCnt<1) {
718 ERR( "CoUninitialize() - not CoInitialized.\n" );
719 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
723 /******************************************************************************
724 * CoDisconnectObject [OLE32.@]
725 * CoDisconnectObject [COMPOBJ.15]
727 * Disconnects all connections to this object from remote processes. Dispatches
728 * pending RPCs while blocking new RPCs from occurring, and then calls
729 * IMarshal::DisconnectObject on the given object.
731 * Typically called when the object server is forced to shut down, for instance by
735 * lpUnk [I] The object whose stub should be disconnected.
736 * reserved [I] Reserved. Should be set to 0.
740 * Failure: HRESULT code.
743 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
745 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
751 TRACE("(%p, 0x%08lx)\n", lpUnk, reserved);
753 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
756 hr = IMarshal_DisconnectObject(marshal, reserved);
757 IMarshal_Release(marshal);
761 apt = COM_CurrentApt();
763 return CO_E_NOTINITIALIZED;
765 apartment_disconnect_object(apt, lpUnk);
767 /* Note: native is pretty broken here because it just silently
768 * fails, without returning an appropriate error code if the object was
769 * not found, making apps think that the object was disconnected, when
770 * it actually wasn't */
775 /******************************************************************************
776 * CoCreateGuid [OLE32.@]
778 * Simply forwards to UuidCreate in RPCRT4.
781 * pguid [O] Points to the GUID to initialize.
785 * Failure: HRESULT code.
790 HRESULT WINAPI CoCreateGuid(GUID *pguid)
792 return UuidCreate(pguid);
795 /******************************************************************************
796 * CLSIDFromString [OLE32.@]
797 * IIDFromString [OLE32.@]
799 * Converts a unique identifier from its string representation into
803 * idstr [I] The string representation of the GUID.
804 * id [O] GUID converted from the string.
808 * CO_E_CLASSSTRING if idstr is not a valid CLSID
812 * In Windows, if idstr is not a valid CLSID string then it gets
813 * treated as a ProgID. Wine currently doesn't do this. If idstr is
814 * NULL it's treated as an all-zero GUID.
819 HRESULT WINAPI __CLSIDFromStringA(LPCSTR idstr, CLSID *id)
821 const BYTE *s = (const BYTE *) idstr;
826 s = "{00000000-0000-0000-0000-000000000000}";
827 else { /* validate the CLSID string */
830 return CO_E_CLASSSTRING;
832 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
833 return CO_E_CLASSSTRING;
835 for (i=1; i<37; i++) {
836 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
837 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
838 ((s[i] >= 'a') && (s[i] <= 'f')) ||
839 ((s[i] >= 'A') && (s[i] <= 'F'))))
840 return CO_E_CLASSSTRING;
844 TRACE("%s -> %p\n", s, id);
846 /* quick lookup table */
847 memset(table, 0, 256);
849 for (i = 0; i < 10; i++) {
852 for (i = 0; i < 6; i++) {
853 table['A' + i] = i+10;
854 table['a' + i] = i+10;
857 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
859 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
860 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
861 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
862 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
864 /* these are just sequential bytes */
865 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
866 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
867 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
868 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
869 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
870 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
871 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
872 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
877 /*****************************************************************************/
879 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
884 if (!WideCharToMultiByte( CP_ACP, 0, idstr, -1, xid, sizeof(xid), NULL, NULL ))
885 return CO_E_CLASSSTRING;
888 ret = __CLSIDFromStringA(xid,id);
889 if(ret != S_OK) { /* It appears a ProgID is also valid */
890 ret = CLSIDFromProgID(idstr, id);
895 /* Converts a GUID into the respective string representation. */
896 HRESULT WINE_StringFromCLSID(
897 const CLSID *id, /* [in] GUID to be converted */
898 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
900 static const char *hex = "0123456789ABCDEF";
905 { ERR("called with id=Null\n");
910 sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
911 id->Data1, id->Data2, id->Data3,
912 id->Data4[0], id->Data4[1]);
916 for (i = 2; i < 8; i++) {
917 *s++ = hex[id->Data4[i]>>4];
918 *s++ = hex[id->Data4[i] & 0xf];
924 TRACE("%p->%s\n", id, idstr);
930 /******************************************************************************
931 * StringFromCLSID [OLE32.@]
932 * StringFromIID [OLE32.@]
934 * Converts a GUID into the respective string representation.
935 * The target string is allocated using the OLE IMalloc.
938 * id [I] the GUID to be converted.
939 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
946 * StringFromGUID2, CLSIDFromString
948 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
954 if ((ret = CoGetMalloc(0,&mllc)))
957 ret=WINE_StringFromCLSID(id,buf);
959 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
960 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
961 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
966 /******************************************************************************
967 * StringFromGUID2 [OLE32.@]
968 * StringFromGUID2 [COMPOBJ.76]
970 * Modified version of StringFromCLSID that allows you to specify max
974 * id [I] GUID to convert to string.
975 * str [O] Buffer where the result will be stored.
976 * cmax [I] Size of the buffer in characters.
979 * Success: The length of the resulting string in characters.
982 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
986 if (WINE_StringFromCLSID(id,xguid))
988 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
991 /******************************************************************************
992 * ProgIDFromCLSID [OLE32.@]
994 * Converts a class id into the respective program ID.
997 * clsid [I] Class ID, as found in registry.
998 * lplpszProgID [O] Associated ProgID.
1003 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1005 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *lplpszProgID)
1007 char strCLSID[50], *buf, *buf2;
1013 WINE_StringFromCLSID(clsid, strCLSID);
1015 buf = HeapAlloc(GetProcessHeap(), 0, strlen(strCLSID)+14);
1016 sprintf(buf,"CLSID\\%s\\ProgID", strCLSID);
1017 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
1018 ret = REGDB_E_CLASSNOTREG;
1020 HeapFree(GetProcessHeap(), 0, buf);
1024 buf2 = HeapAlloc(GetProcessHeap(), 0, 255);
1026 if (RegQueryValueA(xhkey, NULL, buf2, &buf2len))
1027 ret = REGDB_E_CLASSNOTREG;
1031 if (CoGetMalloc(0,&mllc))
1032 ret = E_OUTOFMEMORY;
1035 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf2, -1, NULL, 0 );
1036 *lplpszProgID = IMalloc_Alloc(mllc, len * sizeof(WCHAR) );
1037 MultiByteToWideChar( CP_ACP, 0, buf2, -1, *lplpszProgID, len );
1040 HeapFree(GetProcessHeap(), 0, buf2);
1047 HRESULT WINAPI CLSIDFromProgID16(
1048 LPCOLESTR16 progid, /* [in] program id as found in registry */
1049 LPCLSID riid /* [out] associated CLSID */
1056 buf = HeapAlloc(GetProcessHeap(),0,strlen(progid)+8);
1057 sprintf(buf,"%s\\CLSID",progid);
1058 if ((err=RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&xhkey))) {
1059 HeapFree(GetProcessHeap(),0,buf);
1060 return CO_E_CLASSSTRING;
1062 HeapFree(GetProcessHeap(),0,buf);
1063 buf2len = sizeof(buf2);
1064 if ((err=RegQueryValueA(xhkey,NULL,buf2,&buf2len))) {
1066 return CO_E_CLASSSTRING;
1069 return __CLSIDFromStringA(buf2,riid);
1072 /******************************************************************************
1073 * CLSIDFromProgID [OLE32.@]
1074 * CLSIDFromProgID [COMPOBJ.61]
1076 * Converts a program id into the respective GUID.
1079 * progid [I] Unicode program ID, as found in registry.
1080 * riid [O] Associated CLSID.
1084 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1086 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID riid)
1088 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1090 DWORD buf2len = sizeof(buf2);
1093 WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1094 strcpyW( buf, progid );
1095 strcatW( buf, clsidW );
1096 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1098 HeapFree(GetProcessHeap(),0,buf);
1099 return CO_E_CLASSSTRING;
1101 HeapFree(GetProcessHeap(),0,buf);
1103 if (RegQueryValueA(xhkey,NULL,buf2,&buf2len))
1106 return CO_E_CLASSSTRING;
1109 return __CLSIDFromStringA(buf2,riid);
1114 /*****************************************************************************
1115 * CoGetPSClsid [OLE32.@]
1117 * Retrieves the CLSID of the proxy/stub factory that implements
1118 * IPSFactoryBuffer for the specified interface.
1121 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1122 * pclsid [O] Where to store returned proxy/stub CLSID.
1127 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1131 * The standard marshaller activates the object with the CLSID
1132 * returned and uses the CreateProxy and CreateStub methods on its
1133 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1136 * CoGetPSClsid determines this CLSID by searching the
1137 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1138 * in the registry and any interface id registered by
1139 * CoRegisterPSClsid within the current process.
1143 * We only search the registry, not ids registered with
1144 * CoRegisterPSClsid.
1145 * Also, native returns S_OK for interfaces with an key in HKCR\Interface, but
1146 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1147 * considered a bug in native unless an application depends on this (unlikely).
1149 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1151 char *buf, buf2[40];
1155 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1157 /* Get the input iid as a string */
1158 WINE_StringFromCLSID(riid, buf2);
1159 /* Allocate memory for the registry key we will construct.
1160 (length of iid string plus constant length of static text */
1161 buf = HeapAlloc(GetProcessHeap(), 0, strlen(buf2)+27);
1163 return E_OUTOFMEMORY;
1165 /* Construct the registry key we want */
1166 sprintf(buf,"Interface\\%s\\ProxyStubClsid32", buf2);
1168 /* Open the key.. */
1169 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
1171 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1172 HeapFree(GetProcessHeap(),0,buf);
1173 return REGDB_E_IIDNOTREG;
1175 HeapFree(GetProcessHeap(),0,buf);
1177 /* ... Once we have the key, query the registry to get the
1178 value of CLSID as a string, and convert it into a
1179 proper CLSID structure to be passed back to the app */
1180 buf2len = sizeof(buf2);
1181 if ( (RegQueryValueA(xhkey,NULL,buf2,&buf2len)) )
1184 return REGDB_E_IIDNOTREG;
1188 /* We have the CLSid we want back from the registry as a string, so
1189 lets convert it into a CLSID structure */
1190 if ( (__CLSIDFromStringA(buf2,pclsid)) != NOERROR)
1191 return REGDB_E_IIDNOTREG;
1193 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1199 /***********************************************************************
1200 * WriteClassStm (OLE32.@)
1202 * Writes a CLSID to a stream.
1205 * pStm [I] Stream to write to.
1206 * rclsid [I] CLSID to write.
1210 * Failure: HRESULT code.
1212 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
1214 TRACE("(%p,%p)\n",pStm,rclsid);
1217 return E_INVALIDARG;
1219 return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
1222 /***********************************************************************
1223 * ReadClassStm (OLE32.@)
1225 * Reads a CLSID from a stream.
1228 * pStm [I] Stream to read from.
1229 * rclsid [O] CLSID to read.
1233 * Failure: HRESULT code.
1235 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
1240 TRACE("(%p,%p)\n",pStm,pclsid);
1243 return E_INVALIDARG;
1245 res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
1250 if (nbByte != sizeof(CLSID))
1258 * COM_GetRegisteredClassObject
1260 * This internal method is used to scan the registered class list to
1261 * find a class object.
1264 * rclsid Class ID of the class to find.
1265 * dwClsContext Class context to match.
1266 * ppv [out] returns a pointer to the class object. Complying
1267 * to normal COM usage, this method will increase the
1268 * reference count on this object.
1270 static HRESULT COM_GetRegisteredClassObject(
1275 HRESULT hr = S_FALSE;
1276 RegisteredClass* curClass;
1278 EnterCriticalSection( &csRegisteredClassList );
1286 * Iterate through the whole list and try to match the class ID.
1288 curClass = firstRegisteredClass;
1290 while (curClass != 0)
1293 * Check if we have a match on the class ID.
1295 if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
1298 * Since we don't do out-of process or DCOM just right away, let's ignore the
1303 * We have a match, return the pointer to the class object.
1305 *ppUnk = curClass->classObject;
1307 IUnknown_AddRef(curClass->classObject);
1314 * Step to the next class in the list.
1316 curClass = curClass->nextClass;
1320 LeaveCriticalSection( &csRegisteredClassList );
1322 * If we get to here, we haven't found our class.
1327 /******************************************************************************
1328 * CoRegisterClassObject [OLE32.@]
1330 * Registers the class object for a given class ID. Servers housed in EXE
1331 * files use this method instead of exporting DllGetClassObject to allow
1332 * other code to connect to their objects.
1335 * rclsid [I] CLSID of the object to register.
1336 * pUnk [I] IUnknown of the object.
1337 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1338 * flags [I] REGCLS flags indicating how connections are made.
1339 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1343 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1344 * CO_E_OBJISREG if the object is already registered. We should not return this.
1347 * CoRevokeClassObject, CoGetClassObject
1350 * MSDN claims that multiple interface registrations are legal, but we
1351 * can't do that with our current implementation.
1353 HRESULT WINAPI CoRegisterClassObject(
1358 LPDWORD lpdwRegister)
1360 RegisteredClass* newClass;
1361 LPUNKNOWN foundObject;
1364 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1365 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1367 if ( (lpdwRegister==0) || (pUnk==0) )
1368 return E_INVALIDARG;
1370 if (!COM_CurrentApt())
1372 ERR("COM was not initialized\n");
1373 return CO_E_NOTINITIALIZED;
1379 * First, check if the class is already registered.
1380 * If it is, this should cause an error.
1382 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1384 IUnknown_Release(foundObject);
1385 return CO_E_OBJISREG;
1388 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1389 if ( newClass == NULL )
1390 return E_OUTOFMEMORY;
1392 EnterCriticalSection( &csRegisteredClassList );
1394 newClass->classIdentifier = *rclsid;
1395 newClass->runContext = dwClsContext;
1396 newClass->connectFlags = flags;
1398 * Use the address of the chain node as the cookie since we are sure it's
1399 * unique. FIXME: not on 64-bit platforms.
1401 newClass->dwCookie = (DWORD)newClass;
1402 newClass->nextClass = firstRegisteredClass;
1405 * Since we're making a copy of the object pointer, we have to increase its
1408 newClass->classObject = pUnk;
1409 IUnknown_AddRef(newClass->classObject);
1411 firstRegisteredClass = newClass;
1412 LeaveCriticalSection( &csRegisteredClassList );
1414 *lpdwRegister = newClass->dwCookie;
1416 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1417 IClassFactory *classfac;
1419 hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory,
1420 (LPVOID*)&classfac);
1423 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
1425 FIXME("Failed to create stream on hglobal, %lx\n", hr);
1426 IUnknown_Release(classfac);
1429 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
1430 (LPVOID)classfac, MSHCTX_LOCAL, NULL,
1431 MSHLFLAGS_TABLESTRONG);
1433 FIXME("CoMarshalInterface failed, %lx!\n",hr);
1434 IUnknown_Release(classfac);
1438 IUnknown_Release(classfac);
1440 RPC_StartLocalServer(&newClass->classIdentifier, newClass->pMarshaledData);
1445 /***********************************************************************
1446 * CoRevokeClassObject [OLE32.@]
1448 * Removes a class object from the class registry.
1451 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1455 * Failure: HRESULT code.
1458 * CoRegisterClassObject
1460 HRESULT WINAPI CoRevokeClassObject(
1463 HRESULT hr = E_INVALIDARG;
1464 RegisteredClass** prevClassLink;
1465 RegisteredClass* curClass;
1467 TRACE("(%08lx)\n",dwRegister);
1469 EnterCriticalSection( &csRegisteredClassList );
1472 * Iterate through the whole list and try to match the cookie.
1474 curClass = firstRegisteredClass;
1475 prevClassLink = &firstRegisteredClass;
1477 while (curClass != 0)
1480 * Check if we have a match on the cookie.
1482 if (curClass->dwCookie == dwRegister)
1485 * Remove the class from the chain.
1487 *prevClassLink = curClass->nextClass;
1490 * Release the reference to the class object.
1492 IUnknown_Release(curClass->classObject);
1494 if (curClass->pMarshaledData)
1497 memset(&zero, 0, sizeof(zero));
1498 /* FIXME: stop local server thread */
1499 IStream_Seek(curClass->pMarshaledData, zero, SEEK_SET, NULL);
1500 CoReleaseMarshalData(curClass->pMarshaledData);
1504 * Free the memory used by the chain node.
1506 HeapFree(GetProcessHeap(), 0, curClass);
1513 * Step to the next class in the list.
1515 prevClassLink = &(curClass->nextClass);
1516 curClass = curClass->nextClass;
1520 LeaveCriticalSection( &csRegisteredClassList );
1522 * If we get to here, we haven't found our class.
1527 /***********************************************************************
1528 * compobj_RegReadPath [internal]
1530 * Reads a registry value and expands it when necessary
1532 HRESULT compobj_RegReadPath(char * keyname, char * valuename, char * dst, DWORD dstlen)
1538 DWORD dwLength = dstlen;
1540 if((hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1541 if( (hres = RegQueryValueExA(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1542 if (keytype == REG_EXPAND_SZ) {
1543 if (dstlen <= ExpandEnvironmentStringsA(src, dst, dstlen)) hres = ERROR_MORE_DATA;
1545 lstrcpynA(dst, src, dstlen);
1553 /***********************************************************************
1554 * CoGetClassObject [COMPOBJ.7]
1555 * CoGetClassObject [OLE32.@]
1557 * FIXME. If request allows of several options and there is a failure
1558 * with one (other than not being registered) do we try the
1559 * others or return failure? (E.g. inprocess is registered but
1560 * the DLL is not found but the server version works)
1562 HRESULT WINAPI CoGetClassObject(
1563 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1564 REFIID iid, LPVOID *ppv
1566 LPUNKNOWN regClassObject;
1567 HRESULT hres = E_UNEXPECTED;
1570 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1571 DllGetClassObjectFunc DllGetClassObject;
1573 WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
1575 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1578 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1579 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1583 * First, try and see if we can't match the class ID with one of the
1584 * registered classes.
1586 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, ®ClassObject))
1589 * Get the required interface from the retrieved pointer.
1591 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1594 * Since QI got another reference on the pointer, we want to release the
1595 * one we already have. If QI was unsuccessful, this will release the object. This
1596 * is good since we are not returning it in the "out" parameter.
1598 IUnknown_Release(regClassObject);
1603 /* first try: in-process */
1604 if ((CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER) & dwClsContext) {
1605 char keyname[MAX_PATH];
1606 char dllpath[MAX_PATH+1];
1608 sprintf(keyname,"CLSID\\%s\\InprocServer32",xclsid);
1610 if ( compobj_RegReadPath(keyname, NULL, dllpath, sizeof(dllpath)) != ERROR_SUCCESS) {
1611 /* failure: CLSID is not found in registry */
1612 WARN("class %s not registered inproc\n", xclsid);
1613 hres = REGDB_E_CLASSNOTREG;
1615 if ((hLibrary = LoadLibraryExA(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) {
1616 /* failure: DLL could not be loaded */
1617 ERR("couldn't load InprocServer32 dll %s\n", dllpath);
1618 hres = E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1619 } else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject"))) {
1620 /* failure: the dll did not export DllGetClassObject */
1621 ERR("couldn't find function DllGetClassObject in %s\n", dllpath);
1622 FreeLibrary( hLibrary );
1623 hres = CO_E_DLLNOTFOUND;
1625 /* OK: get the ClassObject */
1626 COMPOBJ_DLLList_Add( hLibrary );
1627 return DllGetClassObject(rclsid, iid, ppv);
1632 /* Next try out of process */
1633 if (CLSCTX_LOCAL_SERVER & dwClsContext)
1635 return create_marshalled_proxy(rclsid,iid,ppv);
1638 /* Finally try remote: this requires networked DCOM (a lot of work) */
1639 if (CLSCTX_REMOTE_SERVER & dwClsContext)
1641 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1642 hres = E_NOINTERFACE;
1647 /***********************************************************************
1648 * CoResumeClassObjects (OLE32.@)
1650 * Resumes all class objects registered with REGCLS_SUSPENDED.
1654 * Failure: HRESULT code.
1656 HRESULT WINAPI CoResumeClassObjects(void)
1662 /***********************************************************************
1663 * GetClassFile (OLE32.@)
1665 * This function supplies the CLSID associated with the given filename.
1667 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1671 int nbElm, length, i;
1673 LPOLESTR *pathDec=0,absFile=0,progId=0;
1675 static const WCHAR bkslashW[] = {'\\',0};
1676 static const WCHAR dotW[] = {'.',0};
1678 TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1680 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1681 if((StgIsStorageFile(filePathName))==S_OK){
1683 res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1686 res=ReadClassStg(pstg,pclsid);
1688 IStorage_Release(pstg);
1692 /* if the file is not a storage object then attemps to match various bits in the file against a
1693 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1696 for(i=0;i<nFileTypes;i++)
1698 for(i=0;j<nPatternsForType;j++){
1703 pat=ReadPatternFromRegistry(i,j);
1704 hFile=CreateFileW(filePathName,,,,,,hFile);
1705 SetFilePosition(hFile,pat.offset);
1706 ReadFile(hFile,buf,pat.size,&r,NULL);
1707 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1709 *pclsid=ReadCLSIDFromRegistry(i);
1715 /* if the above strategies fail then search for the extension key in the registry */
1717 /* get the last element (absolute file) in the path name */
1718 nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1719 absFile=pathDec[nbElm-1];
1721 /* failed if the path represente a directory and not an absolute file name*/
1722 if (!lstrcmpW(absFile, bkslashW))
1723 return MK_E_INVALIDEXTENSION;
1725 /* get the extension of the file */
1727 length=lstrlenW(absFile);
1728 for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1731 if (!extension || !lstrcmpW(extension, dotW))
1732 return MK_E_INVALIDEXTENSION;
1734 res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1736 /* get the progId associated to the extension */
1737 progId = CoTaskMemAlloc(sizeProgId);
1738 res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1740 if (res==ERROR_SUCCESS)
1741 /* return the clsid associated to the progId */
1742 res= CLSIDFromProgID(progId,pclsid);
1744 for(i=0; pathDec[i]!=NULL;i++)
1745 CoTaskMemFree(pathDec[i]);
1746 CoTaskMemFree(pathDec);
1748 CoTaskMemFree(progId);
1750 if (res==ERROR_SUCCESS)
1753 return MK_E_INVALIDEXTENSION;
1755 /***********************************************************************
1756 * CoCreateInstance [COMPOBJ.13]
1757 * CoCreateInstance [OLE32.@]
1759 HRESULT WINAPI CoCreateInstance(
1761 LPUNKNOWN pUnkOuter,
1767 LPCLASSFACTORY lpclf = 0;
1769 if (!COM_CurrentApt()) return CO_E_NOTINITIALIZED;
1778 * Initialize the "out" parameter
1783 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1784 * Rather than create a class factory, we can just check for it here
1786 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
1787 if (StdGlobalInterfaceTableInstance == NULL)
1788 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
1789 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
1790 if (hres) return hres;
1792 TRACE("Retrieved GIT (%p)\n", *ppv);
1797 * Get a class factory to construct the object we want.
1799 hres = CoGetClassObject(rclsid,
1806 FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n",
1807 debugstr_guid(rclsid),hres);
1812 * Create the object and don't forget to release the factory
1814 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
1815 IClassFactory_Release(lpclf);
1817 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1818 debugstr_guid(iid), debugstr_guid(rclsid),hres);
1823 /***********************************************************************
1824 * CoCreateInstanceEx [OLE32.@]
1826 HRESULT WINAPI CoCreateInstanceEx(
1828 LPUNKNOWN pUnkOuter,
1830 COSERVERINFO* pServerInfo,
1834 IUnknown* pUnk = NULL;
1837 ULONG successCount = 0;
1842 if ( (cmq==0) || (pResults==NULL))
1843 return E_INVALIDARG;
1845 if (pServerInfo!=NULL)
1846 FIXME("() non-NULL pServerInfo not supported!\n");
1849 * Initialize all the "out" parameters.
1851 for (index = 0; index < cmq; index++)
1853 pResults[index].pItf = NULL;
1854 pResults[index].hr = E_NOINTERFACE;
1858 * Get the object and get its IUnknown pointer.
1860 hr = CoCreateInstance(rclsid,
1870 * Then, query for all the interfaces requested.
1872 for (index = 0; index < cmq; index++)
1874 pResults[index].hr = IUnknown_QueryInterface(pUnk,
1875 pResults[index].pIID,
1876 (VOID**)&(pResults[index].pItf));
1878 if (pResults[index].hr == S_OK)
1883 * Release our temporary unknown pointer.
1885 IUnknown_Release(pUnk);
1887 if (successCount == 0)
1888 return E_NOINTERFACE;
1890 if (successCount!=cmq)
1891 return CO_S_NOTALLINTERFACES;
1896 /***********************************************************************
1897 * CoLoadLibrary (OLE32.@)
1902 * lpszLibName [I] Path to library.
1903 * bAutoFree [I] Whether the library should automatically be freed.
1906 * Success: Handle to loaded library.
1910 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1912 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
1914 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
1916 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
1919 /***********************************************************************
1920 * CoFreeLibrary [OLE32.@]
1922 * Unloads a library from memory.
1925 * hLibrary [I] Handle to library to unload.
1931 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1933 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
1935 FreeLibrary(hLibrary);
1939 /***********************************************************************
1940 * CoFreeAllLibraries [OLE32.@]
1942 * Function for backwards compatibility only. Does nothing.
1948 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
1950 void WINAPI CoFreeAllLibraries(void)
1956 /***********************************************************************
1957 * CoFreeUnusedLibraries [OLE32.@]
1958 * CoFreeUnusedLibraries [COMPOBJ.17]
1960 * Frees any unused libraries. Unused are identified as those that return
1961 * S_OK from their DllCanUnloadNow function.
1967 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
1969 void WINAPI CoFreeUnusedLibraries(void)
1971 /* FIXME: Calls to CoFreeUnusedLibraries from any thread always route
1972 * through the main apartment's thread to call DllCanUnloadNow */
1973 COMPOBJ_DllList_FreeUnused(0);
1976 /***********************************************************************
1977 * CoFileTimeNow [OLE32.@]
1978 * CoFileTimeNow [COMPOBJ.82]
1980 * Retrieves the current time in FILETIME format.
1983 * lpFileTime [O] The current time.
1988 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
1990 GetSystemTimeAsFileTime( lpFileTime );
1994 static void COM_RevokeAllClasses()
1996 EnterCriticalSection( &csRegisteredClassList );
1998 while (firstRegisteredClass!=0)
2000 CoRevokeClassObject(firstRegisteredClass->dwCookie);
2003 LeaveCriticalSection( &csRegisteredClassList );
2006 /******************************************************************************
2007 * CoLockObjectExternal [OLE32.@]
2009 * Increments or decrements the external reference count of a stub object.
2012 * pUnk [I] Stub object.
2013 * fLock [I] If TRUE then increments the external ref-count,
2014 * otherwise decrements.
2015 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2016 * calling CoDisconnectObject.
2020 * Failure: HRESULT code.
2022 HRESULT WINAPI CoLockObjectExternal(
2025 BOOL fLastUnlockReleases)
2027 struct stub_manager *stubmgr;
2028 struct apartment *apt;
2030 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2031 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2033 apt = COM_CurrentApt();
2034 if (!apt) return CO_E_NOTINITIALIZED;
2036 stubmgr = get_stub_manager_from_object(apt, pUnk);
2041 stub_manager_ext_addref(stubmgr, 1);
2043 stub_manager_ext_release(stubmgr, 1);
2045 stub_manager_int_release(stubmgr);
2051 WARN("stub object not found %p\n", pUnk);
2052 /* Note: native is pretty broken here because it just silently
2053 * fails, without returning an appropriate error code, making apps
2054 * think that the object was disconnected, when it actually wasn't */
2059 /***********************************************************************
2060 * CoInitializeWOW (OLE32.@)
2062 * WOW equivalent of CoInitialize?
2071 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2073 FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
2077 /***********************************************************************
2078 * CoGetState [OLE32.@]
2080 * Retrieves the thread state object previously stored by CoSetState().
2083 * ppv [I] Address where pointer to object will be stored.
2087 * Failure: E_OUTOFMEMORY.
2090 * Crashes on all invalid ppv addresses, including NULL.
2091 * If the function returns a non-NULL object then the caller must release its
2092 * reference on the object when the object is no longer required.
2097 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2099 struct oletls *info = COM_CurrentInfo();
2100 if (!info) return E_OUTOFMEMORY;
2106 IUnknown_AddRef(info->state);
2108 TRACE("apt->state=%p\n", info->state);
2114 /***********************************************************************
2115 * CoSetState [OLE32.@]
2117 * Sets the thread state object.
2120 * pv [I] Pointer to state object to be stored.
2123 * The system keeps a reference on the object while the object stored.
2127 * Failure: E_OUTOFMEMORY.
2129 HRESULT WINAPI CoSetState(IUnknown * pv)
2131 struct oletls *info = COM_CurrentInfo();
2132 if (!info) return E_OUTOFMEMORY;
2134 if (pv) IUnknown_AddRef(pv);
2138 TRACE("-- release %p now\n", info->state);
2139 IUnknown_Release(info->state);
2148 /******************************************************************************
2149 * OleGetAutoConvert [OLE32.@]
2151 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2159 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2160 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2162 res = REGDB_E_CLASSNOTREG;
2166 /* we can just query for the default value of AutoConvertTo key like that,
2167 without opening the AutoConvertTo key and querying for NULL (default) */
2168 if (RegQueryValueA(hkey,"AutoConvertTo",buf,&len))
2170 res = REGDB_E_KEYMISSING;
2173 MultiByteToWideChar( CP_ACP, 0, buf, -1, wbuf, sizeof(wbuf)/sizeof(WCHAR) );
2174 CLSIDFromString(wbuf,pClsidNew);
2176 if (hkey) RegCloseKey(hkey);
2180 /******************************************************************************
2181 * CoTreatAsClass [OLE32.@]
2183 * Sets the TreatAs value of a class.
2186 * clsidOld [I] Class to set TreatAs value on.
2187 * clsidNew [I] The class the clsidOld should be treated as.
2191 * Failure: HRESULT code.
2196 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2200 char szClsidNew[39];
2202 char auto_treat_as[39];
2203 LONG auto_treat_as_size = sizeof(auto_treat_as);
2206 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2207 WINE_StringFromCLSID(clsidNew, szClsidNew);
2208 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2210 res = REGDB_E_CLASSNOTREG;
2213 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2215 if (!RegQueryValueA(hkey, "AutoTreatAs", auto_treat_as, &auto_treat_as_size) &&
2216 !__CLSIDFromStringA(auto_treat_as, &id))
2218 if (RegSetValueA(hkey, "TreatAs", REG_SZ, auto_treat_as, strlen(auto_treat_as)+1))
2220 res = REGDB_E_WRITEREGDB;
2226 RegDeleteKeyA(hkey, "TreatAs");
2230 else if (RegSetValueA(hkey, "TreatAs", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
2232 res = REGDB_E_WRITEREGDB;
2237 if (hkey) RegCloseKey(hkey);
2241 /******************************************************************************
2242 * CoGetTreatAsClass [OLE32.@]
2244 * Gets the TreatAs value of a class.
2247 * clsidOld [I] Class to get the TreatAs value of.
2248 * clsidNew [I] The class the clsidOld should be treated as.
2252 * Failure: HRESULT code.
2257 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2260 char buf[200], szClsidNew[200];
2262 LONG len = sizeof(szClsidNew);
2264 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2265 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2266 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2268 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2270 res = REGDB_E_CLASSNOTREG;
2273 if (RegQueryValueA(hkey, "TreatAs", szClsidNew, &len))
2278 res = __CLSIDFromStringA(szClsidNew,clsidNew);
2280 FIXME("Failed CLSIDFromStringA(%s), hres %lx?\n",szClsidNew,res);
2282 if (hkey) RegCloseKey(hkey);
2287 /******************************************************************************
2288 * CoGetCurrentProcess [OLE32.@]
2289 * CoGetCurrentProcess [COMPOBJ.34]
2291 * Gets the current process ID.
2294 * The current process ID.
2297 * Is DWORD really the correct return type for this function?
2299 DWORD WINAPI CoGetCurrentProcess(void)
2301 return GetCurrentProcessId();
2304 /******************************************************************************
2305 * CoRegisterMessageFilter [OLE32.@]
2307 * Registers a message filter.
2310 * lpMessageFilter [I] Pointer to interface.
2311 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2315 * Failure: HRESULT code.
2317 HRESULT WINAPI CoRegisterMessageFilter(
2318 LPMESSAGEFILTER lpMessageFilter,
2319 LPMESSAGEFILTER *lplpMessageFilter)
2322 if (lplpMessageFilter) {
2323 *lplpMessageFilter = NULL;
2328 /***********************************************************************
2329 * CoIsOle1Class [OLE32.@]
2331 * Determines whether the specified class an OLE v1 class.
2334 * clsid [I] Class to test.
2337 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
2339 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
2341 FIXME("%s\n", debugstr_guid(clsid));
2345 /***********************************************************************
2346 * IsEqualGUID [OLE32.@]
2348 * Compares two Unique Identifiers.
2351 * rguid1 [I] The first GUID to compare.
2352 * rguid2 [I] The other GUID to compare.
2358 BOOL WINAPI IsEqualGUID(
2362 return !memcmp(rguid1,rguid2,sizeof(GUID));
2365 /***********************************************************************
2366 * CoInitializeSecurity [OLE32.@]
2368 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2369 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2370 void* pReserved1, DWORD dwAuthnLevel,
2371 DWORD dwImpLevel, void* pReserved2,
2372 DWORD dwCapabilities, void* pReserved3)
2374 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
2375 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2376 dwCapabilities, pReserved3);
2380 /***********************************************************************
2381 * CoSuspendClassObjects [OLE32.@]
2383 * Suspends all registered class objects to prevent further requests coming in
2384 * for those objects.
2388 * Failure: HRESULT code.
2390 HRESULT WINAPI CoSuspendClassObjects(void)
2396 /***********************************************************************
2397 * CoAddRefServerProcess [OLE32.@]
2399 * Helper function for incrementing the reference count of a local-server
2403 * New reference count.
2405 ULONG WINAPI CoAddRefServerProcess(void)
2411 /***********************************************************************
2412 * CoReleaseServerProcess [OLE32.@]
2414 * Helper function for decrementing the reference count of a local-server
2418 * New reference count.
2420 ULONG WINAPI CoReleaseServerProcess(void)
2426 /***********************************************************************
2427 * CoQueryProxyBlanket [OLE32.@]
2429 * Retrieves the security settings being used by a proxy.
2432 * pProxy [I] Pointer to the proxy object.
2433 * pAuthnSvc [O] The type of authentication service.
2434 * pAuthzSvc [O] The type of authorization service.
2435 * ppServerPrincName [O] Optional. The server prinicple name.
2436 * pAuthnLevel [O] The authentication level.
2437 * pImpLevel [O] The impersonation level.
2438 * ppAuthInfo [O] Information specific to the authorization/authentication service.
2439 * pCapabilities [O] Flags affecting the security behaviour.
2443 * Failure: HRESULT code.
2446 * CoCopyProxy, CoSetProxyBlanket.
2448 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
2449 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
2450 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
2452 IClientSecurity *pCliSec;
2455 TRACE("%p\n", pProxy);
2457 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2460 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
2461 pAuthzSvc, ppServerPrincName,
2462 pAuthnLevel, pImpLevel, ppAuthInfo,
2464 IClientSecurity_Release(pCliSec);
2467 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2471 /***********************************************************************
2472 * CoSetProxyBlanket [OLE32.@]
2474 * Sets the security settings for a proxy.
2477 * pProxy [I] Pointer to the proxy object.
2478 * AuthnSvc [I] The type of authentication service.
2479 * AuthzSvc [I] The type of authorization service.
2480 * pServerPrincName [I] The server prinicple name.
2481 * AuthnLevel [I] The authentication level.
2482 * ImpLevel [I] The impersonation level.
2483 * pAuthInfo [I] Information specific to the authorization/authentication service.
2484 * Capabilities [I] Flags affecting the security behaviour.
2488 * Failure: HRESULT code.
2491 * CoQueryProxyBlanket, CoCopyProxy.
2493 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
2494 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
2495 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
2497 IClientSecurity *pCliSec;
2500 TRACE("%p\n", pProxy);
2502 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2505 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
2506 AuthzSvc, pServerPrincName,
2507 AuthnLevel, ImpLevel, pAuthInfo,
2509 IClientSecurity_Release(pCliSec);
2512 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2516 /***********************************************************************
2517 * CoCopyProxy [OLE32.@]
2522 * pProxy [I] Pointer to the proxy object.
2523 * ppCopy [O] Copy of the proxy.
2527 * Failure: HRESULT code.
2530 * CoQueryProxyBlanket, CoSetProxyBlanket.
2532 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
2534 IClientSecurity *pCliSec;
2537 TRACE("%p\n", pProxy);
2539 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2542 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
2543 IClientSecurity_Release(pCliSec);
2546 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);