1 目标
在完成使用C++以面向对象方式编写三水源新安江模型后,希望进一步把新安江模型做成COM组件的形式(也就是.dll 的形式)。
为此,我先跟导师学习了静态库、动态库和COM的知识,也从网上找到案例复现其创建及调用过程。
现在尝试把新安江模型做成COM组件的步骤记录如下。
2 创建COM组件
-
打开Visual Studio 2019 新建ATL项目
→
\rightarrow
→项目名称:XAJ
→
\rightarrow
→创建
→
\rightarrow
→勾选支持COM+ 1.0、支持组件注册
→
\rightarrow
→确定。 -
添加一个新的ATL对象。右键XAJ项目
→
\rightarrow
→添加
→
\rightarrow
→新建项
→
\rightarrow
→ATL
→
\rightarrow
→ATL简单对象
→
\rightarrow
→名称为Model
→
\rightarrow
→添加
→
\rightarrow
→ProgID取名为项目名+“.”+短名称
→
\rightarrow
→完成。 -
创建自己的方法,即在CModel 类中添加调用新安江模型的函数。在头文件Model.h 添加函数声明Run() ,目的是为了调用原来新安江模型的main() 函数。
#pragma once
#include "resource.h"
#include "XAJ_i.h"
#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)
#error "Windows CE 平台(如不提供完全 DCOM 支持的 Windows Mobile 平台)上无法正确支持单线程 COM 对象。定义 _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA 可强制 ATL 支持创建单线程 COM 对象实现并允许使用其单线程 COM 对象实现。rgs 文件中的线程模型已被设置为“Free”,原因是该模型是非 DCOM Windows CE 平台支持的唯一线程模型。"
#endif
using namespace ATL;
class ATL_NO_VTABLE CModel :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CModel, &CLSID_Model>,
public IDispatchImpl<IModel, &IID_IModel, &LIBID_XAJLib, 1, 0>
{
public:
CModel()
{
}
DECLARE_REGISTRY_RESOURCEID(106)
BEGIN_COM_MAP(CModel)
COM_INTERFACE_ENTRY(IModel)
COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()
DECLARE_PROTECT_FINAL_CONSTRUCT()
HRESULT FinalConstruct()
{
return S_OK;
}
void FinalRelease()
{
}
public:
STDMETHODIMP Run(CHAR* argv[]);
};
OBJECT_ENTRY_AUTO(__uuidof(Model), CModel)
- 将三水源新安江模型中的源文件和头文件导入到
XAJ 项目中,并在导入的所有源文件顶部添加#include "pch.h" 头文件。 - 创建
XinanjiangModel.h ,输入main() 函数声明。
#pragma once
int main(int argc, char* argv[]);
- 在源文件
Model.cpp 添加函数实现,以调用新安江模型main() 函数。
#include "pch.h"
#include "Model.h"
#include "XinanjiangModel.h"
STDMETHODIMP_(HRESULT __stdcall) CModel::Run(CHAR* argv[])
{
main(0, argv);
return S_OK;
}
- 在
XAJ.idl 中添加方法接口设置,如interface IModel : IDispatch 中所示,这里的Run() 函数为纯虚函数。
import "oaidl.idl";
import "ocidl.idl";
[
object,
uuid(a817e7a2-43fa-11d0-9e44-00aa00b6770a),
dual,
pointer_default(unique)
]
interface IComponentRegistrar : IDispatch
{
[id(1)] HRESULT Attach([in] BSTR bstrPath);
[id(2)] HRESULT RegisterAll();
[id(3)] HRESULT UnregisterAll();
[id(4)] HRESULT GetComponents([out] SAFEARRAY(BSTR)* pbstrCLSIDs, [out] SAFEARRAY(BSTR)* pbstrDescriptions);
[id(5)] HRESULT RegisterComponent([in] BSTR bstrCLSID);
[id(6)] HRESULT UnregisterComponent([in] BSTR bstrCLSID);
};
[
object,
uuid(ea7ac902-5dc5-4732-b2dc-46f50fd9385b),
dual,
nonextensible,
pointer_default(unique)
]
interface IModel : IDispatch
{
[id(1)] HRESULT Run([in] CHAR* argv[1]);
};
[
uuid(94233707-a67e-4579-9cba-8e92fbf8ee01),
version(1.0),
custom(a817e7a1-43fa-11d0-9e44-00aa00b6770a,"{fb867d6b-4a32-4e2f-addd-3047d0103833}")
]
library XAJLib
{
importlib("stdole2.tlb");
[
uuid(fb867d6b-4a32-4e2f-addd-3047d0103833)
]
coclass CompReg
{
[default] interface IComponentRegistrar;
};
[
uuid(e002b0ec-9a5c-44c8-8b96-bb7648d05f25)
]
coclass Model
{
[default] interface IModel;
};
};
import "shobjidl.idl";
- 解决方案配置选择
Release ,平台选择x64 ,右键XAJ 项目生成。XAJ.dll 为 64位的COM 组件。XAJ.dll 或 XAJ.tlb 是之后 C++ 调用COM所需要引入的文件。
3 注册COM组件
- 注意: 根据COM组件位数选择
regsvr32.exe ,如果COM组件为32位,用C:\Windows\System32\regsvr32.exe 注册;如果COM组件为64位,则用C:\Windows\SysWOW64\regsvr32.exe 注册。
因为上一步选择x64 ,所以这里的COM组件是64位的,所以应该用C:\Windows\SysWOW64\regsvr32.exe 注册。
- 注册。以管理员身份打开powershell,依次输入如下代码,完成注册。
cd E:\Research\XinanjiangModel\Myself\COM\XAJ\x64\Release
C:\Windows\SysWOW64\regsvr32.exe -i XAJ.dll
- 或者以管理员身份打开CMD,依次输入如下代码,完成注册。
E:
cd E:\Research\XinanjiangModel\Myself\COM\XAJ\x64\Release
C:\Windows\SysWOW64\regsvr32.exe -i XAJ.dll
4 调用COM组件
- 打开Visual Studio 2019,文件
→
\rightarrow
→新建
→
\rightarrow
→项目
→
\rightarrow
→控制台应用
→
\rightarrow
→创建
XAJCOMAPP 项目。 - 在源文件
XAJCOMAPP.cpp 中引入动态库文件XAJ.dll 目录。解决方案配置选择Debug
→
\rightarrow
→平台选择x64
→
\rightarrow
→右键XAJCOMAPP 项目
→
\rightarrow
→配置属性
→
\rightarrow
→C/C++
→
\rightarrow
→常规
→
\rightarrow
→附加包含目录
→
\rightarrow
→新行
→
\rightarrow
→选择动态库目录。这里的平台位数必须与COM组件位数一致。 - 在
XAJCOMAPP.cpp 中输入如下代码:
#include <iostream>
#import "XAJ.dll" raw_interfaces_only raw_native_types no_namespace named_guids
int main(int argc, char* argv[])
{
::CoInitialize(0);
IModelPtr pModel = nullptr;
HRESULT hr = pModel.CreateInstance("XAJ.Model");
pModel->Run(argv);
return 0;
}
- 点击本地Windows调试器,成功调用新安江模型COM组件。在
x64\Debug\ 文件夹内生成流域出口流量过程Q.txt ,但由于该路径下没有新安江模型的输入文件,所以Q.txt 为空文件,文件大小为0KB。 - 在该路径下创建如下图5个新安江模型输入文件,再点击本地Windows调试器或
XAJCOMAPP.exe ,即可生成流域出口流量过程Q.txt 。
5 参考资料
“类未注册(HRESULT异常:0x80040154(REGDB_E_CLASSNOTREG))”
6 本机目录
创建和注册COM组件目录:E:\Research\XinanjiangModel\Myself\COM\XAJ\x64\Release 调用COM组件目录:E:\Master\study\Cpp\XAJCOMAPP\x64\Debug
|