dbghelp: Implement SymEnumSourceFilesW.
[wine] / dlls / wininet / internet.c
index 3d87a73..c865368 100644 (file)
@@ -88,9 +88,7 @@ typedef struct
 } WITHREADERROR, *LPWITHREADERROR;
 
 static DWORD g_dwTlsErrIndex = TLS_OUT_OF_INDEXES;
-static HMODULE WININET_hModule;
-
-#define HANDLE_CHUNK_SIZE 0x10
+HMODULE WININET_hModule;
 
 static CRITICAL_SECTION WININET_cs;
 static CRITICAL_SECTION_DEBUG WININET_cs_debug = 
@@ -101,52 +99,88 @@ static CRITICAL_SECTION_DEBUG WININET_cs_debug =
 };
 static CRITICAL_SECTION WININET_cs = { &WININET_cs_debug, -1, 0, 0, 0, 0 };
 
-static object_header_t **WININET_Handles;
-static UINT WININET_dwNextHandle;
-static UINT WININET_dwMaxHandles;
+static object_header_t **handle_table;
+static UINT_PTR next_handle;
+static UINT_PTR handle_table_size;
 
-HINTERNET WININET_AllocHandle( object_header_t *info )
+typedef struct
+{
+    DWORD dwProxyEnabled;
+    LPWSTR lpszProxyServer;
+    LPWSTR lpszProxyBypass;
+} proxyinfo_t;
+
+static const WCHAR szInternetSettings[] =
+    { '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','\\',
+      'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0 };
+static const WCHAR szProxyServer[] = { 'P','r','o','x','y','S','e','r','v','e','r', 0 };
+static const WCHAR szProxyEnable[] = { 'P','r','o','x','y','E','n','a','b','l','e', 0 };
+
+void *alloc_object(object_header_t *parent, const object_vtbl_t *vtbl, size_t size)
 {
+    UINT_PTR handle = 0, num;
+    object_header_t *ret;
     object_header_t **p;
-    UINT handle = 0, num;
+    BOOL res = TRUE;
 
-    list_init( &info->children );
+    ret = heap_alloc_zero(size);
+    if(!ret)
+        return NULL;
+
+    list_init(&ret->children);
 
     EnterCriticalSection( &WININET_cs );
-    if( !WININET_dwMaxHandles )
-    {
-        num = HANDLE_CHUNK_SIZE;
-        p = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 
-                   sizeof (*WININET_Handles)* num);
-        if( !p )
-            goto end;
-        WININET_Handles = p;
-        WININET_dwMaxHandles = num;
-    }
-    if( WININET_dwMaxHandles == WININET_dwNextHandle )
-    {
-        num = WININET_dwMaxHandles + HANDLE_CHUNK_SIZE;
-        p = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
-                   WININET_Handles, sizeof (*WININET_Handles)* num);
-        if( !p )
-            goto end;
-        WININET_Handles = p;
-        WININET_dwMaxHandles = num;
-    }
-
-    handle = WININET_dwNextHandle;
-    if( WININET_Handles[handle] )
-        ERR("handle isn't free but should be\n");
-    WININET_Handles[handle] = WININET_AddRef( info );
-
-    while( WININET_Handles[WININET_dwNextHandle] && 
-           (WININET_dwNextHandle < WININET_dwMaxHandles ) )
-        WININET_dwNextHandle++;
-    
-end:
+
+    if(!handle_table_size) {
+        num = 16;
+        p = heap_alloc_zero(sizeof(handle_table[0]) * num);
+        if(p) {
+            handle_table = p;
+            handle_table_size = num;
+            next_handle = 1;
+        }else {
+            res = FALSE;
+        }
+    }else if(next_handle == handle_table_size) {
+        num = handle_table_size * 2;
+        p = heap_realloc_zero(handle_table, sizeof(handle_table[0]) * num);
+        if(p) {
+            handle_table = p;
+            handle_table_size = num;
+        }else {
+            res = FALSE;
+        }
+    }
+
+    if(res) {
+        handle = next_handle;
+        if(handle_table[handle])
+            ERR("handle isn't free but should be\n");
+        handle_table[handle] = ret;
+        ret->valid_handle = TRUE;
+
+        while(handle_table[next_handle] && next_handle < handle_table_size)
+            next_handle++;
+    }
+
     LeaveCriticalSection( &WININET_cs );
 
-    return info->hInternet = (HINTERNET) (handle+1);
+    if(!res) {
+        heap_free(ret);
+        return NULL;
+    }
+
+    ret->vtbl = vtbl;
+    ret->refs = 1;
+    ret->hInternet = (HINTERNET)handle;
+
+    if(parent) {
+        ret->lpfnStatusCB = parent->lpfnStatusCB;
+        ret->dwInternalFlags = parent->dwInternalFlags & INET_CALLBACKW;
+    }
+
+    return ret;
 }
 
 object_header_t *WININET_AddRef( object_header_t *info )
@@ -156,30 +190,48 @@ object_header_t *WININET_AddRef( object_header_t *info )
     return info;
 }
 
-object_header_t *WININET_GetObject( HINTERNET hinternet )
+object_header_t *get_handle_object( HINTERNET hinternet )
 {
     object_header_t *info = NULL;
-    UINT handle = (UINT) hinternet;
+    UINT_PTR handle = (UINT_PTR) hinternet;
 
     EnterCriticalSection( &WININET_cs );
 
-    if( (handle > 0) && ( handle <= WININET_dwMaxHandles ) && 
-        WININET_Handles[handle-1] )
-        info = WININET_AddRef( WININET_Handles[handle-1] );
+    if(handle > 0 && handle < handle_table_size && handle_table[handle] && handle_table[handle]->valid_handle)
+        info = WININET_AddRef(handle_table[handle]);
 
     LeaveCriticalSection( &WININET_cs );
 
-    TRACE("handle %d -> %p\n", handle, info);
+    TRACE("handle %ld -> %p\n", handle, info);
 
     return info;
 }
 
