- Better handling when settimeofday is not available.
[wine] / dlls / shlwapi / ordinal.c
1 /*
2  * SHLWAPI ordinal functions
3  *
4  * Copyright 1997 Marcus Meissner
5  *           1998 Jürgen Schmied
6  *           2001 Jon Griffiths
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include <stdio.h>
24 #include <string.h>
25
26 #include "windef.h"
27 #include "winnls.h"
28 #include "winbase.h"
29 #include "ddeml.h"
30 #include "shlobj.h"
31 #include "shellapi.h"
32 #include "commdlg.h"
33 #include "wine/unicode.h"
34 #include "wine/obj_base.h"
35 #include "wine/obj_inplace.h"
36 #include "wine/obj_serviceprovider.h"
37 #include "wingdi.h"
38 #include "winreg.h"
39 #include "winuser.h"
40 #include "wine/debug.h"
41 #include "ordinal.h"
42 #include "shlwapi.h"
43
44 WINE_DEFAULT_DEBUG_CHANNEL(shell);
45
46 extern HINSTANCE shlwapi_hInstance;
47 extern HMODULE SHLWAPI_hshell32;
48 extern HMODULE SHLWAPI_hwinmm;
49 extern HMODULE SHLWAPI_hcomdlg32;
50 extern HMODULE SHLWAPI_hmpr;
51 extern HMODULE SHLWAPI_hmlang;
52 extern HMODULE SHLWAPI_hversion;
53
54 extern DWORD SHLWAPI_ThreadRef_index;
55
56 typedef HANDLE HSHARED; /* Shared memory */
57
58 /* following is GUID for IObjectWithSite::SetSite  -- see _174           */
59 static DWORD id1[4] = {0xfc4801a3, 0x11cf2ba9, 0xaa0029a2, 0x52733d00};
60 /* following is GUID for IPersistMoniker::GetClassID  -- see _174        */
61 static DWORD id2[4] = {0x79eac9ee, 0x11cebaf9, 0xaa00828c, 0x0ba94b00};
62
63 /* The following schemes were identified in the native version of
64  * SHLWAPI.DLL version 5.50
65  */
66 typedef enum {
67     URL_SCHEME_INVALID     = -1,
68     URL_SCHEME_UNKNOWN     =  0,
69     URL_SCHEME_FTP,
70     URL_SCHEME_HTTP,
71     URL_SCHEME_GOPHER,
72     URL_SCHEME_MAILTO,
73     URL_SCHEME_NEWS,
74     URL_SCHEME_NNTP,
75     URL_SCHEME_TELNET,
76     URL_SCHEME_WAIS,
77     URL_SCHEME_FILE,
78     URL_SCHEME_MK,
79     URL_SCHEME_HTTPS,
80     URL_SCHEME_SHELL,
81     URL_SCHEME_SNEWS,
82     URL_SCHEME_LOCAL,
83     URL_SCHEME_JAVASCRIPT,
84     URL_SCHEME_VBSCRIPT,
85     URL_SCHEME_ABOUT,
86     URL_SCHEME_RES,
87     URL_SCHEME_MAXVALUE
88 } URL_SCHEME;
89
90 typedef struct {
91     URL_SCHEME  scheme_number;
92     LPCSTR scheme_name;
93 } SHL_2_inet_scheme;
94
95 static const SHL_2_inet_scheme shlwapi_schemes[] = {
96   {URL_SCHEME_FTP,        "ftp"},
97   {URL_SCHEME_HTTP,       "http"},
98   {URL_SCHEME_GOPHER,     "gopher"},
99   {URL_SCHEME_MAILTO,     "mailto"},
100   {URL_SCHEME_NEWS,       "news"},
101   {URL_SCHEME_NNTP,       "nntp"},
102   {URL_SCHEME_TELNET,     "telnet"},
103   {URL_SCHEME_WAIS,       "wais"},
104   {URL_SCHEME_FILE,       "file"},
105   {URL_SCHEME_MK,         "mk"},
106   {URL_SCHEME_HTTPS,      "https"},
107   {URL_SCHEME_SHELL,      "shell"},
108   {URL_SCHEME_SNEWS,      "snews"},
109   {URL_SCHEME_LOCAL,      "local"},
110   {URL_SCHEME_JAVASCRIPT, "javascript"},
111   {URL_SCHEME_VBSCRIPT,   "vbscript"},
112   {URL_SCHEME_ABOUT,      "about"},
113   {URL_SCHEME_RES,        "res"},
114   {0, 0}
115 };
116
117 /* Macro to get function pointer for a module*/
118 #define GET_FUNC(module, name, fail) \
119   if (!SHLWAPI_h##module) SHLWAPI_h##module = LoadLibraryA(#module ".dll"); \
120   if (!SHLWAPI_h##module) return fail; \
121   if (!pfnFunc) pfnFunc = (void*)GetProcAddress(SHLWAPI_h##module, name); \
122   if (!pfnFunc) return fail
123
124 /*
125  NOTES: Most functions exported by ordinal seem to be superflous.
126  The reason for these functions to be there is to provide a wraper
127  for unicode functions to provide these functions on systems without
128  unicode functions eg. win95/win98. Since we have such functions we just
129  call these. If running Wine with native DLL's, some late bound calls may
130  fail. However, its better to implement the functions in the forward DLL
131  and recommend the builtin rather than reimplementing the calls here!
132 */
133
134 /*************************************************************************
135  *      @       [SHLWAPI.1]
136  *
137  * Identifies the Internet "scheme" in the passed string. ASCII based.
138  * Also determines start and length of item after the ':'
139  */
140 DWORD WINAPI SHLWAPI_1 (LPCSTR x, UNKNOWN_SHLWAPI_1 *y)
141 {
142     DWORD cnt;
143     const SHL_2_inet_scheme *inet_pro;
144
145     if (y->size != 0x18) return E_INVALIDARG;
146     /* FIXME: leading white space generates error of 0x80041001 which 
147      *        is undefined
148      */
149     if (*x <= ' ') return 0x80041001;
150     cnt = 0;
151     y->sizep1 = 0;
152     y->ap1 = x;
153     while (*x) {
154         if (*x == ':') {
155             y->sizep1 = cnt;
156             cnt = -1;
157             y->ap2 = x+1;
158             break;
159         }
160         x++;
161         cnt++;
162     }
163
164     /* check for no scheme in string start */
165     /* (apparently schemes *must* be larger than a single character)  */
166     if ((*x == '\0') || (y->sizep1 <= 1)) {
167         y->ap1 = 0;
168         return 0x80041001;
169     }
170
171     /* found scheme, set length of remainder */
172     y->sizep2 = lstrlenA(y->ap2);
173
174     /* see if known scheme and return indicator number */
175     y->fcncde = URL_SCHEME_UNKNOWN;
176     inet_pro = shlwapi_schemes;
177     while (inet_pro->scheme_name) {
178         if (!strncasecmp(inet_pro->scheme_name, y->ap1,
179                     min(y->sizep1, lstrlenA(inet_pro->scheme_name)))) {
180             y->fcncde = inet_pro->scheme_number;
181             break;
182         }
183         inet_pro++;
184     }
185     return S_OK;
186 }
187
188 /*************************************************************************
189  *      @       [SHLWAPI.2]
190  *
191  * Identifies the Internet "scheme" in the passed string. UNICODE based.
192  * Also determines start and length of item after the ':'
193  */
194 DWORD WINAPI SHLWAPI_2 (LPCWSTR x, UNKNOWN_SHLWAPI_2 *y)
195 {
196     DWORD cnt;
197     const SHL_2_inet_scheme *inet_pro;
198     LPSTR cmpstr;
199     INT len;
200
201     if (y->size != 0x18) return E_INVALIDARG;
202     /* FIXME: leading white space generates error of 0x80041001 which 
203      *        is undefined
204      */
205     if (*x <= L' ') return 0x80041001;
206     cnt = 0;
207     y->sizep1 = 0;
208     y->ap1 = x;
209     while (*x) {
210         if (*x == L':') {
211             y->sizep1 = cnt;
212             cnt = -1;
213             y->ap2 = x+1;
214             break;
215         }
216         x++;
217         cnt++;
218     }
219
220     /* check for no scheme in string start */
221     /* (apparently schemes *must* be larger than a single character)  */
222     if ((*x == L'\0') || (y->sizep1 <= 1)) {
223         y->ap1 = 0;
224         return 0x80041001;
225     }
226
227     /* found scheme, set length of remainder */
228     y->sizep2 = lstrlenW(y->ap2);
229
230     /* see if known scheme and return indicator number */
231     len = WideCharToMultiByte(0, 0, y->ap1, y->sizep1, 0, 0, 0, 0);
232     cmpstr = (LPSTR)HeapAlloc(GetProcessHeap(), 0, len+1);
233     WideCharToMultiByte(0, 0, y->ap1, y->sizep1, cmpstr, len+1, 0, 0);
234     y->fcncde = URL_SCHEME_UNKNOWN;
235     inet_pro = shlwapi_schemes;
236     while (inet_pro->scheme_name) {
237         if (!strncasecmp(inet_pro->scheme_name, cmpstr,
238                     min(len, lstrlenA(inet_pro->scheme_name)))) {
239             y->fcncde = inet_pro->scheme_number;
240             break;
241         }
242         inet_pro++;
243     }
244     HeapFree(GetProcessHeap(), 0, cmpstr);
245     return S_OK;
246 }
247
248 /*************************************************************************
249  * SHLWAPI_DupSharedHandle
250  *
251  * Internal implemetation of SHLWAPI_11.
252  */
253 static
254 HSHARED WINAPI SHLWAPI_DupSharedHandle(HSHARED hShared, DWORD dwDstProcId,
255                                        DWORD dwSrcProcId, DWORD dwAccess,
256                                        DWORD dwOptions)
257 {
258   HANDLE hDst, hSrc;
259   DWORD dwMyProcId = GetCurrentProcessId();
260   HSHARED hRet = (HSHARED)NULL;
261
262   TRACE("(%p,%ld,%ld,%08lx,%08lx)\n", (PVOID)hShared, dwDstProcId, dwSrcProcId,
263         dwAccess, dwOptions);
264
265   /* Get dest process handle */
266   if (dwDstProcId == dwMyProcId)
267     hDst = GetCurrentProcess();
268   else
269     hDst = OpenProcess(PROCESS_DUP_HANDLE, 0, dwDstProcId);
270
271   if (hDst)
272   {
273     /* Get src process handle */
274     if (dwSrcProcId == dwMyProcId)
275       hSrc = GetCurrentProcess();
276     else
277       hSrc = OpenProcess(PROCESS_DUP_HANDLE, 0, dwSrcProcId);
278
279     if (hSrc)
280     {
281       /* Make handle available to dest process */
282       if (!DuplicateHandle(hDst, (HANDLE)hShared, hSrc, &hRet,
283                            dwAccess, 0, dwOptions | DUPLICATE_SAME_ACCESS))
284         hRet = (HSHARED)NULL;
285
286       if (dwSrcProcId != dwMyProcId)
287         CloseHandle(hSrc);
288     }
289
290     if (dwDstProcId != dwMyProcId)
291       CloseHandle(hDst);
292   }
293
294   TRACE("Returning handle %p\n", (PVOID)hRet);
295   return hRet;
296 }
297
298 /*************************************************************************
299  * @  [SHLWAPI.7]
300  *
301  * Create a block of sharable memory and initialise it with data.
302  *
303  * PARAMS
304  * dwProcId [I] ID of process owning data
305  * lpvData  [I] Pointer to data to write
306  * dwSize   [I] Size of data
307  *
308  * RETURNS
309  * Success: A shared memory handle
310  * Failure: NULL
311  *
312  * NOTES
313  * Ordinals 7-11 provide a set of calls to create shared memory between a
314  * group of processes. The shared memory is treated opaquely in that its size
315  * is not exposed to clients who map it. This is accomplished by storing
316  * the size of the map as the first DWORD of mapped data, and then offsetting
317  * the view pointer returned by this size.
318  *
319  * SHLWAPI_7/SHLWAPI_10 - Create/Destroy the shared memory handle
320  * SHLWAPI_8/SHLWAPI_9  - Get/Release a pointer to the shared data
321  * SHLWAPI_11           - Helper function; Duplicate cross-process handles
322    */
323 HSHARED WINAPI SHLWAPI_7 (DWORD dwProcId, DWORD dwSize, LPCVOID lpvData)
324 {
325   HANDLE hMap;
326   LPVOID pMapped;
327   HSHARED hRet = (HSHARED)NULL;
328
329   TRACE("(%ld,%p,%ld)\n", dwProcId, lpvData, dwSize);
330
331   /* Create file mapping of the correct length */
332   hMap = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, FILE_MAP_READ, 0,
333                             dwSize + sizeof(dwSize), NULL);
334   if (!hMap)
335     return hRet;
336
337   /* Get a view in our process address space */
338   pMapped = MapViewOfFile(hMap, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
339
340   if (pMapped)
341   {
342     /* Write size of data, followed by the data, to the view */
343     *((DWORD*)pMapped) = dwSize;
344     if (dwSize)
345       memcpy((char *) pMapped + sizeof(dwSize), lpvData, dwSize);
346
347     /* Release view. All further views mapped will be opaque */
348     UnmapViewOfFile(pMapped);
349     hRet = SHLWAPI_DupSharedHandle((HSHARED)hMap, dwProcId,
350                                    GetCurrentProcessId(), FILE_MAP_ALL_ACCESS,
351                                    DUPLICATE_SAME_ACCESS);
352   }
353
354   CloseHandle(hMap);
355   return hRet;
356 }
357
358 /*************************************************************************
359  * @ [SHLWAPI.8]
360  *
361  * Get a pointer to a block of shared memory from a shared memory handle.
362  *
363  * PARAMS
364  * hShared  [I] Shared memory handle
365  * dwProcId [I] ID of process owning hShared
366  *
367  * RETURNS
368  * Success: A pointer to the shared memory
369  * Failure: NULL
370  *
371  * NOTES
372  * See SHLWAPI_7.
373    */
374 PVOID WINAPI SHLWAPI_8 (HSHARED hShared, DWORD dwProcId)
375   {
376   HSHARED hDup;
377   LPVOID pMapped;
378
379   TRACE("(%p %ld)\n", (PVOID)hShared, dwProcId);
380
381   /* Get handle to shared memory for current process */
382   hDup = SHLWAPI_DupSharedHandle(hShared, dwProcId, GetCurrentProcessId(),
383                                  FILE_MAP_ALL_ACCESS, 0);
384   /* Get View */
385   pMapped = MapViewOfFile((HANDLE)hDup, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
386   CloseHandle(hDup);
387
388   if (pMapped)
389     return (char *) pMapped + sizeof(DWORD); /* Hide size */
390   return NULL;
391 }
392
393 /*************************************************************************
394  * @ [SHLWAPI.9]
395  *
396  * Release a pointer to a block of shared memory.
397  *
398  * PARAMS
399  * lpView [I] Shared memory pointer
400  *
401  * RETURNS
402  * Success: TRUE
403  * Failure: FALSE
404  *
405  * NOTES
406  * See SHLWAPI_7.
407  */
408 BOOL WINAPI SHLWAPI_9 (LPVOID lpView)
409 {
410   TRACE("(%p)\n", lpView);
411   return UnmapViewOfFile((char *) lpView - sizeof(DWORD)); /* Include size */
412 }
413
414 /*************************************************************************
415  * @ [SHLWAPI.10]
416  *
417  * Destroy a block of sharable memory.
418  *
419  * PARAMS
420  * hShared  [I] Shared memory handle
421  * dwProcId [I] ID of process owning hShared
422  *
423  * RETURNS
424  * Success: TRUE
425  * Failure: FALSE
426  *
427  * NOTES
428  * See SHLWAPI_7.
429  */
430 BOOL WINAPI SHLWAPI_10 (HSHARED hShared, DWORD dwProcId)
431 {
432   HSHARED hClose;
433
434   TRACE("(%p %ld)\n", (PVOID)hShared, dwProcId);
435
436   /* Get a copy of the handle for our process, closing the source handle */
437   hClose = SHLWAPI_DupSharedHandle(hShared, dwProcId, GetCurrentProcessId(),
438                                    FILE_MAP_ALL_ACCESS,DUPLICATE_CLOSE_SOURCE);
439   /* Close local copy */
440   return CloseHandle((HANDLE)hClose);
441 }
442
443 /*************************************************************************
444  * @   [SHLWAPI.11]
445  *
446  * Copy a sharable memory handle from one process to another.
447  *
448  * PARAMS
449  * hShared     [I] Shared memory handle to duplicate
450  * dwDstProcId [I] ID of the process wanting the duplicated handle
451  * dwSrcProcId [I] ID of the process owning hShared
452  * dwAccess    [I] Desired DuplicateHandle access
453  * dwOptions   [I] Desired DuplicateHandle options
454  *
455  * RETURNS
456  * Success: A handle suitable for use by the dwDstProcId process.
457  * Failure: A NULL handle.
458  *
459  * NOTES
460  * See SHLWAPI_7.
461  */
462 HSHARED WINAPI SHLWAPI_11(HSHARED hShared, DWORD dwDstProcId, DWORD dwSrcProcId,
463                           DWORD dwAccess, DWORD dwOptions)
464 {
465   HSHARED hRet;
466
467   hRet = SHLWAPI_DupSharedHandle(hShared, dwDstProcId, dwSrcProcId,
468                                  dwAccess, dwOptions);
469   return hRet;
470 }
471
472 /*************************************************************************
473  *      @       [SHLWAPI.13]
474  * (Used by IE4 during startup)
475  */
476 HRESULT WINAPI SHLWAPI_13 (
477         LPVOID w,
478         LPVOID x)
479 {
480         FIXME("(%p %p)stub\n",w,x);
481         return 1;
482 #if 0
483         /* pseudo code extracted from relay trace */
484         RegOpenKeyA(HKLM, "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Aceepted Documents", &newkey);
485         ret = 0;
486         i = 0;
487         size = 0;
488         while(!ret) {
489             ret = RegEnumValueA(newkey, i, a1, a2, 0, a3, 0, 0);
490             size += ???;
491             i++;
492         }
493         b1 = LocalAlloc(0x40, size);
494         ret = 0;
495         i = 0;
496         while(!ret) {
497             ret = RegEnumValueA(newkey, i, a1, a2, 0, a3, a4, a5);
498             RegisterClipBoardFormatA(a4);
499             i++;
500         }
501         hwnd1 = GetModuleHandleA("URLMON.DLL");
502         proc = GetProcAddress(hwnd1, "CreateFormatEnumerator");
503         HeapAlloc(??, 0, 0x14);
504         HeapAlloc(??, 0, 0x50);
505         LocalAlloc(0x40, 0x78);
506         /* FIXME: bad string below */
507         lstrlenW(L"{D0FCA420-D3F5-11CF-B211-00AA004AE837}");
508         StrCpyW(a6,  L"{D0FCA420-D3F5-11CF-B211-00AA004AE837}");
509
510         GetTickCount();
511         IsBadReadPtr(c1 = 0x403fd210,4);
512         InterlockedIncrement(c1+4);
513         LocalFree(b1);
514         RegCloseKey(newkey);
515         IsBadReadPtr(c1 = 0x403fd210,4);
516         InterlockedIncrement(c1+4);
517
518         HeapAlloc(40350000,00000000,00000014) retval=403fd0a8;
519         HeapAlloc(40350000,00000000,00000050) retval=403feb44;
520         hwnd1 = GetModuleHandleA("URLMON.DLL");
521         proc = GetProcAddress(hwnd1, "RegisterFormatEnumerator");
522         /* 0x1a40c88c is in URLMON.DLL just before above proc
523          * content is L"_EnumFORMATETC_"
524          * label is d1
525          */
526         IsBadReadPtr(d1 = 0x1a40c88c,00000002);
527         lstrlenW(d1);
528         lstrlenW(d1);
529         HeapAlloc(40350000,00000000,0000001e) retval=403fed44;
530         IsBadReadPtr(d2 = 0x403fd0a8,00000004);
531         InterlockedIncrement(d2+4);
532         IsBadReadPtr(d2 = 0x403fd0a8,00000004);
533         InterlockedDecrement(d2+4);
534         IsBadReadPtr(c1,00000004);
535         InterlockedDecrement(c1+4);
536         IsBadReadPtr(c1,00000004);
537         InterlockedDecrement(c1+4);
538
539 #endif
540 }
541
542 /*************************************************************************
543  *      @       [SHLWAPI.14]
544  *
545  * Function:
546  *    Retrieves IE "AcceptLanguage" value from registry. ASCII mode.
547  *  
548  */
549 HRESULT WINAPI SHLWAPI_14 (
550         LPSTR langbuf,
551         LPDWORD buflen)
552 {
553         CHAR *mystr;
554         DWORD mystrlen, mytype;
555         HKEY mykey;
556         LCID mylcid;
557
558         mystrlen = (*buflen > 6) ? *buflen : 6;
559         mystr = (CHAR*)HeapAlloc(GetProcessHeap(), 
560                                  HEAP_ZERO_MEMORY, mystrlen);
561         RegOpenKeyA(HKEY_CURRENT_USER, 
562                     "Software\\Microsoft\\Internet Explorer\\International", 
563                     &mykey);
564         if (RegQueryValueExA(mykey, "AcceptLanguage", 
565                               0, &mytype, mystr, &mystrlen)) {
566             /* Did not find value */
567             mylcid = GetUserDefaultLCID();
568             /* somehow the mylcid translates into "en-us"
569              *  this is similar to "LOCALE_SABBREVLANGNAME"
570              *  which could be gotten via GetLocaleInfo.
571              *  The only problem is LOCALE_SABBREVLANGUAGE" is
572              *  a 3 char string (first 2 are country code and third is
573              *  letter for "sublanguage", which does not come close to
574              *  "en-us"
575              */
576             lstrcpyA(mystr, "en-us");
577             mystrlen = lstrlenA(mystr);
578         }
579         else {
580             /* handle returned string */
581             FIXME("missing code\n");
582         }
583         if (mystrlen > *buflen) 
584             lstrcpynA(langbuf, mystr, *buflen);
585         else {
586             lstrcpyA(langbuf, mystr);
587             *buflen = lstrlenA(langbuf);
588         }        
589         RegCloseKey(mykey);
590         HeapFree(GetProcessHeap(), 0, mystr);
591         TRACE("language is %s\n", debugstr_a(langbuf));
592         return 0;
593 }
594
595 /*************************************************************************
596  *      @       [SHLWAPI.15]
597  *
598  * Function:
599  *    Retrieves IE "AcceptLanguage" value from registry. UNICODE mode.
600  *  
601  */
602 HRESULT WINAPI SHLWAPI_15 (
603         LPWSTR langbuf,
604         LPDWORD buflen)
605 {
606         CHAR *mystr;
607         DWORD mystrlen, mytype;
608         HKEY mykey;
609         LCID mylcid;
610
611         mystrlen = (*buflen > 6) ? *buflen : 6;
612         mystr = (CHAR*)HeapAlloc(GetProcessHeap(), 
613                                  HEAP_ZERO_MEMORY, mystrlen);
614         RegOpenKeyA(HKEY_CURRENT_USER, 
615                     "Software\\Microsoft\\Internet Explorer\\International", 
616                     &mykey);
617         if (RegQueryValueExA(mykey, "AcceptLanguage", 
618                               0, &mytype, mystr, &mystrlen)) {
619             /* Did not find value */
620             mylcid = GetUserDefaultLCID();
621             /* somehow the mylcid translates into "en-us"
622              *  this is similar to "LOCALE_SABBREVLANGNAME"
623              *  which could be gotten via GetLocaleInfo.
624              *  The only problem is LOCALE_SABBREVLANGUAGE" is
625              *  a 3 char string (first 2 are country code and third is
626              *  letter for "sublanguage", which does not come close to
627              *  "en-us"
628              */
629             lstrcpyA(mystr, "en-us");
630             mystrlen = lstrlenA(mystr);
631         }
632         else {
633             /* handle returned string */
634             FIXME("missing code\n");
635         }
636         RegCloseKey(mykey);
637         *buflen = MultiByteToWideChar(0, 0, mystr, -1, langbuf, (*buflen)-1);
638         HeapFree(GetProcessHeap(), 0, mystr);
639         TRACE("language is %s\n", debugstr_w(langbuf));
640         return 0;
641 }
642
643 /*************************************************************************
644  *      @       [SHLWAPI.16]
645  */
646 HRESULT WINAPI SHLWAPI_16 (
647         LPVOID w,
648         LPVOID x,
649         LPVOID y,
650         LPWSTR z)
651 {
652         FIXME("(%p %p %p %p)stub\n",w,x,y,z);
653         return 0xabba1252;
654 }
655
656 /*************************************************************************
657  *      @       [SHLWAPI.18]
658  *
659  *  w is pointer to address of callback routine
660  *  x is pointer to LPVOID to receive address of locally allocated
661  *         space size 0x14
662  *  return is 0 (unless out of memory???)
663  *
664  * related to _19, _21 and _22 below
665  *  only seen invoked by SHDOCVW
666  */
667 LONG WINAPI SHLWAPI_18 (
668         LPVOID *w,
669         LPVOID x)
670 {
671         FIXME("(%p %p)stub\n",w,x);
672         *((LPDWORD)x) = 0;
673         return 0;
674 }
675
676 /*************************************************************************
677  *      @       [SHLWAPI.19]
678  *
679  *  w is address of allocated memory from _21
680  *  return is 0 (unless out of memory???)
681  *
682  * related to _18, _21 and _22 below
683  *  only seen invoked by SHDOCVW
684  */
685 LONG WINAPI SHLWAPI_19 (
686         LPVOID w)
687 {
688         FIXME("(%p) stub\n",w);
689         return 0;
690 }
691
692 /*************************************************************************
693  *      @       [SHLWAPI.21]
694  *
695  *  w points to space allocated via .18 above
696  *      LocalSize is done on it (retrieves 18)
697  *      LocalReAlloc is done on it to size 8 with LMEM_MOVEABLE & LMEM_ZEROINIT
698  *  x values seen 0xa0000005
699  *  returns 1
700  *
701  *  relates to _18, _19 and _22 above and below
702  *   only seen invoked by SHDOCVW
703  */
704 LONG WINAPI SHLWAPI_21 (
705         LPVOID w,
706         DWORD  x)
707 {
708         FIXME("(%p %lx)stub\n",w,x);
709         return 1;
710 }
711
712 /*************************************************************************
713  *      @       [SHLWAPI.22]
714  *
715  *  return is 'w' value seen in x is 0xa0000005
716  *
717  *  relates to _18, _19 and _21 above
718  *   only seen invoked by SHDOCVW
719  */
720 LPVOID WINAPI SHLWAPI_22 (
721         LPVOID w,
722         DWORD  x)
723 {
724         FIXME("(%p %lx)stub\n",w,x);
725         return w;
726 }
727
728 /*************************************************************************
729  *      @       [SHLWAPI.23]
730  *
731  * NOTES
732  *      converts a guid to a string
733  *      returns strlen(str)
734  */
735 DWORD WINAPI SHLWAPI_23 (
736         REFGUID guid,   /* [in]  clsid */
737         LPSTR str,      /* [out] buffer */
738         INT cmax)       /* [in]  size of buffer */
739 {
740         char xguid[40];
741
742         sprintf( xguid, "{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
743                  guid->Data1, guid->Data2, guid->Data3,
744                  guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
745                  guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7] );
746         TRACE("(%s %p 0x%08x)stub\n", xguid, str, cmax);
747         if (strlen(xguid)>=cmax) return 0;
748         strcpy(str,xguid);
749         return strlen(xguid) + 1;
750 }
751
752 /*************************************************************************
753  *      @       [SHLWAPI.24]
754  *
755  * NOTES
756  *      converts a guid to a string
757  *      returns strlen(str)
758  */
759 DWORD WINAPI SHLWAPI_24 (
760         REFGUID guid,   /* [in]  clsid */
761         LPWSTR str,     /* [out] buffer */
762         INT cmax)       /* [in]  size of buffer */
763 {
764     char xguid[40];
765
766     sprintf( xguid, "{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
767              guid->Data1, guid->Data2, guid->Data3,
768              guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
769              guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7] );
770     return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
771 }
772
773 /*************************************************************************
774  *      @       [SHLWAPI.25]
775  *
776  * Seems to be iswalpha
777  */
778 BOOL WINAPI SHLWAPI_25(WCHAR wc)
779 {
780     return (get_char_typeW(wc) & C1_ALPHA) != 0;
781 }
782
783 /*************************************************************************
784  *      @       [SHLWAPI.26]
785  *
786  * Seems to be iswupper
787  */
788 BOOL WINAPI SHLWAPI_26(WCHAR wc)
789 {
790     return (get_char_typeW(wc) & C1_UPPER) != 0;
791 }
792
793 /*************************************************************************
794  *      @       [SHLWAPI.27]
795  *
796  * Seems to be iswlower
797  */
798 BOOL WINAPI SHLWAPI_27(WCHAR wc)
799 {
800     return (get_char_typeW(wc) & C1_LOWER) != 0;
801 }
802
803 /*************************************************************************
804  *      @       [SHLWAPI.28]
805  *
806  * Seems to be iswalnum
807  */
808 BOOL WINAPI SHLWAPI_28(WCHAR wc)
809 {
810     return (get_char_typeW(wc) & (C1_ALPHA|C1_DIGIT)) != 0;
811 }
812
813 /*************************************************************************
814  *      @       [SHLWAPI.29]
815  *
816  * Seems to be iswspace
817  */
818 BOOL WINAPI SHLWAPI_29(WCHAR wc)
819 {
820     return (get_char_typeW(wc) & C1_SPACE) != 0;
821 }
822
823 /*************************************************************************
824  *      @       [SHLWAPI.30]
825  *
826  * Seems to be iswblank
827  */
828 BOOL WINAPI SHLWAPI_30(WCHAR wc)
829 {
830     return (get_char_typeW(wc) & C1_BLANK) != 0;
831 }
832
833 /*************************************************************************
834  *      @       [SHLWAPI.31]
835  *
836  * Seems to be iswpunct
837  */
838 BOOL WINAPI SHLWAPI_31(WCHAR wc)
839 {
840     return (get_char_typeW(wc) & C1_PUNCT) != 0;
841 }
842
843 /*************************************************************************
844  *      @       [SHLWAPI.32]
845  *
846  * Seems to be iswcntrl
847  */
848 BOOL WINAPI SHLWAPI_32(WCHAR wc)
849 {
850     return (get_char_typeW(wc) & C1_CNTRL) != 0;
851 }
852
853 /*************************************************************************
854  *      @       [SHLWAPI.33]
855  *
856  * Seems to be iswdigit
857  */
858 BOOL WINAPI SHLWAPI_33(WCHAR wc)
859 {
860     return (get_char_typeW(wc) & C1_DIGIT) != 0;
861 }
862
863 /*************************************************************************
864  *      @       [SHLWAPI.34]
865  *
866  * Seems to be iswxdigit
867  */
868 BOOL WINAPI SHLWAPI_34(WCHAR wc)
869 {
870     return (get_char_typeW(wc) & C1_XDIGIT) != 0;
871 }
872
873 /*************************************************************************
874  *      @       [SHLWAPI.35]
875  *
876  */
877 BOOL WINAPI SHLWAPI_35(LPVOID p1, DWORD dw2, LPVOID p3)
878 {
879     FIXME("(%p, 0x%08lx, %p): stub\n", p1, dw2, p3);
880     return TRUE;
881 }
882
883 /*************************************************************************
884  *      @       [SHLWAPI.36]
885  *
886  */
887 BOOL WINAPI SHLWAPI_36(HMENU h1, UINT ui2, UINT h3, LPCWSTR p4)
888 {
889     TRACE("(0x%08x, 0x%08x, 0x%08x, %s): stub\n", 
890           h1, ui2, h3, debugstr_w(p4));
891     return AppendMenuW(h1, ui2, h3, p4);
892 }
893
894 /*************************************************************************
895  *      @       [SHLWAPI.74]
896  *
897  * Get the text from a given dialog item.
898  */
899 INT WINAPI SHLWAPI_74(HWND hWnd, INT nItem, LPWSTR lpsDest,INT nDestLen)
900 {
901   HWND hItem = GetDlgItem(hWnd, nItem);
902
903   if (hItem)
904     return GetWindowTextW(hItem, lpsDest, nDestLen);
905   if (nDestLen)
906     *lpsDest = (WCHAR)'\0';
907   return 0;
908 }
909
910 /*************************************************************************
911  *      @       [SHLWAPI.151]
912  * Function:  Compare two ASCII strings for "len" bytes.
913  * Returns:   *str1-*str2  (case sensitive)
914  */
915 DWORD WINAPI SHLWAPI_151(LPSTR str1, LPSTR str2, INT len)
916 {
917     return strncmp( str1, str2, len );
918 }
919
920 /*************************************************************************
921  *      @       [SHLWAPI.152]
922  *
923  * Function:  Compare two WIDE strings for "len" bytes.
924  * Returns:   *str1-*str2  (case sensitive)
925  */
926 DWORD WINAPI SHLWAPI_152(LPWSTR str1, LPWSTR str2, INT len)
927 {
928     return strncmpW( str1, str2, len );
929 }
930
931 /*************************************************************************
932  *      @       [SHLWAPI.153]
933  * Function:  Compare two ASCII strings for "len" bytes via caseless compare.
934  * Returns:   *str1-*str2  (case insensitive)
935  */
936 DWORD WINAPI SHLWAPI_153(LPSTR str1, LPSTR str2, DWORD len)
937 {
938     return strncasecmp( str1, str2, len );
939 }
940
941 /*************************************************************************
942  *      @       [SHLWAPI.154]
943  *
944  * Function:  Compare two WIDE strings for "len" bytes via caseless compare.
945  * Returns:   *str1-*str2  (case insensitive)
946  */
947 DWORD WINAPI SHLWAPI_154(LPWSTR str1, LPWSTR str2, DWORD len)
948 {
949     return strncmpiW( str1, str2, len );
950 }
951
952 /*************************************************************************
953  *      @       [SHLWAPI.155]
954  *
955  *      Case sensitive string compare (ASCII). Does not SetLastError().
956  */
957 DWORD WINAPI SHLWAPI_155 ( LPSTR str1, LPSTR str2)
958 {
959     return strcmp(str1, str2);
960 }
961
962 /*************************************************************************
963  *      @       [SHLWAPI.156]
964  *
965  *      Case sensitive string compare. Does not SetLastError().
966  */
967 DWORD WINAPI SHLWAPI_156 ( LPWSTR str1, LPWSTR str2)
968 {
969     return strcmpW( str1, str2 );
970 }
971
972 /*************************************************************************
973  *      @       [SHLWAPI.158]
974  *
975  *      Case insensitive string compare. Does not SetLastError(). ??
976  */
977 DWORD WINAPI SHLWAPI_158 ( LPWSTR str1, LPWSTR str2)
978 {
979     return strcmpiW( str1, str2 );
980 }
981
982 /*************************************************************************
983  *      @       [SHLWAPI.162]
984  *
985  * Ensure a multibyte character string doesn't end in a hanging lead byte.
986  */
987 DWORD WINAPI SHLWAPI_162(LPSTR lpStr, DWORD size)
988 {
989   if (lpStr && size)
990   {
991     LPSTR lastByte = lpStr + size - 1;
992
993     while(lpStr < lastByte)
994       lpStr += IsDBCSLeadByte(*lpStr) ? 2 : 1;
995
996     if(lpStr == lastByte && IsDBCSLeadByte(*lpStr))
997     {
998       *lpStr = '\0';
999       size--;
1000     }
1001     return size;
1002   }
1003   return 0;
1004 }
1005
1006 /*************************************************************************
1007  *      @       [SHLWAPI.164]
1008  */
1009 DWORD WINAPI SHLWAPI_164 (
1010         LPVOID u,
1011         LPVOID v,
1012         LPVOID w,
1013         LPVOID x,
1014         LPVOID y,
1015         LPVOID z)
1016 {
1017         TRACE("(%p %p %p %p %p %p) stub\n",u,v,w,x,y,z);
1018         return 0x80004002;    /* E_NOINTERFACE */
1019 }
1020
1021 /*************************************************************************
1022  *      @       [SHLWAPI.165]
1023  *
1024  * SetWindowLongA with mask.
1025  */
1026 LONG WINAPI SHLWAPI_165(HWND hwnd, INT offset, UINT wFlags, UINT wMask)
1027 {
1028   LONG ret = GetWindowLongA(hwnd, offset);
1029   UINT newFlags = (wFlags & wMask) | (ret & ~wFlags);
1030
1031   if (newFlags != ret)
1032     ret = SetWindowLongA(hwnd, offset, newFlags);
1033   return ret;
1034 }
1035
1036 /*************************************************************************
1037  *      @       [SHLWAPI.169]
1038  *
1039  *  Do IUnknown::Release on passed object.
1040  */
1041 DWORD WINAPI SHLWAPI_169 (IUnknown ** lpUnknown)
1042 {
1043         IUnknown *temp;
1044
1045         TRACE("(%p)\n",lpUnknown);
1046         if(!lpUnknown || !*((LPDWORD)lpUnknown)) return 0;
1047         temp = *lpUnknown;
1048         *lpUnknown = NULL;
1049         TRACE("doing Release\n");
1050         return IUnknown_Release(temp);
1051 }
1052
1053 /*************************************************************************
1054  *      @       [SHLWAPI.170]
1055  *
1056  * Skip URL '//' sequence.
1057  */
1058 LPCSTR WINAPI SHLWAPI_170(LPCSTR lpszSrc)
1059 {
1060   if (lpszSrc && lpszSrc[0] == '/' && lpszSrc[1] == '/')
1061     lpszSrc += 2;
1062   return lpszSrc;
1063 }
1064
1065 /*************************************************************************
1066  *      @       [SHLWAPI.172]
1067  * Get window handle of OLE object
1068  */
1069 DWORD WINAPI SHLWAPI_172 (
1070         IUnknown *y,       /* [in]   OLE object interface */
1071         LPHWND z)          /* [out]  location to put window handle */
1072 {
1073         DWORD ret;
1074         IUnknown *pv;
1075
1076         TRACE("(%p %p)\n",y,z);
1077         if (!y) return E_FAIL;
1078
1079         if ((ret = IUnknown_QueryInterface(y, &IID_IOleWindow,(LPVOID *)&pv)) < 0) {
1080             /* error */
1081             return ret;
1082         }
1083         ret = IOleWindow_GetWindow((IOleWindow *)pv, z);
1084         IUnknown_Release(pv);
1085         TRACE("result hwnd=%08x\n", *z);
1086         return ret;
1087 }
1088
1089 /*************************************************************************
1090  *      @       [SHLWAPI.174]
1091  *
1092  * Seems to do call either IObjectWithSite::SetSite or 
1093  *   IPersistMoniker::GetClassID.  But since we do not implement either
1094  *   of those classes in our headers, we will fake it out.
1095  */
1096 DWORD WINAPI SHLWAPI_174(
1097         IUnknown *p1,     /* [in]   OLE object                          */
1098         LPVOID *p2)       /* [out]  ptr to result of either GetClassID 
1099                                     or SetSite call.                    */
1100 {
1101     DWORD ret, aa;
1102
1103     if (!p1) return E_FAIL;
1104
1105     /* see if SetSite interface exists for IObjectWithSite object */
1106     ret = IUnknown_QueryInterface((IUnknown *)p1, (REFIID)id1, (LPVOID *)&p1);
1107     TRACE("first IU_QI ret=%08lx, p1=%p\n", ret, p1);
1108     if (ret) { 
1109
1110         /* see if GetClassId interface exists for IPersistMoniker object */
1111         ret = IUnknown_QueryInterface((IUnknown *)p1, (REFIID)id2, (LPVOID *)&aa);
1112         TRACE("second IU_QI ret=%08lx, aa=%08lx\n", ret, aa);
1113         if (ret) return ret;
1114
1115         /* fake a GetClassId call */
1116         ret = IOleWindow_GetWindow((IOleWindow *)aa, (HWND*)p2);
1117         TRACE("second IU_QI doing 0x0c ret=%08lx, *p2=%08lx\n", ret, 
1118               *(LPDWORD)p2);
1119         IUnknown_Release((IUnknown *)aa);
1120     }
1121     else {
1122         /* fake a SetSite call */
1123         ret = IOleWindow_GetWindow((IOleWindow *)p1, (HWND*)p2);
1124         TRACE("first IU_QI doing 0x0c ret=%08lx, *p2=%08lx\n", ret, 
1125               *(LPDWORD)p2);
1126         IUnknown_Release((IUnknown *)p1);
1127     }
1128     return ret;
1129 }
1130
1131 /*************************************************************************
1132  *      @       [SHLWAPI.176]
1133  *
1134  * Function appears to be interface to IServiceProvider::QueryService
1135  *
1136  * NOTE:
1137  *   returns E_NOINTERFACE
1138  *           E_FAIL  if w == 0
1139  *           S_OK    if _219 called successfully
1140  */
1141 DWORD WINAPI SHLWAPI_176 (
1142         IUnknown* unk,    /* [in]    object to give Service Provider */
1143         REFGUID   sid,    /* [in]    Service ID                      */
1144         REFIID    riid,   /* [in]    Function requested              */
1145         LPVOID    *z)     /* [out]   place to save interface pointer */
1146 {
1147     DWORD ret;
1148     LPVOID aa;
1149     *z = 0;
1150     if (!unk) return E_FAIL;
1151     ret = IUnknown_QueryInterface(unk, &IID_IServiceProvider, &aa);
1152     TRACE("did IU_QI retval=%08lx, aa=%p\n", ret, aa); 
1153     if (ret) return ret;
1154     ret = IServiceProvider_QueryService((IServiceProvider *)aa, sid, riid, 
1155                                         (void **)z);
1156     TRACE("did ISP_QS retval=%08lx, *z=%p\n", ret, (LPVOID)*z); 
1157     IUnknown_Release((IUnknown*)aa);
1158     return ret;
1159 }
1160
1161 /*************************************************************************
1162  *      @       [SHLWAPI.181]
1163  *
1164  *      Enable or disable a menu item.
1165  */
1166 UINT WINAPI SHLWAPI_181(HMENU hMenu, UINT wItemID, BOOL bEnable)
1167 {
1168   return EnableMenuItem(hMenu, wItemID, bEnable ? MF_ENABLED : MF_GRAYED);
1169 }
1170
1171 /*************************************************************************
1172  *      @       [SHLWAPI.183]
1173  *
1174  * Register a window class if it isn't already.
1175  */
1176 DWORD WINAPI SHLWAPI_183(WNDCLASSA *wndclass)
1177 {
1178   WNDCLASSA wca;
1179   if (GetClassInfoA(wndclass->hInstance, wndclass->lpszClassName, &wca))
1180     return TRUE;
1181   return (DWORD)RegisterClassA(wndclass);
1182 }
1183
1184 /*************************************************************************
1185  *      @       [SHLWAPI.193]
1186  */
1187 DWORD WINAPI SHLWAPI_193 ()
1188 {
1189         HDC hdc;
1190         DWORD ret;
1191
1192         TRACE("()\n");
1193
1194         hdc = GetDC(0);
1195         ret = GetDeviceCaps(hdc, BITSPIXEL) * GetDeviceCaps(hdc, PLANES);
1196         ReleaseDC(0, hdc);
1197         return ret;
1198 }
1199
1200 /*************************************************************************
1201  *      @       [SHLWAPI.199]
1202  *
1203  * Copy interface pointer
1204  */
1205 DWORD WINAPI SHLWAPI_199 (
1206         IUnknown **dest,   /* [out] pointer to copy of interface ptr */
1207         IUnknown *src)     /* [in]  interface pointer */
1208 {
1209         TRACE("(%p %p)\n",dest,src);
1210         if (*dest != src) {
1211             if (*dest)
1212                 IUnknown_Release(*dest);
1213             if (src) {
1214                 IUnknown_AddRef(src);
1215                 *dest = src;
1216             }
1217         }
1218         return 4;
1219 }
1220
1221 /*************************************************************************
1222  *      @       [SHLWAPI.208]
1223  *
1224  * Some sort of memory management process - associated with _210
1225  */
1226 DWORD WINAPI SHLWAPI_208 (
1227         DWORD    a,
1228         DWORD    b,
1229         LPVOID   c,
1230         LPVOID   d,
1231         DWORD    e)
1232 {
1233     FIXME("(0x%08lx 0x%08lx %p %p 0x%08lx) stub\n",
1234           a, b, c, d, e);
1235     return 1;
1236 }
1237
1238 /*************************************************************************
1239  *      @       [SHLWAPI.209]
1240  *
1241  * Some sort of memory management process - associated with _208
1242  */
1243 DWORD WINAPI SHLWAPI_209 (
1244         LPVOID   a)
1245 {
1246     FIXME("(%p) stub\n",
1247           a);
1248     return 1;
1249 }
1250
1251 /*************************************************************************
1252  *      @       [SHLWAPI.210]
1253  *
1254  * Some sort of memory management process - associated with _208
1255  */
1256 DWORD WINAPI SHLWAPI_210 (
1257         LPVOID   a,
1258         DWORD    b,
1259         LPVOID   c)
1260 {
1261     FIXME("(%p 0x%08lx %p) stub\n",
1262           a, b, c);
1263     return 0;
1264 }
1265
1266 /*************************************************************************
1267  *      @       [SHLWAPI.211]
1268  */
1269 DWORD WINAPI SHLWAPI_211 (
1270         LPVOID   a,
1271         DWORD    b)
1272 {
1273     FIXME("(%p 0x%08lx) stub\n",
1274           a, b);
1275     return 1;
1276 }
1277
1278 /*************************************************************************
1279  *      @       [SHLWAPI.215]
1280  *
1281  * NOTES
1282  *  check me!
1283  */
1284 DWORD WINAPI SHLWAPI_215 (
1285         LPCSTR lpStrSrc,
1286         LPWSTR lpwStrDest,
1287         int len)
1288 {
1289         INT len_a, ret;
1290
1291         len_a = lstrlenA(lpStrSrc);
1292         ret = MultiByteToWideChar(0, 0, lpStrSrc, len_a, lpwStrDest, len);
1293         TRACE("%s %s %d, ret=%d\n", 
1294               debugstr_a(lpStrSrc), debugstr_w(lpwStrDest), len, ret);
1295         return ret;
1296 }
1297
1298 /*************************************************************************
1299  *      @       [SHLWAPI.218]
1300  *
1301  * WideCharToMultiByte with multi language support.
1302  */
1303 INT WINAPI SHLWAPI_218(UINT CodePage, LPCWSTR lpSrcStr, LPSTR lpDstStr,
1304                        LPINT lpnMultiCharCount)
1305 {
1306   static HRESULT (WINAPI *pfnFunc)(LPDWORD,DWORD,LPCWSTR,LPINT,LPSTR,LPINT);
1307   WCHAR emptyW[] = { '\0' };
1308   int len , reqLen;
1309   LPSTR mem;
1310
1311   if (!lpDstStr || !lpnMultiCharCount)
1312     return 0;
1313
1314   if (!lpSrcStr)
1315     lpSrcStr = emptyW;
1316
1317   *lpDstStr = '\0';
1318
1319   len = strlenW(lpSrcStr) + 1;
1320
1321   switch (CodePage)
1322   {
1323   case CP_WINUNICODE:
1324     CodePage = CP_UTF8; /* Fall through... */
1325   case 0x0000C350: /* FIXME: CP_ #define */
1326   case CP_UTF7:
1327   case CP_UTF8:
1328     {
1329       DWORD dwMode = 0;
1330       INT nWideCharCount = len - 1;
1331
1332       GET_FUNC(mlang, "ConvertINetUnicodeToMultiByte", 0);
1333       if (!pfnFunc(&dwMode, CodePage, lpSrcStr, &nWideCharCount, lpDstStr,
1334                    lpnMultiCharCount))
1335         return 0;
1336
1337       if (nWideCharCount < len - 1)
1338       {
1339         mem = (LPSTR)HeapAlloc(GetProcessHeap(), 0, *lpnMultiCharCount);
1340         if (!mem)
1341           return 0;
1342
1343         *lpnMultiCharCount = 0;
1344
1345         if (pfnFunc(&dwMode, CodePage, lpSrcStr, &len, mem, lpnMultiCharCount))
1346         {
1347           SHLWAPI_162 (mem, *lpnMultiCharCount);
1348           lstrcpynA(lpDstStr, mem, *lpnMultiCharCount + 1);
1349           return *lpnMultiCharCount + 1;
1350         }
1351         HeapFree(GetProcessHeap(), 0, mem);
1352         return *lpnMultiCharCount;
1353       }
1354       lpDstStr[*lpnMultiCharCount] = '\0';
1355       return *lpnMultiCharCount;
1356     }
1357     break;
1358   default:
1359     break;
1360   }
1361
1362   reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, lpDstStr,
1363                                *lpnMultiCharCount, NULL, NULL);
1364
1365   if (!reqLen && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
1366   {
1367     reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, NULL, 0, NULL, NULL);
1368     if (reqLen)
1369     {
1370       mem = (LPSTR)HeapAlloc(GetProcessHeap(), 0, reqLen);
1371       if (mem)
1372       {
1373         reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, mem,
1374                                      reqLen, NULL, NULL);
1375
1376         reqLen = SHLWAPI_162(mem, *lpnMultiCharCount);
1377         reqLen++;
1378
1379         lstrcpynA(lpDstStr, mem, *lpnMultiCharCount);
1380
1381         HeapFree(GetProcessHeap(), 0, mem);
1382       }
1383     }
1384   }
1385   return reqLen;
1386 }
1387
1388 /*************************************************************************
1389  *      @       [SHLWAPI.217]
1390  *
1391  * Hmm, some program used lpnMultiCharCount == 0x3 (and lpSrcStr was "C")
1392  * --> Crash. Something wrong here.
1393  *
1394  * It seems from OE v5 that the third param is the count. (GA 11/2001)
1395  */
1396 INT WINAPI SHLWAPI_217(LPCWSTR lpSrcStr, LPSTR lpDstStr, INT MultiCharCount)
1397 {
1398     INT myint = MultiCharCount;
1399
1400     return SHLWAPI_218(CP_ACP, lpSrcStr, lpDstStr, &myint);
1401 }
1402
1403 /*************************************************************************
1404  *      @       [SHLWAPI.219]
1405  *
1406  * Seems to be "super" QueryInterface. Supplied with at table of interfaces
1407  * and an array of IIDs and offsets into the table.
1408  *
1409  * NOTES
1410  *  error codes: E_POINTER, E_NOINTERFACE
1411  */
1412 typedef struct {
1413     REFIID   refid;
1414     DWORD    indx;
1415 } IFACE_INDEX_TBL;
1416
1417 HRESULT WINAPI SHLWAPI_219 (
1418         LPVOID w,           /* [in]   table of interfaces                   */
1419         IFACE_INDEX_TBL *x, /* [in]   array of REFIIDs and indexes to above */
1420         REFIID riid,        /* [in]   REFIID to get interface for           */
1421         LPVOID *z)          /* [out]  location to get interface pointer     */
1422 {
1423         HRESULT ret;
1424         IUnknown *a_vtbl;
1425         IFACE_INDEX_TBL *xmove;
1426
1427         TRACE("(%p %p %s %p)\n",
1428               w,x,debugstr_guid(riid),z);
1429         if (z) {
1430             xmove = x;
1431             while (xmove->refid) {
1432                 TRACE("trying (indx %ld) %s\n", xmove->indx, 
1433                       debugstr_guid(xmove->refid));
1434                 if (IsEqualIID(riid, xmove->refid)) {
1435                     a_vtbl = (IUnknown*)(xmove->indx + (LPBYTE)w);
1436                     TRACE("matched, returning (%p)\n", a_vtbl);
1437                     *z = (LPVOID)a_vtbl;
1438                     IUnknown_AddRef(a_vtbl);
1439                     return S_OK;
1440                 }
1441                 xmove++;
1442             }
1443
1444             if (IsEqualIID(riid, &IID_IUnknown)) {
1445                 a_vtbl = (IUnknown*)(x->indx + (LPBYTE)w);
1446                 TRACE("returning first for IUnknown (%p)\n", a_vtbl);
1447                 *z = (LPVOID)a_vtbl;
1448                 IUnknown_AddRef(a_vtbl);
1449                 return S_OK;
1450             }
1451             *z = 0;
1452             ret = E_NOINTERFACE;
1453         } else
1454             ret = E_POINTER;
1455         return ret;
1456 }
1457
1458 /*************************************************************************
1459  *      @       [SHLWAPI.222]
1460  *
1461  * NOTES
1462  *  securityattributes missing
1463  */
1464 HANDLE WINAPI SHLWAPI_222 (LPCLSID guid)
1465 {
1466         char lpstrName[80];
1467
1468         sprintf( lpstrName, "shell.{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
1469                  guid->Data1, guid->Data2, guid->Data3,
1470                  guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
1471                  guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7] );
1472         FIXME("(%s) stub\n", lpstrName);
1473         return CreateSemaphoreA(NULL,0, 0x7fffffff, lpstrName);
1474 }
1475
1476 /*************************************************************************
1477  *      @       [SHLWAPI.223]
1478  *
1479  * NOTES
1480  *  get the count of the semaphore
1481  */
1482 DWORD WINAPI SHLWAPI_223 (HANDLE handle)
1483 {
1484         DWORD oldCount;
1485
1486         FIXME("(0x%08x) stub\n",handle);
1487
1488         ReleaseSemaphore( handle, 1, &oldCount);        /* +1 */
1489         WaitForSingleObject( handle, 0 );               /* -1 */
1490         return oldCount;
1491 }
1492
1493 /*************************************************************************
1494  *      @       [SHLWAPI.236]
1495  */
1496 HMODULE WINAPI SHLWAPI_236 (REFIID lpUnknown)
1497 {
1498     HKEY newkey;
1499     DWORD type, count;
1500     CHAR value[MAX_PATH], string[MAX_PATH];
1501
1502     strcpy(string, "CLSID\\");
1503     strcat(string, debugstr_guid(lpUnknown));
1504     strcat(string, "\\InProcServer32");
1505
1506     count = MAX_PATH;
1507     RegOpenKeyExA(HKEY_CLASSES_ROOT, string, 0, 1, &newkey);
1508     RegQueryValueExA(newkey, 0, 0, &type, value, &count);
1509     RegCloseKey(newkey);
1510     return LoadLibraryExA(value, 0, 0);
1511 }
1512
1513 /*************************************************************************
1514  *      @       [SHLWAPI.237]
1515  *
1516  * Unicode version of SHLWAPI_183.
1517  */
1518 DWORD WINAPI SHLWAPI_237 (WNDCLASSW * lpWndClass)
1519 {
1520         WNDCLASSW WndClass;
1521
1522         TRACE("(0x%08x %s)\n",lpWndClass->hInstance, debugstr_w(lpWndClass->lpszClassName));
1523
1524         if (GetClassInfoW(lpWndClass->hInstance, lpWndClass->lpszClassName, &WndClass))
1525                 return TRUE;
1526         return RegisterClassW(lpWndClass);
1527 }
1528
1529 /*************************************************************************
1530  *      @       [SHLWAPI.239]
1531  */
1532 DWORD WINAPI SHLWAPI_239(HINSTANCE hInstance, LPVOID p2, DWORD dw3)
1533 {
1534     FIXME("(0x%08x %p 0x%08lx) stub\n",
1535           hInstance, p2, dw3);
1536     return 0;
1537 #if 0
1538     /* pseudo code from relay trace */
1539     WideCharToMultiByte(0, 0, L"Shell DocObject View", -1, &aa, 0x0207, 0, 0);
1540     GetClassInfoA(70fe0000,405868ec "Shell DocObject View",40586b14);
1541     /* above pair repeated for:
1542            TridentThicketUrlDlClass
1543            Shell Embedding
1544            CIESplashScreen
1545            Inet Notify_Hidden
1546            OCHost
1547     */
1548 #endif
1549 }
1550
1551 /*************************************************************************
1552  *      @       [SHLWAPI.240]
1553  *
1554  *      Calls ASCII or Unicode WindowProc for the given window.
1555  */
1556 LRESULT CALLBACK SHLWAPI_240(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
1557 {
1558         if (IsWindowUnicode(hWnd))
1559                 return DefWindowProcW(hWnd, uMessage, wParam, lParam);
1560         return DefWindowProcA(hWnd, uMessage, wParam, lParam);
1561 }
1562
1563 /*************************************************************************
1564  *      @       [SHLWAPI.241]
1565  *
1566  */
1567 DWORD WINAPI SHLWAPI_241 ()
1568 {
1569         FIXME("()stub\n");
1570         return /* 0xabba1243 */ 0;
1571 }
1572
1573 /*************************************************************************
1574  *      @       [SHLWAPI.266]
1575  */
1576 DWORD WINAPI SHLWAPI_266 (
1577         LPVOID w,
1578         LPVOID x,
1579         LPVOID y,
1580         LPVOID z)
1581 {
1582         FIXME("(%p %p %p %p)stub\n",w,x,y,z);
1583         return 0xabba1248;
1584 }
1585
1586 /*************************************************************************
1587  *      @       [SHLWAPI.267]
1588  */
1589 HRESULT WINAPI SHLWAPI_267 (
1590         LPVOID w, /* [???] NOTE: same as 1th parameter of SHLWAPI_219 */
1591         LPVOID x, /* [???] NOTE: same as 2nd parameter of SHLWAPI_219 */
1592         LPVOID y,
1593         LPVOID z)
1594 {
1595         FIXME("(%p %p %p %p)stub\n",w,x,y,z);
1596         *((LPDWORD)z) = 0xabba1200;
1597         return 0xabba1254;
1598 }
1599
1600 /*************************************************************************
1601  *      @       [SHLWAPI.268]
1602  */
1603 DWORD WINAPI SHLWAPI_268 (
1604         LPVOID w,
1605         LPVOID x)
1606 {
1607         FIXME("(%p %p)\n",w,x);
1608         return 0xabba1251; /* 0 = failure */
1609 }
1610
1611 /*************************************************************************
1612  *      @       [SHLWAPI.276]
1613  *
1614  */
1615 DWORD WINAPI SHLWAPI_276 ()
1616 {
1617         FIXME("()stub\n");
1618         return /* 0xabba1244 */ 0;
1619 }
1620
1621 /*************************************************************************
1622  *      @       [SHLWAPI.278]
1623  *
1624  */
1625 HWND WINAPI SHLWAPI_278 (
1626         LONG wndProc,
1627         HWND hWndParent,
1628         DWORD dwExStyle,
1629         DWORD dwStyle,
1630         HMENU hMenu,
1631         LONG z)
1632 {
1633         WNDCLASSA wndclass;
1634         HWND hwnd;
1635         HCURSOR hCursor;
1636         char * clsname = "WorkerA";
1637
1638         FIXME("(0x%08lx 0x%08x 0x%08lx 0x%08lx 0x%08x 0x%08lx) partial stub\n",
1639           wndProc,hWndParent,dwExStyle,dwStyle,hMenu,z);
1640
1641         hCursor = LoadCursorA(0x00000000,IDC_ARROWA);
1642
1643         if(!GetClassInfoA(shlwapi_hInstance, clsname, &wndclass))
1644         {
1645           RtlZeroMemory(&wndclass, sizeof(WNDCLASSA));
1646           wndclass.lpfnWndProc = DefWindowProcW;
1647           wndclass.cbWndExtra = 4;
1648           wndclass.hInstance = shlwapi_hInstance;
1649           wndclass.hCursor = hCursor;
1650           wndclass.hbrBackground = COLOR_BTNSHADOW;
1651           wndclass.lpszMenuName = NULL;
1652           wndclass.lpszClassName = clsname;
1653           RegisterClassA (&wndclass);
1654         }
1655         hwnd = CreateWindowExA(dwExStyle, clsname, 0,dwStyle,0,0,0,0,hWndParent,
1656                 hMenu,shlwapi_hInstance,0);
1657         SetWindowLongA(hwnd, 0, z);
1658         SetWindowLongA(hwnd, GWL_WNDPROC, wndProc);
1659         return hwnd;
1660 }
1661
1662 /*************************************************************************
1663  *      @       [SHLWAPI.289]
1664  *
1665  * Late bound call to winmm.PlaySoundW
1666  */
1667 BOOL WINAPI SHLWAPI_289(LPCWSTR pszSound, HMODULE hmod, DWORD fdwSound)
1668 {
1669   static BOOL (WINAPI *pfnFunc)(LPCWSTR, HMODULE, DWORD) = NULL;
1670
1671   GET_FUNC(winmm, "PlaySoundW", FALSE);
1672   return pfnFunc(pszSound, hmod, fdwSound);
1673 }
1674
1675 /*************************************************************************
1676  *      @       [SHLWAPI.294]
1677  */
1678 BOOL WINAPI SHLWAPI_294(LPSTR str1, LPSTR str2, LPSTR pStr, DWORD some_len,  LPCSTR lpStr2)
1679 {
1680     /*
1681      * str1:            "I"     "I"     pushl esp+0x20
1682      * str2:            "U"     "I"     pushl 0x77c93810
1683      * (is "I" and "U" "integer" and "unsigned" ??)
1684      *
1685      * pStr:            ""      ""      pushl eax
1686      * some_len:        0x824   0x104   pushl 0x824
1687      * lpStr2:          "%l"    "%l"    pushl esp+0xc
1688      *
1689      * shlwapi. StrCpyNW(lpStr2, irrelevant_var, 0x104);
1690      * LocalAlloc(0x00, some_len) -> irrelevant_var
1691      * LocalAlloc(0x40, irrelevant_len) -> pStr
1692      * shlwapi.294(str1, str2, pStr, some_len, lpStr2);
1693      * shlwapi.PathRemoveBlanksW(pStr);
1694      */
1695     ERR("('%s', '%s', '%s', %08lx, '%s'): stub!\n", str1, str2, pStr, some_len, lpStr2);
1696     return TRUE;
1697 }
1698
1699 /*************************************************************************
1700  *      @       [SHLWAPI.313]
1701  *
1702  * Late bound call to shell32.SHGetFileInfoW
1703  */
1704 DWORD WINAPI SHLWAPI_313(LPCWSTR path, DWORD dwFileAttributes,
1705                          SHFILEINFOW *psfi, UINT sizeofpsfi, UINT flags)
1706 {
1707   static DWORD (WINAPI *pfnFunc)(LPCWSTR,DWORD,SHFILEINFOW*,UINT,UINT) = NULL;
1708
1709   GET_FUNC(shell32, "SHGetFileInfoW", 0);
1710   return pfnFunc(path, dwFileAttributes, psfi, sizeofpsfi, flags);
1711 }
1712
1713 /*************************************************************************
1714  *      @       [SHLWAPI.318]
1715  *
1716  * Late bound call to shell32.DragQueryFileW
1717  */
1718 UINT WINAPI SHLWAPI_318(HDROP hDrop, UINT lFile, LPWSTR lpszFile, UINT lLength)
1719 {
1720   static UINT (WINAPI *pfnFunc)(HDROP, UINT, LPWSTR, UINT) = NULL;
1721
1722   GET_FUNC(shell32, "DragQueryFileW", 0);
1723   return pfnFunc(hDrop, lFile, lpszFile, lLength);
1724 }
1725
1726 /*************************************************************************
1727  *      @       [SHLWAPI.333]
1728  *
1729  * Late bound call to shell32.SHBrowseForFolderW
1730  */
1731 LPITEMIDLIST WINAPI SHLWAPI_333(LPBROWSEINFOW lpBi)
1732 {
1733   static LPITEMIDLIST (WINAPI *pfnFunc)(LPBROWSEINFOW) = NULL;
1734
1735   GET_FUNC(shell32, "SHBrowseForFolderW", NULL);
1736   return pfnFunc(lpBi);
1737 }
1738
1739 /*************************************************************************
1740  *      @       [SHLWAPI.334]
1741  *
1742  * Late bound call to shell32.SHGetPathFromIDListW
1743  */
1744 BOOL WINAPI SHLWAPI_334(LPCITEMIDLIST pidl,LPWSTR pszPath)
1745 {
1746   static BOOL (WINAPI *pfnFunc)(LPCITEMIDLIST, LPWSTR) = NULL;
1747
1748   GET_FUNC(shell32, "SHGetPathFromIDListW", 0);
1749   return pfnFunc(pidl, pszPath);
1750 }
1751
1752 /*************************************************************************
1753  *      @       [SHLWAPI.335]
1754  *
1755  * Late bound call to shell32.ShellExecuteExW
1756  */
1757 BOOL WINAPI SHLWAPI_335(LPSHELLEXECUTEINFOW lpExecInfo)
1758 {
1759   static BOOL (WINAPI *pfnFunc)(LPSHELLEXECUTEINFOW) = NULL;
1760
1761   GET_FUNC(shell32, "ShellExecuteExW", FALSE);
1762   return pfnFunc(lpExecInfo);
1763 }
1764
1765 /*************************************************************************
1766  *      @       [SHLWAPI.336]
1767  *
1768  * Late bound call to shell32.SHFileOperationW.
1769  */
1770 DWORD WINAPI SHLWAPI_336(LPSHFILEOPSTRUCTW lpFileOp)
1771 {
1772   static HICON (WINAPI *pfnFunc)(LPSHFILEOPSTRUCTW) = NULL;
1773
1774   GET_FUNC(shell32, "SHFileOperationW", 0);
1775   return pfnFunc(lpFileOp);
1776 }
1777
1778 /*************************************************************************
1779  *      @       [SHLWAPI.337]
1780  *
1781  * Late bound call to shell32.ExtractIconExW.
1782  */
1783 HICON WINAPI SHLWAPI_337(LPCWSTR lpszFile, INT nIconIndex, HICON *phiconLarge,
1784                          HICON *phiconSmall, UINT nIcons)
1785 {
1786   static HICON (WINAPI *pfnFunc)(LPCWSTR, INT,HICON *,HICON *, UINT) = NULL;
1787
1788   GET_FUNC(shell32, "ExtractIconExW", (HICON)0);
1789   return pfnFunc(lpszFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
1790 }
1791
1792 /*************************************************************************
1793  *      @       [SHLWAPI.342]
1794  *
1795  */
1796 LONG WINAPI SHLWAPI_342( PLONG dest, LONG xchg, LONG compare)
1797 {
1798         return InterlockedCompareExchange(dest, xchg, compare);
1799 }
1800
1801 /*************************************************************************
1802  *      @       [SHLWAPI.346]
1803  */
1804 DWORD WINAPI SHLWAPI_346 (
1805         LPCWSTR src,
1806         LPWSTR dest,
1807         int len)
1808 {
1809         FIXME("(%s %p 0x%08x)stub\n",debugstr_w(src),dest,len);
1810         lstrcpynW(dest, src, len);
1811         return lstrlenW(dest)+1;
1812 }
1813
1814 /*************************************************************************
1815  *      @       [SHLWAPI.350]
1816  *
1817  * seems to be W interface to GetFileVersionInfoSizeA
1818  */
1819 DWORD WINAPI SHLWAPI_350 (
1820         LPWSTR x,
1821         LPVOID y)
1822 {
1823 static DWORD   WINAPI (*pfnFunc)(LPCSTR,LPDWORD) = NULL;
1824         CHAR mbpath[MAX_PATH];
1825         DWORD ret;
1826
1827         GET_FUNC(version, "GetFileVersionInfoSizeA", 0);
1828         WideCharToMultiByte(0, 0, x, -1, mbpath, MAX_PATH, 0, 0);
1829         ret = pfnFunc(mbpath, y);
1830         return 0x208 + ret;
1831 }
1832
1833 /*************************************************************************
1834  *      @       [SHLWAPI.351]
1835  *
1836  * seems to be W interface to GetFileVersionInfoA
1837  */
1838 BOOL  WINAPI SHLWAPI_351 (
1839         LPWSTR w,   /* [in] path to dll */
1840         DWORD  x,   /* [in] parm 2 to GetFileVersionInfoA */
1841         DWORD  y,   /* [in] return value from .350 - assume length */
1842         LPVOID z)   /* [in/out] buffer (+0x208 sent to GetFileVersionInfoA) */
1843 {
1844         static BOOL    WINAPI (*pfnFunc)(LPCSTR,DWORD,DWORD,LPVOID) = NULL;
1845         CHAR mbpath[MAX_PATH];
1846
1847         GET_FUNC(version, "GetFileVersionInfoA", 0);
1848         WideCharToMultiByte(0, 0, w, -1, mbpath, MAX_PATH, 0, 0);
1849         return pfnFunc(mbpath  , x, y-0x208, z+0x208);
1850 }
1851
1852 /*************************************************************************
1853  *      @       [SHLWAPI.352]
1854  *
1855  * seems to be W interface to VerQueryValueA
1856  */
1857 WORD WINAPI SHLWAPI_352 (
1858         LPVOID w,   /* [in] buffer from _351 */
1859         LPWSTR x,   /* [in]   value to retrieve - 
1860                               converted and passed to VerQueryValueA as #2 */
1861         LPVOID y,   /* [out]  ver buffer - passed to VerQueryValueA as #3 */
1862         UINT*  z)   /* [in]   ver length - passed to VerQueryValueA as #4 */
1863 {
1864         static WORD    WINAPI (*pfnFunc)(LPVOID,LPCSTR,LPVOID*,UINT*) = NULL;
1865         CHAR buf1[MAX_PATH];
1866         WORD ret;
1867
1868         GET_FUNC(version, "VerQueryValueA", 0);
1869         WideCharToMultiByte(0, 0, x, lstrlenW(x)+1, buf1, MAX_PATH, 0, 0);
1870         ret = pfnFunc(w+0x208, buf1, y, z);
1871         if (CompareStringA(GetThreadLocale(), NORM_IGNORECASE, buf1, 1,
1872                            "\\StringFileInfo", 15) == 2 /* CSTR_EQUAL */) {
1873             ERR("Need to translate back to wide - should fail now\n");
1874         }
1875         return ret;
1876 }
1877
1878 /**************************************************************************
1879  *      @       [SHLWAPI.356]
1880  *
1881  *      mbc - this function is undocumented, The parameters are correct and 
1882  *            the calls to InitializeSecurityDescriptor and 
1883  *            SetSecurityDescriptorDacl are correct, but apparently some 
1884  *            apps call this function with all zero parameters. 
1885  */
1886
1887 DWORD WINAPI SHLWAPI_356(PACL pDacl, PSECURITY_DESCRIPTOR pSD, LPCSTR *str)
1888 {
1889   if(str != 0){
1890     *str = 0;
1891   }
1892
1893   if(!pDacl){
1894     return 0;
1895   }
1896
1897   if (!InitializeSecurityDescriptor(pSD, 1)) return 0;
1898   return SetSecurityDescriptorDacl(pSD, 1, pDacl, 0);
1899 }
1900
1901
1902 /*************************************************************************
1903  *      @       [SHLWAPI.357]
1904  *
1905  * Late bound call to shell32.SHGetNewLinkInfoW
1906  */
1907 BOOL WINAPI SHLWAPI_357(LPCWSTR pszLinkTo, LPCWSTR pszDir, LPWSTR pszName,
1908                         BOOL *pfMustCopy, UINT uFlags)
1909 {
1910   static BOOL (WINAPI *pfnFunc)(LPCWSTR, LPCWSTR, LPCWSTR, BOOL*, UINT) = NULL;
1911
1912   GET_FUNC(shell32, "SHGetNewLinkInfoW", FALSE);
1913   return pfnFunc(pszLinkTo, pszDir, pszName, pfMustCopy, uFlags);
1914 }
1915
1916 /*************************************************************************
1917  *      @       [SHLWAPI.358]
1918  *
1919  * Late bound call to shell32.SHDefExtractIconW
1920  */
1921 DWORD WINAPI SHLWAPI_358(LPVOID arg1, LPVOID arg2, LPVOID arg3, LPVOID arg4,
1922                          LPVOID arg5, LPVOID arg6)
1923 {
1924   /* FIXME: Correct args */
1925   static DWORD (WINAPI *pfnFunc)(LPVOID, LPVOID, LPVOID, LPVOID, LPVOID, LPVOID) = NULL;
1926
1927   GET_FUNC(shell32, "SHDefExtractIconW", 0);
1928   return pfnFunc(arg1, arg2, arg3, arg4, arg5, arg6);
1929 }
1930
1931 /*************************************************************************
1932  *      @       [SHLWAPI.364]
1933  *
1934  * Wrapper for lstrcpynA with src and dst swapped.
1935  */
1936 DWORD WINAPI SHLWAPI_364(LPCSTR src, LPSTR dst, INT n)
1937 {
1938   lstrcpynA(dst, src, n);
1939   return TRUE;
1940 }
1941
1942 /*************************************************************************
1943  *      @       [SHLWAPI.370]
1944  *
1945  * Late bound call to shell32.ExtractIconW
1946  */
1947 HICON WINAPI SHLWAPI_370(HINSTANCE hInstance, LPCWSTR lpszExeFileName,
1948                          UINT nIconIndex)
1949 {
1950   static HICON (WINAPI *pfnFunc)(HINSTANCE, LPCWSTR, UINT) = NULL;
1951
1952   GET_FUNC(shell32, "ExtractIconW", (HICON)0);
1953   return pfnFunc(hInstance, lpszExeFileName, nIconIndex);
1954 }
1955
1956 /*************************************************************************
1957  *      @       [SHLWAPI.376]
1958  */
1959 LANGID WINAPI SHLWAPI_376 ()
1960 {
1961     FIXME("() stub\n");
1962     /* FIXME: This should be a forward in the .spec file to the win2k function
1963      * kernel32.GetUserDefaultUILanguage, however that function isn't there yet.
1964      */
1965     return GetUserDefaultLangID();
1966 }
1967
1968 /*************************************************************************
1969  *      @       [SHLWAPI.377]
1970  *
1971  * FIXME: Native appears to do DPA_Create and a DPA_InsertPtr for 
1972  *        each call here.
1973  * FIXME: Native shows calls to:
1974  *  SHRegGetUSValue for "Software\Microsoft\Internet Explorer\International"
1975  *                      CheckVersion
1976  *  RegOpenKeyExA for "HKLM\Software\Microsoft\Internet Explorer"
1977  *  RegQueryValueExA for "LPKInstalled"
1978  *  RegCloseKey
1979  *  RegOpenKeyExA for "HKCU\Software\Microsoft\Internet Explorer\International"
1980  *  RegQueryValueExA for "ResourceLocale"
1981  *  RegCloseKey
1982  *  RegOpenKeyExA for "HKLM\Software\Microsoft\Active Setup\Installed Components\{guid}"
1983  *  RegQueryValueExA for "Locale"
1984  *  RegCloseKey
1985  *  and then tests the Locale ("en" for me).
1986  *     code below
1987  *  after the code then a DPA_Create (first time) and DPA_InsertPtr are done.
1988  */
1989 DWORD WINAPI SHLWAPI_377 (LPCSTR new_mod, HMODULE inst_hwnd, LPVOID z)
1990 {
1991     CHAR mod_path[2*MAX_PATH];
1992     LPSTR ptr;
1993
1994     GetModuleFileNameA(inst_hwnd, mod_path, 2*MAX_PATH);
1995     ptr = strrchr(mod_path, '\\');
1996     if (ptr) {
1997         strcpy(ptr+1, new_mod);
1998         TRACE("loading %s\n", debugstr_a(mod_path));
1999         return (DWORD)LoadLibraryA(mod_path);
2000     }
2001     return 0;
2002 }
2003
2004 /*************************************************************************
2005  *      @       [SHLWAPI.378]
2006  *
2007  *  This is Unicode version of .377
2008  */
2009 DWORD WINAPI SHLWAPI_378 (
2010         LPCWSTR   new_mod,          /* [in] new module name        */
2011         HMODULE   inst_hwnd,        /* [in] calling module handle  */
2012         LPVOID z)                   /* [???] 4 */
2013 {
2014     WCHAR mod_path[2*MAX_PATH];
2015     LPWSTR ptr;
2016
2017     GetModuleFileNameW(inst_hwnd, mod_path, 2*MAX_PATH);
2018     ptr = strrchrW(mod_path, '\\');
2019     if (ptr) {
2020         strcpyW(ptr+1, new_mod);
2021         TRACE("loading %s\n", debugstr_w(mod_path));
2022         return (DWORD)LoadLibraryW(mod_path);
2023     }
2024     return 0;
2025 }
2026
2027 /*************************************************************************
2028  *      @       [SHLWAPI.389]
2029  *
2030  * Late bound call to comdlg32.GetSaveFileNameW
2031  */
2032 BOOL WINAPI SHLWAPI_389(LPOPENFILENAMEW ofn)
2033 {
2034   static BOOL (WINAPI *pfnFunc)(LPOPENFILENAMEW) = NULL;
2035
2036   GET_FUNC(comdlg32, "GetSaveFileNameW", FALSE);
2037   return pfnFunc(ofn);
2038 }
2039
2040 /*************************************************************************
2041  *      @       [SHLWAPI.390]
2042  *
2043  * Late bound call to mpr.WNetRestoreConnectionW
2044  */
2045 DWORD WINAPI SHLWAPI_390(LPVOID arg1, LPVOID arg2)
2046 {
2047   /* FIXME: Correct args */
2048   static DWORD (WINAPI *pfnFunc)(LPVOID, LPVOID) = NULL;
2049
2050   GET_FUNC(mpr, "WNetRestoreConnectionW", 0);
2051   return pfnFunc(arg1, arg2);
2052 }
2053
2054 /*************************************************************************
2055  *      @       [SHLWAPI.391]
2056  *
2057  * Late bound call to mpr.WNetGetLastErrorW
2058  */
2059 DWORD WINAPI SHLWAPI_391(LPVOID arg1, LPVOID arg2, LPVOID arg3, LPVOID arg4,
2060                          LPVOID arg5)
2061 {
2062   /* FIXME: Correct args */
2063   static DWORD (WINAPI *pfnFunc)(LPVOID, LPVOID, LPVOID, LPVOID, LPVOID) = NULL;
2064
2065   GET_FUNC(mpr, "WNetGetLastErrorW", 0);
2066   return pfnFunc(arg1, arg2, arg3, arg4, arg5);
2067 }
2068
2069 /*************************************************************************
2070  *      @       [SHLWAPI.401]
2071  *
2072  * Late bound call to comdlg32.PageSetupDlgW
2073  */
2074 BOOL WINAPI SHLWAPI_401(LPPAGESETUPDLGW pagedlg)
2075 {
2076   static BOOL (WINAPI *pfnFunc)(LPPAGESETUPDLGW) = NULL;
2077
2078   GET_FUNC(comdlg32, "PageSetupDlgW", FALSE);
2079   return pfnFunc(pagedlg);
2080 }
2081
2082 /*************************************************************************
2083  *      @       [SHLWAPI.402]
2084  *
2085  * Late bound call to comdlg32.PrintDlgW
2086  */
2087 BOOL WINAPI SHLWAPI_402(LPPRINTDLGW printdlg)
2088 {
2089   static BOOL (WINAPI *pfnFunc)(LPPRINTDLGW) = NULL;
2090
2091   GET_FUNC(comdlg32, "PrintDlgW", FALSE);
2092   return pfnFunc(printdlg);
2093 }
2094
2095 /*************************************************************************
2096  *      @       [SHLWAPI.403]
2097  *
2098  * Late bound call to comdlg32.GetOpenFileNameW
2099  */
2100 BOOL WINAPI SHLWAPI_403(LPOPENFILENAMEW ofn)
2101 {
2102   static BOOL (WINAPI *pfnFunc)(LPOPENFILENAMEW) = NULL;
2103
2104   GET_FUNC(comdlg32, "GetOpenFileNameW", FALSE);
2105   return pfnFunc(ofn);
2106 }
2107
2108 /* INTERNAL: Map from HLS color space to RGB */
2109 static WORD ConvertHue(int wHue, WORD wMid1, WORD wMid2)
2110 {
2111   wHue = wHue > 240 ? wHue - 240 : wHue < 0 ? wHue + 240 : wHue;
2112
2113   if (wHue > 160)
2114     return wMid1;
2115   else if (wHue > 120)
2116     wHue = 160 - wHue;
2117   else if (wHue > 40)
2118     return wMid2;
2119
2120   return ((wHue * (wMid2 - wMid1) + 20) / 40) + wMid1;
2121 }
2122
2123 /* Convert to RGB and scale into RGB range (0..255) */
2124 #define GET_RGB(h) (ConvertHue(h, wMid1, wMid2) * 255 + 120) / 240
2125
2126 /*************************************************************************
2127  *      ColorHLSToRGB   [SHLWAPI.404]
2128  *
2129  * Convert from HLS color space into an RGB COLORREF.
2130  *
2131  * NOTES
2132  * Input HLS values are constrained to the range (0..240).
2133  */
2134 COLORREF WINAPI ColorHLSToRGB(WORD wHue, WORD wLuminosity, WORD wSaturation)
2135 {
2136   WORD wRed;
2137
2138   if (wSaturation)
2139   {
2140     WORD wGreen, wBlue, wMid1, wMid2;
2141
2142     if (wLuminosity > 120)
2143       wMid2 = wSaturation + wLuminosity - (wSaturation * wLuminosity + 120) / 240;
2144     else
2145       wMid2 = ((wSaturation + 240) * wLuminosity + 120) / 240;
2146
2147     wMid1 = wLuminosity * 2 - wMid2;
2148
2149     wRed   = GET_RGB(wHue + 80);
2150     wGreen = GET_RGB(wHue);
2151     wBlue  = GET_RGB(wHue - 80);
2152
2153     return RGB(wRed, wGreen, wBlue);
2154   }
2155
2156   wRed = wLuminosity * 255 / 240;
2157   return RGB(wRed, wRed, wRed);
2158 }
2159
2160 /*************************************************************************
2161  *      @       [SHLWAPI.413]
2162  *
2163  * Function unknown seems to always to return 0
2164  */
2165 DWORD WINAPI SHLWAPI_413 (DWORD x)
2166 {
2167         FIXME("(0x%08lx)stub\n", x);
2168         return 0;
2169 }
2170
2171 /*************************************************************************
2172  *      @       [SHLWAPI.418]
2173  *
2174  * Function seems to do FreeLibrary plus other things.
2175  *
2176  * FIXME native shows the following calls:
2177  *   RtlEnterCriticalSection
2178  *   LocalFree
2179  *   GetProcAddress(Comctl32??, 150L)
2180  *   DPA_DeletePtr
2181  *   RtlLeaveCriticalSection
2182  *  followed by the FreeLibrary.
2183  *  The above code may be related to .377 above.
2184  */
2185 BOOL  WINAPI SHLWAPI_418 (HMODULE x)
2186 {
2187         FIXME("(0x%08lx) partial stub\n", (LONG)x);
2188         return FreeLibrary(x);
2189 }
2190
2191 /*************************************************************************
2192  *      @       [SHLWAPI.431]
2193  */
2194 DWORD WINAPI SHLWAPI_431 (DWORD x)
2195 {
2196         FIXME("(0x%08lx)stub\n", x);
2197         return 0xabba1247;
2198 }
2199
2200 /*************************************************************************
2201  *      @       [SHLWAPI.436]
2202  *
2203  *  This is really CLSIDFromString which is exported by ole32.dll,
2204  *  however the native shlwapi.dll does *not* import ole32. Nor does
2205  *  ole32.dll import this ordinal from shlwapi. Therefore we must conclude
2206  *  that MS duplicated the code for CLSIDFromString.
2207  *
2208  *  This is a duplicate (with changes for UNICODE) of CLSIDFromString16
2209  *  in dlls/ole32/compobj.c
2210  */
2211 DWORD WINAPI SHLWAPI_436 (LPWSTR idstr, CLSID *id)
2212 {
2213     LPWSTR s = idstr;
2214     BYTE *p;
2215     INT i;
2216     WCHAR table[256];
2217
2218     if (!s) {
2219         memset(s, 0, sizeof(CLSID));
2220         return S_OK;
2221     }
2222     else {  /* validate the CLSID string */
2223
2224         if (strlenW(s) != 38)
2225             return CO_E_CLASSSTRING;
2226
2227         if ((s[0]!=L'{') || (s[9]!=L'-') || (s[14]!=L'-') || (s[19]!=L'-') || (s[24]!=L'-') || (s[37]!=L'}'))
2228             return CO_E_CLASSSTRING;
2229
2230         for (i=1; i<37; i++)
2231             {
2232                 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
2233                 if (!(((s[i] >= L'0') && (s[i] <= L'9'))  ||
2234                       ((s[i] >= L'a') && (s[i] <= L'f'))  ||
2235                       ((s[i] >= L'A') && (s[i] <= L'F')))
2236                     )
2237                     return CO_E_CLASSSTRING;
2238             }
2239     }
2240
2241     TRACE("%s -> %p\n", debugstr_w(s), id);
2242
2243   /* quick lookup table */
2244     memset(table, 0, 256*sizeof(WCHAR));
2245
2246     for (i = 0; i < 10; i++) {
2247         table['0' + i] = i;
2248     }
2249     for (i = 0; i < 6; i++) {
2250         table['A' + i] = i+10;
2251         table['a' + i] = i+10;
2252     }
2253
2254     /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
2255
2256     p = (BYTE *) id;
2257
2258     s++;        /* skip leading brace  */
2259     for (i = 0; i < 4; i++) {
2260         p[3 - i] = table[*s]<<4 | table[*(s+1)];
2261         s += 2;
2262     }
2263     p += 4;
2264     s++;        /* skip - */
2265
2266     for (i = 0; i < 2; i++) {
2267         p[1-i] = table[*s]<<4 | table[*(s+1)];
2268         s += 2;
2269     }
2270     p += 2;
2271     s++;        /* skip - */
2272
2273     for (i = 0; i < 2; i++) {
2274         p[1-i] = table[*s]<<4 | table[*(s+1)];
2275         s += 2;
2276     }
2277     p += 2;
2278     s++;        /* skip - */
2279
2280     /* these are just sequential bytes */
2281     for (i = 0; i < 2; i++) {
2282         *p++ = table[*s]<<4 | table[*(s+1)];
2283         s += 2;
2284     }
2285     s++;        /* skip - */
2286
2287     for (i = 0; i < 6; i++) {
2288         *p++ = table[*s]<<4 | table[*(s+1)];
2289         s += 2;
2290     }
2291
2292     return S_OK;
2293 }
2294
2295 /*************************************************************************
2296  *      @       [SHLWAPI.437]
2297  *
2298  * NOTES
2299  *  In the real shlwapi, One time initialisation calls GetVersionEx and reads
2300  *  the registry to determine what O/S & Service Pack level is running, and
2301  *  therefore which functions are available. Currently we always run as NT,
2302  *  since this means that we don't need extra code to emulate Unicode calls,
2303  *  they are forwarded directly to the appropriate API call instead.
2304  *  Since the flags for whether to call or emulate Unicode are internal to
2305  *  the dll, this function does not need a full implementation.
2306  */
2307 DWORD WINAPI SHLWAPI_437 (DWORD functionToCall)
2308 {
2309         FIXME("(0x%08lx)stub\n", functionToCall);
2310         return /* 0xabba1247 */ 0;
2311 }
2312
2313 /*************************************************************************
2314  *      ColorRGBToHLS   [SHLWAPI.445]
2315  *
2316  * Convert from RGB COLORREF into the HLS color space.
2317  *
2318  * NOTES
2319  * Input HLS values are constrained to the range (0..240).
2320  */
2321 VOID WINAPI ColorRGBToHLS(COLORREF drRGB, LPWORD pwHue, 
2322                           LPWORD wLuminance, LPWORD pwSaturation)
2323 {
2324     FIXME("stub\n");
2325     return;
2326 }
2327
2328 /*************************************************************************
2329  *      SHCreateShellPalette    [SHLWAPI.@]
2330  */
2331 HPALETTE WINAPI SHCreateShellPalette(HDC hdc)
2332 {
2333         FIXME("stub\n");
2334         return CreateHalftonePalette(hdc);
2335 }
2336
2337 /*************************************************************************
2338  *      SHGetInverseCMAP (SHLWAPI.@)
2339  */
2340 DWORD WINAPI SHGetInverseCMAP (LPDWORD* x, DWORD why)
2341 {
2342     if (why == 4) {
2343         FIXME(" - returning bogus address for SHGetInverseCMAP\n");
2344         *x = (LPDWORD)0xabba1249;
2345         return 0;
2346     }
2347     FIXME("(%p, %#lx)stub\n", x, why);
2348     return 0;
2349 }
2350
2351 /*************************************************************************
2352  *      SHIsLowMemoryMachine    [SHLWAPI.@]
2353  */
2354 DWORD WINAPI SHIsLowMemoryMachine (DWORD x)
2355 {
2356         FIXME("0x%08lx\n", x);
2357         return 0;
2358 }
2359
2360 /*************************************************************************
2361  *      GetMenuPosFromID        [SHLWAPI.@]
2362  */
2363 INT WINAPI GetMenuPosFromID(HMENU hMenu, UINT wID)
2364 {
2365  MENUITEMINFOA mi;
2366  INT nCount = GetMenuItemCount(hMenu), nIter = 0;
2367
2368  while (nIter < nCount)
2369  {
2370    mi.wID = 0;
2371    if (!GetMenuItemInfoA(hMenu, nIter, TRUE, &mi) && mi.wID == wID)
2372      return nIter;
2373    nIter++;
2374  }
2375  return -1;
2376 }
2377
2378 /*************************************************************************
2379  *      _SHGetInstanceExplorer@4        [SHLWAPI.@]
2380  *
2381  * Late bound call to shell32.SHGetInstanceExplorer.
2382  */
2383 HRESULT WINAPI _SHGetInstanceExplorer (LPUNKNOWN *lpUnknown)
2384 {
2385   static HRESULT (WINAPI *pfnFunc)(LPUNKNOWN *) = NULL;
2386
2387   GET_FUNC(shell32, "SHGetInstanceExplorer", E_FAIL);
2388   return pfnFunc(lpUnknown);
2389 }
2390
2391 /*************************************************************************
2392  *      SHGetThreadRef  [SHLWAPI.@]
2393  *
2394  * Retrieves the per-thread object reference set by SHSetThreadRef
2395  * "punk" - Address of a pointer to the IUnknown interface. Returns S_OK if
2396  *          successful or E_NOINTERFACE otherwise.
2397  */
2398 HRESULT WINAPI SHGetThreadRef (IUnknown ** ppunk)
2399 {
2400     if (SHLWAPI_ThreadRef_index < 0) return E_NOINTERFACE;
2401     *ppunk = (IUnknown *)TlsGetValue(SHLWAPI_ThreadRef_index);
2402     return S_OK;
2403 }
2404
2405 /*************************************************************************
2406  *      SHSetThreadRef  [SHLWAPI.@]
2407  *
2408  * Stores a per-thread reference to a COM object
2409  * "punk" - Pointer to the IUnknown interface of the object to
2410  *          which you want to store a reference. Returns S_OK if successful
2411  *          or an OLE error value.
2412  */
2413 HRESULT WINAPI SHSetThreadRef (IUnknown * punk)
2414 {
2415     if (SHLWAPI_ThreadRef_index < 0) return E_NOINTERFACE;
2416     TlsSetValue(SHLWAPI_ThreadRef_index, (LPVOID) punk);
2417     return S_OK;
2418 }