65.9K
CodeProject 正在变化。 阅读更多。
Home

带有 MFC 支持的 ATL COM EXE 服务器

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.33/5 (6投票s)

2005年3月17日

2分钟阅读

viewsIcon

188677

downloadIcon

1464

向 ATL COM EXE 服务器添加 MFC 支持。

Sample image

引言

本文将介绍如何实现支持 MFC 的 ATL COM EXE 服务器。 作为一个例子,我们创建一个 ATL COM EXE 服务器,它可以在客户端的父窗口中创建一个 MFC 子窗口和一个 ATL 子窗口。

背景

在最近的一个项目中,我们尝试向 ATL EXE 服务器添加 MFC 支持。 我们希望在我们的服务器中使用 CWnd 派生类创建 MFC 窗口,并使用 CWindow 创建 ATL 窗口。 MSDN 上有一篇关于此的文章:“Q 173974:HOWTO: Add MFC Support to an ATL Project”。 这是我们创建示例应用程序的主要参考。

使用代码

该代码包含两个 Microsoft Visual C++ 6.0 项目

  • ATLMFCCOMClient - 客户端实现。 这是一个简单的 SDI 应用程序。
  • ATLMFCCOMServer - 服务器端实现。

这些项目都支持非 Unicode 和 Unicode 编译。

服务器端实现

这个项目首先使用 ATL COM 向导创建,然后根据 MSDN 的文章 Q 173974 进行修改以支持 MFC。 但是,这还不够;我们应该添加其他三个修改

  1. CMyApp::InitInstance() 中添加 AtlAxWinInit()

    这将允许我们正确创建 ATL 窗口。 见图 1。

  2. CMyApp::InitInstance() 中添加 _Module.StartMonitor()

    当客户端退出时,第 2 项和第 3 项允许 EXE 服务器正确退出。 见图 1。

  3. CExeModule::MonitorShutdown() 中添加 theApp.PostThreadMessage( WM_QUIT, 0, 0)

    见图 2。

BOOL CMyApp::InitInstance()
     {
        // Initialize OLE libraries
        if (!AfxOleInit())
        {
           AfxMessageBox(_T("OLE Initialization Failed!"));
           return FALSE;
        }
       AtlAxWinInit();

        // Initialize the ATL Module
        _Module.Init(ObjectMap,m_hInstance);
     #ifdef _AFXDLL
        Enable3dControls(); // Call this when using MFC in a shared DLL
     #else
        Enable3dControlsStatic(); // Call this when linking
                                  // to MFC statically
     #endif
        // Update the System Registry
        COleObjectFactory::UpdateRegistryAll(); // MFC Classes
        VERIFY(SUCCEEDED(_Module.RegisterServer(TRUE))); // ATL Classes
        // Create the dialog box or other stuff here
        // Register OLE Class Factories
        // MFC ones are for multiple as specified
        // by the IMPLEMENT_OLECREATE() macro
        COleObjectFactory::RegisterAll();
        // ATL ones specifically register with REGCLS_MULTIPLEUSE
        VERIFY(SUCCEEDED(_Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER, 
             REGCLS_MULTIPLEUSE)));

        _Module.StartMonitor();
        // Parse the command line to see if launched as OLE server
        if (RunEmbedded() || RunAutomated())
        {
           // Application was run with /Embedding or /Automation.
           // Don't show the main window in this case.
           return TRUE;
        }

        return FALSE; // Nothing to do, so exit.
     }

图 1

//Monitors the shutdown event
void CExeModule::MonitorShutdown()
{
    while (1)
    {
        WaitForSingleObject(hEventShutdown, INFINITE);
        DWORD dwWait=0;
        do
        {
            bActivity = false;
            dwWait = WaitForSingleObject(hEventShutdown, dwTimeOut);
        } while (dwWait == WAIT_OBJECT_0);
        // timed out
        if (!bActivity && m_nLockCnt == 0) // if no activity let's really bail
        {
#if _WIN32_WINNT >= 0x0400 & defined(_ATL_FREE_THREADED)
            CoSuspendClassObjects();
            if (!bActivity && m_nLockCnt == 0)
#endif
                break;
        }
    }
    CloseHandle(hEventShutdown);
    PostThreadMessage(dwThreadID, WM_QUIT, 0, 0);
    theApp.PostThreadMessage( WM_QUIT, 0, 0);

}