+static void invalidate_handle(object_header_t *info)
+{
+    object_header_t *child, *next;
+
+    if(!info->valid_handle)
+        return;
+    info->valid_handle = FALSE;
+
+    /* Free all children as native does */
+    LIST_FOR_EACH_ENTRY_SAFE( child, next, &info->children, object_header_t, entry )
+    {
+        TRACE("invalidating child handle %p for parent %p\n", child->hInternet, info);
+        invalidate_handle( child );
+    }
+
+    WININET_Release(info);
+}
+
 BOOL WININET_Release( object_header_t *info )
 {
     ULONG refs = InterlockedDecrement(&info->refs);
     TRACE( "object %p refcount = %d\n", info, refs );
     if( !refs )
     {
+        invalidate_handle(info);
         if ( info->vtbl->CloseConnection )
         {
             TRACE( "closing connection %p\n", info);
@@ -197,55 +249,22 @@ BOOL WININET_Release( object_header_t *info )
         if ( info->htype != WH_HINIT )
             list_remove( &info->entry );
         info->vtbl->Destroy( info );
-    }
-    return TRUE;
-}
 
-BOOL WININET_FreeHandle( HINTERNET hinternet )
-{
-    BOOL ret = FALSE;
-    UINT handle = (UINT) hinternet;
-    object_header_t *info = NULL, *child, *next;
+        if(info->hInternet) {
+            UINT_PTR handle = (UINT_PTR)info->hInternet;
 
-    EnterCriticalSection( &WININET_cs );
+            EnterCriticalSection( &WININET_cs );
 
-    if( (handle > 0) && ( handle <= WININET_dwMaxHandles ) )
-    {
-        handle--;
-        if( WININET_Handles[handle] )
-        {
-            info = WININET_Handles[handle];
-            TRACE( "destroying handle %d for object %p\n", handle+1, info);
-            WININET_Handles[handle] = NULL;
-            ret = TRUE;
-        }
-    }
+            handle_table[handle] = NULL;
+            if(next_handle > handle)
+                next_handle = handle;
 
-    LeaveCriticalSection( &WININET_cs );
-
-    /* As on native when the equivalent of WININET_Release is called, the handle
-     * is already invalid, but if a new handle is created at this time it does
-     * not yet get assigned the freed handle number */
-    if( info )
-    {
-        /* Free all children as native does */
-        LIST_FOR_EACH_ENTRY_SAFE( child, next, &info->children, object_header_t, entry )
-        {
-            TRACE( "freeing child handle %d for parent handle %d\n",
-                   (UINT)child->hInternet, handle+1);
-            WININET_FreeHandle( child->hInternet );
+            LeaveCriticalSection( &WININET_cs );
         }
-        WININET_Release( info );
-    }
 
-    EnterCriticalSection( &WININET_cs );
-
-    if( WININET_dwNextHandle > handle && !WININET_Handles[handle] )
-        WININET_dwNextHandle = handle;
-
-    LeaveCriticalSection( &WININET_cs );
-
-    return ret;
+        heap_free(info);
+    }
+    return TRUE;
 }
 
 /***********************************************************************
@@ -281,28 +300,161 @@ BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
            break;
 
         case DLL_THREAD_DETACH:
-           if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
-                       {
-                               LPVOID lpwite = TlsGetValue(g_dwTlsErrIndex);
-                                HeapFree(GetProcessHeap(), 0, lpwite);
-                       }
-           break;
+            if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
+            {
+                heap_free(TlsGetValue(g_dwTlsErrIndex));
+            }
+            break;
 
         case DLL_PROCESS_DETACH:
+            collect_connections(TRUE);
+            NETCON_unload();
+            URLCacheContainers_DeleteAll();
 
-           URLCacheContainers_DeleteAll();
-
-           if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
-           {
-               HeapFree(GetProcessHeap(), 0, TlsGetValue(g_dwTlsErrIndex));
-               TlsFree(g_dwTlsErrIndex);
-           }
+            if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
+            {
+                heap_free(TlsGetValue(g_dwTlsErrIndex));
+                TlsFree(g_dwTlsErrIndex);
+            }
             break;
     }
-
     return TRUE;
 }
 
+/***********************************************************************
+ *           INTERNET_SaveProxySettings
+ *
+ * Stores the proxy settings given by lpwai into the registry
+ *
+ * RETURNS
+ *     ERROR_SUCCESS if no error, or error code on fail
+ */
+static LONG INTERNET_SaveProxySettings( proxyinfo_t *lpwpi )
+{
+    HKEY key;
+    LONG ret;
+
+    if ((ret = RegOpenKeyW( HKEY_CURRENT_USER, szInternetSettings, &key )))
+        return ret;
+
+    if ((ret = RegSetValueExW( key, szProxyEnable, 0, REG_DWORD, (BYTE*)&lpwpi->dwProxyEnabled, sizeof(DWORD))))
+    {
+        RegCloseKey( key );
+        return ret;
+    }
+
+    if (lpwpi->lpszProxyServer)
+    {
+        if ((ret = RegSetValueExW( key, szProxyServer, 0, REG_SZ, (BYTE*)lpwpi->lpszProxyServer, sizeof(WCHAR) * (lstrlenW(lpwpi->lpszProxyServer) + 1))))
+        {
+            RegCloseKey( key );
+            return ret;
+        }
+    }
+    else
+    {
+        if ((ret = RegDeleteValueW( key, szProxyServer )))
+        {
+            RegCloseKey( key );
+            return ret;
+        }
+    }
+
+    RegCloseKey(key);
+    return ERROR_SUCCESS;
+}
+
+/***********************************************************************
+ *           INTERNET_FindProxyForProtocol
+ *
+ * Searches the proxy string for a proxy of the given protocol.
+ * Returns the found proxy, or the default proxy if none of the given
+ * protocol is found.
+ *
+ * PARAMETERS
+ *     szProxy       [In]     proxy string to search
+ *     proto         [In]     protocol to search for, e.g. "http"
+ *     foundProxy    [Out]    found proxy
+ *     foundProxyLen [In/Out] length of foundProxy buffer, in WCHARs
+ *
+ * RETURNS
+ *     TRUE if a proxy is found, FALSE if not.  If foundProxy is too short,
+ *     *foundProxyLen is set to the required size in WCHARs, including the
+ *     NULL terminator, and the last error is set to ERROR_INSUFFICIENT_BUFFER.
+ */
+BOOL INTERNET_FindProxyForProtocol(LPCWSTR szProxy, LPCWSTR proto, WCHAR *foundProxy, DWORD *foundProxyLen)
+{
+    LPCWSTR ptr;
+    BOOL ret = FALSE;
+
+    TRACE("(%s, %s)\n", debugstr_w(szProxy), debugstr_w(proto));
+
+    /* First, look for the specified protocol (proto=scheme://host:port) */
+    for (ptr = szProxy; !ret && ptr && *ptr; )
+    {
+        LPCWSTR end, equal;
+
+        if (!(end = strchrW(ptr, ' ')))
+            end = ptr + strlenW(ptr);
+        if ((equal = strchrW(ptr, '=')) && equal < end &&
+             equal - ptr == strlenW(proto) &&
+             !strncmpiW(proto, ptr, strlenW(proto)))
+        {
+            if (end - equal > *foundProxyLen)
+            {
+                WARN("buffer too short for %s\n",
+                     debugstr_wn(equal + 1, end - equal - 1));
+                *foundProxyLen = end - equal;
+                SetLastError(ERROR_INSUFFICIENT_BUFFER);
+            }
+            else
+            {
+                memcpy(foundProxy, equal + 1, (end - equal) * sizeof(WCHAR));
+                foundProxy[end - equal] = 0;
+                ret = TRUE;
+            }
+        }
+        if (*end == ' ')
+            ptr = end + 1;
+        else
+            ptr = end;
+    }
+    if (!ret)
+    {
+        /* It wasn't found: look for no protocol */
+        for (ptr = szProxy; !ret && ptr && *ptr; )
+        {
+            LPCWSTR end, equal;
+
+            if (!(end = strchrW(ptr, ' ')))
+                end = ptr + strlenW(ptr);
+            if (!(equal = strchrW(ptr, '=')))
+            {
+                if (end - ptr + 1 > *foundProxyLen)
+                {
+                    WARN("buffer too short for %s\n",
+                         debugstr_wn(ptr, end - ptr));
+                    *foundProxyLen = end - ptr + 1;
+                    SetLastError(ERROR_INSUFFICIENT_BUFFER);
+                }
+                else
+                {
+                    memcpy(foundProxy, ptr, (end - ptr) * sizeof(WCHAR));
+                    foundProxy[end - ptr] = 0;
+                    ret = TRUE;
+                }
+            }
+            if (*end == ' ')
+                ptr = end + 1;
+            else
+                ptr = end;
+        }
+    }
+    if (ret)
+        TRACE("found proxy for %s: %s\n", debugstr_w(proto),
+              debugstr_w(foundProxy));
+    return ret;
+}
 
 /***********************************************************************
  *           InternetInitializeAutoProxyDll   (WININET.@)
@@ -319,7 +471,7 @@ BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
 BOOL WINAPI InternetInitializeAutoProxyDll(DWORD dwReserved)
 {
     FIXME("STUB\n");
-    INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
     return FALSE;
 }
 
@@ -336,37 +488,49 @@ BOOL WINAPI DetectAutoProxyUrl(LPSTR lpszAutoProxyUrl,
        DWORD dwAutoProxyUrlLength, DWORD dwDetectFlags)
 {
     FIXME("STUB\n");
-    INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
     return FALSE;
 }
 
+static void FreeProxyInfo( proxyinfo_t *lpwpi )
+{
+    heap_free(lpwpi->lpszProxyServer);
+    heap_free(lpwpi->lpszProxyBypass);
+}
 
 /***********************************************************************
- *           INTERNET_ConfigureProxy
+ *          INTERNET_LoadProxySettings
+ *
+ * Loads proxy information from the registry or environment into lpwpi.
+ *
+ * The caller should call FreeProxyInfo when done with lpwpi.
  *
  * FIXME:
  * The proxy may be specified in the form 'http=proxy.my.org'
  * Presumably that means there can be ftp=ftpproxy.my.org too.
  */
-static BOOL INTERNET_ConfigureProxy( LPWININETAPPINFOW lpwai )
+static LONG INTERNET_LoadProxySettings( proxyinfo_t *lpwpi )
 {
     HKEY key;
-    DWORD type, len, enabled = 0;
+    DWORD type, len;
     LPCSTR envproxy;
-    static const WCHAR szInternetSettings[] =
-        { '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','\\',
-          'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0 };
-    static const WCHAR szProxyServer[] = { 'P','r','o','x','y','S','e','r','v','e','r', 0 };
-    static const WCHAR szProxyEnable[] = { 'P','r','o','x','y','E','n','a','b','l','e', 0 };
+    LONG ret;
 
-    if (RegOpenKeyW( HKEY_CURRENT_USER, szInternetSettings, &key )) return FALSE;
+    if ((ret = RegOpenKeyW( HKEY_CURRENT_USER, szInternetSettings, &key )))
+        return ret;
 
-    len = sizeof enabled;
-    if (RegQueryValueExW( key, szProxyEnable, NULL, &type, (BYTE *)&enabled, &len ) || type != REG_DWORD)
-        RegSetValueExW( key, szProxyEnable, 0, REG_DWORD, (BYTE *)&enabled, sizeof(REG_DWORD) );
+    len = sizeof(DWORD);
+    if (RegQueryValueExW( key, szProxyEnable, NULL, &type, (BYTE *)&lpwpi->dwProxyEnabled, &len ) || type != REG_DWORD)
+    {
+        lpwpi->dwProxyEnabled = 0;
+        if((ret = RegSetValueExW( key, szProxyEnable, 0, REG_DWORD, (BYTE *)&lpwpi->dwProxyEnabled, sizeof(DWORD) )))
+        {
+            RegCloseKey( key );
+            return ret;
+        }
+    }
 
-    if (enabled)
+    if (!(envproxy = getenv( "http_proxy" )) || lpwpi->dwProxyEnabled)
     {
         TRACE("Proxy is enabled.\n");
 
@@ -376,10 +540,10 @@ static BOOL INTERNET_ConfigureProxy( LPWININETAPPINFOW lpwai )
             LPWSTR szProxy, p;
             static const WCHAR szHttp[] = {'h','t','t','p','=',0};
 
-            if (!(szProxy = HeapAlloc( GetProcessHeap(), 0, len )))
+            if (!(szProxy = heap_alloc(len)))
             {
                 RegCloseKey( key );
-                return FALSE;
+                return ERROR_OUTOFMEMORY;
             }
             RegQueryValueExW( key, szProxyServer, NULL, &type, (BYTE*)szProxy, &len );
 
@@ -393,35 +557,56 @@ static BOOL INTERNET_ConfigureProxy( LPWININETAPPINFOW lpwai )
             p = strchrW( szProxy, ' ' );
             if (p) *p = 0;
 
-            lpwai->dwAccessType = INTERNET_OPEN_TYPE_PROXY;
-            lpwai->lpszProxy = szProxy;
+            lpwpi->lpszProxyServer = szProxy;
 
-            TRACE("http proxy = %s\n", debugstr_w(lpwai->lpszProxy));
+            TRACE("http proxy = %s\n", debugstr_w(lpwpi->lpszProxyServer));
         }
         else
-            ERR("Couldn't read proxy server settings from registry.\n");
+        {
+            TRACE("No proxy server settings in registry.\n");
+            lpwpi->lpszProxyServer = NULL;
+        }
     }
-    else if ((envproxy = getenv( "http_proxy" )))
+    else if (envproxy)
     {
         WCHAR *envproxyW;
 
         len = MultiByteToWideChar( CP_UNIXCP, 0, envproxy, -1, NULL, 0 );
-        if (!(envproxyW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR)))) return FALSE;
+        if (!(envproxyW = heap_alloc(len * sizeof(WCHAR))))
+            return ERROR_OUTOFMEMORY;
         MultiByteToWideChar( CP_UNIXCP, 0, envproxy, -1, envproxyW, len );
 
-        lpwai->dwAccessType = INTERNET_OPEN_TYPE_PROXY;
-        lpwai->lpszProxy = envproxyW;
+        lpwpi->dwProxyEnabled = 1;
+        lpwpi->lpszProxyServer = envproxyW;
 
-        TRACE("http proxy (from environment) = %s\n", debugstr_w(lpwai->lpszProxy));
-        enabled = 1;
+        TRACE("http proxy (from environment) = %s\n", debugstr_w(lpwpi->lpszProxyServer));
     }
