[OLE32_WINETEST]
authorAmine Khaldi <amine.khaldi@reactos.org>
Thu, 24 Apr 2014 12:14:32 +0000 (12:14 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Thu, 24 Apr 2014 12:14:32 +0000 (12:14 +0000)
* Sync with Wine 1.7.17.
CORE-8080

svn path=/trunk/; revision=62939

rostests/winetests/ole32/compobj.c
rostests/winetests/ole32/defaulthandler.c
rostests/winetests/ole32/dragdrop.c
rostests/winetests/ole32/marshal.c
rostests/winetests/ole32/ole2.c
rostests/winetests/ole32/ole_server.c
rostests/winetests/ole32/propvariant.c
rostests/winetests/ole32/stg_prop.c
rostests/winetests/ole32/storage32.c
rostests/winetests/ole32/usrmarshal.c

index b6fda82..fb68b34 100644 (file)
@@ -37,7 +37,7 @@
 //#include "objbase.h"
 //#include "shlguid.h"
 #include <ole2.h>
-//#include "urlmon.h" /* for CLSID_FileProtocol */
+#include <urlmon.h> /* for CLSID_FileProtocol */
 
 #include <ctxtcall.h>
 
@@ -68,32 +68,26 @@ static const GUID IID_Testiface = { 0x22222222, 0x1234, 0x1234, { 0x12, 0x34, 0x
 static const GUID IID_Testiface2 = { 0x32222222, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
 static const GUID IID_Testiface3 = { 0x42222222, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
 static const GUID IID_Testiface4 = { 0x52222222, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
+static const GUID IID_Testiface5 = { 0x62222222, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
+static const GUID IID_Testiface6 = { 0x72222222, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
 static const GUID IID_TestPS = { 0x66666666, 0x8888, 0x7777, { 0x66, 0x66, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 } };
 
-static WCHAR stdfont[] = {'S','t','d','F','o','n','t',0};
+DEFINE_GUID(CLSID_InProcFreeMarshaler, 0x0000033a,0x0000,0x0000,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
+
+static const WCHAR stdfont[] = {'S','t','d','F','o','n','t',0};
 static const WCHAR wszNonExistent[] = {'N','o','n','E','x','i','s','t','e','n','t',0};
-static WCHAR wszCLSID_StdFont[] =
+static const WCHAR wszCLSID_StdFont[] =
 {
     '{','0','b','e','3','5','2','0','3','-','8','f','9','1','-','1','1','c','e','-',
     '9','d','e','3','-','0','0','a','a','0','0','4','b','b','8','5','1','}',0
 };
 static const WCHAR progidW[] = {'P','r','o','g','I','d','.','P','r','o','g','I','d',0};
+static const WCHAR cf_brokenW[] = {'{','0','0','0','0','0','0','0','1','-','0','0','0','0','-','0','0','0','0','-',
+                                    'c','0','0','0','-','0','0','0','0','0','0','0','0','0','0','4','6','}','a',0};
 
 DEFINE_GUID(IID_IWineTest, 0x5201163f, 0x8164, 0x4fd0, 0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd);
 DEFINE_GUID(CLSID_WineOOPTest, 0x5201163f, 0x8164, 0x4fd0, 0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd);
 
-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 LONG cLocks;
 
 static void LockModule(void)
@@ -207,7 +201,13 @@ static HANDLE activate_context(const char *manifest, ULONG_PTR *cookie)
     actctx.lpSource = path;
 
     handle = pCreateActCtxW(&actctx);
-    ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError());
+    ok(handle != INVALID_HANDLE_VALUE || broken(handle == INVALID_HANDLE_VALUE) /* some old XP/2k3 versions */,
+        "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError());
+    if (handle == INVALID_HANDLE_VALUE)
+    {
+        win_skip("activation context generation failed, some tests will be skipped\n");
+        handle = NULL;
+    }
 
     ok(actctx.cbSize == sizeof(ACTCTXW), "actctx.cbSize=%d\n", actctx.cbSize);
     ok(actctx.dwFlags == 0, "actctx.dwFlags=%d\n", actctx.dwFlags);
@@ -221,8 +221,11 @@ static HANDLE activate_context(const char *manifest, ULONG_PTR *cookie)
 
     DeleteFileA("file.manifest");
 
-    ret = pActivateActCtx(handle, cookie);
-    ok(ret, "ActivateActCtx failed: %u\n", GetLastError());
+    if (handle)
+    {
+        ret = pActivateActCtx(handle, cookie);
+        ok(ret, "ActivateActCtx failed: %u\n", GetLastError());
+    }
 
     return handle;
 }
@@ -232,6 +235,14 @@ static const char actctx_manifest[] =
 "<assemblyIdentity version=\"1.2.3.4\"  name=\"Wine.Test\" type=\"win32\""
 " publicKeyToken=\"6595b6414666f1df\" />"
 "<file name=\"testlib.dll\">"
+"    <comClass"
+"              clsid=\"{0000033a-0000-0000-c000-000000000046}\""
+"              progid=\"FTMarshal\""
+"    />"
+"    <comClass"
+"              clsid=\"{5201163f-8164-4fd0-a1a2-5d5a3654d3bd}\""
+"              progid=\"WineOOPTest\""
+"    />"
 "    <comClass description=\"Test com class\""
 "              clsid=\"{12345678-1234-1234-1234-56789abcdef0}\""
 "              progid=\"ProgId.ProgId\""
@@ -245,6 +256,9 @@ static const char actctx_manifest[] =
 "    <comClass clsid=\"{0be35203-8f91-11ce-9de3-00aa004bb852}\""
 "              progid=\"StdFont\""
 "    />"
+"    <comClass clsid=\"{62222222-1234-1234-1234-56789abcdef0}\" >"
+"        <progid>ProgId.ProgId.1</progid>"
+"    </comClass>"
 "    <comInterfaceProxyStub "
 "        name=\"Iifaceps\""
 "        iid=\"{22222222-1234-1234-1234-56789abcdef0}\""
@@ -265,6 +279,12 @@ static const char actctx_manifest[] =
 "        iid=\"{52222222-1234-1234-1234-56789abcdef0}\""
 "        proxyStubClsid32=\"{00000000-0000-0000-0000-000000000000}\""
 "    />"
+"    <clrClass "
+"        clsid=\"{72222222-1234-1234-1234-56789abcdef0}\""
+"        name=\"clrclass\""
+"    >"
+"        <progid>clrprogid.1</progid>"
+"    </clrClass>"
 "</assembly>";
 
 DEFINE_GUID(CLSID_Testclass, 0x12345678, 0x1234, 0x1234, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0);
@@ -297,22 +317,24 @@ static void test_ProgIDFromCLSID(void)
         static const WCHAR customfontW[] = {'C','u','s','t','o','m','F','o','n','t',0};
 
         hr = ProgIDFromCLSID(&CLSID_non_existent, &progid);
-todo_wine
         ok(hr == S_OK, "got 0x%08x\n", hr);
-        if (hr == S_OK)
-        {
-            ok(!lstrcmpiW(progid, progidW), "got %s\n", wine_dbgstr_w(progid));
-            CoTaskMemFree(progid);
-        }
+        ok(!lstrcmpiW(progid, progidW), "got %s\n", wine_dbgstr_w(progid));
+        CoTaskMemFree(progid);
 
         /* try something registered and redirected */
         progid = NULL;
         hr = ProgIDFromCLSID(&CLSID_StdFont, &progid);
         ok(hr == S_OK, "got 0x%08x\n", hr);
-todo_wine
         ok(!lstrcmpiW(progid, customfontW), "got wrong progid %s\n", wine_dbgstr_w(progid));
         CoTaskMemFree(progid);
 
+        /* classes without default progid, progid list is not used */
+        hr = ProgIDFromCLSID(&IID_Testiface5, &progid);
+        ok(hr == REGDB_E_CLASSNOTREG, "got 0x%08x\n", hr);
+
+        hr = ProgIDFromCLSID(&IID_Testiface6, &progid);
+        ok(hr == REGDB_E_CLASSNOTREG, "got 0x%08x\n", hr);
+
         pDeactivateActCtx(0, cookie);
         pReleaseActCtx(handle);
     }
@@ -354,14 +376,20 @@ static void test_CLSIDFromProgID(void)
     {
         GUID clsid1;
 
+        memset(&clsid, 0xcc, sizeof(clsid));
+        hr = CLSIDFromProgID(wszNonExistent, &clsid);
+        ok(hr == CO_E_CLASSSTRING, "got 0x%08x\n", hr);
+        ok(IsEqualCLSID(&clsid, &CLSID_NULL), "should have zero CLSID on failure\n");
+
+        /* CLSIDFromString() doesn't check activation context */
+        hr = CLSIDFromString(progidW, &clsid);
+        ok(hr == CO_E_CLASSSTRING, "got 0x%08x\n", hr);
+
         clsid = CLSID_NULL;
         hr = CLSIDFromProgID(progidW, &clsid);
-todo_wine
-        ok(hr == S_OK, "got 0x%08x\n", hr);
-        if (hr == S_OK)
-            /* it returns generated CLSID here */
-            ok(!IsEqualCLSID(&clsid, &CLSID_non_existent) && !IsEqualCLSID(&clsid, &CLSID_NULL),
-                "got wrong clsid %s\n", debugstr_guid(&clsid));
+        /* it returns generated CLSID here */
+        ok(!IsEqualCLSID(&clsid, &CLSID_non_existent) && !IsEqualCLSID(&clsid, &CLSID_NULL),
+                 "got wrong clsid %s\n", wine_dbgstr_guid(&clsid));
 
         /* duplicate progid present in context - returns generated guid here too */
         clsid = CLSID_NULL;
@@ -370,9 +398,8 @@ todo_wine
         clsid1 = CLSID_StdFont;
         /* that's where it differs from StdFont */
         clsid1.Data4[7] = 0x52;
-todo_wine
         ok(!IsEqualCLSID(&clsid, &CLSID_StdFont) && !IsEqualCLSID(&clsid, &CLSID_NULL) && !IsEqualCLSID(&clsid, &clsid1),
-            "got %s\n", debugstr_guid(&clsid));
+            "got %s\n", wine_dbgstr_guid(&clsid));
 
         pDeactivateActCtx(0, cookie);
         pReleaseActCtx(handle);
@@ -389,10 +416,17 @@ static void test_CLSIDFromString(void)
     ok_ole_success(hr, "CLSIDFromString");
     ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n");
 
+    memset(&clsid, 0xab, sizeof(clsid));
     hr = CLSIDFromString(NULL, &clsid);
-    ok_ole_success(hr, "CLSIDFromString");
+    ok(hr == S_OK, "got 0x%08x\n", hr);
     ok(IsEqualCLSID(&clsid, &CLSID_NULL), "clsid wasn't equal to CLSID_NULL\n");
 
+    /* string is longer, but starts with a valid CLSID */
+    memset(&clsid, 0, sizeof(clsid));
+    hr = CLSIDFromString(cf_brokenW, &clsid);
+    ok(hr == CO_E_CLASSSTRING, "got 0x%08x\n", hr);
+    ok(IsEqualCLSID(&clsid, &IID_IClassFactory), "got %s\n", wine_dbgstr_guid(&clsid));
+
     lstrcpyW(wszCLSID_Broken, wszCLSID_StdFont);
     for(i = lstrlenW(wszCLSID_StdFont); i < 49; i++)
         wszCLSID_Broken[i] = 'A';
@@ -448,6 +482,68 @@ static void test_CLSIDFromString(void)
     ok(clsid.Data2 == 0xcccc, "Got %04x\n", clsid.Data2);
 }
 
+static void test_IIDFromString(void)
+{
+    static const WCHAR cfW[] = {'{','0','0','0','0','0','0','0','1','-','0','0','0','0','-','0','0','0','0','-',
+                                    'c','0','0','0','-','0','0','0','0','0','0','0','0','0','0','4','6','}',0};
+    static const WCHAR brokenW[] = {'{','0','0','0','0','0','0','0','1','-','0','0','0','0','-','0','0','0','0','-',
+                                        'g','0','0','0','-','0','0','0','0','0','0','0','0','0','0','4','6','}',0};
+    static const WCHAR broken2W[] = {'{','0','0','0','0','0','0','0','1','=','0','0','0','0','-','0','0','0','0','-',
+                                        'g','0','0','0','-','0','0','0','0','0','0','0','0','0','0','4','6','}',0};
+    static const WCHAR broken3W[] = {'b','r','o','k','e','n','0','0','1','=','0','0','0','0','-','0','0','0','0','-',
+                                        'g','0','0','0','-','0','0','0','0','0','0','0','0','0','0','4','6','}',0};
+    HRESULT hr;
+    IID iid;
+
+    hr = IIDFromString(wszCLSID_StdFont, &iid);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    ok(IsEqualIID(&iid, &CLSID_StdFont), "got iid %s\n", wine_dbgstr_guid(&iid));
+
+    memset(&iid, 0xab, sizeof(iid));
+    hr = IIDFromString(NULL, &iid);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    ok(IsEqualIID(&iid, &CLSID_NULL), "got iid %s\n", wine_dbgstr_guid(&iid));
+
+    hr = IIDFromString(cfW, &iid);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    ok(IsEqualIID(&iid, &IID_IClassFactory), "got iid %s\n", wine_dbgstr_guid(&iid));
+
+    /* string starts with a valid IID but is longer */
+    memset(&iid, 0xab, sizeof(iid));
+    hr = IIDFromString(cf_brokenW, &iid);
+    ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
+    ok(iid.Data1 == 0xabababab, "Got %08x\n", iid.Data1);
+
+    /* invalid IID in a valid format */
+    memset(&iid, 0xab, sizeof(iid));
+    hr = IIDFromString(brokenW, &iid);
+    ok(hr == CO_E_IIDSTRING, "got 0x%08x\n", hr);
+    ok(iid.Data1 == 0x00000001, "Got %08x\n", iid.Data1);
+
+    memset(&iid, 0xab, sizeof(iid));
+    hr = IIDFromString(broken2W, &iid);
+    ok(hr == CO_E_IIDSTRING, "got 0x%08x\n", hr);
+    ok(iid.Data1 == 0x00000001, "Got %08x\n", iid.Data1);
+
+    /* format is broken, but string length is okay */
+    memset(&iid, 0xab, sizeof(iid));
+    hr = IIDFromString(broken3W, &iid);
+    ok(hr == CO_E_IIDSTRING, "got 0x%08x\n", hr);
+    ok(iid.Data1 == 0xabababab, "Got %08x\n", iid.Data1);
+
+    /* invalid string */
+    memset(&iid, 0xab, sizeof(iid));
+    hr = IIDFromString(wszNonExistent, &iid);
+    ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
+    ok(iid.Data1 == 0xabababab, "Got %08x\n", iid.Data1);
+
+    /* valid ProgID */
+    memset(&iid, 0xab, sizeof(iid));
+    hr = IIDFromString(stdfont, &iid);
+    ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
+    ok(iid.Data1 == 0xabababab, "Got %08x\n", iid.Data1);
+}
+
 static void test_StringFromGUID2(void)
 {
   WCHAR str[50];
@@ -539,10 +635,10 @@ static void test_CoCreateInstance(void)
     /* show that COM doesn't have to be initialized for multi-threaded apartments if another
        thread has already done so */
 
-    info.wait = CreateEvent(NULL, TRUE, FALSE, NULL);
+    info.wait = CreateEventA(NULL, TRUE, FALSE, NULL);
     ok(info.wait != NULL, "CreateEvent failed with error %d\n", GetLastError());
 
-    info.stop = CreateEvent(NULL, TRUE, FALSE, NULL);
+    info.stop = CreateEventA(NULL, TRUE, FALSE, NULL);
     ok(info.stop != NULL, "CreateEvent failed with error %d\n", GetLastError());
 
     thread = CreateThread(NULL, 0, ole_initialize_thread, &info, 0, &tid);
@@ -570,8 +666,9 @@ static void test_CoCreateInstance(void)
 static void test_CoGetClassObject(void)
 {
     HRESULT hr;
-    HANDLE thread;
+    HANDLE thread, handle;
     DWORD tid, exitcode;
+    ULONG_PTR cookie;
     IUnknown *pUnk;
     struct info info;
     REFCLSID rclsid = &CLSID_InternetZoneManager;
@@ -590,10 +687,10 @@ static void test_CoGetClassObject(void)
     /* show that COM doesn't have to be initialized for multi-threaded apartments if another
        thread has already done so */
 
-    info.wait = CreateEvent(NULL, TRUE, FALSE, NULL);
+    info.wait = CreateEventA(NULL, TRUE, FALSE, NULL);
     ok(info.wait != NULL, "CreateEvent failed with error %d\n", GetLastError());
 
-    info.stop = CreateEvent(NULL, TRUE, FALSE, NULL);
+    info.stop = CreateEventA(NULL, TRUE, FALSE, NULL);
     ok(info.stop != NULL, "CreateEvent failed with error %d\n", GetLastError());
 
     thread = CreateThread(NULL, 0, ole_initialize_thread, &info, 0, &tid);
@@ -635,7 +732,7 @@ static void test_CoGetClassObject(void)
     {
         IUnknown_Release(pUnk);
 
-        res = RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\Classes", 0, NULL, 0,
+        res = RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Classes", 0, NULL, 0,
                              KEY_ALL_ACCESS, NULL, &hkey, NULL);
         ok(!res, "RegCreateKeyEx returned %d\n", res);
 
@@ -651,26 +748,42 @@ static void test_CoGetClassObject(void)
         if (hr == S_OK) IUnknown_Release(pUnk);
         RegCloseKey(hkey);
     }
+
+    hr = CoGetClassObject(&CLSID_InProcFreeMarshaler, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void **)&pUnk);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    IUnknown_Release(pUnk);
+
+    /* context redefines FreeMarshaler CLSID */
+    if ((handle = activate_context(actctx_manifest, &cookie)))
+    {
+        hr = CoGetClassObject(&CLSID_InProcFreeMarshaler, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void **)&pUnk);
+        ok(hr == S_OK, "got 0x%08x\n", hr);
+        IUnknown_Release(pUnk);
+
+        pDeactivateActCtx(0, cookie);
+        pReleaseActCtx(handle);
+    }
+
     CoUninitialize();
 }
 
 static ATOM register_dummy_class(void)
 {
-    WNDCLASS wc =
+    WNDCLASSA wc =
     {
         0,
-        DefWindowProc,
+        DefWindowProcA,
         0,
         0,
-        GetModuleHandle(NULL),
+        GetModuleHandleA(NULL),
         NULL,
-        LoadCursor(NULL, IDC_ARROW),
+        LoadCursorA(NULL, (LPSTR)IDC_ARROW),
         (HBRUSH)(COLOR_BTNFACE+1),
         NULL,
-        TEXT("WineOleTestClass"),
+        "WineOleTestClass",
     };
 
-    return RegisterClass(&wc);
+    return RegisterClassA(&wc);
 }
 
 static void test_ole_menu(void)
@@ -678,7 +791,7 @@ static void test_ole_menu(void)
        HWND hwndFrame;
        HRESULT hr;
 
-       hwndFrame = CreateWindow(MAKEINTATOM(register_dummy_class()), "Test", 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, NULL);
+       hwndFrame = CreateWindowA((LPCSTR)MAKEINTATOM(register_dummy_class()), "Test", 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, NULL);
        hr = OleSetMenuDescriptor(NULL, hwndFrame, NULL, NULL, NULL);
        todo_wine ok_ole_success(hr, "OleSetMenuDescriptor");
 
@@ -974,8 +1087,8 @@ static void test_CoGetPSClsid(void)
     hr = CoGetPSClsid(&IID_IClassFactory, &clsid);
     ok_ole_success(hr, "CoGetPSClsid");
 
-    res = RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\Classes", 0, NULL, 0,
-                         KEY_ALL_ACCESS, NULL, &hkey, NULL);
+    res = RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Classes", 0, NULL, 0,
+                          KEY_ALL_ACCESS, NULL, &hkey, NULL);
     ok(!res, "RegCreateKeyEx returned %d\n", res);
 
     res = pRegOverridePredefKey(HKEY_CLASSES_ROOT, hkey);
@@ -995,27 +1108,34 @@ static void test_CoGetPSClsid(void)
 
     if ((handle = activate_context(actctx_manifest, &cookie)))
     {
-todo_wine {
         memset(&clsid, 0, sizeof(clsid));
         hr = CoGetPSClsid(&IID_Testiface, &clsid);
         ok(hr == S_OK, "got 0x%08x\n", hr);
-        ok(IsEqualGUID(&clsid, &IID_Testiface), "got clsid %s\n", debugstr_guid(&clsid));
+        ok(IsEqualGUID(&clsid, &IID_Testiface), "got clsid %s\n", wine_dbgstr_guid(&clsid));
 
         memset(&clsid, 0, sizeof(clsid));
         hr = CoGetPSClsid(&IID_Testiface2, &clsid);
         ok(hr == S_OK, "got 0x%08x\n", hr);
-        ok(IsEqualGUID(&clsid, &IID_Testiface2), "got clsid %s\n", debugstr_guid(&clsid));
+        ok(IsEqualGUID(&clsid, &IID_Testiface2), "got clsid %s\n", wine_dbgstr_guid(&clsid));
 
         memset(&clsid, 0, sizeof(clsid));
         hr = CoGetPSClsid(&IID_Testiface3, &clsid);
         ok(hr == S_OK, "got 0x%08x\n", hr);
-        ok(IsEqualGUID(&clsid, &IID_TestPS), "got clsid %s\n", debugstr_guid(&clsid));
+        ok(IsEqualGUID(&clsid, &IID_TestPS), "got clsid %s\n", wine_dbgstr_guid(&clsid));
 
         memset(&clsid, 0xaa, sizeof(clsid));
         hr = CoGetPSClsid(&IID_Testiface4, &clsid);
         ok(hr == S_OK, "got 0x%08x\n", hr);
-        ok(IsEqualGUID(&clsid, &GUID_NULL), "got clsid %s\n", debugstr_guid(&clsid));
-}
+        ok(IsEqualGUID(&clsid, &GUID_NULL), "got clsid %s\n", wine_dbgstr_guid(&clsid));
+
+        /* register same interface and try to get CLSID back */
+        hr = CoRegisterPSClsid(&IID_Testiface, &IID_Testiface4);
+        ok(hr == S_OK, "got 0x%08x\n", hr);
+        memset(&clsid, 0, sizeof(clsid));
+        hr = CoGetPSClsid(&IID_Testiface, &clsid);
+        ok(hr == S_OK, "got 0x%08x\n", hr);
+        ok(IsEqualGUID(&clsid, &IID_Testiface4), "got clsid %s\n", wine_dbgstr_guid(&clsid));
+
         pDeactivateActCtx(0, cookie);
         pReleaseActCtx(handle);
     }
@@ -1138,6 +1258,8 @@ static void test_CoMarshalInterThreadInterfaceInStream(void)
 
 static void test_CoRegisterClassObject(void)
 {
+    ULONG_PTR ctxcookie;
+    HANDLE handle;
     DWORD cookie;
     HRESULT hr;
     IClassFactory *pcf;
@@ -1213,6 +1335,33 @@ static void test_CoRegisterClassObject(void)
     if (0)
         CoRevokeClassObject(cookie);
 
+    /* test that object is accessible */
+    hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory, CLSCTX_INPROC_SERVER,
+        REGCLS_MULTIPLEUSE, &cookie);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER, NULL, &IID_IClassFactory, (void**)&pcf);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    IClassFactory_Release(pcf);
+
+    /* context now contains CLSID_WineOOPTest, test if registered one could still be used */
+    if ((handle = activate_context(actctx_manifest, &ctxcookie)))
+    {
+        hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER, NULL, &IID_IClassFactory, (void**)&pcf);
+todo_wine
+        ok(hr == HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND), "got 0x%08x\n", hr);
+
+        pDeactivateActCtx(0, ctxcookie);
+        pReleaseActCtx(handle);
+    }
+
+    hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER, NULL, &IID_IClassFactory, (void**)&pcf);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    IClassFactory_Release(pcf);
+
+    hr = CoRevokeClassObject(cookie);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
     CoUninitialize();
 }
 
@@ -1394,7 +1543,7 @@ static DWORD CALLBACK free_libraries_thread(LPVOID p)
 
 static inline BOOL is_module_loaded(const char *module)
 {
-    return GetModuleHandle(module) != 0;
+    return GetModuleHandleA(module) != 0;
 }
 
 static void test_CoFreeUnusedLibraries(void)
@@ -1466,10 +1615,10 @@ static void test_CoGetObjectContext(void)
     /* show that COM doesn't have to be initialized for multi-threaded apartments if another
        thread has already done so */
 
-    info.wait = CreateEvent(NULL, TRUE, FALSE, NULL);
+    info.wait = CreateEventA(NULL, TRUE, FALSE, NULL);
     ok(info.wait != NULL, "CreateEvent failed with error %d\n", GetLastError());
 
-    info.stop = CreateEvent(NULL, TRUE, FALSE, NULL);
+    info.stop = CreateEventA(NULL, TRUE, FALSE, NULL);
     ok(info.stop != NULL, "CreateEvent failed with error %d\n", GetLastError());
 
     thread = CreateThread(NULL, 0, ole_initialize_thread, &info, 0, &tid);
@@ -1685,10 +1834,10 @@ static void test_CoGetContextToken(void)
     /* show that COM doesn't have to be initialized for multi-threaded apartments if another
        thread has already done so */
 
-    info.wait = CreateEvent(NULL, TRUE, FALSE, NULL);
+    info.wait = CreateEventA(NULL, TRUE, FALSE, NULL);
     ok(info.wait != NULL, "CreateEvent failed with error %d\n", GetLastError());
 
-    info.stop = CreateEvent(NULL, TRUE, FALSE, NULL);
+    info.stop = CreateEventA(NULL, TRUE, FALSE, NULL);
     ok(info.stop != NULL, "CreateEvent failed with error %d\n", GetLastError());
 
     thread = CreateThread(NULL, 0, ole_initialize_thread, &info, 0, &tid);
@@ -1817,21 +1966,18 @@ static void test_OleRegGetMiscStatus(void)
     {
         status = 0;
         hr = OleRegGetMiscStatus(&CLSID_Testclass, DVASPECT_ICON, &status);
-todo_wine {
         ok(hr == S_OK, "got 0x%08x\n", hr);
         ok(status == OLEMISC_RECOMPOSEONRESIZE, "got 0x%08x\n", status);
-}
+
         /* context data takes precedence over registration info */
         status = 0;
         hr = OleRegGetMiscStatus(&CLSID_StdFont, DVASPECT_ICON, &status);
         ok(hr == S_OK, "got 0x%08x\n", hr);
-todo_wine
         ok(status == OLEMISC_RECOMPOSEONRESIZE, "got 0x%08x\n", status);
 
         /* there's no such attribute in context */
         status = -1;
         hr = OleRegGetMiscStatus(&CLSID_Testclass, DVASPECT_DOCPRINT, &status);
-todo_wine
         ok(hr == S_OK, "got 0x%08x\n", hr);
         ok(status == 0, "got 0x%08x\n", status);
 
@@ -1869,9 +2015,13 @@ START_TEST(compobj)
         return;
     }
 
+    if (!pCreateActCtxW)
+        win_skip("Activation contexts are not supported, some tests will be skipped.\n");
+
     test_ProgIDFromCLSID();
     test_CLSIDFromProgID();
     test_CLSIDFromString();
+    test_IIDFromString();
     test_StringFromGUID2();
     test_CoCreateInstance();
     test_ole_menu();
index 619393f..d8119b1 100644 (file)
@@ -69,18 +69,6 @@ DEFINE_EXPECT(CF_QueryInterface_ClassFactory);
 DEFINE_EXPECT(CF_CreateInstance);
 DEFINE_EXPECT(CF_QueryInterface_IMarshal);
 
-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 create_storage(IStorage **stg)
 {
     HRESULT hr;
@@ -199,7 +187,7 @@ static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID r
         return S_OK;
     }
 
-    ok(0, "unexpected interface: %s\n", debugstr_guid(riid));
+    ok(0, "unexpected interface: %s\n", wine_dbgstr_guid(riid));
     *ppv = NULL;
     return E_NOINTERFACE;
 }
@@ -220,7 +208,7 @@ static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface,
     CHECK_EXPECT(CF_CreateInstance);
 
     ok(pUnkOuter == NULL, "pUnkOuter != NULL\n");
