Sync to Wine-20050725:
[reactos.git] / reactos / lib / shlwapi / ordinal.c
index 99a1821..530b57c 100644 (file)
 #include <stdio.h>
 #include <string.h>
 
+#define COBJMACROS
 #define NONAMELESSUNION
 #define NONAMELESSSTRUCT
+
 #include "windef.h"
 #include "winbase.h"
 #include "winuser.h"
 #include "winnls.h"
-#include "ddeml.h"
+#include "objbase.h"
 #include "docobj.h"
 #include "exdisp.h"
 #include "shlguid.h"
 #include "wingdi.h"
 #include "shlobj.h"
-#include "olectl.h"
 #include "shellapi.h"
 #include "commdlg.h"
 #include "wine/unicode.h"
-#include "servprov.h"
 #include "winreg.h"
-#include "winuser.h"
 #include "wine/debug.h"
 #include "shlwapi.h"
 
@@ -70,14 +69,11 @@ extern HMODULE SHLWAPI_hwinmm;
 extern HMODULE SHLWAPI_hcomdlg32;
 extern HMODULE SHLWAPI_hcomctl32;
 extern HMODULE SHLWAPI_hmpr;
-extern HMODULE SHLWAPI_hmlang;
 extern HMODULE SHLWAPI_hurlmon;
 extern HMODULE SHLWAPI_hversion;
 
 extern DWORD SHLWAPI_ThreadRef_index;
 
-typedef HANDLE HSHARED; /* Shared memory */
-
 /* following is GUID for IObjectWithSite::SetSite  -- see _174           */
 static DWORD id1[4] = {0xfc4801a3, 0x11cf2ba9, 0xaa0029a2, 0x52733d00};
 /* following is GUID for IPersistMoniker::GetClassID  -- see _174        */
@@ -86,8 +82,6 @@ static DWORD id2[4] = {0x79eac9ee, 0x11cebaf9, 0xaa00828c, 0x0ba94b00};
 /* Function pointers for GET_FUNC macro; these need to be global because of gcc bug */
 typedef LPITEMIDLIST (WINAPI *fnpSHBrowseForFolderW)(LPBROWSEINFOW);
 static  fnpSHBrowseForFolderW pSHBrowseForFolderW;
-typedef HRESULT (WINAPI *fnpConvertINetUnicodeToMultiByte)(LPDWORD,DWORD,LPCWSTR,LPINT,LPSTR,LPINT);
-static  fnpConvertINetUnicodeToMultiByte pConvertINetUnicodeToMultiByte;
 typedef BOOL    (WINAPI *fnpPlaySoundW)(LPCWSTR, HMODULE, DWORD);
 static  fnpPlaySoundW pPlaySoundW;
 typedef DWORD   (WINAPI *fnpSHGetFileInfoW)(LPCWSTR,DWORD,SHFILEINFOW*,UINT,UINT);
@@ -145,8 +139,8 @@ BOOL    WINAPI SHAboutInfoW(LPWSTR,DWORD);
  The reason for these functions to be there is to provide a wrapper
  for unicode functions to provide these functions on systems without
  unicode functions eg. win95/win98. Since we have such functions we just
- call these. If running Wine with native DLL's, some late bound calls may
- fail. However, its better to implement the functions in the forward DLL
+ call these. If running Wine with native DLLs, some late bound calls may
+ fail. However, it is better to implement the functions in the forward DLL
  and recommend the builtin rather than reimplementing the calls here!
 */
 
@@ -156,15 +150,15 @@ BOOL    WINAPI SHAboutInfoW(LPWSTR,DWORD);
  * Internal implemetation of SHLWAPI_11.
  */
 static
