[OLE32_WINETEST] Sync with Wine Staging 1.9.4. CORE-10912
authorAmine Khaldi <amine.khaldi@reactos.org>
Fri, 4 Mar 2016 09:30:16 +0000 (09:30 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Fri, 4 Mar 2016 09:30:16 +0000 (09:30 +0000)
svn path=/trunk/; revision=70902

rostests/winetests/ole32/clipboard.c
rostests/winetests/ole32/compobj.c
rostests/winetests/ole32/hglobalstream.c
rostests/winetests/ole32/ole2.c
rostests/winetests/ole32/propvariant.c
rostests/winetests/ole32/storage32.c

index fabd31d..f38ca93 100644 (file)
@@ -461,6 +461,17 @@ static HRESULT DataObjectImpl_CreateComplex(LPDATAOBJECT *lplpdataobj)
     return S_OK;
 }
 
+static void test_get_clipboard_unitialized(void)
+{
+    HRESULT hr;
+    IDataObject *pDObj;
+
+    pDObj = (IDataObject *)0xdeadbeef;
+    hr = OleGetClipboard(&pDObj);
+    todo_wine ok(hr == S_OK, "OleGetClipboard() got 0x%08x instead of 0x%08x\n", hr, S_OK);
+    if (pDObj && pDObj != (IDataObject *)0xdeadbeef) IDataObject_Release(pDObj);
+}
+
 static void test_get_clipboard(void)
 {
     HRESULT hr;
@@ -1545,11 +1556,65 @@ static void test_getdatahere(void)
 
 }
 
+static DWORD CALLBACK test_data_obj(void *arg)
+{
+    IDataObject *data_obj = arg;
+
+    IDataObject_Release(data_obj);
+    return 0;
+}
+
+static void test_multithreaded_clipboard(void)
+{
+    IDataObject *data_obj;
+    HANDLE thread;
+    HRESULT hr;
+    DWORD ret;
+
+    OleInitialize(NULL);
+
+    hr = OleGetClipboard(&data_obj);
+    ok(hr == S_OK, "OleGetClipboard returned %x\n", hr);
+
+    thread = CreateThread(NULL, 0, test_data_obj, data_obj, 0, NULL);
+    ok(thread != NULL, "CreateThread failed (%d)\n", GetLastError());
+    ret = WaitForSingleObject(thread, 5000);
+    ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", ret);
+
+    hr = OleGetClipboard(&data_obj);
+    ok(hr == S_OK, "OleGetClipboard returned %x\n", hr);
+    IDataObject_Release(data_obj);
+
+    OleUninitialize();
+}
+
+static void test_get_clipboard_locked(void)
+{
+    HRESULT hr;
+    IDataObject *pDObj;
+
+    OleInitialize(NULL);
+
+    pDObj = (IDataObject *)0xdeadbeef;
+    /* lock clipboard */
+    OpenClipboard(NULL);
+    hr = OleGetClipboard(&pDObj);
+    todo_wine ok(hr == CLIPBRD_E_CANT_OPEN, "OleGetClipboard() got 0x%08x instead of 0x%08x\n", hr, CLIPBRD_E_CANT_OPEN);
+    todo_wine ok(pDObj == NULL, "OleGetClipboard() got 0x%p instead of NULL\n",pDObj);
+    if (pDObj) IDataObject_Release(pDObj);
+    CloseClipboard();
+
+    OleUninitialize();
+}
+
 START_TEST(clipboard)
 {
+    test_get_clipboard_unitialized();
     test_set_clipboard();
     test_consumer_refs();
     test_flushed_getdata();
     test_nonole_clipboard();
     test_getdatahere();
+    test_multithreaded_clipboard();
+    test_get_clipboard_locked();
 }
index fa2ef03..7d7949a 100644 (file)
@@ -79,6 +79,7 @@ static HRESULT (WINAPI * pCoSwitchCallContext)(IUnknown *pObject, IUnknown **ppO
 static HRESULT (WINAPI * pCoGetTreatAsClass)(REFCLSID clsidOld, LPCLSID pClsidNew);
 static HRESULT (WINAPI * pCoTreatAsClass)(REFCLSID clsidOld, REFCLSID pClsidNew);
 static HRESULT (WINAPI * pCoGetContextToken)(ULONG_PTR *token);
+static HRESULT (WINAPI * pCoGetApartmentType)(APTTYPE *type, APTTYPEQUALIFIER *qualifier);
 static LONG (WINAPI * pRegDeleteKeyExA)(HKEY, LPCSTR, REGSAM, DWORD);
 static LONG (WINAPI * pRegOverridePredefKey)(HKEY key, HKEY override);
 
@@ -280,12 +281,12 @@ static const char actctx_manifest[] =
 "              progid=\"ProgId.ProgId\""
 "              miscStatusIcon=\"recomposeonresize\""
 "    />"
-"    <comClass clsid=\"{0be35203-8f91-11ce-9de3-00aa004bb851}\""
+"    <comClass description=\"CustomFont Description\" clsid=\"{0be35203-8f91-11ce-9de3-00aa004bb851}\""
 "              progid=\"CustomFont\""
 "              miscStatusIcon=\"recomposeonresize\""
 "              miscStatusContent=\"insideout\""
 "    />"
-"    <comClass clsid=\"{0be35203-8f91-11ce-9de3-00aa004bb852}\""
+"    <comClass description=\"StdFont Description\" clsid=\"{0be35203-8f91-11ce-9de3-00aa004bb852}\""
 "              progid=\"StdFont\""
 "    />"
 "    <comClass clsid=\"{62222222-1234-1234-1234-56789abcdef0}\" >"
@@ -2190,6 +2191,73 @@ static void test_CoInitializeEx(void)
     OleUninitialize();
 }
 