-    todo_wine ok(IsEqualGUID(riid, &IID_IUnknown), "riid = %s\n", debugstr_guid(riid));
+    todo_wine ok(IsEqualGUID(riid, &IID_IUnknown), "riid = %s\n", wine_dbgstr_guid(riid));
     if(IsEqualGUID(riid, &IID_IOleObject)) {
         *ppv = NULL;
         return E_NOINTERFACE;
@@ -257,7 +245,7 @@ static void test_default_handler_run(void)
     DWORD class_reg;
     HRESULT hres;
 
-    if(!GetProcAddress(GetModuleHandle("ole32"), "CoRegisterSurrogateEx")) {
+    if(!GetProcAddress(GetModuleHandleA("ole32"), "CoRegisterSurrogateEx")) {
         win_skip("skipping OleCreateDefaultHandler tests\n");
         return;
     }
index 83a7872..20ed864 100644 (file)
 
 #include <wine/test.h>
 
+#define DEFINE_EXPECT(func) \
+    static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
+
+#define SET_EXPECT(func) \
+    expect_ ## func = TRUE
+
+#define CHECK_EXPECT2(func) \
+    do { \
+        ok(expect_ ##func, "unexpected call " #func "\n"); \
+        called_ ## func = TRUE; \
+    }while(0)
+
+#define CHECK_EXPECT(func) \
+    do { \
+        CHECK_EXPECT2(func); \
+        expect_ ## func = FALSE; \
+    }while(0)
+
+#define CHECK_CALLED(func) \
+    do { \
+        ok(called_ ## func, "expected " #func "\n"); \
+        expect_ ## func = called_ ## func = FALSE; \
+    }while(0)
+
+DEFINE_EXPECT(DataObject_EnumFormatEtc);
+DEFINE_EXPECT(EnumFORMATETC_Next);
+DEFINE_EXPECT(EnumFORMATETC_Reset);
+DEFINE_EXPECT(DataObject_QueryGetData);
+DEFINE_EXPECT(DropSource_QueryContinueDrag);
+DEFINE_EXPECT(DropTarget_DragEnter);
+DEFINE_EXPECT(DropSource_GiveFeedback);
+DEFINE_EXPECT(DropTarget_Drop);
+DEFINE_EXPECT(DropTarget_DragLeave);
+
 static int droptarget_refs;
 
 /* helper macros to make tests a bit leaner */
@@ -73,7 +107,9 @@ static HRESULT WINAPI DropTarget_DragEnter(IDropTarget* iface,
                                            DWORD grfKeyState, POINTL pt,
                                            DWORD* pdwEffect)
 {
-    return E_NOTIMPL;
+    CHECK_EXPECT(DropTarget_DragEnter);
+    *pdwEffect = DROPEFFECT_COPY;
+    return S_OK;
 }
 
 static HRESULT WINAPI DropTarget_DragOver(IDropTarget* iface,
@@ -81,11 +117,14 @@ static HRESULT WINAPI DropTarget_DragOver(IDropTarget* iface,
                                           POINTL pt,
                                           DWORD* pdwEffect)
 {
-    return E_NOTIMPL;
+    ok(0, "unexpected call\n");
+    *pdwEffect = DROPEFFECT_COPY;
+    return S_OK;
 }
 
 static HRESULT WINAPI DropTarget_DragLeave(IDropTarget* iface)
 {
+    CHECK_EXPECT(DropTarget_DragLeave);
     return E_NOTIMPL;
 }
 
@@ -93,7 +132,8 @@ static HRESULT WINAPI DropTarget_Drop(IDropTarget* iface,
                                       IDataObject* pDataObj, DWORD grfKeyState,
                                       POINTL pt, DWORD* pdwEffect)
 {
-    return E_NOTIMPL;
+    CHECK_EXPECT(DropTarget_Drop);
+    return 0xbeefbeef;
 }
 
 static const IDropTargetVtbl DropTarget_VTbl =
@@ -109,7 +149,6 @@ static const IDropTargetVtbl DropTarget_VTbl =
 
 static IDropTarget DropTarget = { &DropTarget_VTbl };
 
-/** stub IDropSource **/
 static HRESULT WINAPI DropSource_QueryInterface(IDropSource *iface, REFIID riid, void **ppObj)
 {
     if (IsEqualIID(riid, &IID_IUnknown) ||
@@ -137,7 +176,7 @@ static HRESULT WINAPI DropSource_QueryContinueDrag(
     BOOL fEscapePressed,
     DWORD grfKeyState)
 {
-    /* always drop */
+    CHECK_EXPECT(DropSource_QueryContinueDrag);
     return DRAGDROP_S_DROP;
 }
 
@@ -145,6 +184,7 @@ static HRESULT WINAPI DropSource_GiveFeedback(
     IDropSource *iface,
     DWORD dwEffect)
 {
+    CHECK_EXPECT(DropSource_GiveFeedback);
     return DRAGDROP_S_USEDEFAULTCURSORS;
 }
 
@@ -158,7 +198,75 @@ static const IDropSourceVtbl dropsource_vtbl = {
 
 static IDropSource DropSource = { &dropsource_vtbl };
 
-/** IDataObject stub **/
+static HRESULT WINAPI EnumFORMATETC_QueryInterface(IEnumFORMATETC *iface,
+        REFIID riid, void **ppvObj)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static ULONG WINAPI EnumFORMATETC_AddRef(IEnumFORMATETC *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI EnumFORMATETC_Release(IEnumFORMATETC *iface)
+{
+    return 1;
+}
+
+static BOOL formats_enumerated;
+static HRESULT WINAPI EnumFORMATETC_Next(IEnumFORMATETC *iface,
+        ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched)
+{
+    static FORMATETC format = { CF_TEXT, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
+
+    CHECK_EXPECT2(EnumFORMATETC_Next);
+
+    ok(celt == 1, "celt = %d\n", celt);
+    ok(rgelt != NULL, "rgelt == NULL\n");
+    ok(pceltFetched == NULL, "pceltFetched != NULL\n");
+
+    if(formats_enumerated)
+        return S_FALSE;
+
+    *rgelt = format;
+    formats_enumerated = TRUE;
+    return S_OK;
+}
+
+static HRESULT WINAPI EnumFORMATETC_Skip(IEnumFORMATETC *iface, ULONG celt)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI EnumFORMATETC_Reset(IEnumFORMATETC *iface)
+{
+    CHECK_EXPECT(EnumFORMATETC_Reset);
+    formats_enumerated = FALSE;
+    return S_OK;
+}
+
+static HRESULT WINAPI EnumFORMATETC_Clone(IEnumFORMATETC *iface,
+        IEnumFORMATETC **ppenum)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static const IEnumFORMATETCVtbl enumformatetc_vtbl = {
+    EnumFORMATETC_QueryInterface,
+    EnumFORMATETC_AddRef,
+    EnumFORMATETC_Release,
+    EnumFORMATETC_Next,
+    EnumFORMATETC_Skip,
+    EnumFORMATETC_Reset,
+    EnumFORMATETC_Clone
+};
+
+static IEnumFORMATETC EnumFORMATETC = { &enumformatetc_vtbl };
+
 static HRESULT WINAPI DataObject_QueryInterface(
     IDataObject *iface,
     REFIID riid,
@@ -171,6 +279,8 @@ static HRESULT WINAPI DataObject_QueryInterface(
         IDataObject_AddRef(iface);
         return S_OK;
     }
+
+    trace("DataObject_QueryInterface: %s\n", wine_dbgstr_guid(riid));
     return E_NOINTERFACE;
 }
 
@@ -189,6 +299,7 @@ static HRESULT WINAPI DataObject_GetData(
     FORMATETC *pformatetcIn,
     STGMEDIUM *pmedium)
 {
+    ok(0, "unexpected call\n");
     return E_NOTIMPL;
 }
 
@@ -197,6 +308,7 @@ static HRESULT WINAPI DataObject_GetDataHere(
     FORMATETC *pformatetc,
     STGMEDIUM *pmedium)
 {
+    ok(0, "unexpected call\n");
     return E_NOTIMPL;
 }
 
@@ -204,6 +316,7 @@ static HRESULT WINAPI DataObject_QueryGetData(
     IDataObject *iface,
     FORMATETC *pformatetc)
 {
+    CHECK_EXPECT(DataObject_QueryGetData);
     return S_OK;
 }
 
@@ -212,6 +325,7 @@ static HRESULT WINAPI DataObject_GetCanonicalFormatEtc(
     FORMATETC *pformatectIn,
     FORMATETC *pformatetcOut)
 {
+    ok(0, "unexpected call\n");
     return E_NOTIMPL;
 }
 
@@ -221,6 +335,7 @@ static HRESULT WINAPI DataObject_SetData(
     STGMEDIUM *pmedium,
     BOOL fRelease)
 {
+    ok(0, "unexpected call\n");
     return E_NOTIMPL;
 }
 
@@ -229,6 +344,9 @@ static HRESULT WINAPI DataObject_EnumFormatEtc(
     DWORD dwDirection,
     IEnumFORMATETC **ppenumFormatEtc)
 {
+    CHECK_EXPECT(DataObject_EnumFormatEtc);
+    *ppenumFormatEtc = &EnumFORMATETC;
+    formats_enumerated = FALSE;
     return S_OK;
 }
 
@@ -239,6 +357,7 @@ static HRESULT WINAPI DataObject_DAdvise(
     IAdviseSink *pAdvSink,
     DWORD *pdwConnection)
 {
+    ok(0, "unexpected call\n");
     return E_NOTIMPL;
 }
 
@@ -246,6 +365,7 @@ static HRESULT WINAPI DataObject_DUnadvise(
     IDataObject *iface,
     DWORD dwConnection)
 {
+    ok(0, "unexpected call\n");
     return E_NOTIMPL;
 }
 
@@ -253,6 +373,7 @@ static HRESULT WINAPI DataObject_EnumDAdvise(
     IDataObject *iface,
     IEnumSTATDATA **ppenumAdvise)
 {
+    ok(0, "unexpected call\n");
     return E_NOTIMPL;
 }
 
@@ -275,21 +396,21 @@ static IDataObject DataObject = { &dataobject_vtbl };
 
 static ATOM register_dummy_class(void)
 {
-    WNDCLASS wc =
+    WNDCLASSA wc =
     {
         0,
-        DefWindowProc,
+        DefWindowProcA,
         0,
         0,
-        GetModuleHandle(NULL),
+        GetModuleHandleA(NULL),
         NULL,
-        LoadCursor(NULL, IDC_ARROW),
+        LoadCursorA(NULL, (LPSTR)IDC_ARROW),
         (HBRUSH)(COLOR_BTNFACE+1),
         NULL,
-        TEXT("WineOleTestClass"),
+        "WineOleTestClass",
     };
 
-    return RegisterClass(&wc);
+    return RegisterClassA(&wc);
 }
 
 static void test_Register_Revoke(void)
@@ -367,9 +488,10 @@ static void test_DoDragDrop(void)
     DWORD effect;
     HRESULT hr;
     HWND hwnd;
+    RECT rect;
 
-    hwnd = CreateWindowA("WineOleTestClass", "Test", 0,
-        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL,
+    hwnd = CreateWindowExA(WS_EX_TOPMOST, "WineOleTestClass", "Test", 0,
+        CW_USEDEFAULT, CW_USEDEFAULT, 100, 100, NULL,
         NULL, NULL, NULL);
     ok(IsWindow(hwnd), "failed to create window\n");
 
@@ -401,6 +523,47 @@ static void test_DoDragDrop(void)
     hr = DoDragDrop(&DataObject, NULL, 0, &effect);
     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
 
+    ShowWindow(hwnd, SW_SHOW);
+    GetWindowRect(hwnd, &rect);
+    ok(SetCursorPos(rect.left+50, rect.top+50), "SetCursorPos failed\n");
+    SET_EXPECT(DataObject_EnumFormatEtc);
+    SET_EXPECT(EnumFORMATETC_Next);
+    SET_EXPECT(EnumFORMATETC_Reset);
+    SET_EXPECT(DataObject_QueryGetData);
+    SET_EXPECT(DropSource_QueryContinueDrag);
+    SET_EXPECT(DropTarget_DragEnter);
+    SET_EXPECT(DropSource_GiveFeedback);
+    SET_EXPECT(DropTarget_Drop);
+    hr = DoDragDrop(&DataObject, &DropSource, DROPEFFECT_COPY, &effect);
+    ok(hr == 0xbeefbeef, "got 0x%08x\n", hr);
+    todo_wine CHECK_CALLED(DataObject_EnumFormatEtc);
+    todo_wine CHECK_CALLED(EnumFORMATETC_Next);
+    todo_wine CHECK_CALLED(EnumFORMATETC_Reset);
+    todo_wine CHECK_CALLED(DataObject_QueryGetData);
+    CHECK_CALLED(DropSource_QueryContinueDrag);
+    CHECK_CALLED(DropTarget_DragEnter);
+    CHECK_CALLED(DropSource_GiveFeedback);
+    CHECK_CALLED(DropTarget_Drop);
+
+    SET_EXPECT(DataObject_EnumFormatEtc);
+    SET_EXPECT(EnumFORMATETC_Next);
+    SET_EXPECT(EnumFORMATETC_Reset);
+    SET_EXPECT(DataObject_QueryGetData);
+    SET_EXPECT(DropSource_QueryContinueDrag);
+    SET_EXPECT(DropTarget_DragEnter);
+    SET_EXPECT(DropSource_GiveFeedback);
+    SET_EXPECT(DropTarget_DragLeave);
+    hr = DoDragDrop(&DataObject, &DropSource, 0, &effect);
+    ok(hr == DRAGDROP_S_DROP, "got 0x%08x\n", hr);
+    todo_wine CHECK_CALLED(DataObject_EnumFormatEtc);
+    todo_wine CHECK_CALLED(EnumFORMATETC_Next);
+    todo_wine CHECK_CALLED(EnumFORMATETC_Reset);
+    todo_wine CHECK_CALLED(DataObject_QueryGetData);
+    CHECK_CALLED(DropSource_QueryContinueDrag);
+    CHECK_CALLED(DropTarget_DragEnter);
+    CHECK_CALLED(DropSource_GiveFeedback);
+    CHECK_CALLED(DropTarget_DragLeave);
+
     OleUninitialize();
 
     DestroyWindow(hwnd);
index 9430ff9..fd1ddc0 100644 (file)
@@ -53,6 +53,9 @@ static HRESULT (WINAPI *pDllGetClassObject)(REFCLSID,REFIID,LPVOID);
 #define ok_more_than_one_lock() ok(cLocks > 0, "Number of locks should be > 0, but actually is %d\n", cLocks)
 #define ok_no_locks() ok(cLocks == 0, "Number of locks should be 0, but actually is %d\n", cLocks)
 #define ok_ole_success(hr, func) ok(hr == S_OK, #func " failed with error 0x%08x\n", hr)
+#define ok_non_zero_external_conn() do {if (with_external_conn) ok(external_connections, "got no external connections\n");} while(0);
+#define ok_zero_external_conn() do {if (with_external_conn) ok(!external_connections, "got %d external connections\n", external_connections);} while(0);
+#define ok_last_release_closes(b) do {if (with_external_conn) ok(last_release_closes == b, "got %d expected %d\n", last_release_closes, b);} while(0);
 
 static const IID IID_IWineTest =
 {
@@ -113,6 +116,52 @@ static void UnlockModule(void)
     InterlockedDecrement(&cLocks);
 }
 
+static BOOL with_external_conn;
+static DWORD external_connections;
+static BOOL last_release_closes;
+
+static HRESULT WINAPI ExternalConnection_QueryInterface(IExternalConnection *iface, REFIID riid, void **ppv)
+{
+    ok(0, "unxpected call\n");
+    *ppv = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI ExternalConnection_AddRef(IExternalConnection *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI ExternalConnection_Release(IExternalConnection *iface)
+{
+    return 1;
+}
+
+static DWORD WINAPI ExternalConnection_AddConnection(IExternalConnection *iface, DWORD extconn, DWORD reserved)
+{
+    trace("add connection\n");
+    return ++external_connections;
+}
+
+
+static DWORD WINAPI ExternalConnection_ReleaseConnection(IExternalConnection *iface, DWORD extconn,
+        DWORD reserved, BOOL fLastReleaseCloses)
+{
+    trace("release connection %d\n", fLastReleaseCloses);
+    last_release_closes = fLastReleaseCloses;
+    return --external_connections;
+}
+
+static const IExternalConnectionVtbl ExternalConnectionVtbl = {
+    ExternalConnection_QueryInterface,
+    ExternalConnection_AddRef,
+    ExternalConnection_Release,
+    ExternalConnection_AddConnection,
+    ExternalConnection_ReleaseConnection
+};
+
+static IExternalConnection ExternalConnection = { &ExternalConnectionVtbl };
+
 
 static HRESULT WINAPI Test_IUnknown_QueryInterface(
     LPUNKNOWN iface,
@@ -171,6 +220,12 @@ static HRESULT WINAPI Test_IClassFactory_QueryInterface(
         return S_OK;
     }
 
+    if (with_external_conn && IsEqualGUID(riid, &IID_IExternalConnection))
+    {
+        *ppvObj = &ExternalConnection;
+        return S_OK;
+    }
+
     *ppvObj = NULL;
     return E_NOINTERFACE;
 }
@@ -247,11 +302,11 @@ static DWORD CALLBACK host_object_proc(LPVOID p)
     ok_ole_success(hr, CoMarshalInterface);
 
     /* force the message queue to be created before signaling parent thread */
-    PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
+    PeekMessageA(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
 
     SetEvent(data->marshal_event);
 
-    while (GetMessage(&msg, NULL, 0, 0))
+    while (GetMessageA(&msg, NULL, 0, 0))
     {
         if (msg.hwnd == NULL && msg.message == RELEASEMARSHALDATA)
         {
@@ -259,7 +314,7 @@ static DWORD CALLBACK host_object_proc(LPVOID p)
             SetEvent((HANDLE)msg.lParam);
         }
         else
-            DispatchMessage(&msg);
+            DispatchMessageA(&msg);
     }
 
     HeapFree(GetProcessHeap(), 0, data);
@@ -272,7 +327,7 @@ static DWORD CALLBACK host_object_proc(LPVOID p)
 static DWORD start_host_object2(IStream *stream, REFIID riid, IUnknown *object, MSHLFLAGS marshal_flags, IMessageFilter *filter, HANDLE *thread)
 {
     DWORD tid = 0;
-    HANDLE marshal_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+    HANDLE marshal_event = CreateEventA(NULL, FALSE, FALSE, NULL);
     struct host_object_data *data = HeapAlloc(GetProcessHeap(), 0, sizeof(*data));
 
     data->stream = stream;
@@ -298,17 +353,17 @@ static DWORD start_host_object(IStream *stream, REFIID riid, IUnknown *object, M
 
 /* asks thread to release the marshal data because it has to be done by the
  * same thread that marshaled the interface in the first place. */
-static void release_host_object(DWORD tid)
+static void release_host_object(DWORD tid, WPARAM wp)
 {
-    HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL);
-    PostThreadMessage(tid, RELEASEMARSHALDATA, 0, (LPARAM)event);
+    HANDLE event = CreateEventA(NULL, FALSE, FALSE, NULL);
+    PostThreadMessageA(tid, RELEASEMARSHALDATA, wp, (LPARAM)event);
     ok( !WaitForSingleObject(event, 10000), "wait timed out\n" );
     CloseHandle(event);
 }
 
 static void end_host_object(DWORD tid, HANDLE thread)
 {
-    BOOL ret = PostThreadMessage(tid, WM_QUIT, 0, 0);
+    BOOL ret = PostThreadMessageA(tid, WM_QUIT, 0, 0);
     ok(ret, "PostThreadMessage failed with error %d\n", GetLastError());
     /* be careful of races - don't return until hosting thread has terminated */
     ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
@@ -337,6 +392,7 @@ static void test_normal_marshal_and_release(void)
     IStream *pStream = NULL;
 
     cLocks = 0;
+    external_connections = 0;
 
     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
     ok_ole_success(hr, CreateStreamOnHGlobal);
@@ -344,6 +400,7 @@ static void test_normal_marshal_and_release(void)
     ok_ole_success(hr, CoMarshalInterface);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
 
     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
     hr = CoReleaseMarshalData(pStream);
@@ -351,6 +408,8 @@ static void test_normal_marshal_and_release(void)
     IStream_Release(pStream);
 
     ok_no_locks();
+    ok_zero_external_conn();
+    ok_last_release_closes(TRUE);
 }
 
 /* tests success case of a same-thread marshal and unmarshal */
@@ -361,6 +420,7 @@ static void test_normal_marshal_and_unmarshal(void)
     IUnknown *pProxy = NULL;
 
     cLocks = 0;
+    external_connections = 0;
 
     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
     ok_ole_success(hr, CreateStreamOnHGlobal);
@@ -368,6 +428,7 @@ static void test_normal_marshal_and_unmarshal(void)
     ok_ole_success(hr, CoMarshalInterface);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
     
     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
@@ -375,6 +436,8 @@ static void test_normal_marshal_and_unmarshal(void)
     IStream_Release(pStream);
 
     ok_more_than_one_lock();
+    ok_zero_external_conn();
+    ok_last_release_closes(FALSE);
 
     IUnknown_Release(pProxy);
 
@@ -392,18 +455,22 @@ static void test_marshal_and_unmarshal_invalid(void)
     HANDLE thread;
 
     cLocks = 0;
+    external_connections = 0;
 
     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
     ok_ole_success(hr, CreateStreamOnHGlobal);
     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
 
     ok_more_than_one_lock();
-       
+    ok_non_zero_external_conn();
+
     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
     hr = CoReleaseMarshalData(pStream);
     ok_ole_success(hr, CoReleaseMarshalData);
 
     ok_no_locks();
+    ok_zero_external_conn();
+    ok_last_release_closes(TRUE);
 
     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
@@ -432,6 +499,7 @@ static void test_same_apartment_unmarshal_failure(void)
     static const LARGE_INTEGER llZero;
 
     cLocks = 0;
+    external_connections = 0;
 
     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
     ok_ole_success(hr, CreateStreamOnHGlobal);
@@ -440,6 +508,7 @@ static void test_same_apartment_unmarshal_failure(void)
     ok_ole_success(hr, CoMarshalInterface);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
 
     hr = IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
     ok_ole_success(hr, IStream_Seek);
@@ -448,6 +517,8 @@ static void test_same_apartment_unmarshal_failure(void)
     ok(hr == E_NOINTERFACE, "CoUnmarshalInterface should have returned E_NOINTERFACE instead of 0x%08x\n", hr);
 
     ok_no_locks();
+    ok_zero_external_conn();
+    ok_last_release_closes(FALSE);
 
     IStream_Release(pStream);
 }
@@ -462,12 +533,14 @@ static void test_interthread_marshal_and_unmarshal(void)
     HANDLE thread;
 
     cLocks = 0;
+    external_connections = 0;
 
     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
     ok_ole_success(hr, CreateStreamOnHGlobal);
     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
     
     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
@@ -475,10 +548,13 @@ static void test_interthread_marshal_and_unmarshal(void)
     IStream_Release(pStream);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
 
     IUnknown_Release(pProxy);
 
     ok_no_locks();
+    ok_zero_external_conn();
+    ok_last_release_closes(TRUE);
 
     end_host_object(tid, thread);
 }
@@ -499,12 +575,14 @@ static void test_proxy_marshal_and_unmarshal(void)
     int i;
 
     cLocks = 0;
+    external_connections = 0;
 
     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
     ok_ole_success(hr, CreateStreamOnHGlobal);
     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
     
     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
@@ -537,6 +615,7 @@ static void test_proxy_marshal_and_unmarshal(void)
     ok_ole_success(hr, CoUnmarshalInterface);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
 
     IUnknown_Release(pProxy2);
 
@@ -550,6 +629,8 @@ static void test_proxy_marshal_and_unmarshal(void)
     }
 
     ok_no_locks();
+    ok_zero_external_conn();
+    ok_last_release_closes(TRUE);
 
     IStream_Release(pStream);
 
@@ -568,12 +649,14 @@ static void test_proxy_marshal_and_unmarshal2(void)
     HANDLE thread;
 
     cLocks = 0;
+    external_connections = 0;
 
     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
     ok_ole_success(hr, CreateStreamOnHGlobal);
     tid = start_host_object(pStream, &IID_IUnknown, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
 
     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
     hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
@@ -608,10 +691,13 @@ static void test_proxy_marshal_and_unmarshal2(void)
     IUnknown_Release(pProxy);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
 
     IUnknown_Release(pProxy2);
 
     ok_no_locks();
+    ok_zero_external_conn();
+    ok_last_release_closes(TRUE);
 
     end_host_object(tid, thread);
 }
@@ -627,18 +713,21 @@ static void test_proxy_marshal_and_unmarshal_weak(void)
     HANDLE thread;
 
     cLocks = 0;
+    external_connections = 0;
 
     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
     ok_ole_success(hr, CreateStreamOnHGlobal);
     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
 
     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
     ok_ole_success(hr, CoUnmarshalInterface);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
 
     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
     /* marshal the proxy */
@@ -646,6 +735,7 @@ static void test_proxy_marshal_and_unmarshal_weak(void)
     ok_ole_success(hr, CoMarshalInterface);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
 
     /* release the original proxy to test that we successfully keep the
      * original object alive */
@@ -657,6 +747,8 @@ static void test_proxy_marshal_and_unmarshal_weak(void)
     ok(hr == CO_E_OBJNOTREG, "CoUnmarshalInterface should return CO_E_OBJNOTREG instead of 0x%08x\n", hr);
 
     ok_no_locks();
+    ok_zero_external_conn();
+    ok_last_release_closes(TRUE);
 
     IStream_Release(pStream);
 
@@ -674,18 +766,21 @@ static void test_proxy_marshal_and_unmarshal_strong(void)
     HANDLE thread;
 
     cLocks = 0;
+    external_connections = 0;
 
     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
     ok_ole_success(hr, CreateStreamOnHGlobal);
     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
 
     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
     ok_ole_success(hr, CoUnmarshalInterface);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
 
     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
     /* marshal the proxy */
@@ -699,6 +794,7 @@ static void test_proxy_marshal_and_unmarshal_strong(void)
     }
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
 
     /* release the original proxy to test that we successfully keep the
      * original object alive */
@@ -709,10 +805,12 @@ static void test_proxy_marshal_and_unmarshal_strong(void)
     ok_ole_success(hr, CoUnmarshalInterface);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
 
     IUnknown_Release(pProxy2);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
 
 end:
     IStream_Release(pStream);
@@ -720,6 +818,10 @@ end:
     end_host_object(tid, thread);
 
     ok_no_locks();
+todo_wine {
+    ok_zero_external_conn();
+    ok_last_release_closes(FALSE);
+}
 }
 
 /* tests that stubs are released when the containing apartment is destroyed */
@@ -732,12 +834,14 @@ static void test_marshal_stub_apartment_shutdown(void)
     HANDLE thread;
 
     cLocks = 0;
+    external_connections = 0;
 
     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
     ok_ole_success(hr, CreateStreamOnHGlobal);
     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
     
     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
@@ -745,10 +849,15 @@ static void test_marshal_stub_apartment_shutdown(void)
     IStream_Release(pStream);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
 
     end_host_object(tid, thread);
 
     ok_no_locks();
+todo_wine {
+    ok_zero_external_conn();
+    ok_last_release_closes(FALSE);
+}
 
     IUnknown_Release(pProxy);
 
@@ -765,12 +874,14 @@ static void test_marshal_proxy_apartment_shutdown(void)
     HANDLE thread;
 
     cLocks = 0;
+    external_connections = 0;
 
     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
     ok_ole_success(hr, CreateStreamOnHGlobal);
     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
     
     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
@@ -778,10 +889,13 @@ static void test_marshal_proxy_apartment_shutdown(void)
     IStream_Release(pStream);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
 
     CoUninitialize();
 
     ok_no_locks();
+    ok_zero_external_conn();
+    ok_last_release_closes(TRUE);
 
     IUnknown_Release(pProxy);
 
@@ -805,12 +919,14 @@ static void test_marshal_proxy_mta_apartment_shutdown(void)
     pCoInitializeEx(NULL, COINIT_MULTITHREADED);
 
     cLocks = 0;
+    external_connections = 0;
 
     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
     ok_ole_success(hr, CreateStreamOnHGlobal);
     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
 
     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
@@ -818,10 +934,13 @@ static void test_marshal_proxy_mta_apartment_shutdown(void)
     IStream_Release(pStream);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
 
     CoUninitialize();
 
     ok_no_locks();
+    ok_zero_external_conn();
+    ok_last_release_closes(TRUE);
 
     IUnknown_Release(pProxy);
 
@@ -871,9 +990,10 @@ static void test_no_couninitialize_server(void)
     struct ncu_params ncu_params;
 
     cLocks = 0;
+    external_connections = 0;
 
-    ncu_params.marshal_event = CreateEvent(NULL, TRUE, FALSE, NULL);
-    ncu_params.unmarshal_event = CreateEvent(NULL, TRUE, FALSE, NULL);
+    ncu_params.marshal_event = CreateEventA(NULL, TRUE, FALSE, NULL);
+    ncu_params.unmarshal_event = CreateEventA(NULL, TRUE, FALSE, NULL);
 
     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
     ok_ole_success(hr, CreateStreamOnHGlobal);
@@ -883,6 +1003,7 @@ static void test_no_couninitialize_server(void)
 
     ok( !WaitForSingleObject(ncu_params.marshal_event, 10000), "wait timed out\n" );
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
 
     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
@@ -890,11 +1011,16 @@ static void test_no_couninitialize_server(void)
     IStream_Release(pStream);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
 
     SetEvent(ncu_params.unmarshal_event);
     ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
 
     ok_no_locks();
+todo_wine {
+    ok_zero_external_conn();
+    ok_last_release_closes(FALSE);
+}
 
     CloseHandle(thread);
     CloseHandle(ncu_params.marshal_event);
@@ -937,6 +1063,7 @@ static void test_no_couninitialize_client(void)
     struct ncu_params ncu_params;
 
     cLocks = 0;
+    external_connections = 0;
 
     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
     ok_ole_success(hr, CreateStreamOnHGlobal);
@@ -948,6 +1075,7 @@ static void test_no_couninitialize_client(void)
     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
 
     thread = CreateThread(NULL, 0, no_couninitialize_client_proc, &ncu_params, 0, &tid);
 
@@ -955,6 +1083,8 @@ static void test_no_couninitialize_client(void)
     CloseHandle(thread);
 
     ok_no_locks();
+    ok_zero_external_conn();
+    ok_last_release_closes(TRUE);
 
     end_host_object(host_tid, host_thread);
 }
@@ -970,34 +1100,48 @@ static void test_tableweak_marshal_and_unmarshal_twice(void)
     HANDLE thread;
 
     cLocks = 0;
+    external_connections = 0;
 
     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
     ok_ole_success(hr, CreateStreamOnHGlobal);
     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
 
     ok_more_than_one_lock();
+    ok_zero_external_conn();
 
     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
     ok_ole_success(hr, CoUnmarshalInterface);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
 
     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
-    IStream_Release(pStream);
     ok_ole_success(hr, CoUnmarshalInterface);
 
     ok_more_than_one_lock();
 
     IUnknown_Release(pProxy1);
+    ok_non_zero_external_conn();
     IUnknown_Release(pProxy2);
+    ok_zero_external_conn();
+    ok_last_release_closes(TRUE);
 
-    /* this line is shows the difference between weak and strong table marshaling:
-     *  weak has cLocks == 0
-     *  strong has cLocks > 0 */
+    /* When IExternalConnection is present COM's lifetime management
+     * behaviour is altered; the remaining weak ref prevents stub shutdown. */
+    if (with_external_conn)
+    {
+        ok_more_than_one_lock();
+        IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
+        release_host_object(tid, 0);
+    }
+
+    /* Without IExternalConnection this line is shows the difference between weak and strong table marshaling
+     * weak has cLocks == 0, strong has cLocks > 0. */
     ok_no_locks();
 
+    IStream_Release(pStream);
     end_host_object(tid, thread);
 }
 
@@ -1012,25 +1156,29 @@ static void test_tableweak_marshal_releasedata1(void)
     HANDLE thread;
 
     cLocks = 0;
+    external_connections = 0;
 
     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
     ok_ole_success(hr, CreateStreamOnHGlobal);
     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
 
     ok_more_than_one_lock();
+    ok_zero_external_conn();
 
     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
     ok_ole_success(hr, CoUnmarshalInterface);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
 
     /* release the remaining reference on the object by calling
      * CoReleaseMarshalData in the hosting thread */
     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
-    release_host_object(tid);
+    release_host_object(tid, 0);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
 
     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
@@ -1038,15 +1186,22 @@ static void test_tableweak_marshal_releasedata1(void)
     IStream_Release(pStream);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
 
     IUnknown_Release(pProxy1);
+
     if (pProxy2)
+    {
+        ok_non_zero_external_conn();
         IUnknown_Release(pProxy2);
+    }
 
     /* this line is shows the difference between weak and strong table marshaling:
      *  weak has cLocks == 0
      *  strong has cLocks > 0 */
     ok_no_locks();
+    ok_zero_external_conn();
+    ok_last_release_closes(TRUE);
 
     end_host_object(tid, thread);
 }
@@ -1061,17 +1216,19 @@ static void test_tableweak_marshal_releasedata2(void)
     HANDLE thread;
 
     cLocks = 0;
+    external_connections = 0;
 
     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
     ok_ole_success(hr, CreateStreamOnHGlobal);
     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
 
     ok_more_than_one_lock();
+    ok_zero_external_conn();
 
     /* release the remaining reference on the object by calling
      * CoReleaseMarshalData in the hosting thread */
     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
-    release_host_object(tid);
+    release_host_object(tid, 0);
 
     ok_no_locks();
 
@@ -1086,42 +1243,51 @@ static void test_tableweak_marshal_releasedata2(void)
     IStream_Release(pStream);
 
     ok_no_locks();
+    ok_zero_external_conn();
 
     end_host_object(tid, thread);
 }
 
-struct weak_and_normal_marshal_data
+struct duo_marshal_data
 {
-    IStream *pStreamWeak;
-    IStream *pStreamNormal;
+    MSHLFLAGS marshal_flags1, marshal_flags2;
+    IStream *pStream1, *pStream2;
     HANDLE hReadyEvent;
     HANDLE hQuitEvent;
 };
 
-static DWORD CALLBACK weak_and_normal_marshal_thread_proc(void *p)
+static DWORD CALLBACK duo_marshal_thread_proc(void *p)
 {
     HRESULT hr;
-    struct weak_and_normal_marshal_data *data = p;
+    struct duo_marshal_data *data = p;
     HANDLE hQuitEvent = data->hQuitEvent;
     MSG msg;
 
     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
 
-    hr = CoMarshalInterface(data->pStreamWeak, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_TABLEWEAK);
+    hr = CoMarshalInterface(data->pStream1, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, data->marshal_flags1);
     ok_ole_success(hr, "CoMarshalInterface");
 
-    hr = CoMarshalInterface(data->pStreamNormal, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
+    hr = CoMarshalInterface(data->pStream2, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, data->marshal_flags2);
     ok_ole_success(hr, "CoMarshalInterface");
 
     /* force the message queue to be created before signaling parent thread */
-    PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
+    PeekMessageA(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
 
     SetEvent(data->hReadyEvent);
 
     while (WAIT_OBJECT_0 + 1 == MsgWaitForMultipleObjects(1, &hQuitEvent, FALSE, 10000, QS_ALLINPUT))
     {
-        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
-            DispatchMessage(&msg);
+        while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
+        {
+            if (msg.hwnd == NULL && msg.message == RELEASEMARSHALDATA)
+            {
+                CoReleaseMarshalData(msg.wParam == 1 ? data->pStream1 : data->pStream2);
+                SetEvent((HANDLE)msg.lParam);
+            }
+            else
+                DispatchMessageA(&msg);
+        }
     }
     CloseHandle(hQuitEvent);
 
@@ -1138,31 +1304,37 @@ static void test_tableweak_and_normal_marshal_and_unmarshal(void)
     IUnknown *pProxyNormal = NULL;
     DWORD tid;
     HANDLE thread;
-    struct weak_and_normal_marshal_data data;
+    struct duo_marshal_data data;
 
     cLocks = 0;
+    external_connections = 0;
 
-    data.hReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
-    data.hQuitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
-    hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStreamWeak);
+    data.hReadyEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
+    data.hQuitEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
+    data.marshal_flags1 = MSHLFLAGS_TABLEWEAK;
+    data.marshal_flags2 = MSHLFLAGS_NORMAL;
+    hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStream1);
     ok_ole_success(hr, CreateStreamOnHGlobal);
-    hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStreamNormal);
+    hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStream2);
     ok_ole_success(hr, CreateStreamOnHGlobal);
 
-    thread = CreateThread(NULL, 0, weak_and_normal_marshal_thread_proc, &data, 0, &tid);
+    thread = CreateThread(NULL, 0, duo_marshal_thread_proc, &data, 0, &tid);
     ok( !WaitForSingleObject(data.hReadyEvent, 10000), "wait timed out\n" );
     CloseHandle(data.hReadyEvent);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
 
-    IStream_Seek(data.pStreamWeak, ullZero, STREAM_SEEK_SET, NULL);
-    hr = CoUnmarshalInterface(data.pStreamWeak, &IID_IClassFactory, (void **)&pProxyWeak);
+    /* weak */
+    IStream_Seek(data.pStream1, ullZero, STREAM_SEEK_SET, NULL);
+    hr = CoUnmarshalInterface(data.pStream1, &IID_IClassFactory, (void **)&pProxyWeak);
     ok_ole_success(hr, CoUnmarshalInterface);
 
     ok_more_than_one_lock();
 
-    IStream_Seek(data.pStreamNormal, ullZero, STREAM_SEEK_SET, NULL);
-    hr = CoUnmarshalInterface(data.pStreamNormal, &IID_IClassFactory, (void **)&pProxyNormal);
+    /* normal */
+    IStream_Seek(data.pStream2, ullZero, STREAM_SEEK_SET, NULL);
+    hr = CoUnmarshalInterface(data.pStream2, &IID_IClassFactory, (void **)&pProxyNormal);
     ok_ole_success(hr, CoUnmarshalInterface);
 
     ok_more_than_one_lock();
@@ -1170,13 +1342,120 @@ static void test_tableweak_and_normal_marshal_and_unmarshal(void)
     IUnknown_Release(pProxyNormal);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
 
     IUnknown_Release(pProxyWeak);
 
+    ok_zero_external_conn();
+    ok_last_release_closes(TRUE);
+
+    /* When IExternalConnection is present COM's lifetime management
+     * behaviour is altered; the remaining weak ref prevents stub shutdown. */
+    if (with_external_conn)
+    {
+        ok_more_than_one_lock();
+        IStream_Seek(data.pStream1, ullZero, STREAM_SEEK_SET, NULL);
+        release_host_object(tid, 1);
+    }
     ok_no_locks();
 
-    IStream_Release(data.pStreamWeak);
-    IStream_Release(data.pStreamNormal);
+    IStream_Release(data.pStream1);
+    IStream_Release(data.pStream2);
+
+    SetEvent(data.hQuitEvent);
+    ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
+    CloseHandle(thread);
+}
+
+static void test_tableweak_and_normal_marshal_and_releasedata(void)
+{
+    HRESULT hr;
+    DWORD tid;
+    HANDLE thread;
+    struct duo_marshal_data data;
+
+    cLocks = 0;
+    external_connections = 0;
+
+    data.hReadyEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
+    data.hQuitEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
+    data.marshal_flags1 = MSHLFLAGS_TABLEWEAK;
+    data.marshal_flags2 = MSHLFLAGS_NORMAL;
+    hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStream1);
+    ok_ole_success(hr, CreateStreamOnHGlobal);
+    hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStream2);
+    ok_ole_success(hr, CreateStreamOnHGlobal);
+
+    thread = CreateThread(NULL, 0, duo_marshal_thread_proc, &data, 0, &tid);
+    ok( !WaitForSingleObject(data.hReadyEvent, 10000), "wait timed out\n" );
+    CloseHandle(data.hReadyEvent);
+
+    ok_more_than_one_lock();
+    ok_non_zero_external_conn();
+
+    /* release normal - which in the non-external conn case will free the object despite the weak ref. */
+    IStream_Seek(data.pStream2, ullZero, STREAM_SEEK_SET, NULL);
+    release_host_object(tid, 2);
+
+    ok_zero_external_conn();
+    ok_last_release_closes(TRUE);
+
+    if (with_external_conn)
+    {
+        ok_more_than_one_lock();
+        IStream_Seek(data.pStream1, ullZero, STREAM_SEEK_SET, NULL);
+        release_host_object(tid, 1);
+    }
+
+    ok_no_locks();
+
+    IStream_Release(data.pStream1);
+    IStream_Release(data.pStream2);
+
+    SetEvent(data.hQuitEvent);
+    ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
+    CloseHandle(thread);
+}
+
+static void test_two_tableweak_marshal_and_releasedata(void)
+{
+    HRESULT hr;
+    DWORD tid;
+    HANDLE thread;
+    struct duo_marshal_data data;
+
+    cLocks = 0;
+    external_connections = 0;
+
+    data.hReadyEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
+    data.hQuitEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
+    data.marshal_flags1 = MSHLFLAGS_TABLEWEAK;
+    data.marshal_flags2 = MSHLFLAGS_TABLEWEAK;
+    hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStream1);
+    ok_ole_success(hr, CreateStreamOnHGlobal);
+    hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStream2);
+    ok_ole_success(hr, CreateStreamOnHGlobal);
+
+    thread = CreateThread(NULL, 0, duo_marshal_thread_proc, &data, 0, &tid);
+    ok( !WaitForSingleObject(data.hReadyEvent, 10000), "wait timed out\n" );
+    CloseHandle(data.hReadyEvent);
+
+    ok_more_than_one_lock();
+    ok_zero_external_conn();
+
+    /* release one weak ref - the remaining weak ref will keep the obj alive */
+    IStream_Seek(data.pStream1, ullZero, STREAM_SEEK_SET, NULL);
+    release_host_object(tid, 1);
+
+    ok_more_than_one_lock();
+
+    IStream_Seek(data.pStream2, ullZero, STREAM_SEEK_SET, NULL);
+    release_host_object(tid, 2);
+
+    ok_no_locks();
+
+    IStream_Release(data.pStream1);
+    IStream_Release(data.pStream2);
 
     SetEvent(data.hQuitEvent);
     ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
@@ -1194,12 +1473,14 @@ static void test_tablestrong_marshal_and_unmarshal_twice(void)
     HANDLE thread;
 
     cLocks = 0;
+    external_connections = 0;
 
     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
     ok_ole_success(hr, CreateStreamOnHGlobal);
     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLESTRONG, &thread);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
 
     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
