Implemented strtolW/strtoulW in libwine_unicode and used it to replace
wcstol and friends.

diff --git a/dlls/comctl32/comctl32undoc.c b/dlls/comctl32/comctl32undoc.c
index fedd06a..2d843c2 100644
--- a/dlls/comctl32/comctl32undoc.c
+++ b/dlls/comctl32/comctl32undoc.c
@@ -67,8 +67,6 @@
 
 typedef HRESULT (CALLBACK *DPALOADPROC)(LPLOADDATA,IStream*,LPARAM);
 
-INT __cdecl _wtoi(LPWSTR string);
-
 /**************************************************************************
  * DPA_LoadStream [COMCTL32.9]
  *
@@ -2483,7 +2481,7 @@
 INT WINAPI
 COMCTL32_StrToIntW (LPWSTR lpString)
 {
-    return _wtoi(lpString);
+    return atoiW(lpString);
 }
 
 
diff --git a/dlls/comctl32/ipaddress.c b/dlls/comctl32/ipaddress.c
index 5b200dd..8490699 100644
--- a/dlls/comctl32/ipaddress.c
+++ b/dlls/comctl32/ipaddress.c
@@ -31,6 +31,7 @@
 #include "ntddk.h"
 #include "winbase.h"
 #include "commctrl.h"
+#include "wine/unicode.h"
 #include "wine/debug.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(ipaddress);
@@ -237,7 +238,7 @@
     for (i = 0; i < 4; i++) {
         ip_addr *= 256;
         if (GetWindowTextW (infoPtr->Part[i].EditHwnd, field, 4)) 
-  	    ip_addr += wcstol(field, 0, 10);
+  	    ip_addr += atolW(field);
 	else
 	    invalid++;
     }
@@ -320,7 +321,7 @@
   
     if (!GetWindowTextW (part->EditHwnd, field, 4)) return FALSE;
     
-    curValue = wcstol(field, 0, 10);
+    curValue = atoiW(field);
     TRACE("  curValue=%d\n", curValue);
     
     newValue = IPADDRESS_IPNotify(infoPtr, currentfield, curValue);
diff --git a/dlls/comctl32/updown.c b/dlls/comctl32/updown.c
index 74cc337..1e734fa 100644
--- a/dlls/comctl32/updown.c
+++ b/dlls/comctl32/updown.c
@@ -30,6 +30,7 @@
 #include "commctrl.h"
 #include "winnls.h"
 #include "ntddk.h"
+#include "wine/unicode.h"
 #include "wine/debug.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(updown);
@@ -275,7 +276,7 @@
         *dst = 0;
 
         /* try to convert the number and validate it */
-        newVal = wcstol(txt, &src, infoPtr->Base);
+        newVal = strtolW(txt, &src, infoPtr->Base);
         if(*src || !UPDOWN_InBounds (infoPtr, newVal)) return FALSE;
     }
   
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index 687d1ef..5e46d88 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -884,7 +884,7 @@
 @ cdecl _itoa(long ptr long) _itoa
 @ cdecl _ltoa(long ptr long) _ltoa
 @ cdecl _memccpy(ptr ptr long long) memccpy
-@ cdecl _memicmp(str str long) _memicmp
+@ cdecl _memicmp(str str long) NTDLL__memicmp
 @ varargs _snprintf(ptr long ptr) snprintf
 @ varargs _snwprintf(wstr long wstr) _snwprintf
 @ cdecl _splitpath(str ptr ptr ptr ptr) _splitpath
@@ -900,8 +900,8 @@
 @ cdecl _wcslwr(wstr) NTDLL__wcslwr
 @ cdecl _wcsnicmp(wstr wstr long) NTDLL__wcsnicmp
 @ cdecl _wcsupr(wstr) NTDLL__wcsupr
-@ cdecl _wtoi(wstr) _wtoi
-@ cdecl _wtol(wstr) _wtol
+@ cdecl _wtoi(wstr) NTDLL__wtoi
+@ cdecl _wtol(wstr) NTDLL__wtol
 @ cdecl -noimport abs(long) abs
 @ cdecl -noimport atan(double) atan
 @ cdecl -noimport atoi(str) atoi
