C#作为GUI开发工具,C++作为业务核心模块的实现方式记录

news/2024/12/5 9:10:06/

C#作为GUI开发工具,C++作为业务核心模块的实现方式记录

  • 方式一、利用命名管道实现
  • 方式二、利用SWIG转换C++代码调用

这里主要技术基础就是要实现C#调用C++的dll。
这里主要讲几种方式:

方式一、利用命名管道实现

  1. 主要原理:

C++业务端作为命名管道服务端,负责监听C#的GUI客户端发送的命名管道命令

这里需要注意的点是

a.管道路径规则:
// .: 表示当前计算机
// 注:windows中VC++管道创建放到 …pipe\的路径下
// windows中C#管道创建不需放到 …pipe\的路径下
// e.g. VC++ \\.\pipe\testPipe <==> C# \\.\testPipe

  1. C++命名管道服务端实现
///
/// serverName: 服务端主机地址 默认"."表示当前主机
/// pipeName: 命名管道名字 不能为空
/// bMultiPipe: 是否可以多线程监听多个客户端
///
int Listen(const std::string& serverName, const std::string& pipeName, bool bMultiPipe)
{
#ifdef WIN_USE// 1.组装管道路径// e.g. \\\\.\\pipe\\testPipe std::string pipe;if (serverName.empty()) {pipe.assign("\\\\.\\pipe\\"s);}else {pipe.assign("\\\\"s).append(serverName).append("\\pipe\\"s);}pipe.append(pipeName);// 2.监听业务::HANDLE hPipe;BOOL bConnected;while (true) {// 2.1.创建命名管道Windows句柄hPipe = ::CreateNamedPipeA(pipe.c_str(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, PIPE_CELL_BUFFER_SIZE, PIPE_CELL_BUFFER_SIZE, 0, NULL);// 2.2.等待客户端的连接 此处存在阻塞 直到有客户端连接// Wait for the client to connect; if it succeeds,   // the function returns a nonzero value. If the function  // returns zero, GetLastError returns ERROR_PIPE_CONNECTED. bConnected = ::ConnectNamedPipe(hPipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED); // 当没有客户端连接的时候 ConnectNamedPipe会阻塞等待客户端连接if (bConnected) {// 2.3.阻塞等待接收客户端发送的数据// 此处实现考虑:接收管理上下文的事件,比如开启一个业务通讯、结束服务端等std::byte buffer[bytes] = {0};	// 接收数据的缓冲DWORD nReadBytes;	// 表示当前实际接收到的数据的字节大小::ReadFile(hPipe, buffer, bytes, &nReadBytes, NULL);// 2.4.处理管理上下文的事件std::string event = parse_event(buffer);if (event = "start service") {// Interaction: 业务通讯处理// 也是通过::ReadFile接收客户端发送的业务事件// 也是通过::WriteFile响应客户端结果if (!bMultiPipe) {// 只能单个实例// 开始业务通讯交互Interaction(hPipe);	//	业务通讯处理continue;}// 多个实例支持// Create a thread for this client.   std::thread hThread(&Interaction, this, hPipe);HANDLE thHand = hThread.native_handle();::SetThreadPriority(thHand, THREAD_PRIORITY_HIGHEST);hThread.detach();}// 2.5.响应客户端处理结果std::byte responseBuffer[responseByteSize]; // 响应缓冲DWORD cbWritten;	// 表示实际发送的数据::WriteFile(hPipe, responseBuffer, responseByteSize, &cbWritten, NULL);}}
#endif  // WIN_USE
}
  1. C#命名管道客户端实现
// 1.创建命名管道句柄
// e.g. \\\\.\\pipe\\testPipe 
// 等价于C++的::CreateNamedPipeA("\\\\.\\pipe\\testPipe ",...)
var pipeClient = new NamedPipeClientStream(".","testPipe",PipeDirection.InOut
);// 2.连接服务端
// 客户端发起连接请求 C++服务端::ConnectNamedPipe阻塞直到此连接成功
pipeClient.Connect();using (StreamReader sr = new StreamReader(pipeClient))
{// 3.向服务端发送数据var data = new byte[10240];data = System.Text.Encoding.Default.GetBytes("send to server");pipeClient.Write(data, 0, data.Length);// 4.接收服务端的响应string temp;while ((temp = sr.ReadLine()) != null) ;
}

方式二、利用SWIG转换C++代码调用

SWIG如何实现让C#调用C++的dll,原理是使用C#的互操作技术P/Invoke,SWIG在此基础上对C++代码进行的包装,使开发者更易于调用。

这里需要注意的点是

a.只需用SWIG重新生成接口dll:
e.g. C#GUI.exe --》 C++ facade.dll --》C++ kernel.dll
上述例子只需用SWIG来操作facade.dll

假设C#GUI.exe,C++ facade.dll,C++ kernel.dll,在VS中已经写好代码:
其中C++ facade.dll组织形式如下:

C++ facade.dll
Facade.h
Facade.cpp
  1. 自定义一个example.i文件,用于SWIG自动生成调用的代码文件
    example.i内容如下:
/*--- File: example.i ---*/
%module invoke_dll_name
%{
#include "Facade.h"	
%}%include "std_string.i"
%include "Facade.h"

%module invoke_dll_name: 表示C#调用C++的dll名字
%{}%: 表示C#需要调用的C++函数、变量、类等类型申明
%include指需要进行分装的类型,std_string.i是SWIG封装好的用来处理C++的std::string。此处也表示路径,比如std_string.i位于SWIG的上下文环境下,Facade.h必须位于example.i同级别目录(可将Facade.h单独拷贝到example.i所在目录)

  1. SWIG启动,调用example.i,自动生成调用代码文件
    SWIG命令:

