例子:编写CyberArticle导出文件插件(Visual C++)

建立工程

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

增加COM组件

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

添加属性和方法

添加属性和方法的操作,请参看例子:编写CyberArticle导入文件插件(Visual C++)
 

属性:PluginFlags,只读属性

类型:LONG
 

属性:ExportFlags,只写属性

类型:LONG
 

方法:Export

参数
  1. [in] IDispatch* pNodeDisp
  2. [in] BSTR bstrPath
  3. [out,retval] VARIANT* pvResultFiles
到这里,必须的属性和方法和都已经添加完毕。
 
idl文件片段:
interface ICAExportPlugin1 : IDispatch{ 
    [propget, id(1), helpstring("property PluginFlags")] HRESULT PluginFlags([out, retval] LONG* pVal); 
    [propput, id(2), helpstring("property ExportFlags")] HRESULT ExportFlags([in] LONG newVal); 
    [id(3), helpstring("method Export")] HRESULT Export([in] IDispatch* pNodeDisp, [in] BSTR bstrPath, [out,retval] VARIANT* pvResultFiles); 
}; 
 

注册插件

要让CyberArticle知道这个插件,您必须进行注册。
打开MyCAImportPlugin1.cpp并进行修改(斜体部分是增加的内容)。
 
// MyCAImportPlugin1.cpp : Implementation of DLL Exports. 


#include "stdafx.h" 
#include "resource.h" 
#include "MyCAImportPlugin1.h" 


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


class CMyCAImportPlugin1Module : public CAtlDllModuleT< CMyCAImportPlugin1Module > 
{ 
public : 
    DECLARE_LIBID(LIBID_MyCAImportPlugin1Lib) 
    DECLARE_REGISTRY_APPID_RESOURCEID(IDR_MYCAIMPORTPLUGIN1, "{9649C428-B6E2-4DA5-B733-16AEB91454AC}") 
}; 

CMyCAImportPlugin1Module _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(); 
    //注册插件 
    CyberArticleRegisterImportPlugin(CLSID_CAImportPlugin1, _T("导入插件示例,导入图片(*.gif;*.png;*.jpg;*.bmp)")); 
    // 
    return hr; 
} 


// DllUnregisterServer - Removes entries from the system registry 
STDAPI DllUnregisterServer(void) 
{ 
    HRESULT hr = _AtlModule.DllUnregisterServer(); 
    //卸载插件 
    CyberArticleUnregisterImportPlugin(CLSID_CAImportPlugin1); 
    // 
    return hr; 
} 
上面的代码,在注册COM组件的时候,同时使用CyberArticle辅助函数CyberArticleRegisterImportPlugin/CyberArticleUnregisterImportPlugin,向注册表指定位置写入数据,完成插件注册。
 

完成插件功能

到这里,我们已经完成了插件框架的编写。现在编译整个程序,然后打开CyberArticle,从主菜单中选择“文件->导出->导出为文件”,打开导出文件对话框。
 
在对话框里面,已经有我们的插件了:
 
 
为了能够成功导出图片,我们必须编写一些代码。
打开CAExportPlugin1.cpp文件(斜体部分是新增内容)
 
// CAExportPlugin1.cpp : Implementation of CCAExportPlugin1 

#include "stdafx.h" 
#include "CAExportPlugin1.h" 

#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" 
#include "C:/Program Files/Wizissoft/CyberArticle/developers/interface/include/WizHelper.h" 

// CCAExportPlugin1 

STDMETHODIMP CCAExportPlugin1::get_PluginFlags(LONG* pVal) 
{ 
    if (!pVal) 
        return E_INVALIDARG; 
    // 
    *pVal = 0; 
    // 
    return S_OK; 
} 
STDMETHODIMP CCAExportPlugin1::put_ExportFlags(LONG newVal) 
{ 
    return S_OK; 
} 

HRESULT CyberArticleExportResourceFiles(LPCTSTR lpszPath, IDispatch* pNodeDisp, LPCTSTR lpszFileExt, CWizStdStringArray& arrayFiles); 

STDMETHODIMP CCAExportPlugin1::Export(IDispatch* pNodeDisp, BSTR bstrPath, VARIANT* pvResultFiles) 
{ 
    if (!pvResultFiles) 
        return E_INVALIDARG; 
    // 
    /* 
    导出指定的文件类型 
    */ 
    // 
    CWizStdStringArray arrayFiles; 
    // 
    HRESULT hr = CyberArticleExportResourceFiles(CString(bstrPath), pNodeDisp, _T(";*.jpg;*.bmp;*.png;*.ico;*.gif;"), arrayFiles); 
    if (FAILED(hr)) 
        return hr; 
    // 
    return WizStringArrayToVariant(arrayFiles, *pvResultFiles) ? S_OK : E_FAIL; 
} 


void WizStreamSeekToBegin(IStream* pStream) 
{ 
    LARGE_INTEGER size; 
    memset(&size, 0, sizeof(LARGE_INTEGER)); 
    pStream->Seek(size, STREAM_SEEK_SET, NULL); 
} 

