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