+static void test_OleInitialize_InitCounting(void)
+{
+    HRESULT hr;
+    IUnknown *pUnk;
+    REFCLSID rclsid = &CLSID_InternetZoneManager;
+
+    /* 1. OleInitialize fails but OleUnintialize is still called: apartment stays inited */
+    hr = pCoInitializeEx(NULL, COINIT_MULTITHREADED);
+    ok(hr == S_OK, "CoInitializeEx(COINIT_MULTITHREADED) failed with error 0x%08x\n", hr);
+
+    hr = OleInitialize(NULL);
+    ok(hr == RPC_E_CHANGED_MODE, "OleInitialize should have returned 0x%08x instead of 0x%08x\n", RPC_E_CHANGED_MODE, hr);
+    OleUninitialize();
+
+    pUnk = (IUnknown *)0xdeadbeef;
+    hr = CoCreateInstance(rclsid, NULL, 0x17, &IID_IUnknown, (void **)&pUnk);
+    ok(hr == S_OK, "CoCreateInstance should have returned 0x%08x instead of 0x%08x\n", S_OK, hr);
+    if (pUnk) IUnknown_Release(pUnk);
+
+    CoUninitialize();
+
+    /* 2. Extra multiple OleUninitialize: apartment stays inited until CoUnitialize */
+    hr = CoInitialize(NULL);
+    ok(hr == S_OK, "CoInitialize() failed with error 0x%08x\n", hr);
+
+    hr = OleInitialize(NULL);
+    ok(hr == S_OK, "OleInitialize should have returned 0x%08x instead of 0x%08x\n", S_OK, hr);
+    OleUninitialize();
+    OleUninitialize();
+    OleUninitialize();
+
+    pUnk = (IUnknown *)0xdeadbeef;
+    hr = CoCreateInstance(rclsid, NULL, 0x17, &IID_IUnknown, (void **)&pUnk);
+    ok(hr == S_OK, "CoCreateInstance should have returned 0x%08x instead of 0x%08x\n", S_OK, hr);
+    if (pUnk) IUnknown_Release(pUnk);
+
+    CoUninitialize();
+
+    pUnk = (IUnknown *)0xdeadbeef;
+    hr = CoCreateInstance(rclsid, NULL, 0x17, &IID_IUnknown, (void **)&pUnk);
+    ok(hr == CO_E_NOTINITIALIZED, "CoCreateInstance should have returned 0x%08x instead of 0x%08x\n", CO_E_NOTINITIALIZED, hr);
+    if (pUnk) IUnknown_Release(pUnk);
+
+    /* 3. CoUninitialize does not formally deinit Ole */
+    hr = CoInitialize(NULL);
+    ok(hr == S_OK, "CoInitialize() failed with error 0x%08x\n", hr);
+
+    hr = OleInitialize(NULL);
+    ok(hr == S_OK, "OleInitialize should have returned 0x%08x instead of 0x%08x\n", S_OK, hr);
+
+    CoUninitialize();
+    CoUninitialize();
+
+    pUnk = (IUnknown *)0xdeadbeef;
+    hr = CoCreateInstance(rclsid, NULL, 0x17, &IID_IUnknown, (void **)&pUnk);
+    ok(hr == CO_E_NOTINITIALIZED, "CoCreateInstance should have returned 0x%08x instead of 0x%08x\n", CO_E_NOTINITIALIZED, hr);
+      /* COM is not initialized anymore */
+    if (pUnk) IUnknown_Release(pUnk);
+
+    hr = OleInitialize(NULL);
+    ok(hr == S_FALSE, "OleInitialize should have returned 0x%08x instead of 0x%08x\n", S_FALSE, hr);
+      /* ... but native OleInit returns S_FALSE as if Ole is considered initialized */
+
+    OleUninitialize();
+
+}
+
 static void test_OleRegGetMiscStatus(void)
 {
     ULONG_PTR cookie;
@@ -2234,6 +2302,159 @@ static void test_OleRegGetMiscStatus(void)
     }
 }
 