diff --git a/dlls/ntdll/string.c b/dlls/ntdll/string.c
index c05aeae..3e041a0 100644
--- a/dlls/ntdll/string.c
+++ b/dlls/ntdll/string.c
@@ -29,7 +29,7 @@
 /*********************************************************************
  *                  _memicmp   (NTDLL.@)
  */
-INT __cdecl _memicmp( LPCSTR s1, LPCSTR s2, DWORD len )
+INT __cdecl NTDLL__memicmp( LPCSTR s1, LPCSTR s2, DWORD len )
 {
     int ret = 0;
     while (len--)
diff --git a/dlls/ntdll/wcstring.c b/dlls/ntdll/wcstring.c
index 13a7751..162bc4e 100644
--- a/dlls/ntdll/wcstring.c
+++ b/dlls/ntdll/wcstring.c
@@ -303,51 +303,19 @@
 
 /*********************************************************************
  *                  wcstol  (NTDLL.@)
- * Like strtol, but for wide character strings.
  */
-INT __cdecl NTDLL_wcstol(LPCWSTR s,LPWSTR *end,INT base)
+long __cdecl NTDLL_wcstol(LPCWSTR s,LPWSTR *end,INT base)
 {
-    UNICODE_STRING uni;
-    ANSI_STRING ansi;
-    INT ret;
-    LPSTR endA;
-
-    RtlInitUnicodeString( &uni, s );
-    RtlUnicodeStringToAnsiString( &ansi, &uni, TRUE );
-    ret = strtol( ansi.Buffer, &endA, base );
-    if (end)
-    {
-        DWORD len;
-        RtlMultiByteToUnicodeSize( &len, ansi.Buffer, endA - ansi.Buffer );
-        *end = (LPWSTR)s + len/sizeof(WCHAR);
-    }
-    RtlFreeAnsiString( &ansi );
-    return ret;
+    return strtolW( s, end, base );
 }
 
 
 /*********************************************************************
  *                  wcstoul  (NTDLL.@)
- * Like strtoul, but for wide character strings.
  */
-INT __cdecl NTDLL_wcstoul(LPCWSTR s,LPWSTR *end,INT base)
+unsigned long __cdecl NTDLL_wcstoul(LPCWSTR s,LPWSTR *end,INT base)
 {
-    UNICODE_STRING uni;
-    ANSI_STRING ansi;
-    INT ret;
-    LPSTR endA;
-
-    RtlInitUnicodeString( &uni, s );
-    RtlUnicodeStringToAnsiString( &ansi, &uni, TRUE );
-    ret = strtoul( ansi.Buffer, &endA, base );
-    if (end)
-    {
-        DWORD len;
-        RtlMultiByteToUnicodeSize( &len, ansi.Buffer, endA - ansi.Buffer );
-        *end = (LPWSTR)s + len/sizeof(WCHAR);
-    }
-    RtlFreeAnsiString( &ansi );
-    return ret;
+    return strtoulW( s, end, base );
 }
 
 
@@ -405,19 +373,17 @@
  *           _wtol    (NTDLL.@)
  * Like atol, but for wide character strings.
  */
-LONG __cdecl _wtol(LPWSTR string)
+LONG __cdecl NTDLL__wtol(LPWSTR string)
 {
-    char buffer[30];
-    NTDLL_wcstombs( buffer, string, sizeof(buffer) );
-    return atol( buffer );
+    return strtolW( string, NULL, 10 );
 }
 
 /*********************************************************************
  *           _wtoi    (NTDLL.@)
  */
-INT __cdecl _wtoi(LPWSTR string)
+INT __cdecl NTDLL__wtoi(LPWSTR string)
 {
-    return _wtol(string);
+    return NTDLL__wtol(string);
 }
 
 /* INTERNAL: Wide char snprintf
diff --git a/dlls/oleaut32/Makefile.in b/dlls/oleaut32/Makefile.in
index 7e0b2b7..45f1dae 100644
--- a/dlls/oleaut32/Makefile.in
+++ b/dlls/oleaut32/Makefile.in
@@ -6,7 +6,7 @@
 IMPORTS   = ole32 user32 gdi32 advapi32 kernel32 ntdll
 DELAYIMPORTS = comctl32
 ALTNAMES  = ole2disp.dll typelib.dll
-EXTRALIBS = $(LIBUUID) @JPEGLIB@
+EXTRALIBS = $(LIBUNICODE) $(LIBUUID) @JPEGLIB@
 
 LDDLLFLAGS = @LDDLLFLAGS@
 SYMBOLFILE = $(MODULE).tmp.o
diff --git a/dlls/oleaut32/typelib.c b/dlls/oleaut32/typelib.c
index 8afe1fa..b6d7894 100644
--- a/dlls/oleaut32/typelib.c
+++ b/dlls/oleaut32/typelib.c
@@ -70,7 +70,6 @@
 #include "ole2disp.h"
 #include "typelib.h"
 #include "wine/debug.h"
-#include "ntddk.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(ole);
 WINE_DECLARE_DEBUG_CHANNEL(typelib);
@@ -287,7 +286,7 @@
         /* Look for a trailing '\\' followed by an index */
         pIndexStr = strrchrW(szFile, '\\');
 	if(pIndexStr && pIndexStr != szFile && *++pIndexStr != '\0') {
-	    index = wcstol(pIndexStr, NULL, 10);
+	    index = atoiW(pIndexStr);
 	    memcpy(szFileCopy, szFile,
 		   (pIndexStr - szFile - 1) * sizeof(WCHAR));
 	    szFileCopy[pIndexStr - szFile - 1] = '\0';
diff --git a/dlls/setupapi/install.c b/dlls/setupapi/install.c
index 9390d04..e3f8adf 100644
--- a/dlls/setupapi/install.c
+++ b/dlls/setupapi/install.c
@@ -315,7 +315,7 @@
 
         if (type == REG_DWORD)
         {
-            DWORD dw = str ? wcstol( str, NULL, 16 ) : 0;
+            DWORD dw = str ? strtolW( str, NULL, 16 ) : 0;
             TRACE( "setting dword %s to %lx\n", debugstr_w(value), dw );
             RegSetValueExW( hkey, value, 0, type, (BYTE *)&dw, sizeof(dw) );
         }
diff --git a/dlls/setupapi/parser.c b/dlls/setupapi/parser.c
index e17be95..3fc74e6 100644
--- a/dlls/setupapi/parser.c
+++ b/dlls/setupapi/parser.c
@@ -327,7 +327,7 @@
     {
         memcpy( dirid_str, str, *len * sizeof(WCHAR) );
         dirid_str[*len] = 0;
-        dirid = wcstol( dirid_str, &end, 10 );
+        dirid = strtolW( dirid_str, &end, 10 );
         if (!*end) ret = get_dirid_subst( dirid, len );
         HeapFree( GetProcessHeap(), 0, dirid_str );
         return ret;
diff --git a/include/ntddk.h b/include/ntddk.h
index a8256e7..54879b7 100644
--- a/include/ntddk.h
+++ b/include/ntddk.h
@@ -759,7 +759,6 @@
 	DWORD len,
 	DWORD *pf);
 
-INT __cdecl wcstol(LPCWSTR,LPWSTR*,INT);
 int __cdecl swprintf(LPWSTR,LPCWSTR,...);
 
 /*	resource functions */
diff --git a/include/wine/unicode.h b/include/wine/unicode.h
index 7fa9afa..1d48a98 100644
--- a/include/wine/unicode.h
+++ b/include/wine/unicode.h
@@ -71,6 +71,12 @@
 extern int utf8_wcstombs( const WCHAR *src, int srclen, char *dst, int dstlen );
 extern int utf8_mbstowcs( int flags, const char *src, int srclen, WCHAR *dst, int dstlen );
 
+extern int strcmpiW( const WCHAR *str1, const WCHAR *str2 );
+extern int strncmpiW( const WCHAR *str1, const WCHAR *str2, int n );
+extern WCHAR *strstrW( const WCHAR *str, const WCHAR *sub );
+extern long int strtolW( const WCHAR *nptr, WCHAR **endptr, int base );
+extern unsigned long int strtoulW( const WCHAR *nptr, WCHAR **endptr, int base );
+
 static inline int is_dbcs_leadbyte( const union cptable *table, unsigned char ch )
 {
     return (table->info.char_size == 2) && (table->dbcs.cp2uni_leadbytes[ch]);
@@ -244,8 +250,14 @@
     return ret;
 }
 
-extern int strcmpiW( const WCHAR *str1, const WCHAR *str2 );
-extern int strncmpiW( const WCHAR *str1, const WCHAR *str2, int n );
-extern WCHAR *strstrW( const WCHAR *str, const WCHAR *sub );
+static inline long int atolW( const WCHAR *str )
+{
+    return strtolW( str, (WCHAR **)0, 10 );
+}
+
+static inline int atoiW( const WCHAR *str )
+{
+    return (int)atolW( str );
+}
 
 #endif  /* __WINE_UNICODE_H */
diff --git a/unicode/string.c b/unicode/string.c
index 47bce77..7b69204 100644
--- a/unicode/string.c
+++ b/unicode/string.c
@@ -18,6 +18,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include <limits.h>
+
 #include "wine/unicode.h"
 
 int strcmpiW( const WCHAR *str1, const WCHAR *str2 )
@@ -50,3 +52,237 @@
     }
     return NULL;
 }
