例子:编写一个CyberArticle用于编辑文章的普通插件 (Visual C++)在这里,我们继续使用例子:编写一个CyberArticle普通插件
(Visual C++)里面的工程,添加一个新的插件。
增加COM组件同样,我们需要增加一个新的COM组件,命名为:CANormalEditPlugin1
找到并修改CANormalEditPlugin1.h文件这是COM组件class定义文件。斜体部分为增加的内容:
// CANormalEditPlugin1.h : Declaration of the CCANormalEditPlugin1 #pragma once #include "resource.h" // main symbols #include "MyCANormalPlugin1.h" /* * 包含必要的头文件。如果CyberArticle没有安装在C:\Program Files\Wizissoft\CyberArticle\,请修改下面相应的包含路径。 */ #include <commctrl.h> #include <exdisp.h> #include "C:/Program Files/Wizissoft/CyberArticle/developers/interface/include/CyberArticlePluginInterface.h" #if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA) #error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms." #endif // CCANormalEditPlugin1 class ATL_NO_VTABLE CCANormalEditPlugin1 : public CComObjectRootEx<CComSingleThreadModel>, public CComCoClass<CCANormalEditPlugin1, &CLSID_CANormalEditPlugin1>, public IDispatchImpl<ICANormalEditPlugin1, &IID_ICANormalEditPlugin1, &LIBID_MyCANormalPlugin1Lib, /*wMajor =*/ 1, /*wMinor =*/ 0> , public ICAPlugin , public ICAEditPlugin { public: CCANormalEditPlugin1() { } DECLARE_REGISTRY_RESOURCEID(IDR_CANORMALEDITPLUGIN1) BEGIN_COM_MAP(CCANormalEditPlugin1) COM_INTERFACE_ENTRY(ICANormalEditPlugin1) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY_IID(IID_ICAPlugin, ICAPlugin) // ICAPlugin COM_INTERFACE_ENTRY_IID(IID_ICAEditPlugin, ICAEditPlugin) // ICAEditPlugin END_COM_MAP() DECLARE_PROTECT_FINAL_CONSTRUCT() HRESULT FinalConstruct() { return S_OK; } void FinalRelease() { } public: private: CComPtr<ICAApp> m_spApp; CComPtr<IWebBrowser2> m_spWebBrowser; public: //ICAPlugin virtual HRESULT STDMETHODCALLTYPE Init(ICAApp* pApp); virtual HRESULT STDMETHODCALLTYPE Exit(); virtual HRESULT STDMETHODCALLTYPE get_Flags(long* pnFlags); virtual HRESULT STDMETHODCALLTYPE put_Flags(long nFlags); virtual HRESULT STDMETHODCALLTYPE get_MenuItemText(BSTR* pbstrDescription); virtual HRESULT STDMETHODCALLTYPE get_MenuItemStatus(long* pnStatus); virtual HRESULT STDMETHODCALLTYPE get_MenuItemOrder(long* pnMenuItemOrder); virtual HRESULT STDMETHODCALLTYPE Execute(); //ICAEditPlugin virtual HRESULT STDMETHODCALLTYPE put_WebBrowser(IWebBrowser2* pWebBrowser); virtual HRESULT STDMETHODCALLTYPE put_Book(ICABook* pBook) { return S_OK; } //不关心正在编辑的文章所在的书籍 virtual HRESULT STDMETHODCALLTYPE put_Node(ICANode* pNode) { return S_OK; } //不关心正在编辑的文章 public: }; OBJECT_ENTRY_AUTO(__uuidof(CANormalEditPlugin1), CCANormalEditPlugin1) 找到并修改CANormalEditPlugin1.cpp文件这是COM组件实现文件。(斜体部分为增加的内容)
// CANormalEditPlugin1.cpp : Implementation of CCANormalEditPlugin1 #include "stdafx.h" #include "CANormalEditPlugin1.h" #include <atlstr.h> #include <mshtml.h> #include <mshtmhst.h> #include <mshtmcid.h> // CCANormalEditPlugin1 HRESULT STDMETHODCALLTYPE CCANormalEditPlugin1::Init(ICAApp* pApp) { m_spApp = pApp; ATLASSERT(m_spApp); // return S_OK; } HRESULT STDMETHODCALLTYPE CCANormalEditPlugin1::Exit() { m_spApp = NULL; m_spWebBrowser = NULL; // return S_OK; } HRESULT STDMETHODCALLTYPE CCANormalEditPlugin1::get_Flags(long* pnFlags) { if (!pnFlags) return E_INVALIDARG; // *pnFlags = CAPLUGIN_FLAG_TYPE_EDIT_TOOL; //说明这是一个用来编辑文章的插件。 // return S_OK; } HRESULT STDMETHODCALLTYPE CCANormalEditPlugin1::put_Flags(long nFlags) { return S_OK; } HRESULT STDMETHODCALLTYPE CCANormalEditPlugin1::get_MenuItemText(BSTR* pbstrDescription) { if (!pbstrDescription) return E_INVALIDARG; // CString strDescription = _T("删除未选中的部分"); //返回菜单文字 // *pbstrDescription = strDescription.AllocSysString(); // return S_OK; } HRESULT STDMETHODCALLTYPE CCANormalEditPlugin1::get_MenuItemStatus(long* pnStatus) { if (!pnStatus) return E_INVALIDARG; // *pnStatus = 0; // ATLASSERT(m_spApp); // return S_OK; } HRESULT STDMETHODCALLTYPE CCANormalEditPlugin1::get_MenuItemOrder(long* pnMenuItemOrder) { ATLASSERT(pnMenuItemOrder); *pnMenuItemOrder = 1001; // return S_OK; } HRESULT STDMETHODCALLTYPE CCANormalEditPlugin1::put_WebBrowser(IWebBrowser2* pWebBrowser) { m_spWebBrowser = pWebBrowser; //保留正在编辑的浏览器接口 return S_OK; } BOOL WizHTMLDocumentGetSelection(IHTMLDocument2* pDoc, BOOL bHTML, CString& strText); BOOL WizHTMLDocumentSimplePasteHTML(IHTMLDocument2* pDoc, LPCTSTR lpszHtml); HRESULT WizHTMLDocumentExecHelperNN(IHTMLDocument2* pDoc, UINT nID, long nMinSupportLevel = OLECMDF_SUPPORTED|OLECMDF_ENABLED, long nExecOpt = OLECMDEXECOPT_DODEFAULT); HRESULT STDMETHODCALLTYPE CCANormalEditPlugin1::Execute() { ATLASSERT(m_spApp); if (!m_spWebBrowser) return E_FAIL;; // //获得IHTMLDocument2接口 CComPtr<IDispatch> spDocDisp; if (FAILED(m_spWebBrowser->get_Document(&spDocDisp))) return E_FAIL; // if (!spDocDisp) return E_FAIL; // CComQIPtr<IHTMLDocument2> spDoc(spDocDisp); if (!spDoc) return E_FAIL; // //获得选中的HTML内容 CString strHTML; if (!WizHTMLDocumentGetSelection(spDoc, TRUE, strHTML)) return E_FAIL; // if (strHTML.IsEmpty()) return S_FALSE; // //执行命令,首先全选文章,然后删除 //通过这种方式,可以进行undo/redo WizHTMLDocumentExecHelperNN(spDoc, IDM_SELECTALL); WizHTMLDocumentExecHelperNN(spDoc, IDM_DELETE); // //粘贴选中的部分HTML内容 WizHTMLDocumentSimplePasteHTML(spDoc, strHTML); // return S_OK; } /////////////////////////////////////////////////////////////////////////////////////////// //辅助函数 // //获得选中的HTML内容 BOOL WizHTMLDocumentGetSelection(IHTMLDocument2* pDoc, BOOL bHTML, CString& strText) { ATLASSERT(pDoc); // CComPtr<IHTMLSelectionObject> spSelection = NULL; if (SUCCEEDED(pDoc->get_selection(&spSelection)) && spSelection) { CComPtr<IDispatch> spDisp = NULL; if (SUCCEEDED(spSelection->createRange(&spDisp)) && spDisp) { CComQIPtr<IHTMLTxtRange, &IID_IHTMLTxtRange> spRange(spDisp); if (spRange) { CComBSTR bstr; if (bHTML) { if (SUCCEEDED(spRange->get_htmlText(&bstr))) { strText = bstr; return TRUE; } } else { if (SUCCEEDED(spRange->get_text(&bstr))) { strText = bstr; return TRUE; } } } } } // CComPtr<IHTMLFramesCollection2> spColl = NULL; if (SUCCEEDED(pDoc->get_frames(&spColl)) && spColl) { long nCount = 0; spColl->get_length(&nCount); for (int i = 0; i < nCount; i++) { CComVariant vIn(i, VT_I4); CComVariant vOut; if (SUCCEEDED(spColl->item(&vIn, &vOut))) { CComPtr<IHTMLWindow2> spFrame = NULL; if (SUCCEEDED(vOut.pdispVal->QueryInterface(IID_IHTMLWindow2, (void**)&spFrame))) { CComPtr<IHTMLDocument2> spFrameDoc = NULL; if (SUCCEEDED(spFrame->get_document(&spFrameDoc))) { if (WizHTMLDocumentGetSelection(spFrameDoc, bHTML, strText)) return TRUE; } } } } } return FALSE; } HRESULT WizHTMLDocumentExecCommand(IHTMLDocument2* pDoc, const GUID *pGuid, long cmdID, long cmdExecOpt, VARIANT* pInVar=NULL, VARIANT* pOutVar=NULL) { CComQIPtr<IOleCommandTarget> spCmdTarg = pDoc; if (spCmdTarg) { return spCmdTarg->Exec(pGuid, cmdID, cmdExecOpt, pInVar , pOutVar); } else { return E_NOINTERFACE; } } HRESULT WizHTMLDocumentExecCommand(IHTMLDocument2* pDoc, long cmdID, long cmdExecOpt, VARIANT* pInVar=NULL, VARIANT* pOutVar=NULL) { return WizHTMLDocumentExecCommand(pDoc, &CGID_MSHTML, cmdID, cmdExecOpt, pInVar, pOutVar ); } long WizHTMLDocumentQueryStatus(IHTMLDocument2* pDoc, long cmdID) { CComQIPtr<IOleCommandTarget> spCmdTarg = pDoc; if (spCmdTarg) { OLECMD ocmd = {cmdID, 0}; if (S_OK == spCmdTarg->QueryStatus(&CGID_MSHTML, 1, &ocmd, NULL)) return ocmd.cmdf; } // if an error occurred, returning 0 means the command is disabled return 0; } HRESULT WizHTMLDocumentExecHelperNN(IHTMLDocument2* pDoc, UINT nID, long nMinSupportLevel, long nExecOpt) { HRESULT hr = E_FAIL; long lStatus = WizHTMLDocumentQueryStatus(pDoc, nID); if ((lStatus & nMinSupportLevel) == nMinSupportLevel) hr = WizHTMLDocumentExecCommand(pDoc, nID, nExecOpt); return hr; } BOOL WizHTMLDocumentSelectionScrollInToView(IHTMLDocument2* pDoc) { CComPtr<IHTMLSelectionObject> spSel; pDoc->get_selection(&spSel); if (!spSel) return FALSE; // CComPtr<IDispatch> spRange; spSel->createRange(&spRange); // if (CComQIPtr<IHTMLControlRange, &IID_IHTMLControlRange> spCtrlRange = spRange) // the user has slected controls (e.g. an image) { spCtrlRange->scrollIntoView(CComVariant(true)); } if (CComQIPtr<IHTMLTxtRange, &IID_IHTMLTxtRange> spTxtRange = spRange) { spTxtRange->scrollIntoView(); } // return TRUE; } //粘贴HTML内容 BOOL WizHTMLDocumentSimplePasteHTML(IHTMLDocument2* pDoc, LPCTSTR lpszHtml) { CComPtr<IHTMLSelectionObject> spSel; pDoc->get_selection(&spSel); if (!spSel) return FALSE; CComPtr<IDispatch> spRange; spSel->createRange(&spRange); CComQIPtr<IHTMLControlRange, &IID_IHTMLControlRange> spCtrlRange = spRange; if (spCtrlRange) // the user has slected controls (e.g. an image) { // remove all selected controls CComPtr<IHTMLElement> spElem; long nLen; spCtrlRange->get_length(&nLen); for (long i = nLen - 1; i >= 0; i--) { spCtrlRange->item(i, &spElem); // CComQIPtr<IHTMLDOMNode> spNode(spElem); if (spNode) { CComPtr<IHTMLDOMNode> spOldNode; VARIANT_BOOL vRemChilds(true); spNode->removeNode(vRemChilds, &spOldNode); } } // Now get the textrange after deleting all selected controls spRange = 0; spSel->createRange(&spRange); } CComQIPtr<IHTMLTxtRange, &IID_IHTMLTxtRange> spTxtRange = spRange; if (spTxtRange) { // spTxtRange will be valid if nothing is selected or if text is selected // or if multiple elements are seleted CComBSTR bstrHtml(lpszHtml); if (FAILED(spTxtRange->pasteHTML(bstrHtml))) return FALSE; // WizHTMLDocumentSelectionScrollInToView(pDoc); // return TRUE; } return FALSE; } 找到并修改MyCANormalPlugin1.cpp 这个文件主要用来注册COM组件(斜体部分为增加的内容)
// MyCANormalPlugin1.cpp : Implementation of DLL Exports. #include "stdafx.h" #include "resource.h" #include "MyCANormalPlugin1.h" /* * 包含必要的头文件。如果CyberArticle没有安装在C:\Program Files\Wizissoft\CyberArticle\,请修改下面相应的包含路径。 */ #include "C:/Program Files/Wizissoft/CyberArticle/developers/interface/include/CyberArticlePluginHelper.h" class CMyCANormalPlugin1Module : public CAtlDllModuleT< CMyCANormalPlugin1Module > { public : DECLARE_LIBID(LIBID_MyCANormalPlugin1Lib) DECLARE_REGISTRY_APPID_RESOURCEID(IDR_MYCANORMALPLUGIN1, "{D1AF3660-89D7-4EBC-9549-50C4F6B8A1D7}") }; CMyCANormalPlugin1Module _AtlModule; #ifdef _MANAGED #pragma managed(push, off) #endif // DLL Entry Point extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) { hInstance; return _AtlModule.DllMain(dwReason, lpReserved); } #ifdef _MANAGED #pragma managed(pop) #endif // Used to determine whether the DLL can be unloaded by OLE STDAPI DllCanUnloadNow(void) { return _AtlModule.DllCanUnloadNow(); } // Returns a class factory to create an object of the requested type STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) { return _AtlModule.DllGetClassObject(rclsid, riid, ppv); } // DllRegisterServer - Adds entries to the system registry STDAPI DllRegisterServer(void) { // registers object, typelib and all interfaces in typelib HRESULT hr = _AtlModule.DllRegisterServer(); // /* 注册CyberArticle插件 */ CyberArticleRegisterPlugin(CLSID_CANormalPlugin1, _T("My CA Normal Plugin1")); CyberArticleRegisterPlugin(CLSID_CANormalEditPlugin1, _T("删除为选中部分")); // return hr; } // DllUnregisterServer - Removes entries from the system registry STDAPI DllUnregisterServer(void) { HRESULT hr = _AtlModule.DllUnregisterServer(); // /* 取消注册CyberArticle插件 */ CyberArticleUnregisterPlugin(CLSID_CANormalPlugin1); CyberArticleUnregisterPlugin(CLSID_CANormalEditPlugin1); // return hr; } 从例子中可以看到,要编写一个可以用于编辑文章的插件非常简单,只需要在实现ICAPlugin的基础上,增加实现ICAEditPlugin接口就可以了。 一旦获得了IWebBrowser2接口,插件就可以通过IHTMLDocument2来操作整个HTML文档,实现各种高级功能。 |
|
|