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






3.33/5 (6投票s)
2005年3月17日
2分钟阅读

188677

1464
向 ATL COM EXE 服务器添加 MFC 支持。
引言
本文将介绍如何实现支持 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。 但是,这还不够;我们应该添加其他三个修改
- 在
CMyApp::InitInstance()
中添加AtlAxWinInit()
。这将允许我们正确创建 ATL 窗口。 见图 1。
- 在
CMyApp::InitInstance()
中添加_Module.StartMonitor()
。当客户端退出时,第 2 项和第 3 项允许 EXE 服务器正确退出。 见图 1。
- 在
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 对象:ATLWindowObject
和 MFCWindowObject
。
ATLWindowObject
有两个接口:CreateATLWindow
和 Update
。
MFCWindowObject
有两个接口:CreateMFCWindow
和 Update
。
当客户端父窗口需要刷新时,两个 Update()
接口都用于刷新窗口。 请参阅客户端实现部分。
我们还创建了两个窗口类:从 CWnd
派生的 CMFCWnd
和从 CWindow
派生的 CATLWnd
。 CMFCWnd
将由 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 对象:ATLWindowObject
和 MFCWindowObject
都提供了接口 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