首页 > 编程语言 >通过C++/CLR封装的方式使非托管的C++、VB6.0调用.Net托管代码

通过C++/CLR封装的方式使非托管的C++、VB6.0调用.Net托管代码

时间:2023-05-18 17:12:10浏览次数:44  
标签:使非 托管 NetApiClr C++ dll api Net GetData

通常.Net的dll只能被加载到对应的虚拟机中运行和调用,而无法直接被低版本的.Net或C++和VB6.0等非托管代码调用。但是实际项目开发过程中我们为了兼容,不得不同时支持这些非托管代码或低版本的运行时。实际上微软提供了多种方式可以实现这种需求,如进程间通讯、COM/ActiveX、C++/CLR。本文主要介绍通过C++/CLR包装方式,实现非托管代码访问托管C#.Net调用。简单调用顺序如下图所示。

 

目标C#.Net类库

假设我们有一个目标C#.Net类库,提供以下两个api:

public bool CreateConnection()
public string GetData(string key)

 

创建C++/CLR包装类库

该类库是一个可以跟C#.Net dll互通的公共语言类库,跟C#.Net dll的区别在于他是用c++编写的,对外暴露c语言类api。非托管代码通过P/Invoke的方式实现函数调用。

  • 在Visual Studio新建一个C++/CLR类库

  • 引用目标C#.Net类库

项目右击->属性->公共属性->引用->添加NetApi.dll进入引用

 

  •  编写api的包装类ApiWrapper

这个包装类用于封装对C#.Net dll的调用,本例中维护了目标api类的一个实例,只是简单实现了功能,实际项目中应注意需要更多的异常处理。

NetApiClr.h

// NetApiClr.h

#pragma once

using namespace System;

namespace NetApiClr {

	public ref class ApiWrapper
	{
	public:
		ApiWrapper();
		bool CreateConnection();
		String ^ GetData(String ^);

	private:
		NetApi::DataHelper ^ dataHelper = nullptr;
	};
}

 NetApiClr.cpp

// This is the main DLL file.

#include "stdafx.h"

#include "NetApiClr.h"

NetApiClr::ApiWrapper::ApiWrapper()
{
	dataHelper = gcnew NetApi::DataHelper();
}

bool NetApiClr::ApiWrapper::CreateConnection(){
	return dataHelper->CreateConnection();
}

String ^ NetApiClr::ApiWrapper::GetData(String ^ key)
{
	return dataHelper->GetData(key);
}
  •  编写api入口

这个入库对外暴露了c语言类的api,以便三方程序可以像调用win32接口那样通过P/Invoke的方式调用这些api。

#include "stdafx.h"
#include "NetApiClr.h"
#include <msclr/gcroot.h>

using namespace System;
using namespace std;
using namespace Runtime::InteropServices;

ref class ManagedGlobals abstract sealed {
public:
	static NetApiClr::ApiWrapper ^ apiWrapper = gcnew NetApiClr::ApiWrapper();
};

extern  "C" _declspec(dllexport) bool _stdcall CreateConnection()
{
	return ManagedGlobals::apiWrapper->CreateConnection();
}

extern  "C" _declspec(dllexport) char* _stdcall GetData(char* cKey)
{
	String^ key = gcnew String(cKey);
	String^ strResult = ManagedGlobals::apiWrapper->GetData(key);
	char* cResult =
		(char*)(Marshal::StringToHGlobalAnsi(strResult)).ToPointer();
	return cResult;
}
  •  编写并配置DEF文件

模块定义或 DEF 文件 (*.def) 是一种文本文件,其中包含一个或多个描述 DLL 各种属性的模块语句。

NetApiClr.def

LIBRARY      "NetApiClr"

EXPORTS
    ; Explicit exports can go here
   CreateConnection @1
    GetData @2

 

配置DEF文件

项目右击->属性->配置属性->连接器->输入->在模块定义文件选择中填写你编写的描述文件

C++ demo

  • 定义api函数指针
typedef bool (WINAPI *pCreateConnection)();
typedef char* (WINAPI *pGetData)(char*);
  • 加载C++/CLR dll和函数
//load dll
HINSTANCE hInst=LoadLibrary(_T("NetApiClr.dll"));
//import api pCreateConnection FuncCreateConnection = nullptr; pGetData FuncGetData = nullptr; FuncCreateConnection = (pCreateConnection)GetProcAddress(hInst, "CreateConnection"); FuncGetData = (pGetData)GetProcAddress(hInst, "GetData");
  • 调用函数
if (FuncCreateConnection())
{
	::MessageBoxA(NULL, FuncGetData("abcd"), "Demo Code", MB_OK);
}
else
{
	::MessageBoxA(NULL, "ERROR", "Demo Code", MB_OK);
}
  • 释放dll句柄
