Propagate apartments through the intermediate threads, make listener
[wine/testsucceed.git] / dlls / ole32 / compobj.c
blob68465802477d3f73fb8e25390edbc993459fb3b8
1 /*
2 * COMPOBJ library
4 * Copyright 1995 Martin von Loewis
5 * Copyright 1998 Justin Bradford
6 * Copyright 1999 Francis Beaudet
7 * Copyright 1999 Sylvain St-Germain
8 * Copyright 2002 Marcus Meissner
9 * Copyright 2004 Mike Hearn
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include "config.h"
28 #include <stdlib.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <assert.h>
34 #define COBJMACROS
35 #define NONAMELESSUNION
36 #define NONAMELESSSTRUCT
38 #include "windef.h"
39 #include "winbase.h"
40 #include "winuser.h"
41 #include "objbase.h"
42 #include "ole2.h"
43 #include "ole2ver.h"
44 #include "rpc.h"
45 #include "winerror.h"
46 #include "winreg.h"
47 #include "wownt32.h"
48 #include "wine/unicode.h"
49 #include "objbase.h"
50 #include "ole32_main.h"
51 #include "compobj_private.h"
53 #include "wine/debug.h"
55 WINE_DEFAULT_DEBUG_CHANNEL(ole);
57 typedef LPCSTR LPCOLESTR16;
59 /****************************************************************************
60 * This section defines variables internal to the COM module.
62 * TODO: Most of these things will have to be made thread-safe.
65 static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk);
66 static void COM_RevokeAllClasses(void);
67 static void COM_ExternalLockFreeList(void);
69 const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
71 APARTMENT MTA, *apts;
73 static CRITICAL_SECTION csApartment;
74 static CRITICAL_SECTION_DEBUG critsect_debug =
76 0, 0, &csApartment,
77 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
78 0, 0, { 0, (DWORD)(__FILE__ ": csApartment") }
80 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
83 * This lock count counts the number of times CoInitialize is called. It is
84 * decreased every time CoUninitialize is called. When it hits 0, the COM
85 * libraries are freed
87 static LONG s_COMLockCount = 0;
90 * This linked list contains the list of registered class objects. These
91 * are mostly used to register the factories for out-of-proc servers of OLE
92 * objects.
94 * TODO: Make this data structure aware of inter-process communication. This
95 * means that parts of this will be exported to the Wine Server.
97 typedef struct tagRegisteredClass
99 CLSID classIdentifier;
100 LPUNKNOWN classObject;
101 DWORD runContext;
102 DWORD connectFlags;
103 DWORD dwCookie;
104 HANDLE hThread; /* only for localserver */
105 struct tagRegisteredClass* nextClass;
106 } RegisteredClass;
108 static RegisteredClass* firstRegisteredClass = NULL;
110 static CRITICAL_SECTION csRegisteredClassList;
111 static CRITICAL_SECTION_DEBUG class_cs_debug =
113 0, 0, &csRegisteredClassList,
114 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
115 0, 0, { 0, (DWORD)(__FILE__ ": csRegisteredClassList") }
117 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
119 /*****************************************************************************
120 * This section contains OpenDllList definitions
122 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
123 * other functions that do LoadLibrary _without_ giving back a HMODULE.
124 * Without this list these handles would never be freed.
126 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
127 * next unload-call but not before 600 sec.
130 typedef struct tagOpenDll {
131 HINSTANCE hLibrary;
132 struct tagOpenDll *next;
133 } OpenDll;
135 static OpenDll *openDllList = NULL; /* linked list of open dlls */
137 static CRITICAL_SECTION csOpenDllList;
138 static CRITICAL_SECTION_DEBUG dll_cs_debug =
140 0, 0, &csOpenDllList,
141 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
142 0, 0, { 0, (DWORD)(__FILE__ ": csOpenDllList") }
144 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
146 static const char aptWinClass[] = "WINE_OLE32_APT_CLASS";
147 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
149 static void COMPOBJ_DLLList_Add(HANDLE hLibrary);
150 static void COMPOBJ_DllList_FreeUnused(int Timeout);
152 void COMPOBJ_InitProcess( void )
154 WNDCLASSA wclass;
156 /* Dispatching to the correct thread in an apartment is done through
157 * window messages rather than RPC transports. When an interface is
158 * marshalled into another apartment in the same process, a window of the
159 * following class is created. The *caller* of CoMarshalInterface (ie the
160 * application) is responsible for pumping the message loop in that thread.
161 * The WM_USER messages which point to the RPCs are then dispatched to
162 * COM_AptWndProc by the user's code from the apartment in which the interface
163 * was unmarshalled.
165 memset(&wclass, 0, sizeof(wclass));
166 wclass.lpfnWndProc = &COM_AptWndProc;
167 wclass.hInstance = OLE32_hInstance;
168 wclass.lpszClassName = aptWinClass;
169 RegisterClassA(&wclass);
172 void COMPOBJ_UninitProcess( void )
174 UnregisterClassA(aptWinClass, OLE32_hInstance);
177 /******************************************************************************
178 * Manage apartments.
182 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
183 with free threaded (ie thread safe) COM objects. There is only ever one MTA
184 in a process - you can enter it by calling CoInitializeEx(COINIT_MULTITHREADED)
186 static void COM_InitMTA(void)
188 /* OXIDs are object exporter IDs. Each apartment has an OXID, which is unique
189 within a network. That is, two different MTAs on different machines will have
190 different OXIDs.
192 This method of generating an OXID is therefore wrong as it doesn't work across
193 a network, but for local RPC only it's OK. We can distinguish between MTAs and
194 STAs because STAs use the thread ID as well, and no thread can have an ID of zero.
196 The algorithm Microsoft use is currently unknown.
198 MTA.oxid = ((OXID)GetCurrentProcessId() << 32);
199 InitializeCriticalSection(&MTA.cs);
202 static void COM_UninitMTA(void)
204 DeleteCriticalSection(&MTA.cs);
205 MTA.oxid = 0;
208 /* creates an apartment structure which stores OLE thread-local
209 * information. Call with COINIT_UNINITIALIZED to create an apartment
210 * that will be initialized with a model later. Note: do not call
211 * with COINIT_UNINITIALIZED if the apartment has already been initialized
212 * with a different COINIT value */
213 APARTMENT* COM_CreateApartment(DWORD model)
215 APARTMENT *apt;
216 BOOL create = (NtCurrentTeb()->ReservedForOle == NULL);
218 if (create)
220 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(APARTMENT));
221 apt->tid = GetCurrentThreadId();
222 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
223 GetCurrentProcess(), &apt->thread,
224 THREAD_ALL_ACCESS, FALSE, 0);
226 else
227 apt = NtCurrentTeb()->ReservedForOle;
229 apt->model = model;
230 if (model & COINIT_APARTMENTTHREADED) {
231 /* FIXME: how does windoze create OXIDs? */
232 apt->oxid = MTA.oxid | GetCurrentThreadId();
233 apt->win = CreateWindowA(aptWinClass, NULL, 0,
234 0, 0, 0, 0,
235 0, 0, OLE32_hInstance, NULL);
236 InitializeCriticalSection(&apt->cs);
238 else if (!(model & COINIT_UNINITIALIZED)) {
239 apt->parent = &MTA;
240 apt->oxid = MTA.oxid;
242 EnterCriticalSection(&csApartment);
243 if (create)
245 if (apts) apts->prev = apt;
246 apt->next = apts;
247 apts = apt;
249 LeaveCriticalSection(&csApartment);
250 NtCurrentTeb()->ReservedForOle = apt;
251 return apt;
254 static void COM_DestroyApartment(APARTMENT *apt)
256 EnterCriticalSection(&csApartment);
257 if (apt->prev) apt->prev->next = apt->next;
258 if (apt->next) apt->next->prev = apt->prev;
259 if (apts == apt) apts = apt->next;
260 apt->prev = NULL; apt->next = NULL;
261 LeaveCriticalSection(&csApartment);
262 if (apt->model & COINIT_APARTMENTTHREADED) {
263 if (apt->win) DestroyWindow(apt->win);
264 DeleteCriticalSection(&apt->cs);
266 CloseHandle(apt->thread);
267 HeapFree(GetProcessHeap(), 0, apt);
270 /* The given OXID must be local to this process: you cannot use apartment
271 windows to send RPCs to other processes. This all needs to move to rpcrt4 */
272 HWND COM_GetApartmentWin(OXID oxid)
274 APARTMENT *apt;
275 HWND win = 0;
277 EnterCriticalSection(&csApartment);
278 apt = apts;
279 while (apt && apt->oxid != oxid) apt = apt->next;
280 if (apt) win = apt->win;
281 LeaveCriticalSection(&csApartment);
282 return win;
285 /* Currently inter-thread marshalling is not fully implemented, so this does nothing */
286 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
288 return DefWindowProcA(hWnd, msg, wParam, lParam);
291 /*****************************************************************************
292 * This section contains OpenDllList implemantation
295 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
297 OpenDll *ptr;
298 OpenDll *tmp;
300 TRACE("\n");
302 EnterCriticalSection( &csOpenDllList );
304 if (openDllList == NULL) {
305 /* empty list -- add first node */
306 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
307 openDllList->hLibrary=hLibrary;
308 openDllList->next = NULL;
309 } else {
310 /* search for this dll */
311 int found = FALSE;
312 for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
313 if (ptr->hLibrary == hLibrary) {
314 found = TRUE;
315 break;
318 if (!found) {
319 /* dll not found, add it */
320 tmp = openDllList;
321 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
322 openDllList->hLibrary = hLibrary;
323 openDllList->next = tmp;
327 LeaveCriticalSection( &csOpenDllList );
330 static void COMPOBJ_DllList_FreeUnused(int Timeout)
332 OpenDll *curr, *next, *prev = NULL;
333 typedef HRESULT(*DllCanUnloadNowFunc)(void);
334 DllCanUnloadNowFunc DllCanUnloadNow;
336 TRACE("\n");
338 EnterCriticalSection( &csOpenDllList );
340 for (curr = openDllList; curr != NULL; ) {
341 DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
343 if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
344 next = curr->next;
346 TRACE("freeing %p\n", curr->hLibrary);
347 FreeLibrary(curr->hLibrary);
349 HeapFree(GetProcessHeap(), 0, curr);
350 if (curr == openDllList) {
351 openDllList = next;
352 } else {
353 prev->next = next;
356 curr = next;
357 } else {
358 prev = curr;
359 curr = curr->next;
363 LeaveCriticalSection( &csOpenDllList );
366 /******************************************************************************
367 * CoBuildVersion [COMPOBJ.1]
368 * CoBuildVersion [OLE32.@]
370 * RETURNS
371 * Current build version, hiword is majornumber, loword is minornumber
373 DWORD WINAPI CoBuildVersion(void)
375 TRACE("Returning version %d, build %d.\n", rmm, rup);
376 return (rmm<<16)+rup;
379 /******************************************************************************
380 * CoInitialize [OLE32.@]
382 * Initializes the COM libraries by calling CoInitializeEx with
383 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
385 * SEE ALSO
386 * CoInitializeEx
388 HRESULT WINAPI CoInitialize(
389 LPVOID lpReserved /* [in] pointer to win32 malloc interface
390 (obsolete, should be NULL) */
394 * Just delegate to the newer method.
396 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
399 /******************************************************************************
400 * CoInitializeEx [OLE32.@]
402 * Initializes the COM libraries. The behavior used to set the win32
403 * IMalloc used for memory management is obsolete. If
404 * COINIT_APARTMENTTHREADED is specified this thread enters a new STA
405 * (single threaded apartment), otherwise COINIT_MULTITHREADED should
406 * be specified which indicates that the thread will enter the MTA.
408 * Currently STA threading is only partly implemented.
410 * RETURNS
411 * S_OK if successful,
412 * S_FALSE if this function was called already.
413 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
414 * threading model.
416 * SEE ALSO
417 * CoUninitialize
419 HRESULT WINAPI CoInitializeEx(
420 LPVOID lpReserved, /* [in] pointer to win32 malloc interface
421 (obsolete, should be NULL) */
422 DWORD dwCoInit /* [in] A value from COINIT specifies the threading model */
425 HRESULT hr = S_OK;
426 APARTMENT *apt;
428 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
430 if (lpReserved!=NULL)
432 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
435 apt = NtCurrentTeb()->ReservedForOle;
436 if (apt && !(apt->model == COINIT_UNINITIALIZED))
438 if (dwCoInit != apt->model)
440 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
441 code then we are probably using the wrong threading model to implement that API. */
442 ERR("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit);
443 return RPC_E_CHANGED_MODE;
445 hr = S_FALSE;
447 else
448 hr = S_OK;
451 * Check the lock count. If this is the first time going through the initialize
452 * process, we have to initialize the libraries.
454 * And crank-up that lock count.
456 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
459 * Initialize the various COM libraries and data structures.
461 TRACE("() - Initializing the COM libraries\n");
463 COM_InitMTA();
465 RunningObjectTableImpl_Initialize();
468 if (!apt || apt->model == COINIT_UNINITIALIZED) apt = COM_CreateApartment(dwCoInit);
470 InterlockedIncrement(&apt->inits);
471 if (hr == S_OK) NtCurrentTeb()->ReservedForOle = apt;
473 return hr;
476 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
477 pending RPCs are ignored. Non-COM messages are discarded at this point.
479 void COM_FlushMessageQueue(void)
481 MSG message;
482 APARTMENT *apt = NtCurrentTeb()->ReservedForOle;
484 if (!apt || !apt->win) return;
486 TRACE("Flushing STA message queue\n");
488 while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE)) {
489 if (message.hwnd != apt->win) continue;
490 TranslateMessage(&message);
491 DispatchMessageA(&message);
495 /***********************************************************************
496 * CoUninitialize [OLE32.@]
498 * This method will decrement the refcount on the COM libraries,
499 * potentially unloading them. The current thread leaves the apartment
500 * it's currently in. If not in an apartment, the routine does
501 * nothing.
503 * If COM is to be shut down, any outstanding proxies are
504 * disconnected, all registered class objects are unregistered and the
505 * message queue for the thread is flushed (if native does
506 * this or not is unknown).
508 * SEE ALSO
509 * CoInitializeEx
511 void WINAPI CoUninitialize(void)
513 LONG lCOMRefCnt;
514 APARTMENT *apt;
516 TRACE("()\n");
518 apt = NtCurrentTeb()->ReservedForOle;
519 if (!apt) return;
520 if (InterlockedDecrement(&apt->inits)==0) {
521 NtCurrentTeb()->ReservedForOle = NULL;
522 COM_DestroyApartment(apt);
523 apt = NULL;
527 * Decrease the reference count.
528 * If we are back to 0 locks on the COM library, make sure we free
529 * all the associated data structures.
531 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
532 if (lCOMRefCnt==1)
534 TRACE("() - Releasing the COM libraries\n");
536 RunningObjectTableImpl_UnInitialize();
538 /* disconnect proxies to release the corresponding stubs.
539 * It is confirmed in "Essential COM" in the sub-chapter on
540 * "Lifecycle Management and Marshalling" that the native version also
541 * does some kind of proxy cleanup in this function.
542 * FIXME: does it just disconnect or completely destroy the proxies?
543 * FIXME: should this be in the apartment destructor? */
544 MARSHAL_Disconnect_Proxies();
546 /* Release the references to the registered class objects */
547 COM_RevokeAllClasses();
549 /* This will free the loaded COM Dlls */
550 CoFreeAllLibraries();
552 /* This will free list of external references to COM objects */
553 COM_ExternalLockFreeList();
555 /* This ensures we deal with any pending RPCs */
556 COM_FlushMessageQueue();
558 COM_UninitMTA();
560 else if (lCOMRefCnt<1) {
561 ERR( "CoUninitialize() - not CoInitialized.\n" );
562 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
566 /******************************************************************************
567 * CoDisconnectObject [COMPOBJ.15]
568 * CoDisconnectObject [OLE32.@]
570 * Disconnects all connections to this object from remote processes. Dispatches
571 * pending RPCs while blocking new RPCs from occurring, and then calls
572 * IMarshal::DisconnectObject on the given object.
574 * Typically called when the object server is forced to shut down, for instance by
575 * the user.
577 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
579 FIXME("(%p, %lx): stub - probably harmless\n",lpUnk,reserved);
580 return S_OK;
583 /******************************************************************************
584 * CoCreateGuid[OLE32.@]
586 * Simply forwards to UuidCreate in RPCRT4.
588 * SEE ALSO
589 * UuidCreate
592 HRESULT WINAPI CoCreateGuid(
593 GUID *pguid /* [out] points to the GUID to initialize */
595 return UuidCreate(pguid);
598 /******************************************************************************
599 * CLSIDFromString [OLE32.@]
600 * IIDFromString [OLE32.@]
602 * Converts a unique identifier from its string representation into
603 * the GUID struct.
605 * In Windows, if idstr is not a valid CLSID string then it gets
606 * treated as a ProgID. Wine currently doesn't do this. If idstr is
607 * NULL it's treated as an all-zero GUID.
609 * RETURNS
610 * S_OK on success
611 * CO_E_CLASSSTRING if idstr is not a valid CLSID
613 HRESULT WINAPI __CLSIDFromStringA(
614 LPCSTR idstr, /* [in] string representation of guid */
615 CLSID *id) /* [out] GUID converted from string */
617 const BYTE *s = (const BYTE *) idstr;
618 int i;
619 BYTE table[256];
621 if (!s)
622 s = "{00000000-0000-0000-0000-000000000000}";
623 else { /* validate the CLSID string */
625 if (strlen(s) != 38)
626 return CO_E_CLASSSTRING;
628 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
629 return CO_E_CLASSSTRING;
631 for (i=1; i<37; i++) {
632 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
633 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
634 ((s[i] >= 'a') && (s[i] <= 'f')) ||
635 ((s[i] >= 'A') && (s[i] <= 'F'))))
636 return CO_E_CLASSSTRING;
640 TRACE("%s -> %p\n", s, id);
642 /* quick lookup table */
643 memset(table, 0, 256);
645 for (i = 0; i < 10; i++) {
646 table['0' + i] = i;
648 for (i = 0; i < 6; i++) {
649 table['A' + i] = i+10;
650 table['a' + i] = i+10;
653 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
655 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
656 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
657 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
658 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
660 /* these are just sequential bytes */
661 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
662 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
663 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
664 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
665 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
666 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
667 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
668 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
670 return S_OK;
673 /*****************************************************************************/
675 HRESULT WINAPI CLSIDFromString(
676 LPOLESTR idstr, /* [in] string representation of GUID */
677 CLSID *id ) /* [out] GUID represented by above string */
679 char xid[40];
680 HRESULT ret;
682 if (!WideCharToMultiByte( CP_ACP, 0, idstr, -1, xid, sizeof(xid), NULL, NULL ))
683 return CO_E_CLASSSTRING;
686 ret = __CLSIDFromStringA(xid,id);
687 if(ret != S_OK) { /* It appears a ProgID is also valid */
688 ret = CLSIDFromProgID(idstr, id);
690 return ret;
693 /* Converts a GUID into the respective string representation. */
694 HRESULT WINE_StringFromCLSID(
695 const CLSID *id, /* [in] GUID to be converted */
696 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
698 static const char *hex = "0123456789ABCDEF";
699 char *s;
700 int i;
702 if (!id)
703 { ERR("called with id=Null\n");
704 *idstr = 0x00;
705 return E_FAIL;
708 sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
709 id->Data1, id->Data2, id->Data3,
710 id->Data4[0], id->Data4[1]);
711 s = &idstr[25];
713 /* 6 hex bytes */
714 for (i = 2; i < 8; i++) {
715 *s++ = hex[id->Data4[i]>>4];
716 *s++ = hex[id->Data4[i] & 0xf];
719 *s++ = '}';
720 *s++ = '\0';
722 TRACE("%p->%s\n", id, idstr);
724 return S_OK;
728 /******************************************************************************
729 * StringFromCLSID [OLE32.@]
730 * StringFromIID [OLE32.@]
732 * Converts a GUID into the respective string representation.
733 * The target string is allocated using the OLE IMalloc.
735 * RETURNS
736 * S_OK
737 * E_FAIL
739 HRESULT WINAPI StringFromCLSID(
740 REFCLSID id, /* [in] the GUID to be converted */
741 LPOLESTR *idstr /* [out] a pointer to a to-be-allocated pointer pointing to the resulting string */
743 char buf[80];
744 HRESULT ret;
745 LPMALLOC mllc;
747 if ((ret = CoGetMalloc(0,&mllc)))
748 return ret;
750 ret=WINE_StringFromCLSID(id,buf);
751 if (!ret) {
752 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
753 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
754 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
756 return ret;
759 /******************************************************************************
760 * StringFromGUID2 [COMPOBJ.76]
761 * StringFromGUID2 [OLE32.@]
763 * Modified version of StringFromCLSID that allows you to specify max
764 * buffer size.
766 * RETURNS
767 * The length of the resulting string, 0 if there was any problem.
769 INT WINAPI StringFromGUID2(
770 REFGUID id, /* [in] GUID to convert to string */
771 LPOLESTR str, /* [out] Unicode buffer to hold result */
772 INT cmax)
774 char xguid[80];
776 if (WINE_StringFromCLSID(id,xguid))
777 return 0;
778 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
781 /******************************************************************************
782 * ProgIDFromCLSID [OLE32.@]
784 * Converts a class id into the respective Program ID. (By using a
785 * registry lookup)
787 * RETURNS
788 * S_OK
789 * E_OUTOFMEMORY
790 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
792 HRESULT WINAPI ProgIDFromCLSID(
793 REFCLSID clsid, /* [in] class id as found in registry */
794 LPOLESTR *lplpszProgID/* [out] associated Prog ID */
797 char strCLSID[50], *buf, *buf2;
798 DWORD buf2len;
799 HKEY xhkey;
800 LPMALLOC mllc;
801 HRESULT ret = S_OK;
803 WINE_StringFromCLSID(clsid, strCLSID);
805 buf = HeapAlloc(GetProcessHeap(), 0, strlen(strCLSID)+14);
806 sprintf(buf,"CLSID\\%s\\ProgID", strCLSID);
807 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
808 ret = REGDB_E_CLASSNOTREG;
810 HeapFree(GetProcessHeap(), 0, buf);
812 if (ret == S_OK)
814 buf2 = HeapAlloc(GetProcessHeap(), 0, 255);
815 buf2len = 255;
816 if (RegQueryValueA(xhkey, NULL, buf2, &buf2len))
817 ret = REGDB_E_CLASSNOTREG;
819 if (ret == S_OK)
821 if (CoGetMalloc(0,&mllc))
822 ret = E_OUTOFMEMORY;
823 else
825 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf2, -1, NULL, 0 );
826 *lplpszProgID = IMalloc_Alloc(mllc, len * sizeof(WCHAR) );
827 MultiByteToWideChar( CP_ACP, 0, buf2, -1, *lplpszProgID, len );
830 HeapFree(GetProcessHeap(), 0, buf2);
833 RegCloseKey(xhkey);
834 return ret;
837 HRESULT WINAPI CLSIDFromProgID16(
838 LPCOLESTR16 progid, /* [in] program id as found in registry */
839 LPCLSID riid /* [out] associated CLSID */
841 char *buf,buf2[80];
842 DWORD buf2len;
843 HRESULT err;
844 HKEY xhkey;
846 buf = HeapAlloc(GetProcessHeap(),0,strlen(progid)+8);
847 sprintf(buf,"%s\\CLSID",progid);
848 if ((err=RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&xhkey))) {
849 HeapFree(GetProcessHeap(),0,buf);
850 return CO_E_CLASSSTRING;
852 HeapFree(GetProcessHeap(),0,buf);
853 buf2len = sizeof(buf2);
854 if ((err=RegQueryValueA(xhkey,NULL,buf2,&buf2len))) {
855 RegCloseKey(xhkey);
856 return CO_E_CLASSSTRING;
858 RegCloseKey(xhkey);
859 return __CLSIDFromStringA(buf2,riid);
862 /******************************************************************************
863 * CLSIDFromProgID [COMPOBJ.61]
865 * Converts a program id into the respective GUID. (By using a
866 * registry lookup)
868 * RETURNS
869 * S_OK
870 * CO_E_CLASSSTRING if the given ProgID cannot be found
872 HRESULT WINAPI CLSIDFromProgID(
873 LPCOLESTR progid, /* [in] Unicode program id as found in registry */
874 LPCLSID riid ) /* [out] associated CLSID */
876 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
877 char buf2[80];
878 DWORD buf2len = sizeof(buf2);
879 HKEY xhkey;
881 WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
882 strcpyW( buf, progid );
883 strcatW( buf, clsidW );
884 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
886 HeapFree(GetProcessHeap(),0,buf);
887 return CO_E_CLASSSTRING;
889 HeapFree(GetProcessHeap(),0,buf);
891 if (RegQueryValueA(xhkey,NULL,buf2,&buf2len))
893 RegCloseKey(xhkey);
894 return CO_E_CLASSSTRING;
896 RegCloseKey(xhkey);
897 return __CLSIDFromStringA(buf2,riid);
902 /*****************************************************************************
903 * CoGetPSClsid [OLE32.@]
905 * This function returns the CLSID of the proxy/stub factory that
906 * implements IPSFactoryBuffer for the specified interface.
908 * The standard marshaller activates the object with the CLSID
909 * returned and uses the CreateProxy and CreateStub methods on its
910 * IPSFactoryBuffer interface to construct the proxies and stubs for a
911 * given object.
913 * CoGetPSClsid determines this CLSID by searching the
914 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
915 * in the registry and any interface id registered by
916 * CoRegisterPSClsid within the current process.
918 * FIXME: We only search the registry, not ids registered with
919 * CoRegisterPSClsid.
921 * RETURNS
922 * S_OK
923 * E_OUTOFMEMORY
924 * E_INVALIDARG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
926 HRESULT WINAPI CoGetPSClsid(
927 REFIID riid, /* [in] Interface whose proxy/stub CLSID is to be returned */
928 CLSID *pclsid ) /* [out] Where to store returned proxy/stub CLSID */
930 char *buf, buf2[40];
931 DWORD buf2len;
932 HKEY xhkey;
934 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
936 /* Get the input iid as a string */
937 WINE_StringFromCLSID(riid, buf2);
938 /* Allocate memory for the registry key we will construct.
939 (length of iid string plus constant length of static text */
940 buf = HeapAlloc(GetProcessHeap(), 0, strlen(buf2)+27);
941 if (buf == NULL)
943 return (E_OUTOFMEMORY);
946 /* Construct the registry key we want */
947 sprintf(buf,"Interface\\%s\\ProxyStubClsid32", buf2);
949 /* Open the key.. */
950 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
952 WARN("No PSFactoryBuffer object is registered for this IID\n");
953 HeapFree(GetProcessHeap(),0,buf);
954 return (E_INVALIDARG);
956 HeapFree(GetProcessHeap(),0,buf);
958 /* ... Once we have the key, query the registry to get the
959 value of CLSID as a string, and convert it into a
960 proper CLSID structure to be passed back to the app */
961 buf2len = sizeof(buf2);
962 if ( (RegQueryValueA(xhkey,NULL,buf2,&buf2len)) )
964 RegCloseKey(xhkey);
965 return E_INVALIDARG;
967 RegCloseKey(xhkey);
969 /* We have the CLSid we want back from the registry as a string, so
970 lets convert it into a CLSID structure */
971 if ( (__CLSIDFromStringA(buf2,pclsid)) != NOERROR) {
972 return E_INVALIDARG;
975 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
976 return (S_OK);
981 /***********************************************************************
982 * WriteClassStm (OLE32.@)
984 * This function write a CLSID on stream
986 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
988 TRACE("(%p,%p)\n",pStm,rclsid);
990 if (rclsid==NULL)
991 return E_INVALIDARG;
993 return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
996 /***********************************************************************
997 * ReadClassStm (OLE32.@)
999 * This function read a CLSID from a stream
1001 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
1003 ULONG nbByte;
1004 HRESULT res;
1006 TRACE("(%p,%p)\n",pStm,pclsid);
1008 if (pclsid==NULL)
1009 return E_INVALIDARG;
1011 res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
1013 if (FAILED(res))
1014 return res;
1016 if (nbByte != sizeof(CLSID))
1017 return S_FALSE;
1018 else
1019 return S_OK;
1023 /***
1024 * COM_GetRegisteredClassObject
1026 * This internal method is used to scan the registered class list to
1027 * find a class object.
1029 * Params:
1030 * rclsid Class ID of the class to find.
1031 * dwClsContext Class context to match.
1032 * ppv [out] returns a pointer to the class object. Complying
1033 * to normal COM usage, this method will increase the
1034 * reference count on this object.
1036 static HRESULT COM_GetRegisteredClassObject(
1037 REFCLSID rclsid,
1038 DWORD dwClsContext,
1039 LPUNKNOWN* ppUnk)
1041 HRESULT hr = S_FALSE;
1042 RegisteredClass* curClass;
1044 EnterCriticalSection( &csRegisteredClassList );
1047 * Sanity check
1049 assert(ppUnk!=0);
1052 * Iterate through the whole list and try to match the class ID.
1054 curClass = firstRegisteredClass;
1056 while (curClass != 0)
1059 * Check if we have a match on the class ID.
1061 if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
1064 * Since we don't do out-of process or DCOM just right away, let's ignore the
1065 * class context.
1069 * We have a match, return the pointer to the class object.
1071 *ppUnk = curClass->classObject;
1073 IUnknown_AddRef(curClass->classObject);
1075 hr = S_OK;
1076 goto end;
1080 * Step to the next class in the list.
1082 curClass = curClass->nextClass;
1085 end:
1086 LeaveCriticalSection( &csRegisteredClassList );
1088 * If we get to here, we haven't found our class.
1090 return hr;
1093 static DWORD WINAPI
1094 _LocalServerThread(LPVOID param) {
1095 HANDLE hPipe;
1096 char pipefn[200];
1097 RegisteredClass *newClass = (RegisteredClass*)param;
1098 HRESULT hres;
1099 IStream *pStm;
1100 STATSTG ststg;
1101 unsigned char *buffer;
1102 int buflen;
1103 IClassFactory *classfac;
1104 LARGE_INTEGER seekto;
1105 ULARGE_INTEGER newpos;
1106 ULONG res;
1108 TRACE("Starting classfactory server thread for %s.\n",debugstr_guid(&newClass->classIdentifier));
1110 strcpy(pipefn,PIPEPREF);
1111 WINE_StringFromCLSID(&newClass->classIdentifier,pipefn+strlen(PIPEPREF));
1113 hPipe = CreateNamedPipeA( pipefn, PIPE_ACCESS_DUPLEX,
1114 PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
1115 4096, 4096, NMPWAIT_USE_DEFAULT_WAIT, NULL );
1116 if (hPipe == INVALID_HANDLE_VALUE) {
1117 FIXME("pipe creation failed for %s, le is %lx\n",pipefn,GetLastError());
1118 return 1;
1120 while (1) {
1121 if (!ConnectNamedPipe(hPipe,NULL)) {
1122 ERR("Failure during ConnectNamedPipe %lx, ABORT!\n",GetLastError());
1123 break;
1126 TRACE("marshalling IClassFactory to client\n");
1128 hres = IUnknown_QueryInterface(newClass->classObject,&IID_IClassFactory,(LPVOID*)&classfac);
1129 if (hres) return hres;
1131 hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
1132 if (hres) {
1133 FIXME("Failed to create stream on hglobal.\n");
1134 return hres;
1136 hres = CoMarshalInterface(pStm,&IID_IClassFactory,(LPVOID)classfac,0,NULL,0);
1137 if (hres) {
1138 FIXME("CoMarshalInterface failed, %lx!\n",hres);
1139 return hres;
1142 IUnknown_Release(classfac); /* is this right? */
1144 hres = IStream_Stat(pStm,&ststg,0);
1145 if (hres) return hres;
1147 buflen = ststg.cbSize.u.LowPart;
1148 buffer = HeapAlloc(GetProcessHeap(),0,buflen);
1149 seekto.u.LowPart = 0;
1150 seekto.u.HighPart = 0;
1151 hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
1152 if (hres) {
1153 FIXME("IStream_Seek failed, %lx\n",hres);
1154 return hres;
1157 hres = IStream_Read(pStm,buffer,buflen,&res);
1158 if (hres) {
1159 FIXME("Stream Read failed, %lx\n",hres);
1160 return hres;
1163 IStream_Release(pStm);
1165 WriteFile(hPipe,buffer,buflen,&res,NULL);
1166 FlushFileBuffers(hPipe);
1167 DisconnectNamedPipe(hPipe);
1169 TRACE("done marshalling IClassFactory\n");
1171 CloseHandle(hPipe);
1172 return 0;
1175 /******************************************************************************
1176 * CoRegisterClassObject [OLE32.@]
1178 * This method will register the class object for a given class
1179 * ID. Servers housed in EXE files use this method instead of
1180 * exporting DllGetClassObject to allow other code to connect to their
1181 * objects.
1183 * When a class object (an object which implements IClassFactory) is
1184 * registered in this way, a new thread is started which listens for
1185 * connections on a named pipe specific to the registered CLSID. When
1186 * something else connects to it, it writes out the marshalled
1187 * IClassFactory interface to the pipe. The code on the other end uses
1188 * this buffer to unmarshal the class factory, and can then call
1189 * methods on it.
1191 * In Windows, such objects are registered with the RPC endpoint
1192 * mapper, not with a unique named pipe.
1194 * MSDN claims that multiple interface registrations are legal, but we
1195 * can't do that with our current implementation.
1197 * RETURNS
1198 * S_OK on success,
1199 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1200 * CO_E_OBJISREG if the object is already registered. We should not return this.
1202 * SEE ALSO
1203 * CoRevokeClassObject, CoGetClassObject
1205 HRESULT WINAPI CoRegisterClassObject(
1206 REFCLSID rclsid, /* [in] CLSID of the object to register */
1207 LPUNKNOWN pUnk, /* [in] IUnknown of the object */
1208 DWORD dwClsContext, /* [in] CLSCTX flags indicating the context in which to run the executable */
1209 DWORD flags, /* [in] REGCLS flags indicating how connections are made */
1210 LPDWORD lpdwRegister) /* [out] A unique cookie that can be passed to CoRevokeClassObject */
1212 RegisteredClass* newClass;
1213 LPUNKNOWN foundObject;
1214 HRESULT hr;
1216 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1217 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1219 if ( (lpdwRegister==0) || (pUnk==0) )
1220 return E_INVALIDARG;
1222 *lpdwRegister = 0;
1225 * First, check if the class is already registered.
1226 * If it is, this should cause an error.
1228 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1229 if (hr == S_OK) {
1230 IUnknown_Release(foundObject);
1231 return CO_E_OBJISREG;
1234 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1235 if ( newClass == NULL )
1236 return E_OUTOFMEMORY;
1238 EnterCriticalSection( &csRegisteredClassList );
1240 newClass->classIdentifier = *rclsid;
1241 newClass->runContext = dwClsContext;
1242 newClass->connectFlags = flags;
1244 * Use the address of the chain node as the cookie since we are sure it's
1245 * unique.
1247 newClass->dwCookie = (DWORD)newClass;
1248 newClass->nextClass = firstRegisteredClass;
1251 * Since we're making a copy of the object pointer, we have to increase its
1252 * reference count.
1254 newClass->classObject = pUnk;
1255 IUnknown_AddRef(newClass->classObject);
1257 firstRegisteredClass = newClass;
1258 LeaveCriticalSection( &csRegisteredClassList );
1260 *lpdwRegister = newClass->dwCookie;
1262 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1263 DWORD tid;
1265 start_apartment_listener_thread();
1266 newClass->hThread = CreateThread(NULL,0,_LocalServerThread,newClass,0,&tid);
1268 return S_OK;
1271 /***********************************************************************
1272 * CoRevokeClassObject [OLE32.@]
1274 * This method will remove a class object from the class registry
1276 * See the Windows documentation for more details.
1278 HRESULT WINAPI CoRevokeClassObject(
1279 DWORD dwRegister)
1281 HRESULT hr = E_INVALIDARG;
1282 RegisteredClass** prevClassLink;
1283 RegisteredClass* curClass;
1285 TRACE("(%08lx)\n",dwRegister);
1287 EnterCriticalSection( &csRegisteredClassList );
1290 * Iterate through the whole list and try to match the cookie.
1292 curClass = firstRegisteredClass;
1293 prevClassLink = &firstRegisteredClass;
1295 while (curClass != 0)
1298 * Check if we have a match on the cookie.
1300 if (curClass->dwCookie == dwRegister)
1303 * Remove the class from the chain.
1305 *prevClassLink = curClass->nextClass;
1308 * Release the reference to the class object.
1310 IUnknown_Release(curClass->classObject);
1313 * Free the memory used by the chain node.
1315 HeapFree(GetProcessHeap(), 0, curClass);
1317 hr = S_OK;
1318 goto end;
1322 * Step to the next class in the list.
1324 prevClassLink = &(curClass->nextClass);
1325 curClass = curClass->nextClass;
1328 end:
1329 LeaveCriticalSection( &csRegisteredClassList );
1331 * If we get to here, we haven't found our class.
1333 return hr;
1336 /***********************************************************************
1337 * compobj_RegReadPath [internal]
1339 * Reads a registry value and expands it when necessary
1341 HRESULT compobj_RegReadPath(char * keyname, char * valuename, char * dst, DWORD dstlen)
1343 HRESULT hres;
1344 HKEY key;
1345 DWORD keytype;
1346 char src[MAX_PATH];
1347 DWORD dwLength = dstlen;
1349 if((hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1350 if( (hres = RegQueryValueExA(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1351 if (keytype == REG_EXPAND_SZ) {
1352 if (dstlen <= ExpandEnvironmentStringsA(src, dst, dstlen)) hres = ERROR_MORE_DATA;
1353 } else {
1354 lstrcpynA(dst, src, dstlen);
1357 RegCloseKey (key);
1359 return hres;
1362 /***********************************************************************
1363 * CoGetClassObject [COMPOBJ.7]
1364 * CoGetClassObject [OLE32.@]
1366 * FIXME. If request allows of several options and there is a failure
1367 * with one (other than not being registered) do we try the
1368 * others or return failure? (E.g. inprocess is registered but
1369 * the DLL is not found but the server version works)
1371 HRESULT WINAPI CoGetClassObject(
1372 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1373 REFIID iid, LPVOID *ppv
1375 LPUNKNOWN regClassObject;
1376 HRESULT hres = E_UNEXPECTED;
1377 char xclsid[80];
1378 HINSTANCE hLibrary;
1379 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1380 DllGetClassObjectFunc DllGetClassObject;
1382 WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
1384 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1386 if (pServerInfo) {
1387 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1388 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1392 * First, try and see if we can't match the class ID with one of the
1393 * registered classes.
1395 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, &regClassObject))
1398 * Get the required interface from the retrieved pointer.
1400 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1403 * Since QI got another reference on the pointer, we want to release the
1404 * one we already have. If QI was unsuccessful, this will release the object. This
1405 * is good since we are not returning it in the "out" parameter.
1407 IUnknown_Release(regClassObject);
1409 return hres;
1412 /* first try: in-process */
1413 if ((CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER) & dwClsContext) {
1414 char keyname[MAX_PATH];
1415 char dllpath[MAX_PATH+1];
1417 sprintf(keyname,"CLSID\\%s\\InprocServer32",xclsid);
1419 if ( compobj_RegReadPath(keyname, NULL, dllpath, sizeof(dllpath)) != ERROR_SUCCESS) {
1420 /* failure: CLSID is not found in registry */
1421 WARN("class %s not registered inproc\n", xclsid);
1422 hres = REGDB_E_CLASSNOTREG;
1423 } else {
1424 if ((hLibrary = LoadLibraryExA(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) {
1425 /* failure: DLL could not be loaded */
1426 ERR("couldn't load InprocServer32 dll %s\n", dllpath);
1427 hres = E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1428 } else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject"))) {
1429 /* failure: the dll did not export DllGetClassObject */
1430 ERR("couldn't find function DllGetClassObject in %s\n", dllpath);
1431 FreeLibrary( hLibrary );
1432 hres = CO_E_DLLNOTFOUND;
1433 } else {
1434 /* OK: get the ClassObject */
1435 COMPOBJ_DLLList_Add( hLibrary );
1436 return DllGetClassObject(rclsid, iid, ppv);
1441 /* Next try out of process */
1442 if (CLSCTX_LOCAL_SERVER & dwClsContext)
1444 return create_marshalled_proxy(rclsid,iid,ppv);
1447 /* Finally try remote: this requires networked DCOM (a lot of work) */
1448 if (CLSCTX_REMOTE_SERVER & dwClsContext)
1450 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1451 hres = E_NOINTERFACE;
1454 return hres;
1456 /***********************************************************************
1457 * CoResumeClassObjects (OLE32.@)
1459 * Resumes classobjects registered with REGCLS suspended
1461 HRESULT WINAPI CoResumeClassObjects(void)
1463 FIXME("stub\n");
1464 return S_OK;
1467 /***********************************************************************
1468 * GetClassFile (OLE32.@)
1470 * This function supplies the CLSID associated with the given filename.
1472 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1474 IStorage *pstg=0;
1475 HRESULT res;
1476 int nbElm, length, i;
1477 LONG sizeProgId;
1478 LPOLESTR *pathDec=0,absFile=0,progId=0;
1479 LPWSTR extension;
1480 static const WCHAR bkslashW[] = {'\\',0};
1481 static const WCHAR dotW[] = {'.',0};
1483 TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1485 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1486 if((StgIsStorageFile(filePathName))==S_OK){
1488 res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1490 if (SUCCEEDED(res))
1491 res=ReadClassStg(pstg,pclsid);
1493 IStorage_Release(pstg);
1495 return res;
1497 /* if the file is not a storage object then attemps to match various bits in the file against a
1498 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1499 this case
1501 for(i=0;i<nFileTypes;i++)
1503 for(i=0;j<nPatternsForType;j++){
1505 PATTERN pat;
1506 HANDLE hFile;
1508 pat=ReadPatternFromRegistry(i,j);
1509 hFile=CreateFileW(filePathName,,,,,,hFile);
1510 SetFilePosition(hFile,pat.offset);
1511 ReadFile(hFile,buf,pat.size,&r,NULL);
1512 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1514 *pclsid=ReadCLSIDFromRegistry(i);
1515 return S_OK;
1520 /* if the above strategies fail then search for the extension key in the registry */
1522 /* get the last element (absolute file) in the path name */
1523 nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1524 absFile=pathDec[nbElm-1];
1526 /* failed if the path represente a directory and not an absolute file name*/
1527 if (!lstrcmpW(absFile, bkslashW))
1528 return MK_E_INVALIDEXTENSION;
1530 /* get the extension of the file */
1531 extension = NULL;
1532 length=lstrlenW(absFile);
1533 for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1534 /* nothing */;
1536 if (!extension || !lstrcmpW(extension, dotW))
1537 return MK_E_INVALIDEXTENSION;
1539 res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1541 /* get the progId associated to the extension */
1542 progId = CoTaskMemAlloc(sizeProgId);
1543 res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1545 if (res==ERROR_SUCCESS)
1546 /* return the clsid associated to the progId */
1547 res= CLSIDFromProgID(progId,pclsid);
1549 for(i=0; pathDec[i]!=NULL;i++)
1550 CoTaskMemFree(pathDec[i]);
1551 CoTaskMemFree(pathDec);
1553 CoTaskMemFree(progId);
1555 if (res==ERROR_SUCCESS)
1556 return res;
1558 return MK_E_INVALIDEXTENSION;
1560 /***********************************************************************
1561 * CoCreateInstance [COMPOBJ.13]
1562 * CoCreateInstance [OLE32.@]
1564 HRESULT WINAPI CoCreateInstance(
1565 REFCLSID rclsid,
1566 LPUNKNOWN pUnkOuter,
1567 DWORD dwClsContext,
1568 REFIID iid,
1569 LPVOID *ppv)
1571 HRESULT hres;
1572 LPCLASSFACTORY lpclf = 0;
1574 if (!COM_CurrentApt()) return CO_E_NOTINITIALIZED;
1577 * Sanity check
1579 if (ppv==0)
1580 return E_POINTER;
1583 * Initialize the "out" parameter
1585 *ppv = 0;
1588 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1589 * Rather than create a class factory, we can just check for it here
1591 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
1592 if (StdGlobalInterfaceTableInstance == NULL)
1593 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
1594 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
1595 if (hres) return hres;
1597 TRACE("Retrieved GIT (%p)\n", *ppv);
1598 return S_OK;
1602 * Get a class factory to construct the object we want.
1604 hres = CoGetClassObject(rclsid,
1605 dwClsContext,
1606 NULL,
1607 &IID_IClassFactory,
1608 (LPVOID)&lpclf);
1610 if (FAILED(hres)) {
1611 FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n",
1612 debugstr_guid(rclsid),hres);
1613 return hres;
1617 * Create the object and don't forget to release the factory
1619 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
1620 IClassFactory_Release(lpclf);
1621 if(FAILED(hres))
1622 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1623 debugstr_guid(iid), debugstr_guid(rclsid),hres);
1625 return hres;
1628 /***********************************************************************
1629 * CoCreateInstanceEx [OLE32.@]
1631 HRESULT WINAPI CoCreateInstanceEx(
1632 REFCLSID rclsid,
1633 LPUNKNOWN pUnkOuter,
1634 DWORD dwClsContext,
1635 COSERVERINFO* pServerInfo,
1636 ULONG cmq,
1637 MULTI_QI* pResults)
1639 IUnknown* pUnk = NULL;
1640 HRESULT hr;
1641 ULONG index;
1642 ULONG successCount = 0;
1645 * Sanity check
1647 if ( (cmq==0) || (pResults==NULL))
1648 return E_INVALIDARG;
1650 if (pServerInfo!=NULL)
1651 FIXME("() non-NULL pServerInfo not supported!\n");
1654 * Initialize all the "out" parameters.
1656 for (index = 0; index < cmq; index++)
1658 pResults[index].pItf = NULL;
1659 pResults[index].hr = E_NOINTERFACE;
1663 * Get the object and get its IUnknown pointer.
1665 hr = CoCreateInstance(rclsid,
1666 pUnkOuter,
1667 dwClsContext,
1668 &IID_IUnknown,
1669 (VOID**)&pUnk);
1671 if (hr)
1672 return hr;
1675 * Then, query for all the interfaces requested.
1677 for (index = 0; index < cmq; index++)
1679 pResults[index].hr = IUnknown_QueryInterface(pUnk,
1680 pResults[index].pIID,
1681 (VOID**)&(pResults[index].pItf));
1683 if (pResults[index].hr == S_OK)
1684 successCount++;
1688 * Release our temporary unknown pointer.
1690 IUnknown_Release(pUnk);
1692 if (successCount == 0)
1693 return E_NOINTERFACE;
1695 if (successCount!=cmq)
1696 return CO_S_NOTALLINTERFACES;
1698 return S_OK;
1701 /***********************************************************************
1702 * CoLoadLibrary (OLE32.@)
1704 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
1706 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
1708 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
1711 /***********************************************************************
1712 * CoFreeLibrary [OLE32.@]
1714 * NOTES: don't believe the documentation
1716 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
1718 FreeLibrary(hLibrary);
1722 /***********************************************************************
1723 * CoFreeAllLibraries [OLE32.@]
1725 * NOTES: don't believe the documentation
1727 void WINAPI CoFreeAllLibraries(void)
1729 /* NOP */
1733 /***********************************************************************
1734 * CoFreeUnusedLibraries [COMPOBJ.17]
1735 * CoFreeUnusedLibraries [OLE32.@]
1737 * FIXME: Calls to CoFreeUnusedLibraries from any thread always route
1738 * through the main apartment's thread to call DllCanUnloadNow
1740 void WINAPI CoFreeUnusedLibraries(void)
1742 COMPOBJ_DllList_FreeUnused(0);
1745 /***********************************************************************
1746 * CoFileTimeNow [COMPOBJ.82]
1747 * CoFileTimeNow [OLE32.@]
1749 * RETURNS
1750 * the current system time in lpFileTime
1752 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime ) /* [out] the current time */
1754 GetSystemTimeAsFileTime( lpFileTime );
1755 return S_OK;
1758 /***********************************************************************
1759 * CoLoadLibrary (OLE32.@)
1761 static void COM_RevokeAllClasses()
1763 EnterCriticalSection( &csRegisteredClassList );
1765 while (firstRegisteredClass!=0)
1767 CoRevokeClassObject(firstRegisteredClass->dwCookie);
1770 LeaveCriticalSection( &csRegisteredClassList );
1773 /****************************************************************************
1774 * COM External Lock methods implementation
1776 * This api provides a linked list to managed external references to
1777 * COM objects.
1779 * The public interface consists of three calls:
1780 * COM_ExternalLockAddRef
1781 * COM_ExternalLockRelease
1782 * COM_ExternalLockFreeList
1785 #define EL_END_OF_LIST 0
1786 #define EL_NOT_FOUND 0
1789 * Declaration of the static structure that manage the
1790 * external lock to COM objects.
1792 typedef struct COM_ExternalLock COM_ExternalLock;
1793 typedef struct COM_ExternalLockList COM_ExternalLockList;
1795 struct COM_ExternalLock
1797 IUnknown *pUnk; /* IUnknown referenced */
1798 ULONG uRefCount; /* external lock counter to IUnknown object*/
1799 COM_ExternalLock *next; /* Pointer to next element in list */
1802 struct COM_ExternalLockList
1804 COM_ExternalLock *head; /* head of list */
1808 * Declaration and initialization of the static structure that manages
1809 * the external lock to COM objects.
1811 static COM_ExternalLockList elList = { EL_END_OF_LIST };
1814 * Private methods used to managed the linked list
1818 static COM_ExternalLock* COM_ExternalLockLocate(
1819 COM_ExternalLock *element,
1820 IUnknown *pUnk);
1822 /****************************************************************************
1823 * Internal - Insert a new IUnknown* to the linked list
1825 static BOOL COM_ExternalLockInsert(
1826 IUnknown *pUnk)
1828 COM_ExternalLock *newLock = NULL;
1829 COM_ExternalLock *previousHead = NULL;
1832 * Allocate space for the new storage object
1834 newLock = HeapAlloc(GetProcessHeap(), 0, sizeof(COM_ExternalLock));
1836 if (newLock!=NULL) {
1837 if ( elList.head == EL_END_OF_LIST ) {
1838 elList.head = newLock; /* The list is empty */
1839 } else {
1840 /* insert does it at the head */
1841 previousHead = elList.head;
1842 elList.head = newLock;
1845 /* Set new list item data member */
1846 newLock->pUnk = pUnk;
1847 newLock->uRefCount = 1;
1848 newLock->next = previousHead;
1850 return TRUE;
1852 return FALSE;
1855 /****************************************************************************
1856 * Internal - Method that removes an item from the linked list.
1858 static void COM_ExternalLockDelete(
1859 COM_ExternalLock *itemList)
1861 COM_ExternalLock *current = elList.head;
1863 if ( current == itemList ) {
1864 /* this section handles the deletion of the first node */
1865 elList.head = itemList->next;
1866 HeapFree( GetProcessHeap(), 0, itemList);
1867 } else {
1868 do {
1869 if ( current->next == itemList ){ /* We found the item to free */
1870 current->next = itemList->next; /* readjust the list pointers */
1871 HeapFree( GetProcessHeap(), 0, itemList);
1872 break;
1875 /* Skip to the next item */
1876 current = current->next;
1878 } while ( current != EL_END_OF_LIST );
1882 /****************************************************************************
1883 * Internal - Recursivity agent for IUnknownExternalLockList_Find
1885 * NOTES: how long can the list be ?? (recursive!!!)
1887 static COM_ExternalLock* COM_ExternalLockLocate( COM_ExternalLock *element, IUnknown *pUnk)
1889 if ( element == EL_END_OF_LIST )
1890 return EL_NOT_FOUND;
1891 else if ( element->pUnk == pUnk ) /* We found it */
1892 return element;
1893 else /* Not the right guy, keep on looking */
1894 return COM_ExternalLockLocate( element->next, pUnk);
1897 /****************************************************************************
1898 * Public - Method that increments the count for a IUnknown* in the linked
1899 * list. The item is inserted if not already in the list.
1901 static void COM_ExternalLockAddRef(IUnknown *pUnk)
1903 COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
1906 * Add an external lock to the object. If it was already externally
1907 * locked, just increase the reference count. If it was not.
1908 * add the item to the list.
1910 if ( externalLock == EL_NOT_FOUND )
1911 COM_ExternalLockInsert(pUnk);
1912 else
1913 externalLock->uRefCount++;
1916 * Add an internal lock to the object
1918 IUnknown_AddRef(pUnk);
1921 /****************************************************************************
1922 * Public - Method that decrements the count for a IUnknown* in the linked
1923 * list. The item is removed from the list if its count end up at zero or if
1924 * bRelAll is TRUE.
1926 static void COM_ExternalLockRelease(
1927 IUnknown *pUnk,
1928 BOOL bRelAll)
1930 COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
1932 if ( externalLock != EL_NOT_FOUND ) {
1933 do {
1934 externalLock->uRefCount--; /* release external locks */
1935 IUnknown_Release(pUnk); /* release local locks as well */
1937 if ( bRelAll == FALSE ) break; /* perform single release */
1939 } while ( externalLock->uRefCount > 0 );
1941 if ( externalLock->uRefCount == 0 ) /* get rid of the list entry */
1942 COM_ExternalLockDelete(externalLock);
1945 /****************************************************************************
1946 * Public - Method that frees the content of the list.
1948 static void COM_ExternalLockFreeList()
1950 COM_ExternalLock *head;
1952 head = elList.head; /* grab it by the head */
1953 while ( head != EL_END_OF_LIST ) {
1954 COM_ExternalLockDelete(head); /* get rid of the head stuff */
1955 head = elList.head; /* get the new head... */
1959 /****************************************************************************
1960 * Public - Method that dump the content of the list.
1962 void COM_ExternalLockDump()
1964 COM_ExternalLock *current = elList.head;
1966 DPRINTF("\nExternal lock list contains:\n");
1968 while ( current != EL_END_OF_LIST ) {
1969 DPRINTF( "\t%p with %lu references count.\n", current->pUnk, current->uRefCount);
1971 /* Skip to the next item */
1972 current = current->next;
1976 /******************************************************************************
1977 * CoLockObjectExternal [OLE32.@]
1979 HRESULT WINAPI CoLockObjectExternal(
1980 LPUNKNOWN pUnk, /* [in] object to be locked */
1981 BOOL fLock, /* [in] do lock */
1982 BOOL fLastUnlockReleases) /* [in] unlock all */
1985 if (fLock) {
1987 * Increment the external lock coutner, COM_ExternalLockAddRef also
1988 * increment the object's internal lock counter.
1990 COM_ExternalLockAddRef( pUnk);
1991 } else {
1993 * Decrement the external lock coutner, COM_ExternalLockRelease also
1994 * decrement the object's internal lock counter.
1996 COM_ExternalLockRelease( pUnk, fLastUnlockReleases);
1999 return S_OK;
2002 /***********************************************************************
2003 * CoInitializeWOW (OLE32.@)
2005 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y) {
2006 FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
2007 return 0;
2010 /***********************************************************************
2011 * CoGetState [OLE32.@]
2013 * NOTES: might be incomplete
2015 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2017 APARTMENT * apt = COM_CurrentInfo();
2019 FIXME("\n");
2021 if(apt && apt->state) {
2022 IUnknown_AddRef(apt->state);
2023 *ppv = apt->state;
2024 FIXME("-- %p\n", *ppv);
2025 return S_OK;
2027 *ppv = NULL;
2028 return E_FAIL;
2032 /***********************************************************************
2033 * CoSetState [OLE32.@]
2036 HRESULT WINAPI CoSetState(IUnknown * pv)
2038 APARTMENT * apt = COM_CurrentInfo();
2040 if (!apt) apt = COM_CreateApartment(COINIT_UNINITIALIZED);
2042 FIXME("(%p),stub!\n", pv);
2044 if (pv) {
2045 IUnknown_AddRef(pv);
2048 if (apt->state) {
2049 TRACE("-- release %p now\n", apt->state);
2050 IUnknown_Release(apt->state);
2052 apt->state = pv;
2053 return S_OK;
2057 /******************************************************************************
2058 * OleGetAutoConvert [OLE32.@]
2060 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2062 HKEY hkey = 0;
2063 char buf[200];
2064 WCHAR wbuf[200];
2065 DWORD len;
2066 HRESULT res = S_OK;
2068 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2069 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2071 res = REGDB_E_CLASSNOTREG;
2072 goto done;
2074 len = 200;
2075 /* we can just query for the default value of AutoConvertTo key like that,
2076 without opening the AutoConvertTo key and querying for NULL (default) */
2077 if (RegQueryValueA(hkey,"AutoConvertTo",buf,&len))
2079 res = REGDB_E_KEYMISSING;
2080 goto done;
2082 MultiByteToWideChar( CP_ACP, 0, buf, -1, wbuf, sizeof(wbuf)/sizeof(WCHAR) );
2083 CLSIDFromString(wbuf,pClsidNew);
2084 done:
2085 if (hkey) RegCloseKey(hkey);
2086 return res;
2089 /******************************************************************************
2090 * OleSetAutoConvert [OLE32.@]
2092 HRESULT WINAPI OleSetAutoConvert(REFCLSID clsidOld, REFCLSID clsidNew)
2094 HKEY hkey = 0;
2095 char buf[200], szClsidNew[200];
2096 HRESULT res = S_OK;
2098 TRACE("(%s,%s)\n", debugstr_guid(clsidOld), debugstr_guid(clsidNew));
2099 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2100 WINE_StringFromCLSID(clsidNew, szClsidNew);
2101 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2103 res = REGDB_E_CLASSNOTREG;
2104 goto done;
2106 if (RegSetValueA(hkey, "AutoConvertTo", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
2108 res = REGDB_E_WRITEREGDB;
2109 goto done;
2112 done:
2113 if (hkey) RegCloseKey(hkey);
2114 return res;
2117 /******************************************************************************
2118 * OleDoAutoConvert [OLE32.@]
2120 HRESULT WINAPI OleDoAutoConvert(IStorage *pStg, LPCLSID pClsidNew)
2122 FIXME("(%p,%p) : stub\n",pStg,pClsidNew);
2123 return E_NOTIMPL;
2126 /******************************************************************************
2127 * CoTreatAsClass [OLE32.@]
2129 * Sets TreatAs value of a class
2131 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2133 HKEY hkey = 0;
2134 char buf[47];
2135 char szClsidNew[39];
2136 HRESULT res = S_OK;
2137 char auto_treat_as[39];
2138 LONG auto_treat_as_size = sizeof(auto_treat_as);
2139 CLSID id;
2141 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2142 WINE_StringFromCLSID(clsidNew, szClsidNew);
2143 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2145 res = REGDB_E_CLASSNOTREG;
2146 goto done;
2148 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2150 if (!RegQueryValueA(hkey, "AutoTreatAs", auto_treat_as, &auto_treat_as_size) &&
2151 !__CLSIDFromStringA(auto_treat_as, &id))
2153 if (RegSetValueA(hkey, "TreatAs", REG_SZ, auto_treat_as, strlen(auto_treat_as)+1))
2155 res = REGDB_E_WRITEREGDB;
2156 goto done;
2159 else
2161 RegDeleteKeyA(hkey, "TreatAs");
2162 goto done;
2165 else if (RegSetValueA(hkey, "TreatAs", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
2167 res = REGDB_E_WRITEREGDB;
2168 goto done;
2171 done:
2172 if (hkey) RegCloseKey(hkey);
2173 return res;
2176 /******************************************************************************
2177 * CoGetTreatAsClass [OLE32.@]
2179 * Reads the TreatAs value from a class.
2181 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2183 HKEY hkey = 0;
2184 char buf[200], szClsidNew[200];
2185 HRESULT res = S_OK;
2186 LONG len = sizeof(szClsidNew);
2188 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2189 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2190 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2192 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2194 res = REGDB_E_CLASSNOTREG;
2195 goto done;
2197 if (RegQueryValueA(hkey, "TreatAs", szClsidNew, &len))
2199 res = S_FALSE;
2200 goto done;
2202 res = __CLSIDFromStringA(szClsidNew,clsidNew);
2203 if (FAILED(res))
2204 FIXME("Failed CLSIDFromStringA(%s), hres %lx?\n",szClsidNew,res);
2205 done:
2206 if (hkey) RegCloseKey(hkey);
2207 return res;
2211 /***********************************************************************
2212 * IsEqualGUID [OLE32.@]
2214 * Compares two Unique Identifiers.
2216 * RETURNS
2217 * TRUE if equal
2219 #undef IsEqualGUID
2220 BOOL WINAPI IsEqualGUID(
2221 REFGUID rguid1, /* [in] unique id 1 */
2222 REFGUID rguid2 /* [in] unique id 2 */
2225 return !memcmp(rguid1,rguid2,sizeof(GUID));
2228 /***********************************************************************
2229 * CoInitializeSecurity [OLE32.@]
2231 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2232 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2233 void* pReserved1, DWORD dwAuthnLevel,
2234 DWORD dwImpLevel, void* pReserved2,
2235 DWORD dwCapabilities, void* pReserved3)
2237 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
2238 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2239 dwCapabilities, pReserved3);
2240 return S_OK;
2243 /***********************************************************************
2244 * CoSuspendClassObjects [OLE32.@]
2246 HRESULT WINAPI CoSuspendClassObjects(void)
2248 FIXME("\n");
2249 return S_OK;
2252 /***********************************************************************
2253 * CoAddRefServerProcess [OLE32.@]
2255 ULONG WINAPI CoAddRefServerProcess(void)
2257 FIXME("\n");
2258 return 2;
2261 /***********************************************************************
2262 * CoReleaseServerProcess [OLE32.@]
2264 ULONG WINAPI CoReleaseServerProcess(void)
2266 FIXME("\n");
2267 return 1;