+static void test_OleRegGetUserType(void)
+{
+    static const WCHAR stdfont_usertypeW[] = {'S','t','a','n','d','a','r','d',' ','F','o','n','t',0};
+    static const WCHAR stdfont2_usertypeW[] = {'C','L','S','I','D','_','S','t','d','F','o','n','t',0};
+    static const WCHAR clsidkeyW[] = {'C','L','S','I','D',0};
+    static const WCHAR defvalueW[] = {'D','e','f','a','u','l','t',' ','N','a','m','e',0};
+    static const WCHAR auxvalue0W[] = {'A','u','x',' ','N','a','m','e',' ','0',0};
+    static const WCHAR auxvalue2W[] = {'A','u','x',' ','N','a','m','e',' ','2',0};
+    static const WCHAR auxvalue3W[] = {'A','u','x',' ','N','a','m','e',' ','3',0};
+    static const WCHAR auxvalue4W[] = {'A','u','x',' ','N','a','m','e',' ','4',0};
+
+    static const char auxvalues[][16] = {
+        "Aux Name 0",
+        "Aux Name 1",
+        "Aux Name 2",
+        "Aux Name 3",
+        "Aux Name 4"
+    };
+
+    HKEY clsidhkey, hkey, auxhkey, classkey;
+    DWORD form, ret, disposition;
+    WCHAR clsidW[39];
+    ULONG_PTR cookie;
+    HANDLE handle;
+    HRESULT hr;
+    WCHAR *str;
+    int i;
+
+    for (form = 0; form <= USERCLASSTYPE_APPNAME+1; form++) {
+        hr = OleRegGetUserType(&CLSID_Testclass, form, NULL);
+        ok(hr == E_INVALIDARG, "form %u: got 0x%08x\n", form, hr);
+
+        str = (void*)0xdeadbeef;
+        hr = OleRegGetUserType(&CLSID_Testclass, form, &str);
+        ok(hr == REGDB_E_CLASSNOTREG, "form %u: got 0x%08x\n", form, hr);
+        ok(str == NULL, "form %u: got %p\n", form, str);
+
+        /* same string returned for StdFont for all form types */
+        str = NULL;
+        hr = OleRegGetUserType(&CLSID_StdFont, form, &str);
+        ok(hr == S_OK, "form %u: got 0x%08x\n", form, hr);
+        ok(!lstrcmpW(str, stdfont_usertypeW) || !lstrcmpW(str, stdfont2_usertypeW) /* winxp */,
+            "form %u, got %s\n", form, wine_dbgstr_w(str));
+        CoTaskMemFree(str);
+    }
+
+    if ((handle = activate_context(actctx_manifest, &cookie)))
+    {
+        for (form = 0; form <= USERCLASSTYPE_APPNAME+1; form++) {
+            str = (void*)0xdeadbeef;
+            hr = OleRegGetUserType(&CLSID_Testclass, form, &str);
+            ok(hr == REGDB_E_CLASSNOTREG, "form %u: got 0x%08x\n", form, hr);
+            ok(str == NULL, "form %u: got %s\n", form, wine_dbgstr_w(str));
+
+            /* same string returned for StdFont for all form types */
+            str = NULL;
+            hr = OleRegGetUserType(&CLSID_StdFont, form, &str);
+            ok(hr == S_OK, "form %u: got 0x%08x\n", form, hr);
+            ok(!lstrcmpW(str, stdfont_usertypeW) || !lstrcmpW(str, stdfont2_usertypeW) /* winxp */,
+                "form %u, got %s\n", form, wine_dbgstr_w(str));
+            CoTaskMemFree(str);
+        }
+
+        pDeactivateActCtx(0, cookie);
+        pReleaseActCtx(handle);
+    }
+
+    /* test using registered CLSID */
+    StringFromGUID2(&CLSID_non_existent, clsidW, sizeof(clsidW)/sizeof(clsidW[0]));
+
+    ret = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsidkeyW, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &clsidhkey, &disposition);
+    if (ret == ERROR_ACCESS_DENIED)
+    {
+        skip("Failed to create test key, skipping some of OleRegGetUserType() tests.\n");
+        return;
+    }
+
+    ok(!ret, "failed to create a key %d, error %d\n", ret, GetLastError());
+
+    ret = RegCreateKeyExW(clsidhkey, clsidW, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &classkey, NULL);
+    ok(!ret, "failed to create a key %d, error %d\n", ret, GetLastError());
+
+    ret = RegSetValueExW(classkey, NULL, 0, REG_SZ, (const BYTE*)defvalueW, sizeof(defvalueW));
+    ok(!ret, "got %d, error %d\n", ret, GetLastError());
+
+    ret = RegCreateKeyExA(classkey, "AuxUserType", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &auxhkey, NULL);
+    ok(!ret, "got %d, error %d\n", ret, GetLastError());
+
+    /* populate AuxUserType */
+    for (i = 0; i <= 4; i++) {
+        char name[16];
+
+        sprintf(name, "AuxUserType\\%d", i);
+        ret = RegCreateKeyExA(classkey, name, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
+        ok(!ret, "got %d, error %d\n", ret, GetLastError());
+
+        ret = RegSetValueExA(hkey, NULL, 0, REG_SZ, (const BYTE*)auxvalues[i], strlen(auxvalues[i]));
+        ok(!ret, "got %d, error %d\n", ret, GetLastError());
+        RegCloseKey(hkey);
+    }
+
+    str = NULL;
+    hr = OleRegGetUserType(&CLSID_non_existent, 0, &str);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    ok(!lstrcmpW(str, auxvalue0W), "got %s\n", wine_dbgstr_w(str));
+    CoTaskMemFree(str);
+
+    str = NULL;
+    hr = OleRegGetUserType(&CLSID_non_existent, USERCLASSTYPE_FULL, &str);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    ok(!lstrcmpW(str, defvalueW), "got %s\n", wine_dbgstr_w(str));
+    CoTaskMemFree(str);
+
+    str = NULL;
+    hr = OleRegGetUserType(&CLSID_non_existent, USERCLASSTYPE_SHORT, &str);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    ok(!lstrcmpW(str, auxvalue2W), "got %s\n", wine_dbgstr_w(str));
+    CoTaskMemFree(str);
+
+    str = NULL;
+    hr = OleRegGetUserType(&CLSID_non_existent, USERCLASSTYPE_APPNAME, &str);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    ok(!lstrcmpW(str, auxvalue3W), "got %s\n", wine_dbgstr_w(str));
+    CoTaskMemFree(str);
+
+    str = NULL;
+    hr = OleRegGetUserType(&CLSID_non_existent, USERCLASSTYPE_APPNAME+1, &str);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    ok(!lstrcmpW(str, auxvalue4W), "got %s\n", wine_dbgstr_w(str));
+    CoTaskMemFree(str);
+
+    str = NULL;
+    hr = OleRegGetUserType(&CLSID_non_existent, USERCLASSTYPE_APPNAME+2, &str);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    ok(!lstrcmpW(str, defvalueW), "got %s\n", wine_dbgstr_w(str));
+    CoTaskMemFree(str);
+
+    /* registry cleanup */
+    for (i = 0; i <= 4; i++)
+    {
+        char name[2];
+        sprintf(name, "%d", i);
+        RegDeleteKeyA(auxhkey, name);
+    }
+    RegCloseKey(auxhkey);
+    RegDeleteKeyA(classkey, "AuxUserType");
+    RegCloseKey(classkey);
+    RegDeleteKeyW(clsidhkey, clsidW);
+    RegCloseKey(clsidhkey);
+    if (disposition == REG_CREATED_NEW_KEY)
+        RegDeleteKeyA(HKEY_CLASSES_ROOT, "CLSID");
+}
+
 static void test_CoCreateGuid(void)
 {
     HRESULT hr;
@@ -2628,6 +2849,93 @@ static void test_CoWaitForMultipleHandles(void)
     CoUninitialize();
 }
 
