Autosyncing with Wine HEAD
authorThe Wine Synchronizer <winesync@svn.reactos.org>
Mon, 14 Jan 2008 17:07:49 +0000 (17:07 +0000)
committerThe Wine Synchronizer <winesync@svn.reactos.org>
Mon, 14 Jan 2008 17:07:49 +0000 (17:07 +0000)
svn path=/trunk/; revision=31799

31 files changed:
rostests/winetests/comctl32/comboex.c
rostests/winetests/comctl32/comctl32.rbuild
rostests/winetests/comctl32/comctl32_ros.diff
rostests/winetests/comctl32/datetime.c
rostests/winetests/comctl32/header.c
rostests/winetests/comctl32/imagelist.c
rostests/winetests/comctl32/listview.c
rostests/winetests/comctl32/monthcal.c
rostests/winetests/comctl32/mru.c
rostests/winetests/comctl32/progress.c
rostests/winetests/comctl32/rebar.c
rostests/winetests/comctl32/treeview.c
rostests/winetests/hlink/hlink.c [new file with mode: 0644]
rostests/winetests/hlink/hlink.rbuild [new file with mode: 0644]
rostests/winetests/hlink/testlist.c [new file with mode: 0644]
rostests/winetests/rsaenh/rsaenh.c
rostests/winetests/rsaenh/rsaenh.rbuild
rostests/winetests/schannel/main.c [new file with mode: 0644]
rostests/winetests/schannel/schannel.rbuild [new file with mode: 0644]
rostests/winetests/schannel/testlist.c [new file with mode: 0644]
rostests/winetests/shlwapi/shlwapi.rbuild
rostests/winetests/shlwapi/string.c
rostests/winetests/shlwapi/url.c
rostests/winetests/urlmon/misc.c
rostests/winetests/urlmon/protocol.c
rostests/winetests/urlmon/url.c
rostests/winetests/urlmon/urlmon.rbuild
rostests/winetests/wininet/ftp.c
rostests/winetests/wininet/generated.c
rostests/winetests/wininet/url.c
rostests/winetests/wininet/wininet.rbuild

index 8f436ca..f3f46b3 100644 (file)
@@ -189,11 +189,8 @@ static LRESULT CALLBACK ComboExTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, L
 
 static void init(void) {
     WNDCLASSA wc;
-    INITCOMMONCONTROLSEX icex;
 
-    icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
-    icex.dwICC   = ICC_USEREX_CLASSES;
-    InitCommonControlsEx(&icex);
+    InitCommonControls();
 
     wc.style = CS_HREDRAW | CS_VREDRAW;
     wc.cbClsExtra = 0;
index 07d9b34..f7ed7ae 100644 (file)
@@ -1,5 +1,6 @@
 <?xml version="1.0"?>
 <!DOCTYPE module SYSTEM "../../../tools/rbuild/project.dtd">
+<group>
 <module name="comctl32_winetest" type="win32cui" installbase="bin" installname="comctl32_winetest.exe" allowwarnings="true" entrypoint="0">
        <include base="comctl32_winetest">.</include>
        <define name="WINVER">0x600</define>
@@ -7,7 +8,6 @@
        <library>wine</library>
        <library>comctl32</library>
        <library>ole32</library>
-       <library>shlwapi</library>
        <library>user32</library>
        <library>gdi32</library>
        <library>advapi32</library>
@@ -37,3 +37,4 @@
        <file>rsrc.rc</file>
        <file>testlist.c</file>
 </module>
+</group>
index 4dfe3b1..d8b962d 100644 (file)
@@ -22,3 +22,16 @@ Index: monthcal.c
  #include "winuser.h"
  
  #include "commctrl.h"
+Index: mru.c
+===================================================================
+--- mru.c      (revision 25766)
++++ mru.c      (working copy)
+@@ -75,7 +75,7 @@
+ /* Based on RegDeleteTreeW from dlls/advapi32/registry.c */
+-static LSTATUS mru_RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
++static LONG mru_RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
+ {
+     LONG ret;
+     DWORD dwMaxSubkeyLen, dwMaxValueLen;
index 1a8afd1..956f16e 100644 (file)
@@ -560,11 +560,7 @@ static void test_datetime_control(void)
 
 START_TEST(datetime)
 {
-    INITCOMMONCONTROLSEX icex;
-
-    icex.dwSize = sizeof(icex);
-    icex.dwICC = ICC_DATE_CLASSES;
-    InitCommonControlsEx(&icex);
+    InitCommonControls();
     init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
 
     test_datetime_control();
index e80944f..fa75d49 100644 (file)
@@ -1482,11 +1482,8 @@ static LRESULT CALLBACK HeaderTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LP
 
 static void init(void) {
     WNDCLASSA wc;
-    INITCOMMONCONTROLSEX icex;
 
-    icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
-    icex.dwICC  = ICC_USEREX_CLASSES;
-    InitCommonControlsEx(&icex);
+    InitCommonControls();
 
     wc.style = CS_HREDRAW | CS_VREDRAW;
     wc.cbClsExtra = 0;
index 3d4c333..0d1770b 100644 (file)
@@ -65,7 +65,8 @@ typedef struct _ILHEAD
 } ILHEAD;
 #include "poppack.h"
 
-static BOOL (WINAPI *pImageList_DrawIndirect)(IMAGELISTDRAWPARAMS*) = NULL;
+static BOOL (WINAPI *pImageList_DrawIndirect)(IMAGELISTDRAWPARAMS*);
+static BOOL (WINAPI *pImageList_SetImageCount)(HIMAGELIST,UINT);
 
 static HDC desktopDC;
 static HINSTANCE hinst;
@@ -359,12 +360,19 @@ static BOOL DoTest1(void)
     ok(!ImageList_Remove(himl,0),"removed nonexistent icon\n");
 
     /* check SetImageCount/GetImageCount */
-    ok(ImageList_SetImageCount(himl, 3), "couldn't increase image count\n");
-    ok(ImageList_GetImageCount(himl) == 3, "invalid image count after increase\n");
-    ok(ImageList_SetImageCount(himl, 1), "couldn't decrease image count\n");
-    ok(ImageList_GetImageCount(himl) == 1, "invalid image count after decrease to 1\n");
-    ok(ImageList_SetImageCount(himl, 0), "couldn't decrease image count\n");
-    ok(ImageList_GetImageCount(himl) == 0, "invalid image count after decrease to 0\n");
+    if (pImageList_SetImageCount)
+    {
+        ok(pImageList_SetImageCount(himl, 3), "couldn't increase image count\n");
+        ok(ImageList_GetImageCount(himl) == 3, "invalid image count after increase\n");
+        ok(pImageList_SetImageCount(himl, 1), "couldn't decrease image count\n");
+        ok(ImageList_GetImageCount(himl) == 1, "invalid image count after decrease to 1\n");
+        ok(pImageList_SetImageCount(himl, 0), "couldn't decrease image count\n");
+        ok(ImageList_GetImageCount(himl) == 0, "invalid image count after decrease to 0\n");
+    }
+    else
+    {
+        skip("skipped ImageList_SetImageCount tests\n");
+    }
 
     /* destroy it */
     ok(ImageList_Destroy(himl),"destroy imagelist failed\n");
@@ -425,13 +433,8 @@ static BOOL DoTest3(void)
 
     if (!pImageList_DrawIndirect)
     {
-        HMODULE hComCtl32 = LoadLibraryA("comctl32.dll");
-        pImageList_DrawIndirect = (void*)GetProcAddress(hComCtl32, "ImageList_DrawIndirect");
-        if (!pImageList_DrawIndirect)
-        {
-            trace("ImageList_DrawIndirect not available, skipping test\n");
-            return TRUE;
-        }
+        trace("ImageList_DrawIndirect not available, skipping test\n");
+        return TRUE;
     }
 
     hwndfortest = create_a_window();
@@ -454,9 +457,12 @@ static BOOL DoTest3(void)
     ok(0==ImageList_Add(himl, hbm1, 0),"failed to add bitmap 1\n");
     ok(1==ImageList_Add(himl, hbm2, 0),"failed to add bitmap 2\n");
 
-    ok(ImageList_SetImageCount(himl,3),"Setimage count failed\n");
-    /*ok(2==ImageList_Add(himl, hbm3, NULL),"failed to add bitmap 3\n"); */
-    ok(ImageList_Replace(himl, 2, hbm3, 0),"failed to replace bitmap 3\n");
+    if (pImageList_SetImageCount)
+    {
+        ok(pImageList_SetImageCount(himl,3),"Setimage count failed\n");
+        /*ok(2==ImageList_Add(himl, hbm3, NULL),"failed to add bitmap 3\n"); */
+        ok(ImageList_Replace(himl, 2, hbm3, 0),"failed to replace bitmap 3\n");
+    }
 
     memset(&imldp, 0, sizeof (imldp));
     ok(!pImageList_DrawIndirect(&imldp), "zero data succeeded!\n");
@@ -969,6 +975,10 @@ static void test_imagelist_storage(void)
 
 START_TEST(imagelist)
 {
+    HMODULE hComCtl32 = GetModuleHandle("comctl32.dll");
+    pImageList_DrawIndirect = (void*)GetProcAddress(hComCtl32, "ImageList_DrawIndirect");
+    pImageList_SetImageCount = (void*)GetProcAddress(hComCtl32, "ImageList_SetImageCount");
+
     desktopDC=GetDC(NULL);
     hinst = GetModuleHandleA(NULL);
 
index 9138442..30a81a8 100644 (file)
@@ -1040,11 +1040,7 @@ static void test_item_position(void)
 
 START_TEST(listview)
 {
-    INITCOMMONCONTROLSEX icc;
-
-    icc.dwICC = 0;
-    icc.dwSize = sizeof icc;
-    InitCommonControlsEx(&icc);
+    InitCommonControls();
 
     init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
 
index fae4a37..d670004 100644 (file)
@@ -314,10 +314,9 @@ static void test_monthcal(void)
 {
     HWND hwnd;
     SYSTEMTIME st[2], st1[2];
-    INITCOMMONCONTROLSEX ic = {sizeof(INITCOMMONCONTROLSEX), ICC_DATE_CLASSES};
     int res, month_range;
 
-    InitCommonControlsEx(&ic);
+    InitCommonControls();
     hwnd = CreateWindowA(MONTHCAL_CLASSA, "MonthCal", WS_POPUP | WS_VISIBLE, CW_USEDEFAULT,
                          0, 300, 300, 0, 0, NULL, NULL);
     ok(hwnd != NULL, "Failed to create MonthCal\n");
@@ -479,9 +478,8 @@ static HWND create_monthcal_control(DWORD style, HWND parent_window)
 {
     struct subclass_info *info;
     HWND hwnd;
-    static const INITCOMMONCONTROLSEX ic = {sizeof(INITCOMMONCONTROLSEX), ICC_DATE_CLASSES};
 
-    InitCommonControlsEx(&ic);
+    InitCommonControls();
 
     info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
     if (!info)
index 2893a10..8ef1617 100644 (file)
@@ -68,11 +68,79 @@ static HMODULE hComctl32;
 static HANDLE (WINAPI *pCreateMRUListA)(LPCREATEMRULISTA);
 static void   (WINAPI *pFreeMRUList)(HANDLE);
 static INT    (WINAPI *pAddMRUStringA)(HANDLE,LPCSTR);
+static INT    (WINAPI *pEnumMRUList)(HANDLE,INT,LPVOID,DWORD);
 /*
 static INT    (WINAPI *pFindMRUStringA)(HANDLE,LPCSTR,LPINT);
-static INT    (WINAPI *pEnumMRUList)(HANDLE,INT,LPVOID,DWORD);
 */
 
+
+/* Based on RegDeleteTreeW from dlls/advapi32/registry.c */
+static LONG mru_RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
+{
+    LONG ret;
+    DWORD dwMaxSubkeyLen, dwMaxValueLen;
+    DWORD dwMaxLen, dwSize;
+    CHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
+    HKEY hSubKey = hKey;
+
+    if(lpszSubKey)
+    {
+        ret = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
+        if (ret) return ret;
+    }
+
+    /* Get highest length for keys, values */
+    ret = RegQueryInfoKeyA(hSubKey, NULL, NULL, NULL, NULL,
+            &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
+    if (ret) goto cleanup;
+
+    dwMaxSubkeyLen++;
+    dwMaxValueLen++;
+    dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
+    if (dwMaxLen > sizeof(szNameBuf)/sizeof(CHAR))
+    {
+        /* Name too big: alloc a buffer for it */
+        if (!(lpszName = HeapAlloc( GetProcessHeap(), 0, dwMaxLen*sizeof(CHAR))))
+        {
+            ret = ERROR_NOT_ENOUGH_MEMORY;
+            goto cleanup;
+        }
+    }
+
+
+    /* Recursively delete all the subkeys */
+    while (TRUE)
+    {
+        dwSize = dwMaxLen;
+        if (RegEnumKeyExA(hSubKey, 0, lpszName, &dwSize, NULL,
+                          NULL, NULL, NULL)) break;
+
+        ret = mru_RegDeleteTreeA(hSubKey, lpszName);
+        if (ret) goto cleanup;
+    }
+
+    if (lpszSubKey)
+        ret = RegDeleteKeyA(hKey, lpszSubKey);
+    else
+        while (TRUE)
+        {
+            dwSize = dwMaxLen;
+            if (RegEnumValueA(hKey, 0, lpszName, &dwSize,
+                  NULL, NULL, NULL, NULL)) break;
+
+            ret = RegDeleteValueA(hKey, lpszName);
+            if (ret) goto cleanup;
+        }
+
+cleanup:
+    /* Free buffer if allocated */
+    if (lpszName != szNameBuf)
+        HeapFree( GetProcessHeap(), 0, lpszName);
+    if(lpszSubKey)
+        RegCloseKey(hSubKey);
+    return ret;
+}
+
 static BOOL create_reg_entries(void)
 {
     HKEY hKey = NULL;
@@ -91,7 +159,7 @@ static void delete_reg_entries(void)
     if (RegOpenKeyExA(HKEY_CURRENT_USER, REG_TEST_BASEKEYA, 0, KEY_ALL_ACCESS,
                       &hKey))
         return;
-    SHDeleteKeyA(hKey, REG_TEST_BASESUBKEYA);
+    mru_RegDeleteTreeA(hKey, REG_TEST_BASESUBKEYA);
     RegCloseKey(hKey);
 }
 
@@ -162,8 +230,13 @@ static void test_MRUListA(void)
     pCreateMRUListA = (void*)GetProcAddress(hComctl32,(LPCSTR)151);
     pFreeMRUList = (void*)GetProcAddress(hComctl32,(LPCSTR)152);
     pAddMRUStringA = (void*)GetProcAddress(hComctl32,(LPCSTR)153);
-    if (!pCreateMRUListA || !pFreeMRUList || !pAddMRUStringA)
+    pEnumMRUList = (void*)GetProcAddress(hComctl32,(LPCSTR)154);
+
+    if (!pCreateMRUListA || !pFreeMRUList || !pAddMRUStringA || !pEnumMRUList)
+    {
+        skip("MRU entry points not found\n");
         return;
+    }
 
     if (0)
     {
@@ -213,6 +286,7 @@ static void test_MRUListA(void)
 
     if (hMRU)
     {
+        char buffer[255];
         checks[0] = "Test 1";
         checks[1] = "Test 2";
         checks[2] = "Test 3";
@@ -277,6 +351,61 @@ static void test_MRUListA(void)
         checks[0] = checks[3];
         check_reg_entries("abc", checks);
 
+        /* NULL buffer = get list size */
+        iRet = pEnumMRUList(hMRU, 0, NULL, 0);
+        ok(iRet == 3, "EnumMRUList expected %d, got %d\n", LIST_SIZE, iRet);
+
+        /* negative item pos = get list size */
+        iRet = pEnumMRUList(hMRU, -1, NULL, 0);
+        ok(iRet == 3, "EnumMRUList expected %d, got %d\n", LIST_SIZE, iRet);
+
+        /* negative item pos = get list size */
+        iRet = pEnumMRUList(hMRU, -5, NULL, 0);
+        ok(iRet == 3, "EnumMRUList expected %d, got %d\n", LIST_SIZE, iRet);
+
+        /* negative item pos = get list size */
+        iRet = pEnumMRUList(hMRU, -1, buffer, 255);
+        ok(iRet == 3, "EnumMRUList expected %d, got %d\n", LIST_SIZE, iRet);
+
+        /* negative item pos = get list size */
+        iRet = pEnumMRUList(hMRU, -5, buffer, 255);
+        ok(iRet == 3, "EnumMRUList expected %d, got %d\n", LIST_SIZE, iRet);
+
+        /* check entry 0 */
+        buffer[0] = 0;
+        iRet = pEnumMRUList(hMRU, 0, buffer, 255);
+        todo_wine ok(iRet == lstrlen(checks[3]), "EnumMRUList expected %d, got %d\n", lstrlen(checks[3]), iRet);
+        ok(strcmp(buffer, checks[3]) == 0, "EnumMRUList expected %s, got %s\n", checks[3], buffer);
+
+        /* check entry 0 with a too small buffer */
+        buffer[0] = 0;   /* overwritten with 'T' */
+        buffer[1] = 'A'; /* overwritten with 0   */
+        buffer[2] = 'A'; /* unchanged */
+        buffer[3] = 0;   /* unchanged */
+        iRet = pEnumMRUList(hMRU, 0, buffer, 2);
+        todo_wine ok(iRet == lstrlen(checks[3]), "EnumMRUList expected %d, got %d\n", lstrlen(checks[3]), iRet);
+        todo_wine ok(strcmp(buffer, "T") == 0, "EnumMRUList expected %s, got %s\n", "T", buffer);
+        /* make sure space after buffer has old values */
+        ok(buffer[2] == 'A', "EnumMRUList expected %02x, got %02x\n", 'A', buffer[2]);
+
+        /* check entry 1 */
+        buffer[0] = 0;
+        iRet = pEnumMRUList(hMRU, 1, buffer, 255);
+        todo_wine ok(iRet == lstrlen(checks[1]), "EnumMRUList expected %d, got %d\n", lstrlen(checks[1]), iRet);
+        ok(strcmp(buffer, checks[1]) == 0, "EnumMRUList expected %s, got %s\n", checks[1], buffer);
+
+        /* check entry 2 */
+        buffer[0] = 0;
+        iRet = pEnumMRUList(hMRU, 2, buffer, 255);
+        todo_wine ok(iRet == lstrlen(checks[2]), "EnumMRUList expected %d, got %d\n", lstrlen(checks[2]), iRet);
+        ok(strcmp(buffer, checks[2]) == 0, "EnumMRUList expected %s, got %s\n", checks[2], buffer);
+
+        /* check out of bounds entry 3 */
+        strcpy(buffer, "dummy");
+        iRet = pEnumMRUList(hMRU, 3, buffer, 255);
+        ok(iRet == -1, "EnumMRUList expected %d, got %d\n", -1, iRet);
+        ok(strcmp(buffer, "dummy") == 0, "EnumMRUList expected unchanged buffer %s, got %s\n", "dummy", buffer);
+
         /* Finished with this MRU */
         pFreeMRUList(hMRU);
     }
index 42c1e8d..2716f33 100644 (file)
@@ -91,12 +91,9 @@ static void update_window(HWND hWnd)
 static void init(void)
 {
     WNDCLASSA wc;
-    INITCOMMONCONTROLSEX icex;
     RECT rect;
     
-    icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
-    icex.dwICC   = ICC_PROGRESS_CLASS;
-    InitCommonControlsEx(&icex);
+    InitCommonControls();
   
     wc.style = CS_HREDRAW | CS_VREDRAW;
     wc.cbClsExtra = 0;
index 79da16e..6bebeb7 100644 (file)
@@ -786,14 +786,11 @@ static void bandinfo_test(void)
 
 START_TEST(rebar)
 {
-    INITCOMMONCONTROLSEX icc;
     WNDCLASSA wc;
     MSG msg;
     RECT rc;
 
-    icc.dwSize = sizeof(icc);
-    icc.dwICC = ICC_COOL_CLASSES;
-    InitCommonControlsEx(&icc);
+    InitCommonControls();
 
     wc.style = CS_HREDRAW | CS_VREDRAW;
     wc.cbClsExtra = 0;
index 2981db7..93010d3 100644 (file)
@@ -651,11 +651,8 @@ START_TEST(treeview)
 {
     WNDCLASSA wc;
     MSG msg;
-    INITCOMMONCONTROLSEX icex;
   
-    icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
-    icex.dwICC   = ICC_TREEVIEW_CLASSES;
-    InitCommonControlsEx(&icex);
+    InitCommonControls();
     init_msg_sequences(MsgSequences, NUM_MSG_SEQUENCES);
   
     wc.style = CS_HREDRAW | CS_VREDRAW;
diff --git a/rostests/winetests/hlink/hlink.c b/rostests/winetests/hlink/hlink.c
new file mode 100644 (file)
index 0000000..a2d7360
--- /dev/null
@@ -0,0 +1,458 @@
+/*
+ * Implementation of hyperlinking (hlink.dll)
+ *
+ * Copyright 2006 Mike McCormack
+ * Copyright 2007 Jacek Caban for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define COBJMACROS
+
+#include <stdio.h>
+
+#include <hlink.h>
+#include <hlguids.h>
+
+#include "wine/test.h"
+
+static const char *debugstr_w(LPCWSTR str)
+{
+    static char buf[1024];
+    if(!str)
+        return "(null)";
+    WideCharToMultiByte(CP_ACP, 0, str, -1, buf, sizeof(buf), NULL, NULL);
+    return buf;
+}
+
+static void test_HlinkIsShortcut(void)
+{
+    int i;
+    HRESULT hres;
+
+    static const WCHAR file0[] = {'f','i','l','e',0};
+    static const WCHAR file1[] = {'f','i','l','e','.','u','r','l',0};
+    static const WCHAR file2[] = {'f','i','l','e','.','l','n','k',0};
+    static const WCHAR file3[] = {'f','i','l','e','.','u','R','l',0};
+    static const WCHAR file4[] = {'f','i','l','e','u','r','l',0};
+    static const WCHAR file5[] = {'c',':','\\','f','i','l','e','.','u','r','l',0};
+    static const WCHAR file6[] = {'c',':','\\','f','i','l','e','.','l','n','k',0};
+    static const WCHAR file7[] = {'.','u','r','l',0};
+
+    static struct {
+        LPCWSTR file;
+        HRESULT hres;
+    } shortcut_test[] = {
+        {file0, S_FALSE},
+        {file1, S_OK},
+        {file2, S_FALSE},
+        {file3, S_OK},
+        {file4, S_FALSE},
+        {file5, S_OK},
+        {file6, S_FALSE},
+        {file7, S_OK},
+        {NULL,  E_INVALIDARG}
+    };
+
+    for(i=0; i<sizeof(shortcut_test)/sizeof(shortcut_test[0]); i++) {
+        hres = HlinkIsShortcut(shortcut_test[i].file);
+        ok(hres == shortcut_test[i].hres, "[%d] HlinkIsShortcut returned %08x, expected %08x\n",
+           i, hres, shortcut_test[i].hres);
+    }
+}
+
+static void test_reference(void)
+{
+    HRESULT r;
+    IHlink *lnk = NULL;
+    IMoniker *mk = NULL;
+    const WCHAR url[] = { 'h','t','t','p',':','/','/','w','i','n','e','h','q','.','o','r','g',0 };
+    const WCHAR url2[] = { 'h','t','t','p',':','/','/','w','i','n','e','h','q','.','o','r','g','/',0 };
+    LPWSTR str = NULL;
+
+    r = HlinkCreateFromString(url, NULL, NULL, NULL,
+                              0, NULL, &IID_IHlink, (LPVOID*) &lnk);
+    ok(r == S_OK, "failed to create link\n");
+    if (FAILED(r))
+        return;
+
+    r = IHlink_GetMonikerReference(lnk, HLINKGETREF_DEFAULT, NULL, NULL);
+    ok(r == S_OK, "failed\n");
+
+    r = IHlink_GetMonikerReference(lnk, HLINKGETREF_DEFAULT, &mk, &str);
+    ok(r == S_OK, "failed\n");
+    ok(mk != NULL, "no moniker\n");
+    ok(str == NULL, "string should be null\n");
+
+    r = IMoniker_Release(mk);
+    ok( r == 1, "moniker refcount wrong\n");
+
+    r = IHlink_GetStringReference(lnk, -1, &str, NULL);
+    ok(r == S_OK, "failed\n");
+    CoTaskMemFree(str);
+
+    r = IHlink_GetStringReference(lnk, HLINKGETREF_DEFAULT, &str, NULL);
+    ok(r == S_OK, "failed\n");
+    todo_wine {
+    ok(!lstrcmpW(str, url2), "url wrong\n");
+    }
+    CoTaskMemFree(str);
+
+    r = IHlink_GetStringReference(lnk, HLINKGETREF_DEFAULT, NULL, NULL);
+    ok(r == S_OK, "failed\n");
+
+    r = IHlink_GetStringReference(lnk, HLINKGETREF_DEFAULT, NULL, &str);
+    ok(r == S_OK, "failed\n");
+    ok(str == NULL, "string should be null\n");
+
+    IHlink_Release(lnk);
+}
+
+/* url only */
+static const unsigned char expected_hlink_data[] =
+{
+    0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
+    0xe0,0xc9,0xea,0x79,0xf9,0xba,0xce,0x11,
+    0x8c,0x82,0x00,0xaa,0x00,0x4b,0xa9,0x0b,
+    0x26,0x00,0x00,0x00,0x68,0x00,0x74,0x00,
+    0x74,0x00,0x70,0x00,0x3a,0x00,0x2f,0x00,
+    0x2f,0x00,0x77,0x00,0x69,0x00,0x6e,0x00,
+    0x65,0x00,0x68,0x00,0x71,0x00,0x2e,0x00,
+    0x6f,0x00,0x72,0x00,0x67,0x00,0x2f,0x00,
+    0x00,0x00,
+};
+
+/* url + friendly name */
+static const unsigned char expected_hlink_data2[] =
+{
+    0x02,0x00,0x00,0x00,0x17,0x00,0x00,0x00,
+    0x08,0x00,0x00,0x00,0x57,0x00,0x69,0x00,
+    0x6e,0x00,0x65,0x00,0x20,0x00,0x48,0x00,
+    0x51,0x00,0x00,0x00,0xe0,0xc9,0xea,0x79,
+    0xf9,0xba,0xce,0x11,0x8c,0x82,0x00,0xaa,
+    0x00,0x4b,0xa9,0x0b,0x26,0x00,0x00,0x00,
+    0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00,
+    0x3a,0x00,0x2f,0x00,0x2f,0x00,0x77,0x00,
+    0x69,0x00,0x6e,0x00,0x65,0x00,0x68,0x00,
+    0x71,0x00,0x2e,0x00,0x6f,0x00,0x72,0x00,
+    0x67,0x00,0x2f,0x00,0x00,0x00,
+};
+
+/* url + friendly name + location */
+static const unsigned char expected_hlink_data3[] =
+{
+    0x02,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,
+    0x08,0x00,0x00,0x00,0x57,0x00,0x69,0x00,
+    0x6e,0x00,0x65,0x00,0x20,0x00,0x48,0x00,
+    0x51,0x00,0x00,0x00,0xe0,0xc9,0xea,0x79,
+    0xf9,0xba,0xce,0x11,0x8c,0x82,0x00,0xaa,
+    0x00,0x4b,0xa9,0x0b,0x26,0x00,0x00,0x00,
+    0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00,
+    0x3a,0x00,0x2f,0x00,0x2f,0x00,0x77,0x00,
+    0x69,0x00,0x6e,0x00,0x65,0x00,0x68,0x00,
+    0x71,0x00,0x2e,0x00,0x6f,0x00,0x72,0x00,
+    0x67,0x00,0x2f,0x00,0x00,0x00,0x07,0x00,
+    0x00,0x00,0x5f,0x00,0x62,0x00,0x6c,0x00,
+    0x61,0x00,0x6e,0x00,0x6b,0x00,0x00,0x00,
+};
+
+/* relative url */
+static const unsigned char expected_hlink_data4[] =
+{
+    0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
+    0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
+    0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
+    0x00,0x00,0x0b,0x00,0x00,0x00,0x69,0x6e,
+    0x64,0x65,0x78,0x2e,0x68,0x74,0x6d,0x6c,
+    0x00,0xff,0xff,0xad,0xde,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,
+};
+
+/* url + target frame name */
+static const unsigned char expected_hlink_data5[] =
+{
+    0x02,0x00,0x00,0x00,0x83,0x00,0x00,0x00,
+    0x07,0x00,0x00,0x00,0x74,0x00,0x67,0x00,
+    0x74,0x00,0x66,0x00,0x72,0x00,0x6d,0x00,
+    0x00,0x00,0xe0,0xc9,0xea,0x79,0xf9,0xba,
+    0xce,0x11,0x8c,0x82,0x00,0xaa,0x00,0x4b,
+    0xa9,0x0b,0x26,0x00,0x00,0x00,0x68,0x00,
+    0x74,0x00,0x74,0x00,0x70,0x00,0x3a,0x00,
+    0x2f,0x00,0x2f,0x00,0x77,0x00,0x69,0x00,
+    0x6e,0x00,0x65,0x00,0x68,0x00,0x71,0x00,
+    0x2e,0x00,0x6f,0x00,0x72,0x00,0x67,0x00,
+    0x2f,0x00,0x00,0x00,
+};
+
+/* filename */
+static const unsigned char expected_hlink_data6[] =
+{
+     0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
+     0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
+     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
+     0x00,0x00,0x04,0x00,0x00,0x00,0x63,0x3a,
+     0x5c,0x00,0xff,0xff,0xad,0xde,0x00,0x00,
+     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+     0x00,0x00,0x0c,0x00,0x00,0x00,0x06,0x00,
+     0x00,0x00,0x03,0x00,0x63,0x00,0x3a,0x00,
+     0x5c,0x00,
+};
+
+static void test_persist_save_data(const char *testname, IHlink *lnk,
+                                   const unsigned char *expected_data,
+                                   unsigned int expected_data_size)
+{
+    HRESULT hr;
+    IStream *stream;
+    IPersistStream *ps;
+    HGLOBAL hglobal;
+    DWORD data_size;
+    const unsigned char *data;
+    DWORD i;
+    BOOL same;
+
+    hr = IHlink_QueryInterface(lnk, &IID_IPersistStream, (void **)&ps);
+    ok(hr == S_OK, "IHlink_QueryInterface failed with error 0x%08x\n", hr);
+
+    hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
+    ok(hr == S_OK, "CreateStreamOnHGlobal failed with error 0x%08x\n", hr);
+
+    hr = IPersistStream_Save(ps, stream, TRUE);
+    ok(hr == S_OK, "IPersistStream_Save failed with error 0x%08x\n", hr);
+
+    hr = GetHGlobalFromStream(stream, &hglobal);
+    ok(hr == S_OK, "GetHGlobalFromStream failed with error 0x%08x\n", hr);
+
+    data_size = GlobalSize(hglobal);
+
+    data = GlobalLock(hglobal);
+
+    /* first check we have the right amount of data */
+    ok(data_size == expected_data_size,
+       "%s: Size of saved data differs (expected %d, actual %d)\n",
+       testname, expected_data_size, data_size);
+
+    same = TRUE;
+    /* then do a byte-by-byte comparison */
+    for (i = 0; i < min(data_size, expected_data_size); i++)
+    {
+        if ((expected_data[i] != data[i]) &&
+            (((expected_data != expected_hlink_data2) &&
+              (expected_data != expected_hlink_data3)) ||
+             ((i < 52 || i >= 56) && (i < 80 || i >= 84))))
+        {
+            same = FALSE;
+            break;
+        }
+    }
+
+    ok(same, "%s: Saved data differs\n", testname);
+    if (!same)
+    {
+        for (i = 0; i < data_size; i++)
+        {
+            if (i % 8 == 0) printf("    ");
+            printf("0x%02x,", data[i]);
+            if (i % 8 == 7) printf("\n");
+        }
+        printf("\n");
+    }
+
+    GlobalUnlock(hglobal);
+
+    IStream_Release(stream);
+    IPersistStream_Release(ps);
+}
+
+static void test_persist(void)
+{
+    static const WCHAR url[] = { 'h','t','t','p',':','/','/','w','i','n','e','h','q','.','o','r','g',0 };
+    static const WCHAR rel_url[] = { 'i','n','d','e','x','.','h','t','m','l',0 };
+    static const WCHAR filename[] = { 'c',':','\\',0 };
+    static const WCHAR friendly_name[] = { 'W','i','n','e',' ','H','Q',0 };
+    static const WCHAR location[] = { '_','b','l','a','n','k',0 };
+    static const WCHAR target_frame_name[] = { 't','g','t','f','r','m',0 };
+    HRESULT hr;
+    IHlink *lnk;
+
+    hr = HlinkCreateFromString(url, NULL, NULL, NULL,
+                               0, NULL, &IID_IHlink, (LPVOID*) &lnk);
+    ok(hr == S_OK, "IHlinCreateFromString failed with error 0x%08x\n", hr);
+    test_persist_save_data("url only", lnk, expected_hlink_data, sizeof(expected_hlink_data));
+    IHlink_Release(lnk);
+
+    hr = HlinkCreateFromString(url, NULL, friendly_name, NULL,
+                               0, NULL, &IID_IHlink, (LPVOID*) &lnk);
+    ok(hr == S_OK, "IHlinCreateFromString failed with error 0x%08x\n", hr);
+    test_persist_save_data("url + friendly name", lnk, expected_hlink_data2, sizeof(expected_hlink_data2));
+    IHlink_Release(lnk);
+
+    hr = HlinkCreateFromString(url, location, friendly_name, NULL,
+                               0, NULL, &IID_IHlink, (LPVOID*) &lnk);
+    ok(hr == S_OK, "IHlinCreateFromString failed with error 0x%08x\n", hr);
+    test_persist_save_data("url + friendly_name + location", lnk, expected_hlink_data3, sizeof(expected_hlink_data3));
+    IHlink_Release(lnk);
+
+    hr = HlinkCreateFromString(rel_url, NULL, NULL, NULL,
+                               0, NULL, &IID_IHlink, (LPVOID*) &lnk);
+    ok(hr == S_OK, "IHlinCreateFromString failed with error 0x%08x\n", hr);
+    test_persist_save_data("relative url", lnk, expected_hlink_data4, sizeof(expected_hlink_data4));
+    IHlink_Release(lnk);
+
+    hr = HlinkCreateFromString(url, NULL, NULL, NULL,
+                               0, NULL, &IID_IHlink, (LPVOID*) &lnk);
+    ok(hr == S_OK, "IHlinCreateFromString failed with error 0x%08x\n", hr);
+    hr = IHlink_SetTargetFrameName(lnk, target_frame_name);
+    ok(hr == S_OK, "IHlink_SetTargetFrameName failed with error 0x%08x\n", hr);
+    test_persist_save_data("url + target frame name", lnk, expected_hlink_data5, sizeof(expected_hlink_data5));
+    IHlink_Release(lnk);
+
+    hr = HlinkCreateFromString(filename, NULL, NULL, NULL,
+                               0, NULL, &IID_IHlink, (LPVOID*) &lnk);
+    ok(hr == S_OK, "IHlinCreateFromString failed with error 0x%08x\n", hr);
+    test_persist_save_data("filename", lnk, expected_hlink_data6, sizeof(expected_hlink_data6));
+    IHlink_Release(lnk);
+}
+
+static void test_special_reference(void)
+{
+    LPWSTR ref;
+    HRESULT hres;
+
+    hres = HlinkGetSpecialReference(HLSR_HOME, &ref);
+    ok(hres == S_OK, "HlinkGetSpecialReference(HLSR_HOME) failed: %08x\n", hres);
+    ok(ref != NULL, "ref == NULL\n");
+    CoTaskMemFree(ref);
+
+    hres = HlinkGetSpecialReference(HLSR_SEARCHPAGE, &ref);
+    ok(hres == S_OK, "HlinkGetSpecialReference(HLSR_SEARCHPAGE) failed: %08x\n", hres);
+    ok(ref != NULL, "ref == NULL\n");
+    CoTaskMemFree(ref);
+
+    ref = (void*)0xdeadbeef;
+    hres = HlinkGetSpecialReference(HLSR_HISTORYFOLDER, &ref);
+    ok(hres == E_NOTIMPL, "HlinkGetSpecialReference(HLSR_HISTORYFOLDER) failed: %08x\n", hres);
+    ok(ref == NULL, "ref=%p\n", ref);
+
+    ref = (void*)0xdeadbeef;
+    hres = HlinkGetSpecialReference(4, &ref);
+    ok(hres == E_INVALIDARG, "HlinkGetSpecialReference(HLSR_HISTORYFOLDER) failed: %08x\n", hres);
+    ok(ref == NULL, "ref=%p\n", ref);
+}
+
+static void test_HlinkCreateExtensionServices(void)
+{
+    IAuthenticate *authenticate;
+    IHttpNegotiate *http_negotiate;
+    LPWSTR password, username, headers;
+    HWND hwnd;
+    HRESULT hres;
+
+    static const WCHAR usernameW[] = {'u','s','e','r',0};
+    static const WCHAR passwordW[] = {'p','a','s','s',0};
+    static const WCHAR headersW[] = {'h','e','a','d','e','r','s',0};
+    static const WCHAR headersexW[] = {'h','e','a','d','e','r','s','\r','\n',0};
+
+    hres = HlinkCreateExtensionServices(NULL, NULL, NULL, NULL,
+                                        NULL, &IID_IAuthenticate, (void**)&authenticate);
+    ok(hres == S_OK, "HlinkCreateExtensionServices failed: %08x\n", hres);
+    ok(authenticate != NULL, "HlinkCreateExtensionServices returned NULL\n");
+
+    password = username = (void*)0xdeadbeef;
+    hwnd = (void*)0xdeadbeef;
+    hres = IAuthenticate_Authenticate(authenticate, &hwnd, &username, &password);
+    ok(hres == S_OK, "Authenticate failed: %08x\n", hres);
+    ok(!hwnd, "hwnd != NULL\n");
+    ok(!username, "username != NULL\n");
+    ok(!password, "password != NULL\n");
+
+    hres = IAuthenticate_QueryInterface(authenticate, &IID_IHttpNegotiate, (void**)&http_negotiate);
+    ok(hres == S_OK, "Could not get IHttpNegotiate interface: %08x\n", hres);
+
+    headers = (void*)0xdeadbeef;
+    hres = IHttpNegotiate_BeginningTransaction(http_negotiate, (void*)0xdeadbeef, (void*)0xdeadbeef,
+                                               0, &headers);
+    ok(hres == S_OK, "BeginningTransaction failed: %08x\n", hres);
+    ok(headers == NULL, "headers != NULL\n");
+
+    hres = IHttpNegotiate_BeginningTransaction(http_negotiate, (void*)0xdeadbeef, (void*)0xdeadbeef,
+                                               0, NULL);
+    ok(hres == E_INVALIDARG, "BeginningTransaction failed: %08x, expected E_INVALIDARG\n", hres);
+
+    headers = (void*)0xdeadbeef;
+    hres = IHttpNegotiate_OnResponse(http_negotiate, 200, (void*)0xdeadbeef, (void*)0xdeadbeef, &headers);
+    ok(hres == S_OK, "OnResponse failed: %08x\n", hres);
+    ok(headers == NULL, "headers != NULL\n");
+
+    IHttpNegotiate_Release(http_negotiate);
+    IAuthenticate_Release(authenticate);
+
+
+    hres = HlinkCreateExtensionServices(headersW, (HWND)0xfefefefe, usernameW, passwordW,
+                                        NULL, &IID_IAuthenticate, (void**)&authenticate);
+    ok(hres == S_OK, "HlinkCreateExtensionServices failed: %08x\n", hres);
+    ok(authenticate != NULL, "HlinkCreateExtensionServices returned NULL\n");
+
+    password = username = NULL;
+    hwnd = NULL;
+    hres = IAuthenticate_Authenticate(authenticate, &hwnd, &username, &password);
+    ok(hres == S_OK, "Authenticate failed: %08x\n", hres);
+    ok(hwnd == (HWND)0xfefefefe, "hwnd=%p\n", hwnd);
+    ok(!lstrcmpW(username, usernameW), "unexpected username\n");
+    ok(!lstrcmpW(password, passwordW), "unexpected password\n");
+    CoTaskMemFree(username);
+    CoTaskMemFree(password);
+
+    password = username = (void*)0xdeadbeef;
+    hwnd = (void*)0xdeadbeef;
+    hres = IAuthenticate_Authenticate(authenticate, &hwnd, NULL, &password);
+    ok(hres == E_INVALIDARG, "Authenticate failed: %08x\n", hres);
+    ok(password == (void*)0xdeadbeef, "password = %p\n", password);
+    ok(hwnd == (void*)0xdeadbeef, "hwnd = %p\n", hwnd);
+
+    hres = IAuthenticate_QueryInterface(authenticate, &IID_IHttpNegotiate, (void**)&http_negotiate);
+    ok(hres == S_OK, "Could not get IHttpNegotiate interface: %08x\n", hres);
+
+    headers = (void*)0xdeadbeef;
+    hres = IHttpNegotiate_BeginningTransaction(http_negotiate, (void*)0xdeadbeef, (void*)0xdeadbeef,
+                                               0, &headers);
+    ok(hres == S_OK, "BeginningTransaction failed: %08x\n", hres);
+    ok(!lstrcmpW(headers, headersexW), "unexpected headers \"%s\"\n", debugstr_w(headers));
+    CoTaskMemFree(headers);
+
+    headers = (void*)0xdeadbeef;
+    hres = IHttpNegotiate_OnResponse(http_negotiate, 200, (void*)0xdeadbeef, (void*)0xdeadbeef, &headers);
+    ok(hres == S_OK, "OnResponse failed: %08x\n", hres);
+    ok(headers == NULL, "unexpected headers \"%s\"\n", debugstr_w(headers));
+
+    IHttpNegotiate_Release(http_negotiate);
+    IAuthenticate_Release(authenticate);
+}
+
+START_TEST(hlink)
+{
+    CoInitialize(NULL);
+
+    test_HlinkIsShortcut();
+    test_reference();
+    test_persist();
+    test_special_reference();
+    test_HlinkCreateExtensionServices();
+
+    CoUninitialize();
+}
diff --git a/rostests/winetests/hlink/hlink.rbuild b/rostests/winetests/hlink/hlink.rbuild
new file mode 100644 (file)
index 0000000..de30316
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+<!DOCTYPE module SYSTEM "../../../tools/rbuild/project.dtd">
+<group>
+<module name="hlink_winetest" type="win32cui" installbase="bin" installname="hlink_winetest.exe" allowwarnings="true" entrypoint="0">
+       <include base="hlink_winetest">.</include>
+       <define name="WINVER">0x600</define>
+       <define name="_WIN32_WINNT">0x600</define>
+       <library>wine</library>
+       <library>hlink</library>
+       <library>ole32</library>
+       <library>kernel32</library>
+       <library>uuid</library>
+       <library>ntdll</library>
+       <file>hlink.c</file>
+       <file>testlist.c</file>
+</module>
+</group>
diff --git a/rostests/winetests/hlink/testlist.c b/rostests/winetests/hlink/testlist.c
new file mode 100644 (file)
index 0000000..0876b7c
--- /dev/null
@@ -0,0 +1,15 @@
+/* Automatically generated file; DO NOT EDIT!! */
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#define STANDALONE
+#include "wine/test.h"
+
+extern void func_hlink(void);
+
+const struct test winetest_testlist[] =
+{
+    { "hlink", func_hlink },
+    { 0, 0 }
+};
index b44398d..5a7b474 100644 (file)
@@ -30,7 +30,6 @@
 
 static HCRYPTPROV hProv;
 static const char szContainer[] = "winetest";
-static const unsigned char pbData[] = "Wine rocks totally!";
 static const char szProvider[] = MS_ENHANCED_PROV_A;
 
 typedef struct _ctdatatype {
@@ -477,6 +476,8 @@ static void test_block_cipher_modes(void)
     dwLen = 23;
     result = CryptEncrypt(hKey, (HCRYPTHASH)NULL, TRUE, 0, abData, &dwLen, 24);
     ok(!result && GetLastError() == NTE_BAD_ALGID, "%08x\n", GetLastError());
+
+    CryptDestroyKey(hKey);
 }
 
 static void test_3des112(void)
@@ -1133,18 +1134,23 @@ static void test_import_private(void)
     result = CryptDecrypt(hSessionKey, 0, TRUE, 0, abEncryptedMessage, &dwLen);
     ok(result && dwLen == 12 && !memcmp(abEncryptedMessage, "Wine rocks!",12), 
        "%08x, len: %d\n", GetLastError(), dwLen);
+    CryptDestroyKey(hSessionKey);
     
     if (!derive_key(CALG_RC4, &hSessionKey, 56)) return;
 
     dwLen = (DWORD)sizeof(abSessionKey);
     result = CryptExportKey(hSessionKey, hKeyExchangeKey, SIMPLEBLOB, 0, abSessionKey, &dwLen);
     ok(result, "%08x\n", GetLastError());
+    CryptDestroyKey(hSessionKey);
     if (!result) return;
 
     dwLen = (DWORD)sizeof(abSessionKey);
     result = CryptImportKey(hProv, abSessionKey, dwLen, hKeyExchangeKey, 0, &hSessionKey);
     ok(result, "%08x\n", GetLastError());
     if (!result) return;
+
+    CryptDestroyKey(hSessionKey);
+    CryptDestroyKey(hKeyExchangeKey);
 }
 
 static void test_verify_signature(void) {
@@ -1364,6 +1370,8 @@ static void test_verify_signature(void) {
     ok(!result && GetLastError()==NTE_BAD_SIGNATURE, "%08lx\n", GetLastError());
     if (result) return;*/
 
+    CryptDestroyHash(hHash);
+
     result = CryptCreateHash(hProv, CALG_MD4, 0, 0, &hHash);
     ok(result, "%08x\n", GetLastError());
     if (!result) return;
@@ -1380,6 +1388,8 @@ static void test_verify_signature(void) {
     ok(result, "%08x\n", GetLastError());
     if (!result) return;
 
+    CryptDestroyHash(hHash);
+
     result = CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash);
     ok(result, "%08x\n", GetLastError());
     if (!result) return;
@@ -1396,6 +1406,8 @@ static void test_verify_signature(void) {
     ok(result, "%08x\n", GetLastError());
     if (!result) return;
 
+    CryptDestroyHash(hHash);
+
     result = CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash);
     ok(result, "%08x\n", GetLastError());
     if (!result) return;
@@ -1411,6 +1423,9 @@ static void test_verify_signature(void) {
     result = CryptVerifySignature(hHash, abSignatureSHANoOID, 128, hPubSignKey, NULL, CRYPT_NOHASHOID);
     ok(result, "%08x\n", GetLastError());
     if (!result) return;
+
+    CryptDestroyHash(hHash);
+    CryptDestroyKey(hPubSignKey);
 }
 
 static void test_rsa_encrypt(void)
@@ -1485,6 +1500,8 @@ static void test_import_export(void)
     ok(result, "failed to export the fresh imported public key\n");
     ok(dwLen == 84, "Expected exported key to be 84 bytes long but got %d bytes.\n",dwLen);
     ok(!memcmp(emptyKey, abPlainPublicKey, dwLen), "exported key is different from the imported key\n");
+
+    CryptDestroyKey(hPublicKey);
 }
         
 static void test_schannel_provider(void)
@@ -1497,83 +1514,6 @@ static void test_schannel_provider(void)
     SCHANNEL_ALG saSChannelAlg;
     CRYPT_DATA_BLOB data_blob;
     HMAC_INFO hmacInfo = { CALG_MD5, NULL, 0, NULL, 0 };
-    BYTE abPlainPrivateKey[596] = {
-        0x07, 0x02, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00,
-        0x52, 0x53, 0x41, 0x32, 0x00, 0x04, 0x00, 0x00,
-        0x01, 0x00, 0x01, 0x00, 0x9b, 0x64, 0xef, 0xce,
-        0x31, 0x7c, 0xad, 0x56, 0xe2, 0x1e, 0x9b, 0x96,
-        0xb3, 0xf0, 0x29, 0x88, 0x6e, 0xa8, 0xc2, 0x11,
-        0x33, 0xd6, 0xcc, 0x8c, 0x69, 0xb2, 0x1a, 0xfd,
-        0xfc, 0x23, 0x21, 0x30, 0x4d, 0x29, 0x45, 0xb6,
-        0x3a, 0x67, 0x11, 0x80, 0x1a, 0x91, 0xf2, 0x9f,
-        0x01, 0xac, 0xc0, 0x11, 0x50, 0x5f, 0xcd, 0xb9,
-        0xad, 0x76, 0x9f, 0x6e, 0x91, 0x55, 0x71, 0xda,
-        0x97, 0x96, 0x96, 0x22, 0x75, 0xb4, 0x83, 0x44,
-        0x89, 0x9e, 0xf8, 0x44, 0x40, 0x7c, 0xd6, 0xcd,
-        0x9d, 0x88, 0xd6, 0x88, 0xbc, 0x56, 0xb7, 0x64,
-        0xe9, 0x2c, 0x24, 0x2f, 0x0d, 0x78, 0x55, 0x1c,
-        0xb2, 0x67, 0xb1, 0x5e, 0xbc, 0x0c, 0xcf, 0x1c,
-        0xe9, 0xd3, 0x9e, 0xa2, 0x15, 0x24, 0x73, 0xd6,
-        0xdb, 0x6f, 0x83, 0xb2, 0xf8, 0xbc, 0xe7, 0x47,
-        0x3b, 0x01, 0xef, 0x49, 0x08, 0x98, 0xd6, 0xa3,
-        0xf9, 0x25, 0x57, 0xe9, 0x39, 0x3c, 0x53, 0x30,
-        0x1b, 0xf2, 0xc9, 0x62, 0x31, 0x43, 0x5d, 0x84,
-        0x24, 0x30, 0x21, 0x9a, 0xad, 0xdb, 0x62, 0x91,
-        0xc8, 0x07, 0xd9, 0x2f, 0xd6, 0xb5, 0x37, 0x6f,
-        0xfe, 0x7a, 0x12, 0xbc, 0xd9, 0xd2, 0x2b, 0xbf,
-        0xd7, 0xb1, 0xfa, 0x7d, 0xc0, 0x48, 0xdd, 0x74,
-        0xdd, 0x55, 0x04, 0xa1, 0x8b, 0xc1, 0x0a, 0xc4,
-        0xa5, 0x57, 0x62, 0xee, 0x08, 0x8b, 0xf9, 0x19,
-        0x6c, 0x52, 0x06, 0xf8, 0x73, 0x0f, 0x24, 0xc9,
-        0x71, 0x9f, 0xc5, 0x45, 0x17, 0x3e, 0xae, 0x06,
-        0x81, 0xa2, 0x96, 0x40, 0x06, 0xbf, 0xeb, 0x9e,
-        0x80, 0x2b, 0x27, 0x20, 0x8f, 0x38, 0xcf, 0xeb,
-        0xff, 0x3b, 0x38, 0x41, 0x35, 0x69, 0x66, 0x13,
-        0x1d, 0x3c, 0x01, 0x3b, 0xf6, 0x37, 0xca, 0x9c,
-        0x61, 0x74, 0x98, 0xcf, 0xc9, 0x6e, 0xe8, 0x90,
-        0xc7, 0xb7, 0x33, 0xc0, 0x07, 0x3c, 0xf8, 0xc8,
-        0xf6, 0xf2, 0xd7, 0xf0, 0x21, 0x62, 0x58, 0x8a,
-        0x55, 0xbf, 0xa1, 0x2d, 0x3d, 0xa6, 0x69, 0xc5,
-        0x02, 0x19, 0x31, 0xf0, 0x94, 0x0f, 0x45, 0x5c,
-        0x95, 0x1b, 0x53, 0xbc, 0xf5, 0xb0, 0x1a, 0x8f,
-        0xbf, 0x40, 0xe0, 0xc7, 0x73, 0xe7, 0x72, 0x6e,
-        0xeb, 0xb1, 0x0f, 0x38, 0xc5, 0xf8, 0xee, 0x04,
-        0xed, 0x34, 0x1a, 0x10, 0xf9, 0x53, 0x34, 0xf3,
-        0x3e, 0xe6, 0x5c, 0xd1, 0x47, 0x65, 0xcd, 0xbd,
-        0xf1, 0x06, 0xcb, 0xb4, 0xb1, 0x26, 0x39, 0x9f,
-        0x71, 0xfe, 0x3d, 0xf8, 0x62, 0xab, 0x22, 0x8b,
-        0x0e, 0xdc, 0xb9, 0xe8, 0x74, 0x06, 0xfc, 0x8c,
-        0x25, 0xa1, 0xa9, 0xcf, 0x07, 0xf9, 0xac, 0x21,
-        0x01, 0x7b, 0x1c, 0xdc, 0x94, 0xbd, 0x47, 0xe1,
-        0xa0, 0x86, 0x59, 0x35, 0x6a, 0x6f, 0xb9, 0x70,
-        0x26, 0x7c, 0x3c, 0xfd, 0xbd, 0x81, 0x39, 0x36,
-        0x42, 0xc2, 0xbd, 0xbe, 0x84, 0x27, 0x9a, 0x69,
-        0x81, 0xda, 0x99, 0x27, 0xc2, 0x4f, 0x62, 0x33,
-        0xf4, 0x79, 0x30, 0xc5, 0x63, 0x54, 0x71, 0xf1,
-        0x47, 0x22, 0x25, 0x9b, 0x6c, 0x00, 0x2f, 0x1c,
-        0xf4, 0x1f, 0x85, 0xbc, 0xf6, 0x67, 0x6a, 0xe3,
-        0xf6, 0x55, 0x8a, 0xef, 0xd0, 0x0b, 0xd3, 0xa2,
-        0xc5, 0x51, 0x70, 0x15, 0x0a, 0xf0, 0x98, 0x4c,
-        0xb7, 0x19, 0x62, 0x0e, 0x2d, 0x2a, 0x4a, 0x7d,
-        0x7a, 0x0a, 0xc4, 0x17, 0xe3, 0x5d, 0x20, 0x52,
-        0xa9, 0x98, 0xc3, 0xaa, 0x11, 0xf6, 0xbf, 0x4c,
-        0x94, 0x99, 0x81, 0x89, 0xf0, 0x7f, 0x66, 0xaa,
-        0xc8, 0x88, 0xd7, 0x31, 0x84, 0x71, 0xb6, 0x64,
-        0x09, 0x76, 0x0b, 0x7f, 0x1a, 0x1f, 0x2e, 0xfe,
-        0xcd, 0x59, 0x2a, 0x54, 0x11, 0x84, 0xd4, 0x6a,
-        0x61, 0xdf, 0xaa, 0x76, 0x66, 0x9d, 0x82, 0x11,
-        0x56, 0x3d, 0xd2, 0x52, 0xe6, 0x42, 0x5a, 0x77,
-        0x92, 0x98, 0x34, 0xf3, 0x56, 0x6c, 0x96, 0x10,
-        0x40, 0x59, 0x16, 0xcb, 0x77, 0x61, 0xe3, 0xbf,
-        0x4b, 0xd4, 0x39, 0xfb, 0xb1, 0x4e, 0xc1, 0x74,
-        0xec, 0x7a, 0xea, 0x3d, 0x68, 0xbb, 0x0b, 0xe6,
-        0xc6, 0x06, 0xbf, 0xdd, 0x7f, 0x94, 0x42, 0xc0,
-        0x0f, 0xe4, 0x92, 0x33, 0x6c, 0x6e, 0x1b, 0xba,
-        0x73, 0xf9, 0x79, 0x84, 0xdf, 0x45, 0x00, 0xe4,
-        0x94, 0x88, 0x9d, 0x08, 0x89, 0xcf, 0xf2, 0xa4,
-        0xc5, 0x47, 0x45, 0x85, 0x86, 0xa5, 0xcc, 0xa8,
-        0xf2, 0x5d, 0x58, 0x07
-    };
     BYTE abTLS1Master[140] = {
         0x01, 0x02, 0x00, 0x00, 0x06, 0x4c, 0x00, 0x00, 
         0x00, 0xa4, 0x00, 0x00, 0x5b, 0x13, 0xc7, 0x68, 
@@ -1929,6 +1869,7 @@ static void test_null_provider(void)
     if (!result) return;
     result = CryptImportKey(prov, signBlob, sizeof(signBlob), 0, 0, &key);
     ok(result, "CryptGenKey failed: %08x\n", GetLastError());
+    CryptDestroyKey(key);
     /* doesn't allow access to the key exchange key.. */
     result = CryptGetUserKey(prov, AT_KEYEXCHANGE, &key);
     ok(!result && GetLastError() == NTE_NO_KEY,
@@ -1937,6 +1878,7 @@ static void test_null_provider(void)
     result = CryptGetUserKey(prov, AT_SIGNATURE, &key);
     ok(result, "CryptGetUserKey failed: %08x\n", GetLastError());
     CryptDestroyKey(key);
+    CryptReleaseContext(prov, 0);
 
     CryptAcquireContext(&prov, szContainer, NULL, PROV_RSA_FULL,
      CRYPT_DELETEKEYSET);
@@ -1956,6 +1898,7 @@ static void test_null_provider(void)
     result = CryptGetUserKey(prov, AT_KEYEXCHANGE, &key);
     ok (result, "CryptGetUserKey failed with error %08x\n", GetLastError());
     CryptDestroyKey(key);
+    CryptReleaseContext(prov, 0);
 
     CryptAcquireContext(&prov, szContainer, NULL, PROV_RSA_FULL,
      CRYPT_DELETEKEYSET);
index 2bc6aeb..f8f3ad2 100644 (file)
@@ -1,5 +1,6 @@
 <?xml version="1.0"?>
 <!DOCTYPE module SYSTEM "../../../tools/rbuild/project.dtd">
+<group>
 <module name="rsaenh_winetest" type="win32cui" installbase="bin" installname="rsaenh_winetest.exe" allowwarnings="true" entrypoint="0">
        <include base="rsaenh_winetest">.</include>
        <define name="WINVER">0x600</define>
@@ -11,3 +12,4 @@
        <file>rsaenh.c</file>
        <file>testlist.c</file>
 </module>
+</group>
diff --git a/rostests/winetests/schannel/main.c b/rostests/winetests/schannel/main.c
new file mode 100644 (file)
index 0000000..af245d8
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * Schannel tests
+ *
+ * Copyright 2006 Yuval Fledel
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+#include <windef.h>
+#include <winbase.h>
+#define SECURITY_WIN32
+#include <security.h>
+#include <schannel.h>
+#include <ntsecapi.h>
+#include <ntsecpkg.h>
+
+#include "wine/test.h"
+
+/* Helper macros to find the size of SECPKG_FUNCTION_TABLE */
+#define SECPKG_FUNCTION_TABLE_SIZE_1 FIELD_OFFSET(SECPKG_FUNCTION_TABLE, \
+    SetContextAttributes)
+#define SECPKG_FUNCTION_TABLE_SIZE_2 FIELD_OFFSET(SECPKG_FUNCTION_TABLE, \
+    SetCredentialsAttributes)
+#define SECPKG_FUNCTION_TABLE_SIZE_3 sizeof(SECPKG_FUNCTION_TABLE)
+
+static NTSTATUS (NTAPI *pSpLsaModeInitialize)(ULONG, PULONG,
+    PSECPKG_FUNCTION_TABLE*, PULONG);
+static NTSTATUS (NTAPI *pSpUserModeInitialize)(ULONG, PULONG,
+    PSECPKG_USER_FUNCTION_TABLE*, PULONG);
+
+static void testInitialize(void)
+{
+    PSECPKG_USER_FUNCTION_TABLE pUserTables, pUserTables2;
+    PSECPKG_FUNCTION_TABLE pTables, pTables2;
+    ULONG cTables = 0, cUserTables = 0, Version = 0;
+    NTSTATUS status;
+
+    /* Passing NULL into one of the parameters of SpLsaModeInitialize or
+       SpUserModeInitialize causes a crash. */
+
+    /* SpLsaModeInitialize does not care about the LSA version. */
+    status = pSpLsaModeInitialize(0, &Version, &pTables2, &cTables);
+    ok(status == STATUS_SUCCESS, "status: 0x%x\n", status);
+    ok(cTables == 2, "cTables: %d\n", cTables);
+    ok(pTables2 != NULL,"pTables: %p\n", pTables2);
+
+    /* We can call it as many times we want. */
+    status = pSpLsaModeInitialize(0x10000, &Version, &pTables, &cTables);
+    ok(status == STATUS_SUCCESS, "status: 0x%x\n", status);
+    ok(cTables == 2, "cTables: %d\n", cTables);
+    ok(pTables != NULL, "pTables: %p\n", pTables);
+    /* It will always return the same pointer. */
+    ok(pTables == pTables2, "pTables: %p, pTables2: %p\n", pTables, pTables2);
+
+    status = pSpLsaModeInitialize(0x23456, &Version, &pTables, &cTables);
+    ok(status == STATUS_SUCCESS, "status: 0x%x\n", status);
+    ok(cTables == 2, "cTables: %d\n", cTables);
+    ok(pTables != NULL, "pTables: %p\n", pTables);
+    ok(pTables == pTables2, "pTables: %p, pTables2: %p\n", pTables, pTables2);
+
+    /* Bad versions to SpUserModeInitialize. Parameters unchanged */
+    Version = 0xdead;
+    cUserTables = 0xdead;
+    pUserTables = NULL;
+    status = pSpUserModeInitialize(0, &Version, &pUserTables, &cUserTables);
+    ok(status == STATUS_INVALID_PARAMETER, "status: 0x%x\n", status);
+    ok(Version == 0xdead, "Version: 0x%x\n", Version);
+    ok(cUserTables == 0xdead, "cTables: %d\n", cUserTables);
+    ok(pUserTables == NULL, "pUserTables: %p\n", pUserTables);
+
+    status = pSpUserModeInitialize(0x20000, &Version, &pUserTables,
+                                   &cUserTables);
+    ok(status == STATUS_INVALID_PARAMETER, "status: 0x%x\n", status);
+    ok(Version == 0xdead, "Version: 0x%x\n", Version);
+    ok(cUserTables == 0xdead, "cTables: %d\n", cUserTables);
+    ok(pUserTables == NULL, "pUserTables: %p\n", pUserTables);
+
+    /* Good version to SpUserModeInitialize */
+    status = pSpUserModeInitialize(SECPKG_INTERFACE_VERSION, &Version,
+                                   &pUserTables, &cUserTables);
+    ok(status == STATUS_SUCCESS, "status: 0x%x\n", status);
+    ok(Version == SECPKG_INTERFACE_VERSION, "Version: 0x%x\n", Version);
+    ok(cUserTables == 2, "cUserTables: %d\n", cUserTables);
+    ok(pUserTables != NULL, "pUserTables: %p\n", pUserTables);
+
+    /* Initializing user again */
+    status = pSpUserModeInitialize(SECPKG_INTERFACE_VERSION, &Version,
+                                   &pUserTables2, &cTables);
+    ok(status == STATUS_SUCCESS, "status: 0x%x\n", status);
+    ok(pUserTables == pUserTables2, "pUserTables: %p, pUserTables2: %p\n",
+       pUserTables, pUserTables2);
+}
+
+/* A helper function to find the dispatch table of the next package.
+   Needed because SECPKG_FUNCTION_TABLE's size depend on the version */
+static PSECPKG_FUNCTION_TABLE getNextSecPkgTable(PSECPKG_FUNCTION_TABLE pTable,
+                                                 ULONG Version)
+{
+    size_t size;
+
+    if (Version == SECPKG_INTERFACE_VERSION)
+        size = SECPKG_FUNCTION_TABLE_SIZE_1;
+    else if (Version == SECPKG_INTERFACE_VERSION_2)
+        size = SECPKG_FUNCTION_TABLE_SIZE_2;
+    else if (Version == SECPKG_INTERFACE_VERSION_3)
+        size = SECPKG_FUNCTION_TABLE_SIZE_3;
+    else {
+        ok(FALSE, "Unknown package version 0x%x\n", Version);
+        return NULL;
+    }
+
+    return (PSECPKG_FUNCTION_TABLE)((PBYTE)pTable + size);
+}
+
+static void testGetInfo(void)
+{
+    PSECPKG_FUNCTION_TABLE pTables;
+    SecPkgInfoW PackageInfo;
+    ULONG cTables, Version;
+    NTSTATUS status;
+
+    /* Get the dispatch table */
+    status = pSpLsaModeInitialize(0, &Version, &pTables, &cTables);
+    ok(status == STATUS_SUCCESS, "status: 0x%x\n", status);
+
+    /* Passing NULL into ->GetInfo causes a crash. */
+
+    /* First package: Unified */
+    status = pTables->GetInfo(&PackageInfo);
+    ok(status == STATUS_SUCCESS, "status: 0x%x\n", status);
+    ok(PackageInfo.fCapabilities == 0x107b3, "fCapabilities: 0x%lx\n",
+       PackageInfo.fCapabilities);
+    ok(PackageInfo.wVersion == 1, "wVersion: %d\n", PackageInfo.wVersion);
+    ok(PackageInfo.wRPCID == 14, "wRPCID: %d\n", PackageInfo.wRPCID);
+    ok(PackageInfo.cbMaxToken == 0x4000, "cbMaxToken: 0x%lx\n",
+       PackageInfo.cbMaxToken);
+
+    /* Second package: SChannel */
+    pTables = getNextSecPkgTable(pTables, Version);
+    if (!pTables)
+        return;
+    status = pTables->GetInfo(&PackageInfo);
+    ok(status == STATUS_SUCCESS, "status: 0x%x\n", status);
+    ok(PackageInfo.fCapabilities == 0x107b3, "fCapabilities: 0x%lx\n",
+       PackageInfo.fCapabilities);
+    ok(PackageInfo.wVersion == 1, "wVersion: %d\n", PackageInfo.wVersion);
+    ok(PackageInfo.wRPCID == 14, "wRPCID: %d\n", PackageInfo.wRPCID);
+    ok(PackageInfo.cbMaxToken == 0x4000, "cbMaxToken: 0x%lx\n",
+       PackageInfo.cbMaxToken);
+}
+
+START_TEST(main)
+{
+    HMODULE hMod = LoadLibraryA("schannel.dll");
+    if (!hMod) {
+        skip("schannel.dll not found.\n");
+        return;
+    }
+
+    pSpLsaModeInitialize  = (void *)GetProcAddress(hMod, "SpLsaModeInitialize");
+    pSpUserModeInitialize = (void *)GetProcAddress(hMod, "SpUserModeInitialize");
+
+    if (pSpLsaModeInitialize && pSpUserModeInitialize)
+    {
+        testInitialize();
+        testGetInfo();
+    }
+    else skip( "schannel functions not found\n" );
+
+    FreeLibrary(hMod);
+}
diff --git a/rostests/winetests/schannel/schannel.rbuild b/rostests/winetests/schannel/schannel.rbuild
new file mode 100644 (file)
index 0000000..d8d051b
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<!DOCTYPE module SYSTEM "../../../tools/rbuild/project.dtd">
+<group>
+<module name="schannel_winetest" type="win32cui" installbase="bin" installname="schannel_winetest.exe" allowwarnings="true" entrypoint="0">
+       <include base="schannel_winetest">.</include>
+       <define name="WINVER">0x600</define>
+       <define name="_WIN32_WINNT">0x600</define>
+       <library>wine</library>
+       <library>kernel32</library>
+       <library>ntdll</library>
+       <file>main.c</file>
+       <file>testlist.c</file>
+</module>
+</group>
diff --git a/rostests/winetests/schannel/testlist.c b/rostests/winetests/schannel/testlist.c
new file mode 100644 (file)
index 0000000..6f0c397
--- /dev/null
@@ -0,0 +1,15 @@
+/* Automatically generated file; DO NOT EDIT!! */
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#define STANDALONE
+#include "wine/test.h"
+
+extern void func_main(void);
+
+const struct test winetest_testlist[] =
+{
+    { "main", func_main },
+    { 0, 0 }
+};
index a35aba5..205175e 100644 (file)
@@ -1,5 +1,6 @@
 <?xml version="1.0"?>
 <!DOCTYPE module SYSTEM "../../../tools/rbuild/project.dtd">
+<group>
 <module name="shlwapi_winetest" type="win32cui" installbase="bin" installname="shlwapi_winetest.exe" allowwarnings="true" entrypoint="0">
        <include base="shlwapi_winetest">.</include>
        <define name="WINVER">0x600</define>
@@ -22,3 +23,4 @@
        <file>url.c</file>
        <file>testlist.c</file>
 </module>
+</group>
index 895d767..b90dcc6 100755 (executable)
@@ -483,6 +483,7 @@ static void test_StrDupA(void)
    */
   lpszStr = StrDupA(NULL);
   ok(lpszStr == NULL || *lpszStr == '\0', "NULL string returned %p\n", lpszStr);
+  LocalFree((HLOCAL)lpszStr);
 }
 
 static void test_StrFormatByteSize64A(void)
index 6d219c9..87b8b1d 100644 (file)
@@ -454,12 +454,34 @@ static void test_url_canonicalize(const char *szUrl, DWORD dwFlags, HRESULT dwEx
 
 static void test_UrlEscape(void)
 {
-    DWORD size;
+    DWORD size = 0;
     HRESULT ret;
     unsigned int i;
+    char empty_string[] = "";
 
     ret = UrlEscapeA("/woningplan/woonkamer basis.swf", NULL, &size, URL_ESCAPE_SPACES_ONLY);
     ok(ret == E_INVALIDARG, "got %x, expected %x\n", ret, E_INVALIDARG);
+    ok(size == 0, "got %d, expected %d\n", size, 0);
+
+    size = 0;
+    ret = UrlEscapeA("/woningplan/woonkamer basis.swf", empty_string, &size, URL_ESCAPE_SPACES_ONLY);
+    ok(ret == E_INVALIDARG, "got %x, expected %x\n", ret, E_INVALIDARG);
+    ok(size == 0, "got %d, expected %d\n", size, 0);
+
+    size = 1;
+    ret = UrlEscapeA("/woningplan/woonkamer basis.swf", NULL, &size, URL_ESCAPE_SPACES_ONLY);
+    ok(ret == E_INVALIDARG, "got %x, expected %x\n", ret, E_INVALIDARG);
+    ok(size == 1, "got %d, expected %d\n", size, 1);
+
+    size = 1;
+    ret = UrlEscapeA("/woningplan/woonkamer basis.swf", empty_string, NULL, URL_ESCAPE_SPACES_ONLY);
+    ok(ret == E_INVALIDARG, "got %x, expected %x\n", ret, E_INVALIDARG);
+    ok(size == 1, "got %d, expected %d\n", size, 1);
+
+    size = 1;
+    ret = UrlEscapeA("/woningplan/woonkamer basis.swf", empty_string, &size, URL_ESCAPE_SPACES_ONLY);
+    ok(ret == E_POINTER, "got %x, expected %x\n", ret, E_POINTER);
+    ok(size == 34, "got %d, expected %d\n", size, 34);
 
     for(i=0; i<sizeof(TEST_ESCAPE)/sizeof(TEST_ESCAPE[0]); i++) {
         test_url_escape(TEST_ESCAPE[i].url, TEST_ESCAPE[i].flags,
index 9f33f73..ba36d8a 100644 (file)
@@ -350,6 +350,48 @@ static void test_CoInternetCompareUrl(void)
     ok(hres == S_FALSE, "CoInternetParseUrl failed: %08x\n", hres);
 }
 
+static const struct {
+    LPCWSTR url;
+    DWORD uses_net;
+} query_info_tests[] = {
+    {url1, 0},
+    {url2, 0},
+    {url3, 0},
+    {url4, 0},
+    {url5, 0},
+    {url6, 0},
+    {url7, 0},
+    {url8, 0}
+};
+
+static void test_CoInternetQueryInfo(void)
+{
+    BYTE buf[100];
+    DWORD cb, i;
+    HRESULT hres;
+
+    for(i=0; i < sizeof(query_info_tests)/sizeof(query_info_tests[0]); i++) {
+        cb = 0xdeadbeef;
+        memset(buf, '?', sizeof(buf));
+        hres = CoInternetQueryInfo(query_info_tests[0].url, QUERY_USES_NETWORK, 0, buf, sizeof(buf), &cb, 0);
+        ok(hres == S_OK, "[%d] CoInternetQueryInfo failed: %08x\n", i, hres);
+        ok(cb == sizeof(DWORD), "[%d] cb = %d\n", i, cb);
+        ok(*(DWORD*)buf == query_info_tests[i].uses_net, "[%d] ret %x, expected %x\n",
+           i, *(DWORD*)buf, query_info_tests[i].uses_net);
+
+        hres = CoInternetQueryInfo(query_info_tests[0].url, QUERY_USES_NETWORK, 0, buf, 3, &cb, 0);
+        ok(hres == E_FAIL, "[%d] CoInternetQueryInfo failed: %08x, expected E_FAIL\n", i, hres);
+        hres = CoInternetQueryInfo(query_info_tests[0].url, QUERY_USES_NETWORK, 0, NULL, sizeof(buf), &cb, 0);
+        ok(hres == E_FAIL, "[%d] CoInternetQueryInfo failed: %08x, expected E_FAIL\n", i, hres);
+
+        memset(buf, '?', sizeof(buf));
+        hres = CoInternetQueryInfo(query_info_tests[0].url, QUERY_USES_NETWORK, 0, buf, sizeof(buf), NULL, 0);
+        ok(hres == S_OK, "[%d] CoInternetQueryInfo failed: %08x\n", i, hres);
+        ok(*(DWORD*)buf == query_info_tests[i].uses_net, "[%d] ret %x, expected %x\n",
+           i, *(DWORD*)buf, query_info_tests[i].uses_net);
+    }
+}
+
 static const WCHAR mimeTextHtml[] = {'t','e','x','t','/','h','t','m','l',0};
 static const WCHAR mimeTextPlain[] = {'t','e','x','t','/','p','l','a','i','n',0};
 static const WCHAR mimeTextRichtext[] = {'t','e','x','t','/','r','i','c','h','t','e','x','t',0};
@@ -608,6 +650,7 @@ static void test_FindMimeFromData(void)
             ok(!lstrcmpW(mime, mimeTextHtml), "[%d] wrong mime\n", i);
         else
             ok(!lstrcmpW(mime, mime_tests2[i].mime), "[%d] wrong mime\n", i);
+        CoTaskMemFree(mime);
 
         hres = FindMimeFromData(NULL, NULL, mime_tests2[i].data, mime_tests2[i].size,
                 mimeImagePjpeg, 0, &mime, 0);
@@ -891,6 +934,13 @@ static ULONG WINAPI ClassFactory_Release(IClassFactory *iface)
 
 static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
                                         REFIID riid, void **ppv)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ProtocolCF_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
+                                        REFIID riid, void **ppv)
 {
     CHECK_EXPECT(CreateInstance);
 
@@ -917,8 +967,17 @@ static const IClassFactoryVtbl ClassFactoryVtbl = {
     ClassFactory_LockServer
 };
 
-static IClassFactory test_protocol_cf = { &ClassFactoryVtbl };
-static IClassFactory test_protocol_cf2 = { &ClassFactoryVtbl };
+static const IClassFactoryVtbl ProtocolCFVtbl = {
+    ClassFactory_QueryInterface,
+    ClassFactory_AddRef,
+    ClassFactory_Release,
+    ProtocolCF_CreateInstance,
+    ClassFactory_LockServer
+};
+
+static IClassFactory test_protocol_cf = { &ProtocolCFVtbl };
+static IClassFactory test_protocol_cf2 = { &ProtocolCFVtbl };
+static IClassFactory test_cf = { &ClassFactoryVtbl };
 
 static void test_NameSpace(void)
 {
@@ -1046,6 +1105,33 @@ static void test_NameSpace(void)
     IInternetSession_Release(session);
 }
 
+static void test_MimeFilter(void)
+{
+    IInternetSession *session;
+    HRESULT hres;
+
+    static const WCHAR mimeW[] = {'t','e','s','t','/','m','i','m','e',0};
+
+    hres = CoInternetGetSession(0, &session, 0);
+    ok(hres == S_OK, "CoInternetGetSession failed: %08x\n", hres);
+    if(FAILED(hres))
+        return;
+
+    hres = IInternetSession_RegisterMimeFilter(session, &test_cf, &IID_NULL, mimeW);
+    ok(hres == S_OK, "RegisterMimeFilter failed: %08x\n", hres);
+
+    hres = IInternetSession_UnregisterMimeFilter(session, &test_cf, mimeW);
+    ok(hres == S_OK, "UnregisterMimeFilter failed: %08x\n", hres);
+
+    hres = IInternetSession_UnregisterMimeFilter(session, &test_cf, mimeW);
+    ok(hres == S_OK, "UnregisterMimeFilter failed: %08x\n", hres);
+
+    hres = IInternetSession_UnregisterMimeFilter(session, (void*)0xdeadbeef, mimeW);
+    ok(hres == S_OK, "UnregisterMimeFilter failed: %08x\n", hres);
+
+    IInternetSession_Release(session);
+}
+
 static ULONG WINAPI unk_Release(IUnknown *iface)
 {
     CHECK_EXPECT(unk_Release);
@@ -1195,10 +1281,12 @@ START_TEST(misc)
     test_RegisterFormatEnumerator();
     test_CoInternetParseUrl();
     test_CoInternetCompareUrl();
+    test_CoInternetQueryInfo();
     test_FindMimeFromData();
     test_SecurityManager();
     test_ZoneManager();
     test_NameSpace();
+    test_MimeFilter();
     test_ReleaseBindInfo();
     test_UrlMkGetSessionOption();
     test_ObtainUserAgentString();
index 00335b3..fd92171 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <wine/test.h>
 #include <stdarg.h>
+#include <stdio.h>
 
 #include "windef.h"
 #include "winbase.h"
@@ -73,6 +74,8 @@ DEFINE_EXPECT(ReportProgress_SENDINGREQUEST);
 DEFINE_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE);
 DEFINE_EXPECT(ReportProgress_VERIFIEDMIMETYPEAVAILABLE);
 DEFINE_EXPECT(ReportProgress_PROTOCOLCLASSID);
+DEFINE_EXPECT(ReportProgress_COOKIE_SENT);
+DEFINE_EXPECT(ReportProgress_REDIRECTING);
 DEFINE_EXPECT(ReportData);
 DEFINE_EXPECT(ReportResult);
 DEFINE_EXPECT(GetBindString_ACCEPT_MIMES);
@@ -84,26 +87,41 @@ DEFINE_EXPECT(BeginningTransaction);
 DEFINE_EXPECT(GetRootSecurityId);
 DEFINE_EXPECT(OnResponse);
 DEFINE_EXPECT(Switch);
+DEFINE_EXPECT(Continue);
 DEFINE_EXPECT(CreateInstance);
 DEFINE_EXPECT(Start);
 DEFINE_EXPECT(Terminate);
 DEFINE_EXPECT(Read);
 DEFINE_EXPECT(SetPriority);
+DEFINE_EXPECT(LockRequest);
+DEFINE_EXPECT(UnlockRequest);
 
 static const WCHAR wszIndexHtml[] = {'i','n','d','e','x','.','h','t','m','l',0};
 static const WCHAR index_url[] =
     {'f','i','l','e',':','i','n','d','e','x','.','h','t','m','l',0};
 
+static const WCHAR acc_mimeW[] = {'*','/','*',0};
+static const WCHAR user_agentW[] = {'W','i','n','e',0};
+static const WCHAR text_htmlW[] = {'t','e','x','t','/','h','t','m','l',0};
+static const WCHAR hostW[] = {'w','w','w','.','w','i','n','e','h','q','.','o','r','g',0};
+static const WCHAR winehq_ipW[] = {'2','0','9','.','4','6','.','2','5','.','1','3','4',0};
+static const WCHAR emptyW[] = {0};
+
 static HRESULT expect_hrResult;
 static LPCWSTR file_name, http_url, expect_wsz;
 static IInternetProtocol *http_protocol = NULL;
 static BOOL first_data_notif = FALSE, http_is_first = FALSE,
     http_post_test = FALSE;
-static int state = 0;
-static DWORD bindf = 0;
+static int state = 0, prot_state;
+static DWORD bindf = 0, ex_priority = 0;
+static IInternetProtocol *binding_protocol;
 static IInternetBindInfo *prot_bind_info;
+static IInternetProtocolSink *binding_sink;
 static void *expect_pv;
-static HANDLE event_complete;
+static HANDLE event_complete, event_complete2;
+static BOOL binding_test;
+static PROTOCOLDATA protocoldata, *pdata;
+static DWORD prot_read;
 
 static enum {
     FILE_TEST,
@@ -112,6 +130,41 @@ static enum {
     BIND_TEST
 } tested_protocol;
 
+static const WCHAR protocol_names[][10] = {
+    {'f','i','l','e',0},
+    {'h','t','t','p',0},
+    {'m','k',0},
+    {'t','e','s','t',0}
+};
+
+static const WCHAR binding_urls[][30] = {
+    {'f','i','l','e',':','t','e','s','t','.','h','t','m','l',0},
+    {'h','t','t','p',':','/','/','t','e','s','t','/','t','e','s','t','.','h','t','m','l',0},
+    {'m','k',':','t','e','s','t',0},
+    {'t','e','s','t',':','/','/','f','i','l','e','.','h','t','m','l',0}
+};
+
+static const char *debugstr_w(LPCWSTR str)
+{
+    static char buf[512];
+    if(!str)
+        return "(null)";
+    WideCharToMultiByte(CP_ACP, 0, str, -1, buf, sizeof(buf), NULL, NULL);
+    return buf;
+}
+
+static const char *debugstr_guid(REFIID riid)
+{
+    static char buf[50];
+
+    sprintf(buf, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
+            riid->Data1, riid->Data2, riid->Data3, riid->Data4[0],
+            riid->Data4[1], riid->Data4[2], riid->Data4[3], riid->Data4[4],
+            riid->Data4[5], riid->Data4[6], riid->Data4[7]);
+
+    return buf;
+}
+
 static HRESULT WINAPI HttpNegotiate_QueryInterface(IHttpNegotiate2 *iface, REFIID riid, void **ppv)
 {
     if(IsEqualGUID(&IID_IUnknown, riid)
@@ -147,7 +200,10 @@ static HRESULT WINAPI HttpNegotiate_BeginningTransaction(IHttpNegotiate2 *iface,
 
     CHECK_EXPECT(BeginningTransaction);
 
-    ok(!lstrcmpW(szURL, http_url), "szURL != http_url\n");
+    if(binding_test)
+        ok(!lstrcmpW(szURL, binding_urls[tested_protocol]), "szURL != http_url\n");
+    else
+        ok(!lstrcmpW(szURL, http_url), "szURL != http_url\n");
     ok(!dwReserved, "dwReserved=%d, expected 0\n", dwReserved);
     ok(pszAdditionalHeaders != NULL, "pszAdditionalHeaders == NULL\n");
     if(pszAdditionalHeaders)
@@ -247,7 +303,7 @@ static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface, REFG
         return E_NOINTERFACE;
     }
 
-    ok(0, "unexpected call\n");
+    ok(0, "unexpected service %s\n", debugstr_guid(guidService));
     return E_FAIL;
 }
 
@@ -281,6 +337,15 @@ static HRESULT WINAPI ProtocolSink_Switch(IInternetProtocolSink *iface, PROTOCOL
 
     CHECK_EXPECT(Switch);
     ok(pProtocolData != NULL, "pProtocolData == NULL\n");
+
+    pdata = pProtocolData;
+
+    if(binding_test) {
+        SetEvent(event_complete);
+        WaitForSingleObject(event_complete2, INFINITE);
+        return S_OK;
+    }
+
     if (!state) {
         if (http_is_first) {
             CHECK_CALLED(ReportProgress_FINDINGRESOURCE);
@@ -306,6 +371,7 @@ static HRESULT WINAPI ProtocolSink_Switch(IInternetProtocolSink *iface, PROTOCOL
     }
 
     SetEvent(event_complete);
+
     return S_OK;
 }
 
@@ -314,15 +380,10 @@ static HRESULT WINAPI ProtocolSink_ReportProgress(IInternetProtocolSink *iface,
 {
     static const WCHAR null_guid[] = {'{','0','0','0','0','0','0','0','0','-','0','0','0','0','-',
         '0','0','0','0','-','0','0','0','0','-','0','0','0','0','0','0','0','0','0','0','0','0','}',0};
-    static const WCHAR text_html[] = {'t','e','x','t','/','h','t','m','l',0};
     static const WCHAR text_plain[] = {'t','e','x','t','/','p','l','a','i','n',0};
-    static const WCHAR host[] =
-        {'w','w','w','.','w','i','n','e','h','q','.','o','r','g',0};
     static const WCHAR post_host[] =
         {'c','r','o','s','s','o','v','e','r','.','c','o','d','e',
          'w','e','a','v','e','r','s','.','c','o','m',0};
-    static const WCHAR wszWineHQIP[] =
-        {'2','0','9','.','4','6','.','2','5','.','1','3','4',0};
     static const WCHAR wszCrossoverIP[] =
         {'2','0','9','.','4','6','.','2','5','.','1','3','2',0};
     /* I'm not sure if it's a good idea to hardcode here the IP address... */
@@ -339,8 +400,8 @@ static HRESULT WINAPI ProtocolSink_ReportProgress(IInternetProtocolSink *iface,
                    !memcmp(szStatusText, text_plain, lstrlenW(text_plain)*sizeof(WCHAR)),
                    "szStatusText != text/plain\n");
             else
-                ok(lstrlenW(text_html) <= lstrlenW(szStatusText) &&
-                   !memcmp(szStatusText, text_html, lstrlenW(text_html)*sizeof(WCHAR)),
+                ok(lstrlenW(text_htmlW) <= lstrlenW(szStatusText) &&
+                   !memcmp(szStatusText, text_htmlW, lstrlenW(text_htmlW)*sizeof(WCHAR)),
                    "szStatusText != text/html\n");
         }
         break;
@@ -352,15 +413,15 @@ static HRESULT WINAPI ProtocolSink_ReportProgress(IInternetProtocolSink *iface,
         CHECK_EXPECT2(ReportProgress_RAWMIMETYPE);
         ok(szStatusText != NULL, "szStatusText == NULL\n");
         if(szStatusText)
-            ok(lstrlenW(szStatusText) < lstrlenW(text_html) ||
-               !memcmp(szStatusText, text_html, lstrlenW(text_html)*sizeof(WCHAR)),
+            ok(lstrlenW(szStatusText) < lstrlenW(text_htmlW) ||
+               !memcmp(szStatusText, text_htmlW, lstrlenW(text_htmlW)*sizeof(WCHAR)),
                "szStatusText != text/html\n");
         break;
     case BINDSTATUS_CACHEFILENAMEAVAILABLE:
         CHECK_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE);
         ok(szStatusText != NULL, "szStatusText == NULL\n");
         if(szStatusText) {
-            if(tested_protocol == BIND_TEST)
+            if(binding_test)
                 ok(szStatusText == expect_wsz, "unexpected szStatusText\n");
             else
                 ok(!lstrcmpW(szStatusText, file_name), "szStatusText != file_name\n");
@@ -372,7 +433,7 @@ static HRESULT WINAPI ProtocolSink_ReportProgress(IInternetProtocolSink *iface,
         if(szStatusText)
         {
             if (!http_post_test)
-                ok(!lstrcmpW(szStatusText, host),
+                ok(!lstrcmpW(szStatusText, hostW),
                    "szStatustext != \"www.winehq.org\"\n");
             else
                 ok(!lstrcmpW(szStatusText, post_host),
@@ -384,7 +445,7 @@ static HRESULT WINAPI ProtocolSink_ReportProgress(IInternetProtocolSink *iface,
         ok(szStatusText != NULL, "szStatusText == NULL\n");
         if(szStatusText)
             ok(!lstrcmpW(szStatusText, http_post_test ?
-                         wszCrossoverIP : wszWineHQIP),
+                         wszCrossoverIP : winehq_ipW),
                "Unexpected szStatusText\n");
         break;
     case BINDSTATUS_SENDINGREQUEST:
@@ -393,23 +454,29 @@ static HRESULT WINAPI ProtocolSink_ReportProgress(IInternetProtocolSink *iface,
             ok(szStatusText != NULL, "szStatusText == NULL\n");
             if(szStatusText)
                 ok(!*szStatusText, "wrong szStatusText\n");
-        }else {
-            ok(szStatusText == NULL, "szStatusText != NULL\n");
         }
         break;
     case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
         CHECK_EXPECT(ReportProgress_VERIFIEDMIMETYPEAVAILABLE);
         ok(szStatusText != NULL, "szStatusText == NULL\n");
         if(szStatusText)
-            ok(!lstrcmpW(szStatusText, text_html), "szStatusText != text/html\n");
+            ok(!lstrcmpW(szStatusText, text_htmlW), "szStatusText != text/html\n");
         break;
     case BINDSTATUS_PROTOCOLCLASSID:
         CHECK_EXPECT(ReportProgress_PROTOCOLCLASSID);
         ok(szStatusText != NULL, "szStatusText == NULL\n");
         ok(!lstrcmpW(szStatusText, null_guid), "unexpected szStatusText\n");
         break;
+    case BINDSTATUS_COOKIE_SENT:
+        CHECK_EXPECT(ReportProgress_COOKIE_SENT);
+        ok(szStatusText == NULL, "szStatusText != NULL\n");
+        break;
+    case BINDSTATUS_REDIRECTING:
+        CHECK_EXPECT(ReportProgress_REDIRECTING);
+        ok(szStatusText == NULL, "szStatusText != NULL\n");
+        break;
     default:
-        ok(0, "Unexpected call %d\n", ulStatusCode);
+        ok(0, "Unexpected status %d\n", ulStatusCode);
     };
 
     return S_OK;
@@ -426,7 +493,7 @@ static HRESULT WINAPI ProtocolSink_ReportData(IInternetProtocolSink *iface, DWOR
         ok(ulProgressMax == 13, "ulProgressMax=%d, expected 13\n", ulProgressMax);
         ok(grfBSCF == (BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION),
                 "grcfBSCF = %08x\n", grfBSCF);
-    }else if(tested_protocol == HTTP_TEST) {
+    }else if(!binding_test && tested_protocol == HTTP_TEST) {
         if(!(grfBSCF & BSCF_LASTDATANOTIFICATION))
             CHECK_EXPECT(ReportData);
         else if (http_post_test)
@@ -460,7 +527,23 @@ static HRESULT WINAPI ProtocolSink_ReportData(IInternetProtocolSink *iface, DWOR
             }
             SetEvent(event_complete);
         }
+    }else {
+        BYTE buf[1000];
+        ULONG read;
+        HRESULT hres;
+
+        CHECK_EXPECT(ReportData);
+
+        if(tested_protocol == BIND_TEST)
+            return S_OK;
+
+        do {
+            SET_EXPECT(Read);
+            hres = IInternetProtocol_Read(binding_protocol, expect_pv=buf, sizeof(buf), &read);
+            CHECK_CALLED(Read);
+        }while(hres == S_OK);
     }
+
     return S_OK;
 }
 
@@ -539,6 +622,8 @@ static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface, DWORD *grfB
     ok(pbindinfo->cbSize == sizeof(BINDINFO), "wrong size of pbindinfo: %d\n", pbindinfo->cbSize);
 
     *grfBINDF = bindf;
+    if(binding_test)
+        *grfBINDF |= BINDF_FROMURLMON;
     cbSize = pbindinfo->cbSize;
     memset(pbindinfo, 0, cbSize);
     pbindinfo->cbSize = cbSize;
@@ -566,9 +651,6 @@ static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface, DWORD *grfB
 static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface, ULONG ulStringType,
         LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
 {
-    static const WCHAR acc_mime[] = {'*','/','*',0};
-    static const WCHAR user_agent[] = {'W','i','n','e',0};
-
     ok(ppwzStr != NULL, "ppwzStr == NULL\n");
     ok(pcElFetched != NULL, "pcElFetched == NULL\n");
 
@@ -581,8 +663,8 @@ static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface, ULONG ulS
             *pcElFetched = 1;
         }
         if(ppwzStr) {
-            *ppwzStr = CoTaskMemAlloc(sizeof(acc_mime));
-            memcpy(*ppwzStr, acc_mime, sizeof(acc_mime));
+            *ppwzStr = CoTaskMemAlloc(sizeof(acc_mimeW));
+            memcpy(*ppwzStr, acc_mimeW, sizeof(acc_mimeW));
         }
         return S_OK;
     case BINDSTRING_USER_AGENT:
@@ -593,8 +675,8 @@ static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface, ULONG ulS
             *pcElFetched = 1;
         }
         if(ppwzStr) {
-            *ppwzStr = CoTaskMemAlloc(sizeof(user_agent));
-            memcpy(*ppwzStr, user_agent, sizeof(user_agent));
+            *ppwzStr = CoTaskMemAlloc(sizeof(user_agentW));
+            memcpy(*ppwzStr, user_agentW, sizeof(user_agentW));
         }
         return S_OK;
     case BINDSTRING_POST_COOKIE:
@@ -640,7 +722,7 @@ static ULONG WINAPI InternetPriority_Release(IInternetPriority *iface)
 static HRESULT WINAPI InternetPriority_SetPriority(IInternetPriority *iface, LONG nPriority)
 {
     CHECK_EXPECT(SetPriority);
-    ok(nPriority == 100, "nPriority=%d\n", nPriority);
+    ok(nPriority == ex_priority, "nPriority=%d\n", nPriority);
     return S_OK;
 }
 
@@ -673,7 +755,7 @@ static HRESULT WINAPI Protocol_QueryInterface(IInternetProtocol *iface, REFIID r
         return S_OK;
     }
 
-    ok(0, "unexpected call\n");
+    ok(0, "unexpected riid %s\n", debugstr_guid(riid));
     *ppv = NULL;
     return E_NOINTERFACE;
 }
@@ -688,6 +770,61 @@ static ULONG WINAPI Protocol_Release(IInternetProtocol *iface)
     return 1;
 }
 
+static DWORD WINAPI thread_proc(PVOID arg)
+{
+    HRESULT hres;
+
+    memset(&protocoldata, -1, sizeof(protocoldata));
+
+    prot_state = 0;
+
+    SET_EXPECT(ReportProgress_FINDINGRESOURCE);
+    hres = IInternetProtocolSink_ReportProgress(binding_sink,
+            BINDSTATUS_FINDINGRESOURCE, hostW);
+    CHECK_CALLED(ReportProgress_FINDINGRESOURCE);
+    ok(hres == S_OK, "ReportProgress failed: %08x\n", hres);
+
+    SET_EXPECT(ReportProgress_CONNECTING);
+    hres = IInternetProtocolSink_ReportProgress(binding_sink,
+            BINDSTATUS_CONNECTING, winehq_ipW);
+    CHECK_CALLED(ReportProgress_CONNECTING);
+    ok(hres == S_OK, "ReportProgress failed: %08x\n", hres);
+
+    SET_EXPECT(ReportProgress_SENDINGREQUEST);
+    hres = IInternetProtocolSink_ReportProgress(binding_sink,
+            BINDSTATUS_SENDINGREQUEST, NULL);
+    CHECK_CALLED(ReportProgress_SENDINGREQUEST);
+    ok(hres == S_OK, "ReportProgress failed: %08x\n", hres);
+
+    prot_state = 1;
+    SET_EXPECT(Switch);
+    hres = IInternetProtocolSink_Switch(binding_sink, &protocoldata);
+    CHECK_CALLED(Switch);
+    ok(hres == S_OK, "Switch failed: %08x\n", hres);
+
+    prot_state = 2;
+    SET_EXPECT(Switch);
+    hres = IInternetProtocolSink_Switch(binding_sink, &protocoldata);
+    CHECK_CALLED(Switch);
+    ok(hres == S_OK, "Switch failed: %08x\n", hres);
+
+    prot_state = 2;
+    SET_EXPECT(Switch);
+    hres = IInternetProtocolSink_Switch(binding_sink, &protocoldata);
+    CHECK_CALLED(Switch);
+    ok(hres == S_OK, "Switch failed: %08x\n", hres);
+
+    prot_state = 3;
+    SET_EXPECT(Switch);
+    hres = IInternetProtocolSink_Switch(binding_sink, &protocoldata);
+    CHECK_CALLED(Switch);
+    ok(hres == S_OK, "Switch failed: %08x\n", hres);
+
+    SetEvent(event_complete);
+
+    return 0;
+}
+
 static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
         IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
         DWORD grfPI, DWORD dwReserved)
@@ -696,13 +833,12 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
     DWORD cbindf = 0;
     HRESULT hres;
 
-    static const WCHAR wszTextHtml[] = {'t','e','x','t','/','h','t','m','l',0};
-    static const WCHAR empty_str[] = {0};
-
     CHECK_EXPECT(Start);
 
     ok(pOIProtSink != NULL, "pOIProtSink == NULL\n");
     ok(pOIBindInfo != NULL, "pOIBindInfo == NULL\n");
+    ok(pOIProtSink != &protocol_sink, "unexpected pOIProtSink\n");
+    ok(pOIBindInfo != &bind_info, "unexpected pOIBindInfo\n");
     ok(!grfPI, "grfPI = %x\n", grfPI);
     ok(!dwReserved, "dwReserved = %d\n", dwReserved);
 
@@ -716,29 +852,105 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
     ok(cbindf == (bindf|BINDF_FROMURLMON), "bindf = %x, expected %x\n",
        cbindf, (bindf|BINDF_FROMURLMON));
     ok(!memcmp(&exp_bindinfo, &bindinfo, sizeof(bindinfo)), "unexpected bindinfo\n");
+    ReleaseBindInfo(&bindinfo);
 
     SET_EXPECT(ReportProgress_SENDINGREQUEST);
-    hres = IInternetProtocolSink_ReportProgress(pOIProtSink,
-            BINDSTATUS_SENDINGREQUEST, empty_str);
+    hres = IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_SENDINGREQUEST, emptyW);
     ok(hres == S_OK, "ReportProgress(BINDSTATUS_SENDINGREQUEST) failed: %08x\n", hres);
     CHECK_CALLED(ReportProgress_SENDINGREQUEST);
 
+    if(tested_protocol == HTTP_TEST) {
+        IServiceProvider *service_provider;
+        IHttpNegotiate *http_negotiate;
+        IHttpNegotiate2 *http_negotiate2;
+        LPWSTR ua = (LPWSTR)0xdeadbeef, accept_mimes[256];
+        LPWSTR additional_headers = NULL;
+        BYTE sec_id[100];
+        DWORD fetched = 0, size = 100;
+
+        SET_EXPECT(GetBindString_USER_AGENT);
+        hres = IInternetBindInfo_GetBindString(pOIBindInfo, BINDSTRING_USER_AGENT,
+                                               &ua, 1, &fetched);
+        CHECK_CALLED(GetBindString_USER_AGENT);
+        ok(hres == S_OK, "GetBindString(BINDSTRING_USER_AGETNT) failed: %08x\n", hres);
+        ok(fetched == 1, "fetched = %d, expected 254\n", fetched);
+        ok(ua != NULL, "ua =  %p\n", ua);
+        ok(!lstrcmpW(ua, user_agentW), "unexpected user agent %s\n", debugstr_w(ua));
+        CoTaskMemFree(ua);
+
+        fetched = 256;
+        SET_EXPECT(GetBindString_ACCEPT_MIMES);
+        hres = IInternetBindInfo_GetBindString(pOIBindInfo, BINDSTRING_ACCEPT_MIMES,
+                                               accept_mimes, 256, &fetched);
+        CHECK_CALLED(GetBindString_ACCEPT_MIMES);
+
+        ok(hres == S_OK,
+           "GetBindString(BINDSTRING_ACCEPT_MIMES) failed: %08x\n", hres);
+        ok(fetched == 1, "fetched = %d, expected 1\n", fetched);
+        ok(!lstrcmpW(acc_mimeW, accept_mimes[0]), "unexpected mimes %s\n", debugstr_w(accept_mimes[0]));
+
+        hres = IInternetBindInfo_QueryInterface(pOIBindInfo, &IID_IServiceProvider,
+                                                (void**)&service_provider);
+        ok(hres == S_OK, "QueryInterface failed: %08x\n", hres);
+
+        SET_EXPECT(QueryService_HttpNegotiate);
+        hres = IServiceProvider_QueryService(service_provider, &IID_IHttpNegotiate,
+                &IID_IHttpNegotiate, (void**)&http_negotiate);
+        CHECK_CALLED(QueryService_HttpNegotiate);
+        ok(hres == S_OK, "QueryService failed: %08x\n", hres);
+
+        SET_EXPECT(BeginningTransaction);
+        hres = IHttpNegotiate_BeginningTransaction(http_negotiate, binding_urls[tested_protocol],
+                                                   NULL, 0, &additional_headers);
+        CHECK_CALLED(BeginningTransaction);
+        IHttpNegotiate_Release(http_negotiate);
+        ok(hres == S_OK, "BeginningTransction failed: %08x\n", hres);
+        ok(additional_headers == NULL, "additional_headers=%p\n", additional_headers);
+
+        SET_EXPECT(QueryService_HttpNegotiate);
+        hres = IServiceProvider_QueryService(service_provider, &IID_IHttpNegotiate2,
+                &IID_IHttpNegotiate2, (void**)&http_negotiate2);
+        CHECK_CALLED(QueryService_HttpNegotiate);
+        ok(hres == S_OK, "QueryService failed: %08x\n", hres);
+
+        size = 512;
+        SET_EXPECT(GetRootSecurityId);
+        hres = IHttpNegotiate2_GetRootSecurityId(http_negotiate2, sec_id, &size, 0);
+        CHECK_CALLED(GetRootSecurityId);
+        IHttpNegotiate2_Release(http_negotiate2);
+        ok(hres == E_FAIL, "GetRootSecurityId failed: %08x, expected E_FAIL\n", hres);
+        ok(size == 13, "size=%d\n", size);
+
+        IServiceProvider_Release(service_provider);
+
+        CreateThread(NULL, 0, thread_proc, NULL, 0, NULL);
+
+        return S_OK;
+    }
+
     SET_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE);
     hres = IInternetProtocolSink_ReportProgress(pOIProtSink,
-            BINDSTATUS_CACHEFILENAMEAVAILABLE, expect_wsz = empty_str);
+            BINDSTATUS_CACHEFILENAMEAVAILABLE, expect_wsz = emptyW);
     ok(hres == S_OK, "ReportProgress(BINDSTATUS_CACHEFILENAMEAVAILABLE) failed: %08x\n", hres);
     CHECK_CALLED(ReportProgress_CACHEFILENAMEAVAILABLE);
 
     SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE);
-    hres = IInternetProtocolSink_ReportProgress(pOIProtSink,
-            BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE, expect_wsz = wszTextHtml);
+    hres = IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE,
+                                                expect_wsz = text_htmlW);
     ok(hres == S_OK,
        "ReportProgress(BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE) failed: %08x\n", hres);
     CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE);
 
+    SET_EXPECT(ReportData);
     hres = IInternetProtocolSink_ReportData(pOIProtSink,
             BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION, 13, 13);
     ok(hres == S_OK, "ReportData failed: %08x\n", hres);
+    CHECK_CALLED(ReportData);
+
+    if(tested_protocol == BIND_TEST) {
+        hres = IInternetProtocol_Terminate(binding_protocol, 0);
+        ok(hres == E_FAIL, "Termiante failed: %08x\n", hres);
+    }
 
     SET_EXPECT(ReportResult);
     hres = IInternetProtocolSink_ReportResult(pOIProtSink, S_OK, 0, NULL);
@@ -751,8 +963,64 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
 static HRESULT WINAPI Protocol_Continue(IInternetProtocol *iface,
         PROTOCOLDATA *pProtocolData)
 {
-    ok(0, "unexpected call\n");
-    return E_NOTIMPL;
+    DWORD bscf = 0;
+    HRESULT hres;
+
+    CHECK_EXPECT(Continue);
+
+    ok(pProtocolData != NULL, "pProtocolData == NULL\n");
+    if(!pProtocolData || tested_protocol == BIND_TEST)
+        return S_OK;
+
+    switch(prot_state) {
+    case 1: {
+        IServiceProvider *service_provider;
+        IHttpNegotiate *http_negotiate;
+        static WCHAR header[] = {'?',0};
+
+        hres = IInternetProtocolSink_QueryInterface(binding_sink, &IID_IServiceProvider,
+                                                    (void**)&service_provider);
+        ok(hres == S_OK, "Could not get IServiceProvicder\n");
+
+        SET_EXPECT(QueryService_HttpNegotiate);
+        hres = IServiceProvider_QueryService(service_provider, &IID_IHttpNegotiate,
+                                             &IID_IHttpNegotiate, (void**)&http_negotiate);
+        IServiceProvider_Release(service_provider);
+        CHECK_CALLED(QueryService_HttpNegotiate);
+        ok(hres == S_OK, "Could not get IHttpNegotiate\n");
+
+        SET_EXPECT(OnResponse);
+        hres = IHttpNegotiate_OnResponse(http_negotiate, 200, header, NULL, NULL);
+        IHttpNegotiate_Release(http_negotiate);
+        CHECK_CALLED(OnResponse);
+        IHttpNegotiate_Release(http_negotiate);
+        ok(hres == S_OK, "OnResponse failed: %08x\n", hres);
+
+        SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE);
+        hres = IInternetProtocolSink_ReportProgress(binding_sink,
+                BINDSTATUS_MIMETYPEAVAILABLE, text_htmlW);
+        CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE);
+        ok(hres == S_OK,
+           "ReportProgress(BINDSTATUS_MIMETYPEAVAILABLE) failed: %08x\n", hres);
+
+        bscf |= BSCF_FIRSTDATANOTIFICATION;
+        break;
+    }
+    case 2:
+    case 3:
+        bscf = BSCF_INTERMEDIATEDATANOTIFICATION;
+        break;
+    }
+
+    SET_EXPECT(ReportData);
+    hres = IInternetProtocolSink_ReportData(binding_sink, bscf, 100, 400);
+    CHECK_CALLED(ReportData);
+    ok(hres == S_OK, "ReportData failed: %08x\n", hres);
+
+    if(prot_state == 3)
+        prot_state = 4;
+
+    return S_OK;
 }
 
 static HRESULT WINAPI Protocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
@@ -784,7 +1052,7 @@ static HRESULT WINAPI Protocol_Resume(IInternetProtocol *iface)
 static HRESULT WINAPI Protocol_Read(IInternetProtocol *iface, void *pv,
         ULONG cb, ULONG *pcbRead)
 {
-    static DWORD read;
+    static BOOL b = TRUE;
 
     CHECK_EXPECT(Read);
 
@@ -793,11 +1061,21 @@ static HRESULT WINAPI Protocol_Read(IInternetProtocol *iface, void *pv,
     ok(pcbRead != NULL, "pcbRead == NULL\n");
     ok(!*pcbRead, "*pcbRead = %d\n", *pcbRead);
 
-    if(read)
+    if(prot_state == 3) {
+        HRESULT hres;
+
+        SET_EXPECT(ReportResult);
+        hres = IInternetProtocolSink_ReportResult(binding_sink, S_OK, ERROR_SUCCESS, NULL);
+        CHECK_CALLED(ReportResult);
+
         return S_FALSE;
+    }
+
+    if((b = !b))
+        return tested_protocol == HTTP_TEST ? E_PENDING : S_FALSE;
 
     memset(pv, 'x', 100);
-    *pcbRead = read = 100;
+    prot_read += *pcbRead = 100;
     return S_OK;
 }
 
@@ -810,13 +1088,14 @@ static HRESULT WINAPI Protocol_Seek(IInternetProtocol *iface,
 
 static HRESULT WINAPI Protocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
 {
-    ok(0, "unexpected call\n");
+    CHECK_EXPECT(LockRequest);
+    ok(dwOptions == 0, "dwOptions=%x\n", dwOptions);
     return S_OK;
 }
 
 static HRESULT WINAPI Protocol_UnlockRequest(IInternetProtocol *iface)
 {
-    ok(0, "unexpected call\n");
+    CHECK_EXPECT(UnlockRequest);
     return S_OK;
 }
 
@@ -860,7 +1139,7 @@ static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown
     CHECK_EXPECT(CreateInstance);
 
     ok(pOuter == (IUnknown*)prot_bind_info, "pOuter != protocol_unk\n");
-    ok(IsEqualGUID(&IID_IUnknown, riid), "unexpected riid\n");
+    ok(IsEqualGUID(&IID_IUnknown, riid), "unexpected riid %s\n", debugstr_guid(riid));
     ok(ppv != NULL, "ppv == NULL\n");
 
     *ppv = &Protocol;
@@ -1231,12 +1510,10 @@ static void test_http_protocol_url(LPCWSTR url, BOOL is_first)
     IUnknown *unk;
     HRESULT hres;
 
-    trace("Testing http protocol...\n");
     http_url = url;
     http_is_first = is_first;
 
-    hres = CoGetClassObject(&CLSID_HttpProtocol, CLSCTX_INPROC_SERVER, NULL,
-            &IID_IUnknown, (void**)&unk);
+    hres = CoGetClassObject(&CLSID_HttpProtocol, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void**)&unk);
     ok(hres == S_OK, "CoGetClassObject failed: %08x\n", hres);
     if(!SUCCEEDED(hres))
         return;
@@ -1353,12 +1630,16 @@ static void test_http_protocol(void)
          'c','o','d','e','w','e','a','v','e','r','s','.','c','o','m','/',
          'p','o','s','t','t','e','s','t','.','p','h','p',0};
 
+    trace("Testing http protocol (not from urlmon)...\n");
     tested_protocol = HTTP_TEST;
     bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA;
     test_http_protocol_url(winehq_url, TRUE);
+
+    trace("Testing http protocol (from urlmon)...\n");
     bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA | BINDF_FROMURLMON;
     test_http_protocol_url(winehq_url, FALSE);
 
+    trace("Testing http protocol (post data)...\n");
     http_post_test = TRUE;
     /* Without this flag we get a ReportProgress_CACHEFILENAMEAVAILABLE
      * notification with BINDVERB_POST */
@@ -1429,6 +1710,7 @@ static void test_mk_protocol(void)
 
 static void test_CreateBinding(void)
 {
+    IInternetProtocolSink *sink;
     IInternetProtocol *protocol;
     IInternetPriority *priority;
     IInternetSession *session;
@@ -1443,6 +1725,7 @@ static void test_CreateBinding(void)
 
     trace("Testing CreateBinding...\n");
     tested_protocol = BIND_TEST;
+    binding_test = TRUE;
 
     hres = CoInternetGetSession(0, &session, 0);
     ok(hres == S_OK, "CoInternetGetSession failed: %08x\n", hres);
@@ -1451,12 +1734,16 @@ static void test_CreateBinding(void)
     ok(hres == S_OK, "RegisterNameSpace failed: %08x\n", hres);
 
     hres = IInternetSession_CreateBinding(session, NULL, test_url, NULL, NULL, &protocol, 0);
+    binding_protocol = protocol;
     ok(hres == S_OK, "CreateBinding failed: %08x\n", hres);
     ok(protocol != NULL, "protocol == NULL\n");
 
     hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetBindInfo, (void**)&prot_bind_info);
     ok(hres == S_OK, "QueryInterface(IID_IInternetBindInfo) failed: %08x\n", hres);
 
+    hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetProtocolSink, (void**)&sink);
+    ok(hres == S_OK, "Could not get IInternetProtocolSink: %08x\n", hres);
+
     hres = IInternetProtocol_Start(protocol, test_url, NULL, &bind_info, 0, 0);
     ok(hres == E_INVALIDARG, "Start failed: %08x, expected E_INVALIDARG\n", hres);
     hres = IInternetProtocol_Start(protocol, test_url, &protocol_sink, NULL, 0, 0);
@@ -1472,6 +1759,7 @@ static void test_CreateBinding(void)
     ok(hres == S_OK, "GetPriority failed: %08x\n", hres);
     ok(!p, "p=%d\n", p);
 
+    ex_priority = 100;
     hres = IInternetPriority_SetPriority(priority, 100);
     ok(hres == S_OK, "SetPriority failed: %08x\n", hres);
 
@@ -1523,24 +1811,126 @@ static void test_CreateBinding(void)
     ok(hres == S_OK, "Terminate failed: %08x\n", hres);
     CHECK_CALLED(Terminate);
 
+    SET_EXPECT(Continue);
+    hres = IInternetProtocolSink_Switch(sink, &protocoldata);
+    ok(hres == S_OK, "Switch failed: %08x\n", hres);
+    CHECK_CALLED(Continue);
+
+    hres = IInternetProtocolSink_ReportProgress(sink,
+            BINDSTATUS_CACHEFILENAMEAVAILABLE, expect_wsz = emptyW);
+    ok(hres == S_OK, "ReportProgress(BINDSTATUS_CACHEFILENAMEAVAILABLE) failed: %08x\n", hres);
+
+    hres = IInternetProtocolSink_ReportResult(sink, S_OK, ERROR_SUCCESS, NULL);
+    ok(hres == E_FAIL, "ReportResult failed: %08x, expected E_FAIL\n", hres);
+
+    hres = IInternetProtocolSink_ReportData(sink, 0, 0, 0);
+    ok(hres == S_OK, "ReportData failed: %08x\n", hres);
+
+    IInternetProtocolSink_Release(sink);
     IInternetPriority_Release(priority);
     IInternetBindInfo_Release(prot_bind_info);
     IInternetProtocol_Release(protocol);
     IInternetSession_Release(session);
 }
 
+static void test_binding(int prot)
+{
+    IInternetProtocol *protocol;
+    IInternetSession *session;
+    ULONG ref;
+    HRESULT hres;
+
+    trace("Testing %s binding...\n", debugstr_w(protocol_names[prot]));
+
+    tested_protocol = prot;
+    binding_test = TRUE;
+    first_data_notif = TRUE;
+    prot_read = 0;
+
+    hres = CoInternetGetSession(0, &session, 0);
+    ok(hres == S_OK, "CoInternetGetSession failed: %08x\n", hres);
+
+    hres = IInternetSession_RegisterNameSpace(session, &ClassFactory, &IID_NULL, protocol_names[prot], 0, NULL, 0);
+    ok(hres == S_OK, "RegisterNameSpace failed: %08x\n", hres);
+
+    hres = IInternetSession_CreateBinding(session, NULL, binding_urls[prot], NULL, NULL, &protocol, 0);
+    binding_protocol = protocol;
+    IInternetSession_Release(session);
+    ok(hres == S_OK, "CreateBinding failed: %08x\n", hres);
+    ok(protocol != NULL, "protocol == NULL\n");
+
+    hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetBindInfo, (void**)&prot_bind_info);
+    ok(hres == S_OK, "QueryInterface(IID_IInternetBindInfo) failed: %08x\n", hres);
+
+    hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetProtocolSink, (void**)&binding_sink);
+    ok(hres == S_OK, "QueryInterface(IID_IInternetProtocolSink) failed: %08x\n", hres);
+
+    ex_priority = 0;
+    SET_EXPECT(QueryService_InternetProtocol);
+    SET_EXPECT(CreateInstance);
+    SET_EXPECT(ReportProgress_PROTOCOLCLASSID);
+    SET_EXPECT(SetPriority);
+    SET_EXPECT(Start);
+
+    expect_hrResult = S_OK;
+    hres = IInternetProtocol_Start(protocol, binding_urls[prot], &protocol_sink, &bind_info, 0, 0);
+    ok(hres == S_OK, "Start failed: %08x\n", hres);
+
+    CHECK_CALLED(QueryService_InternetProtocol);
+    CHECK_CALLED(CreateInstance);
+    CHECK_CALLED(ReportProgress_PROTOCOLCLASSID);
+    CHECK_CALLED(SetPriority);
+    CHECK_CALLED(Start);
+
+    if(prot == HTTP_TEST) {
+        while(prot_state < 4) {
+            WaitForSingleObject(event_complete, INFINITE);
+            SET_EXPECT(Continue);
+            IInternetProtocol_Continue(protocol, pdata);
+            CHECK_CALLED(Continue);
+            SetEvent(event_complete2);
+        }
+
+        WaitForSingleObject(event_complete, INFINITE);
+    }else {
+        SET_EXPECT(LockRequest);
+        hres = IInternetProtocol_LockRequest(protocol, 0);
+        ok(hres == S_OK, "LockRequest failed: %08x\n", hres);
+        CHECK_CALLED(LockRequest);
+
+        SET_EXPECT(UnlockRequest);
+        hres = IInternetProtocol_UnlockRequest(protocol);
+        ok(hres == S_OK, "UnlockRequest failed: %08x\n", hres);
+        CHECK_CALLED(UnlockRequest);
+    }
+
+    SET_EXPECT(Terminate);
+    hres = IInternetProtocol_Terminate(protocol, 0);
+    ok(hres == S_OK, "Terminate failed: %08x\n", hres);
+    CHECK_CALLED(Terminate);
+
+    IInternetBindInfo_Release(prot_bind_info);
+    IInternetProtocolSink_Release(binding_sink);
+    ref = IInternetProtocol_Release(protocol);
+    ok(!ref, "ref=%u, expected 0\n", ref);
+}
+
 START_TEST(protocol)
 {
     OleInitialize(NULL);
 
     event_complete = CreateEvent(NULL, FALSE, FALSE, NULL);
+    event_complete2 = CreateEvent(NULL, FALSE, FALSE, NULL);
 
     test_file_protocol();
     test_http_protocol();
     test_mk_protocol();
     test_CreateBinding();
+    test_binding(FILE_TEST);
+    test_binding(HTTP_TEST);
 
     CloseHandle(event_complete);
+    CloseHandle(event_complete2);
 
     OleUninitialize();
 }
index cd8432d..8ac533a 100644 (file)
 #define SET_EXPECT(func) \
     expect_ ## func = TRUE
 
-#define CHECK_EXPECT(func) \
+#define CHECK_EXPECT2(func) \
     do { \
         ok(expect_ ##func, "unexpected call " #func "\n"); \
-        expect_ ## func = FALSE; \
         called_ ## func = TRUE; \
     }while(0)
 
-#define CHECK_EXPECT2(func) \
+#define CHECK_EXPECT(func) \
     do { \
-        ok(expect_ ##func, "unexpected call " #func "\n"); \
-        called_ ## func = TRUE; \
+        CHECK_EXPECT2(func); \
+        expect_ ## func = FALSE; \
     }while(0)
 
 #define CHECK_CALLED(func) \
@@ -90,18 +89,31 @@ DEFINE_EXPECT(OnProgress_MIMETYPEAVAILABLE);
 DEFINE_EXPECT(OnProgress_BEGINDOWNLOADDATA);
 DEFINE_EXPECT(OnProgress_DOWNLOADINGDATA);
 DEFINE_EXPECT(OnProgress_ENDDOWNLOADDATA);
-DEFINE_EXPECT(OnProgress_CLASSIDAVAILABLE);
-DEFINE_EXPECT(OnProgress_BEGINSYNCOPERATION);
-DEFINE_EXPECT(OnProgress_ENDSYNCOPERATION);
 DEFINE_EXPECT(OnStopBinding);
 DEFINE_EXPECT(OnDataAvailable);
 DEFINE_EXPECT(OnObjectAvailable);
+DEFINE_EXPECT(Obj_OnStartBinding);
+DEFINE_EXPECT(Obj_OnStopBinding);
+DEFINE_EXPECT(Obj_GetBindInfo);
+DEFINE_EXPECT(Obj_OnProgress_BEGINDOWNLOADDATA);
+DEFINE_EXPECT(Obj_OnProgress_ENDDOWNLOADDATA);
+DEFINE_EXPECT(Obj_OnProgress_SENDINGREQUEST);
+DEFINE_EXPECT(Obj_OnProgress_MIMETYPEAVAILABLE);
+DEFINE_EXPECT(Obj_OnProgress_CLASSIDAVAILABLE);
+DEFINE_EXPECT(Obj_OnProgress_BEGINSYNCOPERATION);
+DEFINE_EXPECT(Obj_OnProgress_ENDSYNCOPERATION);
+DEFINE_EXPECT(Obj_OnProgress_FINDINGRESOURCE);
+DEFINE_EXPECT(Obj_OnProgress_CONNECTING);
 DEFINE_EXPECT(Start);
 DEFINE_EXPECT(Read);
 DEFINE_EXPECT(LockRequest);
 DEFINE_EXPECT(Terminate);
 DEFINE_EXPECT(UnlockRequest);
 DEFINE_EXPECT(Continue);
+DEFINE_EXPECT(CreateInstance);
+DEFINE_EXPECT(Load);
+DEFINE_EXPECT(PutProperty_MIMETYPEPROP);
+DEFINE_EXPECT(PutProperty_CLASSIDPROP);
 
 static const WCHAR TEST_URL_1[] = {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g','/','\0'};
 static const WCHAR TEST_PART_URL_1[] = {'/','t','e','s','t','/','\0'};
@@ -128,13 +140,15 @@ static const WCHAR wszWineHQSite[] =
 static const WCHAR wszWineHQIP[] =
     {'2','0','9','.','3','2','.','1','4','1','.','3',0};
 static const WCHAR wszIndexHtml[] = {'i','n','d','e','x','.','h','t','m','l',0};
+static const WCHAR emptyW[] = {0};
 
-static BOOL stopped_binding = FALSE, emulate_protocol = FALSE,
-    data_available = FALSE, http_is_first = TRUE;
+static BOOL stopped_binding = FALSE, stopped_obj_binding = FALSE, emulate_protocol = FALSE,
+    data_available = FALSE, http_is_first = TRUE, bind_to_object = FALSE;
 static DWORD read = 0, bindf = 0, prot_state = 0, thread_id;
 static CHAR mime_type[512];
 static IInternetProtocolSink *protocol_sink = NULL;
 static HANDLE complete_event, complete_event2;
+static HRESULT binding_hres;
 
 extern IID IID_IBindStatusCallbackHolder;
 
@@ -160,6 +174,13 @@ static enum {
     END_DOWNLOAD
 } download_state;
 
+static const char *debugstr_w(LPCWSTR str)
+{
+    static char buf[1024];
+    WideCharToMultiByte(CP_ACP, 0, str, -1, buf, sizeof(buf), NULL, NULL);
+    return buf;
+}
+
 static const char *debugstr_guid(REFIID riid)
 {
     static char buf[50];
@@ -219,38 +240,71 @@ static DWORD WINAPI thread_proc(PVOID arg)
     PROTOCOLDATA protocoldata;
     HRESULT hres;
 
-    SET_EXPECT(OnProgress_FINDINGRESOURCE);
+    if(bind_to_object)
+        SET_EXPECT(Obj_OnProgress_FINDINGRESOURCE);
+    else
+        SET_EXPECT(OnProgress_FINDINGRESOURCE);
     hres = IInternetProtocolSink_ReportProgress(protocol_sink,
             BINDSTATUS_FINDINGRESOURCE, wszWineHQSite);
     ok(hres == S_OK, "ReportProgress failed: %08x\n", hres);
     WaitForSingleObject(complete_event, INFINITE);
-    CHECK_CALLED(OnProgress_FINDINGRESOURCE);
+    if(bind_to_object)
+        CHECK_CALLED(Obj_OnProgress_FINDINGRESOURCE);
+    else
+        CHECK_CALLED(OnProgress_FINDINGRESOURCE);
 
-    SET_EXPECT(OnProgress_CONNECTING);
+    if(bind_to_object)
+        SET_EXPECT(Obj_OnProgress_CONNECTING);
+    else
+        SET_EXPECT(OnProgress_CONNECTING);
     hres = IInternetProtocolSink_ReportProgress(protocol_sink,
             BINDSTATUS_CONNECTING, wszWineHQIP);
     ok(hres == S_OK, "ReportProgress failed: %08x\n", hres);
     WaitForSingleObject(complete_event, INFINITE);
-    CHECK_CALLED(OnProgress_CONNECTING);
+    if(bind_to_object)
+        CHECK_CALLED(Obj_OnProgress_CONNECTING);
+    else
+        CHECK_CALLED(OnProgress_CONNECTING);
 
-    SET_EXPECT(OnProgress_SENDINGREQUEST);
+    if(bind_to_object)
+        SET_EXPECT(Obj_OnProgress_SENDINGREQUEST);
+    else
+        SET_EXPECT(OnProgress_SENDINGREQUEST);
     hres = IInternetProtocolSink_ReportProgress(protocol_sink,
             BINDSTATUS_SENDINGREQUEST, NULL);
-    ok(hres == S_OK, "ReportProgress failed: %08x\n", hres);
+    ok(hres == S_OK, "ReportProxgress failed: %08x\n", hres);
     WaitForSingleObject(complete_event, INFINITE);
-    CHECK_CALLED(OnProgress_SENDINGREQUEST);
+    if(bind_to_object)
+        CHECK_CALLED(Obj_OnProgress_SENDINGREQUEST);
+    else
+        CHECK_CALLED(OnProgress_SENDINGREQUEST);
 
     SET_EXPECT(Continue);
     prot_state = 1;
     hres = IInternetProtocolSink_Switch(protocol_sink, &protocoldata);
     ok(hres == S_OK, "Switch failed: %08x\n", hres);
     WaitForSingleObject(complete_event, INFINITE);
+
     CHECK_CALLED(Continue);
     CHECK_CALLED(Read);
-    CHECK_CALLED(OnProgress_MIMETYPEAVAILABLE);
-    CHECK_CALLED(OnProgress_BEGINDOWNLOADDATA);
-    CHECK_CALLED(LockRequest);
-    CHECK_CALLED(OnDataAvailable);
+    if(bind_to_object) {
+        CHECK_CALLED(Obj_OnProgress_MIMETYPEAVAILABLE);
+        CHECK_CALLED(Obj_OnProgress_BEGINDOWNLOADDATA);
+        CHECK_CALLED(Obj_OnProgress_CLASSIDAVAILABLE);
+        CHECK_CALLED(Obj_OnProgress_BEGINSYNCOPERATION);
+        CHECK_CALLED(CreateInstance);
+        CHECK_CALLED(PutProperty_MIMETYPEPROP);
+        CLEAR_CALLED(PutProperty_CLASSIDPROP);
+        CHECK_CALLED(Load);
+        CHECK_CALLED(Obj_OnProgress_ENDSYNCOPERATION);
+        CHECK_CALLED(OnObjectAvailable);
+        CHECK_CALLED(Obj_OnStopBinding);
+    }else {
+        CHECK_CALLED(OnProgress_MIMETYPEAVAILABLE);
+        CHECK_CALLED(OnProgress_BEGINDOWNLOADDATA);
+        CHECK_CALLED(LockRequest);
+        CHECK_CALLED(OnDataAvailable);
+    }
 
     SET_EXPECT(Continue);
     prot_state = 2;
@@ -292,11 +346,13 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
         IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
         DWORD grfPI, DWORD dwReserved)
 {
-    BINDINFO bindinfo, bi = {sizeof(bi), 0};
+    BINDINFO bindinfo;
     DWORD bindf, bscf = BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION;
-    WCHAR null_char = 0;
     HRESULT hres;
 
+    static const STGMEDIUM stgmed_zero = {0};
+    static const SECURITY_ATTRIBUTES sa_zero = {0};
+
     CHECK_EXPECT(Start);
 
     read = 0;
@@ -307,6 +363,17 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
     ok(grfPI == 0, "grfPI=%d, expected 0\n", grfPI);
     ok(dwReserved == 0, "dwReserved=%d, expected 0\n", dwReserved);
 
+    if(binding_hres != S_OK) {
+        SET_EXPECT(OnStopBinding);
+        SET_EXPECT(Terminate);
+        hres = IInternetProtocolSink_ReportResult(pOIProtSink, binding_hres, 0, NULL);
+        ok(hres == S_OK, "ReportResult failed: %08x\n", hres);
+        CHECK_CALLED(OnStopBinding);
+        CHECK_CALLED(Terminate);
+
+        return S_OK;
+    }
+
     memset(&bindinfo, 0, sizeof(bindinfo));
     bindinfo.cbSize = sizeof(bindinfo);
     hres = IInternetBindInfo_GetBindInfo(pOIBindInfo, &bindf, &bindinfo);
@@ -322,7 +389,20 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
            "bindf=%08x\n", bindf);
     }
 
-    ok(!memcmp(&bindinfo, &bi, sizeof(bindinfo)), "wrong bindinfo\n");
+    ok(bindinfo.cbSize == sizeof(bindinfo), "bindinfo.cbSize = %d\n", bindinfo.cbSize);
+    ok(!bindinfo.szExtraInfo, "bindinfo.szExtraInfo = %p\n", bindinfo.szExtraInfo);
+    ok(!memcmp(&bindinfo.stgmedData, &stgmed_zero, sizeof(STGMEDIUM)), "wrong stgmedData\n");
+    ok(!bindinfo.grfBindInfoF, "bindinfo.grfBindInfoF = %d\n", bindinfo.grfBindInfoF);
+    ok(!bindinfo.dwBindVerb, "bindinfo.dwBindVerb = %d\n", bindinfo.dwBindVerb);
+    ok(!bindinfo.szCustomVerb, "bindinfo.szCustomVerb = %p\n", bindinfo.szCustomVerb);
+    ok(!bindinfo.cbstgmedData, "bindinfo.cbstgmedData = %d\n", bindinfo.cbstgmedData);
+    ok(bindinfo.dwOptions == (bind_to_object ? 0x100000 : 0), "bindinfo.dwOptions = %x\n", bindinfo.dwOptions);
+    ok(!bindinfo.dwOptionsFlags, "bindinfo.dwOptionsFlags = %d\n", bindinfo.dwOptionsFlags);
+    ok(!bindinfo.dwCodePage, "bindinfo.dwCodePage = %d\n", bindinfo.dwCodePage);
+    ok(!memcmp(&bindinfo.securityAttributes, &sa_zero, sizeof(sa_zero)), "wrong bindinfo.securityAttributes\n");
+    ok(IsEqualGUID(&bindinfo.iid, &IID_NULL), "wrong bindinfo.iid\n");
+    ok(!bindinfo.pUnk, "bindinfo.pUnk = %p\n", bindinfo.pUnk);
+    ok(!bindinfo.dwReserved, "bindinfo.dwReserved = %d\n", bindinfo.dwReserved);
 
     switch(test_protocol) {
     case MK_TEST:
@@ -333,12 +413,18 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
 
     case FILE_TEST:
     case ITS_TEST:
-        SET_EXPECT(OnProgress_SENDINGREQUEST);
+        if(bind_to_object)
+            SET_EXPECT(Obj_OnProgress_SENDINGREQUEST);
+        else
+            SET_EXPECT(OnProgress_SENDINGREQUEST);
         hres = IInternetProtocolSink_ReportProgress(pOIProtSink,
-                BINDSTATUS_SENDINGREQUEST, &null_char);
+                BINDSTATUS_SENDINGREQUEST, emptyW);
         ok(hres == S_OK,
            "ReportProgress(BINDSTATUS_SENDINGREQUEST) failed: %08x\n", hres);
-        CHECK_CALLED(OnProgress_SENDINGREQUEST);
+        if(bind_to_object)
+            CHECK_CALLED(Obj_OnProgress_SENDINGREQUEST);
+        else
+            CHECK_CALLED(OnProgress_SENDINGREQUEST);
     default:
         break;
     }
@@ -427,16 +513,22 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
 
     if(test_protocol == FILE_TEST) {
         hres = IInternetProtocolSink_ReportProgress(pOIProtSink,
-                BINDSTATUS_CACHEFILENAMEAVAILABLE, &null_char);
+                BINDSTATUS_CACHEFILENAMEAVAILABLE, emptyW);
         ok(hres == S_OK,
            "ReportProgress(BINDSTATUS_CACHEFILENAMEAVAILABLE) failed: %08x\n", hres);
 
-        SET_EXPECT(OnProgress_MIMETYPEAVAILABLE);
+        if(bind_to_object)
+            SET_EXPECT(Obj_OnProgress_MIMETYPEAVAILABLE);
+        else
+            SET_EXPECT(OnProgress_MIMETYPEAVAILABLE);
         hres = IInternetProtocolSink_ReportProgress(pOIProtSink,
                 BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE, wszTextHtml);
         ok(hres == S_OK,
            "ReportProgress(BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE) failed: %08x\n", hres);
-        CHECK_CALLED(OnProgress_MIMETYPEAVAILABLE);
+        if(bind_to_object)
+            CHECK_CALLED(Obj_OnProgress_MIMETYPEAVAILABLE);
+        else
+            CHECK_CALLED(OnProgress_MIMETYPEAVAILABLE);
     }else {
         hres = IInternetProtocolSink_ReportProgress(pOIProtSink,
                 BINDSTATUS_MIMETYPEAVAILABLE, wszTextHtml);
@@ -450,25 +542,57 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
         bscf = BSCF_FIRSTDATANOTIFICATION|BSCF_DATAFULLYAVAILABLE;
 
     SET_EXPECT(Read);
-    if(test_protocol != FILE_TEST && test_protocol != MK_TEST)
-        SET_EXPECT(OnProgress_MIMETYPEAVAILABLE);
-    SET_EXPECT(OnProgress_BEGINDOWNLOADDATA);
-    SET_EXPECT(OnProgress_ENDDOWNLOADDATA);
-    SET_EXPECT(LockRequest);
-    SET_EXPECT(OnDataAvailable);
-    SET_EXPECT(OnStopBinding);
+    if(bind_to_object) {
+        if(test_protocol != FILE_TEST && test_protocol != MK_TEST)
+            SET_EXPECT(Obj_OnProgress_MIMETYPEAVAILABLE);
+        SET_EXPECT(Obj_OnProgress_BEGINDOWNLOADDATA);
+        SET_EXPECT(Obj_OnProgress_ENDDOWNLOADDATA);
+        SET_EXPECT(Obj_OnProgress_CLASSIDAVAILABLE);
+        SET_EXPECT(Obj_OnProgress_BEGINSYNCOPERATION);
+        SET_EXPECT(CreateInstance);
+        SET_EXPECT(PutProperty_MIMETYPEPROP);
+        SET_EXPECT(PutProperty_CLASSIDPROP);
+        SET_EXPECT(Load);
+        SET_EXPECT(Obj_OnProgress_ENDSYNCOPERATION);
+        SET_EXPECT(OnObjectAvailable);
+        SET_EXPECT(Obj_OnStopBinding);
+    }else {
+        if(test_protocol != FILE_TEST && test_protocol != MK_TEST)
+            SET_EXPECT(OnProgress_MIMETYPEAVAILABLE);
+        SET_EXPECT(OnProgress_BEGINDOWNLOADDATA);
+        SET_EXPECT(OnProgress_ENDDOWNLOADDATA);
+        SET_EXPECT(LockRequest);
+        SET_EXPECT(OnDataAvailable);
+        SET_EXPECT(OnStopBinding);
+    }
 
     hres = IInternetProtocolSink_ReportData(pOIProtSink, bscf, 13, 13);
     ok(hres == S_OK, "ReportData failed: %08x\n", hres);
 
     CHECK_CALLED(Read);
-    if(test_protocol != FILE_TEST && test_protocol != MK_TEST)
-        CHECK_CALLED(OnProgress_MIMETYPEAVAILABLE);
-    CHECK_CALLED(OnProgress_BEGINDOWNLOADDATA);
-    CHECK_CALLED(OnProgress_ENDDOWNLOADDATA);
-    CHECK_CALLED(LockRequest);
-    CHECK_CALLED(OnDataAvailable);
-    CHECK_CALLED(OnStopBinding);
+    if(bind_to_object) {
+        if(test_protocol != FILE_TEST && test_protocol != MK_TEST)
+            CHECK_CALLED(Obj_OnProgress_MIMETYPEAVAILABLE);
+        CHECK_CALLED(Obj_OnProgress_BEGINDOWNLOADDATA);
+        CHECK_CALLED(Obj_OnProgress_ENDDOWNLOADDATA);
+        CHECK_CALLED(Obj_OnProgress_CLASSIDAVAILABLE);
+        CHECK_CALLED(Obj_OnProgress_BEGINSYNCOPERATION);
+        CHECK_CALLED(CreateInstance);
+        CHECK_CALLED(PutProperty_MIMETYPEPROP);
+        CLEAR_CALLED(PutProperty_CLASSIDPROP);
+        CHECK_CALLED(Load);
+        CHECK_CALLED(Obj_OnProgress_ENDSYNCOPERATION);
+        CHECK_CALLED(OnObjectAvailable);
+        CHECK_CALLED(Obj_OnStopBinding);
+    }else {
+        if(test_protocol != FILE_TEST && test_protocol != MK_TEST)
+            CHECK_CALLED(OnProgress_MIMETYPEAVAILABLE);
+        CHECK_CALLED(OnProgress_BEGINDOWNLOADDATA);
+        CHECK_CALLED(OnProgress_ENDDOWNLOADDATA);
+        CHECK_CALLED(LockRequest);
+        CHECK_CALLED(OnDataAvailable);
+        CHECK_CALLED(OnStopBinding);
+    }
 
     if(test_protocol == ITS_TEST) {
         SET_EXPECT(Read);
@@ -539,9 +663,23 @@ static HRESULT WINAPI Protocol_Continue(IInternetProtocol *iface,
     SET_EXPECT(Read);
     switch(prot_state) {
     case 1:
-        SET_EXPECT(OnProgress_MIMETYPEAVAILABLE);
-        SET_EXPECT(OnProgress_BEGINDOWNLOADDATA);
-        SET_EXPECT(LockRequest);
+        if(bind_to_object) {
+            SET_EXPECT(Obj_OnProgress_MIMETYPEAVAILABLE);
+            SET_EXPECT(Obj_OnProgress_BEGINDOWNLOADDATA);
+            SET_EXPECT(Obj_OnProgress_CLASSIDAVAILABLE);
+            SET_EXPECT(Obj_OnProgress_BEGINSYNCOPERATION);
+            SET_EXPECT(CreateInstance);
+            SET_EXPECT(PutProperty_MIMETYPEPROP);
+            SET_EXPECT(PutProperty_CLASSIDPROP);
+            SET_EXPECT(Load);
+            SET_EXPECT(Obj_OnProgress_ENDSYNCOPERATION);
+            SET_EXPECT(OnObjectAvailable);
+            SET_EXPECT(Obj_OnStopBinding);
+        }else {
+            SET_EXPECT(OnProgress_MIMETYPEAVAILABLE);
+            SET_EXPECT(OnProgress_BEGINDOWNLOADDATA);
+            SET_EXPECT(LockRequest);
+        }
         break;
     case 2:
         SET_EXPECT(OnProgress_DOWNLOADINGDATA);
@@ -550,7 +688,8 @@ static HRESULT WINAPI Protocol_Continue(IInternetProtocol *iface,
         SET_EXPECT(OnProgress_DOWNLOADINGDATA);
         SET_EXPECT(OnProgress_ENDDOWNLOADDATA);
     }
-    SET_EXPECT(OnDataAvailable);
+    if(!bind_to_object || prot_state >= 2)
+        SET_EXPECT(OnDataAvailable);
     if(prot_state == 3)
         SET_EXPECT(OnStopBinding);
 
@@ -833,6 +972,8 @@ static IServiceProviderVtbl ServiceProviderVtbl = {
 
 static IServiceProvider ServiceProvider = { &ServiceProviderVtbl };
 
+static IBindStatusCallback objbsc;
+
 static HRESULT WINAPI statusclb_QueryInterface(IBindStatusCallback *iface, REFIID riid, void **ppv)
 {
     ok(GetCurrentThreadId() == thread_id, "wrong thread %d\n", GetCurrentThreadId());
@@ -906,10 +1047,14 @@ static ULONG WINAPI statusclb_Release(IBindStatusCallback *iface)
 static HRESULT WINAPI statusclb_OnStartBinding(IBindStatusCallback *iface, DWORD dwReserved,
         IBinding *pib)
 {
+    IWinInetHttpInfo *http_info;
     HRESULT hres;
     IMoniker *mon;
 
-    CHECK_EXPECT(OnStartBinding);
+    if(iface == &objbsc)
+        CHECK_EXPECT(Obj_OnStartBinding);
+    else
+        CHECK_EXPECT(OnStartBinding);
 
     ok(GetCurrentThreadId() == thread_id, "wrong thread %d\n", GetCurrentThreadId());
 
@@ -924,6 +1069,9 @@ static HRESULT WINAPI statusclb_OnStartBinding(IBindStatusCallback *iface, DWORD
     if(SUCCEEDED(hres))
         IMoniker_Release(mon);
 
+    hres = IBinding_QueryInterface(pib, &IID_IWinInetHttpInfo, (void**)&http_info);
+    ok(hres == E_NOINTERFACE, "Could not get IID_IWinInetHttpInfo: %08x\n", hres);
+
     return S_OK;
 }
 
@@ -946,42 +1094,64 @@ static HRESULT WINAPI statusclb_OnProgress(IBindStatusCallback *iface, ULONG ulP
 
     switch(ulStatusCode) {
     case BINDSTATUS_FINDINGRESOURCE:
-        CHECK_EXPECT(OnProgress_FINDINGRESOURCE);
+        if(iface == &objbsc)
+            CHECK_EXPECT(Obj_OnProgress_FINDINGRESOURCE);
+        else
+            CHECK_EXPECT(OnProgress_FINDINGRESOURCE);
         if((bindf & BINDF_ASYNCHRONOUS) && emulate_protocol)
             SetEvent(complete_event);
         break;
     case BINDSTATUS_CONNECTING:
-        CHECK_EXPECT(OnProgress_CONNECTING);
+        if(iface == &objbsc)
+            CHECK_EXPECT(Obj_OnProgress_CONNECTING);
+        else
+            CHECK_EXPECT(OnProgress_CONNECTING);
         if((bindf & BINDF_ASYNCHRONOUS) && emulate_protocol)
             SetEvent(complete_event);
         break;
     case BINDSTATUS_SENDINGREQUEST:
-        CHECK_EXPECT(OnProgress_SENDINGREQUEST);
+        if(iface == &objbsc)
+            CHECK_EXPECT(Obj_OnProgress_SENDINGREQUEST);
+        else
+            CHECK_EXPECT(OnProgress_SENDINGREQUEST);
         if((bindf & BINDF_ASYNCHRONOUS) && emulate_protocol)
             SetEvent(complete_event);
         break;
     case BINDSTATUS_MIMETYPEAVAILABLE:
-        CHECK_EXPECT(OnProgress_MIMETYPEAVAILABLE);
-        ok(download_state == BEFORE_DOWNLOAD, "Download state was %d, expected BEFORE_DOWNLOAD\n",
-           download_state);
+        if(iface == &objbsc)
+            CHECK_EXPECT(Obj_OnProgress_MIMETYPEAVAILABLE);
+        else
+            CHECK_EXPECT(OnProgress_MIMETYPEAVAILABLE);
+        if(!bind_to_object)
+            ok(download_state == BEFORE_DOWNLOAD, "Download state was %d, expected BEFORE_DOWNLOAD\n",
+               download_state);
         WideCharToMultiByte(CP_ACP, 0, szStatusText, -1, mime_type, sizeof(mime_type)-1, NULL, NULL);
         break;
     case BINDSTATUS_BEGINDOWNLOADDATA:
-        CHECK_EXPECT(OnProgress_BEGINDOWNLOADDATA);
+        if(iface == &objbsc)
+            CHECK_EXPECT(Obj_OnProgress_BEGINDOWNLOADDATA);
+        else
+            CHECK_EXPECT(OnProgress_BEGINDOWNLOADDATA);
         ok(szStatusText != NULL, "szStatusText == NULL\n");
         if(szStatusText)
             ok(!lstrcmpW(szStatusText, urls[test_protocol]), "wrong szStatusText\n");
-        ok(download_state == BEFORE_DOWNLOAD, "Download state was %d, expected BEFORE_DOWNLOAD\n",
-           download_state);
+        if(!bind_to_object)
+            ok(download_state == BEFORE_DOWNLOAD, "Download state was %d, expected BEFORE_DOWNLOAD\n",
+               download_state);
         download_state = DOWNLOADING;
         break;
     case BINDSTATUS_DOWNLOADINGDATA:
         CHECK_EXPECT2(OnProgress_DOWNLOADINGDATA);
+        if(iface == &objbsc)
+            todo_wine ok(0, "unexpected call\n");
         ok(download_state == DOWNLOADING, "Download state was %d, expected DOWNLOADING\n",
            download_state);
         break;
     case BINDSTATUS_ENDDOWNLOADDATA:
-        CHECK_EXPECT(OnProgress_ENDDOWNLOADDATA);
+        if(iface == &objbsc)
+            CHECK_EXPECT(Obj_OnProgress_ENDDOWNLOADDATA);
+        else
+            CHECK_EXPECT(OnProgress_ENDDOWNLOADDATA);
         ok(szStatusText != NULL, "szStatusText == NULL\n");
         if(szStatusText)
             ok(!lstrcmpW(szStatusText, urls[test_protocol]), "wrong szStatusText\n");
@@ -998,22 +1168,28 @@ static HRESULT WINAPI statusclb_OnProgress(IBindStatusCallback *iface, ULONG ulP
     {
         CLSID clsid;
         HRESULT hr;
-        CHECK_EXPECT(OnProgress_CLASSIDAVAILABLE);
+        if(iface != &objbsc)
+            ok(0, "unexpected call\n");
+        else if(1||emulate_protocol)
+            CHECK_EXPECT(Obj_OnProgress_CLASSIDAVAILABLE);
+        else
+            todo_wine CHECK_EXPECT(Obj_OnProgress_CLASSIDAVAILABLE);
         hr = CLSIDFromString((LPOLESTR)szStatusText, &clsid);
         ok(hr == S_OK, "CLSIDFromString failed with error 0x%08x\n", hr);
         ok(IsEqualCLSID(&clsid, &CLSID_HTMLDocument),
-            "Expected clsid to be CLSID_HTMLDocument instead of {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n",
-            clsid.Data1, clsid.Data2, clsid.Data3,
-            clsid.Data4[0], clsid.Data4[1], clsid.Data4[2], clsid.Data4[3],
-            clsid.Data4[4], clsid.Data4[5], clsid.Data4[6], clsid.Data4[7]);
+            "Expected clsid to be CLSID_HTMLDocument instead of %s\n", debugstr_guid(&clsid));
         break;
     }
     case BINDSTATUS_BEGINSYNCOPERATION:
-        CHECK_EXPECT(OnProgress_BEGINSYNCOPERATION);
+        CHECK_EXPECT(Obj_OnProgress_BEGINSYNCOPERATION);
+        if(iface != &objbsc)
+            ok(0, "unexpected call\n");
         ok(szStatusText == NULL, "Expected szStatusText to be NULL\n");
         break;
     case BINDSTATUS_ENDSYNCOPERATION:
-        CHECK_EXPECT(OnProgress_ENDSYNCOPERATION);
+        CHECK_EXPECT(Obj_OnProgress_ENDSYNCOPERATION);
+        if(iface != &objbsc)
+            ok(0, "unexpected call\n");
         ok(szStatusText == NULL, "Expected szStatusText to be NULL\n");
         break;
     default:
@@ -1024,22 +1200,27 @@ static HRESULT WINAPI statusclb_OnProgress(IBindStatusCallback *iface, ULONG ulP
 
 static HRESULT WINAPI statusclb_OnStopBinding(IBindStatusCallback *iface, HRESULT hresult, LPCWSTR szError)
 {
-    CHECK_EXPECT(OnStopBinding);
+    if(iface == &objbsc) {
+        CHECK_EXPECT(Obj_OnStopBinding);
+        stopped_obj_binding = TRUE;
+    }else {
+        CHECK_EXPECT(OnStopBinding);
+        stopped_binding = TRUE;
+    }
 
     ok(GetCurrentThreadId() == thread_id, "wrong thread %d\n", GetCurrentThreadId());
 
-    stopped_binding = TRUE;
-
     /* ignore DNS failure */
     if (hresult == HRESULT_FROM_WIN32(ERROR_INTERNET_NAME_NOT_RESOLVED))
         return S_OK;
 
-    ok(hresult == S_OK, "binding failed: %08x\n", hresult);
+    ok(hresult == binding_hres, "binding failed: %08x, expected %08x\n", hresult, binding_hres);
     ok(szError == NULL, "szError should be NULL\n");
 
     if(test_protocol == HTTP_TEST && emulate_protocol) {
         SetEvent(complete_event);
-        WaitForSingleObject(complete_event2, INFINITE);
+        if(iface != &objbsc)
+            WaitForSingleObject(complete_event2, INFINITE);
     }
 
     return S_OK;
@@ -1049,7 +1230,10 @@ static HRESULT WINAPI statusclb_GetBindInfo(IBindStatusCallback *iface, DWORD *g
 {
     DWORD cbSize;
 
-    CHECK_EXPECT(GetBindInfo);
+    if(iface == &objbsc)
+        CHECK_EXPECT(Obj_GetBindInfo);
+    else
+        CHECK_EXPECT(GetBindInfo);
 
     ok(GetCurrentThreadId() == thread_id, "wrong thread %d\n", GetCurrentThreadId());
 
@@ -1069,6 +1253,9 @@ static HRESULT WINAPI statusclb_OnDataAvailable(IBindStatusCallback *iface, DWOR
     BYTE buf[512];
     CHAR clipfmt[512];
 
+    if(iface == &objbsc)
+        ok(0, "unexpected call\n");
+
     CHECK_EXPECT2(OnDataAvailable);
 
     ok(GetCurrentThreadId() == thread_id, "wrong thread %d\n", GetCurrentThreadId());
@@ -1080,12 +1267,12 @@ static HRESULT WINAPI statusclb_OnDataAvailable(IBindStatusCallback *iface, DWOR
 
     ok(pformatetc != NULL, "pformatetx == NULL\n");
     if(pformatetc) {
-        if (mime_type[0]) todo_wine {
+        if (mime_type[0]) {
             clipfmt[0] = 0;
             ok(GetClipboardFormatName(pformatetc->cfFormat, clipfmt, sizeof(clipfmt)-1),
                "GetClipboardFormatName failed, error %d\n", GetLastError());
-            ok(!lstrcmp(clipfmt, mime_type), "clipformat != mime_type, \"%s\" != \"%s\"\n",
-               clipfmt, mime_type);
+            ok(!lstrcmp(clipfmt, mime_type), "clipformat %x != mime_type, \"%s\" != \"%s\"\n",
+               pformatetc->cfFormat, clipfmt, mime_type);
         } else {
             ok(pformatetc->cfFormat == 0, "clipformat=%x\n", pformatetc->cfFormat);
         }
@@ -1122,7 +1309,7 @@ static HRESULT WINAPI statusclb_OnDataAvailable(IBindStatusCallback *iface, DWOR
         ok(hres == S_FALSE || hres == E_PENDING, "IStream_Read returned %08x\n", hres);
     }
 
-    if(test_protocol == HTTP_TEST && emulate_protocol && prot_state < 4)
+    if(test_protocol == HTTP_TEST && emulate_protocol && prot_state < 4 && (!bind_to_object || prot_state > 1))
         SetEvent(complete_event);
 
     return S_OK;
@@ -1131,6 +1318,16 @@ static HRESULT WINAPI statusclb_OnDataAvailable(IBindStatusCallback *iface, DWOR
 static HRESULT WINAPI statusclb_OnObjectAvailable(IBindStatusCallback *iface, REFIID riid, IUnknown *punk)
 {
     CHECK_EXPECT(OnObjectAvailable);
+
+    if(iface != &objbsc)
+        ok(0, "unexpected call\n");
+
+    ok(IsEqualGUID(&IID_IUnknown, riid), "riid = %s\n", debugstr_guid(riid));
+    ok(punk != NULL, "punk == NULL\n");
+
+    if(0&&test_protocol == HTTP_TEST)
+        SetEvent(complete_event);
+
     return S_OK;
 }
 
@@ -1149,6 +1346,245 @@ static const IBindStatusCallbackVtbl BindStatusCallbackVtbl = {
 };
 
 static IBindStatusCallback bsc = { &BindStatusCallbackVtbl };
+static IBindStatusCallback objbsc = { &BindStatusCallbackVtbl };
+
+static HRESULT WINAPI MonikerProp_QueryInterface(IMonikerProp *iface, REFIID riid, void **ppv)
+{
+    *ppv = NULL;
+    ok(0, "unexpected riid %s\n", debugstr_guid(riid));
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI MonikerProp_AddRef(IMonikerProp *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI MonikerProp_Release(IMonikerProp *iface)
+{
+    return 1;
+}
+
+static HRESULT WINAPI MonikerProp_PutProperty(IMonikerProp *iface, MONIKERPROPERTY mkp, LPCWSTR val)
+{
+    switch(mkp) {
+    case MIMETYPEPROP:
+        CHECK_EXPECT(PutProperty_MIMETYPEPROP);
+        ok(!lstrcmpW(val, wszTextHtml), "val = %s\n", debugstr_w(val));
+        break;
+    case CLASSIDPROP:
+        CHECK_EXPECT(PutProperty_CLASSIDPROP);
+        break;
+    default:
+        break;
+    }
+
+    return S_OK;
+}
+
+static const IMonikerPropVtbl MonikerPropVtbl = {
+    MonikerProp_QueryInterface,
+    MonikerProp_AddRef,
+    MonikerProp_Release,
+    MonikerProp_PutProperty
+};
+
+static IMonikerProp MonikerProp = { &MonikerPropVtbl };
+
+static HRESULT WINAPI PersistMoniker_QueryInterface(IPersistMoniker *iface, REFIID riid, void **ppv)
+{
+    *ppv = NULL;
+
+    if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IPersistMoniker, riid))
+        *ppv = iface;
+    else if(IsEqualGUID(&IID_IMonikerProp, riid))
+        *ppv = &MonikerProp;
+
+    if(*ppv)
+        return S_OK;
+
+    ok(0, "unexpected riid %s\n", debugstr_guid(riid));
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI PersistMoniker_AddRef(IPersistMoniker *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI PersistMoniker_Release(IPersistMoniker *iface)
+{
+    return 1;
+}
+
+static HRESULT WINAPI PersistMoniker_GetClassID(IPersistMoniker *iface, CLSID *pClassID)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI PersistMoniker_IsDirty(IPersistMoniker *iface)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI PersistMoniker_Load(IPersistMoniker *iface, BOOL fFullyAvailable,
+                                          IMoniker *pimkName, LPBC pibc, DWORD grfMode)
+{
+    IUnknown *unk;
+    HRESULT hres;
+
+    static WCHAR cbinding_contextW[] =
+        {'C','B','i','n','d','i','n','g',' ','C','o','n','t','e','x','t',0};
+
+    CHECK_EXPECT(Load);
+    ok(GetCurrentThreadId() == thread_id, "wrong thread %d\n", GetCurrentThreadId());
+
+    trace("LOAD %p\n", pibc);
+
+    if(test_protocol == HTTP_TEST)
+        ok(!fFullyAvailable, "fFulyAvailable = %x\n", fFullyAvailable);
+    else
+        ok(fFullyAvailable, "fFulyAvailable = %x\n", fFullyAvailable);
+    ok(pimkName != NULL, "pimkName == NULL\n");
+    ok(pibc != NULL, "pibc == NULL\n");
+    ok(grfMode == 0x12, "grfMode = %x\n", grfMode);
+
+    hres = IBindCtx_GetObjectParam(pibc, cbinding_contextW, &unk);
+    ok(hres == S_OK, "GetObjectParam(CBinding Context) failed: %08x\n", hres);
+    if(SUCCEEDED(hres)) {
+        IBinding *binding;
+
+        hres = IUnknown_QueryInterface(unk, &IID_IBinding, (void**)&binding);
+        ok(hres == S_OK, "Could not get IBinding: %08x\n", hres);
+
+        IBinding_Release(binding);
+        IUnknown_Release(unk);
+    }
+
+    SET_EXPECT(QueryInterface_IServiceProvider);
+    hres = RegisterBindStatusCallback(pibc, &bsc, NULL, 0);
+    ok(hres == S_OK, "RegisterBindStatusCallback failed: %08x\n", hres);
+    CHECK_CALLED(QueryInterface_IServiceProvider);
+
+    SET_EXPECT(GetBindInfo);
+    SET_EXPECT(OnStartBinding);
+    if(test_protocol == FILE_TEST)
+        SET_EXPECT(OnProgress_MIMETYPEAVAILABLE);
+    SET_EXPECT(OnProgress_BEGINDOWNLOADDATA);
+    if(test_protocol != HTTP_TEST)
+        SET_EXPECT(OnProgress_ENDDOWNLOADDATA);
+    SET_EXPECT(LockRequest);
+    SET_EXPECT(OnDataAvailable);
+    if(test_protocol != HTTP_TEST)
+        SET_EXPECT(OnStopBinding);
+
+    hres = IMoniker_BindToStorage(pimkName, pibc, NULL, &IID_IStream, (void**)&unk);
+    ok(hres == S_OK, "Load failed: %08x\n", hres);
+
+    CHECK_CALLED(GetBindInfo);
+    CHECK_CALLED(OnStartBinding);
+    if(test_protocol == FILE_TEST)
+        todo_wine CHECK_CALLED(OnProgress_MIMETYPEAVAILABLE);
+    CHECK_CALLED(OnProgress_BEGINDOWNLOADDATA);
+    if(test_protocol != HTTP_TEST)
+        CHECK_CALLED(OnProgress_ENDDOWNLOADDATA);
+    CHECK_CALLED(LockRequest);
+    CHECK_CALLED(OnDataAvailable);
+    if(test_protocol != HTTP_TEST)
+        CHECK_CALLED(OnStopBinding);
+
+    if(unk)
+        IUnknown_Release(unk);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI PersistMoniker_Save(IPersistMoniker *iface, IMoniker *pimkName, LPBC pbc, BOOL fRemember)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI PersistMoniker_SaveCompleted(IPersistMoniker *iface, IMoniker *pimkName, LPBC pibc)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI PersistMoniker_GetCurMoniker(IPersistMoniker *iface, IMoniker **pimkName)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static const IPersistMonikerVtbl PersistMonikerVtbl = {
+    PersistMoniker_QueryInterface,
+    PersistMoniker_AddRef,
+    PersistMoniker_Release,
+    PersistMoniker_GetClassID,
+    PersistMoniker_IsDirty,
+    PersistMoniker_Load,
+    PersistMoniker_Save,
+    PersistMoniker_SaveCompleted,
+    PersistMoniker_GetCurMoniker
+};
+
+static IPersistMoniker PersistMoniker = { &PersistMonikerVtbl };
+
+static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv)
+{
+    *ppv = NULL;
+
+    if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IClassFactory, riid)) {
+        *ppv = iface;
+        return S_OK;
+    }
+
+    if(IsEqualGUID(&IID_IMarshal, riid))
+        return E_NOINTERFACE;
+    if(IsEqualGUID(&CLSID_IdentityUnmarshal, riid))
+        return E_NOINTERFACE;
+
+    ok(0, "unexpected riid %s\n", debugstr_guid(riid));
+    return E_NOTIMPL;
+}
+
+static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI ClassFactory_Release(IClassFactory *iface)
+{
+    return 1;
+}
+
+static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
+{
+    CHECK_EXPECT(CreateInstance);
+    ok(!outer, "outer = %p\n", outer);
+    ok(IsEqualGUID(&IID_IUnknown, riid), "unexpected riid %s\n", debugstr_guid(riid));
+    *ppv = &PersistMoniker;
+    return S_OK;
+}
+
+static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL dolock)
+{
+    ok(0, "unexpected call\n");
+    return S_OK;
+}
+
+static const IClassFactoryVtbl ClassFactoryVtbl = {
+    ClassFactory_QueryInterface,
+    ClassFactory_AddRef,
+    ClassFactory_Release,
+    ClassFactory_CreateInstance,
+    ClassFactory_LockServer
+};
+
+static IClassFactory mime_cf = { &ClassFactoryVtbl };
 
 static void test_CreateAsyncBindCtx(void)
 {
@@ -1192,11 +1628,13 @@ static void test_CreateAsyncBindCtx(void)
 
 static void test_CreateAsyncBindCtxEx(void)
 {
-    IBindCtx *bctx = NULL, *bctx_arg = NULL;
+    IBindCtx *bctx = NULL, *bctx2 = NULL, *bctx_arg = NULL;
     IUnknown *unk;
     BIND_OPTS bindopts;
     HRESULT hres;
 
+    static WCHAR testW[] = {'t','e','s','t',0};
+
     hres = CreateAsyncBindCtxEx(NULL, 0, NULL, NULL, NULL, 0);
     ok(hres == E_INVALIDARG, "CreateAsyncBindCtx failed: %08x, expected E_INVALIDARG\n", hres);
 
@@ -1249,8 +1687,23 @@ static void test_CreateAsyncBindCtxEx(void)
     if(SUCCEEDED(hres))
         IUnknown_Release(unk);
 
-    if(SUCCEEDED(hres))
-        IBindCtx_Release(bctx);
+    IBindCtx_Release(bctx);
+
+    hres = CreateBindCtx(0, &bctx2);
+    ok(hres == S_OK, "CreateBindCtx failed: %08x\n", hres);
+
+    hres = CreateAsyncBindCtxEx(bctx2, 0, NULL, NULL, &bctx, 0);
+    ok(hres == S_OK, "CreateAsyncBindCtxEx failed: %08x\n", hres);
+
+    hres = IBindCtx_RegisterObjectParam(bctx2, testW, (IUnknown*)&Protocol);
+    ok(hres == S_OK, "RegisterObjectParam failed: %08x\n", hres);
+
+    hres = IBindCtx_GetObjectParam(bctx, testW, &unk);
+    ok(hres == S_OK, "GetObjectParam failed: %08x\n", hres);
+    ok(unk == (IUnknown*)&Protocol, "unexpected unk %p\n", unk);
+
+    IBindCtx_Release(bctx);
+    IBindCtx_Release(bctx2);
 }
 
 static void test_bscholder(IBindStatusCallback *holder)
@@ -1265,8 +1718,6 @@ static void test_bscholder(IBindStatusCallback *holder)
     DWORD dw;
     HRESULT hres;
 
-    static const WCHAR emptyW[] = {0};
-
     hres = IBindStatusCallback_QueryInterface(holder, &IID_IServiceProvider, (void**)&serv_prov);
     ok(hres == S_OK, "Could not get IServiceProvider interface: %08x\n", hres);
 
@@ -1445,6 +1896,19 @@ static void test_RegisterBindStatusCallback(void)
     IBindCtx_Release(bindctx);
 }
 
+static void init_bind_test(int protocol, BOOL emul, BOOL bto)
+{
+    test_protocol = protocol;
+    emulate_protocol = emul;
+    download_state = BEFORE_DOWNLOAD;
+    stopped_binding = FALSE;
+    stopped_obj_binding = FALSE;
+    data_available = FALSE;
+    mime_type[0] = 0;
+    binding_hres = S_OK;
+    bind_to_object = bto;
+}
+
 static void test_BindToStorage(int protocol, BOOL emul)
 {
     IMoniker *mon;
@@ -1456,12 +1920,7 @@ static void test_BindToStorage(int protocol, BOOL emul)
     IUnknown *unk = (IUnknown*)0x00ff00ff;
     IBinding *bind;
 
-    test_protocol = protocol;
-    emulate_protocol = emul;
-    download_state = BEFORE_DOWNLOAD;
-    stopped_binding = FALSE;
-    data_available = FALSE;
-    mime_type[0] = 0;
+    init_bind_test(protocol, emul, FALSE);
 
     SET_EXPECT(QueryInterface_IServiceProvider);
     hres = CreateAsyncBindCtx(0, &bsc, NULL, &bctx);
@@ -1495,7 +1954,9 @@ static void test_BindToStorage(int protocol, BOOL emul)
 
     hres = IMoniker_GetDisplayName(mon, bctx, NULL, &display_name);
     ok(hres == S_OK, "GetDisplayName failed %08x\n", hres);
-    ok(!lstrcmpW(display_name, urls[test_protocol]), "GetDisplayName got wrong name\n");
+    ok(!lstrcmpW(display_name, urls[test_protocol]),
+       "GetDisplayName got wrong name %s\n", debugstr_w(display_name));
+    CoTaskMemFree(display_name);
 
     SET_EXPECT(GetBindInfo);
     SET_EXPECT(QueryInterface_IInternetProtocol);
@@ -1605,32 +2066,23 @@ static void test_BindToObject(int protocol, BOOL emul)
     HRESULT hres;
     LPOLESTR display_name;
     IBindCtx *bctx;
+    DWORD regid;
     MSG msg;
-    IBindStatusCallback *previousclb;
     IUnknown *unk = (IUnknown*)0x00ff00ff;
     IBinding *bind;
 
-    test_protocol = protocol;
-    emulate_protocol = emul;
-    download_state = BEFORE_DOWNLOAD;
-    stopped_binding = FALSE;
-    data_available = FALSE;
-    mime_type[0] = 0;
+    init_bind_test(protocol, emul, TRUE);
+
+    if(emul)
+        CoRegisterClassObject(&CLSID_HTMLDocument, (IUnknown *)&mime_cf,
+                              CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &regid);
 
     SET_EXPECT(QueryInterface_IServiceProvider);
-    hres = CreateAsyncBindCtx(0, &bsc, NULL, &bctx);
+    hres = CreateAsyncBindCtx(0, &objbsc, NULL, &bctx);
     ok(SUCCEEDED(hres), "CreateAsyncBindCtx failed: %08x\n\n", hres);
+    CHECK_CALLED(QueryInterface_IServiceProvider);
     if(FAILED(hres))
         return;
-    CHECK_CALLED(QueryInterface_IServiceProvider);
-
-    SET_EXPECT(QueryInterface_IServiceProvider);
-    hres = RegisterBindStatusCallback(bctx, &bsc, &previousclb, 0);
-    ok(SUCCEEDED(hres), "RegisterBindStatusCallback failed: %08x\n", hres);
-    ok(previousclb == &bsc, "previousclb(%p) != sclb(%p)\n", previousclb, &bsc);
-    CHECK_CALLED(QueryInterface_IServiceProvider);
-    if(previousclb)
-        IBindStatusCallback_Release(previousclb);
 
     hres = CreateURLMoniker(NULL, urls[test_protocol], &mon);
     ok(SUCCEEDED(hres), "failed to create moniker: %08x\n", hres);
@@ -1651,11 +2103,15 @@ static void test_BindToObject(int protocol, BOOL emul)
     ok(hres == S_OK, "GetDisplayName failed %08x\n", hres);
     ok(!lstrcmpW(display_name, urls[test_protocol]), "GetDisplayName got wrong name\n");
 
-    SET_EXPECT(QueryInterface_IServiceProvider);
-    SET_EXPECT(GetBindInfo);
-    SET_EXPECT(OnStartBinding);
+    SET_EXPECT(Obj_GetBindInfo);
+    SET_EXPECT(QueryInterface_IInternetProtocol);
+    if(!emulate_protocol)
+        SET_EXPECT(QueryService_IInternetProtocol);
+    SET_EXPECT(Obj_OnStartBinding);
     if(emulate_protocol) {
         SET_EXPECT(Start);
+        if(test_protocol == HTTP_TEST)
+            SET_EXPECT(Terminate);
         SET_EXPECT(UnlockRequest);
     }else {
         if(test_protocol == HTTP_TEST) {
@@ -1663,56 +2119,63 @@ static void test_BindToObject(int protocol, BOOL emul)
             SET_EXPECT(BeginningTransaction);
             SET_EXPECT(QueryInterface_IHttpNegotiate2);
             SET_EXPECT(GetRootSecurityId);
-            SET_EXPECT(OnProgress_FINDINGRESOURCE);
-            SET_EXPECT(OnProgress_CONNECTING);
+            SET_EXPECT(Obj_OnProgress_FINDINGRESOURCE);
+            SET_EXPECT(Obj_OnProgress_CONNECTING);
         }
         if(test_protocol == HTTP_TEST || test_protocol == FILE_TEST)
-            SET_EXPECT(OnProgress_SENDINGREQUEST);
+            SET_EXPECT(Obj_OnProgress_SENDINGREQUEST);
         if(test_protocol == HTTP_TEST)
             SET_EXPECT(OnResponse);
-        SET_EXPECT(OnProgress_MIMETYPEAVAILABLE);
-        SET_EXPECT(OnProgress_BEGINDOWNLOADDATA);
+        SET_EXPECT(Obj_OnProgress_MIMETYPEAVAILABLE);
+        SET_EXPECT(Obj_OnProgress_BEGINDOWNLOADDATA);
         if(test_protocol == HTTP_TEST)
             SET_EXPECT(OnProgress_DOWNLOADINGDATA);
-        SET_EXPECT(OnProgress_ENDDOWNLOADDATA);
-        SET_EXPECT(OnProgress_CLASSIDAVAILABLE);
-        SET_EXPECT(OnProgress_BEGINSYNCOPERATION);
-        SET_EXPECT(OnProgress_ENDSYNCOPERATION);
+        SET_EXPECT(Obj_OnProgress_ENDDOWNLOADDATA);
+        SET_EXPECT(Obj_OnProgress_CLASSIDAVAILABLE);
+        SET_EXPECT(Obj_OnProgress_BEGINSYNCOPERATION);
+        SET_EXPECT(Obj_OnProgress_ENDSYNCOPERATION);
         SET_EXPECT(OnObjectAvailable);
-        SET_EXPECT(OnStopBinding);
+        SET_EXPECT(Obj_OnStopBinding);
     }
 
     hres = IMoniker_BindToObject(mon, bctx, NULL, &IID_IUnknown, (void**)&unk);
+
     if (test_protocol == HTTP_TEST && hres == HRESULT_FROM_WIN32(ERROR_INTERNET_NAME_NOT_RESOLVED))
     {
         trace( "Network unreachable, skipping tests\n" );
         return;
     }
-    todo_wine ok(SUCCEEDED(hres), "IMoniker_BindToObject failed with error 0x%08x\n", hres);
+
     /* no point testing the calls if binding didn't even work */
-    if (!SUCCEEDED(hres)) return;
+    if (FAILED(hres)) return;
 
-    if((bindf & BINDF_ASYNCHRONOUS) && !data_available) {
-        ok(hres == MK_S_ASYNCHRONOUS, "IMoniker_BindToStorage failed: %08x\n", hres);
+    if(bindf & BINDF_ASYNCHRONOUS) {
+        ok(hres == MK_S_ASYNCHRONOUS, "IMoniker_BindToObject failed: %08x\n", hres);
         ok(unk == NULL, "istr should be NULL\n");
     }else {
         ok(hres == S_OK, "IMoniker_BindToStorage failed: %08x\n", hres);
         ok(unk != NULL, "unk == NULL\n");
+        if(emul)
+            ok(unk == (IUnknown*)&PersistMoniker, "unk != PersistMoniker\n");
     }
     if(unk)
         IUnknown_Release(unk);
 
     while((bindf & BINDF_ASYNCHRONOUS) &&
-          !stopped_binding && GetMessage(&msg,NULL,0,0)) {
+          !((!emul || stopped_binding) && stopped_obj_binding) && GetMessage(&msg,NULL,0,0)) {
         TranslateMessage(&msg);
         DispatchMessage(&msg);
     }
 
-    todo_wine CHECK_NOT_CALLED(QueryInterface_IServiceProvider);
-    CHECK_CALLED(GetBindInfo);
-    CHECK_CALLED(OnStartBinding);
+    CHECK_CALLED(Obj_GetBindInfo);
+    CHECK_CALLED(QueryInterface_IInternetProtocol);
+    if(!emulate_protocol)
+        CHECK_CALLED(QueryService_IInternetProtocol);
+    CHECK_CALLED(Obj_OnStartBinding);
     if(emulate_protocol) {
         CHECK_CALLED(Start);
+        if(test_protocol == HTTP_TEST)
+            CHECK_CALLED(Terminate);
         CHECK_CALLED(UnlockRequest);
     }else {
         if(test_protocol == HTTP_TEST) {
@@ -1723,31 +2186,39 @@ static void test_BindToObject(int protocol, BOOL emul)
             CLEAR_CALLED(QueryInterface_IHttpNegotiate2);
             CLEAR_CALLED(GetRootSecurityId);
             if(http_is_first) {
-                CHECK_CALLED(OnProgress_FINDINGRESOURCE);
-                CHECK_CALLED(OnProgress_CONNECTING);
+                CHECK_CALLED(Obj_OnProgress_FINDINGRESOURCE);
+                CHECK_CALLED(Obj_OnProgress_CONNECTING);
             }else todo_wine {
-                CHECK_NOT_CALLED(OnProgress_FINDINGRESOURCE);
-                CHECK_NOT_CALLED(OnProgress_CONNECTING);
+                CHECK_NOT_CALLED(Obj_OnProgress_FINDINGRESOURCE);
+                CHECK_NOT_CALLED(Obj_OnProgress_CONNECTING);
             }
         }
         if(test_protocol == HTTP_TEST || test_protocol == FILE_TEST)
-            CHECK_CALLED(OnProgress_SENDINGREQUEST);
+            CHECK_CALLED(Obj_OnProgress_SENDINGREQUEST);
         if(test_protocol == HTTP_TEST)
             CHECK_CALLED(OnResponse);
-        CHECK_CALLED(OnProgress_MIMETYPEAVAILABLE);
-        CHECK_CALLED(OnProgress_BEGINDOWNLOADDATA);
+        CHECK_CALLED(Obj_OnProgress_MIMETYPEAVAILABLE);
+        CHECK_CALLED(Obj_OnProgress_BEGINDOWNLOADDATA);
         if(test_protocol == HTTP_TEST)
             CLEAR_CALLED(OnProgress_DOWNLOADINGDATA);
-        CHECK_CALLED(OnProgress_ENDDOWNLOADDATA);
-        CHECK_CALLED(OnProgress_CLASSIDAVAILABLE);
-        CHECK_CALLED(OnProgress_BEGINSYNCOPERATION);
-        CHECK_CALLED(OnProgress_ENDSYNCOPERATION);
+        CLEAR_CALLED(Obj_OnProgress_ENDDOWNLOADDATA);
+        CHECK_CALLED(Obj_OnProgress_CLASSIDAVAILABLE);
+        CHECK_CALLED(Obj_OnProgress_BEGINSYNCOPERATION);
+        CHECK_CALLED(Obj_OnProgress_ENDSYNCOPERATION);
         CHECK_CALLED(OnObjectAvailable);
-        CHECK_CALLED(OnStopBinding);
+        CHECK_CALLED(Obj_OnStopBinding);
     }
 
-    ok(IMoniker_Release(mon) == 0, "mon should be destroyed here\n");
-    ok(IBindCtx_Release(bctx) == 0, "bctx should be destroyed here\n");
+    if(test_protocol != HTTP_TEST || emul || urls[test_protocol] == SHORT_RESPONSE_URL) {
+        ok(IMoniker_Release(mon) == 0, "mon should be destroyed here\n");
+        ok(IBindCtx_Release(bctx) == 0, "bctx should be destroyed here\n");
+    }else todo_wine {
+        ok(IMoniker_Release(mon) == 0, "mon should be destroyed here\n");
+        ok(IBindCtx_Release(bctx) == 0, "bctx should be destroyed here\n");
+    }
+
+    if(emul)
+        CoRevokeClassObject(regid);
 
     if(test_protocol == HTTP_TEST)
         http_is_first = FALSE;
@@ -1786,6 +2257,46 @@ static void create_file(void)
     set_file_url();
 }
 
+static void test_ReportResult(HRESULT exhres)
+{
+    IMoniker *mon = NULL;
+    IBindCtx *bctx = NULL;
+    IUnknown *unk = (void*)0xdeadbeef;
+    HRESULT hres;
+
+    init_bind_test(ABOUT_TEST, TRUE, FALSE);
+    binding_hres = exhres;
+
+    hres = CreateURLMoniker(NULL, ABOUT_BLANK, &mon);
+    ok(hres == S_OK, "CreateURLMoniker failed: %08x\n", hres);
+
+    SET_EXPECT(QueryInterface_IServiceProvider);
+    hres = CreateAsyncBindCtx(0, &bsc, NULL, &bctx);
+    ok(hres == S_OK, "CreateAsyncBindCtx failed: %08x\n\n", hres);
+    CHECK_CALLED(QueryInterface_IServiceProvider);
+
+    SET_EXPECT(GetBindInfo);
+    SET_EXPECT(QueryInterface_IInternetProtocol);
+    SET_EXPECT(OnStartBinding);
+    SET_EXPECT(Start);
+
+    hres = IMoniker_BindToStorage(mon, bctx, NULL, &IID_IStream, (void**)&unk);
+    if(SUCCEEDED(exhres))
+        ok(hres == S_OK, "BindToStorage failed: %08x\n", hres);
+    else
+        ok(hres == exhres, "BindToStorage failed: %08x, expected %08x\n", hres, exhres);
+
+    CHECK_CALLED(GetBindInfo);
+    CHECK_CALLED(QueryInterface_IInternetProtocol);
+    CHECK_CALLED(OnStartBinding);
+    CHECK_CALLED(Start);
+
+    ok(unk == NULL, "unk=%p\n", unk);
+
+    IBindCtx_Release(bctx);
+    IMoniker_Release(mon);
+}
+
 static void test_BindToStorage_fail(void)
 {
     IMoniker *mon = NULL;
@@ -1807,6 +2318,9 @@ static void test_BindToStorage_fail(void)
     IBindCtx_Release(bctx);
 
     IMoniker_Release(mon);
+
+    test_ReportResult(E_NOTIMPL);
+    test_ReportResult(S_FALSE);
 }
 
 START_TEST(url)
@@ -1819,10 +2333,10 @@ START_TEST(url)
     test_CreateAsyncBindCtx();
     test_CreateAsyncBindCtxEx();
     test_RegisterBindStatusCallback();
+    test_BindToStorage_fail();
 
     trace("synchronous http test (COM not initialised)...\n");
     test_BindToStorage(HTTP_TEST, FALSE);
-    test_BindToStorage_fail();
 
     CoInitialize(NULL);
 
@@ -1850,6 +2364,7 @@ START_TEST(url)
 
     trace("emulated http test...\n");
     test_BindToStorage(HTTP_TEST, TRUE);
+    test_BindToObject(HTTP_TEST, TRUE);
 
     trace("about test...\n");
     test_BindToStorage(ABOUT_TEST, FALSE);
@@ -1857,6 +2372,7 @@ START_TEST(url)
 
     trace("emulated about test...\n");
     test_BindToStorage(ABOUT_TEST, TRUE);
+    test_BindToObject(ABOUT_TEST, TRUE);
 
     trace("file test...\n");
     create_file();
@@ -1867,6 +2383,7 @@ START_TEST(url)
     trace("emulated file test...\n");
     set_file_url();
     test_BindToStorage(FILE_TEST, TRUE);
+    test_BindToObject(FILE_TEST, TRUE);
 
     trace("emulated its test...\n");
     test_BindToStorage(ITS_TEST, TRUE);
@@ -1874,6 +2391,7 @@ START_TEST(url)
     trace("emulated mk test...\n");
     test_BindToStorage(MK_TEST, TRUE);
 
+    trace("test failures...\n");
     test_BindToStorage_fail();
 
     CloseHandle(complete_event);
index 674fede..ba4ef13 100644 (file)
@@ -1,5 +1,6 @@
 <?xml version="1.0"?>
 <!DOCTYPE module SYSTEM "../../../tools/rbuild/project.dtd">
+<group>
 <module name="urlmon_winetest" type="win32cui" installbase="bin" installname="urlmon_winetest.exe" allowwarnings="true" entrypoint="0">
        <include base="urlmon_winetest">.</include>
        <define name="WINVER">0x600</define>
@@ -18,3 +19,4 @@
        <file>url.c</file>
        <file>testlist.c</file>
 </module>
+</group>
index 6d03fb8..985b23b 100644 (file)
@@ -691,6 +691,84 @@ static void test_command(HINTERNET hFtp, HINTERNET hConnect)
     }
 }
 
+static void test_get_current_dir(HINTERNET hFtp, HINTERNET hConnect)
+{
+    BOOL    bRet;
+    DWORD   dwCurrentDirectoryLen = MAX_PATH;
+    CHAR    lpszCurrentDirectory[MAX_PATH];
+
+    /* change directories to get a more interesting pwd */
+    bRet = FtpCommandA(hFtp, FALSE, FTP_TRANSFER_TYPE_ASCII, "CWD pub/", 0, NULL);
+    if(bRet == FALSE)
+    {
+        skip("Failed to change directories in test_get_current_dir(HINTERNET hFtp).\n");
+        return;
+    }
+
+    /* test with all NULL arguments */
+    SetLastError(0xdeadbeef);
+    bRet = FtpGetCurrentDirectoryA( NULL, NULL, 0 );
+    ok ( bRet == FALSE, "Expected FtpGetCurrentDirectoryA to fail\n" );
+    ok ( GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got: %d\n", GetLastError());
+
+    /* test with NULL parameters instead of expected LPSTR/LPDWORD */
+    SetLastError(0xdeadbeef);
+    bRet = FtpGetCurrentDirectoryA( hFtp, NULL, 0 );
+    ok ( bRet == FALSE, "Expected FtpGetCurrentDirectoryA to fail\n" );
+    ok ( GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got: %d\n", GetLastError());
+
+    /* test with no valid handle and valid parameters */
+    SetLastError(0xdeadbeef);
+    bRet = FtpGetCurrentDirectoryA( NULL, lpszCurrentDirectory, &dwCurrentDirectoryLen );
+    ok ( bRet == FALSE, "Expected FtpGetCurrentDirectoryA to fail\n" );
+    ok ( GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got: %d\n", GetLastError());
+
+    /* test with invalid dwCurrentDirectory and all other parameters correct */
+    SetLastError(0xdeadbeef);
+    bRet = FtpGetCurrentDirectoryA( hFtp, lpszCurrentDirectory, 0 );
+    ok ( bRet == FALSE, "Expected FtpGetCurrentDirectoryA to fail\n" );
+    ok ( GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got: %d\n", GetLastError());
+
+    /* test with invalid lpszCurrentDirectory and all other parameters correct */
+    SetLastError(0xdeadbeef);
+    bRet = FtpGetCurrentDirectoryA( hFtp, NULL, &dwCurrentDirectoryLen );
+    ok ( bRet == FALSE, "Expected FtpGetCurrentDirectoryA to fail\n" );
+    ok ( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Expected ERROR_INSUFFICIENT_BUFFER, got: %d\n", GetLastError());
+
+    /* test to show it checks the handle type */
+    SetLastError(0xdeadbeef);
+    bRet = FtpGetCurrentDirectoryA( hConnect, lpszCurrentDirectory, &dwCurrentDirectoryLen );
+    ok ( bRet == FALSE, "Expected FtpGetCurrentDirectoryA to fail\n" );
+    ok ( GetLastError() == ERROR_INTERNET_INCORRECT_HANDLE_TYPE,
+    "Expected ERROR_INTERNET_INCORRECT_HANDLE_TYPE, got: %d\n", GetLastError());
+
+    /* test for the current directory with legitimate values */
+    SetLastError(0xdeadbeef);
+    bRet = FtpGetCurrentDirectoryA( hFtp, lpszCurrentDirectory, &dwCurrentDirectoryLen );
+    ok ( bRet == TRUE, "Expected FtpGetCurrentDirectoryA to pass\n" );
+    ok ( !strcmp(lpszCurrentDirectory, "/pub"), "Expected returned value \"%s\" to match \"/pub\"\n", lpszCurrentDirectory);
+    ok ( GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got: %d\n", GetLastError());
+
+    /* test for the current directory with a size only large enough to
+     * fit the string and not the null terminating character */
+    SetLastError(0xdeadbeef);
+    dwCurrentDirectoryLen = 4;
+    lpszCurrentDirectory[4] = 'a'; /* set position 4 of the array to something else to make sure a leftover \0 isn't fooling the test */
+    bRet = FtpGetCurrentDirectoryA( hFtp, lpszCurrentDirectory, &dwCurrentDirectoryLen );
+    ok ( bRet == FALSE, "Expected FtpGetCurrentDirectoryA to fail\n");
+    ok ( strcmp(lpszCurrentDirectory, "/pub"), "Expected returned value \"%s\" to not match \"/pub\"\n", lpszCurrentDirectory);
+    ok ( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Expected ERROR_INSUFFICIENT_BUFFER, got: %d\n", GetLastError());
+
+    /* test for the current directory with a size large enough to store
+     * the expected string as well as the null terminating character */
+    SetLastError(0xdeadbeef);
+    dwCurrentDirectoryLen = 5;
+    bRet = FtpGetCurrentDirectoryA( hFtp, lpszCurrentDirectory, &dwCurrentDirectoryLen );
+    ok ( bRet == TRUE, "Expected FtpGetCurrentDirectoryA to pass\n");
+    ok ( !strcmp(lpszCurrentDirectory, "/pub"), "Expected returned value \"%s\" to match \"/pub\"\n", lpszCurrentDirectory);
+    ok ( GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got: %d\n", GetLastError());
+}
+
 START_TEST(ftp)
 {
     HANDLE hInternet, hFtp, hHttp;
@@ -733,6 +811,7 @@ START_TEST(ftp)
     test_removedir(hFtp, hHttp);
     test_renamefile(hFtp, hHttp);
     test_command(hFtp, hHttp);
+    test_get_current_dir(hFtp, hHttp);
 
     InternetCloseHandle(hHttp);
     InternetCloseHandle(hFtp);
index ce70211..e88b3bf 100644 (file)
@@ -20,7 +20,7 @@
 #include "wine/test.h"
 
 /***********************************************************************
- * Compability macros
+ * Compatibility macros
  */
 
 #define DWORD_PTR UINT_PTR
index 729be53..dd71edb 100644 (file)
@@ -53,7 +53,7 @@
 #define CREATE_URL11 "about:"
 #define CREATE_URL12 "http://www.winehq.org:65535"
 
-static inline void copy_compsA(
+static void copy_compsA(
     URL_COMPONENTSA *src, 
     URL_COMPONENTSA *dst, 
     DWORD scheLen,
@@ -73,7 +73,7 @@ static inline void copy_compsA(
     SetLastError(0xfaceabad);
 }
 
-static inline void zero_compsA(
+static void zero_compsA(
     URL_COMPONENTSA *dst, 
     DWORD scheLen,
     DWORD hostLen,
@@ -239,6 +239,25 @@ static void InternetCrackUrl_test(void)
   GLE = GetLastError();
   ok(ret == FALSE, "Expected InternetCrackUrl to fail\n");
   ok(GLE != 0xdeadbeef && GLE != ERROR_SUCCESS, "Expected GLE to represent a failure\n");
+
+  /* Invalid Call: must set size of components structure (Windows only
+   * enforces this on the InternetCrackUrlA version of the call) */
+  copy_compsA(&urlSrc, &urlComponents, 0, 1024, 1024, 1024, 2048, 1024);
+  SetLastError(0xdeadbeef);
+  urlComponents.dwStructSize = 0;
+  ret = InternetCrackUrlA(TEST_URL, 0, 0, &urlComponents);
+  ok(ret == FALSE, "Expected InternetCrackUrl to fail\n");
+  ok(GLE != 0xdeadbeef && GLE != ERROR_SUCCESS, "Expected GLE to represent a failure\n");
+
+  /* Invalid Call: size of dwStructSize must be one of the "standard" sizes
+   * of the URL_COMPONENTS structure (Windows only enforces this on the
+   * InternetCrackUrlA version of the call) */
+  copy_compsA(&urlSrc, &urlComponents, 0, 1024, 1024, 1024, 2048, 1024);
+  SetLastError(0xdeadbeef);
+  urlComponents.dwStructSize = sizeof(urlComponents) + 1;
+  ret = InternetCrackUrlA(TEST_URL, 0, 0, &urlComponents);
+  ok(ret == FALSE, "Expected InternetCrackUrl to fail\n");
+  ok(GLE != 0xdeadbeef && GLE != ERROR_SUCCESS, "Expected GLE to represent a failure\n");
 }
 
 static void InternetCrackUrlW_test(void)
@@ -442,7 +461,7 @@ static void InternetCreateUrlA_test(void)
                "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
        ok(len == -1, "Expected len -1, got %d\n", len);
 
-       /* test valid lpUrlComponets, emptry szUrl
+       /* test valid lpUrlComponets, empty szUrl
         * lpdwUrlLength is size of buffer required on exit, including
         * the terminating null when GLE == ERROR_INSUFFICIENT_BUFFER
         */
index 059de03..434d845 100644 (file)
@@ -1,5 +1,6 @@
 <?xml version="1.0"?>
 <!DOCTYPE module SYSTEM "../../../tools/rbuild/project.dtd">
+<group>
 <module name="wininet_winetest" type="win32cui" installbase="bin" installname="wininet_winetest.exe" allowwarnings="true" entrypoint="0">
        <include base="wininet_winetest">.</include>
        <define name="WINVER">0x600</define>
@@ -16,3 +17,4 @@
        <file>url.c</file>
        <file>testlist.c</file>
 </module>
+</group>