xref: /reactos/dll/win32/oleaut32/oleaut.c (revision 5bfe6a53)
1 /*
2  *	OLEAUT32
3  *
4  * Copyright 1999, 2000 Marcus Meissner
5  *
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.
10  *
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.
15  *
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
19  */
20 
21 #include "config.h"
22 
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <limits.h>
27 
28 #define COBJMACROS
29 
30 #include "windef.h"
31 #include "winbase.h"
32 #include "wingdi.h"
33 #include "winuser.h"
34 #include "winerror.h"
35 
36 #include "ole2.h"
37 #include "olectl.h"
38 #include "oleauto.h"
39 #include "initguid.h"
40 #include "typelib.h"
41 #include "oleaut32_oaidl.h"
42 
43 #include "wine/debug.h"
44 #include "wine/unicode.h"
45 
46 WINE_DEFAULT_DEBUG_CHANNEL(ole);
47 WINE_DECLARE_DEBUG_CHANNEL(heap);
48 
49 /******************************************************************************
50  * BSTR  {OLEAUT32}
51  *
52  * NOTES
53  *  BSTR is a simple typedef for a wide-character string used as the principle
54  *  string type in ole automation. When encapsulated in a Variant type they are
55  *  automatically copied and destroyed as the variant is processed.
56  *
57  *  The low level BSTR API allows manipulation of these strings and is used by
58  *  higher level API calls to manage the strings transparently to the caller.
59  *
60  *  Internally the BSTR type is allocated with space for a DWORD byte count before
61  *  the string data begins. This is undocumented and non-system code should not
62  *  access the count directly. Use SysStringLen() or SysStringByteLen()
63  *  instead. Note that the byte count does not include the terminating NUL.
64  *
65  *  To create a new BSTR, use SysAllocString(), SysAllocStringLen() or
66  *  SysAllocStringByteLen(). To change the size of an existing BSTR, use SysReAllocString()
67  *  or SysReAllocStringLen(). Finally to destroy a string use SysFreeString().
68  *
69  *  BSTR's are cached by Ole Automation by default. To override this behaviour
70  *  either set the environment variable 'OANOCACHE', or call SetOaNoCache().
71  *
72  * SEE ALSO
73  *  'Inside OLE, second edition' by Kraig Brockshmidt.
74  */
75 
76 static BOOL bstr_cache_enabled;
77 
78 static CRITICAL_SECTION cs_bstr_cache;
79 static CRITICAL_SECTION_DEBUG cs_bstr_cache_dbg =
80 {
81     0, 0, &cs_bstr_cache,
82     { &cs_bstr_cache_dbg.ProcessLocksList, &cs_bstr_cache_dbg.ProcessLocksList },
83       0, 0, { (DWORD_PTR)(__FILE__ ": bstr_cache") }
84 };
85 static CRITICAL_SECTION cs_bstr_cache = { &cs_bstr_cache_dbg, -1, 0, 0, 0, 0 };
86 
87 typedef struct {
88 #ifdef _WIN64
89     DWORD pad;
90 #endif
91     DWORD size;
92     union {
93         char ptr[1];
94         WCHAR str[1];
95         DWORD dwptr[1];
96     } u;
97 } bstr_t;
98 
99 #define BUCKET_SIZE 16
100 #define BUCKET_BUFFER_SIZE 6
101 
102 typedef struct {
103     unsigned short head;
104     unsigned short cnt;
105     bstr_t *buf[BUCKET_BUFFER_SIZE];
106 } bstr_cache_entry_t;
107 
108 #define ARENA_INUSE_FILLER     0x55
109 #define ARENA_TAIL_FILLER      0xab
110 #define ARENA_FREE_FILLER      0xfeeefeee
111 
112 static bstr_cache_entry_t bstr_cache[0x10000/BUCKET_SIZE];
113 
114 static inline size_t bstr_alloc_size(size_t size)
115 {
116     return (FIELD_OFFSET(bstr_t, u.ptr[size]) + sizeof(WCHAR) + BUCKET_SIZE-1) & ~(BUCKET_SIZE-1);
117 }
118 
119 static inline bstr_t *bstr_from_str(BSTR str)
120 {
121     return CONTAINING_RECORD((void *)str, bstr_t, u.str);
122 }
123 
124 static inline bstr_cache_entry_t *get_cache_entry_from_idx(unsigned cache_idx)
125 {
126     return bstr_cache_enabled && cache_idx < ARRAY_SIZE(bstr_cache) ? bstr_cache + cache_idx : NULL;
127 }
128 
129 static inline bstr_cache_entry_t *get_cache_entry(size_t size)
130 {
131     unsigned cache_idx = FIELD_OFFSET(bstr_t, u.ptr[size+sizeof(WCHAR)-1])/BUCKET_SIZE;
132     return get_cache_entry_from_idx(cache_idx);
133 }
134 
135 static inline bstr_cache_entry_t *get_cache_entry_from_alloc_size(SIZE_T alloc_size)
136 {
137     unsigned cache_idx;
138     if (alloc_size < BUCKET_SIZE) return NULL;
139     cache_idx = (alloc_size - BUCKET_SIZE) / BUCKET_SIZE;
140     return get_cache_entry_from_idx(cache_idx);
141 }
142 
143 static bstr_t *alloc_bstr(size_t size)
144 {
145     bstr_cache_entry_t *cache_entry = get_cache_entry(size);
146     bstr_t *ret;
147 
148     if(cache_entry) {
149         EnterCriticalSection(&cs_bstr_cache);
150 
151         if(!cache_entry->cnt) {
152             cache_entry = get_cache_entry(size+BUCKET_SIZE);
153             if(cache_entry && !cache_entry->cnt)
154                 cache_entry = NULL;
155         }
156 
157         if(cache_entry) {
158             ret = cache_entry->buf[cache_entry->head++];
159             cache_entry->head %= BUCKET_BUFFER_SIZE;
160             cache_entry->cnt--;
161         }
162 
163         LeaveCriticalSection(&cs_bstr_cache);
164 
165         if(cache_entry) {
166             if(WARN_ON(heap)) {
167                 size_t fill_size = (FIELD_OFFSET(bstr_t, u.ptr[size])+2*sizeof(WCHAR)-1) & ~(sizeof(WCHAR)-1);
168                 memset(ret, ARENA_INUSE_FILLER, fill_size);
169                 memset((char *)ret+fill_size, ARENA_TAIL_FILLER, bstr_alloc_size(size)-fill_size);
170             }
171             ret->size = size;
172             return ret;
173         }
174     }
175 
176     ret = CoTaskMemAlloc(bstr_alloc_size(size));
177     if(ret)
178         ret->size = size;
179     return ret;
180 }
181 
182 /******************************************************************************
183  *             SysStringLen  [OLEAUT32.7]
184  *
185  * Get the allocated length of a BSTR in wide characters.
186  *
187  * PARAMS
188  *  str [I] BSTR to find the length of
189  *
190  * RETURNS
191  *  The allocated length of str, or 0 if str is NULL.
192  *
193  * NOTES
194  *  See BSTR.
195  *  The returned length may be different from the length of the string as
196  *  calculated by lstrlenW(), since it returns the length that was used to
197  *  allocate the string by SysAllocStringLen().
198  */
199 UINT WINAPI SysStringLen(BSTR str)
200 {
201     return str ? bstr_from_str(str)->size/sizeof(WCHAR) : 0;
202 }
203 
204 /******************************************************************************
205  *             SysStringByteLen  [OLEAUT32.149]
206  *
207  * Get the allocated length of a BSTR in bytes.
208  *
209  * PARAMS
210  *  str [I] BSTR to find the length of
211  *
212  * RETURNS
213  *  The allocated length of str, or 0 if str is NULL.
214  *
215  * NOTES
216  *  See SysStringLen(), BSTR().
217  */
218 UINT WINAPI SysStringByteLen(BSTR str)
219 {
220     return str ? bstr_from_str(str)->size : 0;
221 }
222 
223 /******************************************************************************
224  *		SysAllocString	[OLEAUT32.2]
225  *
226  * Create a BSTR from an OLESTR.
227  *
228  * PARAMS
229  *  str [I] Source to create BSTR from
230  *
231  * RETURNS
232  *  Success: A BSTR allocated with SysAllocStringLen().
233  *  Failure: NULL, if oleStr is NULL.
234  *
235  * NOTES
236  *  See BSTR.
237  *  MSDN (October 2001) incorrectly states that NULL is returned if oleStr has
238  *  a length of 0. Native Win32 and this implementation both return a valid
239  *  empty BSTR in this case.
240  */
241 BSTR WINAPI SysAllocString(LPCOLESTR str)
242 {
243     if (!str) return 0;
244 
245     /* Delegate this to the SysAllocStringLen32 method. */
246     return SysAllocStringLen(str, lstrlenW(str));
247 }
248 
249 static inline IMalloc *get_malloc(void)
250 {
251     static IMalloc *malloc;
252 
253     if (!malloc)
254         CoGetMalloc(1, &malloc);
255 
256     return malloc;
257 }
258 
259 /******************************************************************************
260  *		SysFreeString	[OLEAUT32.6]
261  *
262  * Free a BSTR.
263  *
264  * PARAMS
265  *  str [I] BSTR to free.
266  *
267  * RETURNS
268  *  Nothing.
269  *
270  * NOTES
271  *  See BSTR.
272  *  str may be NULL, in which case this function does nothing.
273  */
274 void WINAPI DECLSPEC_HOTPATCH SysFreeString(BSTR str)
275 {
276     bstr_cache_entry_t *cache_entry;
277     bstr_t *bstr;
278     IMalloc *malloc = get_malloc();
279     SIZE_T alloc_size;
280 
281     if(!str)
282         return;
283 
284     bstr = bstr_from_str(str);
285 
286     alloc_size = IMalloc_GetSize(malloc, bstr);
287     if (alloc_size == ~0UL)
288         return;
289 
290     cache_entry = get_cache_entry_from_alloc_size(alloc_size);
291     if(cache_entry) {
292         unsigned i;
293 
294         EnterCriticalSection(&cs_bstr_cache);
295 
296         /* According to tests, freeing a string that's already in cache doesn't corrupt anything.
297          * For that to work we need to search the cache. */
298         for(i=0; i < cache_entry->cnt; i++) {
299             if(cache_entry->buf[(cache_entry->head+i) % BUCKET_BUFFER_SIZE] == bstr) {
300                 WARN_(heap)("String already is in cache!\n");
301                 LeaveCriticalSection(&cs_bstr_cache);
302                 return;
303             }
304         }
305 
306         if(cache_entry->cnt < ARRAY_SIZE(cache_entry->buf)) {
307             cache_entry->buf[(cache_entry->head+cache_entry->cnt) % BUCKET_BUFFER_SIZE] = bstr;
308             cache_entry->cnt++;
309 
310             if(WARN_ON(heap)) {
311                 unsigned n = (alloc_size-FIELD_OFFSET(bstr_t, u.ptr))/sizeof(DWORD);
312                 for(i=0; i<n; i++)
313                     bstr->u.dwptr[i] = ARENA_FREE_FILLER;
314             }
315 
316             LeaveCriticalSection(&cs_bstr_cache);
317             return;
318         }
319 
320         LeaveCriticalSection(&cs_bstr_cache);
321     }
322 
323     CoTaskMemFree(bstr);
324 }
325 
326 /******************************************************************************
327  *             SysAllocStringLen     [OLEAUT32.4]
328  *
329  * Create a BSTR from an OLESTR of a given wide character length.
330  *
331  * PARAMS
332  *  str [I] Source to create BSTR from
333  *  len [I] Length of oleStr in wide characters
334  *
335  * RETURNS
336  *  Success: A newly allocated BSTR from SysAllocStringByteLen()
337  *  Failure: NULL, if len is >= 0x80000000, or memory allocation fails.
338  *
339  * NOTES
340  *  See BSTR(), SysAllocStringByteLen().
341  */
342 BSTR WINAPI SysAllocStringLen(const OLECHAR *str, unsigned int len)
343 {
344     bstr_t *bstr;
345     DWORD size;
346 
347     /* Detect integer overflow. */
348     if (len >= ((UINT_MAX-sizeof(WCHAR)-sizeof(DWORD))/sizeof(WCHAR)))
349 	return NULL;
350 
351     TRACE("%s\n", debugstr_wn(str, len));
352 
353     size = len*sizeof(WCHAR);
354     bstr = alloc_bstr(size);
355     if(!bstr)
356         return NULL;
357 
358     if(str) {
359         memcpy(bstr->u.str, str, size);
360         bstr->u.str[len] = 0;
361     }else {
362         memset(bstr->u.str, 0, size+sizeof(WCHAR));
363     }
364 
365     return bstr->u.str;
366 }
367 
368 /******************************************************************************
369  *             SysReAllocStringLen   [OLEAUT32.5]
370  *
371  * Change the length of a previously created BSTR.
372  *
373  * PARAMS
374  *  old [O] BSTR to change the length of
375  *  str [I] New source for pbstr
376  *  len [I] Length of oleStr in wide characters
377  *
378  * RETURNS
379  *  Success: 1. The size of pbstr is updated.
380  *  Failure: 0, if len >= 0x80000000 or memory allocation fails.
381  *
382  * NOTES
383  *  See BSTR(), SysAllocStringByteLen().
384  *  *old may be changed by this function.
385  */
386 int WINAPI SysReAllocStringLen(BSTR* old, const OLECHAR* str, unsigned int len)
387 {
388     /* Detect integer overflow. */
389     if (len >= ((UINT_MAX-sizeof(WCHAR)-sizeof(DWORD))/sizeof(WCHAR)))
390 	return FALSE;
391 
392     if (*old!=NULL) {
393       DWORD newbytelen = len*sizeof(WCHAR);
394       bstr_t *old_bstr = bstr_from_str(*old);
395       bstr_t *bstr = CoTaskMemRealloc(old_bstr, bstr_alloc_size(newbytelen));
396 
397       if (!bstr) return FALSE;
398 
399       *old = bstr->u.str;
400       bstr->size = newbytelen;
401       /* The old string data is still there when str is NULL */
402       if (str && old_bstr->u.str != str) memmove(bstr->u.str, str, newbytelen);
403       bstr->u.str[len] = 0;
404     } else {
405       *old = SysAllocStringLen(str, len);
406     }
407 
408     return TRUE;
409 }
410 
411 /******************************************************************************
412  *             SysAllocStringByteLen     [OLEAUT32.150]
413  *
414  * Create a BSTR from an OLESTR of a given byte length.
415  *
416  * PARAMS
417  *  str [I] Source to create BSTR from
418  *  len [I] Length of oleStr in bytes
419  *
420  * RETURNS
421  *  Success: A newly allocated BSTR
422  *  Failure: NULL, if len is >= 0x80000000, or memory allocation fails.
423  *
424  * NOTES
425  *  -If len is 0 or oleStr is NULL the resulting string is empty ("").
426  *  -This function always NUL terminates the resulting BSTR.
427  *  -oleStr may be either an LPCSTR or LPCOLESTR, since it is copied
428  *  without checking for a terminating NUL.
429  *  See BSTR.
430  */
431 BSTR WINAPI DECLSPEC_HOTPATCH SysAllocStringByteLen(LPCSTR str, UINT len)
432 {
433     bstr_t *bstr;
434 
435     /* Detect integer overflow. */
436     if (len >= (UINT_MAX-sizeof(WCHAR)-sizeof(DWORD)))
437 	return NULL;
438 
439     bstr = alloc_bstr(len);
440     if(!bstr)
441         return NULL;
442 
443     if(str) {
444         memcpy(bstr->u.ptr, str, len);
445         bstr->u.ptr[len] = 0;
446     }else {
447         memset(bstr->u.ptr, 0, len+1);
448     }
449     bstr->u.str[(len+sizeof(WCHAR)-1)/sizeof(WCHAR)] = 0;
450 
451     return bstr->u.str;
452 }
453 
454 /******************************************************************************
455  *		SysReAllocString	[OLEAUT32.3]
456  *
457  * Change the length of a previously created BSTR.
458  *
459  * PARAMS
460  *  old [I/O] BSTR to change the length of
461  *  str [I]   New source for pbstr
462  *
463  * RETURNS
464  *  Success: 1
465  *  Failure: 0.
466  *
467  * NOTES
468  *  See BSTR(), SysAllocStringStringLen().
469  */
470 INT WINAPI SysReAllocString(LPBSTR old,LPCOLESTR str)
471 {
472     /*
473      * Sanity check
474      */
475     if (old==NULL)
476       return 0;
477 
478     /*
479      * Make sure we free the old string.
480      */
481     SysFreeString(*old);
482 
483     /*
484      * Allocate the new string
485      */
486     *old = SysAllocString(str);
487 
488      return 1;
489 }
490 
491 /******************************************************************************
492  *		SetOaNoCache (OLEAUT32.327)
493  *
494  * Instruct Ole Automation not to cache BSTR allocations.
495  *
496  * PARAMS
497  *  None.
498  *
499  * RETURNS
500  *  Nothing.
501  *
502  * NOTES
503  *  SetOaNoCache does not release cached strings, so it leaks by design.
504  */
505 void WINAPI SetOaNoCache(void)
506 {
507     TRACE("\n");
508     bstr_cache_enabled = FALSE;
509 }
510 
511 static const WCHAR	_delimiter[] = {'!',0}; /* default delimiter apparently */
512 static const WCHAR	*pdelimiter = &_delimiter[0];
513 
514 /***********************************************************************
515  *		RegisterActiveObject (OLEAUT32.33)
516  *
517  * Registers an object in the global item table.
518  *
519  * PARAMS
520  *  punk        [I] Object to register.
521  *  rcid        [I] CLSID of the object.
522  *  dwFlags     [I] Flags.
523  *  pdwRegister [O] Address to store cookie of object registration in.
524  *
525  * RETURNS
526  *  Success: S_OK.
527  *  Failure: HRESULT code.
528  */
529 HRESULT WINAPI DECLSPEC_HOTPATCH RegisterActiveObject(
530 	LPUNKNOWN punk,REFCLSID rcid,DWORD dwFlags,LPDWORD pdwRegister
531 ) {
532 	WCHAR 			guidbuf[80];
533 	HRESULT			ret;
534 	LPRUNNINGOBJECTTABLE	runobtable;
535 	LPMONIKER		moniker;
536         DWORD                   rot_flags = ROTFLAGS_REGISTRATIONKEEPSALIVE; /* default registration is strong */
537 
538 	StringFromGUID2(rcid,guidbuf,39);
539 	ret = CreateItemMoniker(pdelimiter,guidbuf,&moniker);
540 	if (FAILED(ret))
541 		return ret;
542 	ret = GetRunningObjectTable(0,&runobtable);
543 	if (FAILED(ret)) {
544 		IMoniker_Release(moniker);
545 		return ret;
546 	}
547         if(dwFlags == ACTIVEOBJECT_WEAK)
548           rot_flags = 0;
549 	ret = IRunningObjectTable_Register(runobtable,rot_flags,punk,moniker,pdwRegister);
550 	IRunningObjectTable_Release(runobtable);
551 	IMoniker_Release(moniker);
552 	return ret;
553 }
554 
555 /***********************************************************************
556  *		RevokeActiveObject (OLEAUT32.34)
557  *
558  * Revokes an object from the global item table.
559  *
560  * PARAMS
561  *  xregister [I] Registration cookie.
562  *  reserved  [I] Reserved. Set to NULL.
563  *
564  * RETURNS
565  *  Success: S_OK.
566  *  Failure: HRESULT code.
567  */
568 HRESULT WINAPI DECLSPEC_HOTPATCH RevokeActiveObject(DWORD xregister,LPVOID reserved)
569 {
570 	LPRUNNINGOBJECTTABLE	runobtable;
571 	HRESULT			ret;
572 
573 	ret = GetRunningObjectTable(0,&runobtable);
574 	if (FAILED(ret)) return ret;
575 	ret = IRunningObjectTable_Revoke(runobtable,xregister);
576 	if (SUCCEEDED(ret)) ret = S_OK;
577 	IRunningObjectTable_Release(runobtable);
578 	return ret;
579 }
580 
581 /***********************************************************************
582  *		GetActiveObject (OLEAUT32.35)
583  *
584  * Gets an object from the global item table.
585  *
586  * PARAMS
587  *  rcid        [I] CLSID of the object.
588  *  preserved   [I] Reserved. Set to NULL.
589  *  ppunk       [O] Address to store object into.
590  *
591  * RETURNS
592  *  Success: S_OK.
593  *  Failure: HRESULT code.
594  */
595 HRESULT WINAPI DECLSPEC_HOTPATCH GetActiveObject(REFCLSID rcid,LPVOID preserved,LPUNKNOWN *ppunk)
596 {
597 	WCHAR 			guidbuf[80];
598 	HRESULT			ret;
599 	LPRUNNINGOBJECTTABLE	runobtable;
600 	LPMONIKER		moniker;
601 
602 	StringFromGUID2(rcid,guidbuf,39);
603 	ret = CreateItemMoniker(pdelimiter,guidbuf,&moniker);
604 	if (FAILED(ret))
605 		return ret;
606 	ret = GetRunningObjectTable(0,&runobtable);
607 	if (FAILED(ret)) {
608 		IMoniker_Release(moniker);
609 		return ret;
610 	}
611 	ret = IRunningObjectTable_GetObject(runobtable,moniker,ppunk);
612 	IRunningObjectTable_Release(runobtable);
613 	IMoniker_Release(moniker);
614 	return ret;
615 }
616 
617 
618 /***********************************************************************
619  *           OaBuildVersion           [OLEAUT32.170]
620  *
621  * Get the Ole Automation build version.
622  *
623  * PARAMS
624  *  None
625  *
626  * RETURNS
627  *  The build version.
628  *
629  * NOTES
630  *  Known oleaut32.dll versions:
631  *| OLE Ver.  Comments                   Date     Build Ver.
632  *| --------  -------------------------  ----     ---------
633  *| OLE 2.1   NT                         1993-95  10 3023
634  *| OLE 2.1                                       10 3027
635  *| Win32s    Ver 1.1e                            20 4049
636  *| OLE 2.20  W95/NT                     1993-96  20 4112
637  *| OLE 2.20  W95/NT                     1993-96  20 4118
638  *| OLE 2.20  W95/NT                     1993-96  20 4122
639  *| OLE 2.30  W95/NT                     1993-98  30 4265
640  *| OLE 2.40  NT??                       1993-98  40 4267
641  *| OLE 2.40  W98 SE orig. file          1993-98  40 4275
642  *| OLE 2.40  W2K orig. file             1993-XX  40 4514
643  *
644  * Currently the versions returned are 2.20 for Win3.1, 2.30 for Win95 & NT 3.51,
645  * and 2.40 for all later versions. The build number is maximum, i.e. 0xffff.
646  */
647 ULONG WINAPI OaBuildVersion(void)
648 {
649     switch(GetVersion() & 0x8000ffff)  /* mask off build number */
650     {
651     case 0x80000a03:  /* WIN31 */
652 		return MAKELONG(0xffff, 20);
653     case 0x00003303:  /* NT351 */
654 		return MAKELONG(0xffff, 30);
655     case 0x80000004:  /* WIN95; I'd like to use the "standard" w95 minor
656 		         version here (30), but as we still use w95
657 		         as default winver (which is good IMHO), I better
658 		         play safe and use the latest value for w95 for now.
659 		         Change this as soon as default winver gets changed
660 		         to something more recent */
661     case 0x80000a04:  /* WIN98 */
662     case 0x00000004:  /* NT40 */
663     case 0x00000005:  /* W2K */
664 		return MAKELONG(0xffff, 40);
665     case 0x00000105:  /* WinXP */
666     case 0x00000006:  /* Vista */
667     case 0x00000106:  /* Win7 */
668 		return MAKELONG(0xffff, 50);
669     default:
670 		FIXME("Version value not known yet. Please investigate it !\n");
671 		return MAKELONG(0xffff, 40);  /* for now return the same value as for w2k */
672     }
673 }
674 
675 /******************************************************************************
676  *		OleTranslateColor	[OLEAUT32.421]
677  *
678  * Convert an OLE_COLOR to a COLORREF.
679  *
680  * PARAMS
681  *  clr       [I] Color to convert
682  *  hpal      [I] Handle to a palette for the conversion
683  *  pColorRef [O] Destination for converted color, or NULL to test if the conversion is ok
684  *
685  * RETURNS
686  *  Success: S_OK. The conversion is ok, and pColorRef contains the converted color if non-NULL.
687  *  Failure: E_INVALIDARG, if any argument is invalid.
688  *
689  * FIXME
690  *  Document the conversion rules.
691  */
692 HRESULT WINAPI OleTranslateColor(
693   OLE_COLOR clr,
694   HPALETTE  hpal,
695   COLORREF* pColorRef)
696 {
697   COLORREF colorref;
698   BYTE b = HIBYTE(HIWORD(clr));
699 
700   TRACE("(%08x, %p, %p)\n", clr, hpal, pColorRef);
701 
702   /*
703    * In case pColorRef is NULL, provide our own to simplify the code.
704    */
705   if (pColorRef == NULL)
706     pColorRef = &colorref;
707 
708   switch (b)
709   {
710     case 0x00:
711     {
712       if (hpal != 0)
713         *pColorRef =  PALETTERGB(GetRValue(clr),
714                                  GetGValue(clr),
715                                  GetBValue(clr));
716       else
717         *pColorRef = clr;
718 
719       break;
720     }
721 
722     case 0x01:
723     {
724       if (hpal != 0)
725       {
726         PALETTEENTRY pe;
727         /*
728          * Validate the palette index.
729          */
730         if (GetPaletteEntries(hpal, LOWORD(clr), 1, &pe) == 0)
731           return E_INVALIDARG;
732       }
733 
734       *pColorRef = clr;
735 
736       break;
737     }
738 
739     case 0x02:
740       *pColorRef = clr;
741       break;
742 
743     case 0x80:
744     {
745       int index = LOBYTE(LOWORD(clr));
746 
747       /*
748        * Validate GetSysColor index.
749        */
750       if ((index < COLOR_SCROLLBAR) || (index > COLOR_MENUBAR))
751         return E_INVALIDARG;
752 
753       *pColorRef =  GetSysColor(index);
754 
755       break;
756     }
757 
758     default:
759       return E_INVALIDARG;
760   }
761 
762   return S_OK;
763 }
764 
765 extern HRESULT WINAPI OLEAUTPS_DllGetClassObject(REFCLSID, REFIID, LPVOID *) DECLSPEC_HIDDEN;
766 extern BOOL WINAPI OLEAUTPS_DllMain(HINSTANCE, DWORD, LPVOID) DECLSPEC_HIDDEN;
767 extern HRESULT WINAPI OLEAUTPS_DllRegisterServer(void) DECLSPEC_HIDDEN;
768 extern HRESULT WINAPI OLEAUTPS_DllUnregisterServer(void) DECLSPEC_HIDDEN;
769 
770 extern HRESULT WINAPI CreateProxyFromTypeInfo(ITypeInfo *typeinfo,
771         IUnknown *outer, REFIID iid, IRpcProxyBuffer **proxy, void **obj);
772 extern HRESULT WINAPI CreateStubFromTypeInfo(ITypeInfo *typeinfo, REFIID iid,
773         IUnknown *server, IRpcStubBuffer **stub);
774 
775 struct ifacepsredirect_data
776 {
777     ULONG size;
778     DWORD mask;
779     GUID  iid;
780     ULONG nummethods;
781     GUID  tlbid;
782     GUID  base;
783     ULONG name_len;
784     ULONG name_offset;
785 };
786 
787 struct tlibredirect_data
788 {
789     ULONG  size;
790     DWORD  res;
791     ULONG  name_len;
792     ULONG  name_offset;
793     LANGID langid;
794     WORD   flags;
795     ULONG  help_len;
796     ULONG  help_offset;
797     WORD   major_version;
798     WORD   minor_version;
799 };
800 
801 static BOOL actctx_get_typelib_module(REFIID iid, WCHAR *module, DWORD len)
802 {
803     struct ifacepsredirect_data *iface;
804     struct tlibredirect_data *tlib;
805     ACTCTX_SECTION_KEYED_DATA data;
806     WCHAR *ptrW;
807 
808     data.cbSize = sizeof(data);
809     if (!FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION,
810             iid, &data))
811         return FALSE;
812 
813     iface = (struct ifacepsredirect_data *)data.lpData;
814     if (!FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION,
815             &iface->tlbid, &data))
816         return FALSE;
817 
818     tlib = (struct tlibredirect_data *)data.lpData;
819     ptrW = (WCHAR *)((BYTE *)data.lpSectionBase + tlib->name_offset);
820 
821     if (tlib->name_len/sizeof(WCHAR) >= len)
822     {
823         ERR("need larger module buffer, %u\n", tlib->name_len);
824         return FALSE;
825     }
826 
827     memcpy(module, ptrW, tlib->name_len);
828     module[tlib->name_len/sizeof(WCHAR)] = 0;
829     return TRUE;
830 }
831 
832 static HRESULT reg_get_typelib_module(REFIID iid, WCHAR *module, DWORD len)
833 {
834     REGSAM opposite = (sizeof(void*) == 8) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
835     char tlguid[200], typelibkey[300], interfacekey[300], ver[100], tlfn[260];
836     DWORD tlguidlen, verlen, type;
837     LONG tlfnlen, err;
838     BOOL is_wow64;
839     HKEY ikey;
840 
841     sprintf( interfacekey, "Interface\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\Typelib",
842         iid->Data1, iid->Data2, iid->Data3,
843         iid->Data4[0], iid->Data4[1], iid->Data4[2], iid->Data4[3],
844         iid->Data4[4], iid->Data4[5], iid->Data4[6], iid->Data4[7]
845     );
846 
847     err = RegOpenKeyExA(HKEY_CLASSES_ROOT,interfacekey,0,KEY_READ,&ikey);
848     if (err && (opposite == KEY_WOW64_32KEY || (IsWow64Process(GetCurrentProcess(), &is_wow64)
849                                                 && is_wow64)))
850         err = RegOpenKeyExA(HKEY_CLASSES_ROOT,interfacekey,0,KEY_READ|opposite,&ikey);
851 
852     if (err)
853     {
854         ERR("No %s key found.\n", interfacekey);
855         return E_FAIL;
856     }
857 
858     tlguidlen = sizeof(tlguid);
859     if (RegQueryValueExA(ikey, NULL, NULL, &type, (BYTE *)tlguid, &tlguidlen))
860     {
861         ERR("Getting typelib guid failed.\n");
862         RegCloseKey(ikey);
863         return E_FAIL;
864     }
865 
866     verlen = sizeof(ver);
867     if (RegQueryValueExA(ikey, "Version", NULL, &type, (BYTE *)ver, &verlen))
868     {
869         ERR("Could not get version value?\n");
870         RegCloseKey(ikey);
871         return E_FAIL;
872     }
873 
874     RegCloseKey(ikey);
875 
876     sprintf(typelibkey, "Typelib\\%s\\%s\\0\\win%u", tlguid, ver, sizeof(void *) == 8 ? 64 : 32);
877     tlfnlen = sizeof(tlfn);
878     if (RegQueryValueA(HKEY_CLASSES_ROOT, typelibkey, tlfn, &tlfnlen))
879     {
880 #ifdef _WIN64
881         sprintf(typelibkey, "Typelib\\%s\\%s\\0\\win32", tlguid, ver);
882         tlfnlen = sizeof(tlfn);
883         if (RegQueryValueA(HKEY_CLASSES_ROOT, typelibkey, tlfn, &tlfnlen))
884         {
885 #endif
886             ERR("Could not get typelib fn?\n");
887             return E_FAIL;
888 #ifdef _WIN64
889         }
890 #endif
891     }
892     MultiByteToWideChar(CP_ACP, 0, tlfn, -1, module, len);
893     return S_OK;
894 }
895 
896 static HRESULT get_typeinfo_for_iid(REFIID iid, ITypeInfo **typeinfo)
897 {
898     WCHAR module[MAX_PATH];
899     ITypeLib *typelib;
900     HRESULT hr;
901 
902     *typeinfo = NULL;
903 
904     module[0] = 0;
905     if (!actctx_get_typelib_module(iid, module, ARRAY_SIZE(module)))
906     {
907         hr = reg_get_typelib_module(iid, module, ARRAY_SIZE(module));
908         if (FAILED(hr))
909             return hr;
910     }
911 
912     hr = LoadTypeLib(module, &typelib);
913     if (hr != S_OK) {
914         ERR("Failed to load typelib for %s, but it should be there.\n", debugstr_guid(iid));
915         return hr;
916     }
917 
918     hr = ITypeLib_GetTypeInfoOfGuid(typelib, iid, typeinfo);
919     ITypeLib_Release(typelib);
920     if (hr != S_OK)
921         ERR("typelib does not contain info for %s\n", debugstr_guid(iid));
922 
923     return hr;
924 }
925 
926 static HRESULT WINAPI typelib_ps_QueryInterface(IPSFactoryBuffer *iface, REFIID iid, void **out)
927 {
928     if (IsEqualIID(iid, &IID_IPSFactoryBuffer) || IsEqualIID(iid, &IID_IUnknown))
929     {
930         *out = iface;
931         return S_OK;
932     }
933 
934     FIXME("No interface for %s.\n", debugstr_guid(iid));
935     *out = NULL;
936     return E_NOINTERFACE;
937 }
938 
939 static ULONG WINAPI typelib_ps_AddRef(IPSFactoryBuffer *iface)
940 {
941     return 2;
942 }
943 
944 static ULONG WINAPI typelib_ps_Release(IPSFactoryBuffer *iface)
945 {
946     return 1;
947 }
948 
949 static HRESULT WINAPI typelib_ps_CreateProxy(IPSFactoryBuffer *iface,
950     IUnknown *outer, REFIID iid, IRpcProxyBuffer **proxy, void **out)
951 {
952     ITypeInfo *typeinfo;
953     HRESULT hr;
954 
955     hr = get_typeinfo_for_iid(iid, &typeinfo);
956     if (FAILED(hr)) return hr;
957 
958     hr = CreateProxyFromTypeInfo(typeinfo, outer, iid, proxy, out);
959     if (FAILED(hr))
960         ERR("Failed to create proxy, hr %#x.\n", hr);
961 
962     ITypeInfo_Release(typeinfo);
963     return hr;
964 }
965 
966 static HRESULT WINAPI typelib_ps_CreateStub(IPSFactoryBuffer *iface, REFIID iid,
967     IUnknown *server, IRpcStubBuffer **stub)
968 {
969     ITypeInfo *typeinfo;
970     HRESULT hr;
971 
972     hr = get_typeinfo_for_iid(iid, &typeinfo);
973     if (FAILED(hr)) return hr;
974 
975     hr = CreateStubFromTypeInfo(typeinfo, iid, server, stub);
976     if (FAILED(hr))
977         ERR("Failed to create stub, hr %#x.\n", hr);
978 
979     ITypeInfo_Release(typeinfo);
980     return hr;
981 }
982 
983 static const IPSFactoryBufferVtbl typelib_ps_vtbl =
984 {
985     typelib_ps_QueryInterface,
986     typelib_ps_AddRef,
987     typelib_ps_Release,
988     typelib_ps_CreateProxy,
989     typelib_ps_CreateStub,
990 };
991 
992 static IPSFactoryBuffer typelib_ps = { &typelib_ps_vtbl };
993 
994 extern void _get_STDFONT_CF(LPVOID *);
995 extern void _get_STDPIC_CF(LPVOID *);
996 
997 static HRESULT WINAPI PSDispatchFacBuf_QueryInterface(IPSFactoryBuffer *iface, REFIID riid, void **ppv)
998 {
999     if (IsEqualIID(riid, &IID_IUnknown) ||
1000         IsEqualIID(riid, &IID_IPSFactoryBuffer))
1001     {
1002         IPSFactoryBuffer_AddRef(iface);
1003         *ppv = iface;
1004         return S_OK;
1005     }
1006     return E_NOINTERFACE;
1007 }
1008 
1009 static ULONG WINAPI PSDispatchFacBuf_AddRef(IPSFactoryBuffer *iface)
1010 {
1011     return 2;
1012 }
1013 
1014 static ULONG WINAPI PSDispatchFacBuf_Release(IPSFactoryBuffer *iface)
1015 {
1016     return 1;
1017 }
1018 
1019 static HRESULT WINAPI PSDispatchFacBuf_CreateProxy(IPSFactoryBuffer *iface,
1020     IUnknown *outer, REFIID iid, IRpcProxyBuffer **proxy, void **obj)
1021 {
1022     IPSFactoryBuffer *factory;
1023     HRESULT hr;
1024 
1025     if (IsEqualIID(iid, &IID_IDispatch))
1026     {
1027         hr = OLEAUTPS_DllGetClassObject(&CLSID_PSFactoryBuffer, &IID_IPSFactoryBuffer, (void **)&factory);
1028         if (FAILED(hr)) return hr;
1029 
1030         hr = IPSFactoryBuffer_CreateProxy(factory, outer, iid, proxy, obj);
1031         IPSFactoryBuffer_Release(factory);
1032         return hr;
1033     }
1034     else
1035         return IPSFactoryBuffer_CreateProxy(&typelib_ps, outer, iid, proxy, obj);
1036 }
1037 
1038 static HRESULT WINAPI PSDispatchFacBuf_CreateStub(IPSFactoryBuffer *iface,
1039     REFIID iid, IUnknown *server, IRpcStubBuffer **stub)
1040 {
1041     IPSFactoryBuffer *factory;
1042     HRESULT hr;
1043 
1044     if (IsEqualIID(iid, &IID_IDispatch))
1045     {
1046         hr = OLEAUTPS_DllGetClassObject(&CLSID_PSFactoryBuffer, &IID_IPSFactoryBuffer, (void **)&factory);
1047         if (FAILED(hr)) return hr;
1048 
1049         hr = IPSFactoryBuffer_CreateStub(factory, iid, server, stub);
1050         IPSFactoryBuffer_Release(factory);
1051         return hr;
1052     }
1053     else
1054         return IPSFactoryBuffer_CreateStub(&typelib_ps, iid, server, stub);
1055 }
1056 
1057 static const IPSFactoryBufferVtbl PSDispatchFacBuf_Vtbl =
1058 {
1059     PSDispatchFacBuf_QueryInterface,
1060     PSDispatchFacBuf_AddRef,
1061     PSDispatchFacBuf_Release,
1062     PSDispatchFacBuf_CreateProxy,
1063     PSDispatchFacBuf_CreateStub
1064 };
1065 
1066 /* This is the whole PSFactoryBuffer object, just the vtableptr */
1067 static const IPSFactoryBufferVtbl *pPSDispatchFacBuf = &PSDispatchFacBuf_Vtbl;
1068 
1069 /***********************************************************************
1070  *		DllGetClassObject (OLEAUT32.@)
1071  */
1072 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
1073 {
1074     *ppv = NULL;
1075     if (IsEqualGUID(rclsid,&CLSID_StdFont)) {
1076 	if (IsEqualGUID(iid,&IID_IClassFactory)) {
1077 	    _get_STDFONT_CF(ppv);
1078 	    IClassFactory_AddRef((IClassFactory*)*ppv);
1079 	    return S_OK;
1080 	}
1081     }
1082     if (IsEqualGUID(rclsid,&CLSID_StdPicture)) {
1083 	if (IsEqualGUID(iid,&IID_IClassFactory)) {
1084 	    _get_STDPIC_CF(ppv);
1085 	    IClassFactory_AddRef((IClassFactory*)*ppv);
1086 	    return S_OK;
1087 	}
1088     }
1089     if (IsEqualCLSID(rclsid, &CLSID_PSDispatch) && IsEqualIID(iid, &IID_IPSFactoryBuffer)) {
1090         *ppv = &pPSDispatchFacBuf;
1091         IPSFactoryBuffer_AddRef((IPSFactoryBuffer *)*ppv);
1092         return S_OK;
1093     }
1094 
1095     if (IsEqualGUID(rclsid, &CLSID_PSOAInterface))
1096         return IPSFactoryBuffer_QueryInterface(&typelib_ps, iid, ppv);
1097 
1098     if (IsEqualCLSID(rclsid, &CLSID_PSTypeComp) ||
1099         IsEqualCLSID(rclsid, &CLSID_PSTypeInfo) ||
1100         IsEqualCLSID(rclsid, &CLSID_PSTypeLib) ||
1101         IsEqualCLSID(rclsid, &CLSID_PSDispatch) ||
1102         IsEqualCLSID(rclsid, &CLSID_PSEnumVariant))
1103         return OLEAUTPS_DllGetClassObject(&CLSID_PSFactoryBuffer, iid, ppv);
1104 
1105     return OLEAUTPS_DllGetClassObject(rclsid, iid, ppv);
1106 }
1107 
1108 /***********************************************************************
1109  *		DllCanUnloadNow (OLEAUT32.@)
1110  *
1111  * Determine if this dll can be unloaded from the callers address space.
1112  *
1113  * PARAMS
1114  *  None.
1115  *
1116  * RETURNS
1117  *  Always returns S_FALSE. This dll cannot be unloaded.
1118  */
1119 HRESULT WINAPI DllCanUnloadNow(void)
1120 {
1121     return S_FALSE;
1122 }
1123 
1124 /*****************************************************************************
1125  *              DllMain         [OLEAUT32.@]
1126  */
1127 BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD fdwReason, LPVOID lpvReserved)
1128 {
1129     static const WCHAR oanocacheW[] = {'o','a','n','o','c','a','c','h','e',0};
1130 
1131     if(fdwReason == DLL_PROCESS_ATTACH)
1132         bstr_cache_enabled = !GetEnvironmentVariableW(oanocacheW, NULL, 0);
1133 
1134     return OLEAUTPS_DllMain( hInstDll, fdwReason, lpvReserved );
1135 }
1136 
1137 /***********************************************************************
1138  *		DllRegisterServer (OLEAUT32.@)
1139  */
1140 HRESULT WINAPI DllRegisterServer(void)
1141 {
1142     return OLEAUTPS_DllRegisterServer();
1143 }
1144 
1145 /***********************************************************************
1146  *		DllUnregisterServer (OLEAUT32.@)
1147  */
1148 HRESULT WINAPI DllUnregisterServer(void)
1149 {
1150     return OLEAUTPS_DllUnregisterServer();
1151 }
1152 
1153 /***********************************************************************
1154  *              OleIconToCursor (OLEAUT32.415)
1155  */
1156 HCURSOR WINAPI OleIconToCursor( HINSTANCE hinstExe, HICON hIcon)
1157 {
1158     FIXME("(%p,%p), partially implemented.\n",hinstExe,hIcon);
1159     /* FIXME: make an extended conversation from HICON to HCURSOR */
1160     return CopyCursor(hIcon);
1161 }
1162 
1163 /***********************************************************************
1164  *              GetAltMonthNames (OLEAUT32.@)
1165  */
1166 HRESULT WINAPI GetAltMonthNames(LCID lcid, LPOLESTR **str)
1167 {
1168     static const WCHAR ar_month1W[] = {0x645,0x62d,0x631,0x645,0};
1169     static const WCHAR ar_month2W[] = {0x635,0x641,0x631,0};
1170     static const WCHAR ar_month3W[] = {0x631,0x628,0x64a,0x639,' ',0x627,0x644,0x627,0x648,0x644,0};
1171     static const WCHAR ar_month4W[] = {0x631,0x628,0x64a,0x639,' ',0x627,0x644,0x62b,0x627,0x646,0x64a,0};
1172     static const WCHAR ar_month5W[] = {0x62c,0x645,0x627,0x62f,0x649,' ',0x627,0x644,0x627,0x648,0x644,0x649,0};
1173     static const WCHAR ar_month6W[] = {0x62c,0x645,0x627,0x62f,0x649,' ',0x627,0x644,0x62b,0x627,0x646,0x64a,0x629,0};
1174     static const WCHAR ar_month7W[] = {0x631,0x62c,0x628,0};
1175     static const WCHAR ar_month8W[] = {0x634,0x639,0x628,0x627,0x646,0};
1176     static const WCHAR ar_month9W[] = {0x631,0x645,0x636,0x627,0x646,0};
1177     static const WCHAR ar_month10W[] = {0x634,0x648,0x627,0x643,0};
1178     static const WCHAR ar_month11W[] = {0x630,0x648,' ',0x627,0x644,0x642,0x639,0x62f,0x629,0};
1179     static const WCHAR ar_month12W[] = {0x630,0x648,' ',0x627,0x644,0x62d,0x62c,0x629,0};
1180 
1181     static const WCHAR *arabic_hijri[] =
1182     {
1183         ar_month1W,
1184         ar_month2W,
1185         ar_month3W,
1186         ar_month4W,
1187         ar_month5W,
1188         ar_month6W,
1189         ar_month7W,
1190         ar_month8W,
1191         ar_month9W,
1192         ar_month10W,
1193         ar_month11W,
1194         ar_month12W,
1195         NULL
1196     };
1197 
1198     static const WCHAR pl_month1W[] = {'s','t','y','c','z','n','i','a',0};
1199     static const WCHAR pl_month2W[] = {'l','u','t','e','g','o',0};
1200     static const WCHAR pl_month3W[] = {'m','a','r','c','a',0};
1201     static const WCHAR pl_month4W[] = {'k','w','i','e','t','n','i','a',0};
1202     static const WCHAR pl_month5W[] = {'m','a','j','a',0};
1203     static const WCHAR pl_month6W[] = {'c','z','e','r','w','c','a',0};
1204     static const WCHAR pl_month7W[] = {'l','i','p','c','a',0};
1205     static const WCHAR pl_month8W[] = {'s','i','e','r','p','n','i','a',0};
1206     static const WCHAR pl_month9W[] = {'w','r','z','e',0x15b,'n','i','a',0};
1207     static const WCHAR pl_month10W[] = {'p','a',0x17a,'d','z','i','e','r','n','i','k','a',0};
1208     static const WCHAR pl_month11W[] = {'l','i','s','t','o','p','a','d','a',0};
1209     static const WCHAR pl_month12W[] = {'g','r','u','d','n','i','a',0};
1210 
1211     static const WCHAR *polish_genitive_names[] =
1212     {
1213         pl_month1W,
1214         pl_month2W,
1215         pl_month3W,
1216         pl_month4W,
1217         pl_month5W,
1218         pl_month6W,
1219         pl_month7W,
1220         pl_month8W,
1221         pl_month9W,
1222         pl_month10W,
1223         pl_month11W,
1224         pl_month12W,
1225         NULL
1226     };
1227 
1228     static const WCHAR ru_month1W[] = {0x44f,0x43d,0x432,0x430,0x440,0x44f,0};
1229     static const WCHAR ru_month2W[] = {0x444,0x435,0x432,0x440,0x430,0x43b,0x44f,0};
1230     static const WCHAR ru_month3W[] = {0x43c,0x430,0x440,0x442,0x430,0};
1231     static const WCHAR ru_month4W[] = {0x430,0x43f,0x440,0x435,0x43b,0x44f,0};
1232     static const WCHAR ru_month5W[] = {0x43c,0x430,0x44f,0};
1233     static const WCHAR ru_month6W[] = {0x438,0x44e,0x43d,0x44f,0};
1234     static const WCHAR ru_month7W[] = {0x438,0x44e,0x43b,0x44f,0};
1235     static const WCHAR ru_month8W[] = {0x430,0x432,0x433,0x443,0x441,0x442,0x430,0};
1236     static const WCHAR ru_month9W[] = {0x441,0x435,0x43d,0x442,0x44f,0x431,0x440,0x44f,0};
1237     static const WCHAR ru_month10W[] = {0x43e,0x43a,0x442,0x44f,0x431,0x440,0x44f,0};
1238     static const WCHAR ru_month11W[] = {0x43d,0x43e,0x44f,0x431,0x440,0x44f,0};
1239     static const WCHAR ru_month12W[] = {0x434,0x435,0x43a,0x430,0x431,0x440,0x44f,0};
1240 
1241     static const WCHAR *russian_genitive_names[] =
1242     {
1243         ru_month1W,
1244         ru_month2W,
1245         ru_month3W,
1246         ru_month4W,
1247         ru_month5W,
1248         ru_month6W,
1249         ru_month7W,
1250         ru_month8W,
1251         ru_month9W,
1252         ru_month10W,
1253         ru_month11W,
1254         ru_month12W,
1255         NULL
1256     };
1257 
1258     TRACE("%#x, %p\n", lcid, str);
1259 
1260     if (PRIMARYLANGID(LANGIDFROMLCID(lcid)) == LANG_ARABIC)
1261         *str = (LPOLESTR *)arabic_hijri;
1262     else if (PRIMARYLANGID(LANGIDFROMLCID(lcid)) == LANG_POLISH)
1263         *str = (LPOLESTR *)polish_genitive_names;
1264     else if (PRIMARYLANGID(LANGIDFROMLCID(lcid)) == LANG_RUSSIAN)
1265         *str = (LPOLESTR *)russian_genitive_names;
1266     else
1267         *str = NULL;
1268 
1269     return S_OK;
1270 }
1271