-HSHARED WINAPI SHLWAPI_DupSharedHandle(HSHARED hShared, DWORD dwDstProcId,
+HANDLE WINAPI SHLWAPI_DupSharedHandle(HANDLE hShared, DWORD dwDstProcId,
                                        DWORD dwSrcProcId, DWORD dwAccess,
                                        DWORD dwOptions)
 {
   HANDLE hDst, hSrc;
   DWORD dwMyProcId = GetCurrentProcessId();
-  HSHARED hRet = (HSHARED)NULL;
+  HANDLE hRet = NULL;
 
-  TRACE("(%p,%ld,%ld,%08lx,%08lx)\n", (PVOID)hShared, dwDstProcId, dwSrcProcId,
+  TRACE("(%p,%ld,%ld,%08lx,%08lx)\n", hShared, dwDstProcId, dwSrcProcId,
         dwAccess, dwOptions);
 
   /* Get dest process handle */
@@ -184,9 +178,9 @@ HSHARED WINAPI SHLWAPI_DupSharedHandle(HSHARED hShared, DWORD dwDstProcId,
     if (hSrc)
     {
       /* Make handle available to dest process */
-      if (!DuplicateHandle(hDst, (HANDLE)hShared, hSrc, &hRet,
+      if (!DuplicateHandle(hDst, hShared, hSrc, &hRet,
                            dwAccess, 0, dwOptions | DUPLICATE_SAME_ACCESS))
-        hRet = (HSHARED)NULL;
+        hRet = NULL;
 
       if (dwSrcProcId != dwMyProcId)
         CloseHandle(hSrc);
@@ -196,7 +190,7 @@ HSHARED WINAPI SHLWAPI_DupSharedHandle(HSHARED hShared, DWORD dwDstProcId,
       CloseHandle(hDst);
   }
 
-  TRACE("Returning handle %p\n", (PVOID)hRet);
+  TRACE("Returning handle %p\n", hRet);
   return hRet;
 }
 
@@ -206,9 +200,9 @@ HSHARED WINAPI SHLWAPI_DupSharedHandle(HSHARED hShared, DWORD dwDstProcId,
  * Create a block of sharable memory and initialise it with data.
  *
  * PARAMS
- * dwProcId [I] ID of process owning data
  * lpvData  [I] Pointer to data to write
  * dwSize   [I] Size of data
+ * dwProcId [I] ID of process owning data
  *
  * RETURNS
  * Success: A shared memory handle
@@ -222,13 +216,13 @@ HSHARED WINAPI SHLWAPI_DupSharedHandle(HSHARED hShared, DWORD dwDstProcId,
  * the view pointer returned by this size.
  *
  */
-HSHARED WINAPI SHAllocShared(DWORD dwProcId, DWORD dwSize, LPCVOID lpvData)
+HANDLE WINAPI SHAllocShared(LPCVOID lpvData, DWORD dwSize, DWORD dwProcId)
 {
   HANDLE hMap;
   LPVOID pMapped;
-  HSHARED hRet = (HSHARED)NULL;
+  HANDLE hRet = NULL;
 
-  TRACE("(%ld,%p,%ld)\n", dwProcId, lpvData, dwSize);
+  TRACE("(%p,%ld,%ld)\n", lpvData, dwSize, dwProcId);
 
   /* Create file mapping of the correct length */
   hMap = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, FILE_MAP_READ, 0,
@@ -243,12 +237,12 @@ HSHARED WINAPI SHAllocShared(DWORD dwProcId, DWORD dwSize, LPCVOID lpvData)
   {
     /* Write size of data, followed by the data, to the view */
     *((DWORD*)pMapped) = dwSize;
-    if (dwSize)
+    if (lpvData)
       memcpy((char *) pMapped + sizeof(dwSize), lpvData, dwSize);
 
     /* Release view. All further views mapped will be opaque */
     UnmapViewOfFile(pMapped);
-    hRet = SHLWAPI_DupSharedHandle((HSHARED)hMap, dwProcId,
+    hRet = SHLWAPI_DupSharedHandle(hMap, dwProcId,
                                    GetCurrentProcessId(), FILE_MAP_ALL_ACCESS,
                                    DUPLICATE_SAME_ACCESS);
   }
@@ -271,18 +265,18 @@ HSHARED WINAPI SHAllocShared(DWORD dwProcId, DWORD dwSize, LPCVOID lpvData)
  * Failure: NULL
  *
  */
-PVOID WINAPI SHLockShared(HSHARED hShared, DWORD dwProcId)
+PVOID WINAPI SHLockShared(HANDLE hShared, DWORD dwProcId)
 {
-  HSHARED hDup;
+  HANDLE hDup;
   LPVOID pMapped;
 
-  TRACE("(%p %ld)\n", (PVOID)hShared, dwProcId);
+  TRACE("(%p %ld)\n", hShared, dwProcId);
 
   /* Get handle to shared memory for current process */
   hDup = SHLWAPI_DupSharedHandle(hShared, dwProcId, GetCurrentProcessId(),
                                  FILE_MAP_ALL_ACCESS, 0);
   /* Get View */
-  pMapped = MapViewOfFile((HANDLE)hDup, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
+  pMapped = MapViewOfFile(hDup, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
   CloseHandle(hDup);
 
   if (pMapped)
@@ -323,17 +317,17 @@ BOOL WINAPI SHUnlockShared(LPVOID lpView)
  * Failure: FALSE
  *
  */
-BOOL WINAPI SHFreeShared(HSHARED hShared, DWORD dwProcId)
+BOOL WINAPI SHFreeShared(HANDLE hShared, DWORD dwProcId)
 {
-  HSHARED hClose;
+  HANDLE hClose;
 
-  TRACE("(%p %ld)\n", (PVOID)hShared, dwProcId);
+  TRACE("(%p %ld)\n", hShared, dwProcId);
 
   /* Get a copy of the handle for our process, closing the source handle */
   hClose = SHLWAPI_DupSharedHandle(hShared, dwProcId, GetCurrentProcessId(),
                                    FILE_MAP_ALL_ACCESS,DUPLICATE_CLOSE_SOURCE);
   /* Close local copy */
-  return CloseHandle((HANDLE)hClose);
+  return CloseHandle(hClose);
 }
 
 /*************************************************************************
@@ -353,10 +347,10 @@ BOOL WINAPI SHFreeShared(HSHARED hShared, DWORD dwProcId)
  * Failure: A NULL handle.
  *
  */
-HSHARED WINAPI SHMapHandle(HSHARED hShared, DWORD dwDstProcId, DWORD dwSrcProcId,
+HANDLE WINAPI SHMapHandle(HANDLE hShared, DWORD dwDstProcId, DWORD dwSrcProcId,
                           DWORD dwAccess, DWORD dwOptions)
 {
-  HSHARED hRet;
+  HANDLE hRet;
 
   hRet = SHLWAPI_DupSharedHandle(hShared, dwDstProcId, dwSrcProcId,
                                  dwAccess, dwOptions);
@@ -523,109 +517,99 @@ RegisterDefaultAcceptHeaders_Exit:
 }
 
 /*************************************************************************
- *      @      [SHLWAPI.14]
+ *      @      [SHLWAPI.15]
  *
  * Get Explorers "AcceptLanguage" setting.
  *
  * PARAMS
  *  langbuf [O] Destination for language string
  *  buflen  [I] Length of langbuf
+ *          [0] Success: used length of langbuf
  *
  * RETURNS
  *  Success: S_OK.   langbuf is set to the language string found.
  *  Failure: E_FAIL, If any arguments are invalid, error occurred, or Explorer
  *           does not contain the setting.
- */
-HRESULT WINAPI GetAcceptLanguagesA(
-       LPSTR langbuf,
-       LPDWORD buflen)
-{
-       CHAR *mystr;
-       DWORD mystrlen, mytype;
-       HKEY mykey;
-       LCID mylcid;
-
-       mystrlen = (*buflen > 6) ? *buflen : 6;
-       mystr = (CHAR*)HeapAlloc(GetProcessHeap(),
-                                HEAP_ZERO_MEMORY, mystrlen);
-       RegOpenKeyA(HKEY_CURRENT_USER,
-                   "Software\\Microsoft\\Internet Explorer\\International",
-                   &mykey);
-       if (RegQueryValueExA(mykey, "AcceptLanguage",
-                             0, &mytype, (PBYTE)mystr, &mystrlen)) {
-           /* Did not find value */
-           mylcid = GetUserDefaultLCID();
-           /* somehow the mylcid translates into "en-us"
-            *  this is similar to "LOCALE_SABBREVLANGNAME"
-            *  which could be gotten via GetLocaleInfo.
-            *  The only problem is LOCALE_SABBREVLANGUAGE" is
-            *  a 3 char string (first 2 are country code and third is
-            *  letter for "sublanguage", which does not come close to
-            *  "en-us"
-            */
-           lstrcpyA(mystr, "en-us");
-           mystrlen = lstrlenA(mystr);
-       }
-       else {
-           /* handle returned string */
-           FIXME("missing code\n");
-       }
-       if (mystrlen > *buflen)
-           lstrcpynA(langbuf, mystr, *buflen);
-       else {
-           lstrcpyA(langbuf, mystr);
-           *buflen = lstrlenA(langbuf);
-       }
-       RegCloseKey(mykey);
-       HeapFree(GetProcessHeap(), 0, mystr);
-       TRACE("language is %s\n", debugstr_a(langbuf));
-       return 0;
+ *           E_INVALIDARG, If the buffer is not big enough
+ */
+HRESULT WINAPI GetAcceptLanguagesW( LPWSTR langbuf, LPDWORD buflen)
+{
+    static const WCHAR szkeyW[] = {
+       'S','o','f','t','w','a','r','e','\\',
+       'M','i','c','r','o','s','o','f','t','\\',
+       'I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r','\\',
+       'I','n','t','e','r','n','a','t','i','o','n','a','l',0};
+    static const WCHAR valueW[] = {
+       'A','c','c','e','p','t','L','a','n','g','u','a','g','e',0};
+    static const WCHAR enusW[] = {'e','n','-','u','s',0};
+    DWORD mystrlen, mytype;
+    HKEY mykey;
+    HRESULT retval;
+    LCID mylcid;
+    WCHAR *mystr;
+
+    if(!langbuf || !buflen || !*buflen)
+       return E_FAIL;
+
+    mystrlen = (*buflen > 20) ? *buflen : 20 ;
+    mystr = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * mystrlen);
+    RegOpenKeyW(HKEY_CURRENT_USER, szkeyW, &mykey);
+    if(RegQueryValueExW(mykey, valueW, 0, &mytype, (PBYTE)mystr, &mystrlen)) {
+        /* Did not find value */
+        mylcid = GetUserDefaultLCID();
+        /* somehow the mylcid translates into "en-us"
+         *  this is similar to "LOCALE_SABBREVLANGNAME"
+         *  which could be gotten via GetLocaleInfo.
+         *  The only problem is LOCALE_SABBREVLANGUAGE" is
+         *  a 3 char string (first 2 are country code and third is
+         *  letter for "sublanguage", which does not come close to
+         *  "en-us"
+         */
+        lstrcpyW(mystr, enusW);
+        mystrlen = lstrlenW(mystr);
+    } else {
+        /* handle returned string */
+        FIXME("missing code\n");
+    }
+    memcpy( langbuf, mystr, min(*buflen,strlenW(mystr)+1)*sizeof(WCHAR) );
+
+    if(*buflen > strlenW(mystr)) {
+       *buflen = strlenW(mystr);
+       retval = S_OK;
+    } else {
+       *buflen = 0;
+       retval = E_INVALIDARG;
+       SetLastError(ERROR_INSUFFICIENT_BUFFER);
+    }
+    RegCloseKey(mykey);
+    HeapFree(GetProcessHeap(), 0, mystr);
+    return retval;
 }
 
 /*************************************************************************
- *      @      [SHLWAPI.15]
+ *      @      [SHLWAPI.14]
  *
- * Unicode version of SHLWAPI_14.
- */
-HRESULT WINAPI GetAcceptLanguagesW(
-       LPWSTR langbuf,
-       LPDWORD buflen)
-{
-       CHAR *mystr;
-       DWORD mystrlen, mytype;
-       HKEY mykey;
-       LCID mylcid;
-
-       mystrlen = (*buflen > 6) ? *buflen : 6;
-       mystr = (CHAR*)HeapAlloc(GetProcessHeap(),
-                                HEAP_ZERO_MEMORY, mystrlen);
-       RegOpenKeyA(HKEY_CURRENT_USER,
-                   "Software\\Microsoft\\Internet Explorer\\International",
-                   &mykey);
-       if (RegQueryValueExA(mykey, "AcceptLanguage",
-                             0, &mytype, (PBYTE)mystr, &mystrlen)) {
-           /* Did not find value */
-           mylcid = GetUserDefaultLCID();
-           /* somehow the mylcid translates into "en-us"
-            *  this is similar to "LOCALE_SABBREVLANGNAME"
-            *  which could be gotten via GetLocaleInfo.
-            *  The only problem is LOCALE_SABBREVLANGUAGE" is
-            *  a 3 char string (first 2 are country code and third is
-            *  letter for "sublanguage", which does not come close to
-            *  "en-us"
-            */
-           lstrcpyA(mystr, "en-us");
-           mystrlen = lstrlenA(mystr);
-       }
-       else {
-           /* handle returned string */
-           FIXME("missing code\n");
-       }
-       RegCloseKey(mykey);
-       *buflen = MultiByteToWideChar(0, 0, mystr, -1, langbuf, (*buflen)-1);
-       HeapFree(GetProcessHeap(), 0, mystr);
-       TRACE("language is %s\n", debugstr_w(langbuf));
-       return 0;
+ * Ascii version of GetAcceptLanguagesW.
+ */
+HRESULT WINAPI GetAcceptLanguagesA( LPSTR langbuf, LPDWORD buflen)
+{
+    WCHAR *langbufW;
+    DWORD buflenW, convlen;
+    HRESULT retval;
+
+    if(!langbuf || !buflen || !*buflen) return E_FAIL;
+
+    buflenW = *buflen;
+    langbufW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * buflenW);
+    retval = GetAcceptLanguagesW(langbufW, &buflenW);
+
+    /* FIXME: this is wrong, the string may not be null-terminated */
+    convlen = WideCharToMultiByte(CP_ACP, 0, langbufW, -1, langbuf,
+                                  *buflen, NULL, NULL);
+    *buflen = buflenW ? convlen : 0;
+
+    HeapFree(GetProcessHeap(), 0, langbufW);
+    return retval;
 }
 
 /*************************************************************************
@@ -634,9 +618,9 @@ HRESULT WINAPI GetAcceptLanguagesW(
  * Convert a GUID to a string.
  *
  * PARAMS
- *  guid [I] GUID to convert
- *  str  [O] Destination for string
- *  cmax [I] Length of output buffer
+ *  guid     [I] GUID to convert
+ *  lpszDest [O] Destination for string
+ *  cchMax   [I] Length of output buffer
  *
  * RETURNS
  *  The length of the string created.
@@ -664,84 +648,36 @@ INT WINAPI SHStringFromGUIDA(REFGUID guid, LPSTR lpszDest, INT cchMax)
 /*************************************************************************
  *      @      [SHLWAPI.24]
  *
- * Unicode version of SHStringFromGUIDA.
- */
-INT WINAPI SHStringFromGUIDW(REFGUID guid, LPWSTR lpszDest, INT cchMax)
-{
-  char xguid[40];
-  INT iLen = SHStringFromGUIDA(guid, xguid, cchMax);
-  
-  if (iLen)
-    MultiByteToWideChar(CP_ACP, 0, xguid, -1, lpszDest, cchMax);
-  return iLen;
-}
-
-/*************************************************************************
- *      @      [SHLWAPI.25]
- *
- * Determine if a Unicode character is alphabetic.
+ * Convert a GUID to a string.
  *
  * PARAMS
- *  wc [I] Character to check.
+ *  guid [I] GUID to convert
+ *  str  [O] Destination for string
+ *  cmax [I] Length of output buffer
  *
  * RETURNS
- *  TRUE, if wc is alphabetic,
- *  FALSE otherwise.
+ *  The length of the string created.
  */
-BOOL WINAPI IsCharAlphaWrapW(WCHAR wc)
+INT WINAPI SHStringFromGUIDW(REFGUID guid, LPWSTR lpszDest, INT cchMax)
 {
-    return (get_char_typeW(wc) & C1_ALPHA) != 0;
-}
+  WCHAR xguid[40];
+  INT iLen;
+  static const WCHAR wszFormat[] = {'{','%','0','8','l','X','-','%','0','4','X','-','%','0','4','X','-',
+      '%','0','2','X','%','0','2','X','-','%','0','2','X','%','0','2','X','%','0','2','X','%','0','2',
+      'X','%','0','2','X','%','0','2','X','}',0};
 
-/*************************************************************************
- *      @      [SHLWAPI.26]
- *
- * Determine if a Unicode character is upper-case.
- *
- * PARAMS
- *  wc [I] Character to check.
- *
- * RETURNS
- *  TRUE, if wc is upper-case,
- *  FALSE otherwise.
- */
-BOOL WINAPI IsCharUpperWrapW(WCHAR wc)
-{
-    return (get_char_typeW(wc) & C1_UPPER) != 0;
-}
+  TRACE("(%s,%p,%d)\n", debugstr_guid(guid), lpszDest, cchMax);
 
-/*************************************************************************
- *      @      [SHLWAPI.27]
- *
- * Determine if a Unicode character is lower-case.
- *
- * PARAMS
- *  wc [I] Character to check.
- *
- * RETURNS
- *  TRUE, if wc is lower-case,
- *  FALSE otherwise.
- */
-BOOL WINAPI IsCharLowerWrapW(WCHAR wc)
-{
-    return (get_char_typeW(wc) & C1_LOWER) != 0;
-}
+  sprintfW(xguid, wszFormat, guid->Data1, guid->Data2, guid->Data3,
+          guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
+          guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
 
-/*************************************************************************
- *      @      [SHLWAPI.28]
- *
- * Determine if a Unicode character is alphabetic or a digit.
- *
- * PARAMS
- *  wc [I] Character to check.
- *
- * RETURNS
- *  TRUE, if wc is alphabetic or a digit,
- *  FALSE otherwise.
- */
-BOOL WINAPI IsCharAlphaNumericWrapW(WCHAR wc)
-{
-    return (get_char_typeW(wc) & (C1_ALPHA|C1_DIGIT)) != 0;
+  iLen = strlenW(xguid) + 1;
+
+  if (iLen > cchMax)
+    return 0;
+  memcpy(lpszDest, xguid, iLen*sizeof(WCHAR));
+  return iLen;
 }
 
 /*************************************************************************
@@ -758,7 +694,9 @@ BOOL WINAPI IsCharAlphaNumericWrapW(WCHAR wc)
  */
 BOOL WINAPI IsCharSpaceW(WCHAR wc)
 {
-    return (get_char_typeW(wc) & C1_SPACE) != 0;
+    WORD CharType;
+
+    return GetStringTypeW(CT_CTYPE1, &wc, 1, &CharType) && (CharType & C1_SPACE);
 }
 
 /*************************************************************************
@@ -776,7 +714,9 @@ BOOL WINAPI IsCharSpaceW(WCHAR wc)
  */
 BOOL WINAPI IsCharBlankW(WCHAR wc)
 {
-    return (get_char_typeW(wc) & C1_BLANK) != 0;
+    WORD CharType;
+
+    return GetStringTypeW(CT_CTYPE1, &wc, 1, &CharType) && (CharType & C1_BLANK);
 }
 
 /*************************************************************************
@@ -793,7 +733,9 @@ BOOL WINAPI IsCharBlankW(WCHAR wc)
  */
 BOOL WINAPI IsCharPunctW(WCHAR wc)
 {
-    return (get_char_typeW(wc) & C1_PUNCT) != 0;
+    WORD CharType;
+
+    return GetStringTypeW(CT_CTYPE1, &wc, 1, &CharType) && (CharType & C1_PUNCT);
 }
 
 /*************************************************************************
@@ -810,7 +752,9 @@ BOOL WINAPI IsCharPunctW(WCHAR wc)
  */
 BOOL WINAPI IsCharCntrlW(WCHAR wc)
 {
-    return (get_char_typeW(wc) & C1_CNTRL) != 0;
+    WORD CharType;
+
+    return GetStringTypeW(CT_CTYPE1, &wc, 1, &CharType) && (CharType & C1_CNTRL);
 }
 
 /*************************************************************************
@@ -827,7 +771,9 @@ BOOL WINAPI IsCharCntrlW(WCHAR wc)
  */
 BOOL WINAPI IsCharDigitW(WCHAR wc)
 {
-    return (get_char_typeW(wc) & C1_DIGIT) != 0;
+    WORD CharType;
+
+    return GetStringTypeW(CT_CTYPE1, &wc, 1, &CharType) && (CharType & C1_DIGIT);
 }
 
 /*************************************************************************
@@ -844,7 +790,9 @@ BOOL WINAPI IsCharDigitW(WCHAR wc)
  */
 BOOL WINAPI IsCharXDigitW(WCHAR wc)
 {
-    return (get_char_typeW(wc) & C1_XDIGIT) != 0;
+    WORD CharType;
+
+    return GetStringTypeW(CT_CTYPE1, &wc, 1, &CharType) && (CharType & C1_XDIGIT);
 }
 
 /*************************************************************************
@@ -1168,38 +1116,6 @@ BOOL WINAPI SHAboutInfoW(LPWSTR lpszDest, DWORD dwDestLen)
   return TRUE;
 }
 
-/*************************************************************************
- *      @      [SHLWAPI.162]
- *
- * Remove a hanging lead byte from the end of a string, if present.
- *
- * PARAMS
- *  lpStr [I] String to check for a hanging lead byte
- *  size  [I] Length of lpStr
- *
- * RETURNS
- *  Success: The new length of the string. Any hanging lead bytes are removed.
- *  Failure: 0, if any parameters are invalid.
- */
-DWORD WINAPI SHTruncateString(LPSTR lpStr, DWORD size)
-{
-  if (lpStr && size)
-  {
-    LPSTR lastByte = lpStr + size - 1;
-
-    while(lpStr < lastByte)
-      lpStr += IsDBCSLeadByte(*lpStr) ? 2 : 1;
-
-    if(lpStr == lastByte && IsDBCSLeadByte(*lpStr))
-    {
-      *lpStr = '\0';
-      size--;
-    }
-    return size;
-  }
-  return 0;
-}
-
 /*************************************************************************
  *      @      [SHLWAPI.163]
  *
@@ -1423,7 +1339,7 @@ DWORD WINAPI IUnknown_AtomicRelease(IUnknown ** lpUnknown)
     *lpUnknown = NULL;
 
     TRACE("doing Release\n");
-    
+
     return IUnknown_Release(temp);
 }
 
@@ -1481,7 +1397,7 @@ BOOL WINAPI SHIsSameObject(IUnknown* lpInt1, IUnknown* lpInt2)
 
   if (lpUnknown1 == lpUnknown2)
     return TRUE;
-  
+
   return FALSE;
 }
 
@@ -1594,16 +1510,17 @@ DWORD WINAPI IUnknown_SetSite(
         LPVOID *p2)       /* [out]  ptr for call results */
 {
     DWORD ret, aa;
+    IUnknown *iobjectwithsite;
 
     if (!p1) return E_FAIL;
 
     /* see if SetSite interface exists for IObjectWithSite object */
-    ret = IUnknown_QueryInterface((IUnknown *)p1, (REFIID)id1, (LPVOID *)&p1);
-    TRACE("first IU_QI ret=%08lx, p1=%p\n", ret, p1);
+    ret = IUnknown_QueryInterface((IUnknown *)p1, (REFIID)id1, (LPVOID *)&iobjectwithsite);
+    TRACE("first IU_QI ret=%08lx, iobjectwithsite=%p\n", ret, iobjectwithsite);
     if (ret) {
 
        /* see if GetClassId interface exists for IPersistMoniker object */
-       ret = IUnknown_QueryInterface((IUnknown *)p1, (REFIID)id2, (LPVOID *)&aa);
+       ret = IUnknown_QueryInterface(p1, (REFIID)id2, (LPVOID *)&aa);
        TRACE("second IU_QI ret=%08lx, aa=%08lx\n", ret, aa);
        if (ret) return ret;
 
@@ -1615,10 +1532,10 @@ DWORD WINAPI IUnknown_SetSite(
     }
     else {
        /* fake a SetSite call */
-       ret = IOleWindow_GetWindow((IOleWindow *)p1, (HWND*)p2);
+       ret = IOleWindow_GetWindow((IOleWindow *)iobjectwithsite, (HWND*)p2);
        TRACE("first IU_QI doing 0x0c ret=%08lx, *p2=%08lx\n", ret,
              *(LPDWORD)p2);
-       IUnknown_Release((IUnknown *)p1);
+       IUnknown_Release((IUnknown *)iobjectwithsite);
     }
     return ret;
 }
@@ -1873,6 +1790,30 @@ DWORD WINAPI SHRegisterClassA(WNDCLASSA *wndclass)
   return (DWORD)RegisterClassA(wndclass);
 }
 
+/*************************************************************************
+ *      @      [SHLWAPI.186]
+ */
+BOOL WINAPI SHSimulateDrop(IDropTarget *pDrop, IDataObject *pDataObj,
+                           DWORD grfKeyState, PPOINTL lpPt, DWORD* pdwEffect)
+{
+  DWORD dwEffect = DROPEFFECT_LINK | DROPEFFECT_MOVE | DROPEFFECT_COPY;
+  POINTL pt = { 0, 0 };
+
+  if (!lpPt)
+    lpPt = &pt;
+
+  if (!pdwEffect)
+    pdwEffect = &dwEffect;
+
+  IDropTarget_DragEnter(pDrop, pDataObj, grfKeyState, *lpPt, pdwEffect);
+
+  if (*pdwEffect)
+    return IDropTarget_Drop(pDrop, pDataObj, grfKeyState, *lpPt, pdwEffect);
+
+  IDropTarget_DragLeave(pDrop);
+  return TRUE;
+}
+
 /*************************************************************************
  *      @      [SHLWAPI.187]
  *
@@ -1906,13 +1847,47 @@ DWORD WINAPI SHLoadFromPropertyBag(IUnknown *lpUnknown, IPropertyBag* lpPropBag)
   return hRet;
 }
 
+/*************************************************************************
+ * @  [SHLWAPI.188]
+ *
+ * Call IOleControlSite_TranslateAccelerator()  on an object.
+ *
+ * PARAMS
+ *  lpUnknown   [I] Object supporting the IOleControlSite interface.
+ *  lpMsg       [I] Key message to be processed.
+ *  dwModifiers [I] Flags containing the state of the modifier keys.
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: An HRESULT error code, or E_INVALIDARG if lpUnknown is NULL.
+ */
+HRESULT WINAPI IUnknown_TranslateAcceleratorOCS(IUnknown *lpUnknown, LPMSG lpMsg, DWORD dwModifiers)
+{
+  IOleControlSite* lpCSite = NULL;
+  HRESULT hRet = E_INVALIDARG;
+
+  TRACE("(%p,%p,0x%08lx)\n", lpUnknown, lpMsg, dwModifiers);
+  if (lpUnknown)
+  {
+    hRet = IUnknown_QueryInterface(lpUnknown, &IID_IOleControlSite,
+                                   (void**)&lpCSite);
+    if (SUCCEEDED(hRet) && lpCSite)
+    {
+      hRet = IOleControlSite_TranslateAccelerator(lpCSite, lpMsg, dwModifiers);
+      IOleControlSite_Release(lpCSite);
+    }
+  }
+  return hRet;
+}
+
+
 /*************************************************************************
  * @  [SHLWAPI.189]
  *
  * Call IOleControlSite_GetExtendedControl() on an object.
  *
  * PARAMS
- *  lpUnknown [I] Object supporting the IOleControlSite interface
+ *  lpUnknown [I] Object supporting the IOleControlSite interface.
  *  lppDisp   [O] Destination for resulting IDispatch.
  *
  * RETURNS
@@ -1921,7 +1896,7 @@ DWORD WINAPI SHLoadFromPropertyBag(IUnknown *lpUnknown, IPropertyBag* lpPropBag)
  */
 DWORD WINAPI IUnknown_OnFocusOCS(IUnknown *lpUnknown, IDispatch** lppDisp)
 {
-  IOleControlSite* lpCSite;
+  IOleControlSite* lpCSite = NULL;
   HRESULT hRet = E_FAIL;
 
   TRACE("(%p,%p)\n", lpUnknown, lppDisp);
@@ -1938,39 +1913,39 @@ DWORD WINAPI IUnknown_OnFocusOCS(IUnknown *lpUnknown, IDispatch** lppDisp)
   return hRet;
 }
 
-static const WCHAR szDontShowKey[] = { 'S','o','f','t','w','a','r','e','\\',
-  'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
-  'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
-  'E','x','p','l','o','r','e','r','\\','D','o','n','t','S','h','o','w',
-  'M','e','T','h','i','s','D','i','a','l','o','g','A','g','a','i','n','\0'
-};
-
 /*************************************************************************
- * @    [SHLWAPI.191]
- *
- * Pop up a 'Don't show this message again' error dialog box.
- *
- * PARAMS
- *  hWnd      [I] Window to own the dialog box
- *  arg2      [I] Unknown
- *  arg3      [I] Unknown
- *  arg4      [I] Unknown
- *  arg5      [I] Unknown
- *  lpszValue [I] Registry value holding boolean show/don't show.
- *
- * RETURNS
- *  Nothing.
+ * @    [SHLWAPI.190]
  */
-void WINAPI SHMessageBoxCheckW(HWND hWnd, PVOID arg2, PVOID arg3, PVOID arg4, PVOID arg5, LPCWSTR lpszValue)
+HRESULT WINAPI IUnknown_HandleIRestrict(LPUNKNOWN lpUnknown, PVOID lpArg1,
+                                        PVOID lpArg2, PVOID lpArg3, PVOID lpArg4)
 {
-  FIXME("(%p,%p,%p,%p,%p,%s) - stub!\n", hWnd, arg2, arg3, arg4, arg5, debugstr_w(lpszValue));
+  /* FIXME: {D12F26B2-D90A-11D0-830D-00AA005B4383} - What object does this represent? */
+  static const DWORD service_id[] = { 0xd12f26b2, 0x11d0d90a, 0xaa000d83, 0x83435b00 };
+  /* FIXME: {D12F26B1-D90A-11D0-830D-00AA005B4383} - Also Unknown/undocumented */
+  static const DWORD function_id[] = { 0xd12f26b1, 0x11d0d90a, 0xaa000d83, 0x83435b00 };
+  HRESULT hRet = E_INVALIDARG;
+  LPUNKNOWN lpUnkInner = NULL; /* FIXME: Real type is unknown */
 
-  if (SHRegGetBoolUSValueW(szDontShowKey, lpszValue, FALSE, TRUE))
+  TRACE("(%p,%p,%p,%p,%p)\n", lpUnknown, lpArg1, lpArg2, lpArg3, lpArg4);
+
+  if (lpUnknown && lpArg4)
   {
-    /* FIXME: Should use DialogBoxParamW to load a dialog box; its dlgproc
-     * should accept clicks on 'Don't show' and set the reg value appropriately.
-     */
+     hRet = IUnknown_QueryService(lpUnknown, (REFGUID)service_id,
+                                  (REFGUID)function_id, (void**)&lpUnkInner);
+
+     if (SUCCEEDED(hRet) && lpUnkInner)
+     {
+       /* FIXME: The type of service object requested is unknown, however
+       * testing shows that its first method is called with 4 parameters.
+       * Fake this by using IParseDisplayName_ParseDisplayName since the
+       * signature and position in the vtable matches our unknown object type.
+       */
+       hRet = IParseDisplayName_ParseDisplayName((LPPARSEDISPLAYNAME)lpUnkInner,
+                                                 lpArg1, lpArg2, lpArg3, lpArg4);
+       IUnknown_Release(lpUnkInner);
+     }
   }
+  return hRet;
 }
 
 /*************************************************************************
@@ -1995,7 +1970,7 @@ HMENU WINAPI SHGetMenuFromID(HMENU hMenu, UINT uID)
   mi.fMask = MIIM_SUBMENU;
 
   if (!GetMenuItemInfoA(hMenu, uID, 0, &mi))
-    return (HMENU)NULL;
+    return NULL;
 
   return mi.hSubMenu;
 }
@@ -2024,6 +1999,90 @@ DWORD WINAPI SHGetCurColorRes()
     return ret;
 }
 
+/*************************************************************************
+ *      @      [SHLWAPI.194]
+ *
+ * Wait for a message to arrive, with a timeout.
+ *
+ * PARAMS
+ *  hand      [I] Handle to query
+ *  dwTimeout [I] Timeout in ticks or INFINITE to never timeout
+ *
+ * RETURNS
+ *  STATUS_TIMEOUT if no message is received before dwTimeout ticks passes.
+ *  Otherwise returns the value from MsgWaitForMultipleObjectsEx when a
+ *  message is available.
+ */
+DWORD WINAPI SHWaitForSendMessageThread(HANDLE hand, DWORD dwTimeout)
+{
+  DWORD dwEndTicks = GetTickCount() + dwTimeout;
+  DWORD dwRet;
+
+  while ((dwRet = MsgWaitForMultipleObjectsEx(1, &hand, dwTimeout, QS_SENDMESSAGE, 0)) == 1)
+  {
+    MSG msg;
+
+    PeekMessageW(&msg, NULL, 0, 0, PM_NOREMOVE);
+
+    if (dwTimeout != INFINITE)
+    {
+        if ((int)(dwTimeout = dwEndTicks - GetTickCount()) <= 0)
+            return WAIT_TIMEOUT;
+    }
+  }
+
+  return dwRet;
+}
+
+/*************************************************************************
+ *      @       [SHLWAPI.195]
+ *
+ * Determine if a shell folder can be expanded.
+ *
+ * PARAMS
+ *  lpFolder [I] Parent folder containing the object to test.
+ *  pidl     [I] Id of the object to test.
+ *
+ * RETURNS
+ *  Success: S_OK, if the object is expandable, S_FALSE otherwise.
+ *  Failure: E_INVALIDARG, if any argument is invalid.
+ *
+ * NOTES
+ *  If the object to be tested does not expose the IQueryInfo() interface it
+ *  will not be identified as an expandable folder.
+ */
+HRESULT WINAPI SHIsExpandableFolder(LPSHELLFOLDER lpFolder, LPCITEMIDLIST pidl)
+{
+  HRESULT hRet = E_INVALIDARG;
+  IQueryInfo *lpInfo;
+
+  if (lpFolder && pidl)
+  {
+    hRet = IShellFolder_GetUIObjectOf(lpFolder, NULL, 1, &pidl, &IID_IQueryInfo,
+                                      NULL, (void**)&lpInfo);
+    if (FAILED(hRet))
+      hRet = S_FALSE; /* Doesn't expose IQueryInfo */
+    else
+    {
+      DWORD dwFlags = 0;
+
+      /* MSDN states of IQueryInfo_GetInfoFlags() that "This method is not
+       * currently used". Really? You wouldn't be holding out on me would you?
+       */
+      hRet = IQueryInfo_GetInfoFlags(lpInfo, &dwFlags);
+
+      if (SUCCEEDED(hRet))
+      {
+        /* 0x2 is an undocumented flag apparently indicating expandability */
+        hRet = dwFlags & 0x2 ? S_OK : S_FALSE;
+      }
+
+      IQueryInfo_Release(lpInfo);
+    }
+  }
+  return hRet;
+}
+
 /*************************************************************************
  *      @       [SHLWAPI.197]
  *
@@ -2045,6 +2104,43 @@ DWORD WINAPI SHFillRectClr(HDC hDC, LPCRECT pRect, COLORREF cRef)
     return 0;
 }
 
+/*************************************************************************
+ *      @      [SHLWAPI.198]
+ *
+ * Return the value asociated with a key in a map.
+ *
+ * PARAMS
+ *  lpKeys   [I] A list of keys of length iLen
+ *  lpValues [I] A list of values associated with lpKeys, of length iLen
+ *  iLen     [I] Length of both lpKeys and lpValues
+ *  iKey     [I] The key value to look up in lpKeys
+ *
+ * RETURNS
+ *  The value in lpValues associated with iKey, or -1 if iKey is not
+ *  found in lpKeys.
+ *
+ * NOTES
+ *  - If two elements in the map share the same key, this function returns
+ *    the value closest to the start of the map
+ *  - The native version of this function crashes if lpKeys or lpValues is NULL.
+ */
+int WINAPI SHSearchMapInt(const int *lpKeys, const int *lpValues, int iLen, int iKey)
+{
+  if (lpKeys && lpValues)
+  {
+    int i = 0;
+
+    while (i < iLen)
+    {
+      if (lpKeys[i] == iKey)
+        return lpValues[i]; /* Found */
+      i++;
+    }
+  }
+  return -1; /* Not found */
+}
+
+
 /*************************************************************************
  *      @      [SHLWAPI.199]
  *
@@ -2072,6 +2168,21 @@ VOID WINAPI IUnknown_Set(IUnknown **lppDest, IUnknown *lpUnknown)
   }
 }
 
+/*************************************************************************
+ *      @      [SHLWAPI.200]
+ *
+ */
+HRESULT WINAPI MayQSForward(IUnknown* lpUnknown, PVOID lpReserved,
+                            REFGUID riidCmdGrp, ULONG cCmds,
+                            OLECMD *prgCmds, OLECMDTEXT* pCmdText)
+{
+  FIXME("(%p,%p,%p,%ld,%p,%p) - stub\n",
+        lpUnknown, lpReserved, riidCmdGrp, cCmds, prgCmds, pCmdText);
+
+  /* FIXME: Calls IsQSForward & IUnknown_QueryStatus */
+  return DRAGDROP_E_NOTREGISTERED;
+}
+
 /*************************************************************************
  *      @      [SHLWAPI.201]
  *
@@ -2176,148 +2287,6 @@ DWORD WINAPI FDSA_DeleteItem(
     return 1;
 }
 
-/*************************************************************************
- *      @      [SHLWAPI.215]
- *
- * NOTES
- *  check me!
- */
-DWORD WINAPI SHAnsiToUnicode(
-       LPCSTR lpStrSrc,
-       LPWSTR lpwStrDest,
-       int len)
-{
-       INT len_a, ret;
-
-       len_a = lstrlenA(lpStrSrc);
-       ret = MultiByteToWideChar(0, 0, lpStrSrc, len_a, lpwStrDest, len);
-       TRACE("%s %s %d, ret=%d\n",
-             debugstr_a(lpStrSrc), debugstr_w(lpwStrDest), len, ret);
-       return ret;
-}
-
-/*************************************************************************
- *      @      [SHLWAPI.218]
- *
- * WideCharToMultiByte with support for multiple codepages.
- *
- * PARAMS
- *  CodePage          [I] Code page to use for the conversion
- *  lpSrcStr          [I] Source Unicode string to convert
- *  lpDstStr          [O] Destination for converted Ascii string
- *  lpnMultiCharCount [O] Input length of lpDstStr/destination for length of lpDstStr
- *
- * RETURNS
- *  Success: The number of characters that result from the conversion.
- *  Failure: 0.
- */
-INT WINAPI SHUnicodeToAnsiCP(UINT CodePage, LPCWSTR lpSrcStr, LPSTR lpDstStr,
-                       LPINT lpnMultiCharCount)
-{
-  WCHAR emptyW[] = { '\0' };
-  int len , reqLen;
-  LPSTR mem;
-
-  if (!lpDstStr || !lpnMultiCharCount)
-    return 0;
-
-  if (!lpSrcStr)
-    lpSrcStr = emptyW;
-
-  *lpDstStr = '\0';
-
-  len = strlenW(lpSrcStr) + 1;
-
-  switch (CodePage)
-  {
-  case CP_WINUNICODE:
-    CodePage = CP_UTF8; /* Fall through... */
-  case 0x0000C350: /* FIXME: CP_ #define */
-  case CP_UTF7:
-  case CP_UTF8:
-    {
-      DWORD dwMode = 0;
-      INT nWideCharCount = len - 1;
-
-      GET_FUNC(pConvertINetUnicodeToMultiByte, mlang, "ConvertINetUnicodeToMultiByte", 0);
-      if (!pConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &nWideCharCount, lpDstStr,
-                                          lpnMultiCharCount))
-        return 0;
-
-      if (nWideCharCount < len - 1)
-      {
-        mem = (LPSTR)HeapAlloc(GetProcessHeap(), 0, *lpnMultiCharCount);
-        if (!mem)
-          return 0;
-
-        *lpnMultiCharCount = 0;
-
-        if (pConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &len, mem, lpnMultiCharCount))
-        {
-          SHTruncateString(mem, *lpnMultiCharCount);
-          lstrcpynA(lpDstStr, mem, *lpnMultiCharCount + 1);
-          return *lpnMultiCharCount + 1;
-        }
-        HeapFree(GetProcessHeap(), 0, mem);
-        return *lpnMultiCharCount;
-      }
-      lpDstStr[*lpnMultiCharCount] = '\0';
-      return *lpnMultiCharCount;
-    }
-    break;
-  default:
-    break;
-  }
-
-  reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, lpDstStr,
-                               *lpnMultiCharCount, NULL, NULL);
-
-  if (!reqLen && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
-  {
-    reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, NULL, 0, NULL, NULL);
-    if (reqLen)
-    {
-      mem = (LPSTR)HeapAlloc(GetProcessHeap(), 0, reqLen);
-      if (mem)
-      {
-        reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, mem,
-                                     reqLen, NULL, NULL);
-
-        reqLen = SHTruncateString(mem, *lpnMultiCharCount);
-        reqLen++;
-
-        lstrcpynA(lpDstStr, mem, *lpnMultiCharCount);
-
-        HeapFree(GetProcessHeap(), 0, mem);
-      }
-    }
-  }
-  return reqLen;
-}
-
-/*************************************************************************
- *      @      [SHLWAPI.217]
- *
- * WideCharToMultiByte with support for multiple codepages.
- *
- * PARAMS
- *  lpSrcStr          [I] Source Unicode string to convert
- *  lpDstStr          [O] Destination for converted Ascii string
- *  lpnMultiCharCount [O] Input length of lpDstStr/destination for length of lpDstStr
- *
- * RETURNS
- *  See SHUnicodeToAnsiCP
-
- * NOTES
- *  This function simply calls SHUnicodeToAnsiCP with CodePage = CP_ACP.
- */
-INT WINAPI SHUnicodeToAnsi(LPCWSTR lpSrcStr, LPSTR lpDstStr, INT MultiCharCount)
-{
-    INT myint = MultiCharCount;
-
-    return SHUnicodeToAnsiCP(CP_ACP, lpSrcStr, lpDstStr, &myint);
-}
-
 typedef struct {
     REFIID   refid;
     DWORD    indx;
@@ -2515,13 +2484,26 @@ LRESULT CALLBACK SHDefWindowProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM
 }
 
 /*************************************************************************
- *      @      [SHLWAPI.241]
- *
+ *      @       [SHLWAPI.256]
  */
-DWORD WINAPI StopWatchMode()
+HRESULT WINAPI IUnknown_GetSite(LPUNKNOWN lpUnknown, REFIID iid, PVOID *lppSite)
 {
-       FIXME("()stub\n");
-       return /* 0xabba1243 */ 0;
+  HRESULT hRet = E_INVALIDARG;
+  LPOBJECTWITHSITE lpSite = NULL;
+
+  TRACE("(%p,%s,%p)\n", lpUnknown, debugstr_guid(iid), lppSite);
+
+  if (lpUnknown && iid && lppSite)
+  {
+    hRet = IUnknown_QueryInterface(lpUnknown, &IID_IObjectWithSite,
+                                   (void**)&lpSite);
+    if (SUCCEEDED(hRet) && lpSite)
+    {
+      hRet = IObjectWithSite_GetSite(lpSite, iid, lppSite);
+      IObjectWithSite_Release(lpSite);
+    }
+  }
+  return hRet;
 }
 
 /*************************************************************************
@@ -2557,8 +2539,8 @@ HWND WINAPI SHCreateWorkerWindowA(LONG wndProc, HWND hWndParent, DWORD dwExStyle
   wc.cbClsExtra    = 0;
   wc.cbWndExtra    = 4;
   wc.hInstance     = shlwapi_hInstance;
-  wc.hIcon         = (HICON)0;
-  wc.hCursor       = LoadCursorA((HINSTANCE)0, (LPSTR)IDC_ARROW);
+  wc.hIcon         = NULL;
+  wc.hCursor       = LoadCursorA(NULL, (LPSTR)IDC_ARROW);
   wc.hbrBackground = (HBRUSH)COLOR_BTNSHADOW;
   wc.lpszMenuName  = NULL;
   wc.lpszClassName = szClass;
@@ -2571,10 +2553,10 @@ HWND WINAPI SHCreateWorkerWindowA(LONG wndProc, HWND hWndParent, DWORD dwExStyle
                          hWndParent, hMenu, shlwapi_hInstance, 0);
   if (hWnd)
   {
-    SetWindowLongA(hWnd, DWL_MSGRESULT, z);
+    SetWindowLongPtrW(hWnd, DWLP_MSGRESULT, z);
 
     if (wndProc)
-      SetWindowLongA(hWnd, GWL_WNDPROC, wndProc);
+      SetWindowLongPtrA(hWnd, GWLP_WNDPROC, wndProc);
   }
   return hWnd;
 }
@@ -2589,7 +2571,7 @@ typedef struct tagPOLICYDATA
 #define SHELL_NO_POLICY 0xffffffff
 
 /* default shell policy registry key */
-static WCHAR strRegistryPolicyW[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o',
+static const WCHAR strRegistryPolicyW[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o',
                                       's','o','f','t','\\','W','i','n','d','o','w','s','\\',
                                       'C','u','r','r','e','n','t','V','e','r','s','i','o','n',
                                       '\\','P','o','l','i','c','i','e','s',0};
@@ -2609,12 +2591,12 @@ static WCHAR strRegistryPolicyW[] = {'S','o','f','t','w','a','r','e','\\','M','i
  */
 DWORD WINAPI SHGetRestriction(LPCWSTR lpSubKey, LPCWSTR lpSubName, LPCWSTR lpValue)
 {
-       DWORD retval, datsize = 4;
+       DWORD retval, datsize = sizeof(retval);
        HKEY hKey;
 
        if (!lpSubKey)
-         lpSubKey = (LPCWSTR)strRegistryPolicyW;
-       
+         lpSubKey = strRegistryPolicyW;
+
        retval = RegOpenKeyW(HKEY_LOCAL_MACHINE, lpSubKey, &hKey);
     if (retval != ERROR_SUCCESS)
          retval = RegOpenKeyW(HKEY_CURRENT_USER, lpSubKey, &hKey);
@@ -2623,7 +2605,7 @@ DWORD WINAPI SHGetRestriction(LPCWSTR lpSubKey, LPCWSTR lpSubName, LPCWSTR lpVal
 
        SHGetValueW(hKey, lpSubName, lpValue, NULL, (LPBYTE)&retval, &datsize);
        RegCloseKey(hKey);
-       return retval;  
+       return retval;
 }
 
 /*************************************************************************
@@ -2684,7 +2666,7 @@ DWORD WINAPI SHRestrictionLookup(
  *  Failure: An HRESULT error code.
  *
  * NOTES
- *   This QueryInterface asks the inner object for a interface. In case
+ *   This QueryInterface asks the inner object for an interface. In case
  *   of aggregation this request would be forwarded by the inner to the
  *   outer object. This function asks the inner object directly for the
  *   interface circumventing the forwarding to the outer object.
@@ -2793,7 +2775,7 @@ DWORD WINAPI WhichPlatform()
   GET_FUNC(pDllGetVersion, shell32, "DllGetVersion", 1);
   dwState = pDllGetVersion ? 2 : 1;
 
-  /* Set or delete the key accordinly */
+  /* Set or delete the key accordingly */
   dwRet = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
                         "Software\\Microsoft\\Internet Explorer", 0,
                          KEY_ALL_ACCESS, &hKey);
@@ -2844,8 +2826,8 @@ HWND WINAPI SHCreateWorkerWindowW(LONG wndProc, HWND hWndParent, DWORD dwExStyle
   wc.cbClsExtra    = 0;
   wc.cbWndExtra    = 4;
   wc.hInstance     = shlwapi_hInstance;
-  wc.hIcon         = (HICON)0;
-  wc.hCursor       = LoadCursorA((HINSTANCE)0, (LPSTR)IDC_ARROW);
+  wc.hIcon         = NULL;
+  wc.hCursor       = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
   wc.hbrBackground = (HBRUSH)COLOR_BTNSHADOW;
   wc.lpszMenuName  = NULL;
   wc.lpszClassName = szClass;
@@ -2858,10 +2840,10 @@ HWND WINAPI SHCreateWorkerWindowW(LONG wndProc, HWND hWndParent, DWORD dwExStyle
                          hWndParent, hMenu, shlwapi_hInstance, 0);
   if (hWnd)
   {
-    SetWindowLongA(hWnd, DWL_MSGRESULT, z);
+    SetWindowLongPtrW(hWnd, DWLP_MSGRESULT, z);
 
     if (wndProc)
-      SetWindowLongA(hWnd, GWL_WNDPROC, wndProc);
+      SetWindowLongPtrW(hWnd, GWLP_WNDPROC, wndProc);
   }
   return hWnd;
 }
@@ -3159,19 +3141,6 @@ LONG WINAPI SHInterlockedCompareExchange( PLONG dest, LONG xchg, LONG compare)
         return InterlockedCompareExchange(dest, xchg, compare);
 }
 
-/*************************************************************************
- *      @      [SHLWAPI.346]
- */
-DWORD WINAPI SHUnicodeToUnicode(
-       LPCWSTR src,
-       LPWSTR dest,
-       int len)
-{
-       FIXME("(%s %p 0x%08x)stub\n",debugstr_w(src),dest,len);
-       lstrcpynW(dest, src, len);
-       return lstrlenW(dest)+1;
-}
-
 /*************************************************************************
  *      @      [SHLWAPI.350]
  *
@@ -3238,7 +3207,8 @@ WORD WINAPI VerQueryValueWrapW(
  * NOTES
  *  lpUnknown must support the IOleInPlaceFrame interface, the
  *  IInternetSecurityMgrSite interface, the IShellBrowser interface
- *  or the IDocHostUIHandler interface, or this call fails.
+ *  the IDocHostUIHandler interface, or the IOleInPlaceActiveObject interface,
+ *  or this call will fail.
  */
 HRESULT WINAPI IUnknown_EnableModeless(IUnknown *lpUnknown, BOOL bModeless)
 {
@@ -3250,7 +3220,9 @@ HRESULT WINAPI IUnknown_EnableModeless(IUnknown *lpUnknown, BOOL bModeless)
   if (!lpUnknown)
     return E_FAIL;
 
-  if (IsIface(IOleInPlaceFrame))
+  if (IsIface(IOleInPlaceActiveObject))
+    EnableModeless(IOleInPlaceActiveObject);
+  else if (IsIface(IOleInPlaceFrame))
     EnableModeless(IOleInPlaceFrame);
   else if (IsIface(IShellBrowser))
     EnableModeless(IShellBrowser);
@@ -3357,25 +3329,6 @@ HRESULT WINAPI SHInvokeCommand(HWND hWnd, IShellFolder* lpFolder, LPCITEMIDLIST
   return hRet;
 }
 
-/*************************************************************************
- *      @      [SHLWAPI.364]
- *
- * Copy one string to another, up to a given length.
- *
- * PARAMS
- *  lpszSrc [I] Source string to copy
- *  lpszDst [O] Destination for copied string
- *  iLen    [I] Number of characters to copy
- *
- * RETURNS
- *  TRUE.
- */
-DWORD WINAPI DoesStringRoundTripA(LPCSTR lpszSrc, LPSTR lpszDst, INT iLen)
-{
-  lstrcpynA(lpszDst, lpszSrc, iLen);
-  return TRUE;
-}
-
 /*************************************************************************
  *      @      [SHLWAPI.370]
  *
@@ -3436,9 +3389,12 @@ HMODULE WINAPI MLLoadLibraryA(LPCSTR new_mod, HMODULE inst_hwnd, DWORD dwFlags)
    */
     CHAR mod_path[2*MAX_PATH];
     LPSTR ptr;
+    DWORD len;
 
     FIXME("(%s,%p,0x%08lx) semi-stub!\n", debugstr_a(new_mod), inst_hwnd, dwFlags);
-    GetModuleFileNameA(inst_hwnd, mod_path, 2*MAX_PATH);
+    len = GetModuleFileNameA(inst_hwnd, mod_path, sizeof(mod_path));
+    if (!len || len >= sizeof(mod_path)) return NULL;
+
     ptr = strrchr(mod_path, '\\');
     if (ptr) {
        strcpy(ptr+1, new_mod);
@@ -3457,9 +3413,12 @@ HMODULE WINAPI MLLoadLibraryW(LPCWSTR new_mod, HMODULE inst_hwnd, DWORD dwFlags)
 {
     WCHAR mod_path[2*MAX_PATH];
     LPWSTR ptr;
+    DWORD len;
 
     FIXME("(%s,%p,0x%08lx) semi-stub!\n", debugstr_w(new_mod), inst_hwnd, dwFlags);
-    GetModuleFileNameW(inst_hwnd, mod_path, 2*MAX_PATH);
+    len = GetModuleFileNameW(inst_hwnd, mod_path, sizeof(mod_path) / sizeof(WCHAR));
+    if (!len || len >= sizeof(mod_path) / sizeof(WCHAR)) return NULL;
+
     ptr = strrchrW(mod_path, '\\');
     if (ptr) {
        strcpyW(ptr+1, new_mod);
@@ -3677,6 +3636,14 @@ BOOL WINAPI MLFreeLibrary(HMODULE hModule)
        return FreeLibrary(hModule);
 }
 
+/*************************************************************************
+ *      @      [SHLWAPI.419]
+ */
+BOOL WINAPI SHFlushSFCacheWrap(void) {
+  FIXME(": stub\n");
+  return TRUE;
+}
+
 /*************************************************************************
  *      @      [SHLWAPI.429]
  * FIXME I have no idea what this function does or what its arguments are.
@@ -3824,12 +3791,182 @@ HRESULT WINAPI CLSIDFromStringWrap(LPCWSTR idstr, CLSID *id)
  *  TRUE  If the feature is available.
  *  FALSE If the feature is not available.
  */
-DWORD WINAPI IsOS(DWORD feature)
+BOOL WINAPI IsOS(DWORD feature)
 {
-  FIXME("(0x%08lx) stub\n", feature);
-  if (feature == 4)
-    return TRUE;
-  return FALSE;
+    OSVERSIONINFOA osvi;
+    DWORD platform, majorv, minorv;
+
+    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
+    if(!GetVersionExA(&osvi))  {
+        ERR("GetVersionEx failed");
+        return FALSE;
+    }
+
+    majorv = osvi.dwMajorVersion;
+    minorv = osvi.dwMinorVersion;
+    platform = osvi.dwPlatformId;
+
+#define ISOS_RETURN(x) \
+    TRACE("(0x%lx) ret=%d\n",feature,(x)); \
+    return (x);
+
+    switch(feature)  {
+    case OS_WIN32SORGREATER:
+        ISOS_RETURN(platform == VER_PLATFORM_WIN32s
+                 || platform == VER_PLATFORM_WIN32_WINDOWS)
+    case OS_NT:
+        ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
+    case OS_WIN95ORGREATER:
+        ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS)
+    case OS_NT4ORGREATER:
+        ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 4)
+    case OS_WIN2000ORGREATER_ALT:
+    case OS_WIN2000ORGREATER:
+        ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5)
+    case OS_WIN98ORGREATER:
+        ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv >= 10)
+    case OS_WIN98_GOLD:
+        ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv == 10)
+    case OS_WIN2000PRO:
+        ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5)
+    case OS_WIN2000SERVER:
+        ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1))
+    case OS_WIN2000ADVSERVER:
+        ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1))
+    case OS_WIN2000DATACENTER:
+        ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1))
+    case OS_WIN2000TERMINAL:
+        ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1))
+    case OS_EMBEDDED:
+        FIXME("(OS_EMBEDDED) What should we return here?\n");
+        return FALSE;
+    case OS_TERMINALCLIENT:
+        FIXME("(OS_TERMINALCLIENT) What should we return here?\n");
+        return FALSE;
+    case OS_TERMINALREMOTEADMIN:
+        FIXME("(OS_TERMINALREMOTEADMIN) What should we return here?\n");
+        return FALSE;
+    case OS_WIN95_GOLD:
+        ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv == 0)
+    case OS_MEORGREATER:
+        ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv >= 90)
+    case OS_XPORGREATER:
+        ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5 && minorv >= 1)
+    case OS_HOME:
+        ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5 && minorv >= 1)
+    case OS_PROFESSIONAL:
+        ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
+    case OS_DATACENTER:
+        ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
+    case OS_ADVSERVER:
+        ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5)
+    case OS_SERVER:
+        ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
+    case OS_TERMINALSERVER:
+        ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
+    case OS_PERSONALTERMINALSERVER:
+        ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && minorv >= 1 && majorv >= 5)
+    case OS_FASTUSERSWITCHING:
+        FIXME("(OS_FASTUSERSWITCHING) What should we return here?\n");
+        return TRUE;
+    case OS_WELCOMELOGONUI:
+        FIXME("(OS_WELCOMELOGONUI) What should we return here?\n");
+        return FALSE;
+    case OS_DOMAINMEMBER:
+        FIXME("(OS_DOMAINMEMBER) What should we return here?\n");
+        return TRUE;
+    case OS_ANYSERVER:
+        ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
+    case OS_WOW6432:
+        FIXME("(OS_WOW6432) Should we check this?\n");
+        return FALSE;
+    case OS_WEBSERVER:
+        ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
+    case OS_SMALLBUSINESSSERVER:
+        ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT)
+    case OS_TABLETPC:
+        FIXME("(OS_TABLEPC) What should we return here?\n");
+        return FALSE;
+    case OS_SERVERADMINUI:
+        FIXME("(OS_SERVERADMINUI) What should we return here?\n");
+        return FALSE;
+    case OS_MEDIACENTER:
+        FIXME("(OS_MEDIACENTER) What should we return here?\n");
+        return FALSE;
+    case OS_APPLIANCE:
+        FIXME("(OS_APPLIANCE) What should we return here?\n");
+        return FALSE;
+    }
+
+#undef ISOS_RETURN
+
+    WARN("(0x%lx) unknown parameter\n",feature);
+
+    return FALSE;
+}
+
+/*************************************************************************
+ * @  [SHLWAPI.478]
+ *
+ * Call IInputObject_TranslateAcceleratorIO() on an object.
+ *
+ * PARAMS
+ *  lpUnknown [I] Object supporting the IInputObject interface.
+ *  lpMsg     [I] Key message to be processed.
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: An HRESULT error code, or E_INVALIDARG if lpUnknown is NULL.
+ */
+HRESULT WINAPI IUnknown_TranslateAcceleratorIO(IUnknown *lpUnknown, LPMSG lpMsg)
+{
+  IInputObject* lpInput = NULL;
+  HRESULT hRet = E_INVALIDARG;
+
+  TRACE("(%p,%p)\n", lpUnknown, lpMsg);
+  if (lpUnknown)
+  {
+    hRet = IUnknown_QueryInterface(lpUnknown, &IID_IInputObject,
+                                   (void**)&lpInput);
+    if (SUCCEEDED(hRet) && lpInput)
+    {
+      hRet = IInputObject_TranslateAcceleratorIO(lpInput, lpMsg);
+      IInputObject_Release(lpInput);
+    }
+  }
+  return hRet;
+}
+
+/*************************************************************************
+ * @  [SHLWAPI.481]
+ *
+ * Call IInputObject_HasFocusIO() on an object.
+ *
+ * PARAMS
+ *  lpUnknown [I] Object supporting the IInputObject interface.
+ *
+ * RETURNS
+ *  Success: S_OK, if lpUnknown is an IInputObject object and has the focus,
+ *           or S_FALSE otherwise.
+ *  Failure: An HRESULT error code, or E_INVALIDARG if lpUnknown is NULL.
+ */
+HRESULT WINAPI IUnknown_HasFocusIO(IUnknown *lpUnknown)
+{
+  IInputObject* lpInput = NULL;
+  HRESULT hRet = E_INVALIDARG;
+
+  TRACE("(%p)\n", lpUnknown);
+  if (lpUnknown)
+  {
+    hRet = IUnknown_QueryInterface(lpUnknown, &IID_IInputObject,
+                                   (void**)&lpInput);
+    if (SUCCEEDED(hRet) && lpInput)
+    {
+      hRet = IInputObject_HasFocusIO(lpInput);
+      IInputObject_Release(lpInput);
+    }
+  }
+  return hRet;
 }
 
 /*************************************************************************
@@ -3998,6 +4135,50 @@ INT WINAPI GetMenuPosFromID(HMENU hMenu, UINT wID)
  return -1;
 }
 
+/*************************************************************************
+ *      @      [SHLWAPI.179]
+ *
+ * Same as SHLWAPI.GetMenuPosFromID
+ */
+DWORD WINAPI SHMenuIndexFromID(HMENU hMenu, UINT uID)
+{
+    return GetMenuPosFromID(hMenu, uID);
+}
+
+
+/*************************************************************************
+ *      @      [SHLWAPI.448]
+ */
+VOID WINAPI FixSlashesAndColonW(LPWSTR lpwstr)
+{
+    while (*lpwstr)
+    {
+        if (*lpwstr == '/')
+            *lpwstr = '\\';
+        lpwstr++;
+    }
+}
+
+
+/*************************************************************************
+ *      @      [SHLWAPI.461]
+ */
+DWORD WINAPI SHGetAppCompatFlags(DWORD dwUnknown)
+{
+  FIXME("(0x%08lx) stub\n", dwUnknown);
+  return 0;
+}
+
+
+/*************************************************************************
+ *      @      [SHLWAPI.549]
+ */
+HRESULT WINAPI SHCoCreateInstanceAC(REFCLSID rclsid, LPUNKNOWN pUnkOuter,
+                                    DWORD dwClsContext, REFIID iid, LPVOID *ppv)
+{
+    return CoCreateInstance(rclsid, pUnkOuter, dwClsContext, iid, ppv);
+}
+
 /*************************************************************************
  * SHSkipJunction      [SHLWAPI.@]
  *
@@ -4014,7 +4195,7 @@ INT WINAPI GetMenuPosFromID(HMENU hMenu, UINT wID)
  */
 BOOL WINAPI SHSkipJunction(IBindCtx *pbc, const CLSID *pclsid)
 {
-  static WCHAR szSkipBinding[] = { 'S','k','i','p',' ',
+  static const WCHAR szSkipBinding[] = { 'S','k','i','p',' ',
     'B','i','n','d','i','n','g',' ','C','L','S','I','D','\0' };
   BOOL bRet = FALSE;
 
@@ -4022,7 +4203,7 @@ BOOL WINAPI SHSkipJunction(IBindCtx *pbc, const CLSID *pclsid)
   {
     IUnknown* lpUnk;
 
-    if (SUCCEEDED(IBindCtx_GetObjectParam(pbc, szSkipBinding, &lpUnk)))
+    if (SUCCEEDED(IBindCtx_GetObjectParam(pbc, (LPOLESTR)szSkipBinding, &lpUnk)))
     {
       CLSID clsid;
 
@@ -4036,33 +4217,80 @@ BOOL WINAPI SHSkipJunction(IBindCtx *pbc, const CLSID *pclsid)
   return bRet;
 }
 
+/***********************************************************************
+ *             SHGetShellKey (SHLWAPI.@)
+ */
 DWORD WINAPI SHGetShellKey(DWORD a, DWORD b, DWORD c)
 {
     FIXME("(%lx, %lx, %lx): stub\n", a, b, c);
     return 0x50;
 }
 
+/***********************************************************************
+ *             SHQueueUserWorkItem (SHLWAPI.@)
+ */
 HRESULT WINAPI SHQueueUserWorkItem(DWORD a, DWORD b, DWORD c, DWORD d, DWORD e, DWORD f, DWORD g)
 {
     FIXME("(%lx, %lx, %lx, %lx, %lx, %lx, %lx): stub\n", a, b, c, d, e, f, g);
     return E_FAIL;
 }
 
-DWORD WINAPI IUnknown_OnFocusChangeIS(IUnknown * pUnk, IUnknown * pFocusObject, BOOL bChange)
+/***********************************************************************
+ *             IUnknown_OnFocusChangeIS (SHLWAPI.@)
+ */
+HRESULT WINAPI IUnknown_OnFocusChangeIS(LPUNKNOWN lpUnknown, LPUNKNOWN pFocusObject, BOOL bFocus)
 {
-    FIXME("(%p, %p, %s)\n", pUnk, pFocusObject, bChange ? "TRUE" : "FALSE");
+    IInputObjectSite *pIOS = NULL;
+    HRESULT hRet = E_INVALIDARG;
 
-/*
-    IInputObjectSite * pIOS = NULL;
-    if (SUCCEEDED(IUnknown_QueryInterface(pUnk, &IID_IInputObjectSite, (void **)&pIOS))
-        IInputObjectSite_OnFocusChangeIS(pIOS, pFocusObject, bChange);
-*/
+    TRACE("(%p, %p, %s)\n", lpUnknown, pFocusObject, bFocus ? "TRUE" : "FALSE");
 
-    return 0;
+    if (lpUnknown)
+    {
+        hRet = IUnknown_QueryInterface(lpUnknown, &IID_IInputObjectSite,
+                                       (void **)&pIOS);
+        if (SUCCEEDED(hRet) && pIOS)
+        {
+            hRet = IInputObjectSite_OnFocusChangeIS(pIOS, pFocusObject, bFocus);
+            IInputObjectSite_Release(pIOS);
+        }
+    }
+    return hRet;
 }
 
+/***********************************************************************
+ *             SHGetValueW (SHLWAPI.@)
+ */
 HRESULT WINAPI SKGetValueW(DWORD a, LPWSTR b, LPWSTR c, DWORD d, DWORD e, DWORD f)
 {
     FIXME("(%lx, %s, %s, %lx, %lx, %lx): stub\n", a, debugstr_w(b), debugstr_w(c), d, e, f);
     return E_FAIL;
 }
+
+typedef HRESULT (WINAPI *DllGetVersion_func)(DLLVERSIONINFO *);
+
+/***********************************************************************
+ *              GetUIVersion (SHLWAPI.452)
+ */
+DWORD WINAPI GetUIVersion(void)
+{
+    static DWORD version;
+
+    if (!version)
+    {
+        DllGetVersion_func pDllGetVersion;
+        HMODULE dll = LoadLibraryA("shell32.dll");
+        if (!dll) return 0;
+
+        pDllGetVersion = (DllGetVersion_func)GetProcAddress(dll, "DllGetVersion");
+        if (pDllGetVersion)
+        {
+            DLLVERSIONINFO dvi;
+            dvi.cbSize = sizeof(DLLVERSIONINFO);
+            if (pDllGetVersion(&dvi) == S_OK) version = dvi.dwMajorVersion;
+        }
+        FreeLibrary( dll );
+        if (!version) version = 3;  /* old shell dlls don't have DllGetVersion */
+    }
+    return version;
+}