xref: /reactos/dll/win32/oleaut32/oleaut.c (revision f986527d)
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 
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 
116 static inline bstr_t *bstr_from_str(BSTR str)
117 {
118     return CONTAINING_RECORD((void *)str, bstr_t, u.str);
119 }
120 
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 
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 
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 
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  */
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  */
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  */
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 
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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     case 0x00000006:  /* Vista */
664     case 0x00000106:  /* Win7 */
665 		return MAKELONG(0xffff, 50);
666     default:
667 		FIXME("Version value not known yet. Please investigate it !\n");
668 		return MAKELONG(0xffff, 40);  /* for now return the same value as for w2k */
669     }
670 }
671 
672 /******************************************************************************
673  *		OleTranslateColor	[OLEAUT32.421]
674  *
675  * Convert an OLE_COLOR to a COLORREF.
676  *
677  * PARAMS
678  *  clr       [I] Color to convert
679  *  hpal      [I] Handle to a palette for the conversion
680  *  pColorRef [O] Destination for converted color, or NULL to test if the conversion is ok
681  *
682  * RETURNS
683  *  Success: S_OK. The conversion is ok, and pColorRef contains the converted color if non-NULL.
684  *  Failure: E_INVALIDARG, if any argument is invalid.
685  *
686  * FIXME
687  *  Document the conversion rules.
688  */
689 HRESULT WINAPI OleTranslateColor(
690   OLE_COLOR clr,
691   HPALETTE  hpal,
692   COLORREF* pColorRef)
693 {
694   COLORREF colorref;
695   BYTE b = HIBYTE(HIWORD(clr));
696 
697   TRACE("(%08x, %p, %p)\n", clr, hpal, pColorRef);
698 
699   /*
700    * In case pColorRef is NULL, provide our own to simplify the code.
701    */
702   if (pColorRef == NULL)
703     pColorRef = &colorref;
704 
705   switch (b)
706   {
707     case 0x00:
708     {
709       if (hpal != 0)
710         *pColorRef =  PALETTERGB(GetRValue(clr),
711                                  GetGValue(clr),
712                                  GetBValue(clr));
713       else
714         *pColorRef = clr;
715 
716       break;
717     }
718 
719     case 0x01:
720     {
721       if (hpal != 0)
722       {
723         PALETTEENTRY pe;
724         /*
725          * Validate the palette index.
726          */
727         if (GetPaletteEntries(hpal, LOWORD(clr), 1, &pe) == 0)
728           return E_INVALIDARG;
729       }
730 
731       *pColorRef = clr;
732 
733       break;
734     }
735 
736     case 0x02:
737       *pColorRef = clr;
738       break;
739 
740     case 0x80:
741     {
742       int index = LOBYTE(LOWORD(clr));
743 
744       /*
745        * Validate GetSysColor index.
746        */
747       if ((index < COLOR_SCROLLBAR) || (index > COLOR_MENUBAR))
748         return E_INVALIDARG;
749 
750       *pColorRef =  GetSysColor(index);
751 
752       break;
753     }
754 
755     default:
756       return E_INVALIDARG;
757   }
758 
759   return S_OK;
760 }
761 
762 extern HRESULT WINAPI OLEAUTPS_DllGetClassObject(REFCLSID, REFIID, LPVOID *) DECLSPEC_HIDDEN;
763 extern BOOL WINAPI OLEAUTPS_DllMain(HINSTANCE, DWORD, LPVOID) DECLSPEC_HIDDEN;
764 extern HRESULT WINAPI OLEAUTPS_DllRegisterServer(void) DECLSPEC_HIDDEN;
765 extern HRESULT WINAPI OLEAUTPS_DllUnregisterServer(void) DECLSPEC_HIDDEN;
766 
767 extern HRESULT WINAPI CreateProxyFromTypeInfo(ITypeInfo *typeinfo,
768         IUnknown *outer, REFIID iid, IRpcProxyBuffer **proxy, void **obj);
769 extern HRESULT WINAPI CreateStubFromTypeInfo(ITypeInfo *typeinfo, REFIID iid,
770         IUnknown *server, IRpcStubBuffer **stub);
771 
772 struct ifacepsredirect_data
773 {
774     ULONG size;
775     DWORD mask;
776     GUID  iid;
777     ULONG nummethods;
778     GUID  tlbid;
779     GUID  base;
780     ULONG name_len;
781     ULONG name_offset;
782 };
783 
784 struct tlibredirect_data
785 {
786     ULONG  size;
787     DWORD  res;
788     ULONG  name_len;
789     ULONG  name_offset;
790     LANGID langid;
791     WORD   flags;
792     ULONG  help_len;
793     ULONG  help_offset;
794     WORD   major_version;
795     WORD   minor_version;
796 };
797 
798 static BOOL actctx_get_typelib_module(REFIID iid, WCHAR *module, DWORD len)
799 {
800     struct ifacepsredirect_data *iface;
801     struct tlibredirect_data *tlib;
802     ACTCTX_SECTION_KEYED_DATA data;
803     WCHAR *ptrW;
804 
805     data.cbSize = sizeof(data);
806     if (!FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION,
807             iid, &data))
808         return FALSE;
809 
810     iface = (struct ifacepsredirect_data *)data.lpData;
811     if (!FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION,
812             &iface->tlbid, &data))
813         return FALSE;
814 
815     tlib = (struct tlibredirect_data *)data.lpData;
816     ptrW = (WCHAR *)((BYTE *)data.lpSectionBase + tlib->name_offset);
817 
818     if (tlib->name_len/sizeof(WCHAR) >= len)
819     {
820         ERR("need larger module buffer, %u\n", tlib->name_len);
821         return FALSE;
822     }
823 
824     memcpy(module, ptrW, tlib->name_len);
825     module[tlib->name_len/sizeof(WCHAR)] = 0;
826     return TRUE;
827 }
828 
829 static HRESULT reg_get_typelib_module(REFIID iid, WCHAR *module, DWORD len)
830 {
831     REGSAM opposite = (sizeof(void*) == 8) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
832     char tlguid[200], typelibkey[300], interfacekey[300], ver[100], tlfn[260];
833     DWORD tlguidlen, verlen, type;
834     LONG tlfnlen, err;
835     BOOL is_wow64;
836     HKEY ikey;
837 
838     sprintf( interfacekey, "Interface\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\Typelib",
839         iid->Data1, iid->Data2, iid->Data3,
840         iid->Data4[0], iid->Data4[1], iid->Data4[2], iid->Data4[3],
841         iid->Data4[4], iid->Data4[5], iid->Data4[6], iid->Data4[7]
842     );
843 
844     err = RegOpenKeyExA(HKEY_CLASSES_ROOT,interfacekey,0,KEY_READ,&ikey);
845     if (err && (opposite == KEY_WOW64_32KEY || (IsWow64Process(GetCurrentProcess(), &is_wow64)
846                                                 && is_wow64)))
847         err = RegOpenKeyExA(HKEY_CLASSES_ROOT,interfacekey,0,KEY_READ|opposite,&ikey);
848 
849     if (err)
850     {
851         ERR("No %s key found.\n", interfacekey);
852         return E_FAIL;
853     }
854 
855     tlguidlen = sizeof(tlguid);
856     if (RegQueryValueExA(ikey, NULL, NULL, &type, (BYTE *)tlguid, &tlguidlen))
857     {
858         ERR("Getting typelib guid failed.\n");
859         RegCloseKey(ikey);
860         return E_FAIL;
861     }
862 
863     verlen = sizeof(ver);
864     if (RegQueryValueExA(ikey, "Version", NULL, &type, (BYTE *)ver, &verlen))
865     {
866         ERR("Could not get version value?\n");
867         RegCloseKey(ikey);
868         return E_FAIL;
869     }
870 
871     RegCloseKey(ikey);
872 
873 #ifndef __REACTOS__
874     sprintf(typelibkey, "Typelib\\%s\\%s\\0\\win%u", tlguid, ver, sizeof(void *) == 8 ? 64 : 32);
875 #else
876     snprintf(typelibkey, sizeof(typelibkey), "Typelib\\%s\\%s\\0\\win%u", tlguid, ver, sizeof(void *) == 8 ? 64 : 32);
877 #endif /* __REACTOS__ */
878     tlfnlen = sizeof(tlfn);
879     if (RegQueryValueA(HKEY_CLASSES_ROOT, typelibkey, tlfn, &tlfnlen))
880     {
881 #ifdef _WIN64
882         sprintf(typelibkey, "Typelib\\%s\\%s\\0\\win32", tlguid, ver);
883         tlfnlen = sizeof(tlfn);
884         if (RegQueryValueA(HKEY_CLASSES_ROOT, typelibkey, tlfn, &tlfnlen))
885         {
886 #endif
887             ERR("Could not get typelib fn?\n");
888             return E_FAIL;
889 #ifdef _WIN64
890         }
891 #endif
892     }
893     MultiByteToWideChar(CP_ACP, 0, tlfn, -1, module, len);
894     return S_OK;
895 }
896 
897 static HRESULT get_typeinfo_for_iid(REFIID iid, ITypeInfo **typeinfo)
898 {
899     WCHAR module[MAX_PATH];
900     ITypeLib *typelib;
901     HRESULT hr;
902 
903     *typeinfo = NULL;
904 
905     module[0] = 0;
906     if (!actctx_get_typelib_module(iid, module, ARRAY_SIZE(module)))
907     {
908         hr = reg_get_typelib_module(iid, module, ARRAY_SIZE(module));
909         if (FAILED(hr))
910             return hr;
911     }
912 
913     hr = LoadTypeLib(module, &typelib);
914     if (hr != S_OK) {
915         ERR("Failed to load typelib for %s, but it should be there.\n", debugstr_guid(iid));
916         return hr;
917     }
918 
919     hr = ITypeLib_GetTypeInfoOfGuid(typelib, iid, typeinfo);
920     ITypeLib_Release(typelib);
921     if (hr != S_OK)
922         ERR("typelib does not contain info for %s\n", debugstr_guid(iid));
923 
924     return hr;
925 }
926 
927 static HRESULT WINAPI dispatch_typelib_ps_QueryInterface(IPSFactoryBuffer *iface, REFIID iid, void **out)
928 {
929     if (IsEqualIID(iid, &IID_IPSFactoryBuffer) || IsEqualIID(iid, &IID_IUnknown))
930     {
931         *out = iface;
932         return S_OK;
933     }
934 
935     FIXME("No interface for %s.\n", debugstr_guid(iid));
936     *out = NULL;
937     return E_NOINTERFACE;
938 }
939 
940 static ULONG WINAPI dispatch_typelib_ps_AddRef(IPSFactoryBuffer *iface)
941 {
942     return 2;
943 }
944 
945 static ULONG WINAPI dispatch_typelib_ps_Release(IPSFactoryBuffer *iface)
946 {
947     return 1;
948 }
949 
950 static HRESULT dispatch_create_proxy(IUnknown *outer, IRpcProxyBuffer **proxy, void **out)
951 {
952     IPSFactoryBuffer *factory;
953     HRESULT hr;
954 
955     hr = OLEAUTPS_DllGetClassObject(&CLSID_PSFactoryBuffer, &IID_IPSFactoryBuffer, (void **)&factory);
956     if (FAILED(hr)) return hr;
957 
958     hr = IPSFactoryBuffer_CreateProxy(factory, outer, &IID_IDispatch, proxy, out);
959     IPSFactoryBuffer_Release(factory);
960     return hr;
961 }
962 
963 static HRESULT WINAPI dispatch_typelib_ps_CreateProxy(IPSFactoryBuffer *iface,
964     IUnknown *outer, REFIID iid, IRpcProxyBuffer **proxy, void **out)
965 {
966     ITypeInfo *typeinfo;
967     TYPEATTR *attr;
968     HRESULT hr;
969 
970     if (IsEqualGUID(iid, &IID_IDispatch))
971         return dispatch_create_proxy(outer, proxy, out);
972 
973     hr = get_typeinfo_for_iid(iid, &typeinfo);
974     if (FAILED(hr)) return hr;
975 
976     hr = ITypeInfo_GetTypeAttr(typeinfo, &attr);
977     if (FAILED(hr))
978     {
979         ITypeInfo_Release(typeinfo);
980         return hr;
981     }
982 
983     if (attr->typekind == TKIND_INTERFACE || (attr->wTypeFlags & TYPEFLAG_FDUAL))
984         hr = CreateProxyFromTypeInfo(typeinfo, outer, iid, proxy, out);
985     else
986         hr = dispatch_create_proxy(outer, proxy, out);
987 
988     if (FAILED(hr))
989         ERR("Failed to create proxy, hr %#x.\n", hr);
990 
991     ITypeInfo_ReleaseTypeAttr(typeinfo, attr);
992     ITypeInfo_Release(typeinfo);
993     return hr;
994 }
995 
996 static HRESULT dispatch_create_stub(IUnknown *server, IRpcStubBuffer **stub)
997 {
998     IPSFactoryBuffer *factory;
999     HRESULT hr;
1000 
1001     hr = OLEAUTPS_DllGetClassObject(&CLSID_PSFactoryBuffer, &IID_IPSFactoryBuffer, (void **)&factory);
1002     if (FAILED(hr)) return hr;
1003 
1004     hr = IPSFactoryBuffer_CreateStub(factory, &IID_IDispatch, server, stub);
1005     IPSFactoryBuffer_Release(factory);
1006     return hr;
1007 }
1008 
1009 static HRESULT WINAPI dispatch_typelib_ps_CreateStub(IPSFactoryBuffer *iface,
1010     REFIID iid, IUnknown *server, IRpcStubBuffer **stub)
1011 {
1012     ITypeInfo *typeinfo;
1013     TYPEATTR *attr;
1014     HRESULT hr;
1015 
1016     if (IsEqualGUID(iid, &IID_IDispatch))
1017         return dispatch_create_stub(server, stub);
1018 
1019     hr = get_typeinfo_for_iid(iid, &typeinfo);
1020     if (FAILED(hr)) return hr;
1021 
1022     hr = ITypeInfo_GetTypeAttr(typeinfo, &attr);
1023     if (FAILED(hr))
1024     {
1025         ITypeInfo_Release(typeinfo);
1026         return hr;
1027     }
1028 
1029     if (attr->typekind == TKIND_INTERFACE || (attr->wTypeFlags & TYPEFLAG_FDUAL))
1030         hr = CreateStubFromTypeInfo(typeinfo, iid, server, stub);
1031     else
1032         hr = dispatch_create_stub(server, stub);
1033 
1034     if (FAILED(hr))
1035         ERR("Failed to create proxy, hr %#x.\n", hr);
1036 
1037     ITypeInfo_ReleaseTypeAttr(typeinfo, attr);
1038     ITypeInfo_Release(typeinfo);
1039     return hr;
1040 }
1041 
1042 static const IPSFactoryBufferVtbl dispatch_typelib_ps_vtbl =
1043 {
1044     dispatch_typelib_ps_QueryInterface,
1045     dispatch_typelib_ps_AddRef,
1046     dispatch_typelib_ps_Release,
1047     dispatch_typelib_ps_CreateProxy,
1048     dispatch_typelib_ps_CreateStub,
1049 };
1050 
1051 static IPSFactoryBuffer dispatch_typelib_ps = { &dispatch_typelib_ps_vtbl };
1052 
1053 extern void _get_STDFONT_CF(LPVOID *);
1054 extern void _get_STDPIC_CF(LPVOID *);
1055 
1056 /***********************************************************************
1057  *		DllGetClassObject (OLEAUT32.@)
1058  */
1059 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
1060 {
1061     *ppv = NULL;
1062     if (IsEqualGUID(rclsid,&CLSID_StdFont)) {
1063 	if (IsEqualGUID(iid,&IID_IClassFactory)) {
1064 	    _get_STDFONT_CF(ppv);
1065 	    IClassFactory_AddRef((IClassFactory*)*ppv);
1066 	    return S_OK;
1067 	}
1068     }
1069     if (IsEqualGUID(rclsid,&CLSID_StdPicture)) {
1070 	if (IsEqualGUID(iid,&IID_IClassFactory)) {
1071 	    _get_STDPIC_CF(ppv);
1072 	    IClassFactory_AddRef((IClassFactory*)*ppv);
1073 	    return S_OK;
1074 	}
1075     }
1076 
1077     if (IsEqualGUID(rclsid, &CLSID_PSDispatch) || IsEqualGUID(rclsid, &CLSID_PSOAInterface))
1078         return IPSFactoryBuffer_QueryInterface(&dispatch_typelib_ps, iid, ppv);
1079 
1080     if (IsEqualCLSID(rclsid, &CLSID_PSTypeComp) ||
1081         IsEqualCLSID(rclsid, &CLSID_PSTypeInfo) ||
1082         IsEqualCLSID(rclsid, &CLSID_PSTypeLib) ||
1083         IsEqualCLSID(rclsid, &CLSID_PSDispatch) ||
1084         IsEqualCLSID(rclsid, &CLSID_PSEnumVariant))
1085         return OLEAUTPS_DllGetClassObject(&CLSID_PSFactoryBuffer, iid, ppv);
1086 
1087     return OLEAUTPS_DllGetClassObject(rclsid, iid, ppv);
1088 }
1089 
1090 /***********************************************************************
1091  *		DllCanUnloadNow (OLEAUT32.@)
1092  *
1093  * Determine if this dll can be unloaded from the callers address space.
1094  *
1095  * PARAMS
1096  *  None.
1097  *
1098  * RETURNS
1099  *  Always returns S_FALSE. This dll cannot be unloaded.
1100  */
1101 HRESULT WINAPI DllCanUnloadNow(void)
1102 {
1103     return S_FALSE;
1104 }
1105 
1106 /*****************************************************************************
1107  *              DllMain         [OLEAUT32.@]
1108  */
1109 BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD fdwReason, LPVOID lpvReserved)
1110 {
1111     static const WCHAR oanocacheW[] = {'o','a','n','o','c','a','c','h','e',0};
1112 
1113     if(fdwReason == DLL_PROCESS_ATTACH)
1114         bstr_cache_enabled = !GetEnvironmentVariableW(oanocacheW, NULL, 0);
1115 
1116     return OLEAUTPS_DllMain( hInstDll, fdwReason, lpvReserved );
1117 }
1118 
1119 /***********************************************************************
1120  *		DllRegisterServer (OLEAUT32.@)
1121  */
1122 HRESULT WINAPI DllRegisterServer(void)
1123 {
1124     return OLEAUTPS_DllRegisterServer();
1125 }
1126 
1127 /***********************************************************************
1128  *		DllUnregisterServer (OLEAUT32.@)
1129  */
1130 HRESULT WINAPI DllUnregisterServer(void)
1131 {
1132     return OLEAUTPS_DllUnregisterServer();
1133 }
1134 
1135 /***********************************************************************
1136  *              OleIconToCursor (OLEAUT32.415)
1137  */
1138 HCURSOR WINAPI OleIconToCursor( HINSTANCE hinstExe, HICON hIcon)
1139 {
1140     FIXME("(%p,%p), partially implemented.\n",hinstExe,hIcon);
1141     /* FIXME: make an extended conversation from HICON to HCURSOR */
1142     return CopyCursor(hIcon);
1143 }
1144 
1145 /***********************************************************************
1146  *              GetAltMonthNames (OLEAUT32.@)
1147  */
1148 HRESULT WINAPI GetAltMonthNames(LCID lcid, LPOLESTR **str)
1149 {
1150     static const WCHAR ar_month1W[] = {0x645,0x62d,0x631,0x645,0};
1151     static const WCHAR ar_month2W[] = {0x635,0x641,0x631,0};
1152     static const WCHAR ar_month3W[] = {0x631,0x628,0x64a,0x639,' ',0x627,0x644,0x627,0x648,0x644,0};
1153     static const WCHAR ar_month4W[] = {0x631,0x628,0x64a,0x639,' ',0x627,0x644,0x62b,0x627,0x646,0x64a,0};
1154     static const WCHAR ar_month5W[] = {0x62c,0x645,0x627,0x62f,0x649,' ',0x627,0x644,0x627,0x648,0x644,0x649,0};
1155     static const WCHAR ar_month6W[] = {0x62c,0x645,0x627,0x62f,0x649,' ',0x627,0x644,0x62b,0x627,0x646,0x64a,0x629,0};
1156     static const WCHAR ar_month7W[] = {0x631,0x62c,0x628,0};
1157     static const WCHAR ar_month8W[] = {0x634,0x639,0x628,0x627,0x646,0};
1158     static const WCHAR ar_month9W[] = {0x631,0x645,0x636,0x627,0x646,0};
1159     static const WCHAR ar_month10W[] = {0x634,0x648,0x627,0x643,0};
1160     static const WCHAR ar_month11W[] = {0x630,0x648,' ',0x627,0x644,0x642,0x639,0x62f,0x629,0};
1161     static const WCHAR ar_month12W[] = {0x630,0x648,' ',0x627,0x644,0x62d,0x62c,0x629,0};
1162 
1163     static const WCHAR *arabic_hijri[] =
1164     {
1165         ar_month1W,
1166         ar_month2W,
1167         ar_month3W,
1168         ar_month4W,
1169         ar_month5W,
1170         ar_month6W,
1171         ar_month7W,
1172         ar_month8W,
1173         ar_month9W,
1174         ar_month10W,
1175         ar_month11W,
1176         ar_month12W,
1177         NULL
1178     };
1179 
1180     static const WCHAR pl_month1W[] = {'s','t','y','c','z','n','i','a',0};
1181     static const WCHAR pl_month2W[] = {'l','u','t','e','g','o',0};
1182     static const WCHAR pl_month3W[] = {'m','a','r','c','a',0};
1183     static const WCHAR pl_month4W[] = {'k','w','i','e','t','n','i','a',0};
1184     static const WCHAR pl_month5W[] = {'m','a','j','a',0};
1185     static const WCHAR pl_month6W[] = {'c','z','e','r','w','c','a',0};
1186     static const WCHAR pl_month7W[] = {'l','i','p','c','a',0};
1187     static const WCHAR pl_month8W[] = {'s','i','e','r','p','n','i','a',0};
1188     static const WCHAR pl_month9W[] = {'w','r','z','e',0x15b,'n','i','a',0};
1189     static const WCHAR pl_month10W[] = {'p','a',0x17a,'d','z','i','e','r','n','i','k','a',0};
1190     static const WCHAR pl_month11W[] = {'l','i','s','t','o','p','a','d','a',0};
1191     static const WCHAR pl_month12W[] = {'g','r','u','d','n','i','a',0};
1192 
1193     static const WCHAR *polish_genitive_names[] =
1194     {
1195         pl_month1W,
1196         pl_month2W,
1197         pl_month3W,
1198         pl_month4W,
1199         pl_month5W,
1200         pl_month6W,
1201         pl_month7W,
1202         pl_month8W,
1203         pl_month9W,
1204         pl_month10W,
1205         pl_month11W,
1206         pl_month12W,
1207         NULL
1208     };
1209 
1210     static const WCHAR ru_month1W[] = {0x44f,0x43d,0x432,0x430,0x440,0x44f,0};
1211     static const WCHAR ru_month2W[] = {0x444,0x435,0x432,0x440,0x430,0x43b,0x44f,0};
1212     static const WCHAR ru_month3W[] = {0x43c,0x430,0x440,0x442,0x430,0};
1213     static const WCHAR ru_month4W[] = {0x430,0x43f,0x440,0x435,0x43b,0x44f,0};
1214     static const WCHAR ru_month5W[] = {0x43c,0x430,0x44f,0};
1215     static const WCHAR ru_month6W[] = {0x438,0x44e,0x43d,0x44f,0};
1216     static const WCHAR ru_month7W[] = {0x438,0x44e,0x43b,0x44f,0};
1217     static const WCHAR ru_month8W[] = {0x430,0x432,0x433,0x443,0x441,0x442,0x430,0};
1218     static const WCHAR ru_month9W[] = {0x441,0x435,0x43d,0x442,0x44f,0x431,0x440,0x44f,0};
1219     static const WCHAR ru_month10W[] = {0x43e,0x43a,0x442,0x44f,0x431,0x440,0x44f,0};
1220     static const WCHAR ru_month11W[] = {0x43d,0x43e,0x44f,0x431,0x440,0x44f,0};
1221     static const WCHAR ru_month12W[] = {0x434,0x435,0x43a,0x430,0x431,0x440,0x44f,0};
1222 
1223     static const WCHAR *russian_genitive_names[] =
1224     {
1225         ru_month1W,
1226         ru_month2W,
1227         ru_month3W,
1228         ru_month4W,
1229         ru_month5W,
1230         ru_month6W,
1231         ru_month7W,
1232         ru_month8W,
1233         ru_month9W,
1234         ru_month10W,
1235         ru_month11W,
1236         ru_month12W,
1237         NULL
1238     };
1239 
1240     TRACE("%#x, %p\n", lcid, str);
1241 
1242     if (PRIMARYLANGID(LANGIDFROMLCID(lcid)) == LANG_ARABIC)
1243         *str = (LPOLESTR *)arabic_hijri;
1244     else if (PRIMARYLANGID(LANGIDFROMLCID(lcid)) == LANG_POLISH)
1245         *str = (LPOLESTR *)polish_genitive_names;
1246     else if (PRIMARYLANGID(LANGIDFROMLCID(lcid)) == LANG_RUSSIAN)
1247         *str = (LPOLESTR *)russian_genitive_names;
1248     else
1249         *str = NULL;
1250 
1251     return S_OK;
1252 }
1253