swig -c++ -csharp example.i

生成结果:

Facade_wrap.cxx: // 添加到C++ facade.dll模块后,重新编译,自动生成C#可调用的dll程序集
facade.cs
facadePINVOKE.cs
FacadeClass.cs // *.cs文件,添加到C#GUI.exe模块后,即可调用C++的功能

  1. 重新配置C++ facade.dll代码组成
    将2步骤生成的Facade_wrap.cxx添加到此模块,重新编译生成。
    此时C++ facade.dll组织形式如下:
C++ facade.dll
Facade.h
Facade.cpp
Facade_wrap.cxx
  1. 重新配置C#GUI.exe,将2步骤生成所有*.cs文件添加到此项目,即可调用C++的功能
  2. 编译运行。
    这里需要注意:

需要将所有C++依赖的相关dll都拷贝到GUI.exe所在目录,否则不能执行

运行报错的常见原因:

  • BadImageFormatException: 试图加载格式不正确的程序
    原因:一般情况是,C++的dll是64位,但是 C#GUI.exe编译时设置了“Any CPU”的目标平台来生成
    解决:C#GUI.exe编译设置目标平台与C++的dll保持一致
  • DllNotFoundException: 无法加载 DLL“xxx”:
    原因:一般情况是,没有将C++ facade.dll拷贝到C#GUI.exe所在目录,或者没有将C++ facade.dll依赖的dll拷贝到C#GUI.exe所在目录
    解决:先用Dependency查看缺失的依赖,补齐C++的dll

http://www.ppmy.cn/news/319483.html

相关文章

华为哪些手机可以升级到鸿蒙系统,终于来了!华为手机6月可升级到鸿蒙OS系统,什么是华为鸿蒙系统?...

近日&#xff0c;华为消费者业务软件部总裁、AI与智慧全场景业务部部长王成录博士在”压力下前行“TEDxHouHai大会下发表了以“联接让生活更简单”为主题的演讲&#xff0c;谈到了如今手机行业的现状与对未来的展望&#xff0c;同时也提及到了鸿蒙系统的相关信息。 王成录谈到&…

差动保护原理

差动保护是输入的两端CT矢量差&#xff0c;当达到设定的动作值时启动动作元件。保护范围在输入的两端CT之间的设备&#xff08;可以是线路&#xff0c;发电机&#xff0c;电动机&#xff0c;变压器等电气设备&#xff09; 什么是差动保护 电流差动保护是中的一种保护。正相序是…

android锁屏自动清理,越用越快!华为P10为你锁屏自动清理后台缓存

对于很多安卓手机用户来说&#xff0c;经常会面临手机配置本来挺不错但使用一段时间后就会出现变慢或卡顿的现象&#xff0c;而且耗电量也会越来越快。随着手机应用的越来越丰富&#xff0c;我们的手机里也会经常充满了各种APP呈现&#xff0c;大量APP应用会偷偷在后台运行并且…

华为p10计算机器在哪,华为p10怎么打开屏幕朗读器

大家好&#xff0c;我是时间财富网智能客服时间君&#xff0c;上述问题将由我为大家进行解答。 华为p10打开屏幕朗读器的步骤是&#xff1a; 1、首先在手机桌面打开“设置”。 2、在“设置”中&#xff0c;向上滑动&#xff0c;找到并点击“辅助功能”。 3、点开“智能辅助”之…

华为P10手机有计算机功能吗,手机教程知识:华为P10支持NFC功能吗 华为P10新功能介绍...

在生活和工作中&#xff0c;电脑和手机已成为不可或缺的必备工具&#xff0c;关于电脑和手机上的一些程序很多小伙伴经常都会遇到一些疑难杂症&#xff0c;关于大家提到的关于华为P10支持NFC功能吗 华为P10新功能介绍这方面的问题&#xff0c;小编整理了一些相关的讯息。 华为P…

华为鸿蒙P10plus,华为P10深度评测:徕卡双摄拍照逆天!

华为P10深度评测&#xff1a;徕卡双摄拍照逆天&#xff01;2017年2月26日&#xff0c;华为新旗舰P10在巴塞罗那世界移动通信大会上正式亮相。 P系列是华为智能手机产品中定位时尚精致的高端产品线&#xff0c;全新的P10延续了P系列的经典设计基因(6.98mm的超薄机身、丰富多彩的…

emui华为java2p_大文件包来了!两款华为手机依然在更新,EMUI两大功能很实用

原标题&#xff1a;大文件包来了&#xff01;两款华为手机依然在更新&#xff0c;EMUI两大功能很实用 当硬件遇到瓶颈的时候&#xff0c;很多厂商开始回调&#xff0c;作为手机重要的一环系统体验尤为关键。2020年都在拼旗舰配置、强悍拍照、5G覆盖&#xff0c;但普通用户对于手…

android p 华为,华为真良心,首批Android P升级名单曝光,这些机型有福了

原标题&#xff1a;华为真良心&#xff0c;首批Android P升级名单曝光&#xff0c;这些机型有福了 目前&#xff0c;谷歌已经提前推送了Android 9.0的正式版。在推出之后不久就有小米&#xff0c;一加等厂商对自家的新品手机推送了尝鲜版&#xff0c;这也让一大批粉丝欣喜不已。…