+static void test_CoGetMalloc(void)
+{
+    IMalloc *imalloc;
+    HRESULT hr;
+
+if (0) /* crashes on native */
+    hr = CoGetMalloc(0, NULL);
+
+    imalloc = (void*)0xdeadbeef;
+    hr = CoGetMalloc(0, &imalloc);
+    ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
+    ok(imalloc == NULL, "got %p\n", imalloc);
+
+    imalloc = (void*)0xdeadbeef;
+    hr = CoGetMalloc(MEMCTX_SHARED, &imalloc);
+    ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
+    ok(imalloc == NULL, "got %p\n", imalloc);
+
+    imalloc = (void*)0xdeadbeef;
+    hr = CoGetMalloc(MEMCTX_MACSYSTEM, &imalloc);
+    ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
+    ok(imalloc == NULL, "got %p\n", imalloc);
+
+    imalloc = (void*)0xdeadbeef;
+    hr = CoGetMalloc(MEMCTX_UNKNOWN, &imalloc);
+    ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
+    ok(imalloc == NULL, "got %p\n", imalloc);
+
+    imalloc = (void*)0xdeadbeef;
+    hr = CoGetMalloc(MEMCTX_SAME, &imalloc);
+    ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
+    ok(imalloc == NULL, "got %p\n", imalloc);
+
+    imalloc = NULL;
+    hr = CoGetMalloc(MEMCTX_TASK, &imalloc);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    ok(imalloc != NULL, "got %p\n", imalloc);
+    IMalloc_Release(imalloc);
+}
+
+static void test_CoGetApartmentType(void)
+{
+    APTTYPEQUALIFIER qualifier;
+    APTTYPE type;
+    HRESULT hr;
+
+    if (!pCoGetApartmentType)
+    {
+        win_skip("CoGetApartmentType not present\n");
+        return;
+    }
+
+    hr = pCoGetApartmentType(NULL, NULL);
+    ok(hr == E_INVALIDARG, "CoGetApartmentType succeeded, error: 0x%0x\n", hr);
+
+    hr = pCoGetApartmentType(&type, NULL);
+    ok(hr == E_INVALIDARG, "CoGetApartmentType succeeded, error: 0x%0x\n", hr);
+
+    hr = pCoGetApartmentType(NULL, &qualifier);
+    ok(hr == E_INVALIDARG, "CoGetApartmentType succeeded, error: 0x%0x\n", hr);
+
+    hr = pCoGetApartmentType(&type, &qualifier);
+    ok(hr == CO_E_NOTINITIALIZED, "CoGetApartmentType succeeded, error: 0x%0x\n", hr);
+    ok(type == APTTYPE_CURRENT, "Expected APTTYPE_CURRENT, got %u\n", type);
+    ok(qualifier == APTTYPEQUALIFIER_NONE, "Expected APTTYPEQUALIFIER_NONE, got %u\n", qualifier);
+
+    hr = pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+    ok(!hr, "CoInitializeEx failed, error: 0x%08x\n", hr);
+
+    hr = pCoGetApartmentType(&type, &qualifier);
+    ok(!hr, "CoGetApartmentType failed, error: 0x%08x\n", hr);
+    ok(type == APTTYPE_MAINSTA, "Expected APTTYPE_MAINSTA, got %u\n", type);
+    ok(qualifier == APTTYPEQUALIFIER_NONE, "Expected APTTYPEQUALIFIER_NONE, got %u\n", qualifier);
+
+    CoUninitialize();
+
+    hr = pCoInitializeEx(NULL, COINIT_MULTITHREADED);
+    ok(!hr, "CoInitializeEx failed, error: 0x%08x\n", hr);
+
+    hr = pCoGetApartmentType(&type, &qualifier);
+    ok(!hr, "CoGetApartmentType failed, error: 0x%08x\n", hr);
+    ok(type == APTTYPE_MTA, "Expected APTTYPE_MTA, got %u\n", type);
+    ok(qualifier == APTTYPEQUALIFIER_NONE, "Expected APTTYPEQUALIFIER_NONE, got %u\n", qualifier);
+
+    CoUninitialize();
+}
+
 static void init_funcs(void)
 {
     HMODULE hOle32 = GetModuleHandleA("ole32");
@@ -2639,6 +2947,7 @@ static void init_funcs(void)
     pCoGetTreatAsClass = (void*)GetProcAddress(hOle32,"CoGetTreatAsClass");
     pCoTreatAsClass = (void*)GetProcAddress(hOle32,"CoTreatAsClass");
     pCoGetContextToken = (void*)GetProcAddress(hOle32, "CoGetContextToken");
+    pCoGetApartmentType = (void*)GetProcAddress(hOle32, "CoGetApartmentType");
     pRegDeleteKeyExA = (void*)GetProcAddress(hAdvapi32, "RegDeleteKeyExA");
     pRegOverridePredefKey = (void*)GetProcAddress(hAdvapi32, "RegOverridePredefKey");
     pCoInitializeEx = (void*)GetProcAddress(hOle32, "CoInitializeEx");
@@ -2687,7 +2996,11 @@ START_TEST(compobj)
     test_CoGetContextToken();
     test_TreatAsClass();
     test_CoInitializeEx();
+    test_OleInitialize_InitCounting();
     test_OleRegGetMiscStatus();
     test_CoCreateGuid();
     test_CoWaitForMultipleHandles();
+    test_CoGetMalloc();
+    test_OleRegGetUserType();
+    test_CoGetApartmentType();
 }
index 27ad542..52cf915 100644 (file)
@@ -2,6 +2,7 @@
  * Stream on HGLOBAL Tests
  *
  * Copyright 2006 Robert Shearman (for CodeWeavers)
+ * Copyright 2016 Dmitry Timoshkov
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -513,11 +514,240 @@ static void test_freed_hglobal(void)
     IStream_Release(pStream);
 }
 
