本文将通过介绍自定义接口的实例,解释AO中接口的一般使用方法。这个实例是在VC 6.0下用ATL创建的一个COM。 COM的创建的主要步骤是: 1.实现esriSystemUI ICommand接口,使用户可以把这个组建模型加入ArcScene或其他工具栏上,在点击这个按钮的时候实现相关操作。 2.创建一个连接点实现ISceneGraphEvents接口事件,并改写fire事件的相关函数。我在Fire_BeforeDraw和Fire_AfterDraw中加了一些OpenGL的函数以实现雾化的效果。 3.回过头,我们具体实现ICommand接口。在ICommand的OnCreate函数中用ISceneHookHelper钩住IScene。在OnClick中我们通过ISceneHookHelper进一步获得ISceneViewer用来刷新场景。在刷新场景的前后分别调用Fire_BeforeDraw和Fire_AfterDraw来绘制雾化效果。这样ArcScene中的sink们就可以响应fire事件函数了。 主要流程是这样的:用户-->ArcScene-->ICommand接口-->自定义接口-->连接点-->fire事件-->OpenGL-->ArcScene。 工程名:Walkthrough1Cpp;自定义接口类:CZoomIn;代理接口事件类CProxyISceneGraphEvents 注意:在用ATL创建接口的时候,要在属性面板Interface中选择Custom而不是Dual,前者继承IUnkown,后者继承IDispatch。还要选择支持连接点。
// stdafx.h : include file for standard system include files,// or project specific include files that are used frequently,// but are changed infrequently
#if !defined(AFX_STDAFX_H__FF23B542_C904_4F39_8A97_C4DE3C45A0E6__INCLUDED_)#define AFX_STDAFX_H__FF23B542_C904_4F39_8A97_C4DE3C45A0E6__INCLUDED_
#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000
#define STRICT#ifndef _WIN32_WINNT#define _WIN32_WINNT 0x0400#endif#define _ATL_APARTMENT_THREADED
#include <atlbase.h>//You may derive a class from CComModule and use it if you want to override//something, but do not change the name of _Moduleextern CComModule _Module;#include <atlcom.h>
#pragma warning(push)#pragma warning(disable : 4146)#pragma warning(disable : 4192)#import "e:/Program Files/ArcGIS/com/esriSystem.olb" raw_interfaces_only raw_native_types no_namespace
named_guids exclude("OLE_COLOR", "OLE_HANDLE", "VARTYPE")#import "e:/Program Files/ArcGIS/com/esriSystemUI.olb" raw_interfaces_only raw_native_types no_namespace
named_guids#import "e:/Program Files/ArcGIS/com/esriGeometry.olb" raw_interfaces_only raw_native_types no_namespace
named_guids#import "e:/Program Files/ArcGIS/com/esriDisplay.olb" raw_interfaces_only raw_native_types no_namespace
named_guids#import "e:/Program Files/ArcGIS/com/esriGeoDatabase.olb" raw_interfaces_only raw_native_types
no_namespace named_guids#import "e:/Program Files/ArcGIS/com/esriCarto.olb" raw_interfaces_only raw_native_types no_namespace
named_guids#import "e:/Program Files/ArcGIS/com/esriControlCommands.olb" raw_interfaces_only raw_native_types
no_namespace named_guids#import "e:/Program Files/ArcGIS/com/esriFramework.olb" raw_interfaces_only raw_native_types no_namespace
named_guids#import "e:/Program Files/ArcGIS/com/esri3DAnalyst.olb" raw_interfaces_only raw_native_types no_namespace
named_guids
#pragma warning(pop)
#include "gl/gl.h"#include "gl/glu.h"#include "gl/glaux.h"#include <GL/glut.h>//{{AFX_INSERT_LOCATION}}// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_STDAFX_H__FF23B542_C904_4F39_8A97_C4DE3C45A0E6__INCLUDED)
// ZoomIn.h : Declaration of the CZoomIn
#ifndef __ZOOMIN_H_#define __ZOOMIN_H_
#include "resource.h" // main symbols#include "esri3DAnalystCP.h"//#import "D:/Program Files/ArcGIS/com/esriSystemUI.olb" raw_interfaces_only, raw_native_types,
no_namespace, named_guids
/// CZoomInclass ATL_NO_VTABLE CZoomIn : public CComObjectRootEx<CComSingleThreadModel>, public CComCoClass<CZoomIn, &CLSID_ZoomIn>, public IZoomIn, public ICommand, public CProxyISceneGraphEvents< CZoomIn >, public IConnectionPointContainerImpl<CZoomIn>{public: CZoomIn() { m_hBitmap = ::LoadBitmap(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDB_ZOOMIN)); }
~CZoomIn() { DeleteObject(m_hBitmap); } IHookHelperPtr m_ipHookHelper; ISceneHookHelperPtr m_ipSceneHookHelper;DECLARE_REGISTRY_RESOURCEID(IDR_ZOOMIN)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CZoomIn) COM_INTERFACE_ENTRY(IZoomIn) COM_INTERFACE_ENTRY(ICommand) COM_INTERFACE_ENTRY_IMPL(IConnectionPointContainer)END_COM_MAP()
// IZoomInprivate: HBITMAP m_hBitmap;public:// ICommand STDMETHOD(get_Enabled)(VARIANT_BOOL * Enabled); STDMETHOD(get_Checked)(VARIANT_BOOL * Checked); STDMETHOD(get_Name)(BSTR * Name); STDMETHOD(get_Caption)(BSTR * Caption); STDMETHOD(get_Tooltip)(BSTR * Tooltip); STDMETHOD(get_Message)(BSTR * Message); STDMETHOD(get_HelpFile)(BSTR * HelpFile); STDMETHOD(get_HelpContextID)(LONG * helpID); STDMETHOD(get_Bitmap)(OLE_HANDLE * Bitmap); STDMETHOD(get_Category)(BSTR * categoryName); STDMETHOD(OnCreate)(IDispatch * hook); STDMETHOD(OnClick)();public :
BEGIN_CONNECTION_POINT_MAP(CZoomIn) CONNECTION_POINT_ENTRY(IID_ISceneGraphEvents)END_CONNECTION_POINT_MAP()
};
#endif //__ZOOMIN_H_
// ZoomIn.cpp : Implementation of CZoomIn#include "stdafx.h"#include "Walkthrough1Cpp.h"#include "ZoomIn.h"
/// CZoomInSTDMETHODIMP CZoomIn::get_Enabled(VARIANT_BOOL * Enabled){ if (Enabled == NULL) return E_POINTER; *Enabled = VARIANT_TRUE; // Enable the tool always
return S_OK;
}
STDMETHODIMP CZoomIn::get_Checked(VARIANT_BOOL * Checked){ if (Checked == NULL) return E_POINTER; return E_NOTIMPL;}
STDMETHODIMP CZoomIn::get_Name(BSTR * Name){if (Name == NULL) return E_POINTER;
*Name = ::SysAllocString(L"ZoomIn x 0.5 Cpp"); return S_OK;
}
STDMETHODIMP CZoomIn::get_Caption(BSTR * Caption){ if (Caption == NULL) return E_POINTER;
*Caption = ::SysAllocString(L"ZoomIn x 0.5 Cpp"); return S_OK;
}
STDMETHODIMP CZoomIn::get_Tooltip(BSTR * Tooltip){ if (Tooltip == NULL) return E_POINTER; return E_NOTIMPL;}
STDMETHODIMP CZoomIn::get_Message(BSTR * Message){ if (Message == NULL) return E_POINTER; return E_NOTIMPL;}
STDMETHODIMP CZoomIn::get_HelpFile(BSTR * HelpFile){ if (HelpFile == NULL) return E_POINTER; return E_NOTIMPL;}
STDMETHODIMP CZoomIn::get_HelpContextID(LONG * helpID){ if (helpID == NULL) return E_POINTER; return E_NOTIMPL;}
STDMETHODIMP CZoomIn::get_Bitmap(OLE_HANDLE * Bitmap){ if (Bitmap == NULL) return E_POINTER;
*Bitmap = (OLE_HANDLE) m_hBitmap;
return S_OK;}
STDMETHODIMP CZoomIn::get_Category(BSTR * categoryName){ if (categoryName == NULL) return E_POINTER;
*categoryName = ::SysAllocString(L"Developer Samples"); return S_OK;
}
STDMETHODIMP CZoomIn::OnCreate(IDispatch * hook){ m_ipSceneHookHelper.CreateInstance(CLSID_SceneHookHelper); HRESULT hr = m_ipSceneHookHelper->putref_Hook(hook); return hr;
}
STDMETHODIMP CZoomIn::OnClick(){ // HRESULT checking omitted for clarity IScenePtr ipScene; m_ipSceneHookHelper->get_Scene(&ipScene); ISceneGraphPtr ipSceneGraph; ipScene->get_SceneGraph(&ipSceneGraph);
ISceneViewer * pViewer; ipSceneGraph->get_ActiveViewer(&pViewer); Fire_BeforeDraw(pViewer, NULL); ipSceneGraph->RefreshViewers(); Fire_AfterDraw(pViewer);
return S_OK;
}
// Walkthrough1Cpp.idl : IDL source for Walkthrough1Cpp.dll//
// This file will be processed by the MIDL tool to// produce the type library (Walkthrough1Cpp.tlb) and marshalling code.
import "oaidl.idl";import "ocidl.idl"; [ object, uuid(5CA669DE-0DFE-4C49-8546-B8AE24A629D5), helpstring("IZoomIn Interface"), pointer_default(unique) ] interface IZoomIn : IUnknown { };
[ uuid(5C0841D7-80E7-4CDB-AFCD-5D77B23B879E), version(1.0), helpstring("Walkthrough1Cpp 1.0 Type Library")]library WALKTHROUGH1CPPLib{ importlib("stdole32.tlb"); importlib("stdole2.tlb"); importlib("e:/Program Files/ArcGIS/com/esriSystemUI.olb"); [ uuid(C9265E95-7317-4CB2-9ACC-E3EA5C9CA550), helpstring("ZoomIn Class") ] coclass ZoomIn { [default] interface IUnknown; interface IZoomIn; interface ICommand;
// [default] interface IZoomIn; };};
//esri3DAnalystCP.h#ifndef _ESRI3DANALYSTCP_H_#define _ESRI3DANALYSTCP_H_
#import "E:/Program Files/ArcGIS/com/esri3DAnalyst.olb" raw_interfaces_only, raw_native_types,
no_namespace, named_guids //"Import typelib"template <class T>class CProxyISceneGraphEvents : public IConnectionPointImpl<T, &IID_ISceneGraphEvents,
CComDynamicUnkArray>{ //Warning this class may be recreated by the wizard.public: HRESULT Fire_ActiveViewerChanged(ISceneViewer * pViewer) { HRESULT ret; T* pT = static_cast<T*>(this); int nConnectionIndex; int nConnections = m_vec.GetSize(); for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++) { pT->Lock(); CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex); pT->Unlock(); ISceneGraphEvents* pISceneGraphEvents = reinterpret_cast<ISceneGraphEvents*>
(sp.p); if (pISceneGraphEvents != NULL) ret = pISceneGraphEvents->ActiveViewerChanged(pViewer); } return ret; } HRESULT Fire_ViewerAdded(ISceneViewer * pViewer) { HRESULT ret; T* pT = static_cast<T*>(this); int nConnectionIndex; int nConnections = m_vec.GetSize(); for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++) { pT->Lock(); CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex); pT->Unlock(); ISceneGraphEvents* pISceneGraphEvents = reinterpret_cast<ISceneGraphEvents*>
(sp.p); if (pISceneGraphEvents != NULL) ret = pISceneGraphEvents->ViewerAdded(pViewer); } return ret; } HRESULT Fire_ViewerRemoved(ISceneViewer * pViewer) { HRESULT ret; T* pT = static_cast<T*>(this); int nConnectionIndex; int nConnections = m_vec.GetSize(); for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++) { pT->Lock(); CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex); pT->Unlock(); ISceneGraphEvents* pISceneGraphEvents = reinterpret_cast<ISceneGraphEvents*>
(sp.p); if (pISceneGraphEvents != NULL) ret = pISceneGraphEvents->ViewerRemoved(pViewer); } return ret; } HRESULT Fire_InteractionStopped() { HRESULT ret; T* pT = static_cast<T*>(this); int nConnectionIndex; int nConnections = m_vec.GetSize(); for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++) { pT->Lock(); CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex); pT->Unlock(); ISceneGraphEvents* pISceneGraphEvents = reinterpret_cast<ISceneGraphEvents*>
(sp.p); if (pISceneGraphEvents != NULL) ret = pISceneGraphEvents->InteractionStopped(); } return ret; } HRESULT Fire_RecordingStarted(BSTR Name) { HRESULT ret; T* pT = static_cast<T*>(this); int nConnectionIndex; int nConnections = m_vec.GetSize(); for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++) { pT->Lock(); CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex); pT->Unlock(); ISceneGraphEvents* pISceneGraphEvents = reinterpret_cast<ISceneGraphEvents*>
(sp.p); if (pISceneGraphEvents != NULL) ret = pISceneGraphEvents->RecordingStarted(Name); } return ret; } HRESULT Fire_RecordingStopped() { HRESULT ret; T* pT = static_cast<T*>(this); int nConnectionIndex; int nConnections = m_vec.GetSize(); for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++) { pT->Lock(); CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex); pT->Unlock(); ISceneGraphEvents* pISceneGraphEvents = reinterpret_cast<ISceneGraphEvents*>
(sp.p); if (pISceneGraphEvents != NULL) ret = pISceneGraphEvents->RecordingStopped(); } return ret; } HRESULT Fire_BeforeDraw(ISceneViewer * pViewer, VARIANT_BOOL * pbHandled) { ISceneGraphPtr ipSceneGraph; pViewer->get_SceneGraph(&ipSceneGraph);
IEnvelopePtr pExtent; ipSceneGraph->get_Extent(&pExtent); ICameraPtr pCamera; pViewer->get_Camera(&pCamera);
double Near; double Far; double Angle; double m_aspect;
pCamera->QueryViewingPlatformMBB(pExtent, &Near, &Far, &Angle, &m_aspect);
glEnable(GL_FOG); glFogf(GL_FOG_MODE, GL_LINEAR); glFogf(GL_FOG_START, Near); glFogf(GL_FOG_END, Far);
float red = 0.8; float green = 0.4; float blue = 0.4; GLfloat FogColor[4] = {red, green, blue, 1}; glFogfv(GL_FOG_COLOR, FogColor);
HRESULT ret; T* pT = static_cast<T*>(this); int nConnectionIndex; int nConnections = m_vec.GetSize(); for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++) { pT->Lock(); CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex); pT->Unlock(); ISceneGraphEvents* pISceneGraphEvents = reinterpret_cast<ISceneGraphEvents*>
(sp.p); if (pISceneGraphEvents != NULL) ret = pISceneGraphEvents->BeforeDraw(pViewer, pbHandled); } return ret; } HRESULT Fire_AfterDraw(ISceneViewer * pViewer) { glDisable(GL_FOG);
HRESULT ret; T* pT = static_cast<T*>(this); int nConnectionIndex; int nConnections = m_vec.GetSize(); for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++) { pT->Lock(); CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex); pT->Unlock(); ISceneGraphEvents* pISceneGraphEvents = reinterpret_cast<ISceneGraphEvents*>
(sp.p); if (pISceneGraphEvents != NULL) ret = pISceneGraphEvents->AfterDraw(pViewer); } return ret; }};#endif
处理前
处理后