MSGLOOP.CPP
//--------------------------------------------------------------------------- 
// MsgLoop.cpp 
//--------------------------------------------------------------------------- 
// Implementation of message loop for application.  Includes implementation 
// of IOleComponentManager. 
//--------------------------------------------------------------------------- 
// (C) Copyright 1995-1997 by Microsoft Corporation.  All rights reserved. 
// 
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF  
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO  
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A  
// PARTICULAR PURPOSE. 
//--------------------------------------------------------------------------- 
 
#include "Main.h" 
#pragma hdrstop 
#include "MsgLoop.h" 
 
 
//--------------------------------------------------------------------------- 
// DEBUG info 
//--------------------------------------------------------------------------- 
SZTHISFILE 
 
 
//--------------------------------------------------------------------------- 
// 
//--------------------------------------------------------------------------- 
CMsgLoop::CMsgLoop 
( 
  HWND hwnd 
) 
  { 
  INIT_SIGNATURE(SIG_MsgLoop); 
 
  for (int i=0; i<cCOMP; i++) 
    m_rgcomp[i].pcomp = NULL; 
 
  m_icompActive  = icompNIL; 
  m_fInState     = FALSE; 
  m_icompState   = icompNIL; 
  m_uStateID     = 0; 
  m_fScrptReset  = FALSE; 
  m_fQuitting    = FALSE; 
  m_hwnd         = hwnd; 
  m_haccel       = NULL;     // Load accel table here 
  m_icompMsgLoop =icompNIL; 
 
  m_cref        = 1; 
  m_cMsgLoop    = 0; 
  } 
 
 
//--------------------------------------------------------------------------- 
// 
//--------------------------------------------------------------------------- 
CMsgLoop::~CMsgLoop 
( 
  void 
) 
  { 
  CHECK_SIGNATURE(SIG_MsgLoop); 
 
  for (int i=0; i<cCOMP; i++) 
    if (m_rgcomp[i].pcomp) 
      { 
      m_rgcomp[i].pcomp->Terminate(); 
      RELEASEPTR(m_rgcomp[i].pcomp); 
      } 
 
  DESTROY_SIGNATURE(SIG_MsgLoop); 
  } 
 
 
//*************************************************************************** 
// IUnknown methods 
//*************************************************************************** 
 
//--------------------------------------------------------------------------- 
// 
//--------------------------------------------------------------------------- 
STDMETHODIMP CMsgLoop::QueryInterface 
( 
  REFIID   riid,  
  void   **ppvObj 
) 
  { 
  *ppvObj = NULL; 
 
  if (riid == IID_IUnknown) 
    *ppvObj = (LPVOID)(IUnknown *)(IOleComponentManager *)this; 
  else if (riid == IID_IOleComponentManager) 
    *ppvObj = (LPVOID)(IOleComponentManager *)this;  
 
  if (*ppvObj)  
    { 
    this->AddRef(); 
    return S_OK; 
    } 
   
  return E_NOINTERFACE; 
  } 
 
 
//--------------------------------------------------------------------------- 
// 
//--------------------------------------------------------------------------- 
STDMETHODIMP_(ULONG) CMsgLoop::AddRef 
( 
  void 
) 
  { 
  CHECK_SIGNATURE(SIG_MsgLoop); 
  return ++m_cref; 
  } 
 
 
//--------------------------------------------------------------------------- 
// 
//--------------------------------------------------------------------------- 
STDMETHODIMP_(ULONG) CMsgLoop::Release 
( 
  void 
) 
  { 
  CHECK_SIGNATURE(SIG_MsgLoop); 
  if (--m_cref) 
    return m_cref; 
 
  delete this; 
  return 0; 
  } 
 
 
 
//*************************************************************************** 
// IOleComponentManager Methods 
//*************************************************************************** 
 
//--------------------------------------------------------------------------- 
// 
//--------------------------------------------------------------------------- 
STDMETHODIMP CMsgLoop::QueryService 
( 
  REFGUID guidService,  
  REFIID  iid,  
  void  **ppvObjOut 
)  
  { 
  *ppvObjOut = NULL; 
  return E_NOINTERFACE; 
  } 
 
 