+static void stream_info(IStream *stream, HGLOBAL *hmem, int *size, int *pos)
+{
+    HRESULT hr;
+    STATSTG stat;
+    LARGE_INTEGER offset;
+    ULARGE_INTEGER newpos;
+
+    *hmem = 0;
+    *size = *pos = -1;
+
+    hr = GetHGlobalFromStream(stream, hmem);
+    ok(hr == S_OK, "unexpected %#x\n", hr);
+
+    memset(&stat, 0x55, sizeof(stat));
+    hr = IStream_Stat(stream, &stat, STATFLAG_DEFAULT);
+    ok(hr == S_OK, "unexpected %#x\n", hr);
+    ok(stat.type == STGTY_STREAM, "unexpected %#x\n", stat.type);
+    ok(!stat.pwcsName, "unexpected %p\n", stat.pwcsName);
+    ok(IsEqualIID(&stat.clsid, &GUID_NULL), "unexpected %s\n", wine_dbgstr_guid(&stat.clsid));
+    ok(!stat.cbSize.HighPart, "unexpected %#x\n", stat.cbSize.HighPart);
+    *size = stat.cbSize.LowPart;
+
+    offset.QuadPart = 0;
+    hr = IStream_Seek(stream, offset, STREAM_SEEK_CUR, &newpos);
+    ok(hr == S_OK, "unexpected %#x\n", hr);
+    ok(!newpos.HighPart, "unexpected %#x\n", newpos.HighPart);
+    *pos = newpos.LowPart;
+}
+
+static void test_IStream_Clone(void)
+{
+    static const char hello[] = "Hello World!";
+    char buf[32];
+    HRESULT hr;
+    IStream *stream, *clone;
+    HGLOBAL orig_hmem, hmem, hmem_clone;
+    ULARGE_INTEGER newsize;
+    LARGE_INTEGER offset;
+    int size, pos, ret;
+
+    /* test simple case for Clone */
+    orig_hmem = GlobalAlloc(GMEM_MOVEABLE, 0);
+    ok(orig_hmem != 0, "unexpected %p\n", orig_hmem);
+    hr = CreateStreamOnHGlobal(orig_hmem, TRUE, &stream);
+    ok(hr == S_OK, "unexpected %#x\n", hr);
+
+    hr = GetHGlobalFromStream(stream, NULL);
+    ok(hr == E_INVALIDARG, "unexpected %#x\n", hr);
+
+    hr = GetHGlobalFromStream(NULL, &hmem);
+    ok(hr == E_INVALIDARG, "unexpected %#x\n", hr);
+
+    stream_info(stream, &hmem, &size, &pos);
+    ok(hmem == orig_hmem, "handles should match\n");
+    ok(size == 0,  "unexpected %d\n", size);
+    ok(pos == 0,  "unexpected %d\n", pos);
+
+    hr = IStream_Clone(stream, &clone);
+    ok(hr == S_OK, "unexpected %#x\n", hr);
+
+    hr = IStream_Write(stream, hello, sizeof(hello), NULL);
+    ok(hr == S_OK, "unexpected %#x\n", hr);
+
+    stream_info(stream, &hmem, &size, &pos);
+    ok(hmem != 0, "unexpected %p\n", hmem);
+    ok(size == 13,  "unexpected %d\n", size);
+    ok(pos == 13,  "unexpected %d\n", pos);
+
+    stream_info(clone, &hmem_clone, &size, &pos);
+    ok(hmem_clone == hmem, "handles should match\n");
+    ok(size == 13,  "unexpected %d\n", size);
+    ok(pos == 0,  "unexpected %d\n", pos);
+
+    buf[0] = 0;
+    hr = IStream_Read(clone, buf, sizeof(buf), NULL);
+    ok(hr == S_OK, "unexpected %#x\n", hr);
+    ok(!strcmp(buf, hello), "wrong stream contents\n");
+
+    newsize.QuadPart = 0x8000;
+    hr = IStream_SetSize(stream, newsize);
+    ok(hr == S_OK, "unexpected %#x\n", hr);
+
+    stream_info(stream, &hmem, &size, &pos);
+    ok(hmem != 0,  "unexpected %p\n", hmem);
+    ok(hmem == orig_hmem,  "unexpected %p\n", hmem);
+    ok(size == 0x8000,  "unexpected %#x\n", size);
+    ok(pos == 13,  "unexpected %d\n", pos);
+
+    stream_info(clone, &hmem_clone, &size, &pos);
+    ok(hmem_clone == hmem, "handles should match\n");
+    ok(size == 0x8000,  "unexpected %#x\n", size);
+    ok(pos == 13,  "unexpected %d\n", pos);
+
+    IStream_Release(clone);
+    IStream_Release(stream);
+
+    /* exploit GMEM_FIXED forced move for the same base streams */
+    orig_hmem = GlobalAlloc(GMEM_FIXED, 1);
+    ok(orig_hmem != 0, "unexpected %p\n", orig_hmem);
+    hr = CreateStreamOnHGlobal(orig_hmem, TRUE, &stream);
+    ok(hr == S_OK, "unexpected %#x\n", hr);
+
+    hr = IStream_Clone(stream, &clone);
+    ok(hr == S_OK, "unexpected %#x\n", hr);
+
+    stream_info(stream, &hmem, &size, &pos);
+    ok(hmem != 0,  "unexpected %p\n", hmem);
+    ok(size == 1,  "unexpected %d\n", size);
+    ok(pos == 0,  "unexpected %d\n", pos);
+
+    stream_info(clone, &hmem_clone, &size, &pos);
+    ok(hmem_clone == hmem, "handles should match\n");
+    ok(size == 1,  "unexpected %d\n", size);
+    ok(pos == 0,  "unexpected %d\n", pos);
+
+    newsize.QuadPart = 0x8000;
+    hr = IStream_SetSize(stream, newsize);
+    ok(hr == S_OK, "unexpected %#x\n", hr);
+
+    stream_info(stream, &hmem, &size, &pos);
+    ok(hmem != 0,  "unexpected %p\n", hmem);
+    ok(hmem != orig_hmem,  "unexpected %p\n", hmem);
+    ok(size == 0x8000,  "unexpected %#x\n", size);
+    ok(pos == 0,  "unexpected %d\n", pos);
+
+    stream_info(clone, &hmem_clone, &size, &pos);
+    ok(hmem_clone == hmem, "handles should match\n");
+    ok(size == 0x8000,  "unexpected %#x\n", size);
+    ok(pos == 0,  "unexpected %d\n", pos);
+
+    IStream_Release(stream);
+    IStream_Release(clone);
+
+    /* exploit GMEM_FIXED forced move for different base streams */
+    orig_hmem = GlobalAlloc(GMEM_FIXED, 1);
+    ok(orig_hmem != 0, "unexpected %p\n", orig_hmem);
+    hr = CreateStreamOnHGlobal(orig_hmem, TRUE, &stream);
+    ok(hr == S_OK, "unexpected %#x\n", hr);
+
+    hr = CreateStreamOnHGlobal(orig_hmem, TRUE, &clone);
+    ok(hr == S_OK, "unexpected %#x\n", hr);
+
+    stream_info(stream, &hmem, &size, &pos);
+    ok(hmem != 0,  "unexpected %p\n", hmem);
+    ok(size == 1,  "unexpected %d\n", size);
+    ok(pos == 0,  "unexpected %d\n", pos);
+
+    stream_info(clone, &hmem_clone, &size, &pos);
+    ok(hmem_clone == hmem, "handles should match\n");
+    ok(size == 1,  "unexpected %d\n", size);
+    ok(pos == 0,  "unexpected %d\n", pos);
+
+    newsize.QuadPart = 0x8000;
+    hr = IStream_SetSize(stream, newsize);
+    ok(hr == S_OK, "unexpected %#x\n", hr);
+
+    stream_info(stream, &hmem, &size, &pos);
+    ok(hmem != 0,  "unexpected %p\n", hmem);
+    ok(hmem != orig_hmem,  "unexpected %p\n", hmem);
+    ok(size == 0x8000,  "unexpected %#x\n", size);
+    ok(pos == 0,  "unexpected %d\n", pos);
+
+    stream_info(clone, &hmem_clone, &size, &pos);
+    ok(hmem_clone != hmem, "handles should not match\n");
+    ok(size == 1,  "unexpected %#x\n", size);
+    ok(pos == 0,  "unexpected %d\n", pos);
+
+    IStream_Release(stream);
+    /* releasing clone leads to test termination under windows
+    IStream_Release(clone);
+    */
+
+    /* test Release for a being cloned stream */
+    hr = CreateStreamOnHGlobal(0, TRUE, &stream);
+    ok(hr == S_OK, "unexpected %#x\n", hr);
+
+    hr = IStream_Clone(stream, &clone);
+    ok(hr == S_OK, "unexpected %#x\n", hr);
+
+    stream_info(stream, &hmem, &size, &pos);
+    ok(hmem != 0,  "unexpected %p\n", hmem);
+    ok(size == 0,  "unexpected %d\n", size);
+    ok(pos == 0,  "unexpected %d\n", pos);
+
+    stream_info(clone, &hmem_clone, &size, &pos);
+    ok(hmem_clone == hmem, "handles should match\n");
+    ok(size == 0,  "unexpected %#x\n", size);
+    ok(pos == 0,  "unexpected %d\n", pos);
+
+    ret = IStream_Release(stream);
+    ok(ret == 0, "unexpected %d\n", ret);
+
+    newsize.QuadPart = 0x8000;
+    hr = IStream_SetSize(clone, newsize);
+    ok(hr == S_OK, "unexpected %#x\n", hr);
+
+    stream_info(clone, &hmem_clone, &size, &pos);
+    ok(hmem_clone == hmem, "handles should match\n");
+    ok(size == 0x8000,  "unexpected %#x\n", size);
+    ok(pos == 0,  "unexpected %d\n", pos);
+
+    hr = IStream_Write(clone, hello, sizeof(hello), NULL);
+    ok(hr == S_OK, "unexpected %#x\n", hr);
+
+    stream_info(clone, &hmem_clone, &size, &pos);
+    ok(hmem_clone == hmem, "handles should match\n");
+    ok(size == 0x8000,  "unexpected %#x\n", size);
+    ok(pos == 13,  "unexpected %d\n", pos);
+
+    offset.QuadPart = 0;
+    hr = IStream_Seek(clone, offset, STREAM_SEEK_SET, NULL);
+    ok(hr == S_OK, "unexpected %#x\n", hr);
+
+    buf[0] = 0;
+    hr = IStream_Read(clone, buf, sizeof(buf), NULL);
+    ok(hr == S_OK, "unexpected %#x\n", hr);
+    ok(!strcmp(buf, hello), "wrong stream contents\n");
+
+    stream_info(clone, &hmem_clone, &size, &pos);
+    ok(hmem_clone == hmem, "handles should match\n");
+    ok(size == 0x8000,  "unexpected %#x\n", size);
+    ok(pos == 32,  "unexpected %d\n", pos);
+
+    ret = IStream_Release(clone);
+    ok(ret == 0, "unexpected %d\n", ret);
+}
+
 START_TEST(hglobalstream)
 {
     HRESULT hr;
     IStream *pStream;
 
+    test_IStream_Clone();
+
     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
     ok_ole_success(hr, "CreateStreamOnHGlobal");
 
index cf3bd1b..7753946 100644 (file)
@@ -113,7 +113,7 @@ static FORMATETC *g_expected_fetc = NULL;
 
 static BOOL g_showRunnable = TRUE;
 static BOOL g_isRunning = TRUE;
-static BOOL g_failGetMiscStatus;
+static HRESULT g_GetMiscStatusFailsWith = S_OK;
 static HRESULT g_QIFailsWith;
 
 static UINT cf_test_1, cf_test_2, cf_test_3;
@@ -423,12 +423,15 @@ static HRESULT WINAPI OleObject_EnumAdvise
 static HRESULT WINAPI OleObject_GetMiscStatus
 (
     IOleObject *iface,
-    DWORD dwAspect,
+    DWORD aspect,
     DWORD *pdwStatus
 )
 {
     CHECK_EXPECTED_METHOD("OleObject_GetMiscStatus");
-    if(!g_failGetMiscStatus)
+
+    ok(aspect == DVASPECT_CONTENT, "got aspect %d\n", aspect);
+
+    if (g_GetMiscStatusFailsWith == S_OK)
     {
         *pdwStatus = OLEMISC_RECOMPOSEONRESIZE;
         return S_OK;
@@ -436,7 +439,7 @@ static HRESULT WINAPI OleObject_GetMiscStatus
     else
     {
         *pdwStatus = 0x1234;
-        return E_FAIL;
+        return g_GetMiscStatusFailsWith;
     }
 }
 
@@ -483,7 +486,7 @@ static IOleObject OleObject = { &OleObjectVtbl };
 static HRESULT WINAPI OleObjectPersistStg_QueryInterface(IPersistStorage *iface, REFIID riid, void **ppv)
 {
     trace("OleObjectPersistStg_QueryInterface\n");
-    return IUnknown_QueryInterface((IUnknown *)&OleObject, riid, ppv);
+    return IOleObject_QueryInterface(&OleObject, riid, ppv);
 }
 
 static ULONG WINAPI OleObjectPersistStg_AddRef(IPersistStorage *iface)
@@ -581,7 +584,7 @@ static IPersistStorage OleObjectPersistStg = { &OleObjectPersistStgVtbl };
 
 static HRESULT WINAPI OleObjectCache_QueryInterface(IOleCache *iface, REFIID riid, void **ppv)
 {
-    return IUnknown_QueryInterface((IUnknown *)&OleObject, riid, ppv);
+    return IOleObject_QueryInterface(&OleObject, riid, ppv);
 }
 
 static ULONG WINAPI OleObjectCache_AddRef(IOleCache *iface)
@@ -707,7 +710,7 @@ static ULONG WINAPI OleObjectCF_Release(IClassFactory *iface)
 
 static HRESULT WINAPI OleObjectCF_CreateInstance(IClassFactory *iface, IUnknown *punkOuter, REFIID riid, void **ppv)
 {
-    return IUnknown_QueryInterface((IUnknown *)&OleObject, riid, ppv);
+    return IOleObject_QueryInterface(&OleObject, riid, ppv);
 }
 
 static HRESULT WINAPI OleObjectCF_LockServer(IClassFactory *iface, BOOL lock)
@@ -728,7 +731,7 @@ static IClassFactory OleObjectCF = { &OleObjectCFVtbl };
 
 static HRESULT WINAPI OleObjectRunnable_QueryInterface(IRunnableObject *iface, REFIID riid, void **ppv)
 {
-    return IUnknown_QueryInterface((IUnknown *)&OleObject, riid, ppv);
+    return IOleObject_QueryInterface(&OleObject, riid, ppv);
 }
 
 static ULONG WINAPI OleObjectRunnable_AddRef(IRunnableObject *iface)
@@ -919,6 +922,30 @@ static void test_OleCreate(IStorage *pStorage)
         { "OleObject_Release", TEST_OPTIONAL /* NT4 only */ },
         { NULL, 0 }
     };
+    static const struct expected_method methods_olerender_draw_with_site[] =
+    {
+        { "OleObject_QueryInterface", 0 },
+        { "OleObject_AddRef", 0 },
+        { "OleObject_QueryInterface", 0 },
+        { "OleObject_AddRef", 0 },
+        { "OleObject_GetMiscStatus", 0 },
+        { "OleObject_QueryInterface", 0 },
+        { "OleObjectPersistStg_AddRef", 0 },
+        { "OleObjectPersistStg_InitNew", 0 },
+        { "OleObjectPersistStg_Release", 0 },
+        { "OleObject_SetClientSite", 0 },
+        { "OleObject_Release", 0 },
+        { "OleObject_QueryInterface", 0 },
+        { "OleObjectRunnable_AddRef", 0 },
+        { "OleObjectRunnable_Run", 0 },
+        { "OleObjectRunnable_Release", 0 },
+        { "OleObject_QueryInterface", 0 },
+        { "OleObjectCache_AddRef", 0 },
+        { "OleObjectCache_Cache", 0 },
+        { "OleObjectCache_Release", 0 },
+        { "OleObject_Release", 0 },
+        { NULL, 0 }
+    };
     static const struct expected_method methods_olerender_format[] =
     {
         { "OleObject_QueryInterface", 0 },
@@ -1021,6 +1048,23 @@ static void test_OleCreate(IStorage *pStorage)
     IOleObject_Release(pObject);
     CHECK_NO_EXTRA_METHODS();
 
+    expected_method_list = methods_olerender_draw_with_site;
+    trace("OleCreate with OLERENDER_DRAW, with site:\n");
+    hr = OleCreate(&CLSID_Equation3, &IID_IOleObject, OLERENDER_DRAW, NULL, (IOleClientSite*)0xdeadbeef, pStorage, (void **)&pObject);
+    ok_ole_success(hr, "OleCreate");
+    IOleObject_Release(pObject);
+    CHECK_NO_EXTRA_METHODS();
+
+    /* GetMiscStatus fails */
+    g_GetMiscStatusFailsWith = 0x8fafefaf;
+    expected_method_list = methods_olerender_draw_with_site;
+    trace("OleCreate with OLERENDER_DRAW, with site:\n");
+    hr = OleCreate(&CLSID_Equation3, &IID_IOleObject, OLERENDER_DRAW, NULL, (IOleClientSite*)0xdeadbeef, pStorage, (void **)&pObject);
+    ok_ole_success(hr, "OleCreate");
+    IOleObject_Release(pObject);
+    CHECK_NO_EXTRA_METHODS();
+    g_GetMiscStatusFailsWith = S_OK;
+
     formatetc.cfFormat = CF_TEXT;
     formatetc.ptd = NULL;
     formatetc.dwAspect = DVASPECT_CONTENT;
@@ -1094,7 +1138,7 @@ static void test_OleLoad(IStorage *pStorage)
 
     /* Test once with IOleObject_GetMiscStatus failing */
     expected_method_list = methods_oleload;
-    g_failGetMiscStatus = TRUE;
+    g_GetMiscStatusFailsWith = E_FAIL;
     trace("OleLoad:\n");
     hr = OleLoad(pStorage, &IID_IOleObject, (IOleClientSite *)0xdeadbeef, (void **)&pObject);
     ok(hr == S_OK ||
@@ -1110,9 +1154,9 @@ static void test_OleLoad(IStorage *pStorage)
         IOleObject_Release(pObject);
         CHECK_NO_EXTRA_METHODS();
     }
+    g_GetMiscStatusFailsWith = S_OK;
 
     /* Test again, let IOleObject_GetMiscStatus succeed. */
-    g_failGetMiscStatus = FALSE;
     expected_method_list = methods_oleload;
     trace("OleLoad:\n");
     hr = OleLoad(pStorage, &IID_IOleObject, (IOleClientSite *)0xdeadbeef, (void **)&pObject);
@@ -1454,6 +1498,39 @@ static IDataObjectVtbl DataObjectVtbl =
 
 static IDataObject DataObject = { &DataObjectVtbl };
 
+static HRESULT WINAPI Unknown_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
+{
+    *ppv = NULL;
+    if (IsEqualIID(riid, &IID_IUnknown)) *ppv = iface;
+    if (*ppv)
+    {
+        IUnknown_AddRef((IUnknown *)*ppv);
+        return S_OK;
+    }
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI Unknown_AddRef(IUnknown *iface)
+{
+    ok(0, "unexpected AddRef\n");
+    return 2;
+}
+
+static ULONG WINAPI Unknown_Release(IUnknown *iface)
+{
+    ok(0, "unexpected Release\n");
+    return 1;
+}
+
+static const IUnknownVtbl UnknownVtbl =
+{
+    Unknown_QueryInterface,
+    Unknown_AddRef,
+    Unknown_Release
+};
+
+static IUnknown unknown = { &UnknownVtbl };
+
 static void test_data_cache(void)
 {
     HRESULT hr;
@@ -1524,6 +1601,17 @@ static void test_data_cache(void)
     hr = StgCreateDocfile(NULL, STGM_READWRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE, 0, &pStorage);
     ok_ole_success(hr, "StgCreateDocfile");
 
+    /* aggregation */
+
+    /* requested is not IUnknown */
+    hr = CreateDataCache(&unknown, &CLSID_NULL, &IID_IOleCache2, (void**)&pOleCache);
+todo_wine
+    ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
+
+    hr = CreateDataCache(&unknown, &CLSID_NULL, &IID_IUnknown, (void**)&pOleCache);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    IOleCache2_Release(pOleCache);
+
     /* Test with new data */
 
     hr = CreateDataCache(NULL, &CLSID_NULL, &IID_IOleCache2, (LPVOID *)&pOleCache);
@@ -1870,13 +1958,13 @@ static void test_data_cache_dib_contents_stream(int num)
     CLSID cls;
     SIZEL sz;
 
-    hr = CreateDataCache( NULL, &CLSID_Picture_Metafile, &IID_IUnknown, (void *)&unk );
+    hr = CreateDataCache( NULL, &CLSID_Picture_Metafile, &IID_IUnknown, (void **)&unk );
     ok( SUCCEEDED(hr), "got %08x\n", hr );
-    hr = IUnknown_QueryInterface( unk, &IID_IPersistStorage, (void *)&persist );
+    hr = IUnknown_QueryInterface( unk, &IID_IPersistStorage, (void **)&persist );
     ok( SUCCEEDED(hr), "got %08x\n", hr );
-    hr = IUnknown_QueryInterface( unk, &IID_IDataObject, (void *)&data );
+    hr = IUnknown_QueryInterface( unk, &IID_IDataObject, (void **)&data );
     ok( SUCCEEDED(hr), "got %08x\n", hr );
-    hr = IUnknown_QueryInterface( unk, &IID_IViewObject2, (void *)&view );
+    hr = IUnknown_QueryInterface( unk, &IID_IViewObject2, (void **)&view );
     ok( SUCCEEDED(hr), "got %08x\n", hr );
 
     stg = create_storage( num );
@@ -2172,34 +2260,6 @@ static void test_runnable(void)
     g_showRunnable = TRUE;
 }
 
-static HRESULT WINAPI Unknown_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
-{
-    *ppv = NULL;
-    if (IsEqualIID(riid, &IID_IUnknown)) *ppv = iface;
-    if (*ppv)
-    {
-        IUnknown_AddRef((IUnknown *)*ppv);
-        return S_OK;
-    }
-    return E_NOINTERFACE;
-}
-
-static ULONG WINAPI Unknown_AddRef(IUnknown *iface)
-{
-    return 2;
-}
-
-static ULONG WINAPI Unknown_Release(IUnknown *iface)
-{
-    return 1;
-}
-
-static const IUnknownVtbl UnknownVtbl =
-{
-    Unknown_QueryInterface,
-    Unknown_AddRef,
-    Unknown_Release
-};
 
 static HRESULT WINAPI OleRun_QueryInterface(IRunnableObject *iface, REFIID riid, void **ppv)
 {
@@ -2272,7 +2332,6 @@ static const IRunnableObjectVtbl oleruntestvtbl =
     OleRun_SetContainedObject
 };
 
-static IUnknown unknown = { &UnknownVtbl };
 static IRunnableObject testrunnable = { &oleruntestvtbl };
 
 static void test_OleRun(void)
@@ -2291,7 +2350,7 @@ static void test_OleLockRunning(void)
 {
     HRESULT hr;
 
-    hr = OleLockRunning((LPUNKNOWN)&unknown, TRUE, FALSE);
+    hr = OleLockRunning(&unknown, TRUE, FALSE);
     ok(hr == S_OK, "OleLockRunning failed 0x%08x\n", hr);
 }
 
index 5a8e81d..f426a5a 100644 (file)
@@ -364,18 +364,12 @@ typedef struct _PMemoryAllocator {
     struct _PMemoryAllocator_vtable *vt;
 } PMemoryAllocator;
 
-#ifdef __i386__
-#define __thiscall_wrapper __stdcall
-#else
-#define __thiscall_wrapper __cdecl
-#endif
-
-static void * __thiscall_wrapper PMemoryAllocator_Allocate(PMemoryAllocator *_this, ULONG cbSize)
+static void * WINAPI PMemoryAllocator_Allocate(PMemoryAllocator *_this, ULONG cbSize)
 {
     return CoTaskMemAlloc(cbSize);
 }
 
-static void __thiscall_wrapper PMemoryAllocator_Free(PMemoryAllocator *_this, void *pv)
+static void WINAPI PMemoryAllocator_Free(PMemoryAllocator *_this, void *pv)
 {
     CoTaskMemFree(pv);
 }
index 5bea5d2..b7ed290 100644 (file)
@@ -1180,7 +1180,7 @@ static void test_writeclassstg(void)
 {
     IStorage *stg = NULL;
     HRESULT r;
-    CLSID temp_cls;
+    CLSID temp_cls, cls2;
 
     DeleteFileA(filenameA);
 
@@ -1192,6 +1192,12 @@ static void test_writeclassstg(void)
     r = ReadClassStg( NULL, NULL );
     ok(r == E_INVALIDARG, "ReadClassStg should return E_INVALIDARG instead of 0x%08X\n", r);
 
+    memset(&temp_cls, 0xcc, sizeof(temp_cls));
+    memset(&cls2, 0xcc, sizeof(cls2));
+    r = ReadClassStg( NULL, &temp_cls );
+    ok(r == E_INVALIDARG, "got 0x%08x\n", r);
+    ok(IsEqualCLSID(&temp_cls, &cls2), "got wrong clsid\n");
+
     r = ReadClassStg( stg, NULL );
     ok(r == E_INVALIDARG, "ReadClassStg should return E_INVALIDARG instead of 0x%08X\n", r);
 
@@ -1961,7 +1967,7 @@ static void test_nonroot_transacted(void)
 
 static void test_ReadClassStm(void)
 {
-    CLSID clsid;
+    CLSID clsid, clsid2;
     HRESULT hr;
     IStream *pStream;
     static const LARGE_INTEGER llZero;
@@ -1977,6 +1983,12 @@ static void test_ReadClassStm(void)
     hr = ReadClassStm(pStream, NULL);
     ok(hr == E_INVALIDARG, "ReadClassStm should have returned E_INVALIDARG instead of 0x%08x\n", hr);
 
+    memset(&clsid, 0xcc, sizeof(clsid));
+    memset(&clsid2, 0xcc, sizeof(clsid2));
+    hr = ReadClassStm(NULL, &clsid);
+    ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
+    ok(IsEqualCLSID(&clsid, &clsid2), "got wrong clsid\n");
+
     /* test not rewound stream */
     hr = ReadClassStm(pStream, &clsid);
     ok(hr == STG_E_READFAULT, "ReadClassStm should have returned STG_E_READFAULT instead of 0x%08x\n", hr);