Handle exceptions in user drop targets code in wxMSW

All exceptions thrown by wxDropTarget::OnXXX() must be caught and handled in
the same way as we already do it for the exceptions in the event handlers as
we can't let the exceptions escape into system/kernel code: while it can work
in some cases, it doesn't work in general, e.g. exceptions simply disappear
when they happen in 32 bit programs under 64 bit Windows 7.
This commit is contained in:
Vadim Zeitlin
2016-11-15 01:00:05 +01:00
parent 239469457d
commit 32ebf86ea1

View File

@@ -27,6 +27,7 @@
#ifndef WX_PRECOMP #ifndef WX_PRECOMP
#include "wx/msw/wrapwin.h" #include "wx/msw/wrapwin.h"
#include "wx/except.h"
#include "wx/log.h" #include "wx/log.h"
#endif #endif
@@ -181,68 +182,72 @@ STDMETHODIMP wxIDropTarget::DragEnter(IDataObject *pIDataSource,
POINTL pt, POINTL pt,
DWORD *pdwEffect) DWORD *pdwEffect)
{ {
wxLogTrace(wxTRACE_OleCalls, wxT("IDropTarget::DragEnter")); wxTRY
{
wxLogTrace(wxTRACE_OleCalls, wxT("IDropTarget::DragEnter"));
wxASSERT_MSG( m_pIDataObject == NULL, wxASSERT_MSG( m_pIDataObject == NULL,
wxT("drop target must have data object") ); wxT("drop target must have data object") );
// show the list of formats supported by the source data object for the // show the list of formats supported by the source data object for the
// debugging purposes, this is quite useful sometimes - please don't remove // debugging purposes, this is quite useful sometimes - please don't remove
#if 0 #if 0
IEnumFORMATETC *penumFmt; IEnumFORMATETC *penumFmt;
if ( SUCCEEDED(pIDataSource->EnumFormatEtc(DATADIR_GET, &penumFmt)) ) if ( SUCCEEDED(pIDataSource->EnumFormatEtc(DATADIR_GET, &penumFmt)) )
{
FORMATETC fmt;
while ( penumFmt->Next(1, &fmt, NULL) == S_OK )
{ {
wxLogDebug(wxT("Drop source supports format %s"), FORMATETC fmt;
wxDataObject::GetFormatName(fmt.cfFormat)); while ( penumFmt->Next(1, &fmt, NULL) == S_OK )
} {
wxLogDebug(wxT("Drop source supports format %s"),
wxDataObject::GetFormatName(fmt.cfFormat));
}
penumFmt->Release(); penumFmt->Release();
} }
else else
{ {
wxLogLastError(wxT("IDataObject::EnumFormatEtc")); wxLogLastError(wxT("IDataObject::EnumFormatEtc"));
} }
#endif // 0 #endif // 0
if ( !m_pTarget->MSWIsAcceptedData(pIDataSource) ) { if ( !m_pTarget->MSWIsAcceptedData(pIDataSource) ) {
// we don't accept this kind of data // we don't accept this kind of data
*pdwEffect = DROPEFFECT_NONE; *pdwEffect = DROPEFFECT_NONE;
// Don't do anything else if we don't support this format at all, notably // Don't do anything else if we don't support this format at all, notably
// don't call our OnEnter() below which would show misleading cursor to // don't call our OnEnter() below which would show misleading cursor to
// the user. // the user.
return S_OK; return S_OK;
}
// for use in OnEnter and OnDrag calls
m_pTarget->MSWSetDataSource(pIDataSource);
// get hold of the data object
m_pIDataObject = pIDataSource;
m_pIDataObject->AddRef();
// we need client coordinates to pass to wxWin functions
if ( !ScreenToClient(m_hwnd, (POINT *)&pt) )
{
wxLogLastError(wxT("ScreenToClient"));
}
// give some visual feedback
*pdwEffect = ConvertDragResultToEffect(
m_pTarget->OnEnter(pt.x, pt.y, ConvertDragEffectToResult(
GetDropEffect(grfKeyState, m_pTarget->GetDefaultAction(), *pdwEffect))
)
);
// update drag image
const wxDragResult res = ConvertDragEffectToResult(*pdwEffect);
m_pTarget->MSWUpdateDragImageOnEnter(pt.x, pt.y, res);
m_pTarget->MSWUpdateDragImageOnDragOver(pt.x, pt.y, res);
return S_OK;
} }
wxCATCH_ALL( wxEvtHandler::WXConsumeException(); return E_UNEXPECTED; )
// for use in OnEnter and OnDrag calls
m_pTarget->MSWSetDataSource(pIDataSource);
// get hold of the data object
m_pIDataObject = pIDataSource;
m_pIDataObject->AddRef();
// we need client coordinates to pass to wxWin functions
if ( !ScreenToClient(m_hwnd, (POINT *)&pt) )
{
wxLogLastError(wxT("ScreenToClient"));
}
// give some visual feedback
*pdwEffect = ConvertDragResultToEffect(
m_pTarget->OnEnter(pt.x, pt.y, ConvertDragEffectToResult(
GetDropEffect(grfKeyState, m_pTarget->GetDefaultAction(), *pdwEffect))
)
);
// update drag image
const wxDragResult res = ConvertDragEffectToResult(*pdwEffect);
m_pTarget->MSWUpdateDragImageOnEnter(pt.x, pt.y, res);
m_pTarget->MSWUpdateDragImageOnDragOver(pt.x, pt.y, res);
return S_OK;
} }
@@ -260,38 +265,42 @@ STDMETHODIMP wxIDropTarget::DragOver(DWORD grfKeyState,
POINTL pt, POINTL pt,
LPDWORD pdwEffect) LPDWORD pdwEffect)
{ {
// there are too many of them... wxLogDebug("IDropTarget::DragOver"); wxTRY
{
// there are too many of them... wxLogDebug("IDropTarget::DragOver");
wxDragResult result; wxDragResult result;
if ( m_pIDataObject ) { if ( m_pIDataObject ) {
result = ConvertDragEffectToResult( result = ConvertDragEffectToResult(
GetDropEffect(grfKeyState, m_pTarget->GetDefaultAction(), *pdwEffect)); GetDropEffect(grfKeyState, m_pTarget->GetDefaultAction(), *pdwEffect));
} }
else { else {
// can't accept data anyhow normally // can't accept data anyhow normally
result = wxDragNone; result = wxDragNone;
}
if ( result != wxDragNone ) {
// we need client coordinates to pass to wxWin functions
if ( !ScreenToClient(m_hwnd, (POINT *)&pt) )
{
wxLogLastError(wxT("ScreenToClient"));
} }
*pdwEffect = ConvertDragResultToEffect( if ( result != wxDragNone ) {
m_pTarget->OnDragOver(pt.x, pt.y, result) // we need client coordinates to pass to wxWin functions
); if ( !ScreenToClient(m_hwnd, (POINT *)&pt) )
} {
else { wxLogLastError(wxT("ScreenToClient"));
*pdwEffect = DROPEFFECT_NONE; }
}
// update drag image *pdwEffect = ConvertDragResultToEffect(
m_pTarget->MSWUpdateDragImageOnDragOver(pt.x, pt.y, m_pTarget->OnDragOver(pt.x, pt.y, result)
ConvertDragEffectToResult(*pdwEffect)); );
}
else {
*pdwEffect = DROPEFFECT_NONE;
}
return S_OK; // update drag image
m_pTarget->MSWUpdateDragImageOnDragOver(pt.x, pt.y,
ConvertDragEffectToResult(*pdwEffect));
return S_OK;
}
wxCATCH_ALL( wxEvtHandler::WXConsumeException(); return E_UNEXPECTED; )
} }
// Name : wxIDropTarget::DragLeave // Name : wxIDropTarget::DragLeave
@@ -300,18 +309,22 @@ STDMETHODIMP wxIDropTarget::DragOver(DWORD grfKeyState,
// Notes : good place to do any clean-up // Notes : good place to do any clean-up
STDMETHODIMP wxIDropTarget::DragLeave() STDMETHODIMP wxIDropTarget::DragLeave()
{ {
wxLogTrace(wxTRACE_OleCalls, wxT("IDropTarget::DragLeave")); wxTRY
{
wxLogTrace(wxTRACE_OleCalls, wxT("IDropTarget::DragLeave"));
// remove the UI feedback // remove the UI feedback
m_pTarget->OnLeave(); m_pTarget->OnLeave();
// release the held object // release the held object
RELEASE_AND_NULL(m_pIDataObject); RELEASE_AND_NULL(m_pIDataObject);
// update drag image // update drag image
m_pTarget->MSWUpdateDragImageOnLeave(); m_pTarget->MSWUpdateDragImageOnLeave();
return S_OK; return S_OK;
}
wxCATCH_ALL( wxEvtHandler::WXConsumeException(); return E_UNEXPECTED; )
} }
// Name : wxIDropTarget::Drop // Name : wxIDropTarget::Drop
@@ -328,48 +341,52 @@ STDMETHODIMP wxIDropTarget::Drop(IDataObject *pIDataSource,
POINTL pt, POINTL pt,
DWORD *pdwEffect) DWORD *pdwEffect)
{ {
wxLogTrace(wxTRACE_OleCalls, wxT("IDropTarget::Drop")); wxTRY
// TODO I don't know why there is this parameter, but so far I assume
// that it's the same we've already got in DragEnter
wxASSERT( m_pIDataObject == pIDataSource );
// we need client coordinates to pass to wxWin functions
if ( !ScreenToClient(m_hwnd, (POINT *)&pt) )
{ {
wxLogLastError(wxT("ScreenToClient")); wxLogTrace(wxTRACE_OleCalls, wxT("IDropTarget::Drop"));
}
// first ask the drop target if it wants data // TODO I don't know why there is this parameter, but so far I assume
if ( m_pTarget->OnDrop(pt.x, pt.y) ) { // that it's the same we've already got in DragEnter
// it does, so give it the data source wxASSERT( m_pIDataObject == pIDataSource );
m_pTarget->MSWSetDataSource(pIDataSource);
// and now it has the data // we need client coordinates to pass to wxWin functions
wxDragResult rc = ConvertDragEffectToResult( if ( !ScreenToClient(m_hwnd, (POINT *)&pt) )
GetDropEffect(grfKeyState, m_pTarget->GetDefaultAction(), *pdwEffect)); {
rc = m_pTarget->OnData(pt.x, pt.y, rc); wxLogLastError(wxT("ScreenToClient"));
if ( wxIsDragResultOk(rc) ) { }
// operation succeeded
*pdwEffect = ConvertDragResultToEffect(rc); // first ask the drop target if it wants data
if ( m_pTarget->OnDrop(pt.x, pt.y) ) {
// it does, so give it the data source
m_pTarget->MSWSetDataSource(pIDataSource);
// and now it has the data
wxDragResult rc = ConvertDragEffectToResult(
GetDropEffect(grfKeyState, m_pTarget->GetDefaultAction(), *pdwEffect));
rc = m_pTarget->OnData(pt.x, pt.y, rc);
if ( wxIsDragResultOk(rc) ) {
// operation succeeded
*pdwEffect = ConvertDragResultToEffect(rc);
}
else {
*pdwEffect = DROPEFFECT_NONE;
}
} }
else { else {
// OnDrop() returned false, no need to copy data
*pdwEffect = DROPEFFECT_NONE; *pdwEffect = DROPEFFECT_NONE;
} }
// release the held object
RELEASE_AND_NULL(m_pIDataObject);
// update drag image
m_pTarget->MSWUpdateDragImageOnData(pt.x, pt.y,
ConvertDragEffectToResult(*pdwEffect));
return S_OK;
} }
else { wxCATCH_ALL( wxEvtHandler::WXConsumeException(); return E_UNEXPECTED; )
// OnDrop() returned false, no need to copy data
*pdwEffect = DROPEFFECT_NONE;
}
// release the held object
RELEASE_AND_NULL(m_pIDataObject);
// update drag image
m_pTarget->MSWUpdateDragImageOnData(pt.x, pt.y,
ConvertDragEffectToResult(*pdwEffect));
return S_OK;
} }
// ============================================================================ // ============================================================================