【C++】07 新安江模型COM组件

作者简介

很高兴认识您!
我叫卢家波,河海大学水文学及水资源博士研究生,研究兴趣为高效洪水淹没预测、洪水灾害预警、机器学习、替代模型和降阶模型。
变化环境下,极端洪水事件多发,我希望能通过研究为水灾害防御做出贡献,为人民服务。
我很乐意与您交流和研究合作,vx Jiabo_Lu
主页 https://lujiabo98.github.io
简历 https://lujiabo98.github.io/file/CV_JiaboLu_zh.pdf
博客 https://blog.csdn.net/weixin_43012724?type=blog
来信请说明博客标题及链接,谢谢。

1 目标

在完成使用C++以面向对象方式编写三水源新安江模型后,希望进一步把新安江模型做成COM组件的形式(也就是.dll的形式)。

为此,我先跟导师学习了静态库动态库COM的知识,也从网上找到案例复现其创建及调用过程。

现在尝试把新安江模型做成COM组件的步骤记录如下。

2 创建COM组件

  1. 打开Visual Studio 2019 新建ATL项目 → \rightarrow 项目名称:XAJ → \rightarrow 创建 → \rightarrow 勾选支持COM+ 1.0、支持组件注册 → \rightarrow 确定。
    在这里插入图片描述

  2. 添加一个新的ATL对象。右键XAJ项目 → \rightarrow 添加 → \rightarrow 新建项 → \rightarrow ATL → \rightarrow ATL简单对象 → \rightarrow 名称为Model → \rightarrow 添加 → \rightarrow ProgID取名为项目名+“.”+短名称 → \rightarrow 完成。
    在这里插入图片描述
    在这里插入图片描述

  3. 创建自己的方法,即在CModel类中添加调用新安江模型的函数。在头文件Model.h添加函数声明Run(),目的是为了调用原来新安江模型的main()函数。

// Model.h: CModel 的声明

#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;


// CModel

class ATL_NO_VTABLE CModel :
	public CComObjectRootEx<CComSingleThreadModel>,
	public CComCoClass<CModel, &CLSID_Model>,
	public IDispatchImpl<IModel, &IID_IModel, &LIBID_XAJLib, /*wMajor =*/ 1, /*wMinor =*/ 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)
  1. 将三水源新安江模型中的源文件头文件导入到XAJ项目中,并在导入的所有源文件顶部添加#include "pch.h"头文件。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  2. 创建XinanjiangModel.h,输入main()函数声明。
    在这里插入图片描述
//XinanjiangModel.h
#pragma once

//主函数声明
int main(int argc, char* argv[]);
  1. 在源文件Model.cpp添加函数实现,以调用新安江模型main()函数。
// Model.cpp: CModel 的实现


#include "pch.h"
#include "Model.h"

//添加新安江模型的头文件
#include "XinanjiangModel.h"

// CModel

STDMETHODIMP_(HRESULT __stdcall) CModel::Run(CHAR* argv[])
{
	//运行新安江模型
	main(0, argv);

	//默认返回 函数执行正确
	return S_OK;
}

  1. XAJ.idl中添加方法接口设置,如interface IModel : IDispatch中所示,这里的Run()函数为纯虚函数。
// XAJ.idl: XAJ 的 IDL 源
//

// 此文件将由 MIDL 工具处理以
// 生成类型库(XAJ.tlb)和封送处理代码。

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";

  1. 解决方案配置选择Release,平台选择x64,右键XAJ项目生成。XAJ.dll 为 64位的COM 组件。XAJ.dllXAJ.tlb 是之后 C++ 调用COM所需要引入的文件。
    在这里插入图片描述

3 注册COM组件

  1. 注意: 根据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注册。

  1. 注册。以管理员身份打开powershell,依次输入如下代码,完成注册。
cd E:\Research\XinanjiangModel\Myself\COM\XAJ\x64\Release
C:\Windows\SysWOW64\regsvr32.exe -i  XAJ.dll

在这里插入图片描述

  1. 或者以管理员身份打开CMD,依次输入如下代码,完成注册。
E:
cd E:\Research\XinanjiangModel\Myself\COM\XAJ\x64\Release
C:\Windows\SysWOW64\regsvr32.exe -i  XAJ.dll

在这里插入图片描述

4 调用COM组件

  1. 打开Visual Studio 2019,文件 → \rightarrow 新建 → \rightarrow 项目 → \rightarrow 控制台应用 → \rightarrow 创建XAJCOMAPP项目。
    在这里插入图片描述
  2. 在源文件XAJCOMAPP.cpp中引入动态库文件XAJ.dll目录。解决方案配置选择Debug → \rightarrow 平台选择x64 → \rightarrow 右键XAJCOMAPP项目 → \rightarrow 配置属性 → \rightarrow C/C++ → \rightarrow 常规 → \rightarrow 附加包含目录 → \rightarrow 新行 → \rightarrow 选择动态库目录。这里的平台位数必须与COM组件位数一致。
    在这里插入图片描述
  3. XAJCOMAPP.cpp中输入如下代码:
// XAJCOMAPP.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>

#import "XAJ.dll"	 raw_interfaces_only raw_native_types no_namespace named_guids

int main(int argc, char* argv[])
{
	//初始化 COM 库,用来告诉 Windows 以单线程的方式创建 COM 对象
	::CoInitialize(0);

	//指向ITEMP类的智能指针
	IModelPtr pModel = nullptr;
	//创建 COM 组件对象,有两种方式
	//HRESULT hr = pModel.CreateInstance(CLSID_Model);     //使用CLSID创建
	HRESULT hr = pModel.CreateInstance("XAJ.Model");       //使用ProgID创建

	//调用新安江模型
	pModel->Run(argv);

	return 0;
}
  1. 点击本地Windows调试器,成功调用新安江模型COM组件。在x64\Debug\文件夹内生成流域出口流量过程Q.txt,但由于该路径下没有新安江模型的输入文件,所以Q.txt为空文件,文件大小为0KB。
    在这里插入图片描述
  2. 在该路径下创建如下图5个新安江模型输入文件,再点击本地Windows调试器或XAJCOMAPP.exe,即可生成流域出口流量过程Q.txt
    在这里插入图片描述
    在这里插入图片描述

5 参考资料

“类未注册(HRESULT异常:0x80040154(REGDB_E_CLASSNOTREG))”
lujiabo98/XAJCOMAPP
lujiabo98/XAJ
lujiabo98/XinanjiangModel

6 本机目录

创建和注册COM组件目录:E:\Research\XinanjiangModel\Myself\COM\XAJ\x64\Release
调用COM组件目录:E:\Master\study\Cpp\XAJCOMAPP\x64\Debug

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

卢家波

如果对你有帮助,请我喝杯茶吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值