@@ -1224,10 +1505,12 @@ static void test_tablestrong_marshal_and_unmarshal_twice(void)
     /* release the remaining reference on the object by calling
      * CoReleaseMarshalData in the hosting thread */
     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
-    release_host_object(tid);
+    release_host_object(tid, 0);
     IStream_Release(pStream);
 
     ok_no_locks();
+    ok_zero_external_conn();
+    ok_last_release_closes(TRUE);
 
     end_host_object(tid, thread);
 }
@@ -1239,16 +1522,20 @@ static void test_lock_object_external(void)
     IStream *pStream = NULL;
 
     cLocks = 0;
+    external_connections = 0;
 
     /* test the stub manager creation aspect of CoLockObjectExternal when the
      * object hasn't been marshaled yet */
     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
 
     CoDisconnectObject((IUnknown*)&Test_ClassFactory, 0);
 
     ok_no_locks();
+    ok_non_zero_external_conn();
+    external_connections = 0;
 
     /* test our empty stub manager being handled correctly in
      * CoMarshalInterface */
@@ -1262,6 +1549,7 @@ static void test_lock_object_external(void)
     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
 
     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
     hr = CoReleaseMarshalData(pStream);
@@ -1269,14 +1557,20 @@ static void test_lock_object_external(void)
     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