-    if (!enabled)
+    RegCloseKey( key );
+
+    lpwpi->lpszProxyBypass = NULL;
+
+    return ERROR_SUCCESS;
+}
+
+/***********************************************************************
+ *           INTERNET_ConfigureProxy
+ */
+static BOOL INTERNET_ConfigureProxy( appinfo_t *lpwai )
+{
+    proxyinfo_t wpi;
+
+    if (INTERNET_LoadProxySettings( &wpi ))
+        return FALSE;
+
+    if (wpi.dwProxyEnabled)
     {
-        TRACE("Proxy is not enabled.\n");
-        lpwai->dwAccessType = INTERNET_OPEN_TYPE_DIRECT;
+        lpwai->accessType = INTERNET_OPEN_TYPE_PROXY;
+        lpwai->proxy = wpi.lpszProxyServer;
+        return TRUE;
     }
-    RegCloseKey( key );
-    return (enabled > 0);
+
+    lpwai->accessType = INTERNET_OPEN_TYPE_DIRECT;
+    return FALSE;
 }
 
 /***********************************************************************
@@ -489,21 +674,20 @@ static void dump_INTERNET_FLAGS(DWORD dwFlags)
  */
 static VOID APPINFO_Destroy(object_header_t *hdr)
 {
-    LPWININETAPPINFOW lpwai = (LPWININETAPPINFOW) hdr;
+    appinfo_t *lpwai = (appinfo_t*)hdr;
 
     TRACE("%p\n",lpwai);
 
-    HeapFree(GetProcessHeap(), 0, lpwai->lpszAgent);
-    HeapFree(GetProcessHeap(), 0, lpwai->lpszProxy);
-    HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyBypass);
-    HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyUsername);
-    HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyPassword);
-    HeapFree(GetProcessHeap(), 0, lpwai);
+    heap_free(lpwai->agent);
+    heap_free(lpwai->proxy);
+    heap_free(lpwai->proxyBypass);
+    heap_free(lpwai->proxyUsername);
+    heap_free(lpwai->proxyPassword);
 }
 
 static DWORD APPINFO_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
 {
-    LPWININETAPPINFOW ai = (LPWININETAPPINFOW)hdr;
+    appinfo_t *ai = (appinfo_t*)hdr;
 
     switch(option) {
     case INTERNET_OPTION_HANDLE_TYPE:
@@ -524,17 +708,36 @@ static DWORD APPINFO_QueryOption(object_header_t *hdr, DWORD option, void *buffe
         bufsize = *size;
 
         if (unicode) {
-            *size = (strlenW(ai->lpszAgent) + 1) * sizeof(WCHAR);
+            DWORD len = ai->agent ? strlenW(ai->agent) : 0;
+
+            *size = (len + 1) * sizeof(WCHAR);
             if(!buffer || bufsize < *size)
                 return ERROR_INSUFFICIENT_BUFFER;
 
-            strcpyW(buffer, ai->lpszAgent);
+            if (ai->agent)
+                strcpyW(buffer, ai->agent);
+            else
+                *(WCHAR *)buffer = 0;
+            /* If the buffer is copied, the returned length doesn't include
+             * the NULL terminator.
+             */
+            *size = len * sizeof(WCHAR);
         }else {
-            *size = WideCharToMultiByte(CP_ACP, 0, ai->lpszAgent, -1, NULL, 0, NULL, NULL);
+            if (ai->agent)
+                *size = WideCharToMultiByte(CP_ACP, 0, ai->agent, -1, NULL, 0, NULL, NULL);
+            else
+                *size = 1;
             if(!buffer || bufsize < *size)
                 return ERROR_INSUFFICIENT_BUFFER;
 
-            WideCharToMultiByte(CP_ACP, 0, ai->lpszAgent, -1, buffer, *size, NULL, NULL);
+            if (ai->agent)
+                WideCharToMultiByte(CP_ACP, 0, ai->agent, -1, buffer, *size, NULL, NULL);
+            else
+                *(char *)buffer = 0;
+            /* If the buffer is copied, the returned length doesn't include
+             * the NULL terminator.
+             */
+            *size -= 1;
         }
 
         return ERROR_SUCCESS;
@@ -546,10 +749,10 @@ static DWORD APPINFO_QueryOption(object_header_t *hdr, DWORD option, void *buffe
             DWORD proxyBytesRequired = 0, proxyBypassBytesRequired = 0;
             LPWSTR proxy, proxy_bypass;
 
-            if (ai->lpszProxy)
-                proxyBytesRequired = (lstrlenW(ai->lpszProxy) + 1) * sizeof(WCHAR);
-            if (ai->lpszProxyBypass)
-                proxyBypassBytesRequired = (lstrlenW(ai->lpszProxyBypass) + 1) * sizeof(WCHAR);
+            if (ai->proxy)
+                proxyBytesRequired = (lstrlenW(ai->proxy) + 1) * sizeof(WCHAR);
+            if (ai->proxyBypass)
+                proxyBypassBytesRequired = (lstrlenW(ai->proxyBypass) + 1) * sizeof(WCHAR);
             if (*size < sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired + proxyBypassBytesRequired)
             {
                 *size = sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired + proxyBypassBytesRequired;
@@ -558,16 +761,16 @@ static DWORD APPINFO_QueryOption(object_header_t *hdr, DWORD option, void *buffe
             proxy = (LPWSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOW));
             proxy_bypass = (LPWSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired);
 
-            pi->dwAccessType = ai->dwAccessType;
+            pi->dwAccessType = ai->accessType;
             pi->lpszProxy = NULL;
             pi->lpszProxyBypass = NULL;
-            if (ai->lpszProxy) {
-                lstrcpyW(proxy, ai->lpszProxy);
+            if (ai->proxy) {
+                lstrcpyW(proxy, ai->proxy);
                 pi->lpszProxy = proxy;
             }
 
-            if (ai->lpszProxyBypass) {
-                lstrcpyW(proxy_bypass, ai->lpszProxyBypass);
+            if (ai->proxyBypass) {
+                lstrcpyW(proxy_bypass, ai->proxyBypass);
                 pi->lpszProxyBypass = proxy_bypass;
             }
 
@@ -578,10 +781,10 @@ static DWORD APPINFO_QueryOption(object_header_t *hdr, DWORD option, void *buffe
             DWORD proxyBytesRequired = 0, proxyBypassBytesRequired = 0;
             LPSTR proxy, proxy_bypass;
 
-            if (ai->lpszProxy)
-                proxyBytesRequired = WideCharToMultiByte(CP_ACP, 0, ai->lpszProxy, -1, NULL, 0, NULL, NULL);
-            if (ai->lpszProxyBypass)
-                proxyBypassBytesRequired = WideCharToMultiByte(CP_ACP, 0, ai->lpszProxyBypass, -1,
+            if (ai->proxy)
+                proxyBytesRequired = WideCharToMultiByte(CP_ACP, 0, ai->proxy, -1, NULL, 0, NULL, NULL);
+            if (ai->proxyBypass)
+                proxyBypassBytesRequired = WideCharToMultiByte(CP_ACP, 0, ai->proxyBypass, -1,
                         NULL, 0, NULL, NULL);
             if (*size < sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired + proxyBypassBytesRequired)
             {
@@ -591,16 +794,16 @@ static DWORD APPINFO_QueryOption(object_header_t *hdr, DWORD option, void *buffe
             proxy = (LPSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOA));
             proxy_bypass = (LPSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired);
 
-            pi->dwAccessType = ai->dwAccessType;
+            pi->dwAccessType = ai->accessType;
             pi->lpszProxy = NULL;
             pi->lpszProxyBypass = NULL;
-            if (ai->lpszProxy) {
-                WideCharToMultiByte(CP_ACP, 0, ai->lpszProxy, -1, proxy, proxyBytesRequired, NULL, NULL);
+            if (ai->proxy) {
+                WideCharToMultiByte(CP_ACP, 0, ai->proxy, -1, proxy, proxyBytesRequired, NULL, NULL);
                 pi->lpszProxy = proxy;
             }
 
-            if (ai->lpszProxyBypass) {
-                WideCharToMultiByte(CP_ACP, 0, ai->lpszProxyBypass, -1, proxy_bypass,
+            if (ai->proxyBypass) {
+                WideCharToMultiByte(CP_ACP, 0, ai->proxyBypass, -1, proxy_bypass,
                         proxyBypassBytesRequired, NULL, NULL);
                 pi->lpszProxyBypass = proxy_bypass;
             }
@@ -610,7 +813,7 @@ static DWORD APPINFO_QueryOption(object_header_t *hdr, DWORD option, void *buffe
         }
     }
 
-    return INET_QueryOption(option, buffer, size, unicode);
+    return INET_QueryOption(hdr, option, buffer, size, unicode);
 }
 
 static const object_vtbl_t APPINFOVtbl = {
@@ -639,8 +842,7 @@ static const object_vtbl_t APPINFOVtbl = {
 HINTERNET WINAPI InternetOpenW(LPCWSTR lpszAgent, DWORD dwAccessType,
     LPCWSTR lpszProxy, LPCWSTR lpszProxyBypass, DWORD dwFlags)
 {
-    LPWININETAPPINFOW lpwai = NULL;
-    HINTERNET handle = NULL;
+    appinfo_t *lpwai = NULL;
 
     if (TRACE_ON(wininet)) {
 #define FE(x) { x, #x }
@@ -670,61 +872,28 @@ HINTERNET WINAPI InternetOpenW(LPCWSTR lpszAgent, DWORD dwAccessType,
     /* Clear any error information */
     INTERNET_SetLastError(0);
 
-    lpwai = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETAPPINFOW));
-    if (NULL == lpwai)
-    {
-        INTERNET_SetLastError(ERROR_OUTOFMEMORY);
-       goto lend;
+    lpwai = alloc_object(NULL, &APPINFOVtbl, sizeof(appinfo_t));
+    if (!lpwai) {
+        SetLastError(ERROR_OUTOFMEMORY);
+        return NULL;
     }
 
     lpwai->hdr.htype = WH_HINIT;
-    lpwai->hdr.vtbl = &APPINFOVtbl;
     lpwai->hdr.dwFlags = dwFlags;
-    lpwai->hdr.refs = 1;
-    lpwai->dwAccessType = dwAccessType;
-    lpwai->lpszProxyUsername = NULL;
-    lpwai->lpszProxyPassword = NULL;
+    lpwai->accessType = dwAccessType;
+    lpwai->proxyUsername = NULL;
+    lpwai->proxyPassword = NULL;
 
-    handle = WININET_AllocHandle( &lpwai->hdr );
-    if( !handle )
-    {
-        HeapFree( GetProcessHeap(), 0, lpwai );
-        INTERNET_SetLastError(ERROR_OUTOFMEMORY);
-       goto lend;
-    }
-
-    if (NULL != lpszAgent)
-    {
-        lpwai->lpszAgent = HeapAlloc( GetProcessHeap(),0,
-                                      (strlenW(lpszAgent)+1)*sizeof(WCHAR));
-        if (lpwai->lpszAgent)
-            lstrcpyW( lpwai->lpszAgent, lpszAgent );
-    }
+    lpwai->agent = heap_strdupW(lpszAgent);
     if(dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG)
         INTERNET_ConfigureProxy( lpwai );
-    else if (NULL != lpszProxy)
-    {
-        lpwai->lpszProxy = HeapAlloc( GetProcessHeap(), 0,
-                                      (strlenW(lpszProxy)+1)*sizeof(WCHAR));
-        if (lpwai->lpszProxy)
-            lstrcpyW( lpwai->lpszProxy, lpszProxy );
-    }
-
-    if (NULL != lpszProxyBypass)
-    {
-        lpwai->lpszProxyBypass = HeapAlloc( GetProcessHeap(), 0,
-                                     (strlenW(lpszProxyBypass)+1)*sizeof(WCHAR));
-        if (lpwai->lpszProxyBypass)
-            lstrcpyW( lpwai->lpszProxyBypass, lpszProxyBypass );
-    }
-
-lend:
-    if( lpwai )
-        WININET_Release( &lpwai->hdr );
+    else
+        lpwai->proxy = heap_strdupW(lpszProxy);
+    lpwai->proxyBypass = heap_strdupW(lpszProxyBypass);
 
     TRACE("returning %p\n", lpwai);
 
-    return handle;
+    return lpwai->hdr.hInternet;
 }
 
 
@@ -741,40 +910,21 @@ lend:
 HINTERNET WINAPI InternetOpenA(LPCSTR lpszAgent, DWORD dwAccessType,
     LPCSTR lpszProxy, LPCSTR lpszProxyBypass, DWORD dwFlags)
 {
-    HINTERNET rc = NULL;
-    INT len;
-    WCHAR *szAgent = NULL, *szProxy = NULL, *szBypass = NULL;
+    WCHAR *szAgent, *szProxy, *szBypass;
+    HINTERNET rc;
 
     TRACE("(%s, 0x%08x, %s, %s, 0x%08x)\n", debugstr_a(lpszAgent),
        dwAccessType, debugstr_a(lpszProxy), debugstr_a(lpszProxyBypass), dwFlags);
 
-    if( lpszAgent )
-    {
-        len = MultiByteToWideChar(CP_ACP, 0, lpszAgent, -1, NULL, 0);
-        szAgent = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
-        MultiByteToWideChar(CP_ACP, 0, lpszAgent, -1, szAgent, len);
-    }
-
-    if( lpszProxy )
-    {
-        len = MultiByteToWideChar(CP_ACP, 0, lpszProxy, -1, NULL, 0);
-        szProxy = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
-        MultiByteToWideChar(CP_ACP, 0, lpszProxy, -1, szProxy, len);
-    }
-
-    if( lpszProxyBypass )
-    {
-        len = MultiByteToWideChar(CP_ACP, 0, lpszProxyBypass, -1, NULL, 0);
-        szBypass = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
-        MultiByteToWideChar(CP_ACP, 0, lpszProxyBypass, -1, szBypass, len);
-    }
+    szAgent = heap_strdupAtoW(lpszAgent);
+    szProxy = heap_strdupAtoW(lpszProxy);
+    szBypass = heap_strdupAtoW(lpszProxyBypass);
 
     rc = InternetOpenW(szAgent, dwAccessType, szProxy, szBypass, dwFlags);
 
-    HeapFree(GetProcessHeap(), 0, szAgent);
-    HeapFree(GetProcessHeap(), 0, szProxy);
-    HeapFree(GetProcessHeap(), 0, szBypass);
-
+    heap_free(szAgent);
+    heap_free(szProxy);
+    heap_free(szBypass);
     return rc;
 }
 
@@ -931,7 +1081,7 @@ BOOL WINAPI InternetGetConnectedStateExA(LPDWORD lpdwStatus, LPSTR lpszConnectio
     TRACE("(%p, %p, %d, 0x%08x)\n", lpdwStatus, lpszConnectionName, dwNameLen, dwReserved);
 
     if (lpszConnectionName && dwNameLen > 0)
-        lpwszConnectionName= HeapAlloc(GetProcessHeap(), 0, dwNameLen * sizeof(WCHAR));
+        lpwszConnectionName = heap_alloc(dwNameLen * sizeof(WCHAR));
 
     rc = InternetGetConnectedStateExW(lpdwStatus,lpwszConnectionName, dwNameLen,
                                       dwReserved);
@@ -939,10 +1089,8 @@ BOOL WINAPI InternetGetConnectedStateExA(LPDWORD lpdwStatus, LPSTR lpszConnectio
     {
         WideCharToMultiByte(CP_ACP,0,lpwszConnectionName,-1,lpszConnectionName,
                             dwNameLen, NULL, NULL);
-
-        HeapFree(GetProcessHeap(),0,lpwszConnectionName);
+        heap_free(lpwszConnectionName);
     }
-
     return rc;
 }
 
@@ -962,8 +1110,9 @@ HINTERNET WINAPI InternetConnectW(HINTERNET hInternet,
     LPCWSTR lpszUserName, LPCWSTR lpszPassword,
     DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext)
 {
-    LPWININETAPPINFOW hIC;
+    appinfo_t *hIC;
     HINTERNET rc = NULL;
+    DWORD res = ERROR_SUCCESS;
 
     TRACE("(%p, %s, %i, %s, %s, %i, %i, %lx)\n", hInternet, debugstr_w(lpszServerName),
          nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword),
@@ -971,16 +1120,14 @@ HINTERNET WINAPI InternetConnectW(HINTERNET hInternet,
 
     if (!lpszServerName)
     {
-        INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
+        SetLastError(ERROR_INVALID_PARAMETER);
         return NULL;
     }
 
-    /* Clear any error information */
-    INTERNET_SetLastError(0);
-    hIC = (LPWININETAPPINFOW) WININET_GetObject( hInternet );
+    hIC = (appinfo_t*)get_handle_object( hInternet );
     if ( (hIC == NULL) || (hIC->hdr.htype != WH_HINIT) )
     {
-        INTERNET_SetLastError(ERROR_INVALID_HANDLE);
+        res = ERROR_INVALID_HANDLE;
         goto lend;
     }
 
@@ -989,11 +1136,13 @@ HINTERNET WINAPI InternetConnectW(HINTERNET hInternet,
         case INTERNET_SERVICE_FTP:
             rc = FTP_Connect(hIC, lpszServerName, nServerPort,
             lpszUserName, lpszPassword, dwFlags, dwContext, 0);
+            if(!rc)
+                res = INTERNET_GetLastError();
             break;
 
         case INTERNET_SERVICE_HTTP:
-           rc = HTTP_Connect(hIC, lpszServerName, nServerPort,
-            lpszUserName, lpszPassword, dwFlags, dwContext, 0);
+           res = HTTP_Connect(hIC, lpszServerName, nServerPort,
+                    lpszUserName, lpszPassword, dwFlags, dwContext, 0, &rc);
             break;
 
         case INTERNET_SERVICE_GOPHER:
@@ -1005,6 +1154,7 @@ lend:
         WININET_Release( &hIC->hdr );
 
     TRACE("returning %p\n", rc);
+    SetLastError(res);
     return rc;
 }
 
@@ -1025,37 +1175,20 @@ HINTERNET WINAPI InternetConnectA(HINTERNET hInternet,
     DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext)
 {
     HINTERNET rc = NULL;
-    INT len = 0;
-    LPWSTR szServerName = NULL;
-    LPWSTR szUserName = NULL;
-    LPWSTR szPassword = NULL;
-
-    if (lpszServerName)
-    {
-       len = MultiByteToWideChar(CP_ACP, 0, lpszServerName, -1, NULL, 0);
-        szServerName = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
-        MultiByteToWideChar(CP_ACP, 0, lpszServerName, -1, szServerName, len);
-    }
-    if (lpszUserName)
-    {
-       len = MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, NULL, 0);
-        szUserName = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
-        MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, szUserName, len);
-    }
-    if (lpszPassword)
-    {
-       len = MultiByteToWideChar(CP_ACP, 0, lpszPassword, -1, NULL, 0);
-        szPassword = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
-        MultiByteToWideChar(CP_ACP, 0, lpszPassword, -1, szPassword, len);
-    }
+    LPWSTR szServerName;
+    LPWSTR szUserName;
+    LPWSTR szPassword;
 
+    szServerName = heap_strdupAtoW(lpszServerName);
+    szUserName = heap_strdupAtoW(lpszUserName);
+    szPassword = heap_strdupAtoW(lpszPassword);
 
     rc = InternetConnectW(hInternet, szServerName, nServerPort,
         szUserName, szPassword, dwService, dwFlags, dwContext);
 
-    HeapFree(GetProcessHeap(), 0, szServerName);
-    HeapFree(GetProcessHeap(), 0, szUserName);
-    HeapFree(GetProcessHeap(), 0, szPassword);
+    heap_free(szServerName);
+    heap_free(szUserName);
+    heap_free(szPassword);
     return rc;
 }
 
@@ -1098,7 +1231,7 @@ BOOL WINAPI InternetFindNextFileW(HINTERNET hFind, LPVOID lpvFindData)
 
     TRACE("\n");
 
-    hdr = WININET_GetObject(hFind);
+    hdr = get_handle_object(hFind);
     if(!hdr) {
         WARN("Invalid handle\n");
         SetLastError(ERROR_INVALID_HANDLE);
@@ -1131,19 +1264,18 @@ BOOL WINAPI InternetFindNextFileW(HINTERNET hFind, LPVOID lpvFindData)
  */
 BOOL WINAPI InternetCloseHandle(HINTERNET hInternet)
 {
-    object_header_t *lpwh;
+    object_header_t *obj;
     
-    TRACE("%p\n",hInternet);
+    TRACE("%p\n", hInternet);
 
-    lpwh = WININET_GetObject( hInternet );
-    if (NULL == lpwh)
-    {
-        INTERNET_SetLastError(ERROR_INVALID_HANDLE);
+    obj = get_handle_object( hInternet );
+    if (!obj) {
+        SetLastError(ERROR_INVALID_HANDLE);
         return FALSE;
     }
 
-    WININET_Release( lpwh );
-    WININET_FreeHandle( hInternet );
+    invalidate_handle(obj);
+    WININET_Release(obj);
 
     return TRUE;
 }
@@ -1165,11 +1297,14 @@ static void ConvertUrlComponentValue(LPSTR* lppszComponent, LPDWORD dwComponentL
         DWORD nASCIILength=WideCharToMultiByte(CP_ACP,0,lpwszComponent,dwwComponentLen,NULL,0,NULL,NULL);
         if (*lppszComponent == NULL)
         {
-            int nASCIIOffset=WideCharToMultiByte(CP_ACP,0,lpwszStart,lpwszComponent-lpwszStart,NULL,0,NULL,NULL);
             if (lpwszComponent)
-                *lppszComponent = (LPSTR)lpszStart+nASCIIOffset;
+            {
+                int offset = WideCharToMultiByte(CP_ACP, 0, lpwszStart, lpwszComponent-lpwszStart, NULL, 0, NULL, NULL);
+                *lppszComponent = (LPSTR)lpszStart + offset;
+            }
             else
                 *lppszComponent = NULL;
+
             *dwComponentLen = nASCIILength;
         }
         else
@@ -1216,8 +1351,9 @@ BOOL WINAPI InternetCrackUrlA(LPCSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
        InternetCrackUrlW should not include it                  */
   if (dwUrlLength == -1) nLength--;
 
-  lpwszUrl=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR)*nLength);
-  MultiByteToWideChar(CP_ACP,0,lpszUrl,dwUrlLength,lpwszUrl,nLength);
+  lpwszUrl = heap_alloc((nLength + 1) * sizeof(WCHAR));
+  MultiByteToWideChar(CP_ACP,0,lpszUrl,dwUrlLength,lpwszUrl,nLength + 1);
+  lpwszUrl[nLength] = '\0';
 
   memset(&UCW,0,sizeof(UCW));
   UCW.dwStructSize = sizeof(URL_COMPONENTSW);
@@ -1226,7 +1362,7 @@ BOOL WINAPI InternetCrackUrlA(LPCSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
     UCW.dwHostNameLength = lpUrlComponents->dwHostNameLength;
     if (lpUrlComponents->lpszHostName)
     {
-      hostname = HeapAlloc(GetProcessHeap(), 0, UCW.dwHostNameLength * sizeof(WCHAR));
+      hostname = heap_alloc(UCW.dwHostNameLength * sizeof(WCHAR));
       UCW.lpszHostName = hostname;
     }
   }
@@ -1235,7 +1371,7 @@ BOOL WINAPI InternetCrackUrlA(LPCSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
     UCW.dwUserNameLength = lpUrlComponents->dwUserNameLength;
     if (lpUrlComponents->lpszUserName)
     {
-      username = HeapAlloc(GetProcessHeap(), 0, UCW.dwUserNameLength * sizeof(WCHAR));
+      username = heap_alloc(UCW.dwUserNameLength * sizeof(WCHAR));
       UCW.lpszUserName = username;
     }
   }
@@ -1244,7 +1380,7 @@ BOOL WINAPI InternetCrackUrlA(LPCSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
     UCW.dwPasswordLength = lpUrlComponents->dwPasswordLength;
     if (lpUrlComponents->lpszPassword)
     {
-      password = HeapAlloc(GetProcessHeap(), 0, UCW.dwPasswordLength * sizeof(WCHAR));
+      password = heap_alloc(UCW.dwPasswordLength * sizeof(WCHAR));
       UCW.lpszPassword = password;
     }
   }
@@ -1253,7 +1389,7 @@ BOOL WINAPI InternetCrackUrlA(LPCSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
     UCW.dwUrlPathLength = lpUrlComponents->dwUrlPathLength;
     if (lpUrlComponents->lpszUrlPath)
     {
-      path = HeapAlloc(GetProcessHeap(), 0, UCW.dwUrlPathLength * sizeof(WCHAR));
+      path = heap_alloc(UCW.dwUrlPathLength * sizeof(WCHAR));
       UCW.lpszUrlPath = path;
     }
   }
@@ -1262,7 +1398,7 @@ BOOL WINAPI InternetCrackUrlA(LPCSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
     UCW.dwSchemeLength = lpUrlComponents->dwSchemeLength;
     if (lpUrlComponents->lpszScheme)
     {
-      scheme = HeapAlloc(GetProcessHeap(), 0, UCW.dwSchemeLength * sizeof(WCHAR));
+      scheme = heap_alloc(UCW.dwSchemeLength * sizeof(WCHAR));
       UCW.lpszScheme = scheme;
     }
   }
@@ -1271,7 +1407,7 @@ BOOL WINAPI InternetCrackUrlA(LPCSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
     UCW.dwExtraInfoLength = lpUrlComponents->dwExtraInfoLength;
     if (lpUrlComponents->lpszExtraInfo)
     {
-      extra = HeapAlloc(GetProcessHeap(), 0, UCW.dwExtraInfoLength * sizeof(WCHAR));
+      extra = heap_alloc(UCW.dwExtraInfoLength * sizeof(WCHAR));
       UCW.lpszExtraInfo = extra;
     }
   }
@@ -1293,19 +1429,19 @@ BOOL WINAPI InternetCrackUrlA(LPCSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
     lpUrlComponents->nScheme = UCW.nScheme;
     lpUrlComponents->nPort = UCW.nPort;
 
-    TRACE("%s: scheme(%s) host(%s) path(%s) extra(%s)\n", lpszUrl,
+    TRACE("%s: scheme(%s) host(%s) path(%s) extra(%s)\n", debugstr_a(lpszUrl),
           debugstr_an(lpUrlComponents->lpszScheme, lpUrlComponents->dwSchemeLength),
           debugstr_an(lpUrlComponents->lpszHostName, lpUrlComponents->dwHostNameLength),
           debugstr_an(lpUrlComponents->lpszUrlPath, lpUrlComponents->dwUrlPathLength),
           debugstr_an(lpUrlComponents->lpszExtraInfo, lpUrlComponents->dwExtraInfoLength));
   }
-  HeapFree(GetProcessHeap(), 0, lpwszUrl);
-  HeapFree(GetProcessHeap(), 0, hostname);
-  HeapFree(GetProcessHeap(), 0, username);
-  HeapFree(GetProcessHeap(), 0, password);
-  HeapFree(GetProcessHeap(), 0, path);
-  HeapFree(GetProcessHeap(), 0, scheme);
-  HeapFree(GetProcessHeap(), 0, extra);
+  heap_free(lpwszUrl);
+  heap_free(hostname);
+  heap_free(username);
+  heap_free(password);
+  heap_free(path);
+  heap_free(scheme);
+  heap_free(extra);
   return ret;
 }
 
@@ -1430,16 +1566,16 @@ BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWOR
         WCHAR *url_tmp;
         DWORD len = dwUrlLength + 1;
 
-        if (!(url_tmp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
+        if (!(url_tmp = heap_alloc(len * sizeof(WCHAR))))
         {
             INTERNET_SetLastError(ERROR_OUTOFMEMORY);
             return FALSE;
         }
         memcpy(url_tmp, lpszUrl_orig, dwUrlLength * sizeof(WCHAR));
         url_tmp[dwUrlLength] = 0;
-        if (!(lpszUrl_decode = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
+        if (!(lpszUrl_decode = heap_alloc(len * sizeof(WCHAR))))
         {
-            HeapFree(GetProcessHeap(), 0, url_tmp);
+            heap_free(url_tmp);
             INTERNET_SetLastError(ERROR_OUTOFMEMORY);
             return FALSE;
         }
@@ -1448,14 +1584,14 @@ BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWOR
             dwUrlLength = len;
             lpszUrl = lpszUrl_decode;
         }
-        HeapFree(GetProcessHeap(), 0, url_tmp);
+        heap_free(url_tmp);
     }
     lpszap = lpszUrl;
     
     /* Determine if the URI is absolute. */
     while (lpszap - lpszUrl < dwUrlLength)
     {
-        if (isalnumW(*lpszap))
+        if (isalnumW(*lpszap) || *lpszap == '+' || *lpszap == '.' || *lpszap == '-')
         {
             lpszap++;
             continue;
@@ -1477,8 +1613,11 @@ BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWOR
     lpUC->nPort = INTERNET_INVALID_PORT_NUMBER;
 
     /* Parse <params> */
-    if (!(lpszParam = memchrW(lpszap, ';', dwUrlLength - (lpszap - lpszUrl))))
+    lpszParam = memchrW(lpszap, ';', dwUrlLength - (lpszap - lpszUrl));
+    if(!lpszParam)
         lpszParam = memchrW(lpszap, '?', dwUrlLength - (lpszap - lpszUrl));
+    if(!lpszParam)
+        lpszParam = memchrW(lpszap, '#', dwUrlLength - (lpszap - lpszUrl));
 
     SetUrlComponentValueW(&lpUC->lpszExtraInfo, &lpUC->dwExtraInfoLength,
                           lpszParam, lpszParam ? dwUrlLength-(lpszParam-lpszUrl) : 0);
@@ -1576,7 +1715,7 @@ BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWOR
                     }
 
                     /* If the scheme is "file" and the host is just one letter, it's not a host */
-                    if(lpUC->nScheme==INTERNET_SCHEME_FILE && (lpszPort-lpszHost)==1)
+                    if(lpUC->nScheme==INTERNET_SCHEME_FILE && lpszPort <= lpszHost+1)
                     {
                         lpszcp=lpszHost;
                         SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
@@ -1629,9 +1768,9 @@ BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWOR
      * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
      *                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      */
-    if (lpszcp != 0 && lpszcp - lpszUrl < dwUrlLength && (!lpszParam || lpszcp < lpszParam))
+    if (lpszcp != 0 && lpszcp - lpszUrl < dwUrlLength && (!lpszParam || lpszcp <= lpszParam))
     {
-        INT len;
+        DWORD len;
 
         /* Only truncate the parameter list if it's already been saved
          * in lpUC->lpszExtraInfo.
@@ -1649,8 +1788,46 @@ BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWOR
             else
                 len = dwUrlLength-(lpszcp-lpszUrl);
         }
-        SetUrlComponentValueW(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength,
-                                   lpszcp, len);
+        if (lpUC->dwUrlPathLength && lpUC->lpszUrlPath &&
+                lpUC->nScheme == INTERNET_SCHEME_FILE)
+        {
+            WCHAR tmppath[MAX_PATH];
+            if (*lpszcp == '/')
+            {
+                len = MAX_PATH;
+                PathCreateFromUrlW(lpszUrl_orig, tmppath, &len, 0);
+            }
+            else
+            {
+                WCHAR *iter;
+                memcpy(tmppath, lpszcp, len * sizeof(WCHAR));
+                tmppath[len] = '\0';
+
+                iter = tmppath;
+                while (*iter) {
+                    if (*iter == '/')
+                        *iter = '\\';
+                    ++iter;
+                }
+            }
+            /* if ends in \. or \.. append a backslash */
+            if (tmppath[len - 1] == '.' &&
+                    (tmppath[len - 2] == '\\' ||
+                     (tmppath[len - 2] == '.' && tmppath[len - 3] == '\\')))
+            {
+                if (len < MAX_PATH - 1)
+                {
+                    tmppath[len] = '\\';
+                    tmppath[len+1] = '\0';
+                    ++len;
+                }
+            }
+            SetUrlComponentValueW(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength,
+                                       tmppath, len);
+        }
+        else
+            SetUrlComponentValueW(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength,
+                                       lpszcp, len);
     }
     else
     {
@@ -1665,7 +1842,7 @@ BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWOR
              debugstr_wn(lpUC->lpszUrlPath,lpUC->dwUrlPathLength),
              debugstr_wn(lpUC->lpszExtraInfo,lpUC->dwExtraInfoLength));
 
-    HeapFree(GetProcessHeap(), 0, lpszUrl_decode );
+    heap_free( lpszUrl_decode );
     return TRUE;
 }
 
@@ -1703,7 +1880,7 @@ BOOL WINAPI InternetCanonicalizeUrlA(LPCSTR lpszUrl, LPSTR lpszBuffer,
     DWORD dwURLFlags = URL_WININET_COMPATIBILITY | URL_ESCAPE_UNSAFE;
 
     TRACE("(%s, %p, %p, 0x%08x) bufferlength: %d\n", debugstr_a(lpszUrl), lpszBuffer,
-        lpdwBufferLength, lpdwBufferLength ? *lpdwBufferLength : -1, dwFlags);
+        lpdwBufferLength, dwFlags, lpdwBufferLength ? *lpdwBufferLength : -1);
 
     if(dwFlags & ICU_DECODE)
     {
@@ -1827,7 +2004,7 @@ INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackA(
 
     TRACE("%p\n", hInternet);
 
-    if (!(lpwh = WININET_GetObject(hInternet)))
+    if (!(lpwh = get_handle_object(hInternet)))
         return INTERNET_INVALID_STATUS_CALLBACK;
 
     retVal = set_status_callback(lpwh, lpfnIntCB, FALSE);
@@ -1855,7 +2032,7 @@ INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackW(
 
     TRACE("%p\n", hInternet);
 
-    if (!(lpwh = WININET_GetObject(hInternet)))
+    if (!(lpwh = get_handle_object(hInternet)))
         return INTERNET_INVALID_STATUS_CALLBACK;
 
     retVal = set_status_callback(lpwh, lpfnIntCB, TRUE);
@@ -1888,11 +2065,11 @@ BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer,
        DWORD dwNumOfBytesToWrite, LPDWORD lpdwNumOfBytesWritten)
 {
     object_header_t *lpwh;
-    BOOL retval = FALSE;
+    BOOL res;
 
     TRACE("(%p %p %d %p)\n", hFile, lpBuffer, dwNumOfBytesToWrite, lpdwNumOfBytesWritten);
 
-    lpwh = WININET_GetObject( hFile );
+    lpwh = get_handle_object( hFile );
     if (!lpwh) {
         WARN("Invalid handle\n");
         SetLastError(ERROR_INVALID_HANDLE);
@@ -1900,16 +2077,17 @@ BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer,
     }
 
     if(lpwh->vtbl->WriteFile) {
-        retval = lpwh->vtbl->WriteFile(lpwh, lpBuffer, dwNumOfBytesToWrite, lpdwNumOfBytesWritten);
+        res = lpwh->vtbl->WriteFile(lpwh, lpBuffer, dwNumOfBytesToWrite, lpdwNumOfBytesWritten);
     }else {
         WARN("No Writefile method.\n");
-        SetLastError(ERROR_INVALID_HANDLE);
-        retval = FALSE;
+        res = ERROR_INVALID_HANDLE;
     }
 
     WININET_Release( lpwh );
 
-    return retval;
+    if(res != ERROR_SUCCESS)
+        SetLastError(res);
+    return res == ERROR_SUCCESS;
 }
 
 
@@ -1931,7 +2109,7 @@ BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer,
 
     TRACE("%p %p %d %p\n", hFile, lpBuffer, dwNumOfBytesToRead, pdwNumOfBytesRead);
 
-    hdr = WININET_GetObject(hFile);
+    hdr = get_handle_object(hFile);
     if (!hdr) {
         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
         return FALSE;
@@ -1985,7 +2163,7 @@ BOOL WINAPI InternetReadFileExA(HINTERNET hFile, LPINTERNET_BUFFERSA lpBuffersOu
 
     TRACE("(%p %p 0x%x 0x%lx)\n", hFile, lpBuffersOut, dwFlags, dwContext);
 
-    hdr = WININET_GetObject(hFile);
+    hdr = get_handle_object(hFile);
     if (!hdr) {
         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
         return FALSE;
@@ -2017,7 +2195,7 @@ BOOL WINAPI InternetReadFileExW(HINTERNET hFile, LPINTERNET_BUFFERSW lpBuffer,
 
     TRACE("(%p %p 0x%x 0x%lx)\n", hFile, lpBuffer, dwFlags, dwContext);
 
-    hdr = WININET_GetObject(hFile);
+    hdr = get_handle_object(hFile);
     if (!hdr) {
         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
         return FALSE;
@@ -2036,7 +2214,7 @@ BOOL WINAPI InternetReadFileExW(HINTERNET hFile, LPINTERNET_BUFFERSW lpBuffer,
     return res == ERROR_SUCCESS;
 }
 
-DWORD INET_QueryOption(DWORD option, void *buffer, DWORD *size, BOOL unicode)
+DWORD INET_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
 {
     static BOOL warn = TRUE;
 
@@ -2066,7 +2244,6 @@ DWORD INET_QueryOption(DWORD option, void *buffer, DWORD *size, BOOL unicode)
         return ERROR_SUCCESS;
 
     case INTERNET_OPTION_CONNECTED_STATE:
-
         if (warn) {
             FIXME("INTERNET_OPTION_CONNECTED_STATE: semi-stub\n");
             warn = FALSE;
@@ -2080,13 +2257,16 @@ DWORD INET_QueryOption(DWORD option, void *buffer, DWORD *size, BOOL unicode)
         return ERROR_SUCCESS;
 
     case INTERNET_OPTION_PROXY: {
-        WININETAPPINFOW ai;
+        appinfo_t ai;
+        BOOL ret;
 
         TRACE("Getting global proxy info\n");
-        memset(&ai, 0, sizeof(WININETAPPINFOW));
+        memset(&ai, 0, sizeof(appinfo_t));
         INTERNET_ConfigureProxy(&ai);
 
-        return APPINFO_QueryOption(&ai.hdr, INTERNET_OPTION_PROXY, buffer, size, unicode); /* FIXME */
+        ret = APPINFO_QueryOption(&ai.hdr, INTERNET_OPTION_PROXY, buffer, size, unicode); /* FIXME */
+        APPINFO_Destroy(&ai.hdr);
+        return ret;
     }
 
     case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
@@ -2106,7 +2286,7 @@ DWORD INET_QueryOption(DWORD option, void *buffer, DWORD *size, BOOL unicode)
             if (*size < sizeof(ULONG))
                 return ERROR_INSUFFICIENT_BUFFER;
 
-            *(ULONG*)size = 4;
+            *(ULONG*)buffer = 4;
             *size = sizeof(ULONG);
 
             return ERROR_SUCCESS;
@@ -2131,42 +2311,91 @@ DWORD INET_QueryOption(DWORD option, void *buffer, DWORD *size, BOOL unicode)
 
     case INTERNET_OPTION_PER_CONNECTION_OPTION: {
         INTERNET_PER_CONN_OPTION_LISTW *con = buffer;
+        INTERNET_PER_CONN_OPTION_LISTA *conA = buffer;
         DWORD res = ERROR_SUCCESS, i;
+        proxyinfo_t pi;
+        LONG ret;
+
+        TRACE("Getting global proxy info\n");
+        if((ret = INTERNET_LoadProxySettings(&pi)))
+            return ret;
 
         FIXME("INTERNET_OPTION_PER_CONNECTION_OPTION stub\n");
 
-        if (*size < sizeof(INTERNET_PER_CONN_OPTION_LISTW))
+        if (*size < sizeof(INTERNET_PER_CONN_OPTION_LISTW)) {
+            FreeProxyInfo(&pi);
             return ERROR_INSUFFICIENT_BUFFER;
+        }
 
         for (i = 0; i < con->dwOptionCount; i++) {
-            INTERNET_PER_CONN_OPTIONW *option = con->pOptions + i;
+            INTERNET_PER_CONN_OPTIONW *optionW = con->pOptions + i;
+            INTERNET_PER_CONN_OPTIONA *optionA = conA->pOptions + i;
 
-            switch (option->dwOption) {
+            switch (optionW->dwOption) {
             case INTERNET_PER_CONN_FLAGS:
-                option->Value.dwValue = PROXY_TYPE_DIRECT;
+                if(pi.dwProxyEnabled)
+                    optionW->Value.dwValue = PROXY_TYPE_PROXY;
+                else
+                    optionW->Value.dwValue = PROXY_TYPE_DIRECT;
                 break;
 
             case INTERNET_PER_CONN_PROXY_SERVER:
+                if (unicode)
+                    optionW->Value.pszValue = heap_strdupW(pi.lpszProxyServer);
+                else
+                    optionA->Value.pszValue = heap_strdupWtoA(pi.lpszProxyServer);
+                break;
+
             case INTERNET_PER_CONN_PROXY_BYPASS:
+                if (unicode)
+                    optionW->Value.pszValue = heap_strdupW(pi.lpszProxyBypass);
+                else
+                    optionA->Value.pszValue = heap_strdupWtoA(pi.lpszProxyBypass);
+                break;
+
             case INTERNET_PER_CONN_AUTOCONFIG_URL:
             case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
             case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
             case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
             case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
             case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
-                FIXME("Unhandled dwOption %d\n", option->dwOption);
-                memset(&option->Value, 0, sizeof(option->Value));
+                FIXME("Unhandled dwOption %d\n", optionW->dwOption);
+                memset(&optionW->Value, 0, sizeof(optionW->Value));
                 break;
 
             default:
-                FIXME("Unknown dwOption %d\n", option->dwOption);
+                FIXME("Unknown dwOption %d\n", optionW->dwOption);
                 res = ERROR_INVALID_PARAMETER;
                 break;
             }
         }
+        FreeProxyInfo(&pi);
 
         return res;
     }
+    case INTERNET_OPTION_USER_AGENT:
+        return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
+    case INTERNET_OPTION_POLICY:
+        return ERROR_INVALID_PARAMETER;
+    case INTERNET_OPTION_CONTEXT_VALUE:
+    {
+        if (!hdr)
+            return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
+        if (!size)
+            return ERROR_INVALID_PARAMETER;
+
+        if (*size < sizeof(DWORD_PTR))
+        {
+            *size = sizeof(DWORD_PTR);
+            return ERROR_INSUFFICIENT_BUFFER;
+        }
+        if (!buffer)
+            return ERROR_INVALID_PARAMETER;
+
+        *(DWORD_PTR *)buffer = hdr->dwContext;
+        *size = sizeof(DWORD_PTR);
+        return ERROR_SUCCESS;
+    }
     }
 
     FIXME("Stub for %d\n", option);
@@ -2192,13 +2421,13 @@ BOOL WINAPI InternetQueryOptionW(HINTERNET hInternet, DWORD dwOption,
     TRACE("%p %d %p %p\n", hInternet, dwOption, lpBuffer, lpdwBufferLength);
 
     if(hInternet) {
-        hdr = WININET_GetObject(hInternet);
+        hdr = get_handle_object(hInternet);
         if (hdr) {
             res = hdr->vtbl->QueryOption(hdr, dwOption, lpBuffer, lpdwBufferLength, TRUE);
             WININET_Release(hdr);
         }
     }else {
-        res = INET_QueryOption(dwOption, lpBuffer, lpdwBufferLength, TRUE);
+        res = INET_QueryOption(NULL, dwOption, lpBuffer, lpdwBufferLength, TRUE);
     }
 
     if(res != ERROR_SUCCESS)
@@ -2225,13 +2454,13 @@ BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption,
     TRACE("%p %d %p %p\n", hInternet, dwOption, lpBuffer, lpdwBufferLength);
 
     if(hInternet) {
-        hdr = WININET_GetObject(hInternet);
+        hdr = get_handle_object(hInternet);
         if (hdr) {
             res = hdr->vtbl->QueryOption(hdr, dwOption, lpBuffer, lpdwBufferLength, FALSE);
             WININET_Release(hdr);
         }
     }else {
-        res = INET_QueryOption(dwOption, lpBuffer, lpdwBufferLength, FALSE);
+        res = INET_QueryOption(NULL, dwOption, lpBuffer, lpdwBufferLength, FALSE);
     }
 
     if(res != ERROR_SUCCESS)
@@ -2258,7 +2487,7 @@ BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption,
 
     TRACE("(%p %d %p %d)\n", hInternet, dwOption, lpBuffer, dwBufferLength);
 
-    lpwhh = (object_header_t*) WININET_GetObject( hInternet );
+    lpwhh = (object_header_t*) get_handle_object( hInternet );
     if(lpwhh && lpwhh->vtbl->SetOption) {
         DWORD res;
 
@@ -2279,11 +2508,11 @@ BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption,
       {
         if (!lpwhh)
         {
-            INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
+            SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
             return FALSE;
         }
         WININET_Release(lpwhh);
-        INTERNET_SetLastError(ERROR_INTERNET_OPTION_NOT_SETTABLE);
+        SetLastError(ERROR_INTERNET_OPTION_NOT_SETTABLE);
         return FALSE;
       }
     case INTERNET_OPTION_HTTP_VERSION:
@@ -2294,8 +2523,19 @@ BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption,
       break;
     case INTERNET_OPTION_ERROR_MASK:
       {
-        ULONG flags = *(ULONG *)lpBuffer;
-        FIXME("Option INTERNET_OPTION_ERROR_MASK(%d): STUB\n", flags);
+        if(!lpwhh) {
+            SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
+            return FALSE;
+        } else if(*(ULONG*)lpBuffer & (~(INTERNET_ERROR_MASK_INSERT_CDROM|
+                        INTERNET_ERROR_MASK_COMBINED_SEC_CERT|
+                        INTERNET_ERROR_MASK_LOGIN_FAILURE_DISPLAY_ENTITY_BODY))) {
+            SetLastError(ERROR_INVALID_PARAMETER);
+            ret = FALSE;
+        } else if(dwBufferLength != sizeof(ULONG)) {
+            SetLastError(ERROR_INTERNET_BAD_OPTION_LENGTH);
+            ret = FALSE;
+        } else
+            lpwhh->ErrorMask = *(ULONG*)lpBuffer;
       }
       break;
     case INTERNET_OPTION_CODEPAGE:
@@ -2348,9 +2588,10 @@ BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption,
        break;
     case INTERNET_OPTION_SEND_TIMEOUT:
     case INTERNET_OPTION_RECEIVE_TIMEOUT:
+    case INTERNET_OPTION_DATA_SEND_TIMEOUT:
     {
         ULONG timeout = *(ULONG *)lpBuffer;
-        FIXME("INTERNET_OPTION_SEND/RECEIVE_TIMEOUT %d\n", timeout);
+        FIXME("INTERNET_OPTION_SEND/RECEIVE_TIMEOUT/DATA_SEND_TIMEOUT %d\n", timeout);
         break;
     }
     case INTERNET_OPTION_CONNECT_RETRIES:
@@ -2360,8 +2601,21 @@ BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption,
         break;
     }
     case INTERNET_OPTION_CONTEXT_VALUE:
-        FIXME("Option INTERNET_OPTION_CONTEXT_VALUE; STUB\n");
-        break;
+    {
+        if (!lpwhh)
+        {
+            SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
+            return FALSE;
+        }
+        if (!lpBuffer || dwBufferLength != sizeof(DWORD_PTR))
+        {
+            SetLastError(ERROR_INVALID_PARAMETER);
+            ret = FALSE;
+        }
+        else
+            lpwhh->dwContext = *(DWORD_PTR *)lpBuffer;
+        break;
+    }
     case INTERNET_OPTION_SECURITY_FLAGS:
         FIXME("Option INTERNET_OPTION_SECURITY_FLAGS; STUB\n");
         break;
@@ -2370,37 +2624,94 @@ BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption,
         break;
     case INTERNET_OPTION_HTTP_DECODING:
         FIXME("INTERNET_OPTION_HTTP_DECODING; STUB\n");
-        INTERNET_SetLastError(ERROR_INTERNET_INVALID_OPTION);
+        SetLastError(ERROR_INTERNET_INVALID_OPTION);
         ret = FALSE;
         break;
     case INTERNET_OPTION_COOKIES_3RD_PARTY:
         FIXME("INTERNET_OPTION_COOKIES_3RD_PARTY; STUB\n");
-        INTERNET_SetLastError(ERROR_INTERNET_INVALID_OPTION);
+        SetLastError(ERROR_INTERNET_INVALID_OPTION);
         ret = FALSE;
         break;
     case INTERNET_OPTION_SEND_UTF8_SERVERNAME_TO_PROXY:
         FIXME("INTERNET_OPTION_SEND_UTF8_SERVERNAME_TO_PROXY; STUB\n");
-        INTERNET_SetLastError(ERROR_INTERNET_INVALID_OPTION);
+        SetLastError(ERROR_INTERNET_INVALID_OPTION);
         ret = FALSE;
         break;
     case INTERNET_OPTION_CODEPAGE_PATH:
         FIXME("INTERNET_OPTION_CODEPAGE_PATH; STUB\n");
-        INTERNET_SetLastError(ERROR_INTERNET_INVALID_OPTION);
+        SetLastError(ERROR_INTERNET_INVALID_OPTION);
         ret = FALSE;
         break;
     case INTERNET_OPTION_CODEPAGE_EXTRA:
         FIXME("INTERNET_OPTION_CODEPAGE_EXTRA; STUB\n");
-        INTERNET_SetLastError(ERROR_INTERNET_INVALID_OPTION);
+        SetLastError(ERROR_INTERNET_INVALID_OPTION);
         ret = FALSE;
         break;
     case INTERNET_OPTION_IDN:
         FIXME("INTERNET_OPTION_IDN; STUB\n");
-        INTERNET_SetLastError(ERROR_INTERNET_INVALID_OPTION);
+        SetLastError(ERROR_INTERNET_INVALID_OPTION);
         ret = FALSE;
         break;
+    case INTERNET_OPTION_POLICY:
+        SetLastError(ERROR_INVALID_PARAMETER);
+        ret = FALSE;
+        break;
+    case INTERNET_OPTION_PER_CONNECTION_OPTION: {
+        INTERNET_PER_CONN_OPTION_LISTW *con = lpBuffer;
+        LONG res;
+        int i;
+        proxyinfo_t pi;
+
+        INTERNET_LoadProxySettings(&pi);
+
+        for (i = 0; i < con->dwOptionCount; i++) {
+            INTERNET_PER_CONN_OPTIONW *option = con->pOptions + i;
+
+            switch (option->dwOption) {
+            case INTERNET_PER_CONN_PROXY_SERVER:
+                heap_free(pi.lpszProxyServer);
+                pi.lpszProxyServer = heap_strdupW(option->Value.pszValue);
+                break;
+
+            case INTERNET_PER_CONN_FLAGS:
+                if(option->Value.dwValue & PROXY_TYPE_PROXY)
+                    pi.dwProxyEnabled = 1;
+                else
+                {
+                    if(option->Value.dwValue != PROXY_TYPE_DIRECT)
+                        FIXME("Unhandled flags: 0x%x\n", option->Value.dwValue);
+                    pi.dwProxyEnabled = 0;
+                }
+                break;
+
+            case INTERNET_PER_CONN_AUTOCONFIG_URL:
+            case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
+            case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
+            case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
+            case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
+            case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
+            case INTERNET_PER_CONN_PROXY_BYPASS:
+                FIXME("Unhandled dwOption %d\n", option->dwOption);
+                break;
+
+            default:
+                FIXME("Unknown dwOption %d\n", option->dwOption);
+                SetLastError(ERROR_INVALID_PARAMETER);
+                break;
+            }
+        }
+
+        if ((res = INTERNET_SaveProxySettings(&pi)))
+            SetLastError(res);
+
+        FreeProxyInfo(&pi);
+
+        ret = (res == ERROR_SUCCESS);
+        break;
+        }
     default:
         FIXME("Option %d STUB\n",dwOption);
-        INTERNET_SetLastError(ERROR_INTERNET_INVALID_OPTION);
+        SetLastError(ERROR_INTERNET_INVALID_OPTION);
         ret = FALSE;
         break;
     }
@@ -2435,7 +2746,7 @@ BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption,
         {
         object_header_t *lpwh;
 
-        if (!(lpwh = WININET_GetObject(hInternet)))
+        if (!(lpwh = get_handle_object(hInternet)))
         {
             INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
             return FALSE;
@@ -2454,7 +2765,7 @@ BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption,
         proxlen = MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, NULL, 0);
         prbylen= MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, NULL, 0);
         wlen = sizeof(*piw) + proxlen + prbylen;
-        wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
+        wbuffer = heap_alloc(wlen*sizeof(WCHAR) );
         piw = (LPINTERNET_PROXY_INFOW) wbuffer;
         piw->dwAccessType = pi->dwAccessType;
         prox = (LPWSTR) &piw[1];
@@ -2470,10 +2781,68 @@ BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption,
     case INTERNET_OPTION_PASSWORD:
         wlen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength,
                                    NULL, 0 );
-        wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
+        wbuffer = heap_alloc(wlen*sizeof(WCHAR) );
         MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength,
                                    wbuffer, wlen );
         break;
+    case INTERNET_OPTION_PER_CONNECTION_OPTION: {
+        int i;
+        INTERNET_PER_CONN_OPTION_LISTW *listW;
+        INTERNET_PER_CONN_OPTION_LISTA *listA = lpBuffer;
+        wlen = sizeof(INTERNET_PER_CONN_OPTION_LISTW);
+        wbuffer = heap_alloc(wlen);
+        listW = wbuffer;
+
+        listW->dwSize = sizeof(INTERNET_PER_CONN_OPTION_LISTW);
+        if (listA->pszConnection)
+        {
+            wlen = MultiByteToWideChar( CP_ACP, 0, listA->pszConnection, -1, NULL, 0 );
+            listW->pszConnection = heap_alloc(wlen*sizeof(WCHAR));
+            MultiByteToWideChar( CP_ACP, 0, listA->pszConnection, -1, listW->pszConnection, wlen );
+        }
+        else
+            listW->pszConnection = NULL;
+        listW->dwOptionCount = listA->dwOptionCount;
+        listW->dwOptionError = listA->dwOptionError;
+        listW->pOptions = heap_alloc(sizeof(INTERNET_PER_CONN_OPTIONW) * listA->dwOptionCount);
+
+        for (i = 0; i < listA->dwOptionCount; ++i) {
+            INTERNET_PER_CONN_OPTIONA *optA = listA->pOptions + i;
+            INTERNET_PER_CONN_OPTIONW *optW = listW->pOptions + i;
+
+            optW->dwOption = optA->dwOption;
+
+            switch (optA->dwOption) {
+            case INTERNET_PER_CONN_AUTOCONFIG_URL:
+            case INTERNET_PER_CONN_PROXY_BYPASS:
+            case INTERNET_PER_CONN_PROXY_SERVER:
+            case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
+            case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
+                if (optA->Value.pszValue)
+                {
+                    wlen = MultiByteToWideChar( CP_ACP, 0, optA->Value.pszValue, -1, NULL, 0 );
+                    optW->Value.pszValue = heap_alloc(wlen*sizeof(WCHAR));
+                    MultiByteToWideChar( CP_ACP, 0, optA->Value.pszValue, -1, optW->Value.pszValue, wlen );
+                }
+                else
+                    optW->Value.pszValue = NULL;
+                break;
+            case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
+            case INTERNET_PER_CONN_FLAGS:
+            case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
+                optW->Value.dwValue = optA->Value.dwValue;
+                break;
+            case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
+                optW->Value.ftValue = optA->Value.ftValue;
+                break;
+            default:
+                WARN("Unknown PER_CONN dwOption: %d, guessing at conversion to Wide\n", optA->dwOption);
+                optW->Value.dwValue = optA->Value.dwValue;
+                break;
+            }
+        }
+        }
+        break;
     default:
         wbuffer = lpBuffer;
         wlen = dwBufferLength;
@@ -2482,7 +2851,29 @@ BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption,
     r = InternetSetOptionW(hInternet,dwOption, wbuffer, wlen);
 
     if( lpBuffer != wbuffer )
-        HeapFree( GetProcessHeap(), 0, wbuffer );
+    {
+        if (dwOption == INTERNET_OPTION_PER_CONNECTION_OPTION)
+        {
+            INTERNET_PER_CONN_OPTION_LISTW *list = wbuffer;
+            int i;
+            for (i = 0; i < list->dwOptionCount; ++i) {
+                INTERNET_PER_CONN_OPTIONW *opt = list->pOptions + i;
+                switch (opt->dwOption) {
+                case INTERNET_PER_CONN_AUTOCONFIG_URL:
+                case INTERNET_PER_CONN_PROXY_BYPASS:
+                case INTERNET_PER_CONN_PROXY_SERVER:
+                case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
+                case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
+                    heap_free( opt->Value.pszValue );
+                    break;
+                default:
+                    break;
+                }
+            }
+            heap_free( list->pOptions );
+        }
+        heap_free( wbuffer );
+    }
 
     return r;
 }
@@ -2507,7 +2898,7 @@ BOOL WINAPI InternetSetOptionExW(HINTERNET hInternet, DWORD dwOption,
     FIXME("Flags %08x ignored\n", dwFlags);
     if( dwFlags & ~ISO_VALID_FLAGS )
     {
-        INTERNET_SetLastError( ERROR_INVALID_PARAMETER );
+        SetLastError( ERROR_INVALID_PARAMETER );
         return FALSE;
     }
     return InternetSetOptionW( hInternet, dwOption, lpBuffer, dwBufferLength );
@@ -2591,18 +2982,14 @@ BOOL WINAPI InternetTimeToSystemTimeA( LPCSTR string, SYSTEMTIME* time, DWORD re
 {
     BOOL ret = FALSE;
     WCHAR *stringW;
-    int len;
 
     TRACE( "%s %p 0x%08x\n", debugstr_a(string), time, reserved );
 
-    len = MultiByteToWideChar( CP_ACP, 0, string, -1, NULL, 0 );
-    stringW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
-
+    stringW = heap_strdupAtoW(string);
     if (stringW)
     {
-        MultiByteToWideChar( CP_ACP, 0, string, -1, stringW, len );
         ret = InternetTimeToSystemTimeW( stringW, time, reserved );
-        HeapFree( GetProcessHeap(), 0, stringW );
+        heap_free( stringW );
     }
     return ret;
 }
@@ -2749,15 +3136,16 @@ BOOL WINAPI InternetCheckConnectionW( LPCWSTR lpszUrl, DWORD dwFlags, DWORD dwRe
 
   if (dwFlags & FLAG_ICC_FORCE_CONNECTION)
   {
-      struct sockaddr_in sin;
+      struct sockaddr_storage saddr;
+      socklen_t sa_len = sizeof(saddr);
       int fd;
 
-      if (!GetAddress(hostW, port, &sin))
+      if (!GetAddress(hostW, port, (struct sockaddr *)&saddr, &sa_len))
           goto End;
-      fd = socket(sin.sin_family, SOCK_STREAM, 0);
+      fd = socket(saddr.ss_family, SOCK_STREAM, 0);
       if (fd != -1)
       {
-          if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) == 0)
+          if (connect(fd, (struct sockaddr *)&saddr, sa_len) == 0)
               rc = TRUE;
           close(fd);
       }
@@ -2768,7 +3156,7 @@ BOOL WINAPI InternetCheckConnectionW( LPCWSTR lpszUrl, DWORD dwFlags, DWORD dwRe
        * Build our ping command
        */
       len = WideCharToMultiByte(CP_UNIXCP, 0, hostW, -1, NULL, 0, NULL, NULL);
-      command = HeapAlloc( GetProcessHeap(), 0, strlen(ping)+len+strlen(redirect) );
+      command = heap_alloc(strlen(ping)+len+strlen(redirect));
       strcpy(command,ping);
       WideCharToMultiByte(CP_UNIXCP, 0, hostW, -1, command+strlen(ping), len, NULL, NULL);
       strcat(command,redirect);
@@ -2785,8 +3173,7 @@ BOOL WINAPI InternetCheckConnectionW( LPCWSTR lpszUrl, DWORD dwFlags, DWORD dwRe
   }
 
 End:
-
-  HeapFree( GetProcessHeap(), 0, command );
+  heap_free( command );
   if (rc == FALSE)
     INTERNET_SetLastError(ERROR_NOT_CONNECTED);
 
@@ -2806,17 +3193,18 @@ End:
  */
 BOOL WINAPI InternetCheckConnectionA(LPCSTR lpszUrl, DWORD dwFlags, DWORD dwReserved)
 {
-    WCHAR *szUrl;
-    INT len;
+    WCHAR *url = NULL;
     BOOL rc;
 
-    len = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0);
-    if (!(szUrl = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR))))
-        return FALSE;
-    MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, szUrl, len);
-    rc = InternetCheckConnectionW(szUrl, dwFlags, dwReserved);
-    HeapFree(GetProcessHeap(), 0, szUrl);
-    
+    if(lpszUrl) {
+        url = heap_strdupAtoW(lpszUrl);
+        if(!url)
+            return FALSE;
+    }
+
+    rc = InternetCheckConnectionW(url, dwFlags, dwReserved);
+
+    heap_free(url);
     return rc;
 }
 
@@ -2829,13 +3217,14 @@ BOOL WINAPI InternetCheckConnectionA(LPCSTR lpszUrl, DWORD dwFlags, DWORD dwRese
  * RETURNS
  *   handle of connection or NULL on failure
  */
-static HINTERNET INTERNET_InternetOpenUrlW(LPWININETAPPINFOW hIC, LPCWSTR lpszUrl,
+static HINTERNET INTERNET_InternetOpenUrlW(appinfo_t *hIC, LPCWSTR lpszUrl,
     LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
 {
     URL_COMPONENTSW urlComponents;
     WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024];
     WCHAR password[1024], path[2048], extra[1024];
     HINTERNET client = NULL, client1 = NULL;
+    DWORD res;
     
     TRACE("(%p, %s, %s, %08x, %08x, %08lx)\n", hIC, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
          dwHeadersLength, dwFlags, dwContext);
@@ -2883,16 +3272,18 @@ static HINTERNET INTERNET_InternetOpenUrlW(LPWININETAPPINFOW hIC, LPCWSTR lpszUr
         if (urlComponents.nScheme == INTERNET_SCHEME_HTTPS) dwFlags |= INTERNET_FLAG_SECURE;
 
         /* FIXME: should use pointers, not handles, as handles are not thread-safe */
-       client = HTTP_Connect(hIC, hostName, urlComponents.nPort,
-                             userName, password, dwFlags, dwContext, INET_OPENURL);
-       if(client == NULL)
+       res = HTTP_Connect(hIC, hostName, urlComponents.nPort,
+                           userName, password, dwFlags, dwContext, INET_OPENURL, &client);
+        if(res != ERROR_SUCCESS) {
+            INTERNET_SetLastError(res);
            break;
+        }
 
        if (urlComponents.dwExtraInfoLength) {
                WCHAR *path_extra;
                DWORD len = urlComponents.dwUrlPathLength + urlComponents.dwExtraInfoLength + 1;
 
-               if (!(path_extra = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
+               if (!(path_extra = heap_alloc(len * sizeof(WCHAR))))
                {
                        InternetCloseHandle(client);
                        break;
@@ -2900,7 +3291,7 @@ static HINTERNET INTERNET_InternetOpenUrlW(LPWININETAPPINFOW hIC, LPCWSTR lpszUr
                strcpyW(path_extra, urlComponents.lpszUrlPath);
                strcatW(path_extra, urlComponents.lpszExtraInfo);
                client1 = HttpOpenRequestW(client, NULL, path_extra, NULL, NULL, accept, dwFlags, dwContext);
-               HeapFree(GetProcessHeap(), 0, path_extra);
+               heap_free(path_extra);
        }
        else
                client1 = HttpOpenRequestW(client, NULL, path, NULL, NULL, accept, dwFlags, dwContext);
@@ -2921,7 +3312,7 @@ static HINTERNET INTERNET_InternetOpenUrlW(LPWININETAPPINFOW hIC, LPCWSTR lpszUr
        /* gopher doesn't seem to be implemented in wine, but it's supposed
         * to be supported by InternetOpenUrlA. */
     default:
-        INTERNET_SetLastError(ERROR_INTERNET_UNRECOGNIZED_SCHEME);
+        SetLastError(ERROR_INTERNET_UNRECOGNIZED_SCHEME);
        break;
     }
 
@@ -2941,21 +3332,21 @@ static HINTERNET INTERNET_InternetOpenUrlW(LPWININETAPPINFOW hIC, LPCWSTR lpszUr
 static void AsyncInternetOpenUrlProc(WORKREQUEST *workRequest)
 {
     struct WORKREQ_INTERNETOPENURLW const *req = &workRequest->u.InternetOpenUrlW;
-    LPWININETAPPINFOW hIC = (LPWININETAPPINFOW) workRequest->hdr;
+    appinfo_t *hIC = (appinfo_t*) workRequest->hdr;
 
     TRACE("%p\n", hIC);
 
     INTERNET_InternetOpenUrlW(hIC, req->lpszUrl,
                               req->lpszHeaders, req->dwHeadersLength, req->dwFlags, req->dwContext);
-    HeapFree(GetProcessHeap(), 0, req->lpszUrl);
-    HeapFree(GetProcessHeap(), 0, req->lpszHeaders);
+    heap_free(req->lpszUrl);
+    heap_free(req->lpszHeaders);
 }
 
 HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl,
     LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
 {
     HINTERNET ret = NULL;
-    LPWININETAPPINFOW hIC = NULL;
+    appinfo_t *hIC = NULL;
 
     if (TRACE_ON(wininet)) {
        TRACE("(%p, %s, %s, %08x, %08x, %08lx)\n", hInternet, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
@@ -2966,13 +3357,13 @@ HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl,
 
     if (!lpszUrl)
     {
-        INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
+        SetLastError(ERROR_INVALID_PARAMETER);
         goto lend;
     }
 
-    hIC = (LPWININETAPPINFOW) WININET_GetObject( hInternet );
+    hIC = (appinfo_t*)get_handle_object( hInternet );
     if (NULL == hIC ||  hIC->hdr.htype != WH_HINIT) {
-       INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
+       SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
        goto lend;
     }
     
@@ -2982,12 +3373,9 @@ HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl,
 
        workRequest.asyncproc = AsyncInternetOpenUrlProc;
        workRequest.hdr = WININET_AddRef( &hIC->hdr );
-       req = &workRequest.u.InternetOpenUrlW;
-       req->lpszUrl = WININET_strdupW(lpszUrl);
-       if (lpszHeaders)
-           req->lpszHeaders = WININET_strdupW(lpszHeaders);
-       else
-           req->lpszHeaders = 0;
+        req = &workRequest.u.InternetOpenUrlW;
+        req->lpszUrl = heap_strdupW(lpszUrl);
+        req->lpszHeaders = heap_strdupW(lpszHeaders);
        req->dwHeadersLength = dwHeadersLength;
        req->dwFlags = dwFlags;
        req->dwContext = dwContext;
@@ -2996,7 +3384,7 @@ HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl,
        /*
         * This is from windows.
         */
-       INTERNET_SetLastError(ERROR_IO_PENDING);
+       SetLastError(ERROR_IO_PENDING);
     } else {
        ret = INTERNET_InternetOpenUrlW(hIC, lpszUrl, lpszHeaders, dwHeadersLength, dwFlags, dwContext);
     }
@@ -3021,27 +3409,23 @@ HINTERNET WINAPI InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl,
     LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
 {
     HINTERNET rc = NULL;
-
-    INT lenUrl;
-    INT lenHeaders = 0;
+    DWORD lenHeaders = 0;
     LPWSTR szUrl = NULL;
     LPWSTR szHeaders = NULL;
 
     TRACE("\n");
 
     if(lpszUrl) {
-        lenUrl = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0 );
-        szUrl = HeapAlloc(GetProcessHeap(), 0, lenUrl*sizeof(WCHAR));
+        szUrl = heap_strdupAtoW(lpszUrl);
         if(!szUrl)
             return NULL;
-        MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, szUrl, lenUrl);
     }
 
     if(lpszHeaders) {
         lenHeaders = MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, NULL, 0 );
-        szHeaders = HeapAlloc(GetProcessHeap(), 0, lenHeaders*sizeof(WCHAR));
+        szHeaders = heap_alloc(lenHeaders*sizeof(WCHAR));
         if(!szHeaders) {
-            HeapFree(GetProcessHeap(), 0, szUrl);
+            heap_free(szUrl);
             return NULL;
         }
         MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, szHeaders, lenHeaders);
@@ -3050,16 +3434,15 @@ HINTERNET WINAPI InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl,
     rc = InternetOpenUrlW(hInternet, szUrl, szHeaders,
         lenHeaders, dwFlags, dwContext);
 
-    HeapFree(GetProcessHeap(), 0, szUrl);
-    HeapFree(GetProcessHeap(), 0, szHeaders);
-
+    heap_free(szUrl);
+    heap_free(szHeaders);
     return rc;
 }
 
 
 static LPWITHREADERROR INTERNET_AllocThreadError(void)
 {
-    LPWITHREADERROR lpwite = HeapAlloc(GetProcessHeap(), 0, sizeof(*lpwite));
+    LPWITHREADERROR lpwite = heap_alloc(sizeof(*lpwite));
 
     if (lpwite)
     {
@@ -3069,10 +3452,9 @@ static LPWITHREADERROR INTERNET_AllocThreadError(void)
 
     if (!TlsSetValue(g_dwTlsErrIndex, lpwite))
     {
-        HeapFree(GetProcessHeap(), 0, lpwite);
+        heap_free(lpwite);
         return NULL;
     }
-
     return lpwite;
 }
 
@@ -3132,11 +3514,16 @@ static DWORD CALLBACK INTERNET_WorkerThreadFunc(LPVOID lpvParam)
     TRACE("\n");
 
     workRequest = *lpRequest;
-    HeapFree(GetProcessHeap(), 0, lpRequest);
+    heap_free(lpRequest);
 
     workRequest.asyncproc(&workRequest);
-
     WININET_Release( workRequest.hdr );
+
+    if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
+    {
+        heap_free(TlsGetValue(g_dwTlsErrIndex));
+        TlsSetValue(g_dwTlsErrIndex, NULL);
+    }
     return TRUE;
 }
 
@@ -3149,27 +3536,26 @@ static DWORD CALLBACK INTERNET_WorkerThreadFunc(LPVOID lpvParam)
  * RETURNS
  *
  */
-BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest)
+DWORD INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest)
 {
     BOOL bSuccess;
     LPWORKREQUEST lpNewRequest;
 
     TRACE("\n");
 
-    lpNewRequest = HeapAlloc(GetProcessHeap(), 0, sizeof(WORKREQUEST));
+    lpNewRequest = heap_alloc(sizeof(WORKREQUEST));
     if (!lpNewRequest)
-        return FALSE;
+        return ERROR_OUTOFMEMORY;
 
     *lpNewRequest = *lpWorkRequest;
 
     bSuccess = QueueUserWorkItem(INTERNET_WorkerThreadFunc, lpNewRequest, WT_EXECUTELONGFUNCTION);
     if (!bSuccess)
     {
-        HeapFree(GetProcessHeap(), 0, lpNewRequest);
-        INTERNET_SetLastError(ERROR_INTERNET_ASYNC_THREAD_FAILED);
+        heap_free(lpNewRequest);
+        return ERROR_INTERNET_ASYNC_THREAD_FAILED;
     }
-
-    return bSuccess;
+    return ERROR_SUCCESS;
 }
 
 
@@ -3272,9 +3658,9 @@ BOOL WINAPI InternetQueryDataAvailable( HINTERNET hFile,
 
     TRACE("(%p %p %x %lx)\n", hFile, lpdwNumberOfBytesAvailble, dwFlags, dwContext);
 
-    hdr = WININET_GetObject( hFile );
+    hdr = get_handle_object( hFile );
     if (!hdr) {
-        INTERNET_SetLastError(ERROR_INVALID_HANDLE);
+        SetLastError(ERROR_INVALID_HANDLE);
         return FALSE;
     }
 
@@ -3550,7 +3936,7 @@ static void convert_urlcomp_atow(LPURL_COMPONENTSA lpUrlComponents, LPURL_COMPON
     if (lpUrlComponents->lpszScheme)
     {
         len = URL_GET_COMP_LENGTHA(lpUrlComponents, Scheme) + 1;
-        urlCompW->lpszScheme = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        urlCompW->lpszScheme = heap_alloc(len * sizeof(WCHAR));
         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszScheme,
                             -1, urlCompW->lpszScheme, len);
     }
@@ -3558,7 +3944,7 @@ static void convert_urlcomp_atow(LPURL_COMPONENTSA lpUrlComponents, LPURL_COMPON
     if (lpUrlComponents->lpszHostName)
     {
         len = URL_GET_COMP_LENGTHA(lpUrlComponents, HostName) + 1;
-        urlCompW->lpszHostName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        urlCompW->lpszHostName = heap_alloc(len * sizeof(WCHAR));
         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszHostName,
                             -1, urlCompW->lpszHostName, len);
     }
@@ -3566,7 +3952,7 @@ static void convert_urlcomp_atow(LPURL_COMPONENTSA lpUrlComponents, LPURL_COMPON
     if (lpUrlComponents->lpszUserName)
     {
         len = URL_GET_COMP_LENGTHA(lpUrlComponents, UserName) + 1;
-        urlCompW->lpszUserName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        urlCompW->lpszUserName = heap_alloc(len * sizeof(WCHAR));
         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszUserName,
                             -1, urlCompW->lpszUserName, len);
     }
@@ -3574,7 +3960,7 @@ static void convert_urlcomp_atow(LPURL_COMPONENTSA lpUrlComponents, LPURL_COMPON
     if (lpUrlComponents->lpszPassword)
     {
         len = URL_GET_COMP_LENGTHA(lpUrlComponents, Password) + 1;
-        urlCompW->lpszPassword = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        urlCompW->lpszPassword = heap_alloc(len * sizeof(WCHAR));
         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszPassword,
                             -1, urlCompW->lpszPassword, len);
     }
@@ -3582,7 +3968,7 @@ static void convert_urlcomp_atow(LPURL_COMPONENTSA lpUrlComponents, LPURL_COMPON
     if (lpUrlComponents->lpszUrlPath)
     {
         len = URL_GET_COMP_LENGTHA(lpUrlComponents, UrlPath) + 1;
-        urlCompW->lpszUrlPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        urlCompW->lpszUrlPath = heap_alloc(len * sizeof(WCHAR));
         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszUrlPath,
                             -1, urlCompW->lpszUrlPath, len);
     }
@@ -3590,7 +3976,7 @@ static void convert_urlcomp_atow(LPURL_COMPONENTSA lpUrlComponents, LPURL_COMPON
     if (lpUrlComponents->lpszExtraInfo)
     {
         len = URL_GET_COMP_LENGTHA(lpUrlComponents, ExtraInfo) + 1;
-        urlCompW->lpszExtraInfo = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        urlCompW->lpszExtraInfo = heap_alloc(len * sizeof(WCHAR));
         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszExtraInfo,
                             -1, urlCompW->lpszExtraInfo, len);
     }
@@ -3612,14 +3998,14 @@ BOOL WINAPI InternetCreateUrlA(LPURL_COMPONENTSA lpUrlComponents, DWORD dwFlags,
 
     if (!lpUrlComponents || lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSW) || !lpdwUrlLength)
     {
-        INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
+        SetLastError(ERROR_INVALID_PARAMETER);
         return FALSE;
     }
 
     convert_urlcomp_atow(lpUrlComponents, &urlCompW);
 
     if (lpszUrl)
-        urlW = HeapAlloc(GetProcessHeap(), 0, *lpdwUrlLength * sizeof(WCHAR));
+        urlW = heap_alloc(*lpdwUrlLength * sizeof(WCHAR));
 
     ret = InternetCreateUrlW(&urlCompW, dwFlags, urlW, lpdwUrlLength);
 
@@ -3632,14 +4018,13 @@ BOOL WINAPI InternetCreateUrlA(LPURL_COMPONENTSA lpUrlComponents, DWORD dwFlags,
     if (ret)
         WideCharToMultiByte(CP_ACP, 0, urlW, -1, lpszUrl, *lpdwUrlLength + 1, NULL, NULL);
 
-    HeapFree(GetProcessHeap(), 0, urlCompW.lpszScheme);
-    HeapFree(GetProcessHeap(), 0, urlCompW.lpszHostName);
-    HeapFree(GetProcessHeap(), 0, urlCompW.lpszUserName);
-    HeapFree(GetProcessHeap(), 0, urlCompW.lpszPassword);
-    HeapFree(GetProcessHeap(), 0, urlCompW.lpszUrlPath);
-    HeapFree(GetProcessHeap(), 0, urlCompW.lpszExtraInfo);
-    HeapFree(GetProcessHeap(), 0, urlW);
-
+    heap_free(urlCompW.lpszScheme);
+    heap_free(urlCompW.lpszHostName);
+    heap_free(urlCompW.lpszUserName);
+    heap_free(urlCompW.lpszPassword);
+    heap_free(urlCompW.lpszUrlPath);
+    heap_free(urlCompW.lpszExtraInfo);
+    heap_free(urlW);
     return ret;
 }
 
@@ -3673,7 +4058,7 @@ BOOL WINAPI InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents, DWORD dwFlags,
     INTERNET_SCHEME nScheme;
 
     static const WCHAR slashSlashW[] = {'/','/'};
-    static const WCHAR percentD[] = {'%','d',0};
+    static const WCHAR fmtW[] = {'%','u',0};
 
     TRACE("(%p,%d,%p,%p)\n", lpUrlComponents, dwFlags, lpszUrl, lpdwUrlLength);
 
@@ -3760,7 +4145,7 @@ BOOL WINAPI InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents, DWORD dwFlags,
         {
             WCHAR szPort[MAX_WORD_DIGITS+1];
 
-            sprintfW(szPort, percentD, lpUrlComponents->nPort);
+            sprintfW(szPort, fmtW, lpUrlComponents->nPort);
             *lpszUrl = ':';
             lpszUrl++;
             dwLen = strlenW(szPort);