+
+/* strtolW and strtoulW implementation based on the GNU C library code */
+/* Copyright (C) 1991,92,94,95,96,97,98,99,2000,2001 Free Software Foundation, Inc. */
+
+long int strtolW( const WCHAR *nptr, WCHAR **endptr, int base )
+{
+  int negative;
+  register unsigned long int cutoff;
+  register unsigned int cutlim;
+  register unsigned long int i;
+  register const WCHAR *s;
+  register WCHAR c;
+  const WCHAR *save, *end;
+  int overflow;
+
+  if (base < 0 || base == 1 || base > 36) return 0;
+
+  save = s = nptr;
+
+  /* Skip white space.  */
+  while (isspaceW (*s))
+    ++s;
+  if (!*s) goto noconv;
+
+  /* Check for a sign.  */
+  negative = 0;
+  if (*s == '-')
+    {
+      negative = 1;
+      ++s;
+    }
+  else if (*s == '+')
+    ++s;
+
+  /* Recognize number prefix and if BASE is zero, figure it out ourselves.  */
+  if (*s == '0')
+    {
+      if ((base == 0 || base == 16) && toupperW(s[1]) == 'X')
+	{
+	  s += 2;
+	  base = 16;
+	}
+      else if (base == 0)
+	base = 8;
+    }
+  else if (base == 0)
+    base = 10;
+
+  /* Save the pointer so we can check later if anything happened.  */
+  save = s;
+  end = NULL;
+
+  cutoff = ULONG_MAX / (unsigned long int) base;
+  cutlim = ULONG_MAX % (unsigned long int) base;
+
+  overflow = 0;
+  i = 0;
+  c = *s;
+  for (;c != '\0'; c = *++s)
+  {
+      if (s == end)
+          break;
+      if (c >= '0' && c <= '9')
+          c -= '0';
+      else if (isalphaW (c))
+          c = toupperW (c) - 'A' + 10;
+      else
+          break;
+      if ((int) c >= base)
+          break;
+      /* Check for overflow.  */
+      if (i > cutoff || (i == cutoff && c > cutlim))
+          overflow = 1;
+      else
+      {
+          i *= (unsigned long int) base;
+          i += c;
+      }
+  }
+
+  /* Check if anything actually happened.  */
+  if (s == save)
+    goto noconv;
+
+  /* Store in ENDPTR the address of one character
+     past the last character we converted.  */
+  if (endptr != NULL)
+    *endptr = (WCHAR *)s;
+
+  /* Check for a value that is within the range of
+     `unsigned LONG int', but outside the range of `LONG int'.  */
+  if (overflow == 0
+      && i > (negative
+	      ? -((unsigned long int) (LONG_MIN + 1)) + 1
+	      : (unsigned long int) LONG_MAX))
+    overflow = 1;
+
+  if (overflow)
+    {
+      return negative ? LONG_MIN : LONG_MAX;
+    }
+
+  /* Return the result of the appropriate sign.  */
+  return negative ? -i : i;
+
+noconv:
+  /* We must handle a special case here: the base is 0 or 16 and the
+     first two characters are '0' and 'x', but the rest are no
+     hexadecimal digits.  This is no error case.  We return 0 and
+     ENDPTR points to the `x`.  */
+  if (endptr != NULL)
+    {
+      if (save - nptr >= 2 && toupperW (save[-1]) == 'X'
+	  && save[-2] == '0')
+	*endptr = (WCHAR *)&save[-1];
+      else
+	/*  There was no number to convert.  */
+	*endptr = (WCHAR *)nptr;
+    }
+
+  return 0L;
+}
+
+
+unsigned long int strtoulW( const WCHAR *nptr, WCHAR **endptr, int base )
+{
+  int negative;
+  register unsigned long int cutoff;
+  register unsigned int cutlim;
+  register unsigned long int i;
+  register const WCHAR *s;
+  register WCHAR c;
+  const WCHAR *save, *end;
+  int overflow;
+
+  if (base < 0 || base == 1 || base > 36) return 0;
+
+  save = s = nptr;
+
+  /* Skip white space.  */
+  while (isspaceW (*s))
+    ++s;
+  if (!*s) goto noconv;
+
+  /* Check for a sign.  */
+  negative = 0;
+  if (*s == '-')
+    {
+      negative = 1;
+      ++s;
+    }
+  else if (*s == '+')
+    ++s;
+
+  /* Recognize number prefix and if BASE is zero, figure it out ourselves.  */
+  if (*s == '0')
+    {
+      if ((base == 0 || base == 16) && toupperW(s[1]) == 'X')
+	{
+	  s += 2;
+	  base = 16;
+	}
+      else if (base == 0)
+	base = 8;
+    }
+  else if (base == 0)
+    base = 10;
+
+  /* Save the pointer so we can check later if anything happened.  */
+  save = s;
+  end = NULL;
+
+  cutoff = ULONG_MAX / (unsigned long int) base;
+  cutlim = ULONG_MAX % (unsigned long int) base;
+
+  overflow = 0;
+  i = 0;
+  c = *s;
+  for (;c != '\0'; c = *++s)
+  {
+      if (s == end)
+          break;
+      if (c >= '0' && c <= '9')
+          c -= '0';
+      else if (isalphaW (c))
+          c = toupperW (c) - 'A' + 10;
+      else
+          break;
+      if ((int) c >= base)
+          break;
+      /* Check for overflow.  */
+      if (i > cutoff || (i == cutoff && c > cutlim))
+          overflow = 1;
+      else
+      {
+          i *= (unsigned long int) base;
+          i += c;
+      }
+  }
+
+  /* Check if anything actually happened.  */
+  if (s == save)
+    goto noconv;
+
+  /* Store in ENDPTR the address of one character
+     past the last character we converted.  */
+  if (endptr != NULL)
+    *endptr = (WCHAR *)s;
+
+  if (overflow)
+    {
+      return ULONG_MAX;
+    }
+
+  /* Return the result of the appropriate sign.  */
+  return negative ? -i : i;
+
+noconv:
+  /* We must handle a special case here: the base is 0 or 16 and the
+     first two characters are '0' and 'x', but the rest are no
+     hexadecimal digits.  This is no error case.  We return 0 and
+     ENDPTR points to the `x`.  */
+  if (endptr != NULL)
+    {
+      if (save - nptr >= 2 && toupperW (save[-1]) == 'X'
+	  && save[-2] == '0')
+	*endptr = (WCHAR *)&save[-1];
+      else
+	/*  There was no number to convert.  */
+	*endptr = (WCHAR *)nptr;
+    }
+
+  return 0L;
+}