例子:编写一个CyberArticle普通插件 (Visual C++)

下面是一个用Visual Studio 2005 (Visual C++)开发一个简单的CyberArticle 普通插件的过程。

建立工程

启动Visual Studio,然后点击菜单 File->New->Project
 
 
选择Visual C++->ATL->ATL工程
 
 
工程名为MyCANormalPlugin1。
 
新建工程向导中,完全采用默认设置。新建工程后,VS2005会生成工程文件
 
 

增加COM组件

在工程上面点击右键,选择Add->Class
 
 
选择Visual C++->ATL->ATL Simple Object
 
在ATL对象向导对话框中,输入COM组件的名称(short name): CANormalPlugin1
 
 
然后点击完成。
 
Visual Studio将会自动生成COM组件对应的class, idl等等。
 

找到并修改CANormalPlugin1.h文件

这是COM组件class定义文件。斜体部分为增加的内容:
 
// CANormalPlugin1.h : Declaration of the CCANormalPlugin1

#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



// CCANormalPlugin1

class ATL_NO_VTABLE CCANormalPlugin1 :
    public CComObjectRootEx<CComSingleThreadModel>,
    public CComCoClass<CCANormalPlugin1, &CLSID_CANormalPlugin1>,
    public IDispatchImpl<ICANormalPlugin1, &IID_ICANormalPlugin1, &LIBID_MyCANormalPlugin1Lib, /*wMajor =*/ 1, /*wMinor =*/ 0>
    , public ICAPlugin        //增加实现的接口
{
public:
    CCANormalPlugin1()
    {
    }

DECLARE_REGISTRY_RESOURCEID(IDR_CANORMALPLUGIN1)


BEGIN_COM_MAP(CCANormalPlugin1)
    COM_INTERFACE_ENTRY(ICANormalPlugin1)
    COM_INTERFACE_ENTRY(IDispatch)
    COM_INTERFACE_ENTRY_IID(IID_ICAPlugin, ICAPlugin)        //增加接口
END_COM_MAP()



    DECLARE_PROTECT_FINAL_CONSTRUCT()

    HRESULT FinalConstruct()
    {
        return S_OK;
    }

    void FinalRelease()
    {
    }

public:

    //实现接口ICAPlugin
private:
    CComPtr<ICAApp> m_spApp;

public:
    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();
};

OBJECT_ENTRY_AUTO(__uuidof(CANormalPlugin1), CCANormalPlugin1)

找到并修改CANormalPlugin1.cpp文件

这是COM组件实现文件。(斜体部分为增加的内容)
// CANormalPlugin1.cpp : Implementation of CCANormalPlugin1

#include "stdafx.h"
#include "CANormalPlugin1.h"


/*
* 包含必要的头文件。如果CyberArticle没有安装在C:\Program Files\Wizissoft\CyberArticle\,请修改下面相应的包含路径。
*/
#include <atlstr.h>
#include "C:/Program Files/Wizissoft/CyberArticle/developers/interface/include/cyberarticlebook.h"
#include "C:/Program Files/Wizissoft/CyberArticle/developers/interface/include/cyberarticlebook_i.c"

// CCANormalPlugin1