//--------------------------------------------------------------------------- 
// 
//--------------------------------------------------------------------------- 
STDMETHODIMP_(BOOL) CMsgLoop::FRegisterComponent 
( 
  IOleComponent   *piComponent,  
  const CMGRRINFO *pcrinfo,  
  DWORD           *pdwCompIDOut 
) 
  { 
  for (int i=0; i<cCOMP; i++) 
    if (!m_rgcomp[i].pcomp) 
      { 
      piComponent->AddRef(); 
      m_rgcomp[i].pcomp = piComponent; 
      *pdwCompIDOut = i; 
      return TRUE; 
      } 
 
  FAIL("Out of room!"); 
  return FALSE; 
  } 
 
 
//--------------------------------------------------------------------------- 
// 
//--------------------------------------------------------------------------- 
STDMETHODIMP_(BOOL) CMsgLoop::FRevokeComponent 
( 
  DWORD icomp 
) 
  { 
  ASSERT(m_rgcomp[icomp].pcomp, "Bogus icomp"); 
  RELEASEPTR(m_rgcomp[icomp].pcomp); 
  if (m_icompActive == icomp) 
    m_icompActive = icompNIL; 
  if (m_icompMsgLoop == icomp) 
    m_icompMsgLoop = icompNIL; 
  return TRUE; 
  } 
 
 
//--------------------------------------------------------------------------- 
// 
//--------------------------------------------------------------------------- 
STDMETHODIMP_(BOOL) CMsgLoop::FUpdateComponentRegistration 
(  
  DWORD            dwComponentID,  
  const CMGRRINFO *pcrinfo 
) 
  { 
  // Don't track info anyway, so pretend it worked: 
  return TRUE; 
  } 
 
 
//--------------------------------------------------------------------------- 
// 
//--------------------------------------------------------------------------- 
STDMETHODIMP_(void) CMsgLoop::OnComponentActivate 
( 
  DWORD icomp 
) 
  { 
  ASSERT(m_rgcomp[icomp].pcomp, "Bad icomp"); 
  m_icompActive = icomp; 
  return; 
  } 
 
 
//--------------------------------------------------------------------------- 
// 
//--------------------------------------------------------------------------- 
STDMETHODIMP_(BOOL) CMsgLoop::FSetTrackingComponent 
( 
  DWORD dwComponentID,  
  BOOL  fTrack 
) 
  { 
  // UNDONE: Need to support 
  return FALSE; 
  } 
 
 
//--------------------------------------------------------------------------- 
// 
//--------------------------------------------------------------------------- 
STDMETHODIMP_(void) CMsgLoop::OnComponentEnterState 
( 
  DWORD icomp, 
  ULONG uStateID,  
  ULONG uContext,  
  ULONG cpicmExclude, 
  IOleComponentManager **rgpicmExclude, 
  DWORD dwReserved 
) 
  { 
  ASSERT(m_rgcomp[icomp].pcomp, "Bad icomp"); 
  ASSERT(uStateID==cmgrstateModal,  "Not modal state"); 
  ASSERT(!m_fInState, "Nested modal states"); 
 
  m_icompState = icomp; 
  m_fInState   = TRUE; 
  m_uStateID   = uStateID; 
  if (uStateID == cmgrstateModal) 
    EnableWindow(m_hwnd, FALSE); 
  } 
 
 
//--------------------------------------------------------------------------- 
// 
//--------------------------------------------------------------------------- 
STDMETHODIMP_(BOOL) CMsgLoop::FOnComponentExitState 
( 
  DWORD icomp, 
  ULONG uStateID, 
  ULONG uContext, 
  ULONG cpicmExclude, 
  IOleComponentManager **rgpicmExclude 
) 
  { 
  ASSERT(m_rgcomp[icomp].pcomp, "Bad icomp"); 
  ASSERT(icomp==(DWORD)m_icompState, "icomp didn't own state"); 
  ASSERT(uStateID==cmgrstateModal,  "Not modal state"); 
  ASSERT(uStateID==m_uStateID, "non-matching modal states on pop"); 
  ASSERT(m_fInState, "underflow of modal state"); 
 
  m_fInState   = FALSE; 
  m_icompState = icompNIL; 
  if (uStateID == cmgrstateModal) 
    EnableWindow(m_hwnd, TRUE); 
  return TRUE; 
  } 
 
 
//--------------------------------------------------------------------------- 
// 
//--------------------------------------------------------------------------- 
STDMETHODIMP_(BOOL) CMsgLoop::FInState 
( 
  ULONG uStateID, 
  void *pvoid 
) 
  { 
  return m_fInState && uStateID==m_uStateID; 
  } 
 
 
//--------------------------------------------------------------------------- 
// 
//--------------------------------------------------------------------------- 
STDMETHODIMP_(BOOL) CMsgLoop::FContinueIdle 
( 
  void 
) 
  { 
  return FALSE; 
  } 
 
 
//--------------------------------------------------------------------------- 
// 
//--------------------------------------------------------------------------- 
STDMETHODIMP_(BOOL) CMsgLoop::FPushMessageLoop 
( 
  DWORD icomp,  
  ULONG uReason,  
  void *pvLoopData 
) 
  { 
  MessageLoop(icomp, uReason, pvLoopData); 
  return TRUE; 
  } 
 
 
//--------------------------------------------------------------------------- 
// 
//--------------------------------------------------------------------------- 
STDMETHODIMP_(BOOL) CMsgLoop::FCreateSubComponentManager 
( 
  IUnknown *piunkOuter,  
  IUnknown *piunkServProv, 
  REFIID    riid,  
  void    **ppvObj 
) 
  { 
  ASSERT(!piunkOuter, "Don't support aggre. SubCompMgr"); 
  HRESULT hr = this->QueryInterface(riid, ppvObj); 
  return !FAILED(hr); 
  } 
 
 
//--------------------------------------------------------------------------- 
// 
//--------------------------------------------------------------------------- 
STDMETHODIMP_(BOOL) CMsgLoop::FGetParentComponentManager 
( 
  IOleComponentManager **ppicm 
) 
  { 
  // UNDONE: Need to implement 
  return FALSE; 
  } 
 
 
//--------------------------------------------------------------------------- 
// 
//--------------------------------------------------------------------------- 
STDMETHODIMP_(BOOL) CMsgLoop::FGetActiveComponent 
( 
  DWORD           dwReserved, 
  IOleComponent **ppcompOut 
) 
  { 
  // Do we have an active component? 
  if (m_icompActive == icompNIL) 
    { 
    *ppcompOut = NULL; 
    return FALSE; 
    } 
 
  // Yes, return it 
  *ppcompOut = m_rgcomp[m_icompActive].pcomp; 
  (*ppcompOut)->AddRef();       // for *ppcompOut 
  return TRUE; 
  } 
 
 
 
//*************************************************************************** 
// Message Loop Implementation 
//*************************************************************************** 
 
//--------------------------------------------------------------------------- 
// This pushes a new message loop. 
//--------------------------------------------------------------------------- 
void CMsgLoop::MessageLoop 
( 
  DWORD icomp, 
  ULONG uReason,  
  void *pvLoopData 
) 
  { 
  BOOL  fExitLoop = FALSE; 
 
  m_cMsgLoop++; 
 
  while (!fExitLoop)  
    fExitLoop = PumpMessage(icomp, uReason, pvLoopData); 
 
  m_cMsgLoop--; 
 
  if (!m_cMsgLoop) 
    m_fScrptReset = FALSE; 
  } 
 
 
