ole32: Make clipboard latest_snapshot access thread safe.
Signed-off-by: Piotr Caban <piotr@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
81bd72640b
commit
d90ec79be2
|
@ -174,6 +174,15 @@ typedef struct PresentationDataHeader
|
|||
*/
|
||||
static ole_clipbrd* theOleClipboard;
|
||||
|
||||
static CRITICAL_SECTION latest_snapshot_cs;
|
||||
static CRITICAL_SECTION_DEBUG latest_snapshot_cs_debug =
|
||||
{
|
||||
0, 0, &latest_snapshot_cs,
|
||||
{ &latest_snapshot_cs_debug.ProcessLocksList, &latest_snapshot_cs_debug.ProcessLocksList },
|
||||
0, 0, { (DWORD_PTR)(__FILE__ ": clipboard last snapshot") }
|
||||
};
|
||||
static CRITICAL_SECTION latest_snapshot_cs = { &latest_snapshot_cs_debug, -1, 0, 0, 0, 0 };
|
||||
|
||||
static inline HRESULT get_ole_clipbrd(ole_clipbrd **clipbrd)
|
||||
{
|
||||
struct oletls *info = COM_CurrentInfo();
|
||||
|
@ -1042,13 +1051,17 @@ static ULONG WINAPI snapshot_Release(IDataObject *iface)
|
|||
|
||||
if (ref == 0)
|
||||
{
|
||||
ole_clipbrd *clipbrd;
|
||||
HRESULT hr = get_ole_clipbrd(&clipbrd);
|
||||
EnterCriticalSection(&latest_snapshot_cs);
|
||||
if (This->ref)
|
||||
{
|
||||
LeaveCriticalSection(&latest_snapshot_cs);
|
||||
return ref;
|
||||
}
|
||||
if (theOleClipboard->latest_snapshot == This)
|
||||
theOleClipboard->latest_snapshot = NULL;
|
||||
LeaveCriticalSection(&latest_snapshot_cs);
|
||||
|
||||
if(This->data) IDataObject_Release(This->data);
|
||||
|
||||
if(SUCCEEDED(hr) && clipbrd->latest_snapshot == This)
|
||||
clipbrd->latest_snapshot = NULL;
|
||||
HeapFree(GetProcessHeap(), 0, This);
|
||||
}
|
||||
|
||||
|
@ -2192,17 +2205,23 @@ HRESULT WINAPI OleGetClipboard(IDataObject **obj)
|
|||
if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
|
||||
|
||||
seq_no = GetClipboardSequenceNumber();
|
||||
EnterCriticalSection(&latest_snapshot_cs);
|
||||
if(clipbrd->latest_snapshot && clipbrd->latest_snapshot->seq_no != seq_no)
|
||||
clipbrd->latest_snapshot = NULL;
|
||||
|
||||
if(!clipbrd->latest_snapshot)
|
||||
{
|
||||
clipbrd->latest_snapshot = snapshot_construct(seq_no);
|
||||
if(!clipbrd->latest_snapshot) return E_OUTOFMEMORY;
|
||||
if(!clipbrd->latest_snapshot)
|
||||
{
|
||||
LeaveCriticalSection(&latest_snapshot_cs);
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
*obj = &clipbrd->latest_snapshot->IDataObject_iface;
|
||||
IDataObject_AddRef(*obj);
|
||||
LeaveCriticalSection(&latest_snapshot_cs);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
|
|
@ -1539,6 +1539,38 @@ 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();
|
||||
}
|
||||
|
||||
START_TEST(clipboard)
|
||||
{
|
||||
test_set_clipboard();
|
||||
|
@ -1546,4 +1578,5 @@ START_TEST(clipboard)
|
|||
test_flushed_getdata();
|
||||
test_nonole_clipboard();
|
||||
test_getdatahere();
|
||||
test_multithreaded_clipboard();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue