[OLE32_WINETEST] Sync with Wine Staging 2.9. CORE-13362
[reactos.git] / rostests / winetests / ole32 / clipboard.c
index fabd31d..ff3b03d 100644 (file)
@@ -198,7 +198,7 @@ static HRESULT EnumFormatImpl_Create(FORMATETC *fmtetc, UINT fmtetc_cnt, IEnumFO
     ret->fmtetc_cnt = fmtetc_cnt;
     ret->fmtetc = HeapAlloc(GetProcessHeap(), 0, fmtetc_cnt*sizeof(FORMATETC));
     memcpy(ret->fmtetc, fmtetc, fmtetc_cnt*sizeof(FORMATETC));
-    *lplpformatetc = (LPENUMFORMATETC)ret;
+    *lplpformatetc = &ret->IEnumFORMATETC_iface;
     return S_OK;
 }
 
@@ -252,6 +252,10 @@ static HRESULT WINAPI DataObjectImpl_GetData(IDataObject* iface, FORMATETC *pfor
 
     DataObjectImpl_GetData_calls++;
 
+    ok(pmedium->tymed == 0, "pmedium->tymed = %u\n", pmedium->tymed);
+    ok(U(*pmedium).hGlobal == NULL, "pmedium->hGlobal = %p\n", U(*pmedium).hGlobal);
+    ok(pmedium->pUnkForRelease == NULL, "pmedium->pUnkForRelease = %p\n", pmedium->pUnkForRelease);
+
     if(pformatetc->lindex != -1)
         return DV_E_FORMATETC;
 
@@ -401,7 +405,7 @@ static HRESULT DataObjectImpl_CreateText(LPCSTR text, LPDATAOBJECT *lplpdataobj)
     obj->fmtetc = HeapAlloc(GetProcessHeap(), 0, obj->fmtetc_cnt*sizeof(FORMATETC));
     InitFormatEtc(obj->fmtetc[0], CF_TEXT, TYMED_HGLOBAL);
 
-    *lplpdataobj = (LPDATAOBJECT)obj;
+    *lplpdataobj = &obj->IDataObject_iface;
     return S_OK;
 }
 
@@ -457,10 +461,21 @@ static HRESULT DataObjectImpl_CreateComplex(LPDATAOBJECT *lplpdataobj)
     InitFormatEtc(obj->fmtetc[7], cf_another, 0xfffff);
     obj->fmtetc[7].dwAspect = DVASPECT_ICON;
 
-    *lplpdataobj = (LPDATAOBJECT)obj;
+    *lplpdataobj = &obj->IDataObject_iface;
     return S_OK;
 }
 
