首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

VC++ 監聽 ArcEngine COM 事件完整實作:以 IWorkspaceEditEvents 為例

     編輯:關於VC++

ArcEngine 眾多元件 (如 MapControl、Workspace) 透過 COM 事件 (Connection Point) 通知外部變更。本文示範如何在 VC++ (ATL/MFC) 中實作 IWorkspaceEditEvents 接口,並透過 AtlAdvise / AtlUnadvise 建立/移除事件連接,達到監聽編輯狀態 (開始/停止/復原/重做) 的目的。

一、定義事件接口 (來自 ArcEngine 型別庫)

struct __declspec(uuid("0B437962-89F9-11D4-8B5F-000000000000"))
IWorkspaceEditEvents : IUnknown {
  virtual HRESULT __stdcall OnStartEditing(VARIANT_BOOL withUndoRedo) = 0;
  virtual HRESULT __stdcall OnStopEditing(VARIANT_BOOL saveEdits) = 0;
  virtual HRESULT __stdcall OnStartEditOperation() = 0;
  virtual HRESULT __stdcall OnAbortEditOperation() = 0;
  virtual HRESULT __stdcall OnStopEditOperation() = 0;
  virtual HRESULT __stdcall OnUndoEditOperation() = 0;
  virtual HRESULT __stdcall OnRedoEditOperation() = 0;
};

二、實作事件接收類別 (Sink)

#include <atlbase.h>
#include <atlcom.h>

class CAEEditEvents :
  public CComObjectRootEx<CComSingleThreadModel>,
  public IWorkspaceEditEvents
{
public:
  CAEEditEvents() {}
  ~CAEEditEvents() {}

  BEGIN_COM_MAP(CAEEditEvents)
    COM_INTERFACE_ENTRY(IWorkspaceEditEvents)
  END_COM_MAP()

  // STDMETHOD 宏展開為 virtual HRESULT __stdcall
  STDMETHOD(OnStartEditing)(VARIANT_BOOL withUndoRedo) {
    ::MessageBox(NULL, _T("開始編輯了呢?"), _T("注意!!!"), MB_OK);
    return S_OK; // 建議回傳 S_OK 而非 E_NOTIMPL
  }
  STDMETHOD(OnStopEditing)(VARIANT_BOOL saveEdits) { return S_OK; }
  STDMETHOD(OnStartEditOperation)() { return S_OK; }
  STDMETHOD(OnAbortEditOperation)() { return S_OK; }
  STDMETHOD(OnStopEditOperation)() { return S_OK; }
  STDMETHOD(OnUndoEditOperation)() { return S_OK; }
  STDMETHOD(OnRedoEditOperation)() { return S_OK; }
};
關鍵點:繼承 CComObjectRootEx 提供參考計數與 QueryInterface 實作,BEGIN_COM_MAP 註冊介面項目,使 AtlAdvise 能正確查詢 IWorkspaceEditEvents。

三、建立與移除事件連線

成員變數宣告

CComObject<CAEEditEvents>* g_pEvents = nullptr;
DWORD m_dwCookie = 0; // 連線餅乾,用於解除建議

啟動監聽 (Advise)


// ipWorkspace 為 IWorkspaceEdit 介面指標 (支援 IConnectionPointContainer)
HRESULT hr = S_OK;
g_pEvents = new CComObject<CAEEditEvents>();
CComPtr<IUnknown> pUnk = g_pEvents; // 取得 IUnknown

// AtlAdvise 內部會 QI IConnectionPointContainer -> FindConnectionPoint -> Advise
hr = AtlAdvise(ipWorkspace, pUnk, __uuidof(IWorkspaceEditEvents), &m_dwCookie);
if (FAILED(hr)) {
  // 處理錯誤:介面不支援事件、Cookie 衝突等
  delete g_pEvents; g_pEvents = nullptr;
}

停止監聽 (Unadvise)


if (g_pEvents && m_dwCookie) {
  hr = AtlUnadvise(ipWorkspace, __uuidof(IWorkspaceEditEvents), m_dwCookie);
  if (SUCCEEDED(hr)) {
    m_dwCookie = 0;
    g_pEvents->Release(); // CComObject 參考計數歸零自動刪除
    g_pEvents = nullptr;
  }
}

四、完整生命週期管理建議

  1. 在應用程式初始化 (如 OnCreate、InitInstance) 時呼叫 Advise。
  2. 在視窗銷毀、文件關閉、應用程式退出時呼叫 Unadvise,避免事件觸發時存取已釋放物件。
  3. 事件處理函式中勿執行耗時操作 (如彈出 MessageBox、資料庫寫入),應將通知佇列至工作執行緒處理。
  4. 若監聽多種事件介面,每種介面需個別 Advise 並保存各自 dwCookie。

五、常見問題排查

現象可能原因解決
AtlAdvise 回傳 E_NOINTERFACEipWorkspace 不支援 IConnectionPointContainer確認物件實際型別、查詢支援介面
事件不觸發Cookie 遺失、Sink 物件已釋放、執行緒模型不符檢查 g_pEvents 生命週期、使用 CComMultiThreadModel
程式在 Unadvise 時崩潰重複 Unadvise、ipWorkspace 已無效加入旗標防重複、在有效範圍內呼叫
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved