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
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
42 #include "wine/winbase16.h"
44 #include "wine/debug.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
48 typedef LPCSTR LPCOLESTR16
;
50 #define CHARS_IN_GUID 39
54 SEGPTR QueryInterface
;
70 static ULONG
call_IMalloc_AddRef(SEGPTR iface
)
72 IMalloc16
*malloc
= MapSL(iface
);
73 IMalloc16Vtbl
*vtbl
= MapSL(malloc
->lpVtbl
);
77 WOWCallback16Ex(vtbl
->AddRef
, WCB16_CDECL
, sizeof(args
), args
, &ret
);
81 static ULONG
call_IMalloc_Release(SEGPTR iface
)
83 IMalloc16
*malloc
= MapSL(iface
);
84 IMalloc16Vtbl
*vtbl
= MapSL(malloc
->lpVtbl
);
88 WOWCallback16Ex(vtbl
->Release
, WCB16_CDECL
, sizeof(args
), args
, &ret
);
92 static SEGPTR
call_IMalloc_Alloc(SEGPTR iface
, DWORD size
)
94 IMalloc16
*malloc
= MapSL(iface
);
95 IMalloc16Vtbl
*vtbl
= MapSL(malloc
->lpVtbl
);
100 WOWCallback16Ex(vtbl
->Alloc
, WCB16_CDECL
, sizeof(args
), args
, &ret
);
104 static HTASK16 hETask
= 0;
105 static WORD Table_ETask
[62];
107 static SEGPTR compobj_malloc
;
109 /* --- IMalloc16 implementation */
114 IMalloc16 IMalloc16_iface
;
118 static inline IMalloc16Impl
*impl_from_IMalloc16(IMalloc16
*iface
)
120 return CONTAINING_RECORD(iface
, IMalloc16Impl
, IMalloc16_iface
);
123 /******************************************************************************
124 * IMalloc16_QueryInterface [COMPOBJ.500]
126 HRESULT CDECL
IMalloc16_fnQueryInterface(IMalloc16
* iface
,REFIID refiid
,LPVOID
*obj
) {
127 IMalloc16Impl
*This
= impl_from_IMalloc16(iface
);
129 TRACE("(%p)->QueryInterface(%s,%p)\n",This
,debugstr_guid(refiid
),obj
);
130 if ( !memcmp(&IID_IUnknown
,refiid
,sizeof(IID_IUnknown
)) ||
131 !memcmp(&IID_IMalloc
,refiid
,sizeof(IID_IMalloc
))
136 return OLE_E_ENUM_NOMORE
;
139 /******************************************************************************
140 * IMalloc16_AddRef [COMPOBJ.501]
142 ULONG CDECL
IMalloc16_fnAddRef(IMalloc16
*iface
)
144 IMalloc16Impl
*malloc
= impl_from_IMalloc16(iface
);
145 ULONG refcount
= InterlockedIncrement(&malloc
->refcount
);
146 TRACE("%p increasing refcount to %u.\n", malloc
, refcount
);
150 /******************************************************************************
151 * IMalloc16_Release [COMPOBJ.502]
153 ULONG CDECL
IMalloc16_fnRelease(SEGPTR iface
)
155 IMalloc16Impl
*malloc
= impl_from_IMalloc16(MapSL(iface
));
156 ULONG refcount
= InterlockedDecrement(&malloc
->refcount
);
157 TRACE("%p decreasing refcount to %u.\n", malloc
, refcount
);
161 HeapFree(GetProcessHeap(), 0, malloc
);
166 /******************************************************************************
167 * IMalloc16_Alloc [COMPOBJ.503]
169 SEGPTR CDECL
IMalloc16_fnAlloc(IMalloc16
* iface
,DWORD cb
) {
170 IMalloc16Impl
*This
= impl_from_IMalloc16(iface
);
172 TRACE("(%p)->Alloc(%d)\n",This
,cb
);
173 return MapLS( HeapAlloc( GetProcessHeap(), 0, cb
) );
176 /******************************************************************************
177 * IMalloc16_Free [COMPOBJ.505]
179 VOID CDECL
IMalloc16_fnFree(IMalloc16
* iface
,SEGPTR pv
)
181 void *ptr
= MapSL(pv
);
182 IMalloc16Impl
*This
= impl_from_IMalloc16(iface
);
183 TRACE("(%p)->Free(%08x)\n",This
,pv
);
185 HeapFree( GetProcessHeap(), 0, ptr
);
188 /******************************************************************************
189 * IMalloc16_Realloc [COMPOBJ.504]
191 SEGPTR CDECL
IMalloc16_fnRealloc(IMalloc16
* iface
,SEGPTR pv
,DWORD cb
)
194 IMalloc16Impl
*This
= impl_from_IMalloc16(iface
);
196 TRACE("(%p)->Realloc(%08x,%d)\n",This
,pv
,cb
);
198 ret
= IMalloc16_fnAlloc(iface
, cb
);
200 ret
= MapLS( HeapReAlloc( GetProcessHeap(), 0, MapSL(pv
), cb
) );
203 IMalloc16_fnFree(iface
, pv
);
209 /******************************************************************************
210 * IMalloc16_GetSize [COMPOBJ.506]
212 DWORD CDECL
IMalloc16_fnGetSize(IMalloc16
* iface
,SEGPTR pv
)
214 IMalloc16Impl
*This
= impl_from_IMalloc16(iface
);
216 TRACE("(%p)->GetSize(%08x)\n",This
,pv
);
217 return HeapSize( GetProcessHeap(), 0, MapSL(pv
) );
220 /******************************************************************************
221 * IMalloc16_DidAlloc [COMPOBJ.507]
223 INT16 CDECL
IMalloc16_fnDidAlloc(IMalloc16
* iface
,LPVOID pv
) {
224 IMalloc16Impl
*This
= impl_from_IMalloc16(iface
);
226 TRACE("(%p)->DidAlloc(%p)\n",This
,pv
);
230 /******************************************************************************
231 * IMalloc16_HeapMinimize [COMPOBJ.508]
233 LPVOID CDECL
IMalloc16_fnHeapMinimize(IMalloc16
* iface
) {
234 IMalloc16Impl
*This
= impl_from_IMalloc16(iface
);
236 TRACE("(%p)->HeapMinimize()\n",This
);
240 /******************************************************************************
241 * IMalloc16_Constructor [VTABLE]
243 static SEGPTR
IMalloc16_Constructor(void)
245 static IMalloc16Vtbl vt16
;
246 static SEGPTR msegvt16
;
248 HMODULE16 hcomp
= GetModuleHandle16("COMPOBJ");
250 This
= HeapAlloc( GetProcessHeap(), 0, sizeof(IMalloc16Impl
) );
253 #define VTENT(x) vt16.x = (SEGPTR)GetProcAddress16(hcomp,"IMalloc16_"#x);assert(vt16.x)
254 VTENT(QueryInterface
);
264 msegvt16
= MapLS( &vt16
);
266 This
->IMalloc16_iface
.lpVtbl
= msegvt16
;
271 /******************************************************************************
272 * CoBuildVersion [COMPOBJ.1]
274 DWORD WINAPI
CoBuildVersion16(void)
276 return CoBuildVersion();
279 /***********************************************************************
280 * CoGetMalloc [COMPOBJ.4]
282 HRESULT WINAPI
CoGetMalloc16(MEMCTX context
, SEGPTR
*malloc
)
284 call_IMalloc_AddRef(*malloc
= compobj_malloc
);
288 /***********************************************************************
289 * CoCreateStandardMalloc [COMPOBJ.71]
291 HRESULT WINAPI
CoCreateStandardMalloc16(MEMCTX context
, SEGPTR
*malloc
)
293 /* FIXME: docu says we shouldn't return the same allocator as in
295 *malloc
= IMalloc16_Constructor();
299 /***********************************************************************
300 * CoMemAlloc [COMPOBJ.151]
302 SEGPTR WINAPI
CoMemAlloc(DWORD size
, MEMCTX context
, DWORD unknown
)
304 TRACE("size %u, context %d, unknown %#x.\n", size
, context
, unknown
);
305 if (context
!= MEMCTX_TASK
)
306 FIXME("Ignoring context %d.\n", context
);
308 FIXME("Ignoring unknown parameter %#x.\n", unknown
);
310 return call_IMalloc_Alloc(compobj_malloc
, size
);
313 /***********************************************************************
314 * CoInitialize [COMPOBJ.2]
316 HRESULT WINAPI
CoInitialize16(SEGPTR malloc
)
319 CoCreateStandardMalloc16(MEMCTX_TASK
, &compobj_malloc
);
321 call_IMalloc_AddRef(compobj_malloc
= malloc
);
325 /***********************************************************************
326 * CoUninitialize [COMPOBJ.3]
327 * Don't know what it does.
328 * 3-Nov-98 -- this was originally misspelled, I changed it to what I
329 * believe is the correct spelling
331 void WINAPI
CoUninitialize16(void)
335 CoFreeAllLibraries();
336 call_IMalloc_Release(compobj_malloc
);
340 /***********************************************************************
341 * CoFreeUnusedLibraries [COMPOBJ.17]
343 void WINAPI
CoFreeUnusedLibraries16(void)
345 CoFreeUnusedLibraries();
348 /***********************************************************************
349 * IsEqualGUID [COMPOBJ.18]
351 * Compares two Unique Identifiers.
356 BOOL16 WINAPI
IsEqualGUID16(
357 GUID
* g1
, /* [in] unique id 1 */
358 GUID
* g2
) /* [in] unique id 2 */
360 return !memcmp( g1
, g2
, sizeof(GUID
) );
363 /******************************************************************************
364 * CLSIDFromString [COMPOBJ.20]
365 * Converts a unique identifier from its string representation into
368 * Class id: DWORD-WORD-WORD-BYTES[2]-BYTES[6]
373 HRESULT WINAPI
CLSIDFromString16(
374 LPCOLESTR16 idstr
, /* [in] string representation of guid */
375 CLSID
*id
) /* [out] GUID converted from string */
382 memset( id
, 0, sizeof (CLSID
) );
386 /* validate the CLSID string */
387 if (strlen(idstr
) != 38)
388 return CO_E_CLASSSTRING
;
390 s
= (const BYTE
*) idstr
;
391 if ((s
[0]!='{') || (s
[9]!='-') || (s
[14]!='-') || (s
[19]!='-') || (s
[24]!='-') || (s
[37]!='}'))
392 return CO_E_CLASSSTRING
;
394 for (i
=1; i
<37; i
++) {
395 if ((i
== 9)||(i
== 14)||(i
== 19)||(i
== 24)) continue;
396 if (!(((s
[i
] >= '0') && (s
[i
] <= '9')) ||
397 ((s
[i
] >= 'a') && (s
[i
] <= 'f')) ||
398 ((s
[i
] >= 'A') && (s
[i
] <= 'F'))))
399 return CO_E_CLASSSTRING
;
402 TRACE("%s -> %p\n", s
, id
);
404 /* quick lookup table */
405 memset(table
, 0, 256);
407 for (i
= 0; i
< 10; i
++) {
410 for (i
= 0; i
< 6; i
++) {
411 table
['A' + i
] = i
+10;
412 table
['a' + i
] = i
+10;
415 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
417 id
->Data1
= (table
[s
[1]] << 28 | table
[s
[2]] << 24 | table
[s
[3]] << 20 | table
[s
[4]] << 16 |
418 table
[s
[5]] << 12 | table
[s
[6]] << 8 | table
[s
[7]] << 4 | table
[s
[8]]);
419 id
->Data2
= table
[s
[10]] << 12 | table
[s
[11]] << 8 | table
[s
[12]] << 4 | table
[s
[13]];
420 id
->Data3
= table
[s
[15]] << 12 | table
[s
[16]] << 8 | table
[s
[17]] << 4 | table
[s
[18]];
422 /* these are just sequential bytes */
423 id
->Data4
[0] = table
[s
[20]] << 4 | table
[s
[21]];
424 id
->Data4
[1] = table
[s
[22]] << 4 | table
[s
[23]];
425 id
->Data4
[2] = table
[s
[25]] << 4 | table
[s
[26]];
426 id
->Data4
[3] = table
[s
[27]] << 4 | table
[s
[28]];
427 id
->Data4
[4] = table
[s
[29]] << 4 | table
[s
[30]];
428 id
->Data4
[5] = table
[s
[31]] << 4 | table
[s
[32]];
429 id
->Data4
[6] = table
[s
[33]] << 4 | table
[s
[34]];
430 id
->Data4
[7] = table
[s
[35]] << 4 | table
[s
[36]];
435 /***********************************************************************
436 * StringFromCLSID [COMPOBJ.151]
438 HRESULT WINAPI
StringFromCLSID16(REFCLSID id
, SEGPTR
*str
)
441 if (!(*str
= CoMemAlloc(40, MEMCTX_TASK
, 0)))
442 return E_OUTOFMEMORY
;
443 StringFromGUID2( id
, buffer
, 40 );
444 WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, MapSL(*str
), 40, NULL
, NULL
);
448 /***********************************************************************
449 * ProgIDFromCLSID [COMPOBJ.151]
451 HRESULT WINAPI
ProgIDFromCLSID16(REFCLSID clsid
, SEGPTR
*str
)
456 ret
= ProgIDFromCLSID( clsid
, &progid
);
459 INT len
= WideCharToMultiByte( CP_ACP
, 0, progid
, -1, NULL
, 0, NULL
, NULL
);
460 if ((*str
= CoMemAlloc(len
, MEMCTX_TASK
, 0)))
461 WideCharToMultiByte( CP_ACP
, 0, progid
, -1, MapSL(*str
), len
, NULL
, NULL
);
462 CoTaskMemFree( progid
);
467 /***********************************************************************
468 * LookupETask (COMPOBJ.94)
470 HRESULT WINAPI
LookupETask16(HTASK16
*hTask
,LPVOID p
) {
471 FIXME("(%p,%p),stub!\n",hTask
,p
);
472 if ((*hTask
= GetCurrentTask()) == hETask
) {
473 memcpy(p
, Table_ETask
, sizeof(Table_ETask
));
478 /***********************************************************************
479 * SetETask (COMPOBJ.95)
481 HRESULT WINAPI
SetETask16(HTASK16 hTask
, LPVOID p
) {
482 FIXME("(%04x,%p),stub!\n",hTask
,p
);
487 /***********************************************************************
488 * CALLOBJECTINWOW (COMPOBJ.201)
490 HRESULT WINAPI
CallObjectInWOW(LPVOID p1
,LPVOID p2
) {
491 FIXME("(%p,%p),stub!\n",p1
,p2
);
495 /******************************************************************************
496 * CoRegisterClassObject [COMPOBJ.5]
498 * Don't know where it registers it ...
500 HRESULT WINAPI
CoRegisterClassObject16(
503 DWORD dwClsContext
, /* [in] CLSCTX flags indicating the context in which to run the executable */
504 DWORD flags
, /* [in] REGCLS flags indicating how connections are made */
507 FIXME("(%s,%p,0x%08x,0x%08x,%p),stub\n",
508 debugstr_guid(rclsid
),pUnk
,dwClsContext
,flags
,lpdwRegister
513 /******************************************************************************
514 * CoRevokeClassObject [COMPOBJ.6]
517 HRESULT WINAPI
CoRevokeClassObject16(DWORD dwRegister
) /* [in] token on class obj */
519 FIXME("(0x%08x),stub!\n", dwRegister
);
523 /******************************************************************************
524 * IsValidInterface [COMPOBJ.23]
526 * Determines whether a pointer is a valid interface.
529 * punk [I] Interface to be tested.
532 * TRUE, if the passed pointer is a valid interface, or FALSE otherwise.
534 BOOL WINAPI
IsValidInterface16(SEGPTR punk
)
538 if (IsBadReadPtr16(punk
,4))
541 if (IsBadReadPtr16((SEGPTR
)ptr
[0],4)) /* check vtable ptr */
543 ptr
= MapSL((SEGPTR
)ptr
[0]); /* ptr to first method */
544 if (IsBadReadPtr16((SEGPTR
)ptr
[0],2))
549 /******************************************************************************
550 * CoFileTimeToDosDateTime [COMPOBJ.30]
552 BOOL16 WINAPI
CoFileTimeToDosDateTime16(const FILETIME
*ft
, LPWORD lpDosDate
, LPWORD lpDosTime
)
554 return FileTimeToDosDateTime(ft
, lpDosDate
, lpDosTime
);
557 /******************************************************************************
558 * CoDosDateTimeToFileTime [COMPOBJ.31]
560 BOOL16 WINAPI
CoDosDateTimeToFileTime16(WORD wDosDate
, WORD wDosTime
, FILETIME
*ft
)
562 return DosDateTimeToFileTime(wDosDate
, wDosTime
, ft
);
565 /******************************************************************************
566 * CoGetCurrentProcess [COMPOBJ.34]
568 DWORD WINAPI
CoGetCurrentProcess16(void)
570 return CoGetCurrentProcess();
573 /******************************************************************************
574 * CoRegisterMessageFilter [COMPOBJ.27]
576 HRESULT WINAPI
CoRegisterMessageFilter16(
577 LPMESSAGEFILTER lpMessageFilter
,
578 LPMESSAGEFILTER
*lplpMessageFilter
580 FIXME("(%p,%p),stub!\n",lpMessageFilter
,lplpMessageFilter
);
584 /******************************************************************************
585 * CoLockObjectExternal [COMPOBJ.63]
587 HRESULT WINAPI
CoLockObjectExternal16(
588 LPUNKNOWN pUnk
, /* [in] object to be locked */
589 BOOL16 fLock
, /* [in] do lock */
590 BOOL16 fLastUnlockReleases
/* [in] ? */
592 FIXME("(%p,%d,%d),stub!\n",pUnk
,fLock
,fLastUnlockReleases
);
596 /***********************************************************************
597 * CoGetState [COMPOBJ.115]
599 HRESULT WINAPI
CoGetState16(LPDWORD state
)
601 FIXME("(%p),stub!\n", state
);
607 /***********************************************************************
608 * DllEntryPoint [COMPOBJ.116]
610 * Initialization code for the COMPOBJ DLL
614 BOOL WINAPI
COMPOBJ_DllEntryPoint(DWORD Reason
, HINSTANCE16 hInst
, WORD ds
, WORD HeapSize
, DWORD res1
, WORD res2
)
616 TRACE("(%08x, %04x, %04x, %04x, %08x, %04x)\n", Reason
, hInst
, ds
, HeapSize
, res1
, res2
);
620 /******************************************************************************
621 * CLSIDFromProgID [COMPOBJ.61]
623 * Converts a program ID into the respective GUID.
626 * progid [I] program id as found in registry
627 * riid [O] associated CLSID
631 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
633 HRESULT WINAPI
CLSIDFromProgID16(LPCOLESTR16 progid
, LPCLSID riid
)
639 buf
= HeapAlloc(GetProcessHeap(),0,strlen(progid
)+8);
640 sprintf(buf
,"%s\\CLSID",progid
);
641 if (RegOpenKeyA(HKEY_CLASSES_ROOT
,buf
,&xhkey
)) {
642 HeapFree(GetProcessHeap(),0,buf
);
643 return CO_E_CLASSSTRING
;
645 HeapFree(GetProcessHeap(),0,buf
);
646 buf2len
= sizeof(buf2
);
647 if (RegQueryValueA(xhkey
,NULL
,buf2
,&buf2len
)) {
649 return CO_E_CLASSSTRING
;
652 return CLSIDFromString16(buf2
,riid
);
655 /******************************************************************************
656 * StringFromGUID2 [COMPOBJ.76]
658 INT16 WINAPI
StringFromGUID216(REFGUID id
, char *str
, INT16 cmax
)
660 static const char format
[] = "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}";
661 if (!id
|| cmax
< CHARS_IN_GUID
) return 0;
662 sprintf( str
, format
, id
->Data1
, id
->Data2
, id
->Data3
,
663 id
->Data4
[0], id
->Data4
[1], id
->Data4
[2], id
->Data4
[3],
664 id
->Data4
[4], id
->Data4
[5], id
->Data4
[6], id
->Data4
[7] );
665 return CHARS_IN_GUID
;
669 /***********************************************************************
670 * CoFileTimeNow [COMPOBJ.82]
672 HRESULT WINAPI
CoFileTimeNow16( FILETIME
*lpFileTime
)
674 return CoFileTimeNow( lpFileTime
);
677 /***********************************************************************
678 * CoGetClassObject [COMPOBJ.7]
681 HRESULT WINAPI
CoGetClassObject16(
682 SEGPTR rclsid
, DWORD dwClsContext
, COSERVERINFO
*pServerInfo
,
683 SEGPTR riid
, SEGPTR ppv
)
685 LPVOID
*ppvl
= MapSL(ppv
);
687 TRACE("CLSID: %s, IID: %s\n", debugstr_guid(MapSL(rclsid
)), debugstr_guid(MapSL(riid
)));
692 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
693 debugstr_w(pServerInfo
->pwszName
), pServerInfo
->pAuthInfo
);
696 if (CLSCTX_INPROC_SERVER
& dwClsContext
)
698 char idstr
[CHARS_IN_GUID
];
699 char buf_key
[CHARS_IN_GUID
+19], dllpath
[MAX_PATH
+1];
700 LONG dllpath_len
= sizeof(dllpath
);
703 FARPROC16 DllGetClassObject
;
708 StringFromGUID216(MapSL(rclsid
), idstr
, CHARS_IN_GUID
);
709 sprintf(buf_key
, "CLSID\\%s\\InprocServer", idstr
);
710 if (RegQueryValueA(HKEY_CLASSES_ROOT
, buf_key
, dllpath
, &dllpath_len
))
712 ERR("class %s not registered\n", debugstr_guid(MapSL(rclsid
)));
713 return REGDB_E_CLASSNOTREG
;
716 dll
= LoadLibrary16(dllpath
);
719 ERR("couldn't load in-process dll %s\n", debugstr_a(dllpath
));
720 return E_ACCESSDENIED
; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
723 DllGetClassObject
= GetProcAddress16(dll
, "DllGetClassObject");
724 if (!DllGetClassObject
)
726 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_a(dllpath
));
728 return CO_E_DLLNOTFOUND
;
731 TRACE("calling DllGetClassObject %p\n", DllGetClassObject
);
732 args
[5] = SELECTOROF(rclsid
);
733 args
[4] = OFFSETOF(rclsid
);
734 args
[3] = SELECTOROF(riid
);
735 args
[2] = OFFSETOF(riid
);
736 args
[1] = SELECTOROF(ppv
);
737 args
[0] = OFFSETOF(ppv
);
738 WOWCallback16Ex((DWORD
) DllGetClassObject
, WCB16_PASCAL
, sizeof(args
), args
, &dwRet
);
741 ERR("DllGetClassObject returned error 0x%08x\n", dwRet
);
749 FIXME("semi-stub\n");
753 /******************************************************************************
754 * CoCreateGuid [COMPOBJ.73]
756 HRESULT WINAPI
CoCreateGuid16(GUID
*pguid
)
758 return CoCreateGuid( pguid
);
761 /***********************************************************************
762 * CoCreateInstance [COMPOBJ.13]
764 HRESULT WINAPI
CoCreateInstance16(
771 FIXME("(%s, %p, %x, %s, %p), stub!\n",
772 debugstr_guid(rclsid
), pUnkOuter
, dwClsContext
, debugstr_guid(iid
),
778 /***********************************************************************
779 * CoDisconnectObject [COMPOBJ.15]
781 HRESULT WINAPI
CoDisconnectObject16( LPUNKNOWN lpUnk
, DWORD reserved
)
783 FIXME("(%p, 0x%08x): stub!\n", lpUnk
, reserved
);