+    ok_last_release_closes(TRUE);
 
     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, FALSE, TRUE);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
+    ok_last_release_closes(TRUE);
 
     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, FALSE, TRUE);
 
     ok_no_locks();
+    ok_zero_external_conn();
+    ok_last_release_closes(TRUE);
 
     /* test CoLockObjectExternal releases reference to object with
      * fLastUnlockReleases as TRUE and there are only strong references on
@@ -1284,10 +1578,13 @@ static void test_lock_object_external(void)
     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, FALSE);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
 
     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, FALSE, FALSE);
 
     ok_no_locks();
+    ok_zero_external_conn();
+    ok_last_release_closes(FALSE);
 
     /* test CoLockObjectExternal doesn't release the last reference to an
      * object with fLastUnlockReleases as TRUE and there is a weak reference
@@ -1296,14 +1593,18 @@ static void test_lock_object_external(void)
     ok_ole_success(hr, CoMarshalInterface);
 
     ok_more_than_one_lock();
+    ok_zero_external_conn();
 
     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, FALSE);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
 
     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, FALSE, FALSE);
 
     ok_more_than_one_lock();
+    ok_zero_external_conn();
+    ok_last_release_closes(FALSE);
 
     CoDisconnectObject((IUnknown*)&Test_ClassFactory, 0);
 
@@ -1319,15 +1620,19 @@ static void test_disconnect_stub(void)
     IStream *pStream = NULL;
 
     cLocks = 0;
+    external_connections = 0;
 
     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
     ok_ole_success(hr, CreateStreamOnHGlobal);
     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
     ok_ole_success(hr, CoMarshalInterface);
 
+    ok_non_zero_external_conn();
+
     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
     
     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
     hr = CoReleaseMarshalData(pStream);
@@ -1335,10 +1640,12 @@ static void test_disconnect_stub(void)
     IStream_Release(pStream);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
 
     CoDisconnectObject((IUnknown*)&Test_ClassFactory, 0);
 
     ok_no_locks();
+    ok_non_zero_external_conn();
 
     hr = CoDisconnectObject(NULL, 0);
     ok( hr == E_INVALIDARG, "wrong status %x\n", hr );
@@ -1353,6 +1660,7 @@ static void test_normal_marshal_and_unmarshal_twice(void)
     IUnknown *pProxy2 = NULL;
 
     cLocks = 0;
+    external_connections = 0;
 
     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
     ok_ole_success(hr, CreateStreamOnHGlobal);
@@ -1360,12 +1668,15 @@ static void test_normal_marshal_and_unmarshal_twice(void)
     ok_ole_success(hr, CoMarshalInterface);
 
     ok_more_than_one_lock();
+    ok_non_zero_external_conn();
     
     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
     ok_ole_success(hr, CoUnmarshalInterface);
 
     ok_more_than_one_lock();
+    ok_zero_external_conn();
+    ok_last_release_closes(FALSE);
 
     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
@@ -1492,7 +1803,7 @@ static void test_proxy_used_in_wrong_thread(void)
     CloseHandle(thread);
 
     /* do release statement on Win9x that we should have done above */
-    if (!GetProcAddress(GetModuleHandle("ole32"), "CoRegisterSurrogateEx"))
+    if (!GetProcAddress(GetModuleHandleA("ole32"), "CoRegisterSurrogateEx"))
         IUnknown_Release(pProxy);
 
     ok_no_locks();
@@ -1832,7 +2143,7 @@ static HRESULT WINAPI TestRE_IClassFactory_CreateInstance(
     DWORD_PTR res;
     if (IsEqualIID(riid, &IID_IWineTest))
     {
-        BOOL ret = SendMessageTimeout(hwnd_app, WM_NULL, 0, 0, SMTO_BLOCK, 5000, &res);
+        BOOL ret = SendMessageTimeoutA(hwnd_app, WM_NULL, 0, 0, SMTO_BLOCK, 5000, &res);
         ok(ret, "Timed out sending a message to originating window during RPC call\n");
     }
     *ppvObj = NULL;
@@ -1889,7 +2200,7 @@ static LRESULT CALLBACK window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM l
 
         end_host_object(tid, thread);
 
-        PostMessage(hwnd, WM_QUIT, 0, 0);
+        PostMessageA(hwnd, WM_QUIT, 0, 0);
 
         return 0;
     }
@@ -1919,7 +2230,7 @@ static LRESULT CALLBACK window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM l
 
         /* post quit message before a doing a COM call to show that a pending
         * WM_QUIT message doesn't stop the call from succeeding */
-        PostMessage(hwnd, WM_QUIT, 0, 0);
+        PostMessageA(hwnd, WM_QUIT, 0, 0);
         hr = IClassFactory_CreateInstance(proxy, NULL, &IID_IUnknown, (void **)&object);
        ok(hr == S_FALSE, "IClassFactory_CreateInstance returned 0x%08x, expected S_FALSE\n", hr);
 
@@ -1964,34 +2275,34 @@ static LRESULT CALLBACK window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM l
         return 0;
     }
     default:
-        return DefWindowProc(hwnd, msg, wparam, lparam);
+        return DefWindowProcA(hwnd, msg, wparam, lparam);
     }
 }
 
 static void register_test_window(void)
 {
-    WNDCLASS wndclass;
+    WNDCLASSA wndclass;
 
     memset(&wndclass, 0, sizeof(wndclass));
     wndclass.lpfnWndProc = window_proc;
     wndclass.lpszClassName = "WineCOMTest";
-    RegisterClass(&wndclass);
+    RegisterClassA(&wndclass);
 }
 
 static void test_message_reentrancy(void)
 {
     MSG msg;
 
-    hwnd_app = CreateWindow("WineCOMTest", NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, 0);
+    hwnd_app = CreateWindowA("WineCOMTest", NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, 0);
     ok(hwnd_app != NULL, "Window creation failed\n");
 
     /* start message re-entrancy test */
-    PostMessage(hwnd_app, WM_USER, 0, 0);
+    PostMessageA(hwnd_app, WM_USER, 0, 0);
 
-    while (GetMessage(&msg, NULL, 0, 0))
+    while (GetMessageA(&msg, NULL, 0, 0))
     {
         TranslateMessage(&msg);
-        DispatchMessage(&msg);
+        DispatchMessageA(&msg);
     }
     DestroyWindow(hwnd_app);
 }
@@ -2003,7 +2314,7 @@ static HRESULT WINAPI TestMsg_IClassFactory_CreateInstance(
     LPVOID *ppvObj)
 {
     *ppvObj = NULL;
-    SendMessage(hwnd_app, WM_USER+2, 0, 0);
+    SendMessageA(hwnd_app, WM_USER+2, 0, 0);
     return S_OK;
 }
 
@@ -2028,7 +2339,7 @@ static void test_call_from_message(void)
     HANDLE thread;
     IUnknown *object;
 
-    hwnd_app = CreateWindow("WineCOMTest", NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, 0);
+    hwnd_app = CreateWindowA("WineCOMTest", NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, 0);
     ok(hwnd_app != NULL, "Window creation failed\n");
 
     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
@@ -2054,10 +2365,10 @@ static void test_call_from_message(void)
 
     end_host_object(tid, thread);
 
-    while (GetMessage(&msg, NULL, 0, 0))
+    while (GetMessageA(&msg, NULL, 0, 0))
     {
         TranslateMessage(&msg);
-        DispatchMessage(&msg);
+        DispatchMessageA(&msg);
     }
     DestroyWindow(hwnd_app);
 }
@@ -2066,16 +2377,16 @@ static void test_WM_QUIT_handling(void)
 {
     MSG msg;
 
-    hwnd_app = CreateWindow("WineCOMTest", NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, 0);
+    hwnd_app = CreateWindowA("WineCOMTest", NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, 0);
     ok(hwnd_app != NULL, "Window creation failed\n");
 
     /* start WM_QUIT handling test */
-    PostMessage(hwnd_app, WM_USER+1, 0, 0);
+    PostMessageA(hwnd_app, WM_USER+1, 0, 0);
 
-    while (GetMessage(&msg, NULL, 0, 0))
+    while (GetMessageA(&msg, NULL, 0, 0))
     {
         TranslateMessage(&msg);
-        DispatchMessage(&msg);
+        DispatchMessageA(&msg);
     }
 }
 
@@ -2124,10 +2435,7 @@ static void test_freethreadedmarshaldata(IStream *pStream, MSHCTX mshctx, void *
         }
         if (size >= 3*sizeof(DWORD) + sizeof(GUID))
         {
-            trace("got guid data: {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n",
-                ((GUID *)marshal_data)->Data1, ((GUID *)marshal_data)->Data2, ((GUID *)marshal_data)->Data3,
-                ((GUID *)marshal_data)->Data4[0], ((GUID *)marshal_data)->Data4[1], ((GUID *)marshal_data)->Data4[2], ((GUID *)marshal_data)->Data4[3],
-                ((GUID *)marshal_data)->Data4[4], ((GUID *)marshal_data)->Data4[5], ((GUID *)marshal_data)->Data4[6], ((GUID *)marshal_data)->Data4[7]);
+            trace("got guid data: %s\n", wine_dbgstr_guid((GUID *)marshal_data));
         }
     }
     else
@@ -2296,7 +2604,7 @@ static HRESULT reg_unreg_wine_test_class(BOOL Register)
     strcat(buffer, "\\InprocHandler32");
     if (Register)
     {
-        error = RegCreateKeyEx(HKEY_CLASSES_ROOT, buffer, 0, NULL, 0, KEY_SET_VALUE, NULL, &hkey, &dwDisposition);
+        error = RegCreateKeyExA(HKEY_CLASSES_ROOT, buffer, 0, NULL, 0, KEY_SET_VALUE, NULL, &hkey, &dwDisposition);
         if (error == ERROR_ACCESS_DENIED)
         {
             skip("Not authorized to modify the Classes key\n");
@@ -2304,16 +2612,16 @@ static HRESULT reg_unreg_wine_test_class(BOOL Register)
         }
         ok(error == ERROR_SUCCESS, "RegCreateKeyEx failed with error %d\n", error);
         if (error != ERROR_SUCCESS) hr = E_FAIL;
-        error = RegSetValueEx(hkey, NULL, 0, REG_SZ, (const unsigned char *)"\"ole32.dll\"", strlen("\"ole32.dll\"") + 1);
+        error = RegSetValueExA(hkey, NULL, 0, REG_SZ, (const unsigned char *)"\"ole32.dll\"", strlen("\"ole32.dll\"") + 1);
         ok(error == ERROR_SUCCESS, "RegSetValueEx failed with error %d\n", error);
         if (error != ERROR_SUCCESS) hr = E_FAIL;
         RegCloseKey(hkey);
     }
     else
     {
-        RegDeleteKey(HKEY_CLASSES_ROOT, buffer);
+        RegDeleteKeyA(HKEY_CLASSES_ROOT, buffer);
         *strrchr(buffer, '\\') = '\0';
-        RegDeleteKey(HKEY_CLASSES_ROOT, buffer);
+        RegDeleteKeyA(HKEY_CLASSES_ROOT, buffer);
     }
     return hr;
 }
@@ -2623,16 +2931,16 @@ static void test_register_local_server(void)
     HANDLE quit_event;
     DWORD wait;
 
-    heventShutdown = CreateEvent(NULL, TRUE, FALSE, NULL);
+    heventShutdown = CreateEventA(NULL, TRUE, FALSE, NULL);
 
     hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&TestOOP_ClassFactory,
                                CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &cookie);
     ok_ole_success(hr, CoRegisterClassObject);
 
-    ready_event = CreateEvent(NULL, FALSE, FALSE, "Wine COM Test Ready Event");
+    ready_event = CreateEventA(NULL, FALSE, FALSE, "Wine COM Test Ready Event");
     SetEvent(ready_event);
 