HRESULT STDMETHODCALLTYPE CCANormalPlugin1::Init(ICAApp* pApp)
{
    /*
    插件初始化,在CyberArticle启动的时候,会调用这个方法。
    */
    m_spApp = pApp;
    ATLASSERT(m_spApp);
    //
    return S_OK;
}
HRESULT STDMETHODCALLTYPE CCANormalPlugin1::Exit()
{
    /*
    在CyberArticle退出的时候,会调用这个方法。
    */
    m_spApp = NULL;
    //
    return S_OK;
}
HRESULT STDMETHODCALLTYPE CCANormalPlugin1::get_Flags(long* pnFlags)
{
    if (!pnFlags)
        return E_INVALIDARG;
    //
    /*
    获得插件信息。
    CAPLUGIN_FLAG_TYPE_NODES_TOOL:这是一个用来处理节点的插件
    CAPLUGIN_FLAG_MENU_BEGIN_GROUP:告诉CyberArticle,在插件菜单前面,先是一个分割线,用来和其它的菜单分开。
    */
    *pnFlags = CAPLUGIN_FLAG_TYPE_NODES_TOOL | CAPLUGIN_FLAG_MENU_BEGIN_GROUP;
    //
    return S_OK;
}
HRESULT STDMETHODCALLTYPE CCANormalPlugin1::put_Flags(long nFlags)
{
    return S_OK;
}
HRESULT STDMETHODCALLTYPE CCANormalPlugin1::get_MenuItemText(BSTR* pbstrDescription)
{
    if (!pbstrDescription)
        return E_INVALIDARG;
    //
    /*
    返回菜单文字
    */
    CString strDescription = _T("My CA Normal Plugin");
    //
    *pbstrDescription = strDescription.AllocSysString();
    //
    return S_OK;
}
HRESULT STDMETHODCALLTYPE CCANormalPlugin1::get_MenuItemStatus(long* pnStatus)
{
    /*
    用来更新菜单状态。
    */
    if (!pnStatus)
        return E_INVALIDARG;
    //
    *pnStatus = 0;
    //
    ATLASSERT(m_spApp);
    //
    CComPtr<ICAWindow> spWindow;
    if (FAILED(m_spApp->get_Window(&spWindow)))
        return S_OK;
    //
    long nCount = 0;
    if (S_OK != spWindow->get_SelectedNodesCount(&nCount) || 0 == nCount)
    {
        /*
        如果在CyberArticle里面,没有选中任何节点,则让菜单实效
        */
        *pnStatus = CAPLUGIN_MIS_DISABLED;
        return S_OK;
    }
    //
    return S_OK;
}
HRESULT STDMETHODCALLTYPE CCANormalPlugin1::get_MenuItemOrder(long* pnMenuItemOrder)
{
    /*
    返回菜单显示顺序
    */
    ATLASSERT(pnMenuItemOrder);
    *pnMenuItemOrder = 1000;
    //
    return S_OK;
}

HRESULT STDMETHODCALLTYPE CCANormalPlugin1::Execute()
{
    ATLASSERT(m_spApp);
    //
    /*
    获得CyberArticle窗口
    */
    CComPtr<ICAWindow> spWindow;
    if (FAILED(m_spApp->get_Window(&spWindow)))
        return E_FAIL;
    //
    /*
    获得CyberArticle窗口句柄
    */
    HWND hwndCyberArticle = NULL;
    spWindow->get_HWND(&hwndCyberArticle);
    //

    /*
    获得CyberArticle选中的节点
    */
    CComPtr<ICANodeCollection> spNodeCollection;
    if (FAILED(spWindow->get_SelectedNodes(&spNodeCollection)))
        return E_FAIL;
    //
    /*
    获得CyberArticle选中的节点数量
    */
    long nCount = 0;
    spNodeCollection->get_Count(&nCount);
    //
    for (long i = 0; i < nCount; i++)
    {
        /*
        获得每一个选中的节点
        */
        CComPtr<IDispatch> spDispNode = NULL;
        if (FAILED(spNodeCollection->get_Item(i, &spDispNode)))
            continue;
        //
        CComQIPtr<ICANode> spNode(spDispNode);
        if (spNode)
        {
            /*
            获得节点的标题
            */
            CComBSTR bstrTitle;
            if (SUCCEEDED(spNode->get_Title(&bstrTitle)) && bstrTitle)
            {
                /*
                调用MessageBox对话框,显示节点标题
                */
                MessageBox(hwndCyberArticle, CString(bstrTitle), _T("My CA Normal Plugin"), MB_OK | MB_ICONINFORMATION);
            }
        }
    }
    return S_OK;
}

找到并修改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"));
    //
    return hr;
}


// DllUnregisterServer - Removes entries from the system registry
STDAPI DllUnregisterServer(void)
{
    HRESULT hr = _AtlModule.DllUnregisterServer();
    //
    /*
    取消注册CyberArticle插件
    */
    CyberArticleUnregisterPlugin(CLSID_CANormalPlugin1);
    //
    return hr;
}
 
 

编译并测试插件

然后编译整个工程。如果出现错误,请检查相应的代码。
重新运行CyberArticle,选中一个获这多个节点,然后再选中的节点上面,点击右键,再出现的菜单中,将会有我们的插件菜单;
点击这个菜单,将会出现消息对话框,上面显示了我们选中的节点的标题。

调试插件:

在Visual Studio里面,将CyberArticle.exe设置为调试程序,就可以调试插件了。
启动CyberArticle,就可以调试插件了。