Advertisement
Catachan

StackOverflow ActiveX Exception Handling Rough Draft

Jul 21st, 2016
80
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.19 KB | None | 0 0
  1. **Question**
  2.  
  3. Why is `pWnd = (CWnd*)pMap->LookupPermanent(m_hWnd);` occasionally returning NULL in the CWnd::DestroyWindow() function causing an ASSERT statement to fail while trying to destroy a modal dialog?
  4.  
  5. **Initial Information**
  6.  
  7. I have an ActiveX control that implements an on screen keyboard.
  8. This keyboard accepts both touch/click events and keystroke events from an attached hardware keyboard.
  9. Input to the control is validated using an algorithm defined by the module that created the keyboard.
  10.  
  11. Touching the buttons on screen generates input that follows
  12.  
  13. OnButtonUP()->AddCharacter()->ValidateText()
  14.  
  15. Typing on the physical keyboard generates input that follows
  16.  
  17. PreTranslateMessage()->AddCharacter()->ValidateText()
  18.  
  19. The ValidateText() function fires an event that is handled by the module that created the keyboard.
  20.  
  21. I have added a try-catch block around the event firing to handle any errors that occur while the event is being processed.
  22.  
  23. **Confusing Behavior**
  24.  
  25. What I have found is that if an error is caused by using the USB Keyboard, when the user attempts to close the Keyboard a debug assert statement in CWnd::DestroyWindow() fails.
  26. If the same error is caused by using the touch screen interface, the assert statement succeeds.
  27.  
  28.  
  29. **Source Code Snippets**
  30.  
  31. The code for firing the event is as follows:
  32.  
  33. try
  34. {
  35. m_control->OnValidate(&text, &isValid);
  36. }
  37. catch (...)
  38. {
  39. LOG_CRITICAL_ERROR(/*Format(*/L"Keyboard::ValidateText: Error occured while validating"/*, badText.c_str()).c_str()*/);
  40. }
  41.  
  42. Where the OnValidate() function is defined as:
  43.  
  44. void OnValidate(BSTR* text, LONG* isValid)
  45. {
  46. FireEvent(eventidOnValidate, EVENT_PARAM(VTS_PBSTR VTS_PI4), text, isValid);
  47. }
  48.  
  49. The CWnd::DestroyWindow() function is (With some bits preprocessor bits removed) :
  50.  
  51. BOOL CWnd::DestroyWindow()
  52. {
  53. CWnd* pWnd;
  54. CHandleMap* pMap;
  55. HWND hWndOrig;
  56. BOOL bResult;
  57.  
  58. if ((m_hWnd == NULL) && (m_pCtrlSite == NULL))
  59. return FALSE;
  60.  
  61. bResult = FALSE;
  62. pMap = NULL;
  63. pWnd = NULL;
  64. hWndOrig = NULL;
  65. if (m_hWnd != NULL)
  66. {
  67. pMap = afxMapHWND();
  68. ENSURE(pMap != NULL);
  69. pWnd = (CWnd*)pMap->LookupPermanent(m_hWnd); //<- This returns NULL before the Assert fails
  70. hWndOrig = m_hWnd;
  71. }
  72.  
  73. if ((m_hWnd != NULL) || (m_pCtrlSite != NULL))
  74. {
  75. if (m_pCtrlSite == NULL)
  76. bResult = ::DestroyWindow(m_hWnd);
  77. else
  78. bResult = m_pCtrlSite->DestroyControl();
  79. }
  80.  
  81. if (hWndOrig != NULL)
  82. {
  83. // Note that 'this' may have been deleted at this point,
  84. // (but only if pWnd != NULL)
  85. if (pWnd != NULL)
  86. {
  87. // Should have been detached by OnNcDestroy
  88. ASSERT(pMap->LookupPermanent(hWndOrig) == NULL);
  89. }
  90. else
  91. {
  92. ASSERT(m_hWnd == hWndOrig); //<-This is the ASSERT that fails!
  93. // Detach after DestroyWindow called just in case
  94. Detach();
  95. }
  96. }
  97.  
  98. return bResult;
  99. }
  100.  
  101. From what I have been able to obtain via tracepoints, when the assert fails, `pWnd = (CWnd*)pMap->LookupPermanent(m_hWnd);` returns NULL.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement