用C++开发Sap2000第一个插件

过程与上一篇《用C#开发SAP2000第一个插件》很相似,因为从本质上讲,都是写一个 COM 对象,给SAP2000主程序调用,从而实现插件功能。

我的开发环境:Win7 SP1 + Visual Studio 2010 + SAP2000 v15.2.1 

1. 首先启动VS2010,新建一个 ATL 项目。我们需要 VC++ 中的 ATL 框架来实现COM架构。

2. 在Class View中,添加一个类,选择 ATL Simple Object,设置如下图所示。其中ProgID的设置很重要,必须为 LibraryName.cPlugin 的形式。(结构狮会编程http://cnblogs.com/sap2000/ 版权所有)

3. 在下一步的设置中,一定要选择“Dual Interface”也就是双接口。双接口允许以IDispatch接口调用COM中的方法,这对SAP2000主程序很重要,原因在后面讲。

4. 下一步是在新建立的 _cPlugin 接口中,添加方法。SAP2000支持两个方法,分别是用作插件主程序的 Main() 方法,一个显示插件信息的 Info() 方法。它们在IDL接口定义文件中的声明如下:

[id(1)] HRESULT Main([in,out] _cSapModel** ppSapModel, [in,out] _cSapPlugin** ppSapPlugin);
[id(2)] HRESULT Info([in,out] BSTR* info, [out,retval] LONG* pRetVal);

5. 添加好方法之后,就可以在 cpp 文件中开始写程序了。我写好的两个方法的示例代码如下:

主方法Main()

// Main method for sap2000 plugin
// Demonstrated by http://cnblogs.com/sap2000/ 
STDMETHODIMP CPlugin::Main(_cSapModel** ppSapModel, _cSapPlugin** ppSapPlugin)
{
    // com calling result
    HRESULT hr;
    // parameters
    long num = 0;
    SAFEARRAY* pObjTypes = NULL;
    SAFEARRAY* pObjNames = NULL;
    // call sap2000 api
    hr = (*ppSapModel)->SelectObj->GetSelected(&num, &pObjTypes, &pObjNames);
    // check return value using pre-defined macro
    if(SUCCEEDED(hr)) {
        // prepare message
        TCHAR *str = new TCHAR[512];
        wsprintf(str, _T("Selected %ld object"), num);
        // message box output
        ::MessageBox(NULL, str, _T("Selected"), MB_OK | MB_ICONINFORMATION);

        delete[] str;
    }
    if(ppSapPlugin) {
        // return from sap2000 plugin to the main program
        // required by sap2000
        (*ppSapPlugin)->Finish(0);
    }
    return S_OK;
}

插件信息方法 Info()

// Information method for sap2000 plugin
// Demonstrated by http://cnblogs.com/sap2000/ 
STDMETHODIMP CPlugin::Info(BSTR* info, LONG* pRetVal)
{
    // text output
    const TCHAR *pText = _T("Count Selected Object.\r\nPlugin by xiaoding.");
    // output 
    SysReAllocString(info, pText);
    // return zero to indicate a successful call, required by sap2000
    (*pRetVal) = 0;
    return S_OK;
}

6. 这些方法中,用到了 SAP2000 中导出的类型,现在编译器还不识别,我们需要导入相关的TypeLib,以顺利完成编译。将SAP2000安装目录下的SAP2000.TLB文件拷到VC++的工程目录中,与源程序文件放在一起。然后在 stdafx.h 头文件中,添加以下代码导入sap2000的typelib(此代码引用自CSI的OAPI帮助文件)

#import "Sap2000.tlb" high_property_prefixes("Get_","Put_","PutRef_") no_smart_pointers no_namespace raw_native_types rename("min", "sap2000v12_min") rename("SetProp", "sap2000v12_SetProp") rename("GetProp", "sap2000v12_GetProp") rename("Yield", "sap2000v12_Yield")

注意这些代码应该写在一行上。这样就向项目中导入了sap2000的typelib,可以使用导出的类型了。

7. 现在程序还不能编译,原因是IDL文件中也使用了相关的导出类,导致IDL文件编译失败。我们要向IDL文件中导入sap2000.tlb这个类型库,在IDL文件的library定义中,加入 importlib("sap2000.tlb"); 这一句。另外,还要把 interface _cPlugin 的定义移到 library 的定义中,放到 importlib 语句的后边。这样MIDL编译器才能在导入sap2000.tlb类型库后识别我们在interface中使用到的自定义类型。

我的IDL文件定义如下,其结构可以作为参考。(默认生成的IDL文件,其interface的定义是在library上面的)

// ObjectCount.idl : IDL source for ObjectCount
// Courtesy by http://cnblogs.com/sap2000/

// This file will be processed by the MIDL tool to
// produce the type library (ObjectCount.tlb) and marshalling code.

import "oaidl.idl";
import "ocidl.idl";

[
    uuid(B6B0D7FC-FBDF-4734-BAB0-B95B80A26D3D),
    version(1.0),
]
library ObjectCountLib
{
    importlib("stdole2.tlb");
    importlib("sap2000.tlb");

    [
        uuid(43393962-C98D-4AC0-BF4F-F636D2032ACC)        
    ]
    coclass Plugin
    {
        [default] interface _cPlugin;
    };

    [
        object,
        uuid(C54C20F7-E99D-4AD9-A4C8-1D7EC50753A5),
        dual,
        nonextensible,
        pointer_default(unique)
    ]
    interface _cPlugin : IDispatch{
        [id(1)] HRESULT Main([in,out] _cSapModel** ppSapModel, [in,out] _cSapPlugin** ppSapPlugin);
        [id(2)] HRESULT Info([in,out] BSTR* info, [out,retval] LONG* pRetVal);
    };
};

8. 这样,我们的设置就顺利完成了,可以成功编译。然后在SAP2000中添加相应的插件。插件的截图如下:

可以看到插件已经添加成功。可以从菜单中调用:

这是调用结果:

同时,在插件管理界面,也能向用户显示关于插件的信息。我们这里显示了一小段程序和版权信息,内容与我们在Info()方法中设置的相同(废话!),如图:

以上就是用C++为SAP2000编写插件的全部介绍了。由于CSI的官方文档不够全面,很多技术问题写得比较模糊,网上的介绍又非常少(包括英文的也很少)。很多地方都是我自己一点点摸索出来的,在这里介绍出来,也算是给后来者一点帮助。

--

Courtesy of 结构狮会编程

posted @ 2013-03-28 15:52  结构狮会编程  阅读(2582)  评论(0编辑  收藏  举报