BOOL WizStreamRead(IStream* pStream, void* pBuffer, ULONG nNeedRead) 
{ 
    ULONG nRead = 0; 
    HRESULT hr = pStream->Read(pBuffer, nNeedRead, &nRead); 
    if (FAILED(hr)) 
        return FALSE; 
    if (nRead != nNeedRead) 
        return FALSE; 
    return TRUE; 
} 

__int64 WizStreamGetSize(IStream* pStream) 
{ 
    __int64 nLen = 0; 
    LARGE_INTEGER    cur; 
    LARGE_INTEGER    zero; 
    memset(&zero, 0, sizeof(LARGE_INTEGER)); 
    if (pStream->Seek(zero, STREAM_SEEK_CUR, (ULARGE_INTEGER*)&cur) == S_OK) 
    { 
        ULARGE_INTEGER    result; 
        if (pStream->Seek(zero, STREAM_SEEK_END, &result) == S_OK) 
        { 
            nLen = result.QuadPart; 
            pStream->Seek(cur, STREAM_SEEK_SET, NULL); 
        } 
    } 
    return nLen; 
} 

BOOL WizStreamSaveToFile(IStream* pStream, LPCTSTR lpszFileName) 
{ 
    WizStreamSeekToBegin(pStream); 
    // 
    ULONG nSize = ULONG(WizStreamGetSize(pStream)); 
    BYTE* pBuffer = new BYTE[nSize]; 
    if (!pBuffer) 
        return FALSE; 
    // 
    BOOL bRet = FALSE; 
    // 
    if (WizStreamRead(pStream, pBuffer, nSize)) 
    { 
        FILE* fp = NULL; 
        if (0 == _tfopen_s(&fp, lpszFileName, _T("wb"))) 
        { 
            fwrite(pBuffer, nSize, 1, fp); 
            bRet = TRUE; 
            // 
            fclose(fp); 
        } 
    } 
    // 
    delete [] pBuffer; 
    // 
    return bRet; 
} 

/* 
将CyberArticle资源文件按照类型导出成文件 
*/ 
HRESULT CyberArticleExportResourceFiles(LPCTSTR lpszPath, IDispatch* pNodeDisp, LPCTSTR lpszFileExt, CWizStdStringArray& arrayFiles) 
{ 
    CComQIPtr<ICANode> spNode(pNodeDisp); 
    if (!spNode) 
        return E_INVALIDARG; 
    // 
    CString strFileExt = CString(_T(";")) + lpszFileExt + _T(";"); 
    strFileExt.MakeLower(); 
    // 
    CString strPath(lpszPath); 
    if (strPath.IsEmpty()) 
        return E_INVALIDARG; 
    if (strPath[strPath.GetLength() - 1] != '\\') 
        strPath += _T("\\"); 
    // 
    /* 
    获得文章 
    */ 
    CComPtr<IDispatch> spArticleDisp; 
    if (FAILED(spNode->get_Article(&spArticleDisp))) 
        return E_FAIL; 
    // 
    CComQIPtr<ICAArticle> spArticle(spArticleDisp); 
    if (!spArticle) 
        return E_FAIL; 
    // 
    /* 
    获得资源 
    */ 
    CComPtr<IDispatch> spResourceCollDisp; 
    if (FAILED(spArticle->get_Children(&spResourceCollDisp))) 
        return E_FAIL; 
    // 
    CComQIPtr<ICAArticleResourceCollection> spResourceColl(spResourceCollDisp); 
    if (!spResourceColl) 
        return E_FAIL; 
    // 
    long nCount = 0; 
    spResourceColl->get_Count(&nCount); 
    for (long i = 0; i < nCount; i++) 
    { 
        CComPtr<IDispatch> spResourceDisp; 
        if (FAILED(spResourceColl->get_Item(i, &spResourceDisp))) 
            return E_FAIL; 
        // 
        CComQIPtr<ICAArticleResource> spResource(spResourceDisp); 
        if (!spResource) 
            return E_FAIL; 
        // 
        /* 
        获得资源名称 
        */ 
        CComBSTR bstrName; 
        if (FAILED(spResource->get_Name(&bstrName))) 
            return E_FAIL; 
        // 
        /* 
        检查扩展名 
        */ 
        CString strName(bstrName); 
        TCHAR szExt[MAX_PATH]; 
        _tsplitpath_s(strName, NULL, 0, NULL, 0, NULL, 0, szExt, MAX_PATH); 
        CString strExt = CString(_T(";*")) + szExt + _T(";"); 
        if (-1 == strFileExt.Find(strExt)) 
            continue; 
        // 
        /* 
        保存到stream里面 
        */ 
        CComPtr<IStream> spStream; 
        if (FAILED(CreateStreamOnHGlobal(NULL, TRUE, &spStream))) 
            return E_FAIL; 
        // 
        if (FAILED(spResource->SaveToStream(spStream))) 
            return E_FAIL; 
        // 
        CString strFileName = strPath + CString(bstrName); 
        // 
        /* 
        保存到文件 
        */ 
        if (!WizStreamSaveToFile(spStream, strFileName)) 
            continue; 
        // 
        /* 
        添加保存成功的文件 
        */ 
        arrayFiles.push_back(strFileName); 
    } 
    // 
    return S_OK; 
}
 
重新编译工程,在CyberArticle里面,就可以利用我们的插件,导入图片了。