本例要實現的是如何創建定製的可停靠窗口(Dockable Window),目前用C# AddIn寫這個很方便,但是市面上用C++,MFC寫停靠欄的就很少了。本例爲方便大家學習而寫。
其實步驟很簡單。
1、實現IdockableWindowDef接口(參見實例);
用戶通過在類模塊中實現IDockableWindowDef接口來創建定製的可停靠窗口(Dockable Window)。IDockableWindowDef接口包括Caption、ChildHWND,UserData及Name等屬性和OnCreate、OnDestroy事件。
·ChildHWND屬性表示可停靠窗口包含的Window的Handle。
·OnCreate事件的參數hook傳入ArcGIS的Application實例。
下面是一個實現IDockableWindowDef 的類,主要看get_ChildHWND,這裏實現了窗口句柄Hwnd的返回。
lass ATL_NO_VTABLE CCArcMatrixOneChkResDocView :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CCArcMatrixOneChkResDocView, &CLSID_CArcMatrixOneChkResDocView>,
public ICArcMatrixOneChkResDocView,
public IDockableWindowDef
{
public:
CCArcMatrixOneChkResDocView()
{
}
DECLARE_REGISTRY_RESOURCEID(IDR_CARCMATRIXONECHKRESDOCVIEW)
DECLARE_NOT_AGGREGATABLE(CCArcMatrixOneChkResDocView)
BEGIN_COM_MAP(CCArcMatrixOneChkResDocView)
COM_INTERFACE_ENTRY(ICArcMatrixOneChkResDocView)
COM_INTERFACE_ENTRY(IDockableWindowDef)
END_COM_MAP()
DECLARE_PROTECT_FINAL_CONSTRUCT()
HRESULT FinalConstruct()
{
m_pHookllelper = NULL;
m_pApplication = NULL;
m_DlgChkResultView = NULL;
return S_OK;
}
void FinalRelease()
{
m_pHookllelper = NULL;
m_pApplication = NULL;
}
public:
IHookHelperPtr m_pHookllelper;
IApplicationPtr m_pApplication;
CDlgChkResultView* m_DlgChkResultView;
// IDockableWindowDef Methods
public:
STDMETHOD(OnCreate)(LPDISPATCH hook)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
if (m_pHookllelper != NULL)
{
m_pHookllelper->putref_Hook(NULL);
m_pHookllelper = NULL;
}
m_pHookllelper.CreateInstance(CLSID_HookHelper);
if (!m_pHookllelper) return E_POINTER;
HRESULT hr = m_pHookllelper->putref_Hook(hook);
if (FAILED(hr))
{
return S_FALSE;
}
GpHookllelper = m_pHookllelper;
if (m_pApplication != NULL)
{
m_pApplication = NULL;
}
ATLASSERT(hook!=NULL);
m_pApplication = hook;
OLE_HANDLE oleHandle;
AfxOleInit();
m_pApplication->get_hWnd(&oleHandle);
CWnd *pwnd = new CWnd();
pwnd->Attach((HWND)oleHandle);
return S_OK;
}
STDMETHOD(get_ChildHWND)(OLE_HANDLE * hWnd)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
if (hWnd == NULL) return E_POINTER;
if (m_DlgChkResultView!=NULL && m_DlgChkResultView->m_hWnd != NULL && ::IsWindow(m_DlgChkResultView->m_hWnd) && ::IsWindowVisible(m_DlgChkResultView->m_hWnd))
{
m_DlgChkResultView->ShowWindow(SW_HIDE);
}
else
{
if (m_DlgChkResultView == NULL)
{
m_DlgChkResultView = new CDlgChkResultView();
m_DlgChkResultView->Create(IDD_DIALOG_RESULTVIEW);
}
m_DlgChkResultView->ShowWindow(SW_HIDE);
}
if (m_DlgChkResultView != NULL)
{
*hWnd = (OLE_HANDLE ) m_DlgChkResultView->GetSafeHwnd();
}
else
{
*hWnd = NULL;
}
return S_OK;
}
STDMETHOD(get_Name)(BSTR * Name)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
if (Name == NULL)
{
return E_NOTIMPL;
}
CString strName;
strName.LoadStringW(IDS_CHECKRESULT);
*Name = strName.AllocSysString();
return S_OK;
}
STDMETHOD(get_Caption)(BSTR * Caption)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
if (Caption == NULL)
{
return E_NOTIMPL;
}
CString strCaption;
strCaption.LoadStringW(IDS_CHECKRESULT);
*Caption = strCaption.AllocSysString();
return S_OK;
}
STDMETHOD(OnDestroy)()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
m_pApplication = NULL;
m_pHookllelper = NULL;
return S_OK;
}
STDMETHOD(get_UserData)(VARIANT * data)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
return S_OK;
}
};
2、編譯成DLL;
3、調用windows目錄下system32子目錄下的regsvr32.exe用下面的形式註冊編譯好的DLL:
win目錄\system32\regsvr32.exe <路徑>\<文件名>.dll
4、運行<arcmap目錄>\arcexe81\Bin\categories.exe,在打開的Component Catregory Manager中找到ESRI Mx Dockable Window,點擊Add Object…按鈕將上面註冊的DLL文件加入,並選中實現IdockableWindowDef接口的類名即可。
5、實現一個Command命令,獲取DocWindow 並且顯示。OnClick時顯示停靠欄。
class ATL_NO_VTABLE CCArcMatrixOneCheckResultCommand :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CCArcMatrixOneCheckResultCommand, &CLSID_CArcMatrixOneCheckResultCommand>,
public IDispatchImpl<ICArcMatrixOneCheckResultCommand, &IID_ICArcMatrixOneCheckResultCommand, &LIBID_ArcMatrixOneLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,
public esriICommand
{
public:
CCArcMatrixOneCheckResultCommand()
{
}
DECLARE_REGISTRY_RESOURCEID(IDR_CARCMATRIXONECHECKRESULTCOMMAND)
DECLARE_NOT_AGGREGATABLE(CCArcMatrixOneCheckResultCommand)
BEGIN_COM_MAP(CCArcMatrixOneCheckResultCommand)
COM_INTERFACE_ENTRY(ICArcMatrixOneCheckResultCommand)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(esriICommand)
END_COM_MAP()
DECLARE_PROTECT_FINAL_CONSTRUCT()
HRESULT FinalConstruct()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
m_hBitmap= ::LoadBitmap(_AtlBaseModule.GetResourceInstance(),MAKEINTRESOURCE(IDB_BITMAP_CHECKRESULTVIEW));
m_hCursor = (HCURSOR)::LoadCursor(NULL,IDC_CROSS);
m_pDispath = NULL;
m_pApplication = NULL;
m_pDocWnd = NULL;
m_pHookllelper = NULL;
m_bChecked = VARIANT_FALSE;
m_DlgChkResultView = NULL;
return S_OK;
}
void FinalRelease()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
::DeleteObject(m_hBitmap);
::DestroyCursor(m_hCursor);
m_pDispath = NULL;
m_pApplication = NULL;
m_pDocWnd = NULL;
m_pHookllelper = NULL;
m_DlgChkResultView = NULL;
}
public:
HBITMAP m_hBitmap;
HCURSOR m_hCursor;
LPDISPATCH m_pDispath;
IHookHelperPtr m_pHookllelper;
IApplicationPtr m_pApplication;
IDockableWindowPtr m_pDocWnd;
VARIANT_BOOL m_bChecked;
CDlgChkResultView *m_DlgChkResultView;
// ICommand Methods
public:
STDMETHOD(get_Enabled)(VARIANT_BOOL * Enabled)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
if (Enabled == NULL)
{
return E_POINTER;
}
*Enabled = VARIANT_TRUE;
return S_OK;
}
STDMETHOD(get_Checked)(VARIANT_BOOL * Checked)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
if (Checked == NULL || m_pDocWnd == NULL )
{
return S_FALSE;
}
*Checked = m_bChecked;
return S_OK;
}
STDMETHOD(get_Name)(BSTR * Name)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
if (Name == NULL)
{
return E_POINTER;
}
CString strName ;
strName.LoadStringW(IDS_CHECKRESULT);
*Name = SysAllocString(strName);
return S_OK;
}
STDMETHOD(get_Caption)(BSTR * Caption)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
if (Caption == NULL)
{
return E_POINTER;
}
CString strCaption ;
strCaption.LoadStringW(IDS_CHECKRESULT);
*Caption = SysAllocString(strCaption);
return S_OK;
}
STDMETHOD(get_Tooltip)(BSTR * Tooltip)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
if (Tooltip == NULL)
{
return E_POINTER;
}
CString strTooltip ;
strTooltip.LoadStringW(IDS_CHECKRESULT);
*Tooltip = SysAllocString(strTooltip);
return S_OK;
}
STDMETHOD(get_Message)(BSTR * Message)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
if (Message == NULL)
{
return E_POINTER;
}
CString strMessage ;
strMessage.LoadStringW(IDS_CHECKRESULT);
*Message = SysAllocString(strMessage);
return S_OK;
}
STDMETHOD(get_HelpFile)(BSTR * HelpFile)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
return S_OK;
}
STDMETHOD(get_HelpContextID)(long * helpID)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
return S_OK;
}
STDMETHOD(get_Bitmap)(OLE_HANDLE * Bitmap)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
if (Bitmap == NULL)
return E_POINTER;
*Bitmap = (OLE_HANDLE)m_hBitmap;
return S_OK;
}
STDMETHOD(get_Category)(BSTR * categoryName)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
if (categoryName == NULL)
{
return E_POINTER;
}
CString strMessage = StrFromResID(IDS_CATEGORY);
*categoryName = ::SysAllocString(L"CustomCategory");//strMessage.AllocSysString();
return S_OK;
}
STDMETHOD(OnCreate)(LPDISPATCH Hook)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
m_pDispath = Hook;
m_pApplication = Hook;
if (m_pHookllelper != NULL)
{
m_pHookllelper->putref_Hook(NULL);
m_pHookllelper = NULL;
}
m_pHookllelper.CreateInstance(CLSID_HookHelper);
if (!m_pHookllelper) return E_POINTER;
HRESULT hr = m_pHookllelper->putref_Hook(Hook);
if (FAILED(hr))
{
return S_FALSE;
}
GpHookllelper = m_pHookllelper;
return E_NOTIMPL;
}
STDMETHOD(OnClick)()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
HRESULT hr = S_OK;
IDockableWindowManagerPtr ipDockableWindowManager = NULL;
ipDockableWindowManager = m_pApplication;
if (!ipDockableWindowManager)
{
return S_FALSE;
}
IUIDPtr ipUID(CLSID_UID);
CComBSTR bsVal;
//9CB364C5,0xF1A2,0x455E,0x9D,0xE3,0x86,0x4A,0x26,0x22,0xCB,0xCE 本工程中實現的 uuid CCArcMatrixOneCheckResultDocView
ipUID->put_Value(CComVariant("{9CB364C5-F1A2-455E-9DE3-864A2622CBCE}"));
hr = ipDockableWindowManager->GetDockableWindow(ipUID,&m_pDocWnd);
if (FAILED(hr) || m_pDocWnd == NULL)
{
MessageBox(NULL,_T("getDockWindow failed"),_T("Note"),MB_OK);
return S_FALSE;
}
VARIANT_BOOL varVisual = VARIANT_FALSE;
if (m_pDocWnd)
{
hr = m_pDocWnd->IsVisible(&varVisual);
if (varVisual == VARIANT_FALSE)
{
m_pDocWnd->Show(VARIANT_TRUE);
IWindowPositionPtr ipWindowPosition = NULL;
ipWindowPosition=m_pDocWnd;
long width = 200 ;
long height = 100;
if (m_pDocWnd)
{
hr=m_pDocWnd->Show(VARIANT_TRUE);
/*
esriDockHide = 0,
esriDockShow = 1,
esriDockLeft = 2,
esriDockRight = 4,
esriDockTop = 8,
esriDockBottom = 16,
esriDockFloat = 32,
esriDockToggle = 64,
esriDockTabbed = 128,
esriDockUnPinned = 256
*/
hr=m_pDocWnd->Dock(esriDockTabbed);
}
}
else
{
m_pDocWnd->Show(VARIANT_FALSE);
}
m_pDocWnd->IsVisible(&varVisual);
}
else
{
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
varVisual = VARIANT_FALSE;
return S_FALSE;
}
m_bChecked = varVisual ;
return S_OK;
}
};
6、打開arcMap註冊命令,測試。