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