home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / MS_VC.50 / VC / MFC / SRC / OLEMSGF.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1996-12-11  |  9.1 KB  |  366 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1997 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #include "stdafx.h"
  12.  
  13. #ifdef AFX_OLE4_SEG
  14. #pragma code_seg(AFX_OLE4_SEG)
  15. #endif
  16.  
  17. #ifdef _DEBUG
  18. #undef THIS_FILE
  19. static char THIS_FILE[] = __FILE__;
  20. #endif
  21.  
  22. #define new DEBUG_NEW
  23.  
  24. /////////////////////////////////////////////////////////////////////////////
  25. // COleMessageFilter::IMessageFilter implementation
  26.  
  27. #ifdef AFX_INIT_SEG
  28. #pragma code_seg(AFX_INIT_SEG)
  29. #endif
  30.  
  31. COleMessageFilter::COleMessageFilter()
  32. {
  33.     // begin in not-busy state
  34.     m_nBusyCount = 0;
  35.  
  36.     // dialogs are enabled by default
  37.     m_bEnableBusy = TRUE;
  38.     m_bEnableNotResponding = TRUE;
  39.  
  40.     m_nBusyReply = SERVERCALL_RETRYLATER;
  41.         // effective only when m_nBusyCount != 0
  42.  
  43.     m_nRetryReply = 10000;  // default is 10 sec
  44.     m_nTimeout = 8000;  // default is 8 sec
  45.  
  46.     m_bUnblocking = FALSE;
  47.         // TRUE to avoid re-entrancy when busy dialog is up
  48.  
  49.     m_bRegistered = FALSE;
  50.  
  51.     ASSERT_VALID(this);
  52. }
  53.  
  54. #ifdef AFX_TERM_SEG
  55. #pragma code_seg(AFX_TERM_SEG)
  56. #endif
  57.  
  58. COleMessageFilter::~COleMessageFilter()
  59. {
  60.     ASSERT_VALID(this);
  61.  
  62.     Revoke();
  63. }
  64.  
  65. /////////////////////////////////////////////////////////////////////////////
  66. // Busy state management
  67.  
  68. #ifdef AFX_OLE4_SEG
  69. #pragma code_seg(AFX_OLE4_SEG)
  70. #endif
  71.  
  72. void COleMessageFilter::BeginBusyState()
  73. {
  74.     ASSERT_VALID(this);
  75.     ++m_nBusyCount;
  76. }
  77.  
  78. void COleMessageFilter::EndBusyState()
  79. {
  80.     ASSERT_VALID(this);
  81.     if (m_nBusyCount != 0)
  82.         --m_nBusyCount;
  83. }
  84.  
  85. /////////////////////////////////////////////////////////////////////////////
  86. // COleMessageFilter operations
  87.  
  88. #ifdef AFX_INIT_SEG
  89. #pragma code_seg(AFX_INIT_SEG)
  90. #endif
  91.  
  92. BOOL COleMessageFilter::Register()
  93. {
  94.     ASSERT_VALID(this);
  95.     ASSERT(!m_bRegistered); // calling Register twice?
  96.  
  97.     if (::CoRegisterMessageFilter(&m_xMessageFilter, NULL) == S_OK)
  98.     {
  99.         m_bRegistered = TRUE;
  100.         return TRUE;
  101.     }
  102.     return FALSE;
  103. }
  104.  
  105. #ifdef AFX_TERM_SEG
  106. #pragma code_seg(AFX_TERM_SEG)
  107. #endif
  108.  
  109. void COleMessageFilter::Revoke()
  110. {
  111.     ASSERT_VALID(this);
  112.  
  113.     if (m_bRegistered)
  114.     {
  115.         ::CoRegisterMessageFilter(NULL, NULL);
  116.         m_bRegistered = FALSE;
  117.     }
  118. }
  119.  
  120. /////////////////////////////////////////////////////////////////////////////
  121. // COleMessageFilter standard implementation of callbacks
  122.  
  123. #ifdef AFX_OLE4_SEG
  124. #pragma code_seg(AFX_OLE4_SEG)
  125. #endif
  126.  
  127. BOOL COleMessageFilter::OnMessagePending(const MSG* /*pMsg*/)
  128. {
  129.     // By default we rely on OLE's default message handling for every message
  130.     //  except WM_PAINT messages.  WM_PAINT messages should not generate
  131.     //  out-going calls.
  132.  
  133.     BOOL bEatMessage = FALSE;
  134.     MSG msg;
  135.     while (::PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE|PM_NOYIELD))
  136.     {
  137.         bEatMessage = TRUE;
  138.         DispatchMessage(&msg);
  139.     }
  140.     return bEatMessage;
  141. }
  142.  
  143. BOOL COleMessageFilter::IsSignificantMessage(MSG*)
  144. {
  145.     // check for "significant" messages in the queue
  146.     static const UINT rgnMsgs[] =
  147.     {
  148.         WM_KEYDOWN, WM_SYSKEYDOWN,    WM_TIMER,
  149.         WM_LBUTTONDOWN, WM_RBUTTONDOWN, WM_MBUTTONDOWN,
  150.         WM_NCLBUTTONDOWN, WM_NCRBUTTONDOWN, WM_NCMBUTTONDOWN,
  151.         WM_LBUTTONDBLCLK, WM_RBUTTONDBLCLK, WM_MBUTTONDBLCLK,
  152.         WM_NCLBUTTONDBLCLK, WM_NCRBUTTONDBLCLK, WM_NCMBUTTONDBLCLK
  153.     };
  154.     MSG msg;
  155.     for (int i = 0; i < _countof(rgnMsgs); i++)
  156.     {
  157.         if (::PeekMessage(&msg, NULL, rgnMsgs[i], rgnMsgs[i],
  158.             PM_NOREMOVE|PM_NOYIELD))
  159.         {
  160.             if ((msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN) &&
  161.                 (HIWORD(msg.lParam) & KF_REPEAT))
  162.             {
  163.                 // a key-repeat is a non-significant message
  164.                 continue;
  165.             }
  166.  
  167.             // "significant" message is waiting in the queue
  168.             return TRUE;
  169.         }
  170.     }
  171.  
  172.     // no significant messages in the queue
  173.     return FALSE;
  174. }
  175.  
  176. int COleMessageFilter::OnBusyDialog(HTASK htaskBusy)
  177. {
  178.     COleBusyDialog dlg(htaskBusy, FALSE);
  179.  
  180.     int nResult = -1;
  181.     TRY
  182.     {
  183.         if (dlg.DoModal() == IDOK)
  184.             nResult = dlg.GetSelectionType();
  185.     }
  186.     END_TRY
  187.  
  188.     return nResult;
  189. }
  190.  
  191. int COleMessageFilter::OnNotRespondingDialog(HTASK htaskBusy)
  192. {
  193.     COleBusyDialog dlg(htaskBusy, TRUE);
  194.  
  195.     int nResult = -1;
  196.     TRY
  197.     {
  198.         if (dlg.DoModal() == IDOK)
  199.             nResult = dlg.GetSelectionType();
  200.     }
  201.     END_TRY
  202.  
  203.     return nResult;
  204. }
  205.  
  206. /////////////////////////////////////////////////////////////////////////////
  207. // COleMessageFilter OLE interface implementation
  208.  
  209. BEGIN_INTERFACE_MAP(COleMessageFilter, CCmdTarget)
  210.     INTERFACE_PART(COleMessageFilter, IID_IMessageFilter, MessageFilter)
  211. END_INTERFACE_MAP()
  212.  
  213. STDMETHODIMP_(ULONG) COleMessageFilter::XMessageFilter::AddRef()
  214. {
  215.     METHOD_PROLOGUE_EX_(COleMessageFilter, MessageFilter)
  216.     return pThis->ExternalAddRef();
  217. }
  218.  
  219. STDMETHODIMP_(ULONG) COleMessageFilter::XMessageFilter::Release()
  220. {
  221.     METHOD_PROLOGUE_EX_(COleMessageFilter, MessageFilter)
  222.     return pThis->ExternalRelease();
  223. }
  224.  
  225. STDMETHODIMP COleMessageFilter::XMessageFilter::QueryInterface(
  226.     REFIID iid, LPVOID* ppvObj)
  227. {
  228.     METHOD_PROLOGUE_EX_(COleMessageFilter, MessageFilter)
  229.     return pThis->ExternalQueryInterface(&iid, ppvObj);
  230. }
  231.  
  232. STDMETHODIMP_(DWORD) COleMessageFilter::XMessageFilter::HandleInComingCall(
  233.     DWORD dwCallType, HTASK /*htaskCaller*/,
  234.     DWORD /*dwTickCount*/, LPINTERFACEINFO /*lpInterfaceInfo*/)
  235. {
  236.     METHOD_PROLOGUE_EX_(COleMessageFilter, MessageFilter)
  237.  
  238.     // check for application busy first...
  239.     if (pThis->m_nBusyCount == 0)
  240.     {
  241.         if (dwCallType == CALLTYPE_TOPLEVEL ||
  242.             dwCallType == CALLTYPE_TOPLEVEL_CALLPENDING)
  243.         {
  244.             // make sure CWinThread::OnIdle has a chance to run later
  245.             MSG msg;
  246.             if (!::PeekMessage(&msg, NULL, WM_KICKIDLE, WM_KICKIDLE, PM_NOREMOVE))
  247.                 ::PostThreadMessage(GetCurrentThreadId(), WM_KICKIDLE, 0, 0);
  248.         }
  249.         return SERVERCALL_ISHANDLED;
  250.     }
  251.  
  252.     if (dwCallType == CALLTYPE_TOPLEVEL ||
  253.         dwCallType == CALLTYPE_TOPLEVEL_CALLPENDING)
  254.     {
  255.         // application is busy and we have rejectable CALLTYPE
  256.         return pThis->m_nBusyReply;
  257.     }
  258.  
  259.     // application is busy, but CALLTYPE indicates that it *must* be handled
  260.     return SERVERCALL_ISHANDLED;
  261. }
  262.  
  263. STDMETHODIMP_(DWORD) COleMessageFilter::XMessageFilter::RetryRejectedCall(
  264.     HTASK htaskCallee, DWORD dwTickCount, DWORD dwRejectType)
  265. {
  266.     METHOD_PROLOGUE_EX(COleMessageFilter, MessageFilter)
  267.     ASSERT_VALID(pThis);
  268.  
  269.     // rejected calls get cancelled regardless of timeout
  270.     if (dwRejectType == SERVERCALL_REJECTED)
  271.         return (DWORD)-1;
  272.  
  273.     // if insignificant time has passed, don't panic -- just retry
  274.     if (dwTickCount <= pThis->m_nRetryReply)
  275.         return 0;   // retry right away (0-100 are retry immediate)
  276.  
  277.     // too much time has passed, do something more drastic
  278.     if (pThis->m_bEnableBusy)
  279.     {
  280.         // show busy dialog
  281.         int selType = pThis->OnBusyDialog(htaskCallee);
  282.  
  283.         // take action depending on selection
  284.         switch (selType)
  285.         {
  286.         case -1:
  287.             return (DWORD)-1;   // cancel outgoing call
  288.  
  289.         case COleBusyDialog::retry:
  290.             return 0;           // retry immediately
  291.         }
  292.     }
  293.     return pThis->m_nRetryReply;    // use standard retry timeout
  294. }
  295.  
  296. STDMETHODIMP_(DWORD) COleMessageFilter::XMessageFilter::MessagePending(
  297.     HTASK htaskCallee, DWORD dwTickCount, DWORD /*dwPendingType*/)
  298. {
  299.     METHOD_PROLOGUE_EX(COleMessageFilter, MessageFilter)
  300.     ASSERT_VALID(pThis);
  301.  
  302.     MSG msg;
  303.     if (dwTickCount > pThis->m_nTimeout && !pThis->m_bUnblocking &&
  304.         pThis->IsSignificantMessage(&msg))
  305.     {
  306.         if (pThis->m_bEnableNotResponding)
  307.         {
  308.             pThis->m_bUnblocking = TRUE;    // avoid reentrant calls
  309.  
  310.             // eat all mouse messages in our queue
  311.             while (PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST,
  312.                 PM_REMOVE|PM_NOYIELD))
  313.                 ;
  314.             // eat all keyboard messages in our queue
  315.             while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST,
  316.                 PM_REMOVE|PM_NOYIELD))
  317.                 ;
  318.  
  319.             // show not responding dialog
  320.             pThis->OnNotRespondingDialog(htaskCallee);
  321.             pThis->m_bUnblocking = FALSE;
  322.  
  323.             return PENDINGMSG_WAITNOPROCESS;
  324.         }
  325.     }
  326.  
  327.     // don't process re-entrant messages
  328.     if (pThis->m_bUnblocking)
  329.         return PENDINGMSG_WAITDEFPROCESS;
  330.  
  331.     // allow application to process pending message
  332.     if (::PeekMessage(&msg, NULL, NULL, NULL, PM_NOREMOVE|PM_NOYIELD))
  333.         pThis->OnMessagePending(&msg);
  334.  
  335.     // by default we return pending MSG wait
  336.     return PENDINGMSG_WAITNOPROCESS;
  337. }
  338.  
  339. /////////////////////////////////////////////////////////////////////////////
  340. // COleMessageFilter diagnostics
  341.  
  342. #ifdef _DEBUG
  343. void COleMessageFilter::AssertValid() const
  344. {
  345.     CCmdTarget::AssertValid();
  346. }
  347.  
  348. void COleMessageFilter::Dump(CDumpContext& dc) const
  349. {
  350.     CCmdTarget::Dump(dc);
  351.  
  352.     dc << "m_bRegistered = " << m_bRegistered;
  353.     dc << "\nm_nBusyCount = " << m_nBusyCount;
  354.     dc << "\nm_bEnableBusy = " << m_bEnableBusy;
  355.     dc << "\nm_bEnableNotResponding = " << m_bEnableNotResponding;
  356.     dc << "\nm_bUnblocking = " << m_bUnblocking;
  357.     dc << "\nm_nRetryReply = " << m_nRetryReply;
  358.     dc << "\nm_nBusyReply = " << m_nBusyReply;
  359.     dc << "\nm_nTimeout = " << m_nTimeout;
  360.  
  361.     dc << "\n";
  362. }
  363. #endif
  364.  
  365. /////////////////////////////////////////////////////////////////////////////
  366.