图 2

我们创建了两个 COM 对象:ATLWindowObjectMFCWindowObject

ATLWindowObject 有两个接口:CreateATLWindowUpdate

MFCWindowObject 有两个接口:CreateMFCWindowUpdate

当客户端父窗口需要刷新时,两个 Update() 接口都用于刷新窗口。 请参阅客户端实现部分。

我们还创建了两个窗口类:从 CWnd 派生的 CMFCWnd 和从 CWindow 派生的 CATLWndCMFCWnd 将由 MFCWindowObject 创建,而 CATLWnd 将由 ATLWindowObject 创建。

CMFCWnd 很容易,但 CATLWnd 需要手动添加消息映射,见图 3。

class CATLWnd : public CWindowImpl<CATLWND, CWindow>
{
public:
    DECLARE_WND_CLASS(_T("ATL Window Class"))
    CATLWnd() { m_hbrBkgnd = CreateSolidBrush(RGB(0,0,255)); }
    ~CATLWnd() { DeleteObject ( m_hbrBkgnd ); }
 
    BEGIN_MSG_MAP(CATLWnd)
        MESSAGE_HANDLER(WM_PAINT, OnPaint)
    END_MSG_MAP()

    LRESULT OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
    {
        RECT rcClient;
        PAINTSTRUCT ps;
        BeginPaint(&ps);
        HDC  dc = GetDC();
        GetClientRect ( &rcClient );
        FillRect ( dc, &rcClient, m_hbrBkgnd );
        TextOut(dc,2,10,_T("ATL Window"),10);
        EndPaint(&ps);
        return 0;    
    }
protected:
    HBRUSH m_hbrBkgnd;
};

图 3

客户端实现

当用户选择“Create MFC Window”菜单时,将调用函数 OnMfcWindow。 首先实例化 MFCWindowObject,然后调用其接口 CreateMFCWindow 以创建一个 MFC 窗口。

同样地,当用户选择“Create ATLWindow”菜单时,将调用函数 OnATLWindow。 首先实例化 ATLWindowObject,然后调用其接口 CreateATLWindow 以创建一个 ATL 窗口。 见图 4。

请注意,两个窗口都是 CATLMFCCOMClientView 的子窗口

void CATLMFCCOMClientView::OnMfcWindow() 
{
    if(m_pMFCWindowObject) return;
    HRESULT hResult = S_OK;          
    hResult = CoCreateInstance(CLSID_MFCWindowObject,
         NULL,CLSCTX_LOCAL_SERVER,IID_IMFCWindowObject,
         (LPVOID*)&m_pMFCWindowObject);
    m_pMFCWindowObject->CreateMFCWindow((long)m_hWnd);
}

void CATLMFCCOMClientView::OnAtlWindow() 
{
    if(m_pATLWindowObject) return;
    HRESULT hResult = S_OK;          
    hResult = CoCreateInstance(CLSID_ATLWindowObject,
        NULL,CLSCTX_LOCAL_SERVER,IID_IATLWindowObject,
        (LPVOID*)&m_pATLWindowObject);
    m_pATLWindowObject->CreateATLWindow((long)m_hWnd);
}

图 4

在服务器端实现部分,我们提到两个 COM 对象:ATLWindowObjectMFCWindowObject 都提供了接口 Update。 此接口在 CATLMFCCOMClientView::OnDraw 中用于避免窗口刷新问题,见图 5。

void CATLMFCCOMClientView::OnDraw(CDC* pDC)
{
    CATLMFCCOMClientDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    if(m_pMFCWindowObject)
        m_pMFCWindowObject->Update();
    if(m_pATLWindowObject)
        m_pATLWindowObject->Update();
}

图 5

© . All rights reserved.