Adam Martinson : ole32: Don't call IDropTarget::QueryInterface() in RegisterDragDrop().
Alexandre Julliard
julliard at winehq.org
Wed Jun 8 11:27:03 CDT 2011
Module: wine
Branch: master
Commit: e85668b4630266845c44c23450f8006505ee73fa
URL: http://source.winehq.org/git/wine.git/?a=commit;h=e85668b4630266845c44c23450f8006505ee73fa
Author: Adam Martinson <amartinson at codeweavers.com>
Date: Mon Jun 6 11:57:27 2011 -0500
ole32: Don't call IDropTarget::QueryInterface() in RegisterDragDrop().
---
dlls/ole32/ole2.c | 128 ++++++++++++++++++++++++++++++++++++++++---
dlls/ole32/tests/dragdrop.c | 2 +-
2 files changed, 120 insertions(+), 10 deletions(-)
diff --git a/dlls/ole32/ole2.c b/dlls/ole32/ole2.c
index 3254619..b449a76 100644
--- a/dlls/ole32/ole2.c
+++ b/dlls/ole32/ole2.c
@@ -6,6 +6,7 @@
* Copyright 1999 Noel Borthwick
* Copyright 1999, 2000 Marcus Meissner
* Copyright 2005 Juan Lang
+ * Copyright 2011 Adam Martinson for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -377,6 +378,116 @@ static HRESULT create_stream_from_map(HANDLE map, IStream **stream)
return hr;
}
+/* This is to work around apps which break COM rules by not implementing
+ * IDropTarget::QueryInterface(). Windows doesn't expose this because it
+ * doesn't call CoMarshallInterface() in RegisterDragDrop().
+ * The wrapper is only used internally, and only exists for the life of
+ * the marshal. */
+typedef struct {
+ IDropTarget IDropTarget_iface;
+ IDropTarget* inner;
+ LONG refs;
+} DropTargetWrapper;
+
+static inline DropTargetWrapper* impl_from_IDropTarget(IDropTarget* iface)
+{
+ return CONTAINING_RECORD(iface, DropTargetWrapper, IDropTarget_iface);
+}
+
+static HRESULT WINAPI DropTargetWrapper_QueryInterface(IDropTarget* iface,
+ REFIID riid,
+ void** ppvObject)
+{
+ DropTargetWrapper* This = impl_from_IDropTarget(iface);
+ if (IsEqualIID(riid, &IID_IUnknown) ||
+ IsEqualIID(riid, &IID_IDropTarget))
+ {
+ IDropTarget_AddRef(&This->IDropTarget_iface);
+ *ppvObject = &This->IDropTarget_iface;
+ return S_OK;
+ }
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI DropTargetWrapper_AddRef(IDropTarget* iface)
+{
+ DropTargetWrapper* This = impl_from_IDropTarget(iface);
+ return InterlockedIncrement(&This->refs);
+}
+
+static ULONG WINAPI DropTargetWrapper_Release(IDropTarget* iface)
+{
+ DropTargetWrapper* This = impl_from_IDropTarget(iface);
+ ULONG refs = InterlockedDecrement(&This->refs);
+ if (!refs)
+ {
+ IDropTarget_Release(This->inner);
+ HeapFree(GetProcessHeap(), 0, This);
+ }
+ return refs;
+}
+
+static HRESULT WINAPI DropTargetWrapper_DragEnter(IDropTarget* iface,
+ IDataObject* pDataObj,
+ DWORD grfKeyState,
+ POINTL pt,
+ DWORD* pdwEffect)
+{
+ DropTargetWrapper* This = impl_from_IDropTarget(iface);
+ return IDropTarget_DragEnter(This->inner, pDataObj, grfKeyState, pt, pdwEffect);
+}
+
+static HRESULT WINAPI DropTargetWrapper_DragOver(IDropTarget* iface,
+ DWORD grfKeyState,
+ POINTL pt,
+ DWORD* pdwEffect)
+{
+ DropTargetWrapper* This = impl_from_IDropTarget(iface);
+ return IDropTarget_DragOver(This->inner, grfKeyState, pt, pdwEffect);
+}
+
+static HRESULT WINAPI DropTargetWrapper_DragLeave(IDropTarget* iface)
+{
+ DropTargetWrapper* This = impl_from_IDropTarget(iface);
+ return IDropTarget_DragLeave(This->inner);
+}
+
+static HRESULT WINAPI DropTargetWrapper_Drop(IDropTarget* iface,
+ IDataObject* pDataObj,
+ DWORD grfKeyState,
+ POINTL pt,
+ DWORD* pdwEffect)
+{
+ DropTargetWrapper* This = impl_from_IDropTarget(iface);
+ return IDropTarget_Drop(This->inner, pDataObj, grfKeyState, pt, pdwEffect);
+}
+
+static const IDropTargetVtbl DropTargetWrapperVTbl =
+{
+ DropTargetWrapper_QueryInterface,
+ DropTargetWrapper_AddRef,
+ DropTargetWrapper_Release,
+ DropTargetWrapper_DragEnter,
+ DropTargetWrapper_DragOver,
+ DropTargetWrapper_DragLeave,
+ DropTargetWrapper_Drop
+};
+
+static IDropTarget* WrapDropTarget(IDropTarget* inner)
+{
+ DropTargetWrapper* This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
+
+ if (This)
+ {
+ IDropTarget_AddRef(inner);
+ This->IDropTarget_iface.lpVtbl = &DropTargetWrapperVTbl;
+ This->inner = inner;
+ This->refs = 1;
+ }
+ return &This->IDropTarget_iface;
+}
+
/***********************************************************************
* get_droptarget_pointer
*
@@ -409,7 +520,7 @@ HRESULT WINAPI RegisterDragDrop(HWND hwnd, LPDROPTARGET pDropTarget)
HRESULT hr;
IStream *stream;
HANDLE map;
- IUnknown *unk;
+ IDropTarget *wrapper;
TRACE("(%p,%p)\n", hwnd, pDropTarget);
@@ -450,16 +561,15 @@ HRESULT WINAPI RegisterDragDrop(HWND hwnd, LPDROPTARGET pDropTarget)
hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
if(FAILED(hr)) return hr;
- unk = NULL;
- hr = IDropTarget_QueryInterface(pDropTarget, &IID_IUnknown, (void**)&unk);
- if (SUCCEEDED(hr) && !unk) hr = E_NOINTERFACE;
- if(FAILED(hr))
+ /* IDropTarget::QueryInterface() shouldn't be called, some (broken) apps depend on this. */
+ wrapper = WrapDropTarget(pDropTarget);
+ if(!wrapper)
{
- IStream_Release(stream);
- return hr;
+ IStream_Release(stream);
+ return E_OUTOFMEMORY;
}
- hr = CoMarshalInterface(stream, &IID_IDropTarget, unk, MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
- IUnknown_Release(unk);
+ hr = CoMarshalInterface(stream, &IID_IDropTarget, (IUnknown*)wrapper, MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
+ IDropTarget_Release(wrapper);
if(SUCCEEDED(hr))
{
diff --git a/dlls/ole32/tests/dragdrop.c b/dlls/ole32/tests/dragdrop.c
index 0c56cb4..b0e1259 100644
--- a/dlls/ole32/tests/dragdrop.c
+++ b/dlls/ole32/tests/dragdrop.c
@@ -39,7 +39,7 @@ static int droptarget_refs;
static HRESULT WINAPI DropTarget_QueryInterface(IDropTarget* iface, REFIID riid,
void** ppvObject)
{
- todo_wine ok(0, "DropTarget_QueryInterface() shouldn't be called\n");
+ ok(0, "DropTarget_QueryInterface() shouldn't be called\n");
if (IsEqualIID(riid, &IID_IUnknown) ||
IsEqualIID(riid, &IID_IDropTarget))
{
More information about the wine-cvs
mailing list