-    quit_event = CreateEvent(NULL, FALSE, FALSE, "Wine COM Test Quit Event");
+    quit_event = CreateEventA(NULL, FALSE, FALSE, "Wine COM Test Quit Event");
 
     do
     {
@@ -2640,12 +2948,12 @@ static void test_register_local_server(void)
         if (wait == WAIT_OBJECT_0+1)
         {
             MSG msg;
-            BOOL ret = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
-            if (ret)
+
+            if (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
             {
                 trace("Message 0x%x\n", msg.message);
                 TranslateMessage(&msg);
-                DispatchMessage(&msg);
+                DispatchMessageA(&msg);
             }
         }
     }
@@ -2662,14 +2970,14 @@ static HANDLE create_target_process(const char *arg)
     char cmdline[MAX_PATH];
     BOOL ret;
     PROCESS_INFORMATION pi;
-    STARTUPINFO si = { 0 };
+    STARTUPINFOA si = { 0 };
     si.cb = sizeof(si);
 
     pi.hThread = NULL;
     pi.hProcess = NULL;
     winetest_get_mainargs( &argv );
     sprintf(cmdline, "%s %s %s", argv[0], argv[1], arg);
-    ret = CreateProcess(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
+    ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
     ok(ret, "CreateProcess failed with error: %u\n", GetLastError());
     if (pi.hThread) CloseHandle(pi.hThread);
     return pi.hProcess;
@@ -2686,7 +2994,7 @@ static void test_local_server(void)
     HANDLE quit_event;
     HANDLE ready_event;
 
-    heventShutdown = CreateEvent(NULL, TRUE, FALSE, NULL);
+    heventShutdown = CreateEventA(NULL, TRUE, FALSE, NULL);
 
     cLocks = 0;
 
@@ -2749,7 +3057,7 @@ static void test_local_server(void)
     process = create_target_process("-Embedding");
     ok(process != NULL, "couldn't start local server process, error was %d\n", GetLastError());
 
-    ready_event = CreateEvent(NULL, FALSE, FALSE, "Wine COM Test Ready Event");
+    ready_event = CreateEventA(NULL, FALSE, FALSE, "Wine COM Test Ready Event");
     ok( !WaitForSingleObject(ready_event, 10000), "wait timed out\n" );
     CloseHandle(ready_event);
 
@@ -2761,7 +3069,7 @@ static void test_local_server(void)
     hr = CoCreateInstance(&CLSID_WineOOPTest, NULL, CLSCTX_LOCAL_SERVER, &IID_IClassFactory, (void **)&cf);
     ok(hr == REGDB_E_CLASSNOTREG, "Second CoCreateInstance on REGCLS_SINGLEUSE object should have failed\n");
 
-    quit_event = CreateEvent(NULL, FALSE, FALSE, "Wine COM Test Quit Event");
+    quit_event = CreateEventA(NULL, FALSE, FALSE, "Wine COM Test Quit Event");
     SetEvent(quit_event);
 
     winetest_wait_child_process( process );
@@ -2854,8 +3162,8 @@ static void test_globalinterfacetable(void)
        while (ret == WAIT_OBJECT_0 + 1)
        {
                MSG msg;
-               while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
-                       DispatchMessage(&msg);
+               while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
+                       DispatchMessageA(&msg);
                ret = MsgWaitForMultipleObjects(1, &thread, FALSE, 10000, QS_ALLINPUT);
        }
 
@@ -2963,12 +3271,12 @@ static const char *debugstr_iid(REFIID riid)
     LONG name_size = sizeof(name);
     StringFromGUID2(riid, bufferW, sizeof(bufferW)/sizeof(bufferW[0]));
     WideCharToMultiByte(CP_ACP, 0, bufferW, sizeof(bufferW)/sizeof(bufferW[0]), buffer, sizeof(buffer), NULL, NULL);
-    if (RegOpenKeyEx(HKEY_CLASSES_ROOT, "Interface", 0, KEY_QUERY_VALUE, &hkeyInterface) != ERROR_SUCCESS)
+    if (RegOpenKeyExA(HKEY_CLASSES_ROOT, "Interface", 0, KEY_QUERY_VALUE, &hkeyInterface) != ERROR_SUCCESS)
     {
         memcpy(name, buffer, sizeof(buffer));
         goto done;
     }
-    if (RegQueryValue(hkeyInterface, buffer, name, &name_size) != ERROR_SUCCESS)
+    if (RegQueryValueA(hkeyInterface, buffer, name, &name_size) != ERROR_SUCCESS)
     {
         memcpy(name, buffer, sizeof(buffer));
         goto done;
@@ -3167,7 +3475,7 @@ static void test_channel_hook(void)
 
 START_TEST(marshal)
 {
-    HMODULE hOle32 = GetModuleHandle("ole32");
+    HMODULE hOle32 = GetModuleHandleA("ole32");
     int argc;
     char **argv;
 
@@ -3198,29 +3506,37 @@ START_TEST(marshal)
     /* FIXME: test CoCreateInstanceEx */
 
     /* lifecycle management and marshaling tests */
-    test_no_marshaler();
-    test_normal_marshal_and_release();
-    test_normal_marshal_and_unmarshal();
-    test_marshal_and_unmarshal_invalid();
-    test_same_apartment_unmarshal_failure();
-    test_interthread_marshal_and_unmarshal();
-    test_proxy_marshal_and_unmarshal();
-    test_proxy_marshal_and_unmarshal2();
-    test_proxy_marshal_and_unmarshal_weak();
-    test_proxy_marshal_and_unmarshal_strong();
-    test_marshal_stub_apartment_shutdown();
-    test_marshal_proxy_apartment_shutdown();
-    test_marshal_proxy_mta_apartment_shutdown();
-    test_no_couninitialize_server();
-    test_no_couninitialize_client();
-    test_tableweak_marshal_and_unmarshal_twice();
-    test_tableweak_marshal_releasedata1();
-    test_tableweak_marshal_releasedata2();
-    test_tableweak_and_normal_marshal_and_unmarshal();
-    test_tablestrong_marshal_and_unmarshal_twice();
-    test_lock_object_external();
-    test_disconnect_stub();
-    test_normal_marshal_and_unmarshal_twice();
+    do
+    {
+        test_no_marshaler();
+        test_normal_marshal_and_release();
+        test_normal_marshal_and_unmarshal();
+        test_marshal_and_unmarshal_invalid();
+        test_same_apartment_unmarshal_failure();
+        test_interthread_marshal_and_unmarshal();
+        test_proxy_marshal_and_unmarshal();
+        test_proxy_marshal_and_unmarshal2();
+        test_proxy_marshal_and_unmarshal_weak();
+        test_proxy_marshal_and_unmarshal_strong();
+        test_marshal_stub_apartment_shutdown();
+        test_marshal_proxy_apartment_shutdown();
+        test_marshal_proxy_mta_apartment_shutdown();
+        test_no_couninitialize_server();
+        test_no_couninitialize_client();
+        test_tableweak_marshal_and_unmarshal_twice();
+        test_tableweak_marshal_releasedata1();
+        test_tableweak_marshal_releasedata2();
+        test_tableweak_and_normal_marshal_and_unmarshal();
+        test_tableweak_and_normal_marshal_and_releasedata();
+        test_two_tableweak_marshal_and_releasedata();
+        test_tablestrong_marshal_and_unmarshal_twice();
+        test_lock_object_external();
+        test_disconnect_stub();
+        test_normal_marshal_and_unmarshal_twice();
+
+        with_external_conn = !with_external_conn;
+    } while (with_external_conn);
+
     test_hresult_marshaling();
     test_proxy_used_in_wrong_thread();
     test_message_filter();
index 6b9ed14..a03e923 100644 (file)
@@ -32,6 +32,7 @@
 #include <winbase.h>
 #include <winnls.h>
 #include <wingdi.h>
+#include <winreg.h>
 #include <ole2.h>
 //#include "objbase.h"
 //#include "shlguid.h"
 
 #define ok_ole_success(hr, func) ok(hr == S_OK, func " failed with error 0x%08x\n", hr)
 
+#define DEFINE_EXPECT(func) \
+    static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
+
+#define SET_EXPECT(func) \
+    expect_ ## func = TRUE
+
+#define CHECK_EXPECT2(func) \
+    do { \
+        ok(expect_ ##func, "unexpected call " #func "\n"); \
+        called_ ## func = TRUE; \
+    }while(0)
+
+#define CHECK_EXPECT(func) \
+    do { \
+        CHECK_EXPECT2(func); \
+        expect_ ## func = FALSE; \
+    }while(0)
+
+#define CHECK_CALLED(func) \
+    do { \
+        ok(called_ ## func, "expected " #func "\n"); \
+        expect_ ## func = called_ ## func = FALSE; \
+    }while(0)
+
+DEFINE_EXPECT(Storage_Stat);
+DEFINE_EXPECT(Storage_OpenStream_CompObj);
+DEFINE_EXPECT(Storage_SetClass);
+DEFINE_EXPECT(Storage_CreateStream_CompObj);
+DEFINE_EXPECT(Storage_OpenStream_Ole);
+
 static IPersistStorage OleObjectPersistStg;
 static IOleCache *cache;
 static IRunnableObject *runnable;
 
+static const CLSID CLSID_WineTestOld =
+{ /* 9474ba1a-258b-490b-bc13-516e9239acd0 */
+    0x9474ba1a,
+    0x258b,
+    0x490b,
+    {0xbc, 0x13, 0x51, 0x6e, 0x92, 0x39, 0xac, 0xd0}
+};
+
 static const CLSID CLSID_WineTest =
 { /* 9474ba1a-258b-490b-bc13-516e9239ace0 */
     0x9474ba1a,
@@ -1346,7 +1385,7 @@ static void test_data_cache(void)
         { NULL, 0 }
     };
 
-    GetSystemDirectory(szSystemDir, sizeof(szSystemDir)/sizeof(szSystemDir[0]));
+    GetSystemDirectoryA(szSystemDir, sizeof(szSystemDir)/sizeof(szSystemDir[0]));
 
     expected_method_list = methods_cacheinitnew;
 
@@ -1449,7 +1488,7 @@ static void test_data_cache(void)
     fmtetc.cfFormat = CF_METAFILEPICT;
     stgmedium.tymed = TYMED_MFPICT;
     U(stgmedium).hMetaFilePict = OleMetafilePictFromIconAndLabel(
-        LoadIcon(NULL, IDI_APPLICATION), wszPath, wszPath, 0);
+        LoadIconA(NULL, (LPSTR)IDI_APPLICATION), wszPath, wszPath, 0);
     stgmedium.pUnkForRelease = NULL;
 
     fmtetc.dwAspect = DVASPECT_CONTENT;
@@ -1964,6 +2003,363 @@ static void test_OleDraw(void)
     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
 }
 
+static const WCHAR comp_objW[] = {1,'C','o','m','p','O','b','j',0};
+static IStream *comp_obj_stream;
+static IStream *ole_stream;
+
+static HRESULT WINAPI Storage_QueryInterface(IStorage *iface, REFIID riid, void **ppvObject)
+{
+    ok(0, "unexpected call to QueryInterface\n");
+    return E_NOTIMPL;
+}
+
+static ULONG WINAPI Storage_AddRef(IStorage *iface)
+{
+    ok(0, "unexpected call to AddRef\n");
+    return 2;
+}
+
+static ULONG WINAPI Storage_Release(IStorage *iface)
+{
+    ok(0, "unexpected call to Release\n");
+    return 1;
+}
+
+static HRESULT WINAPI Storage_CreateStream(IStorage *iface, LPCOLESTR pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStream **ppstm)
+{
+    ULARGE_INTEGER size = {{0}};
+    LARGE_INTEGER pos = {{0}};
+    HRESULT hr;
+
+    CHECK_EXPECT(Storage_CreateStream_CompObj);
+    ok(!lstrcmpW(pwcsName, comp_objW), "pwcsName = %s\n", wine_dbgstr_w(pwcsName));
+    todo_wine ok(grfMode == (STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE), "grfMode = %x\n", grfMode);
+    ok(!reserved1, "reserved1 = %x\n", reserved1);
+    ok(!reserved2, "reserved2 = %x\n", reserved2);
+    ok(!!ppstm, "ppstm = NULL\n");
+
+    *ppstm = comp_obj_stream;
+    IStream_AddRef(comp_obj_stream);
+    hr = IStream_Seek(comp_obj_stream, pos, STREAM_SEEK_SET, NULL);
+    ok(hr == S_OK, "IStream_Seek returned %x\n", hr);
+    hr = IStream_SetSize(comp_obj_stream, size);
+    ok(hr == S_OK, "IStream_SetSize returned %x\n", hr);
+    return S_OK;
+}
+
+static HRESULT WINAPI Storage_OpenStream(IStorage *iface, LPCOLESTR pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream **ppstm)
+{
+    static  const WCHAR ole1W[] = {1,'O','l','e',0};
+
+    LARGE_INTEGER pos = {{0}};
+    HRESULT hr;
+
+    ok(!reserved1, "reserved1 = %p\n", reserved1);
+    ok(!reserved2, "reserved2 = %x\n", reserved2);
+    ok(!!ppstm, "ppstm = NULL\n");
+
+    if(!lstrcmpW(pwcsName, comp_objW)) {
+        CHECK_EXPECT2(Storage_OpenStream_CompObj);
+        ok(grfMode == STGM_SHARE_EXCLUSIVE, "grfMode = %x\n", grfMode);
+
+        *ppstm = comp_obj_stream;
+        IStream_AddRef(comp_obj_stream);
+        hr = IStream_Seek(comp_obj_stream, pos, STREAM_SEEK_SET, NULL);
+        ok(hr == S_OK, "IStream_Seek returned %x\n", hr);
+        return S_OK;
+    }else if(!lstrcmpW(pwcsName, ole1W)) {
+        CHECK_EXPECT(Storage_OpenStream_Ole);
+        ok(grfMode == (STGM_SHARE_EXCLUSIVE|STGM_READWRITE), "grfMode = %x\n", grfMode);
+
+        *ppstm = ole_stream;
+        IStream_AddRef(ole_stream);
+        hr = IStream_Seek(ole_stream, pos, STREAM_SEEK_SET, NULL);
+        ok(hr == S_OK, "IStream_Seek returned %x\n", hr);
+        return S_OK;
+    }
+
+    ok(0, "unexpected call to OpenStream: %s\n", wine_dbgstr_w(pwcsName));
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Storage_CreateStorage(IStorage *iface, LPCOLESTR pwcsName, DWORD grfMode, DWORD dwStgFmt, DWORD reserved2, IStorage **ppstg)
+{
+    ok(0, "unexpected call to CreateStorage\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Storage_OpenStorage(IStorage *iface, LPCOLESTR pwcsName, IStorage *pstgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, IStorage **ppstg)
+{
+    ok(0, "unexpected call to OpenStorage\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Storage_CopyTo(IStorage *iface, DWORD ciidExclude, const IID *rgiidExclude, SNB snbExclude, IStorage *pstgDest)
+{
+    ok(0, "unexpected call to CopyTo\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Storage_MoveElementTo(IStorage *iface, LPCOLESTR pwcsName, IStorage *pstgDest, LPCOLESTR pwcsNewName, DWORD grfFlags)
+{
+    ok(0, "unexpected call to MoveElementTo\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Storage_Commit(IStorage *iface, DWORD grfCommitFlags)
+{
+    ok(0, "unexpected call to Commit\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Storage_Revert(IStorage *iface)
+{
+    ok(0, "unexpected call to Revert\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Storage_EnumElements(IStorage *iface, DWORD reserved1, void *reserved2, DWORD reserved3, IEnumSTATSTG **ppenum)
+{
+    ok(0, "unexpected call to EnumElements\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Storage_DestroyElement(IStorage *iface, LPCOLESTR pwcsName)
+{
+    ok(0, "unexpected call to DestroyElement\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Storage_RenameElement(IStorage *iface, LPCOLESTR pwcsOldName, LPCOLESTR pwcsNewName)
+{
+    ok(0, "unexpected call to RenameElement\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Storage_SetElementTimes(IStorage *iface, LPCOLESTR pwcsName, const FILETIME *pctime, const FILETIME *patime, const FILETIME *pmtime)
+{
+    ok(0, "unexpected call to SetElementTimes\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Storage_SetClass(IStorage *iface, REFCLSID clsid)
+{
+    CHECK_EXPECT(Storage_SetClass);
+    ok(IsEqualIID(clsid, &CLSID_WineTest), "clsid = %s\n", wine_dbgstr_guid(clsid));
+    return S_OK;
+}
+
+static HRESULT WINAPI Storage_SetStateBits(IStorage *iface, DWORD grfStateBits, DWORD grfMask)
+{
+    ok(0, "unexpected call to SetStateBits\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Storage_Stat(IStorage *iface, STATSTG *pstatstg, DWORD grfStatFlag)
+{
+    CHECK_EXPECT2(Storage_Stat);
+    ok(pstatstg != NULL, "pstatstg = NULL\n");
+    ok(grfStatFlag == STATFLAG_NONAME, "grfStatFlag = %x\n", grfStatFlag);
+
+    memset(pstatstg, 0, sizeof(STATSTG));
+    pstatstg->type = STGTY_STORAGE;
+    pstatstg->clsid = CLSID_WineTestOld;
+    return S_OK;
+}
+
+static IStorageVtbl StorageVtbl =
+{
+    Storage_QueryInterface,
+    Storage_AddRef,
+    Storage_Release,
+    Storage_CreateStream,
+    Storage_OpenStream,
+    Storage_CreateStorage,
+    Storage_OpenStorage,
+    Storage_CopyTo,
+    Storage_MoveElementTo,
+    Storage_Commit,
+    Storage_Revert,
+    Storage_EnumElements,
+    Storage_DestroyElement,
+    Storage_RenameElement,
+    Storage_SetElementTimes,
+    Storage_SetClass,
+    Storage_SetStateBits,
+    Storage_Stat
+};
+
+static IStorage Storage = { &StorageVtbl };
+
+static void test_OleDoAutoConvert(void)
+{
+    static const WCHAR clsidW[] = {'C','L','S','I','D','\\',0};
+    static struct {
+        DWORD reserved1;
+        DWORD version;
+        DWORD reserved2[5];
+        DWORD ansi_user_type_len;
+        DWORD ansi_clipboard_format_len;
+        DWORD reserved3;
+        DWORD unicode_marker;
+        DWORD unicode_user_type_len;
+        DWORD unicode_clipboard_format_len;
+        DWORD reserved4;
+    } comp_obj_data;
+    static struct {
+        DWORD version;
+        DWORD flags;
+        DWORD link_update_option;
+        DWORD reserved1;
+        DWORD reserved_moniker_stream_size;
+        DWORD relative_source_moniker_stream_size;
+        DWORD absolute_source_moniker_stream_size;
+        DWORD clsid_indicator;
+        CLSID clsid;
+        DWORD reserved_display_name;
+        DWORD reserved2;
+        DWORD local_update_time;
+        DWORD local_check_update_time;
+        DWORD remote_update_time;
+    } ole_data;
+
+    LARGE_INTEGER pos = {{0}};
+    WCHAR buf[39+6];
+    DWORD i, ret;
+    HKEY root;
+    CLSID clsid;
+    HRESULT hr;
+
+    hr = CreateStreamOnHGlobal(NULL, TRUE, &comp_obj_stream);
+    ok(hr == S_OK, "CreateStreamOnHGlobal returned %x\n", hr);
+    hr = IStream_Write(comp_obj_stream, (char*)&comp_obj_data, sizeof(comp_obj_data), NULL);
+    ok(hr == S_OK, "IStream_Write returned %x\n", hr);
+
+    hr = CreateStreamOnHGlobal(NULL, TRUE, &ole_stream);
+    ok(hr == S_OK, "CreateStreamOnHGlobal returned %x\n", hr);
+    hr = IStream_Write(ole_stream, (char*)&ole_data, sizeof(ole_data), NULL);
+    ok(hr == S_OK, "IStream_Write returned %x\n", hr);
+
+    clsid = IID_WineTest;
+    hr = OleDoAutoConvert(NULL, &clsid);
+    ok(hr == E_INVALIDARG, "OleDoAutoConvert returned %x\n", hr);
+    ok(IsEqualIID(&clsid, &IID_NULL), "clsid = %s\n", wine_dbgstr_guid(&clsid));
+
+    if(0) /* crashes on Win7 */
+        OleDoAutoConvert(&Storage, NULL);
+
+    clsid = IID_WineTest;
+    SET_EXPECT(Storage_Stat);
+    hr = OleDoAutoConvert(&Storage, &clsid);
+    ok(hr == REGDB_E_CLASSNOTREG, "OleDoAutoConvert returned %x\n", hr);
+    CHECK_CALLED(Storage_Stat);
+    ok(IsEqualIID(&clsid, &CLSID_WineTestOld), "clsid = %s\n", wine_dbgstr_guid(&clsid));
+
+    lstrcpyW(buf, clsidW);
+    StringFromGUID2(&CLSID_WineTestOld, buf+6, 39);
+
+    ret = RegCreateKeyExW(HKEY_CLASSES_ROOT, buf, 0, NULL, 0,
+            KEY_READ | KEY_WRITE | KEY_CREATE_SUB_KEY, NULL, &root, NULL);
+    if(ret != ERROR_SUCCESS) {
+        win_skip("not enough permissions to create CLSID key (%u)\n", ret);
+        return;
+    }
+
+    clsid = IID_WineTest;
+    SET_EXPECT(Storage_Stat);
+    hr = OleDoAutoConvert(&Storage, &clsid);
+    ok(hr == REGDB_E_KEYMISSING, "OleDoAutoConvert returned %x\n", hr);
+    CHECK_CALLED(Storage_Stat);
+    ok(IsEqualIID(&clsid, &CLSID_WineTestOld), "clsid = %s\n", wine_dbgstr_guid(&clsid));
+
+    hr = OleSetAutoConvert(&CLSID_WineTestOld, &CLSID_WineTest);
+    ok_ole_success(hr, "OleSetAutoConvert");
+
+    hr = OleGetAutoConvert(&CLSID_WineTestOld, &clsid);
+    ok_ole_success(hr, "OleGetAutoConvert");
+    ok(IsEqualIID(&clsid, &CLSID_WineTest), "incorrect clsid: %s\n", wine_dbgstr_guid(&clsid));
+
+    clsid = IID_WineTest;
+    SET_EXPECT(Storage_Stat);
+    SET_EXPECT(Storage_OpenStream_CompObj);
+    SET_EXPECT(Storage_SetClass);
+    SET_EXPECT(Storage_CreateStream_CompObj);
+    SET_EXPECT(Storage_OpenStream_Ole);
+    hr = OleDoAutoConvert(&Storage, &clsid);
+    ok(hr == S_OK, "OleDoAutoConvert returned %x\n", hr);
+    CHECK_CALLED(Storage_Stat);
+    CHECK_CALLED(Storage_OpenStream_CompObj);
+    CHECK_CALLED(Storage_SetClass);
+    CHECK_CALLED(Storage_CreateStream_CompObj);
+    CHECK_CALLED(Storage_OpenStream_Ole);
+    ok(IsEqualIID(&clsid, &CLSID_WineTest), "clsid = %s\n", wine_dbgstr_guid(&clsid));
+
+    hr = IStream_Seek(comp_obj_stream, pos, STREAM_SEEK_SET, NULL);
+    ok(hr == S_OK, "IStream_Seek returned %x\n", hr);
+    hr = IStream_Read(comp_obj_stream, &comp_obj_data, sizeof(comp_obj_data), NULL);
+    ok(hr == S_OK, "IStream_Read returned %x\n", hr);
+    ok(comp_obj_data.reserved1 == 0xfffe0001, "reserved1 = %x\n", comp_obj_data.reserved1);
+    ok(comp_obj_data.version == 0xa03, "version = %x\n", comp_obj_data.version);
+    ok(comp_obj_data.reserved2[0] == -1, "reserved2[0] = %x\n", comp_obj_data.reserved2[0]);
+    ok(IsEqualIID(comp_obj_data.reserved2+1, &CLSID_WineTestOld), "reserved2 = %s\n", wine_dbgstr_guid((CLSID*)(comp_obj_data.reserved2+1)));
+    ok(!comp_obj_data.ansi_user_type_len, "ansi_user_type_len = %d\n", comp_obj_data.ansi_user_type_len);
+    ok(!comp_obj_data.ansi_clipboard_format_len, "ansi_clipboard_format_len = %d\n", comp_obj_data.ansi_clipboard_format_len);
+    ok(!comp_obj_data.reserved3, "reserved3 = %x\n", comp_obj_data.reserved3);
+    ok(comp_obj_data.unicode_marker == 0x71b239f4, "unicode_marker = %x\n", comp_obj_data.unicode_marker);
+    ok(!comp_obj_data.unicode_user_type_len, "unicode_user_type_len = %d\n", comp_obj_data.unicode_user_type_len);
+    ok(!comp_obj_data.unicode_clipboard_format_len, "unicode_clipboard_format_len = %d\n", comp_obj_data.unicode_clipboard_format_len);
+    ok(!comp_obj_data.reserved4, "reserved4 %d\n", comp_obj_data.reserved4);
+
+    hr = IStream_Seek(ole_stream, pos, STREAM_SEEK_SET, NULL);
+    ok(hr == S_OK, "IStream_Seek returned %x\n", hr);
+    hr = IStream_Read(ole_stream, &ole_data, sizeof(ole_data), NULL);
+    ok(hr == S_OK, "IStream_Read returned %x\n", hr);
+    ok(ole_data.version == 0, "version = %x\n", ole_data.version);
+    ok(ole_data.flags == 4, "flags = %x\n", ole_data.flags);
+    for(i=2; i<sizeof(ole_data)/sizeof(DWORD); i++)
+        ok(((DWORD*)&ole_data)[i] == 0, "ole_data[%d] = %x\n", i, ((DWORD*)&ole_data)[i]);
+
+    SET_EXPECT(Storage_OpenStream_Ole);
+    hr = SetConvertStg(&Storage, TRUE);
+    ok(hr == S_OK, "SetConvertStg returned %x\n", hr);
+    CHECK_CALLED(Storage_OpenStream_Ole);
+
+    SET_EXPECT(Storage_OpenStream_CompObj);
+    SET_EXPECT(Storage_Stat);
+    SET_EXPECT(Storage_CreateStream_CompObj);
+    hr = WriteFmtUserTypeStg(&Storage, 0, NULL);
+    ok(hr == S_OK, "WriteFmtUserTypeStg returned %x\n", hr);
+    todo_wine CHECK_CALLED(Storage_OpenStream_CompObj);
+    CHECK_CALLED(Storage_Stat);
+    CHECK_CALLED(Storage_CreateStream_CompObj);
+    hr = IStream_Seek(comp_obj_stream, pos, STREAM_SEEK_SET, NULL);
+    ok(hr == S_OK, "IStream_Seek returned %x\n", hr);
+    hr = IStream_Read(comp_obj_stream, &comp_obj_data, sizeof(comp_obj_data), NULL);
+    ok(hr == S_OK, "IStream_Read returned %x\n", hr);
+    ok(comp_obj_data.reserved1 == 0xfffe0001, "reserved1 = %x\n", comp_obj_data.reserved1);
+    ok(comp_obj_data.version == 0xa03, "version = %x\n", comp_obj_data.version);
+    ok(comp_obj_data.reserved2[0] == -1, "reserved2[0] = %x\n", comp_obj_data.reserved2[0]);
+    ok(IsEqualIID(comp_obj_data.reserved2+1, &CLSID_WineTestOld), "reserved2 = %s\n", wine_dbgstr_guid((CLSID*)(comp_obj_data.reserved2+1)));
+    ok(!comp_obj_data.ansi_user_type_len, "ansi_user_type_len = %d\n", comp_obj_data.ansi_user_type_len);
+    ok(!comp_obj_data.ansi_clipboard_format_len, "ansi_clipboard_format_len = %d\n", comp_obj_data.ansi_clipboard_format_len);
+    ok(!comp_obj_data.reserved3, "reserved3 = %x\n", comp_obj_data.reserved3);
+    ok(comp_obj_data.unicode_marker == 0x71b239f4, "unicode_marker = %x\n", comp_obj_data.unicode_marker);
+    ok(!comp_obj_data.unicode_user_type_len, "unicode_user_type_len = %d\n", comp_obj_data.unicode_user_type_len);
+    ok(!comp_obj_data.unicode_clipboard_format_len, "unicode_clipboard_format_len = %d\n", comp_obj_data.unicode_clipboard_format_len);
+    ok(!comp_obj_data.reserved4, "reserved4 %d\n", comp_obj_data.reserved4);
+
+    ret = IStream_Release(comp_obj_stream);
+    ok(!ret, "comp_obj_stream was not freed\n");
+    ret = IStream_Release(ole_stream);
+    ok(!ret, "ole_stream was not freed\n");
+
+    ret = RegDeleteKeyA(root, "AutoConvertTo");
+    ok(ret == ERROR_SUCCESS, "RegDeleteKey error %u\n", ret);
+    ret = RegDeleteKeyA(root, "");
+    ok(ret == ERROR_SUCCESS, "RegDeleteKey error %u\n", ret);
+    RegCloseKey(root);
+}
+
 START_TEST(ole2)
 {
     DWORD dwRegister;
@@ -2002,6 +2398,7 @@ START_TEST(ole2)
     test_OleRun();
     test_OleLockRunning();
     test_OleDraw();
+    test_OleDoAutoConvert();
 
     CoUninitialize();
 }
index 9c901ee..77abda4 100644 (file)
@@ -65,7 +65,6 @@ static LONG obj_ref, class_ref, server_locks;
 
 static const char *debugstr_guid(const GUID *guid)
 {
-    static char buf[50];
     int i;
 
     if (!guid) return "(null)";
@@ -76,11 +75,7 @@ static const char *debugstr_guid(const GUID *guid)
             return guid_name[i].name;
     }
 
-    sprintf(buf, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
-            guid->Data1, guid->Data2, guid->Data3, guid->Data4[0],
-            guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4],
-            guid->Data4[5], guid->Data4[6], guid->Data4[7]);
-    return buf;
+    return wine_dbgstr_guid(guid);
 }
 
 /******************************* OLE server *******************************/
@@ -258,9 +253,9 @@ static void ole_server(void)
         {
             HANDLE done_event, init_done_event;
 
-            done_event = OpenEvent(SYNCHRONIZE, FALSE, "ole_server_done_event");
+            done_event = OpenEventA(SYNCHRONIZE, FALSE, "ole_server_done_event");
             ok(done_event != 0, "server: OpenEvent error %d\n", GetLastError());
-            init_done_event = OpenEvent(EVENT_MODIFY_STATE, FALSE, "ole_server_init_done_event");
+            init_done_event = OpenEventA(EVENT_MODIFY_STATE, FALSE, "ole_server_init_done_event");
             ok(init_done_event != 0, "server: OpenEvent error %d\n", GetLastError());
 
             SetEvent(init_done_event);
@@ -300,8 +295,8 @@ static BOOL register_server(const char *server, BOOL inproc_handler)
     WCHAR buf[39 + 6];
     char server_path[MAX_PATH];
 
-    lstrcpy(server_path, server);
-    lstrcat(server_path, " ole_server");
+    lstrcpyA(server_path, server);
+    lstrcatA(server_path, " ole_server");
 
     lstrcpyW(buf, clsidW);
     StringFromGUID2(&CLSID_WineTestObject, buf + 6, 39);
@@ -310,12 +305,12 @@ static BOOL register_server(const char *server, BOOL inproc_handler)
                           KEY_READ | KEY_WRITE | KEY_CREATE_SUB_KEY, NULL, &root, NULL);
     if (ret == ERROR_SUCCESS)
     {
-        ret = RegSetValue(root, "LocalServer32", REG_SZ, server_path, strlen(server_path));
+        ret = RegSetValueA(root, "LocalServer32", REG_SZ, server_path, strlen(server_path));
         ok(ret == ERROR_SUCCESS, "RegSetValue error %u\n", ret);
 
         if (inproc_handler)
         {
-            ret = RegSetValue(root, "InprocHandler32", REG_SZ, "ole32.dll", 9);
+            ret = RegSetValueA(root, "InprocHandler32", REG_SZ, "ole32.dll", 9);
             ok(ret == ERROR_SUCCESS, "RegSetValue error %u\n", ret);
         }
 
@@ -339,11 +334,11 @@ static void unregister_server(void)
                           DELETE, NULL, &root, NULL);
     if (ret == ERROR_SUCCESS)
     {
-        ret = RegDeleteKey(root, "InprocHandler32");
+        ret = RegDeleteKeyA(root, "InprocHandler32");
         ok(ret == ERROR_SUCCESS, "RegDeleteKey error %u\n", ret);
-        ret = RegDeleteKey(root, "LocalServer32");
+        ret = RegDeleteKeyA(root, "LocalServer32");
         ok(ret == ERROR_SUCCESS, "RegDeleteKey error %u\n", ret);
-        ret = RegDeleteKey(root, "");
+        ret = RegDeleteKeyA(root, "");
         ok(ret == ERROR_SUCCESS, "RegDeleteKey error %u\n", ret);
         RegCloseKey(root);
     }
@@ -352,7 +347,7 @@ static void unregister_server(void)
 static HANDLE start_server(const char *argv0)
 {
     PROCESS_INFORMATION pi;
-    STARTUPINFO si;
+    STARTUPINFOA si;
     SECURITY_ATTRIBUTES sa;
     char cmdline[MAX_PATH * 2];
     BOOL ret;
@@ -369,7 +364,7 @@ static HANDLE start_server(const char *argv0)
     sa.bInheritHandle = TRUE;
 
     sprintf(cmdline, "\"%s\" ole_server -server", argv0);
-    ret = CreateProcess(argv0, cmdline, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
+    ret = CreateProcessA(argv0, cmdline, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
     ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
     if (!ret) return 0;
 
@@ -391,26 +386,26 @@ START_TEST(ole_server)
     int argc;
     char **argv;
 
-    mapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, "winetest_ole_server");
+    mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, "winetest_ole_server");
     ok(mapping != 0, "CreateFileMapping failed\n");
     info = MapViewOfFile(mapping, FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, 4096);
 
     argc = winetest_get_mainargs(&argv);
 
-    done_event = CreateEvent(NULL, TRUE, FALSE, "ole_server_done_event");
+    done_event = CreateEventA(NULL, TRUE, FALSE, "ole_server_done_event");
     ok(done_event != 0, "CreateEvent error %d\n", GetLastError());
-    init_done_event = CreateEvent(NULL, TRUE, FALSE, "ole_server_init_done_event");
+    init_done_event = CreateEventA(NULL, TRUE, FALSE, "ole_server_init_done_event");
     ok(init_done_event != 0, "CreateEvent error %d\n", GetLastError());
 
     if (argc > 2)
     {
-        if (!lstrcmpi(argv[2], "-Embedding"))
+        if (!lstrcmpiA(argv[2], "-Embedding"))
         {
             trace("server: Refusing to be run by ole32\n");
             return;
         }
 
-        if (!lstrcmpi(argv[2], "-server"))
+        if (!lstrcmpiA(argv[2], "-server"))
         {
             info->child_failures = 0;
             ole_server();
index ac912ae..f601e62 100644 (file)
@@ -74,8 +74,8 @@ static const struct valid_mapping
     { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO  }, /* VT_UI4 */
     { PROP_V0 , PROP_V1A | PROP_TODO, PROP_V0 , PROP_V1A | PROP_TODO }, /* VT_I8 */
     { PROP_V0 , PROP_V1A | PROP_TODO, PROP_V0 , PROP_V1A | PROP_TODO }, /* VT_UI8 */
-    { PROP_V1 | PROP_TODO , PROP_V1 | PROP_TODO , PROP_INV, PROP_V1 | PROP_TODO  }, /* VT_INT */
-    { PROP_V1 | PROP_TODO , PROP_V1 | PROP_TODO , PROP_INV, PROP_V1 | PROP_TODO  }, /* VT_UINT */
+    { PROP_V1 , PROP_V1 | PROP_TODO , PROP_INV, PROP_V1 | PROP_TODO  }, /* VT_INT */
+    { PROP_V1 , PROP_V1 | PROP_TODO , PROP_INV, PROP_V1 | PROP_TODO  }, /* VT_UINT */
     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* VT_VOID */
     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* VT_HRESULT */
     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* VT_PTR */
@@ -140,7 +140,7 @@ static const char* wine_vtypes[VT_CLSID+1] =
 };
 
 
-static void expect(HRESULT hr, VARTYPE vt)
+static void expect(HRESULT hr, VARTYPE vt, BOOL copy)
 {
     int idx = vt & VT_TYPEMASK;
     BYTE flags;
@@ -168,7 +168,7 @@ static void expect(HRESULT hr, VARTYPE vt)
     }
 
     if(flags == PROP_INV)
-        ok(hr == STG_E_INVALIDPARAMETER, "%s (%s): got %08x\n", wine_vtypes[idx], modifier, hr);
+        ok(hr == copy ? DISP_E_BADVARTYPE : STG_E_INVALIDPARAMETER, "%s (%s): got %08x\n", wine_vtypes[idx], modifier, hr);
     else if(flags == PROP_V0)
         ok(hr == S_OK, "%s (%s): got %08x\n", wine_vtypes[idx], modifier, hr);
     else if(flags & PROP_TODO)
@@ -190,32 +190,125 @@ static void expect(HRESULT hr, VARTYPE vt)
 
 static void test_validtypes(void)
 {
-    PROPVARIANT propvar;
+    PROPVARIANT propvar, copy, uninit;
     HRESULT hr;
-    unsigned int i;
+    unsigned int i, ret;
+
+    memset(&uninit, 0x77, sizeof(uninit));
 
-    memset(&propvar, 0, sizeof(propvar));
+    memset(&propvar, 0x55, sizeof(propvar));
+    hr = PropVariantClear(&propvar);
+    ok(hr == STG_E_INVALIDPARAMETER, "expected STG_E_INVALIDPARAMETER, got %08x\n", hr);
+    ok(propvar.vt == 0, "expected 0, got %d\n", propvar.vt);
+    ok(U(propvar).uhVal.QuadPart == 0, "expected 0, got %#x/%#x\n",
+       U(propvar).uhVal.u.LowPart, U(propvar).uhVal.u.HighPart);
 
     for (i = 0; i < sizeof(valid_types)/sizeof(valid_types[0]); i++)
     {
         VARTYPE vt;
 
+        memset(&propvar, 0x55, sizeof(propvar));
+        if (i == VT_RECORD)
+            memset(&propvar, 0, sizeof(propvar));
+        else if (i == VT_BLOB || i == VT_BLOB_OBJECT)
+        {
+            U(propvar).blob.cbSize = 0;
+            U(propvar).blob.pBlobData = NULL;
+        }
+        else
+            U(propvar).pszVal = NULL;
         vt = propvar.vt = i;
+        memset(&copy, 0x77, sizeof(copy));
+        hr = PropVariantCopy(&copy, &propvar);
+        expect(hr, vt, TRUE);
+        if (hr == S_OK)
+        {
+            ok(copy.vt == propvar.vt, "expected %d, got %d\n", propvar.vt, copy.vt);
+            ok(U(copy).uhVal.QuadPart == U(propvar).uhVal.QuadPart, "%u: expected %#x/%#x, got %#x/%#x\n",
+               i, U(propvar).uhVal.u.LowPart, U(propvar).uhVal.u.HighPart,
+               U(copy).uhVal.u.LowPart, U(copy).uhVal.u.HighPart);
+        }
+        else
+        {
+            ret = memcmp(&copy, &uninit, sizeof(copy));
+            ok(!ret || broken(ret) /* win2000 */, "%d: copy should stay unchanged\n", i);
+        }
         hr = PropVariantClear(&propvar);
-        expect(hr, vt);
+        expect(hr, vt, FALSE);
+        ok(propvar.vt == 0, "expected 0, got %d\n", propvar.vt);
+        ok(U(propvar).uhVal.QuadPart == 0, "%u: expected 0, got %#x/%#x\n",
+           i, U(propvar).uhVal.u.LowPart, U(propvar).uhVal.u.HighPart);
 
+        memset(&propvar, 0x55, sizeof(propvar));
+        U(propvar).pszVal = NULL;
         vt = propvar.vt = i | VT_ARRAY;
+        memset(&copy, 0x77, sizeof(copy));
+        hr = PropVariantCopy(&copy, &propvar);
+        expect(hr, vt, TRUE);
+        if (hr == S_OK)
+        {
+            ok(copy.vt == propvar.vt, "expected %d, got %d\n", propvar.vt, copy.vt);
+            ok(U(copy).uhVal.QuadPart == 0, "%u: expected 0, got %#x/%#x\n",
+               i, U(copy).uhVal.u.LowPart, U(copy).uhVal.u.HighPart);
+        }
+        else
+        {
+            ret = memcmp(&copy, &uninit, sizeof(copy));
+            ok(!ret || broken(ret) /* win2000 */, "%d: copy should stay unchanged\n", i);
+        }
         hr = PropVariantClear(&propvar);
-        expect(hr, vt);
-
+        expect(hr, vt, FALSE);
+        ok(propvar.vt == 0, "expected 0, got %d\n", propvar.vt);
+        ok(U(propvar).uhVal.QuadPart == 0, "%u: expected 0, got %#x/%#x\n",
+           i, U(propvar).uhVal.u.LowPart, U(propvar).uhVal.u.HighPart);
+
+        memset(&propvar, 0x55, sizeof(propvar));
+        U(propvar).caub.cElems = 0;
+        U(propvar).caub.pElems = NULL;
         vt = propvar.vt = i | VT_VECTOR;
+        memset(&copy, 0x77, sizeof(copy));
+        hr = PropVariantCopy(&copy, &propvar);
+        expect(hr, vt, TRUE);
+        if (hr == S_OK)
+        {
+            ok(copy.vt == propvar.vt, "expected %d, got %d\n", propvar.vt, copy.vt);
+            ok(!U(copy).caub.cElems, "%u: expected 0, got %d\n", i, U(copy).caub.cElems);
+            ok(!U(copy).caub.pElems, "%u: expected NULL, got %p\n", i, U(copy).caub.pElems);
+        }
+        else
+        {
+            ret = memcmp(&copy, &uninit, sizeof(copy));
+            ok(!ret || broken(ret) /* win2000 */, "%d: copy should stay unchanged\n", i);
+        }
         hr = PropVariantClear(&propvar);
-        expect(hr, vt);
+        expect(hr, vt, FALSE);
+        ok(propvar.vt == 0, "expected 0, got %d\n", propvar.vt);
+        ok(U(propvar).uhVal.QuadPart == 0, "%u: expected 0, got %#x/%#x\n",
+           i, U(propvar).uhVal.u.LowPart, U(propvar).uhVal.u.HighPart);
 
+        memset(&propvar, 0x55, sizeof(propvar));
+        U(propvar).pszVal = NULL;
         vt = propvar.vt = i | VT_BYREF;
+        memset(&copy, 0x77, sizeof(copy));
+        hr = PropVariantCopy(&copy, &propvar);
+        expect(hr, vt, TRUE);
+        if (hr == S_OK)
+        {
+            ok(copy.vt == propvar.vt, "expected %d, got %d\n", propvar.vt, copy.vt);
+            ok(U(copy).uhVal.QuadPart == U(propvar).uhVal.QuadPart, "%u: expected %#x/%#x, got %#x/%#x\n",
+               i, U(propvar).uhVal.u.LowPart, U(propvar).uhVal.u.HighPart,
+               U(copy).uhVal.u.LowPart, U(copy).uhVal.u.HighPart);
+        }
+        else
+        {
+            ret = memcmp(&copy, &uninit, sizeof(copy));
+            ok(!ret || broken(ret) /* win2000 */, "%d: copy should stay unchanged\n", i);
+        }
         hr = PropVariantClear(&propvar);
-        expect(hr, vt);
-
+        expect(hr, vt, FALSE);
+        ok(propvar.vt == 0, "expected 0, got %d\n", propvar.vt);
+        ok(U(propvar).uhVal.QuadPart == 0, "%u: expected 0, got %#x/%#x\n",
+           i, U(propvar).uhVal.u.LowPart, U(propvar).uhVal.u.HighPart);
     }
 }
 
index 2040556..ba323fe 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <windef.h>
 #include <winbase.h>
+#include <winuser.h>
 #define COBJMACROS
 #include <objbase.h>
 #include <wine/test.h>
index b224ab5..4c7c7d2 100644 (file)
@@ -254,7 +254,7 @@ static void test_create_storage_modes(void)
 static void test_stgcreatestorageex(void)
 {
    HRESULT (WINAPI *pStgCreateStorageEx)(const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS* pStgOptions, void* reserved, REFIID riid, void** ppObjectOpen);
-   HMODULE hOle32 = GetModuleHandle("ole32");
+   HMODULE hOle32 = GetModuleHandleA("ole32");
    IStorage *stg = NULL;
    STGOPTIONS stgoptions = {1, 0, 4096};
    HRESULT r;
@@ -933,7 +933,48 @@ static void test_storage_refcount(void)
         r = IStorage_Release(stg);
         ok(r == 0, "wrong ref count\n");
     }
-    IStorage_Release(stgprio);
+
+    /* Multiple STGM_PRIORITY opens are possible. */
+    r = StgOpenStorage( filename, NULL, STGM_PRIORITY, NULL, 0, &stg);
+    ok(r==S_OK, "StgOpenStorage failed with error 0x%08x\n", r);
+    if(stg)
+    {
+        r = IStorage_Release(stg);
+        ok(r == 0, "wrong ref count\n");
+    }
+
+    r = StgOpenStorage( NULL, stgprio, STGM_TRANSACTED|STGM_SHARE_DENY_WRITE|STGM_READWRITE, NULL, 0, &stg);
+    ok(r==S_OK, "StgOpenStorage failed with error 0x%08x\n", r);
+    if(stg)
+    {
+        static const WCHAR stgname[] = { ' ',' ',' ','2','9',0 };
+        IStorage *stg2;
+        STATSTG statstg;
+
+        r = IStorage_Stat( stg, &statstg, STATFLAG_NONAME );
+        ok(r == S_OK, "Stat should have succeeded instead of returning 0x%08x\n", r);
+        ok(statstg.type == STGTY_STORAGE, "Statstg type should have been STGTY_STORAGE instead of %d\n", statstg.type);
+        ok(U(statstg.cbSize).LowPart == 0, "Statstg cbSize.LowPart should have been 0 instead of %d\n", U(statstg.cbSize).LowPart);
+        ok(U(statstg.cbSize).HighPart == 0, "Statstg cbSize.HighPart should have been 0 instead of %d\n", U(statstg.cbSize).HighPart);
+        ok(statstg.grfMode == (STGM_TRANSACTED|STGM_SHARE_DENY_WRITE|STGM_READWRITE),
+            "Statstg grfMode should have been 0x10022 instead of 0x%x\n", statstg.grfMode);
+        ok(statstg.grfLocksSupported == 0, "Statstg grfLocksSupported should have been 0 instead of %d\n", statstg.grfLocksSupported);
+        ok(IsEqualCLSID(&statstg.clsid, &test_stg_cls), "Statstg clsid is not test_stg_cls\n");
+        ok(statstg.grfStateBits == 0, "Statstg grfStateBits should have been 0 instead of %d\n", statstg.grfStateBits);
+        ok(statstg.reserved == 0, "Statstg reserved should have been 0 instead of %d\n", statstg.reserved);
+
+        r = IStorage_CreateStorage( stg, stgname, STGM_SHARE_EXCLUSIVE, 0, 0, &stg2 );
+        ok(r == S_OK, "CreateStorage should have succeeded instead of returning 0x%08x\n", r);
+
+        IStorage_Release(stg2);
+
+        r = IStorage_Commit( stg, 0 );
+        ok(r == S_OK, "Commit should have succeeded instead of returning 0x%08x\n", r);
+
+        r = IStorage_Release(stg);
+        ok(r == 0, "wrong ref count\n");
+    }
+    /* IStorage_Release(stgprio) not necessary because StgOpenStorage released it. */
 
     DeleteFileA(filenameA);
 }
@@ -2178,7 +2219,7 @@ static void test_fmtusertypestg(void)
     static const char fileA[]  = {'f','m','t','t','e','s','t',0};
     static const WCHAR fileW[] = {'f','m','t','t','e','s','t',0};
     static WCHAR userTypeW[] = {'S','t','g','U','s','r','T','y','p','e',0};
-    static WCHAR strmNameW[] = {1,'C','o','m','p','O','b','j',0};
+    static const WCHAR strmNameW[] = {1,'C','o','m','p','O','b','j',0};
 
     hr = StgCreateDocfile( fileW, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &stg);
     ok(hr == S_OK, "should succeed, res=%x\n", hr);
@@ -3086,19 +3127,21 @@ if (hr == S_OK) {
     /* writer mode */
     hr = StgOpenStorage(fileW, NULL, STGM_DIRECT_SWMR | STGM_READWRITE | STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
     ok(hr == S_OK, "got %08x\n", hr);
+    if(hr == S_OK)
+    {
+        ref = IStorage_AddRef(stg);
+        IStorage_Release(stg);
 
-    ref = IStorage_AddRef(stg);
-    IStorage_Release(stg);
-
-    hr = IStorage_QueryInterface(stg, &IID_IDirectWriterLock, (void**)&dwlock);
-    ok(hr == S_OK, "got %08x\n", hr);
+        hr = IStorage_QueryInterface(stg, &IID_IDirectWriterLock, (void**)&dwlock);
+        ok(hr == S_OK, "got %08x\n", hr);
 
-    ref2 = IStorage_AddRef(stg);
-    IStorage_Release(stg);
-    ok(ref2 == ref + 1, "got %u\n", ref2);
+        ref2 = IStorage_AddRef(stg);
+        IStorage_Release(stg);
+        ok(ref2 == ref + 1, "got %u\n", ref2);
 
-    IDirectWriterLock_Release(dwlock);
-    IStorage_Release(stg);
+        IDirectWriterLock_Release(dwlock);
+        IStorage_Release(stg);
+    }
 
     DeleteFileW(fileW);
 }
index e50968b..cec2ece 100644 (file)
@@ -247,8 +247,8 @@ static void test_marshal_HGLOBAL(void)
 static HENHMETAFILE create_emf(void)
 {
     const RECT rect = {0, 0, 100, 100};
-    HDC hdc = CreateEnhMetaFile(NULL, NULL, &rect, "HENHMETAFILE Marshaling Test\0Test\0\0");
-    ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, "Test String", strlen("Test String"), NULL);
+    HDC hdc = CreateEnhMetaFileA(NULL, NULL, &rect, "HENHMETAFILE Marshaling Test\0Test\0\0");
+    ExtTextOutA(hdc, 0, 0, ETO_OPAQUE, &rect, "Test String", strlen("Test String"), NULL);
     return CloseEnhMetaFile(hdc);
 }
 
@@ -319,8 +319,8 @@ static void test_marshal_HENHMETAFILE(void)
 static HMETAFILE create_mf(void)
 {
     RECT rect = {0, 0, 100, 100};
-    HDC hdc = CreateMetaFile(NULL);
-    ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, "Test String", strlen("Test String"), NULL);
+    HDC hdc = CreateMetaFileA(NULL);
+    ExtTextOutA(hdc, 0, 0, ETO_OPAQUE, &rect, "Test String", strlen("Test String"), NULL);
     return CloseMetaFile(hdc);
 }