Browse Source

Handle exception when placing items on the clipboard, should fix a reported crash

scott brogden 8 years ago
parent
commit
adb2be924a
3 changed files with 122 additions and 73 deletions
  1. 83 53
      ProcessPaste.cpp
  2. 1 0
      ProcessPaste.h
  3. 38 20
      QPasteWnd.cpp

+ 83 - 53
ProcessPaste.cpp

@@ -24,73 +24,103 @@ CProcessPaste::~CProcessPaste()
 
 BOOL CProcessPaste::DoPaste()
 {
-	m_pOle->m_pasteOptions = m_pasteOptions;
-
-	if(m_pOle->DoImmediateRender())
+	try
 	{
-		// MarkAsPasted() must be done first since it makes use of
-		//  m_pOle->m_ClipIDs and m_pOle is inaccessible after
-		//  SetClipboard is called.
-		MarkAsPasted();
-		
-		// Ignore the clipboard change that we will cause IF:
-		// 1) we are pasting a single element, since the element is already
-		//    in the db and its lDate was updated by MarkAsPas???ted().
-		// OR
-		// 2) we are pasting multiple, but g_Opt.m_bSaveMultiPaste is false
-		if(GetClipIDs().GetSize() == 1 || !g_Opt.m_bSaveMultiPaste)
-		{
-			m_pOle->CacheGlobalData(theApp.m_cfIgnoreClipboard, NewGlobalP("Ignore", sizeof("Ignore")));
-		}
-		else
+		m_pOle->m_pasteOptions = m_pasteOptions;
+
+		if (m_pOle->DoImmediateRender())
 		{
-			m_pOle->CacheGlobalData(theApp.m_cfDelaySavingData, NewGlobalP("Delay", sizeof("Delay")));
-		}
-		
-		m_pOle->SetClipboard(); // m_pOle is now managed by the OLE clipboard
+			// MarkAsPasted() must be done first since it makes use of
+			//  m_pOle->m_ClipIDs and m_pOle is inaccessible after
+			//  SetClipboard is called.
+			MarkAsPasted();
+
+			// Ignore the clipboard change that we will cause IF:
+			// 1) we are pasting a single element, since the element is already
+			//    in the db and its lDate was updated by MarkAsPas???ted().
+			// OR
+			// 2) we are pasting multiple, but g_Opt.m_bSaveMultiPaste is false
+			if (GetClipIDs().GetSize() == 1 || !g_Opt.m_bSaveMultiPaste)
+			{
+				m_pOle->CacheGlobalData(theApp.m_cfIgnoreClipboard, NewGlobalP("Ignore", sizeof("Ignore")));
+			}
+			else
+			{
+				m_pOle->CacheGlobalData(theApp.m_cfDelaySavingData, NewGlobalP("Delay", sizeof("Delay")));
+			}
 
-		// The Clipboard now owns the allocated memory
-		// and will delete this data object
-		// when new data is put on the Clipboard
-		m_pOle = NULL; // m_pOle should not be accessed past this point
+			m_pOle->SetClipboard(); // m_pOle is now managed by the OLE clipboard
 
-		if(m_bSendPaste)
-		{
-			Log(_T("Sending Paste to active window"));
-			theApp.m_activeWnd.SendPaste(m_bActivateTarget);
-		}
-		else if(m_bActivateTarget)
-		{
-			Log(_T("Activating active window"));
-			theApp.m_activeWnd.ActivateTarget();
+			// The Clipboard now owns the allocated memory
+			// and will delete this data object
+			// when new data is put on the Clipboard
+			m_pOle = NULL; // m_pOle should not be accessed past this point
+
+			if (m_bSendPaste)
+			{
+				Log(_T("Sending Paste to active window"));
+				theApp.m_activeWnd.SendPaste(m_bActivateTarget);
+			}
+			else if (m_bActivateTarget)
+			{
+				Log(_T("Activating active window"));
+				theApp.m_activeWnd.ActivateTarget();
+			}
+
+			return TRUE;
 		}
-		
-		return TRUE;
+	}
+	catch (CException *ex)
+	{
+		TCHAR szCause[255];
+		ex->GetErrorMessage(szCause, 255);
+		m_lastErrorMessage.Format(_T("Paste exception: %s"), szCause);
+		Log(m_lastErrorMessage);
+	}
+	catch (...) 
+	{
+		m_lastErrorMessage = _T("Paste generic exception");
+		Log(m_lastErrorMessage);
 	}
 	return FALSE;
 }
 
 BOOL CProcessPaste::DoDrag()
 {
-	m_pOle->m_pasteOptions = m_pasteOptions;
-	m_pOle->DoDelayRender();
-	DROPEFFECT de = m_pOle->DoDragDrop(DROPEFFECT_COPY);
-	if(de != DROPEFFECT_NONE)
+	try
 	{
-		MarkAsPasted();
-		return TRUE;
-	}
+		m_pOle->m_pasteOptions = m_pasteOptions;
+		m_pOle->DoDelayRender();
+		DROPEFFECT de = m_pOle->DoDragDrop(DROPEFFECT_COPY);
+		if (de != DROPEFFECT_NONE)
+		{
+			MarkAsPasted();
+			return TRUE;
+		}
 
-	//from https://www.codeproject.com/Articles/886711/Drag-Drop-Images-and-Drop-Descriptions-for-MFC-App
-	//You may have noted the InternalRelease() function call.This is required here to delete the object.While it is possible to use 
-	//delete or create the object on the stack with Drag & Drop operations, it is not recommended to do so.
+		//from https://www.codeproject.com/Articles/886711/Drag-Drop-Images-and-Drop-Descriptions-for-MFC-App
+		//You may have noted the InternalRelease() function call.This is required here to delete the object.While it is possible to use 
+		//delete or create the object on the stack with Drag & Drop operations, it is not recommended to do so.
 
-	m_pOle->InternalRelease();
-	
-	// The Clipboard now owns the allocated memory
-	// and will delete this data object
-	// when new data is put on the Clipboard
-	m_pOle = NULL; // m_pOle should not be accessed past this point
+		m_pOle->InternalRelease();
+
+		// The Clipboard now owns the allocated memory
+		// and will delete this data object
+		// when new data is put on the Clipboard
+		m_pOle = NULL; // m_pOle should not be accessed past this point
+	}
+	catch (CException *ex)
+	{
+		TCHAR szCause[255];
+		ex->GetErrorMessage(szCause, 255);
+		m_lastErrorMessage.Format(_T("Drag drop exception: %s"), szCause);
+		Log(m_lastErrorMessage);
+	}
+	catch (...)
+	{
+		m_lastErrorMessage = _T("Drag drop generic exception");
+		Log(m_lastErrorMessage);
+	}
 
 	return FALSE;
 }

