oleaut32: Manually construct a stub buffer for dispinterfaces.
[wine.git] / dlls / oleaut32 / oleaut.c
blob92a9f12661bc3dadab6c707befe00c93f2dc9814
1 /*
2 * OLEAUT32
4 * Copyright 1999, 2000 Marcus Meissner
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <assert.h>
22 #include <stdarg.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <limits.h>
27 #define COBJMACROS
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winuser.h"
33 #include "winerror.h"
35 #include "ole2.h"
36 #include "olectl.h"
37 #include "oleauto.h"
38 #include "rpcproxy.h"
39 #include "initguid.h"
40 #include "typelib.h"
41 #include "oleaut32_oaidl.h"
43 #include "wine/debug.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(ole);
46 WINE_DECLARE_DEBUG_CHANNEL(heap);
48 /******************************************************************************
49 * BSTR {OLEAUT32}
51 * NOTES
52 * BSTR is a simple typedef for a wide-character string used as the principle
53 * string type in ole automation. When encapsulated in a Variant type they are
54 * automatically copied and destroyed as the variant is processed.
56 * The low level BSTR API allows manipulation of these strings and is used by
57 * higher level API calls to manage the strings transparently to the caller.
59 * Internally the BSTR type is allocated with space for a DWORD byte count before
60 * the string data begins. This is undocumented and non-system code should not
61 * access the count directly. Use SysStringLen() or SysStringByteLen()
62 * instead. Note that the byte count does not include the terminating NUL.
64 * To create a new BSTR, use SysAllocString(), SysAllocStringLen() or
65 * SysAllocStringByteLen(). To change the size of an existing BSTR, use SysReAllocString()
66 * or SysReAllocStringLen(). Finally to destroy a string use SysFreeString().
68 * BSTR's are cached by Ole Automation by default. To override this behaviour
69 * either set the environment variable 'OANOCACHE', or call SetOaNoCache().
71 * SEE ALSO
72 * 'Inside OLE, second edition' by Kraig Brockshmidt.
75 static BOOL bstr_cache_enabled;
77 static CRITICAL_SECTION cs_bstr_cache;
78 static CRITICAL_SECTION_DEBUG cs_bstr_cache_dbg =
80 0, 0, &cs_bstr_cache,
81 { &cs_bstr_cache_dbg.ProcessLocksList, &cs_bstr_cache_dbg.ProcessLocksList },
82 0, 0, { (DWORD_PTR)(__FILE__ ": bstr_cache") }
84 static CRITICAL_SECTION cs_bstr_cache = { &cs_bstr_cache_dbg, -1, 0, 0, 0, 0 };
86 typedef struct {
87 #ifdef _WIN64
88 DWORD pad;
89 #endif
90 DWORD size;
91 union {
92 char ptr[1];
93 WCHAR str[1];
94 DWORD dwptr[1];
95 } u;
96 } bstr_t;
98 #define BUCKET_SIZE 16
99 #define BUCKET_BUFFER_SIZE 6
101 typedef struct {
102 unsigned short head;
103 unsigned short cnt;
104 bstr_t *buf[BUCKET_BUFFER_SIZE];
105 } bstr_cache_entry_t;
107 #define ARENA_INUSE_FILLER 0x55
108 #define ARENA_TAIL_FILLER 0xab
109 #define ARENA_FREE_FILLER 0xfeeefeee
111 static bstr_cache_entry_t bstr_cache[0x10000/BUCKET_SIZE];
113 static inline size_t bstr_alloc_size(size_t size)
115 return (FIELD_OFFSET(bstr_t, u.ptr[size]) + sizeof(WCHAR) + BUCKET_SIZE-1) & ~(BUCKET_SIZE-1);
118 static inline bstr_t *bstr_from_str(BSTR str)
120 return CONTAINING_RECORD(str, bstr_t, u.str);
123 static inline bstr_cache_entry_t *get_cache_entry_from_idx(unsigned cache_idx)
125 return bstr_cache_enabled && cache_idx < ARRAY_SIZE(bstr_cache) ? bstr_cache + cache_idx : NULL;
128 static inline bstr_cache_entry_t *get_cache_entry(size_t size)
130 unsigned cache_idx = FIELD_OFFSET(bstr_t, u.ptr[size+sizeof(WCHAR)-1])/BUCKET_SIZE;
131 return get_cache_entry_from_idx(cache_idx);
134 static inline bstr_cache_entry_t *get_cache_entry_from_alloc_size(SIZE_T alloc_size)
136 unsigned cache_idx;
137 if (alloc_size < BUCKET_SIZE) return NULL;
138 cache_idx = (alloc_size - BUCKET_SIZE) / BUCKET_SIZE;
139 return get_cache_entry_from_idx(cache_idx);
142 static bstr_t *alloc_bstr(size_t size)
144 bstr_cache_entry_t *cache_entry = get_cache_entry(size);
145 bstr_t *ret;
147 if(cache_entry) {
148 EnterCriticalSection(&cs_bstr_cache);
150 if(!cache_entry->cnt) {
151 cache_entry = get_cache_entry(size+BUCKET_SIZE);
152 if(cache_entry && !cache_entry->cnt)
153 cache_entry = NULL;
156 if(cache_entry) {
157 ret = cache_entry->buf[cache_entry->head++];
158 cache_entry->head %= BUCKET_BUFFER_SIZE;
159 cache_entry->cnt--;
162 LeaveCriticalSection(&cs_bstr_cache);
164 if(cache_entry) {
165 if(WARN_ON(heap)) {
166 size_t fill_size = (FIELD_OFFSET(bstr_t, u.ptr[size])+2*sizeof(WCHAR)-1) & ~(sizeof(WCHAR)-1);
167 memset(ret, ARENA_INUSE_FILLER, fill_size);
168 memset((char *)ret+fill_size, ARENA_TAIL_FILLER, bstr_alloc_size(size)-fill_size);
170 ret->size = size;
171 return ret;
175 ret = CoTaskMemAlloc(bstr_alloc_size(size));
176 if(ret)
177 ret->size = size;
178 return ret;
181 /******************************************************************************
182 * SysStringLen [OLEAUT32.7]
184 * Get the allocated length of a BSTR in wide characters.
186 * PARAMS
187 * str [I] BSTR to find the length of
189 * RETURNS
190 * The allocated length of str, or 0 if str is NULL.
192 * NOTES
193 * See BSTR.
194 * The returned length may be different from the length of the string as
195 * calculated by lstrlenW(), since it returns the length that was used to
196 * allocate the string by SysAllocStringLen().
198 UINT WINAPI SysStringLen(BSTR str)
200 return str ? bstr_from_str(str)->size/sizeof(WCHAR) : 0;
203 /******************************************************************************
204 * SysStringByteLen [OLEAUT32.149]
206 * Get the allocated length of a BSTR in bytes.
208 * PARAMS
209 * str [I] BSTR to find the length of
211 * RETURNS
212 * The allocated length of str, or 0 if str is NULL.
214 * NOTES
215 * See SysStringLen(), BSTR().
217 UINT WINAPI SysStringByteLen(BSTR str)
219 return str ? bstr_from_str(str)->size : 0;
222 /******************************************************************************
223 * SysAllocString [OLEAUT32.2]
225 * Create a BSTR from an OLESTR.
227 * PARAMS
228 * str [I] Source to create BSTR from
230 * RETURNS
231 * Success: A BSTR allocated with SysAllocStringLen().
232 * Failure: NULL, if oleStr is NULL.
234 * NOTES
235 * See BSTR.
236 * MSDN (October 2001) incorrectly states that NULL is returned if oleStr has
237 * a length of 0. Native Win32 and this implementation both return a valid
238 * empty BSTR in this case.
240 BSTR WINAPI SysAllocString(LPCOLESTR str)
242 if (!str) return 0;
244 /* Delegate this to the SysAllocStringLen32 method. */
245 return SysAllocStringLen(str, lstrlenW(str));
248 static inline IMalloc *get_malloc(void)
250 static IMalloc *malloc;
252 if (!malloc)
253 CoGetMalloc(1, &malloc);
255 return malloc;
258 /******************************************************************************
259 * SysFreeString [OLEAUT32.6]
261 * Free a BSTR.
263 * PARAMS
264 * str [I] BSTR to free.
266 * RETURNS
267 * Nothing.
269 * NOTES
270 * See BSTR.
271 * str may be NULL, in which case this function does nothing.
273 void WINAPI DECLSPEC_HOTPATCH SysFreeString(BSTR str)
275 bstr_cache_entry_t *cache_entry;
276 bstr_t *bstr;
277 IMalloc *malloc = get_malloc();
278 SIZE_T alloc_size;
280 if(!str)
281 return;
283 bstr = bstr_from_str(str);
285 alloc_size = IMalloc_GetSize(malloc, bstr);
286 if (alloc_size == ~0UL)
287 return;
289 cache_entry = get_cache_entry_from_alloc_size(alloc_size);
290 if(cache_entry) {
291 unsigned i;
293 EnterCriticalSection(&cs_bstr_cache);
295 /* According to tests, freeing a string that's already in cache doesn't corrupt anything.
296 * For that to work we need to search the cache. */
297 for(i=0; i < cache_entry->cnt; i++) {
298 if(cache_entry->buf[(cache_entry->head+i) % BUCKET_BUFFER_SIZE] == bstr) {
299 WARN_(heap)("String already is in cache!\n");
300 LeaveCriticalSection(&cs_bstr_cache);
301 return;
305 if(cache_entry->cnt < ARRAY_SIZE(cache_entry->buf)) {
306 cache_entry->buf[(cache_entry->head+cache_entry->cnt) % BUCKET_BUFFER_SIZE] = bstr;
307 cache_entry->cnt++;
309 if(WARN_ON(heap)) {
310 unsigned n = (alloc_size-FIELD_OFFSET(bstr_t, u.ptr))/sizeof(DWORD);
311 for(i=0; i<n; i++)
312 bstr->u.dwptr[i] = ARENA_FREE_FILLER;
315 LeaveCriticalSection(&cs_bstr_cache);
316 return;
319 LeaveCriticalSection(&cs_bstr_cache);
322 CoTaskMemFree(bstr);
325 /******************************************************************************
326 * SysAllocStringLen [OLEAUT32.4]
328 * Create a BSTR from an OLESTR of a given wide character length.
330 * PARAMS
331 * str [I] Source to create BSTR from
332 * len [I] Length of oleStr in wide characters
334 * RETURNS
335 * Success: A newly allocated BSTR from SysAllocStringByteLen()
336 * Failure: NULL, if len is >= 0x80000000, or memory allocation fails.
338 * NOTES
339 * See BSTR(), SysAllocStringByteLen().
341 BSTR WINAPI SysAllocStringLen(const OLECHAR *str, unsigned int len)
343 bstr_t *bstr;
344 DWORD size;
346 /* Detect integer overflow. */
347 if (len >= ((UINT_MAX-sizeof(WCHAR)-sizeof(DWORD))/sizeof(WCHAR)))
348 return NULL;
350 TRACE("%s\n", debugstr_wn(str, len));
352 size = len*sizeof(WCHAR);
353 bstr = alloc_bstr(size);
354 if(!bstr)
355 return NULL;
357 if(str) {
358 memcpy(bstr->u.str, str, size);
359 bstr->u.str[len] = 0;
360 }else {
361 memset(bstr->u.str, 0, size+sizeof(WCHAR));
364 return bstr->u.str;
367 /******************************************************************************
368 * SysReAllocStringLen [OLEAUT32.5]
370 * Change the length of a previously created BSTR.
372 * PARAMS
373 * old [O] BSTR to change the length of
374 * str [I] New source for pbstr
375 * len [I] Length of oleStr in wide characters
377 * RETURNS
378 * Success: 1. The size of pbstr is updated.
379 * Failure: 0, if len >= 0x80000000 or memory allocation fails.
381 * NOTES
382 * See BSTR(), SysAllocStringByteLen().
383 * *old may be changed by this function.
385 int WINAPI SysReAllocStringLen(BSTR* old, const OLECHAR* str, unsigned int len)
387 /* Detect integer overflow. */
388 if (len >= ((UINT_MAX-sizeof(WCHAR)-sizeof(DWORD))/sizeof(WCHAR)))
389 return FALSE;
391 if (*old!=NULL) {
392 DWORD newbytelen = len*sizeof(WCHAR);
393 bstr_t *old_bstr = bstr_from_str(*old);
394 bstr_t *bstr = CoTaskMemRealloc(old_bstr, bstr_alloc_size(newbytelen));
396 if (!bstr) return FALSE;
398 *old = bstr->u.str;
399 bstr->size = newbytelen;
400 /* The old string data is still there when str is NULL */
401 if (str && old_bstr->u.str != str) memmove(bstr->u.str, str, newbytelen);
402 bstr->u.str[len] = 0;
403 } else {
404 *old = SysAllocStringLen(str, len);
407 return TRUE;
410 /******************************************************************************
411 * SysAllocStringByteLen [OLEAUT32.150]
413 * Create a BSTR from an OLESTR of a given byte length.
415 * PARAMS
416 * str [I] Source to create BSTR from
417 * len [I] Length of oleStr in bytes
419 * RETURNS
420 * Success: A newly allocated BSTR
421 * Failure: NULL, if len is >= 0x80000000, or memory allocation fails.
423 * NOTES
424 * -If len is 0 or oleStr is NULL the resulting string is empty ("").
425 * -This function always NUL terminates the resulting BSTR.
426 * -oleStr may be either an LPCSTR or LPCOLESTR, since it is copied
427 * without checking for a terminating NUL.
428 * See BSTR.
430 BSTR WINAPI DECLSPEC_HOTPATCH SysAllocStringByteLen(LPCSTR str, UINT len)
432 bstr_t *bstr;
434 /* Detect integer overflow. */
435 if (len >= (UINT_MAX-sizeof(WCHAR)-sizeof(DWORD)))
436 return NULL;
438 bstr = alloc_bstr(len);
439 if(!bstr)
440 return NULL;
442 if(str) {
443 memcpy(bstr->u.ptr, str, len);
444 bstr->u.ptr[len] = 0;
445 }else {
446 memset(bstr->u.ptr, 0, len+1);
448 bstr->u.str[(len+sizeof(WCHAR)-1)/sizeof(WCHAR)] = 0;
450 return bstr->u.str;
453 /******************************************************************************
454 * SysReAllocString [OLEAUT32.3]
456 * Change the length of a previously created BSTR.
458 * PARAMS
459 * old [I/O] BSTR to change the length of
460 * str [I] New source for pbstr
462 * RETURNS
463 * Success: 1
464 * Failure: 0.
466 * NOTES
467 * See BSTR(), SysAllocStringStringLen().
469 INT WINAPI SysReAllocString(LPBSTR old,LPCOLESTR str)
472 * Sanity check
474 if (old==NULL)
475 return 0;
478 * Make sure we free the old string.
480 SysFreeString(*old);
483 * Allocate the new string
485 *old = SysAllocString(str);
487 return 1;
490 /******************************************************************************
491 * SetOaNoCache (OLEAUT32.327)
493 * Instruct Ole Automation not to cache BSTR allocations.
495 * PARAMS
496 * None.
498 * RETURNS
499 * Nothing.
501 * NOTES
502 * SetOaNoCache does not release cached strings, so it leaks by design.
504 void WINAPI SetOaNoCache(void)
506 TRACE("\n");
507 bstr_cache_enabled = FALSE;
510 /***********************************************************************
511 * RegisterActiveObject (OLEAUT32.33)
513 * Registers an object in the global item table.
515 * PARAMS
516 * punk [I] Object to register.
517 * rcid [I] CLSID of the object.
518 * dwFlags [I] Flags.
519 * pdwRegister [O] Address to store cookie of object registration in.
521 * RETURNS
522 * Success: S_OK.
523 * Failure: HRESULT code.
525 HRESULT WINAPI DECLSPEC_HOTPATCH RegisterActiveObject(
526 LPUNKNOWN punk,REFCLSID rcid,DWORD dwFlags,LPDWORD pdwRegister
528 WCHAR guidbuf[80];
529 HRESULT ret;
530 LPRUNNINGOBJECTTABLE runobtable;
531 LPMONIKER moniker;
532 DWORD rot_flags = ROTFLAGS_REGISTRATIONKEEPSALIVE; /* default registration is strong */
534 StringFromGUID2(rcid,guidbuf,39);
535 ret = CreateItemMoniker(L"!", guidbuf, &moniker);
536 if (FAILED(ret))
537 return ret;
538 ret = GetRunningObjectTable(0,&runobtable);
539 if (FAILED(ret)) {
540 IMoniker_Release(moniker);
541 return ret;
543 if(dwFlags == ACTIVEOBJECT_WEAK)
544 rot_flags = 0;
545 ret = IRunningObjectTable_Register(runobtable,rot_flags,punk,moniker,pdwRegister);
546 IRunningObjectTable_Release(runobtable);
547 IMoniker_Release(moniker);
548 return ret;
551 /***********************************************************************
552 * RevokeActiveObject (OLEAUT32.34)
554 * Revokes an object from the global item table.
556 * PARAMS
557 * xregister [I] Registration cookie.
558 * reserved [I] Reserved. Set to NULL.
560 * RETURNS
561 * Success: S_OK.
562 * Failure: HRESULT code.
564 HRESULT WINAPI DECLSPEC_HOTPATCH RevokeActiveObject(DWORD xregister,LPVOID reserved)
566 LPRUNNINGOBJECTTABLE runobtable;
567 HRESULT ret;
569 ret = GetRunningObjectTable(0,&runobtable);
570 if (FAILED(ret)) return ret;
571 ret = IRunningObjectTable_Revoke(runobtable,xregister);
572 if (SUCCEEDED(ret)) ret = S_OK;
573 IRunningObjectTable_Release(runobtable);
574 return ret;
577 /***********************************************************************
578 * GetActiveObject (OLEAUT32.35)
580 * Gets an object from the global item table.
582 * PARAMS
583 * rcid [I] CLSID of the object.
584 * preserved [I] Reserved. Set to NULL.
585 * ppunk [O] Address to store object into.
587 * RETURNS
588 * Success: S_OK.
589 * Failure: HRESULT code.
591 HRESULT WINAPI DECLSPEC_HOTPATCH GetActiveObject(REFCLSID rcid,LPVOID preserved,LPUNKNOWN *ppunk)
593 WCHAR guidbuf[80];
594 HRESULT ret;
595 LPRUNNINGOBJECTTABLE runobtable;
596 LPMONIKER moniker;
598 StringFromGUID2(rcid,guidbuf,39);
599 ret = CreateItemMoniker(L"!", guidbuf, &moniker);
600 if (FAILED(ret))
601 return ret;
602 ret = GetRunningObjectTable(0,&runobtable);
603 if (FAILED(ret)) {
604 IMoniker_Release(moniker);
605 return ret;
607 ret = IRunningObjectTable_GetObject(runobtable,moniker,ppunk);
608 IRunningObjectTable_Release(runobtable);
609 IMoniker_Release(moniker);
610 return ret;
614 /***********************************************************************
615 * OaBuildVersion [OLEAUT32.170]
617 * Get the Ole Automation build version.
619 * PARAMS
620 * None
622 * RETURNS
623 * The build version.
625 * NOTES
626 * Known oleaut32.dll versions:
627 *| OLE Ver. Comments Date Build Ver.
628 *| -------- ------------------------- ---- ---------
629 *| OLE 2.1 NT 1993-95 10 3023
630 *| OLE 2.1 10 3027
631 *| Win32s Ver 1.1e 20 4049
632 *| OLE 2.20 W95/NT 1993-96 20 4112
633 *| OLE 2.20 W95/NT 1993-96 20 4118
634 *| OLE 2.20 W95/NT 1993-96 20 4122
635 *| OLE 2.30 W95/NT 1993-98 30 4265
636 *| OLE 2.40 NT?? 1993-98 40 4267
637 *| OLE 2.40 W98 SE orig. file 1993-98 40 4275
638 *| OLE 2.40 W2K orig. file 1993-XX 40 4514
640 * Currently the versions returned are 2.20 for Win3.1, 2.30 for Win95 & NT 3.51,
641 * and 2.40 for all later versions. The build number is maximum, i.e. 0xffff.
643 ULONG WINAPI OaBuildVersion(void)
645 switch(GetVersion() & 0x8000ffff) /* mask off build number */
647 case 0x80000a03: /* WIN31 */
648 return MAKELONG(0xffff, 20);
649 case 0x00003303: /* NT351 */
650 return MAKELONG(0xffff, 30);
651 case 0x80000004: /* WIN95; I'd like to use the "standard" w95 minor
652 version here (30), but as we still use w95
653 as default winver (which is good IMHO), I better
654 play safe and use the latest value for w95 for now.
655 Change this as soon as default winver gets changed
656 to something more recent */
657 case 0x80000a04: /* WIN98 */
658 case 0x00000004: /* NT40 */
659 case 0x00000005: /* W2K */
660 return MAKELONG(0xffff, 40);
661 case 0x00000105: /* WinXP */
662 case 0x00000006: /* Vista */
663 case 0x00000106: /* Win7 */
664 return MAKELONG(0xffff, 50);
665 default:
666 FIXME("Version value not known yet. Please investigate it !\n");
667 return MAKELONG(0xffff, 40); /* for now return the same value as for w2k */
671 /******************************************************************************
672 * OleTranslateColor [OLEAUT32.421]
674 * Convert an OLE_COLOR to a COLORREF.
676 * PARAMS
677 * clr [I] Color to convert
678 * hpal [I] Handle to a palette for the conversion
679 * pColorRef [O] Destination for converted color, or NULL to test if the conversion is ok
681 * RETURNS
682 * Success: S_OK. The conversion is ok, and pColorRef contains the converted color if non-NULL.
683 * Failure: E_INVALIDARG, if any argument is invalid.
685 * FIXME
686 * Document the conversion rules.
688 HRESULT WINAPI OleTranslateColor(
689 OLE_COLOR clr,
690 HPALETTE hpal,
691 COLORREF* pColorRef)
693 COLORREF colorref;
694 BYTE b = HIBYTE(HIWORD(clr));
696 TRACE("%#lx, %p, %p.\n", clr, hpal, pColorRef);
699 * In case pColorRef is NULL, provide our own to simplify the code.
701 if (pColorRef == NULL)
702 pColorRef = &colorref;
704 switch (b)
706 case 0x00:
708 if (hpal != 0)
709 *pColorRef = PALETTERGB(GetRValue(clr),
710 GetGValue(clr),
711 GetBValue(clr));
712 else
713 *pColorRef = clr;
715 break;
718 case 0x01:
720 if (hpal != 0)
722 PALETTEENTRY pe;
724 * Validate the palette index.
726 if (GetPaletteEntries(hpal, LOWORD(clr), 1, &pe) == 0)
727 return E_INVALIDARG;
730 *pColorRef = clr;
732 break;
735 case 0x02:
736 *pColorRef = clr;
737 break;
739 case 0x80:
741 int index = LOBYTE(LOWORD(clr));
744 * Validate GetSysColor index.
746 if ((index < COLOR_SCROLLBAR) || (index > COLOR_MENUBAR))
747 return E_INVALIDARG;
749 *pColorRef = GetSysColor(index);
751 break;
754 default:
755 return E_INVALIDARG;
758 return S_OK;
761 extern HRESULT WINAPI OLEAUTPS_DllGetClassObject(REFCLSID, REFIID, LPVOID *) DECLSPEC_HIDDEN;
762 extern BOOL WINAPI OLEAUTPS_DllMain(HINSTANCE, DWORD, LPVOID) DECLSPEC_HIDDEN;
763 extern HRESULT WINAPI OLEAUTPS_DllRegisterServer(void) DECLSPEC_HIDDEN;
764 extern HRESULT WINAPI OLEAUTPS_DllUnregisterServer(void) DECLSPEC_HIDDEN;
766 extern HRESULT WINAPI CreateProxyFromTypeInfo(ITypeInfo *typeinfo,
767 IUnknown *outer, REFIID iid, IRpcProxyBuffer **proxy, void **obj);
768 extern HRESULT WINAPI CreateStubFromTypeInfo(ITypeInfo *typeinfo, REFIID iid,
769 IUnknown *server, IRpcStubBuffer **stub);
771 struct ifacepsredirect_data
773 ULONG size;
774 DWORD mask;
775 GUID iid;
776 ULONG nummethods;
777 GUID tlbid;
778 GUID base;
779 ULONG name_len;
780 ULONG name_offset;
783 struct tlibredirect_data
785 ULONG size;
786 DWORD res;
787 ULONG name_len;
788 ULONG name_offset;
789 LANGID langid;
790 WORD flags;
791 ULONG help_len;
792 ULONG help_offset;
793 WORD major_version;
794 WORD minor_version;
797 static BOOL actctx_get_typelib_module(REFIID iid, WCHAR *module, DWORD len)
799 struct ifacepsredirect_data *iface;
800 struct tlibredirect_data *tlib;
801 ACTCTX_SECTION_KEYED_DATA data;
802 WCHAR *ptrW;
804 data.cbSize = sizeof(data);
805 if (!FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION,
806 iid, &data))
807 return FALSE;
809 iface = (struct ifacepsredirect_data *)data.lpData;
810 if (!FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION,
811 &iface->tlbid, &data))
812 return FALSE;
814 tlib = (struct tlibredirect_data *)data.lpData;
815 ptrW = (WCHAR *)((BYTE *)data.lpSectionBase + tlib->name_offset);
817 if (tlib->name_len/sizeof(WCHAR) >= len)
819 ERR("need larger module buffer, %lu.\n", tlib->name_len);
820 return FALSE;
823 memcpy(module, ptrW, tlib->name_len);
824 module[tlib->name_len/sizeof(WCHAR)] = 0;
825 return TRUE;
828 static HRESULT reg_get_typelib_module(REFIID iid, WCHAR *module, DWORD len)
830 REGSAM opposite = (sizeof(void*) == 8) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
831 char tlguid[200], typelibkey[316], interfacekey[300], ver[100], tlfn[260];
832 DWORD tlguidlen, verlen, type;
833 LONG tlfnlen, err;
834 BOOL is_wow64;
835 HKEY ikey;
837 sprintf( interfacekey, "Interface\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\Typelib",
838 iid->Data1, iid->Data2, iid->Data3,
839 iid->Data4[0], iid->Data4[1], iid->Data4[2], iid->Data4[3],
840 iid->Data4[4], iid->Data4[5], iid->Data4[6], iid->Data4[7]
843 err = RegOpenKeyExA(HKEY_CLASSES_ROOT,interfacekey,0,KEY_READ,&ikey);
844 if (err && (opposite == KEY_WOW64_32KEY || (IsWow64Process(GetCurrentProcess(), &is_wow64)
845 && is_wow64)))
846 err = RegOpenKeyExA(HKEY_CLASSES_ROOT,interfacekey,0,KEY_READ|opposite,&ikey);
848 if (err)
850 ERR("No %s key found.\n", interfacekey);
851 return E_FAIL;
854 tlguidlen = sizeof(tlguid);
855 if (RegQueryValueExA(ikey, NULL, NULL, &type, (BYTE *)tlguid, &tlguidlen))
857 ERR("Getting typelib guid failed.\n");
858 RegCloseKey(ikey);
859 return E_FAIL;
862 verlen = sizeof(ver);
863 if (RegQueryValueExA(ikey, "Version", NULL, &type, (BYTE *)ver, &verlen))
865 ERR("Could not get version value?\n");
866 RegCloseKey(ikey);
867 return E_FAIL;
870 RegCloseKey(ikey);
872 sprintf(typelibkey, "Typelib\\%s\\%s\\0\\win%u", tlguid, ver, sizeof(void *) == 8 ? 64 : 32);
873 tlfnlen = sizeof(tlfn);
874 if (RegQueryValueA(HKEY_CLASSES_ROOT, typelibkey, tlfn, &tlfnlen))
876 #ifdef _WIN64
877 sprintf(typelibkey, "Typelib\\%s\\%s\\0\\win32", tlguid, ver);
878 tlfnlen = sizeof(tlfn);
879 if (RegQueryValueA(HKEY_CLASSES_ROOT, typelibkey, tlfn, &tlfnlen))
881 #endif
882 ERR("Could not get typelib fn?\n");
883 return E_FAIL;
884 #ifdef _WIN64
886 #endif
888 MultiByteToWideChar(CP_ACP, 0, tlfn, -1, module, len);
889 return S_OK;
892 static HRESULT get_typeinfo_for_iid(REFIID iid, ITypeInfo **typeinfo)
894 WCHAR module[MAX_PATH];
895 ITypeLib *typelib;
896 HRESULT hr;
898 *typeinfo = NULL;
900 module[0] = 0;
901 if (!actctx_get_typelib_module(iid, module, ARRAY_SIZE(module)))
903 hr = reg_get_typelib_module(iid, module, ARRAY_SIZE(module));
904 if (FAILED(hr))
905 return hr;
908 hr = LoadTypeLib(module, &typelib);
909 if (hr != S_OK) {
910 ERR("Failed to load typelib for %s, but it should be there.\n", debugstr_guid(iid));
911 return hr;
914 hr = ITypeLib_GetTypeInfoOfGuid(typelib, iid, typeinfo);
915 ITypeLib_Release(typelib);
916 if (hr != S_OK)
917 ERR("typelib does not contain info for %s\n", debugstr_guid(iid));
919 return hr;
922 static HRESULT WINAPI dispatch_typelib_ps_QueryInterface(IPSFactoryBuffer *iface, REFIID iid, void **out)
924 if (IsEqualIID(iid, &IID_IPSFactoryBuffer) || IsEqualIID(iid, &IID_IUnknown))
926 *out = iface;
927 return S_OK;
930 FIXME("No interface for %s.\n", debugstr_guid(iid));
931 *out = NULL;
932 return E_NOINTERFACE;
935 static ULONG WINAPI dispatch_typelib_ps_AddRef(IPSFactoryBuffer *iface)
937 return 2;
940 static ULONG WINAPI dispatch_typelib_ps_Release(IPSFactoryBuffer *iface)
942 return 1;
945 static HRESULT dispatch_create_proxy(IUnknown *outer, IRpcProxyBuffer **proxy, void **out)
947 IPSFactoryBuffer *factory;
948 HRESULT hr;
950 hr = OLEAUTPS_DllGetClassObject(&CLSID_PSFactoryBuffer, &IID_IPSFactoryBuffer, (void **)&factory);
951 if (FAILED(hr)) return hr;
953 hr = IPSFactoryBuffer_CreateProxy(factory, outer, &IID_IDispatch, proxy, out);
954 IPSFactoryBuffer_Release(factory);
955 return hr;
958 static HRESULT WINAPI dispatch_typelib_ps_CreateProxy(IPSFactoryBuffer *iface,
959 IUnknown *outer, REFIID iid, IRpcProxyBuffer **proxy, void **out)
961 ITypeInfo *typeinfo;
962 TYPEATTR *attr;
963 HRESULT hr;
965 if (IsEqualGUID(iid, &IID_IDispatch))
966 return dispatch_create_proxy(outer, proxy, out);
968 hr = get_typeinfo_for_iid(iid, &typeinfo);
969 if (FAILED(hr)) return hr;
971 hr = ITypeInfo_GetTypeAttr(typeinfo, &attr);
972 if (FAILED(hr))
974 ITypeInfo_Release(typeinfo);
975 return hr;
978 if (attr->typekind == TKIND_INTERFACE || (attr->wTypeFlags & TYPEFLAG_FDUAL))
979 hr = CreateProxyFromTypeInfo(typeinfo, outer, iid, proxy, out);
980 else
981 hr = dispatch_create_proxy(outer, proxy, out);
983 if (FAILED(hr))
984 ERR("Failed to create proxy, hr %#lx.\n", hr);
986 ITypeInfo_ReleaseTypeAttr(typeinfo, attr);
987 ITypeInfo_Release(typeinfo);
988 return hr;
991 static HRESULT dispatch_create_stub(IUnknown *server, IRpcStubBuffer **stub)
993 IPSFactoryBuffer *factory;
994 HRESULT hr;
996 hr = OLEAUTPS_DllGetClassObject(&CLSID_PSFactoryBuffer, &IID_IPSFactoryBuffer, (void **)&factory);
997 if (FAILED(hr)) return hr;
999 hr = IPSFactoryBuffer_CreateStub(factory, &IID_IDispatch, server, stub);
1000 IPSFactoryBuffer_Release(factory);
1001 return hr;
1004 struct dispinterface_stub
1006 CInterfaceStubVtbl stub_vtbl;
1007 CStdStubBuffer stub_buffer;
1010 static struct dispinterface_stub *impl_from_IRpcStubBuffer(IRpcStubBuffer *iface)
1012 return CONTAINING_RECORD(&iface->lpVtbl, struct dispinterface_stub, stub_buffer.lpVtbl);
1015 static ULONG WINAPI dispinterface_stub_Release(IRpcStubBuffer *iface)
1017 struct dispinterface_stub *stub = impl_from_IRpcStubBuffer(iface);
1018 unsigned int refcount = InterlockedDecrement(&stub->stub_buffer.RefCount);
1020 TRACE("%p decreasing refcount to %u.\n", stub, refcount);
1022 if (!refcount)
1024 /* Copied from NdrCStdStubBuffer_Release(), but supposedly incorrect
1025 * according to the comment there. */
1026 IRpcStubBuffer_Disconnect(iface);
1028 free(stub);
1030 return refcount;
1033 extern const ExtendedProxyFileInfo oleaut32_oaidl_ProxyFileInfo;
1035 static const CInterfaceStubVtbl *find_idispatch_stub_vtbl(void)
1037 CInterfaceStubVtbl *const *vtbl;
1039 for (vtbl = oleaut32_oaidl_ProxyFileInfo.pStubVtblList; *vtbl; ++vtbl)
1041 if (IsEqualGUID((*vtbl)->header.piid, &IID_IDispatch))
1042 return *vtbl;
1045 assert(0);
1046 return NULL;
1049 /* Normal dispinterfaces have an IID specified by the IDL compiler as DIID_*,
1050 * but are otherwise identical to IDispatch. Unfortunately, such interfaces may
1051 * not actually support IDispatch in QueryInterface.
1053 * This becomes a problem, since CreateStub() was designed such that, for some
1054 * reason, the caller need not actually pass the interface matching "iid". As
1055 * such the standard rpcrt4 implementation will query the server for the
1056 * relevant IID.
1058 * This means that we cannot just pass IID_IDispatch with the object, even
1059 * though it is in theory an IDispatch. However, while the standard stub
1060 * constructor is not exported from rpcrt4, all of the vtbl methods are, and
1061 * the type is public, so we *can* manually create it ourselves, bypassing the
1062 * QueryInterface check.
1064 * This relies on some rpcrt4 implementation details.
1066 static HRESULT dispinterface_create_stub(IUnknown *server, const GUID *iid, IRpcStubBuffer **stub)
1068 const CInterfaceStubVtbl *stub_vtbl = find_idispatch_stub_vtbl();
1069 struct dispinterface_stub *object;
1070 void *dispatch;
1071 HRESULT hr;
1073 if (!(object = calloc(1, sizeof(*object))))
1074 return E_OUTOFMEMORY;
1076 /* It's possible we can just assume that "server" is already the
1077 * dispinterface type—we don't have tests for this—but since rpcrt4 queries
1078 * (which we do have tests for) it makes sense for us to match that
1079 * behaviour. */
1080 if (FAILED(hr = IUnknown_QueryInterface(server, iid, &dispatch)))
1082 ERR("Object does not support interface %s.\n", debugstr_guid(iid));
1083 free(object);
1084 return hr;
1087 object->stub_vtbl.header = stub_vtbl->header;
1088 object->stub_vtbl.Vtbl.QueryInterface = CStdStubBuffer_QueryInterface;
1089 object->stub_vtbl.Vtbl.AddRef = CStdStubBuffer_AddRef;
1090 object->stub_vtbl.Vtbl.Release = dispinterface_stub_Release;
1091 object->stub_vtbl.Vtbl.Connect = CStdStubBuffer_Connect;
1092 object->stub_vtbl.Vtbl.Disconnect = CStdStubBuffer_Disconnect;
1093 object->stub_vtbl.Vtbl.Invoke = CStdStubBuffer_Invoke;
1094 object->stub_vtbl.Vtbl.IsIIDSupported = CStdStubBuffer_IsIIDSupported;
1095 object->stub_vtbl.Vtbl.CountRefs = CStdStubBuffer_CountRefs;
1096 object->stub_vtbl.Vtbl.DebugServerQueryInterface = CStdStubBuffer_DebugServerQueryInterface;
1097 object->stub_vtbl.Vtbl.DebugServerRelease = CStdStubBuffer_DebugServerRelease;
1098 object->stub_buffer.lpVtbl = &object->stub_vtbl.Vtbl;
1099 object->stub_buffer.RefCount = 1;
1100 object->stub_buffer.pvServerObject = dispatch;
1101 /* rpcrt4 will also fill pPSFactory, but it never uses it except in the
1102 * Release method (which we reimplement). It's only to keep a reference to
1103 * the module to implement NdrDllCanUnloadNow(). We use the default
1104 * DllCanUnloadNow() from winecrt0, which always returns S_FALSE, so don't
1105 * bother filling pPSFactory. */
1107 TRACE("Created stub %p.\n", object);
1108 *stub = (IRpcStubBuffer *)&object->stub_buffer.lpVtbl;
1109 return S_OK;
1112 static HRESULT WINAPI dispatch_typelib_ps_CreateStub(IPSFactoryBuffer *iface,
1113 REFIID iid, IUnknown *server, IRpcStubBuffer **stub)
1115 ITypeInfo *typeinfo;
1116 TYPEATTR *attr;
1117 HRESULT hr;
1119 if (IsEqualGUID(iid, &IID_IDispatch))
1120 return dispatch_create_stub(server, stub);
1122 hr = get_typeinfo_for_iid(iid, &typeinfo);
1123 if (FAILED(hr)) return hr;
1125 hr = ITypeInfo_GetTypeAttr(typeinfo, &attr);
1126 if (FAILED(hr))
1128 ITypeInfo_Release(typeinfo);
1129 return hr;
1132 if (attr->typekind == TKIND_INTERFACE || (attr->wTypeFlags & TYPEFLAG_FDUAL))
1133 hr = CreateStubFromTypeInfo(typeinfo, iid, server, stub);
1134 else
1135 hr = dispinterface_create_stub(server, iid, stub);
1137 if (FAILED(hr))
1138 ERR("Failed to create stub, hr %#lx.\n", hr);
1140 ITypeInfo_ReleaseTypeAttr(typeinfo, attr);
1141 ITypeInfo_Release(typeinfo);
1142 return hr;
1145 static const IPSFactoryBufferVtbl dispatch_typelib_ps_vtbl =
1147 dispatch_typelib_ps_QueryInterface,
1148 dispatch_typelib_ps_AddRef,
1149 dispatch_typelib_ps_Release,
1150 dispatch_typelib_ps_CreateProxy,
1151 dispatch_typelib_ps_CreateStub,
1154 static IPSFactoryBuffer dispatch_typelib_ps = { &dispatch_typelib_ps_vtbl };
1156 extern void _get_STDFONT_CF(LPVOID *);
1157 extern void _get_STDPIC_CF(LPVOID *);
1159 /***********************************************************************
1160 * DllGetClassObject (OLEAUT32.@)
1162 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
1164 *ppv = NULL;
1165 if (IsEqualGUID(rclsid,&CLSID_StdFont)) {
1166 if (IsEqualGUID(iid,&IID_IClassFactory)) {
1167 _get_STDFONT_CF(ppv);
1168 IClassFactory_AddRef((IClassFactory*)*ppv);
1169 return S_OK;
1172 if (IsEqualGUID(rclsid,&CLSID_StdPicture)) {
1173 if (IsEqualGUID(iid,&IID_IClassFactory)) {
1174 _get_STDPIC_CF(ppv);
1175 IClassFactory_AddRef((IClassFactory*)*ppv);
1176 return S_OK;
1180 if (IsEqualGUID(rclsid, &CLSID_PSDispatch) || IsEqualGUID(rclsid, &CLSID_PSOAInterface))
1181 return IPSFactoryBuffer_QueryInterface(&dispatch_typelib_ps, iid, ppv);
1183 if (IsEqualCLSID(rclsid, &CLSID_PSTypeComp) ||
1184 IsEqualCLSID(rclsid, &CLSID_PSTypeInfo) ||
1185 IsEqualCLSID(rclsid, &CLSID_PSTypeLib) ||
1186 IsEqualCLSID(rclsid, &CLSID_PSDispatch) ||
1187 IsEqualCLSID(rclsid, &CLSID_PSEnumVariant))
1188 return OLEAUTPS_DllGetClassObject(&CLSID_PSFactoryBuffer, iid, ppv);
1190 return OLEAUTPS_DllGetClassObject(rclsid, iid, ppv);
1193 /*****************************************************************************
1194 * DllMain [OLEAUT32.@]
1196 BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD fdwReason, LPVOID lpvReserved)
1198 if(fdwReason == DLL_PROCESS_ATTACH)
1199 bstr_cache_enabled = !GetEnvironmentVariableW(L"oanocache", NULL, 0);
1201 return OLEAUTPS_DllMain( hInstDll, fdwReason, lpvReserved );
1204 /***********************************************************************
1205 * DllRegisterServer (OLEAUT32.@)
1207 HRESULT WINAPI DllRegisterServer(void)
1209 return OLEAUTPS_DllRegisterServer();
1212 /***********************************************************************
1213 * DllUnregisterServer (OLEAUT32.@)
1215 HRESULT WINAPI DllUnregisterServer(void)
1217 return OLEAUTPS_DllUnregisterServer();
1220 /***********************************************************************
1221 * OleIconToCursor (OLEAUT32.415)
1223 HCURSOR WINAPI OleIconToCursor( HINSTANCE hinstExe, HICON hIcon)
1225 FIXME("(%p,%p), partially implemented.\n",hinstExe,hIcon);
1226 /* FIXME: make an extended conversation from HICON to HCURSOR */
1227 return CopyCursor(hIcon);
1230 /***********************************************************************
1231 * GetAltMonthNames (OLEAUT32.@)
1233 HRESULT WINAPI GetAltMonthNames(LCID lcid, LPOLESTR **str)
1235 static const WCHAR *arabic_hijri[] =
1237 L"\x0645\x062d\x0631\x0645",
1238 L"\x0635\x0641\x0631",
1239 L"\x0631\x0628\x064a\x0639 \x0627\x0644\x0627\x0648\x0644",
1240 L"\x0631\x0628\x064a\x0639 \x0627\x0644\x062b\x0627\x0646\x064a",
1241 L"\x062c\x0645\x0627\x062f\x0649 \x0627\x0644\x0627\x0648\x0644\x0649",
1242 L"\x062c\x0645\x0627\x062f\x0649 \x0627\x0644\x062b\x0627\x0646\x064a\x0629",
1243 L"\x0631\x062c\x0628",
1244 L"\x0634\x0639\x0628\x0627\x0646",
1245 L"\x0631\x0645\x0636\x0627\x0646",
1246 L"\x0634\x0648\x0627\x0643",
1247 L"\x0630\x0648 \x0627\x0644\x0642\x0639\x062f\x0629",
1248 L"\x0630\x0648 \x0627\x0644\x062d\x062c\x0629",
1249 NULL
1252 static const WCHAR *polish_genitive_names[] =
1254 L"stycznia",
1255 L"lutego",
1256 L"marca",
1257 L"kwietnia",
1258 L"maja",
1259 L"czerwca",
1260 L"lipca",
1261 L"sierpnia",
1262 L"wrze\x015bnia",
1263 L"pa\x017a" "dziernika",
1264 L"listopada",
1265 L"grudnia",
1266 NULL
1269 static const WCHAR *russian_genitive_names[] =
1271 L"\x044f\x043d\x0432\x0430\x0440\x044f",
1272 L"\x0444\x0435\x0432\x0440\x0430\x043b\x044f",
1273 L"\x043c\x0430\x0440\x0442\x0430",
1274 L"\x0430\x043f\x0440\x0435\x043b\x044f",
1275 L"\x043c\x0430\x044f",
1276 L"\x0438\x044e\x043d\x044f",
1277 L"\x0438\x044e\x043b\x044f",
1278 L"\x0430\x0432\x0433\x0443\x0441\x0442\x0430",
1279 L"\x0441\x0435\x043d\x0442\x044f\x0431\x0440\x044f",
1280 L"\x043e\x043a\x0442\x044f\x0431\x0440\x044f",
1281 L"\x043d\x043e\x044f\x0431\x0440\x044f",
1282 L"\x0434\x0435\x043a\x0430\x0431\x0440\x044f",
1283 NULL
1286 TRACE("%#lx, %p.\n", lcid, str);
1288 if (PRIMARYLANGID(LANGIDFROMLCID(lcid)) == LANG_ARABIC)
1289 *str = (LPOLESTR *)arabic_hijri;
1290 else if (PRIMARYLANGID(LANGIDFROMLCID(lcid)) == LANG_POLISH)
1291 *str = (LPOLESTR *)polish_genitive_names;
1292 else if (PRIMARYLANGID(LANGIDFROMLCID(lcid)) == LANG_RUSSIAN)
1293 *str = (LPOLESTR *)russian_genitive_names;
1294 else
1295 *str = NULL;
1297 return S_OK;