+static void test_get_clipboard_uninitialized(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;
@@ -607,9 +622,7 @@ static void test_enum_fmtetc(IDataObject *src)
     if(src)
     {
         hr = IEnumFORMATETC_Next(src_enum, 1, &src_fmt, NULL);
-        ok(hr == S_FALSE ||
-           broken(hr == S_OK && count == 5), /* win9x and winme don't enumerate duplicated cf's */
-           "%d: got %08x\n", count, hr);
+        ok(hr == S_FALSE, "%d: got %08x\n", count, hr);
         IEnumFORMATETC_Release(src_enum);
     }
 
@@ -790,8 +803,7 @@ static void test_cf_dataobject(IDataObject *data)
             ok(DataObjectImpl_GetDataHere_calls == 1, "got %d\n", DataObjectImpl_GetDataHere_calls);
             ptr = GlobalLock(h);
             size = GlobalSize(h);
-            ok(size == strlen(cmpl_stm_data) ||
-               broken(size > strlen(cmpl_stm_data)), /* win9x, winme */
+            ok(size == strlen(cmpl_stm_data),
                "expected %d got %d\n", lstrlenA(cmpl_stm_data), size);
             ok(!memcmp(ptr, cmpl_stm_data, strlen(cmpl_stm_data)), "mismatch\n");
             GlobalUnlock(h);
@@ -807,8 +819,7 @@ static void test_cf_dataobject(IDataObject *data)
             ok(DataObjectImpl_GetDataHere_calls == 0, "got %d\n", DataObjectImpl_GetDataHere_calls);
             ptr = GlobalLock(h);
             size = GlobalSize(h);
-            ok(size == strlen(cmpl_text_data) + 1 ||
-               broken(size > strlen(cmpl_text_data) + 1), /* win9x, winme */
+            ok(size == strlen(cmpl_text_data) + 1,
                "expected %d got %d\n", lstrlenA(cmpl_text_data) + 1, size);
             ok(!memcmp(ptr, cmpl_text_data, strlen(cmpl_text_data) + 1), "mismatch\n");
             GlobalUnlock(h);
@@ -825,6 +836,7 @@ static void test_set_clipboard(void)
     ULONG ref;
     LPDATAOBJECT data1, data2, data_cmpl;
     HGLOBAL hblob, h;
+    void *ptr;
 
     cf_stream = RegisterClipboardFormatA("stream format");
     cf_storage = RegisterClipboardFormatA("storage format");
@@ -850,10 +862,7 @@ static void test_set_clipboard(void)
 
     CoInitialize(NULL);
     hr = OleSetClipboard(data1);
-    ok(hr == CO_E_NOTINITIALIZED ||
-       hr == CLIPBRD_E_CANT_SET, /* win9x */
-       "OleSetClipboard should have failed with "
-       "CO_E_NOTINITIALIZED or CLIPBRD_E_CANT_SET instead of 0x%08x\n", hr);
+    ok(hr == CO_E_NOTINITIALIZED, "OleSetClipboard failed with 0x%08x\n", hr);
     CoUninitialize();
 
     hr = OleInitialize(NULL);
@@ -885,14 +894,18 @@ static void test_set_clipboard(void)
     /* put a format directly onto the clipboard to show
        OleFlushClipboard doesn't empty the clipboard */
     hblob = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT, 10);
-    OpenClipboard(NULL);
+    ptr = GlobalLock( hblob );
+    ok( ptr && ptr != hblob, "got fixed block %p / %p\n", ptr, hblob );
+    GlobalUnlock( hblob );
+    ok( OpenClipboard(NULL), "OpenClipboard failed\n" );
     h = SetClipboardData(cf_onemore, hblob);
     ok(h == hblob, "got %p\n", h);
     h = GetClipboardData(cf_onemore);
-    ok(h == hblob ||
-       broken(h != NULL), /* win9x */
-       "got %p\n", h);
-    CloseClipboard();
+    ok(h == hblob, "got %p / %p\n", h, hblob);
+    ptr = GlobalLock( h );
+    ok( ptr && ptr != h, "got fixed block %p / %p\n", ptr, h );
+    GlobalUnlock( hblob );
+    ok( CloseClipboard(), "CloseClipboard failed\n" );
 
     hr = OleFlushClipboard();
     ok(hr == S_OK, "failed to flush clipboard, hr = 0x%08x\n", hr);
@@ -904,12 +917,13 @@ static void test_set_clipboard(void)
     ok(hr == S_FALSE, "expect S_FALSE, hr = 0x%08x\n", hr);
 
     /* format should survive the flush */
-    OpenClipboard(NULL);
+    ok( OpenClipboard(NULL), "OpenClipboard failed\n" );
     h = GetClipboardData(cf_onemore);
-    ok(h == hblob ||
-       broken(h != NULL), /* win9x */
-       "got %p\n", h);
-    CloseClipboard();
+    ok(h == hblob, "got %p\n", h);
+    ptr = GlobalLock( h );
+    ok( ptr && ptr != h, "got fixed block %p / %p\n", ptr, h );
+    GlobalUnlock( hblob );
+    ok( CloseClipboard(), "CloseClipboard failed\n" );
 
     test_cf_dataobject(NULL);
 
@@ -941,6 +955,104 @@ static void test_set_clipboard(void)
     OleUninitialize();
 }
 
+static LPDATAOBJECT clip_data;
+static HWND next_wnd;
+static UINT wm_drawclipboard;
+
+static LRESULT CALLBACK clipboard_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
+{
+    LRESULT ret;
+
+    switch (msg)
+    {
+    case WM_DRAWCLIPBOARD:
+        wm_drawclipboard++;
+        if (clip_data)
+        {
+            /* if this is the WM_DRAWCLIPBOARD of a previous change, the data isn't current yet */
+            /* this demonstrates an issue in Qt where it will free the data while it's being set */
+            HRESULT hr = OleIsCurrentClipboard( clip_data );
+            ok( hr == (wm_drawclipboard > 1) ? S_OK : S_FALSE,
+                "OleIsCurrentClipboard returned %x\n", hr );
+        }
+        break;
+    case WM_CHANGECBCHAIN:
+        if (next_wnd == (HWND)wp) next_wnd = (HWND)lp;
+        else if (next_wnd) SendMessageA( next_wnd, msg, wp, lp );
+        break;
+    case WM_USER:
+        ret = wm_drawclipboard;
+        wm_drawclipboard = 0;
+        return ret;
+    }
+
+    return DefWindowProcA(hwnd, msg, wp, lp);
+}
+
+static DWORD CALLBACK set_clipboard_thread(void *arg)
+{
+    OpenClipboard( GetDesktopWindow() );
+    EmptyClipboard();
+    SetClipboardData( CF_WAVE, 0 );
+    CloseClipboard();
+    return 0;
+}
+
+/* test that WM_DRAWCLIPBOARD can be delivered for a previous change during OleSetClipboard */
+static void test_set_clipboard_DRAWCLIPBOARD(void)
+{
+    LPDATAOBJECT data;
+    HRESULT hr;
+    WNDCLASSA cls;
+    HWND viewer;
+    int ret;
+    HANDLE thread;
+
+    hr = DataObjectImpl_CreateText("data", &data);
+    ok(hr == S_OK, "Failed to create data object: 0x%08x\n", hr);
+
+    memset(&cls, 0, sizeof(cls));
+    cls.lpfnWndProc = clipboard_wnd_proc;
+    cls.hInstance = GetModuleHandleA(NULL);
+    cls.lpszClassName = "clipboard_test";
+    RegisterClassA(&cls);
+
+    viewer = CreateWindowA("clipboard_test", NULL, 0, 0, 0, 0, 0, NULL, 0, NULL, 0);
+    ok(viewer != NULL, "CreateWindow failed: %d\n", GetLastError());
+    next_wnd = SetClipboardViewer( viewer );
+
+    ret = SendMessageA( viewer, WM_USER, 0, 0 );
+    ok( ret == 1, "%u WM_DRAWCLIPBOARD received\n", ret );
+
+    hr = OleInitialize(NULL);
+    ok(hr == S_OK, "OleInitialize failed with error 0x%08x\n", hr);
+
+    ret = SendMessageA( viewer, WM_USER, 0, 0 );
+    ok( !ret, "%u WM_DRAWCLIPBOARD received\n", ret );
+
+    thread = CreateThread(NULL, 0, set_clipboard_thread, NULL, 0, NULL);
+    ok(thread != NULL, "CreateThread failed (%d)\n", GetLastError());
+    ret = WaitForSingleObject(thread, 5000);
+    ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", ret);
+
+    clip_data = data;
+    hr = OleSetClipboard(data);
+    ok(hr == S_OK, "failed to set clipboard to data, hr = 0x%08x\n", hr);
+
+    ret = SendMessageA( viewer, WM_USER, 0, 0 );
+    ok( ret == 2, "%u WM_DRAWCLIPBOARD received\n", ret );
+
+    clip_data = NULL;
+    hr = OleFlushClipboard();
+    ok(hr == S_OK, "failed to flush clipboard, hr = 0x%08x\n", hr);
+    ret = IDataObject_Release(data);
+    ok(ret == 0, "got %d\n", ret);
+
+    OleUninitialize();
+    ChangeClipboardChain( viewer, next_wnd );
+    DestroyWindow( viewer );
+}
+
 static inline ULONG count_refs(IDataObject *d)
 {
     IDataObject_AddRef(d);
@@ -976,9 +1088,7 @@ static void test_consumer_refs(void)
     hr = OleGetClipboard(&get2);
     ok(hr == S_OK, "got %08x\n", hr);
 
-    ok(get1 == get2 ||
-       broken(get1 != get2), /* win9x, winme & nt4 */
-       "data objects differ\n");
+    ok(get1 == get2, "data objects differ\n");
     refs = IDataObject_Release(get2);
     ok(refs == (get1 == get2 ? 1 : 0), "got %d\n", refs);
 
@@ -1083,9 +1193,21 @@ static void test_consumer_refs(void)
     IDataObject_Release(get1);
 
     IDataObject_Release(src2);
-    IDataObject_Release(src);
+
+    /* Show that OleUninitialize() doesn't release the
+       dataobject's ref, and thus the object is leaked. */
+    old_refs = count_refs(src);
+    ok(old_refs == 1, "%d\n", old_refs);
+
+    OleSetClipboard(src);
+    refs = count_refs(src);
+    ok(refs > old_refs, "%d %d\n", refs, old_refs);
 
     OleUninitialize();
+    refs = count_refs(src);
+    ok(refs == 2, "%d\n", refs);
+
+    IDataObject_Release(src);
 }
 
 static void test_flushed_getdata(void)
@@ -1334,17 +1456,14 @@ static void test_nonole_clipboard(void)
     hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
     ok(hr == S_OK, "got %08x\n", hr); /* User32 adds some synthesised formats */
 
-    todo_wine ok(fmt.cfFormat == CF_LOCALE, "cf %04x\n", fmt.cfFormat);
-    if(fmt.cfFormat == CF_LOCALE)
-    {
-        ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
-        ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
-        ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
-        ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
+    ok(fmt.cfFormat == CF_LOCALE, "cf %04x\n", fmt.cfFormat);
+    ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
+    ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
+    ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
+    todo_wine ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
 
-        hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
-        ok(hr == S_OK, "got %08x\n", hr);
-    }
+    hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
+    ok(hr == S_OK, "got %08x\n", hr);
 
     ok(fmt.cfFormat == CF_OEMTEXT, "cf %04x\n", fmt.cfFormat);
     ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
@@ -1354,19 +1473,14 @@ static void test_nonole_clipboard(void)
 
     hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
     ok(hr == S_OK, "got %08x\n", hr);
-    ok(fmt.cfFormat == CF_UNICODETEXT ||
-       broken(fmt.cfFormat == CF_METAFILEPICT), /* win9x and winme don't have CF_UNICODETEXT */
-       "cf %04x\n", fmt.cfFormat);
-    if(fmt.cfFormat == CF_UNICODETEXT)
-    {
-        ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
-        ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
-        ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
-        ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
+    ok(fmt.cfFormat == CF_UNICODETEXT, "cf %04x\n", fmt.cfFormat);
+    ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
+    ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
+    ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
+    ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
 
-        hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
-        ok(hr == S_OK, "got %08x\n", hr);
-    }
+    hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
+    ok(hr == S_OK, "got %08x\n", hr);
     ok(fmt.cfFormat == CF_METAFILEPICT, "cf %04x\n", fmt.cfFormat);
     ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
     ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
@@ -1545,11 +1659,66 @@ 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_uninitialized();
     test_set_clipboard();
+    test_set_clipboard_DRAWCLIPBOARD();
     test_consumer_refs();
     test_flushed_getdata();
     test_nonole_clipboard();
     test_getdatahere();
+    test_multithreaded_clipboard();
+    test_get_clipboard_locked();
 }