//--------------------------------------------------------------------------- 
// This processes one message. 
// Returns TRUE if it is time to exit the current message loop. 
//--------------------------------------------------------------------------- 
BOOL CMsgLoop::PumpMessage 
( 
  DWORD icomp, 
  ULONG uReason,  
  void *pvLoopData 
) 
  { 
  BOOL fExitLoop = FALSE; 
  BOOL fMsg; 
  MSG  msg; 
 
  fMsg = PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE); 
  if (fMsg)  
    { 
    if (msg.message == WM_QUIT) 
      { 
      // Since we're not really an app, re-post the WM_QUIT message, until 
      // we can pop any msgloops we've pushed. 
      if (m_cMsgLoop) 
       PostQuitMessage(msg.wParam); 
      return TRUE; 
      } 
    else 
      ProcessMessage(&msg); 
    } 
 
  if (m_fScrptReset) 
    return TRUE; 
 
  // A Component told us to push this message loop, and so we 
  // ask them whether it's time yet to exit the loop 
  fExitLoop = !m_rgcomp[icomp].pcomp->FContinueMessageLoop(uReason, pvLoopData); 
 
  if (!fMsg && !fExitLoop)  
    { 
    // There weren't any messages and we don't need to exit this message 
    // loop yet.  Therefore, now is the right time to do idle processing 
    DoIdleProcessing(); 
    WaitMessage(); 
    } 
 
  return fExitLoop; 
  } 
 
 
//--------------------------------------------------------------------------- 
// This processes one message. 
//--------------------------------------------------------------------------- 
void CMsgLoop::ProcessMessage 
( 
  MSG  *pmsg 
) 
  {     
  // When a component is active give it a chance to translate 
  // its accelerators. 
  if (m_icompActive != icompNIL) 
    { 
    if (!m_rgcomp[m_icompActive].pcomp->FPreTranslateMessage(pmsg)) 
      { 
      TranslateMessage(pmsg);    // Translates virtual key codes   
      DispatchMessage(pmsg);    // Dispatches message to window  
      } 
    }  
  else  
    { 
    if (!TranslateAccelerator(m_hwnd, m_haccel, pmsg)) 
      { 
      TranslateMessage(pmsg); // Translates virtual key codes   
      DispatchMessage(pmsg);  // Dispatches message to window  
      } 
    } 
  } 
 
 
//--------------------------------------------------------------------------- 
// This is called at idle time. 
//--------------------------------------------------------------------------- 
void CMsgLoop::DoIdleProcessing 
( 
  void 
) 
  { 
  MSG  msg; 
  BOOL fContinue = TRUE; 
 
  while (fContinue && !PeekMessage(&msg, NULL, NULL, NULL, PM_NOREMOVE)) 
    { 
    fContinue = DoIdle(); 
    } 
  } 
 
 
//--------------------------------------------------------------------------- 
// 
//--------------------------------------------------------------------------- 
BOOL CMsgLoop::DoIdle 
( 
  void 
) 
  { 
  int  i; 
  BOOL fDidWork = FALSE; 
 
  // if we have periodic idle tasks that to be done,  
  // do them and return TRUE. 
  for (i=0; i<cCOMP; i++) 
    { 
    if (m_rgcomp[i].pcomp) 
      if (m_rgcomp[i].pcomp->FDoIdle(cmgridlefPeriodic)) 
        fDidWork = TRUE; 
    if (fDidWork) 
      return TRUE; 
    } 
 
  // if any high priority idle tasks need to be done, 
  // do it, and return TRUE. 
  for (i=0; i<cCOMP; i++) 
    { 
    if (m_rgcomp[i].pcomp) 
      if (m_rgcomp[i].pcomp->FDoIdle(cmgridlefPriority)) 
        fDidWork = TRUE; 
    if (fDidWork) 
      return TRUE; 
    } 
 
  // if any lower priority idle tasks need to be done, 
  // do it, and return TRUE. 
  for (i=0; i<cCOMP; i++) 
    { 
    if (m_rgcomp[i].pcomp) 
      if (m_rgcomp[i].pcomp->FDoIdle(cmgridlefNonPeriodic)) 
        fDidWork = TRUE; 
    if (fDidWork) 
      return TRUE; 
    } 
 
  return FALSE; 
  } 
 
//--- EOF -------------------------------------------------------------------