//free dll
FreeLibrary(hInst);

VB6.0 demo

  • 加载C++/CLR dll并定义api
Public Declare Function CreateConnection Lib "NetApiClr.dll" () As Boolean
Public Declare Function GetData Lib "NetApiClr.dll" (ByVal message As String) As String
  • 调用api
If CreateConnection Then
	MsgBox GetData("abcd")
Else
	MsgBox "Error"
End If

 

参考:

 

转载请注明出处: https://www.cnblogs.com/keitsi/p/17102345.html

标签:使非,托管,NetApiClr,C++,dll,api,Net,GetData
From: https://www.cnblogs.com/keitsi/p/17102345.html

相关文章

  • ffmpeg实现的C++纯音频软解码器
    只实现解码,不包含前置的demux,以及后置的resample要求输入demux后的音频数据实现的C++类如下:AudioSoftDecoder.h:#ifndef_AUDIOSOFTDECODER_H_#define_AUDIOSOFTDECODER_H_#include<stdio.h>#include<stdlib.h>#include<string.h>#include<vector>extern"C&......
  • C++ ffmpeg硬件解码的实现方法
    什么是硬件解码普通解码是利用cpu去解码也就是软件解码硬件解码就是利用gpu去解码为什么要使用硬件解码首先最大的好处快硬解播放出来的视频较为流畅,并且能够延长移动设备播放视频的时间;而软解由于软解加大CPU工作负荷,会占用过多的移动CPU资源,如果CPU能力不足,则软件也将受......
  • c++程序流程结构
    c++程序流程结构c++中支持最基本的三种流程结构:顺序结构、选择结构、循环结构顺序结构:程序按顺序执行,不会发生跳转。选择结构:根据条件是否满足,有选择的执行相应的功能。循环结构:根据条件是否满足,循环多次执行某代码块。if语句:作用:执行满足条件的语句单行if语句:语法:if(条件){ 条件......
  • 初识c++
    c++开发环境搭建初识c++第一个c++程序c++程序框架:实例:#include<iostream>usingnamespacestd;intmain(){ system("pause"); return0;}//#include代表预处理指令iostream中声明了程序所需要的的输入和输出操作的有关信息#include<iostream>//usingnamespace针对命名......
  • c++ ffmpeg 推送rtsp码_编译ffmpeg以获得极佳性能
    背景Gemfield最近尝试使用python封装的ffmpeg库(PyAV)来进行mp4文件、rtmp协议及其它协议的decode,具体来说就是将mp4文件(或者rtmp协议的数据,下同)进行demux并逐帧decode。然而在这期间发现了一些decode的性能问题。这些问题概括起来就是2点:python封装的ffmpeg是否能够利用到多核CPU的......
  • 【C++】多态(下)
    @TOC1.单继承中的虚函数表整体代码#include<iostream>usingnamespacestd;classBase{public:virtualvoidFunc1(){cout<<"Base::Func1()"<<endl;}virtualvoidFunc2(){cout<<"Base::Func......
  • c++打卡第二十九天
    模板编程对于模板编程,写template<typenameT>一、函数模板编程1、编辑模板表明返回值T或者无返回值+函数名(T&变量) 2、例题描述请使用模板参数设计实现双倍功能函数,函数功能要求实现返回值为输入参数的两倍,函数参数应能适应整型、浮点型、双精度型等各种类型,返回值类型与......
  • 输入输出流(C++)
    一、问题描述定义一个Dog类,包括体重和年龄两个数据成员及其成员函数,声明一个实例dog1,体重5,年龄10,使用I/O流把dog1的状态写入磁盘文件。再声明一个实例dog2,通过读取文件dog1的状态赋给dog2。分别用文本方式和二进制方式操作文件。二、代码实现1#include<fstream>2#includ......
  • 2654. 使数组所有元素变成 1 的最少操作次数(c++,gcd性质)
    题目链接:2654.使数组所有元素变成1的最少操作次数方法一:计算最短的gcd为1的子数组解题思路本题目标:使得所有的数组元素都变为\(1\),通过求相邻元素\(gcd\)将其赋值给一方的方式;思路:若想操作数最少,那么就是不为\(1\)的数\(x\)和1求\(gcd\),即\(x=gcd(x,1)\),......
  • c++打卡练习(33)
    歌星大赛,十个评委打分,去掉一个最高分,去掉一个最低分,求剩下的八个评分的平均分,作为选手的最终分数流程图:伪代码:源代码:#include<iostream>usingnamespacestd;intmain(){ inta[10],b[8]; inti,j,k,t,sum=0,Ave,max,min; cout<<"输入十个正整数"<<endl; for(i=0;i<10;i++){ ......