Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

378 lines
8.9 KiB

// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1995 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#include "stdafx.h"
#ifdef AFX_OLE4_SEG
#pragma code_seg(AFX_OLE4_SEG)
#endif
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define new DEBUG_NEW
/////////////////////////////////////////////////////////////////////////////
// COleMessageFilter::IMessageFilter implementation
#ifdef AFX_INIT_SEG
#pragma code_seg(AFX_INIT_SEG)
#endif
COleMessageFilter::COleMessageFilter()
{
// begin in not-busy state
m_nBusyCount = 0;
// dialogs are enabled by default
m_bEnableBusy = TRUE;
m_bEnableNotResponding = TRUE;
m_nBusyReply = SERVERCALL_RETRYLATER;
// effective only when m_nBusyCount != 0
m_nRetryReply = 10000; // default is 10 sec
m_nTimeout = 8000; // default is 8 sec
m_bUnblocking = FALSE;
// TRUE to avoid re-entrancy when busy dialog is up
m_bRegistered = FALSE;
ASSERT_VALID(this);
}
#ifdef AFX_TERM_SEG
#pragma code_seg(AFX_TERM_SEG)
#endif
COleMessageFilter::~COleMessageFilter()
{
ASSERT_VALID(this);
Revoke();
}
/////////////////////////////////////////////////////////////////////////////
// Busy state management
#ifdef AFX_OLE4_SEG
#pragma code_seg(AFX_OLE4_SEG)
#endif
void COleMessageFilter::BeginBusyState()
{
ASSERT_VALID(this);
++m_nBusyCount;
}
void COleMessageFilter::EndBusyState()
{
ASSERT_VALID(this);
if (m_nBusyCount != 0)
--m_nBusyCount;
}
/////////////////////////////////////////////////////////////////////////////
// COleMessageFilter operations
#ifdef AFX_INIT_SEG
#pragma code_seg(AFX_INIT_SEG)
#endif
BOOL COleMessageFilter::Register()
{
ASSERT_VALID(this);
ASSERT(!m_bRegistered); // calling Register twice?
if (::CoRegisterMessageFilter(&m_xMessageFilter, NULL) == S_OK)
{
m_bRegistered = TRUE;
return TRUE;
}
return FALSE;
}
#ifdef AFX_TERM_SEG
#pragma code_seg(AFX_TERM_SEG)
#endif
void COleMessageFilter::Revoke()
{
ASSERT_VALID(this);
if (m_bRegistered)
{
::CoRegisterMessageFilter(NULL, NULL);
m_bRegistered = FALSE;
}
}
/////////////////////////////////////////////////////////////////////////////
// COleMessageFilter standard implementation of callbacks
#ifdef AFX_OLE4_SEG
#pragma code_seg(AFX_OLE4_SEG)
#endif
BOOL COleMessageFilter::OnMessagePending(const MSG* pMsg)
{
// By default we rely on OLE's default message handling for every message
// except WM_PAINT messages. WM_PAINT messages should not generate
// out-going calls.
BOOL bEatMessage = FALSE;
switch (pMsg->message)
{
case WM_PAINT:
DispatchMessage(pMsg);
bEatMessage = TRUE;
break;
}
if (bEatMessage)
{
MSG msg;
::PeekMessage(&msg, NULL, pMsg->message, pMsg->message,
PM_REMOVE|PM_NOYIELD);
}
return bEatMessage;
}
BOOL COleMessageFilter::IsSignificantMessage(MSG*)
{
// check for "significant" messages in the queue
UINT rgnMsgs[] =
{
WM_KEYDOWN, WM_SYSKEYDOWN,
WM_LBUTTONDOWN, WM_RBUTTONDOWN, WM_MBUTTONDOWN,
WM_NCLBUTTONDOWN, WM_NCRBUTTONDOWN, WM_NCMBUTTONDOWN,
WM_LBUTTONDBLCLK, WM_RBUTTONDBLCLK, WM_MBUTTONDBLCLK,
WM_NCLBUTTONDBLCLK, WM_NCRBUTTONDBLCLK, WM_NCMBUTTONDBLCLK
};
MSG msg;
for (int i = 0; i < _countof(rgnMsgs); i++)
{
if (::PeekMessage(&msg, NULL, rgnMsgs[i], rgnMsgs[i],
PM_NOREMOVE|PM_NOYIELD))
{
if ((msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN) &&
(HIWORD(msg.lParam) & KF_REPEAT))
{
// a key-repeat is a non-significant message
continue;
}
// "significant" message is waiting in the queue
return TRUE;
}
}
// no significant messages in the queue
return FALSE;
}
int COleMessageFilter::OnBusyDialog(HTASK htaskBusy)
{
COleBusyDialog dlg(htaskBusy, FALSE);
int nResult = -1;
TRY
{
if (dlg.DoModal() == IDOK)
nResult = dlg.GetSelectionType();
}
END_TRY
return nResult;
}
int COleMessageFilter::OnNotRespondingDialog(HTASK htaskBusy)
{
COleBusyDialog dlg(htaskBusy, TRUE);
int nResult = -1;
TRY
{
if (dlg.DoModal() == IDOK)
nResult = dlg.GetSelectionType();
}
END_TRY
return nResult;
}
/////////////////////////////////////////////////////////////////////////////
// COleMessageFilter OLE interface implementation
BEGIN_INTERFACE_MAP(COleMessageFilter, CCmdTarget)
INTERFACE_PART(COleMessageFilter, IID_IMessageFilter, MessageFilter)
END_INTERFACE_MAP()
STDMETHODIMP_(ULONG) COleMessageFilter::XMessageFilter::AddRef()
{
METHOD_PROLOGUE_EX_(COleMessageFilter, MessageFilter)
return pThis->ExternalAddRef();
}
STDMETHODIMP_(ULONG) COleMessageFilter::XMessageFilter::Release()
{
METHOD_PROLOGUE_EX_(COleMessageFilter, MessageFilter)
return pThis->ExternalRelease();
}
STDMETHODIMP COleMessageFilter::XMessageFilter::QueryInterface(
REFIID iid, LPVOID* ppvObj)
{
METHOD_PROLOGUE_EX_(COleMessageFilter, MessageFilter)
return pThis->ExternalQueryInterface(&iid, ppvObj);
}
STDMETHODIMP_(DWORD) COleMessageFilter::XMessageFilter::HandleInComingCall(
DWORD dwCallType, HTASK /*htaskCaller*/,
DWORD /*dwTickCount*/, LPINTERFACEINFO /*lpInterfaceInfo*/)
{
METHOD_PROLOGUE_EX_(COleMessageFilter, MessageFilter)
// check for application busy first...
if (pThis->m_nBusyCount == 0)
{
if (dwCallType == CALLTYPE_TOPLEVEL ||
dwCallType == CALLTYPE_TOPLEVEL_CALLPENDING)
{
// make sure CWinThread::OnIdle has a chance to run later
MSG msg;
if (!::PeekMessage(&msg, NULL, WM_KICKIDLE, WM_KICKIDLE, PM_NOREMOVE))
::PostThreadMessage(GetCurrentThreadId(), WM_KICKIDLE, 0, 0);
}
return SERVERCALL_ISHANDLED;
}
if (dwCallType == CALLTYPE_TOPLEVEL ||
dwCallType == CALLTYPE_TOPLEVEL_CALLPENDING)
{
// application is busy and we have rejectable CALLTYPE
return pThis->m_nBusyReply;
}
// application is busy, but CALLTYPE indicates that it *must* be handled
return SERVERCALL_ISHANDLED;
}
STDMETHODIMP_(DWORD) COleMessageFilter::XMessageFilter::RetryRejectedCall(
HTASK htaskCallee, DWORD dwTickCount, DWORD dwRejectType)
{
METHOD_PROLOGUE_EX(COleMessageFilter, MessageFilter)
ASSERT_VALID(pThis);
// rejected calls get cancelled regardless of timeout
if (dwRejectType == SERVERCALL_REJECTED)
return (DWORD)-1;
// if insignificant time has passed, don't panic -- just retry
if (dwTickCount <= pThis->m_nRetryReply)
return 0; // retry right away (0-100 are retry immediate)
// too much time has passed, do something more drastic
if (pThis->m_bEnableBusy)
{
// show busy dialog
int selType = pThis->OnBusyDialog(htaskCallee);
// take action depending on selection
switch (selType)
{
case -1:
return (DWORD)-1; // cancel outgoing call
case COleBusyDialog::retry:
return 0; // retry immediately
}
}
return pThis->m_nRetryReply; // use standard retry timeout
}
STDMETHODIMP_(DWORD) COleMessageFilter::XMessageFilter::MessagePending(
HTASK htaskCallee, DWORD dwTickCount, DWORD /*dwPendingType*/)
{
METHOD_PROLOGUE_EX(COleMessageFilter, MessageFilter)
ASSERT_VALID(pThis);
MSG msg;
if (dwTickCount > pThis->m_nTimeout && !pThis->m_bUnblocking &&
pThis->IsSignificantMessage(&msg))
{
if (pThis->m_bEnableNotResponding)
{
pThis->m_bUnblocking = TRUE; // avoid reentrant calls
// eat all mouse messages in our queue
while (PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST,
PM_REMOVE|PM_NOYIELD))
;
// eat all keyboard messages in our queue
while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST,
PM_REMOVE|PM_NOYIELD))
;
// show not responding dialog
pThis->OnNotRespondingDialog(htaskCallee);
pThis->m_bUnblocking = FALSE;
return PENDINGMSG_WAITNOPROCESS;
}
}
// don't process re-entrant messages
if (pThis->m_bUnblocking)
return PENDINGMSG_WAITDEFPROCESS;
// allow application to process pending message
if (::PeekMessage(&msg, NULL, NULL, NULL, PM_NOREMOVE|PM_NOYIELD) &&
pThis->OnMessagePending(&msg))
{
// app has processed the message (and removed it from the queue)
return PENDINGMSG_WAITNOPROCESS;
}
// by default we return pending MSG wait
return PENDINGMSG_WAITNOPROCESS;
}
/////////////////////////////////////////////////////////////////////////////
// COleMessageFilter diagnostics
#ifdef _DEBUG
void COleMessageFilter::AssertValid() const
{
CCmdTarget::AssertValid();
}
void COleMessageFilter::Dump(CDumpContext& dc) const
{
CCmdTarget::Dump(dc);
dc << "m_bRegistered = " << m_bRegistered;
dc << "\nm_nBusyCount = " << m_nBusyCount;
dc << "\nm_bEnableBusy = " << m_bEnableBusy;
dc << "\nm_bEnableNotResponding = " << m_bEnableNotResponding;
dc << "\nm_bUnblocking = " << m_bUnblocking;
dc << "\nm_nRetryReply = " << m_nRetryReply;
dc << "\nm_nBusyReply = " << m_nBusyReply;
dc << "\nm_nTimeout = " << m_nTimeout;
dc << "\n";
}
#endif
/////////////////////////////////////////////////////////////////////////////