+ 1 - 0
ProcessPaste.h

@@ -26,6 +26,7 @@ public:
 	bool m_bActivateTarget;
 	CSpecialPasteOptions m_pasteOptions;
 	bool m_pastedFromGroup;
+	CString m_lastErrorMessage;
 
 	struct MarkAsPastedData 
 	{

+ 38 - 20
QPasteWnd.cpp

@@ -844,18 +844,27 @@ BOOL CQPasteWnd::OpenID(int id, CSpecialPasteOptions pasteOptions)
 
     paste.GetClipIDs().Add(id);
     
-    paste.DoPaste();
-    theApp.OnPasteCompleted();
+	if (paste.DoPaste())
+	{
+		theApp.OnPasteCompleted();
 
-    if(g_Opt.m_bSendPasteMessageAfterSelection == FALSE)
-    {
-        theApp.m_activeWnd.ActivateTarget();
-    }
+		if (g_Opt.m_bSendPasteMessageAfterSelection == FALSE)
+		{
+			theApp.m_activeWnd.ActivateTarget();
+		}
 
-    if(g_Opt.m_bShowPersistent && g_Opt.GetAutoHide())
-    {
-        MinMaxWindow(FORCE_MIN);
-    }
+		if (g_Opt.m_bShowPersistent && g_Opt.GetAutoHide())
+		{
+			MinMaxWindow(FORCE_MIN);
+		}
+	}
+	else
+	{
+		CString errorMessage;
+		errorMessage.Format(_T("Paste Error - %s"), paste.m_lastErrorMessage);
+		m_popupMsg.Show(errorMessage, CPoint(0, 0), true);
+		SetTimer(TIMER_ERROR_MSG, CGetSetOptions::GetErrorMsgPopupTimeout(), NULL);
+	}
 
 	Log(StrF(_T("End OpenId, Id: %d, Only CF_TEXT: %s"), id, pasteOptions.ToString()));
 
@@ -887,18 +896,27 @@ BOOL CQPasteWnd::OpenSelection(CSpecialPasteOptions pasteOptions)
 	paste.m_pastedFromGroup = (theApp.m_GroupID > 0);
 
     paste.GetClipIDs().Copy(IDs);
-    paste.DoPaste();
-    theApp.OnPasteCompleted();
+	if (paste.DoPaste())
+	{
+		theApp.OnPasteCompleted();
 
-    if(g_Opt.m_bSendPasteMessageAfterSelection == FALSE)
-    {
-        theApp.m_activeWnd.ActivateTarget();
-    }
+		if (g_Opt.m_bSendPasteMessageAfterSelection == FALSE)
+		{
+			theApp.m_activeWnd.ActivateTarget();
+		}
 
-    if(g_Opt.m_bShowPersistent && g_Opt.GetAutoHide())
-    {
-        MinMaxWindow(FORCE_MIN);
-    }
+		if (g_Opt.m_bShowPersistent && g_Opt.GetAutoHide())
+		{
+			MinMaxWindow(FORCE_MIN);
+		}
+	}
+	else
+	{
+		CString errorMessage;
+		errorMessage.Format(_T("Paste Error - %s"), paste.m_lastErrorMessage);
+		m_popupMsg.Show(errorMessage, CPoint(0, 0), true);
+		SetTimer(TIMER_ERROR_MSG, CGetSetOptions::GetErrorMsgPopupTimeout(), NULL);
+	}
 
     Log(_T("End Open Selection"));
     return TRUE;