用C#掉用C++的dll直接import就可以之前有不同的类型对应,当要传递结构体的时候就有点麻烦了,这里有一个结构体里边有char*类型,这个类型在C#中调用没法声明,传string是不行的默认string是对应const char*,传stringbuilder得指定大小,不然是没法传的,

查了好久,最后只能用unsafe代码来实现了

用C/C++写一个标准的动态链接库:

头文件,定义了三个接口函数,

#pragma once
#define TESTDLL _declspec(dllexport) #ifndef PKI_DATA_ST
#define PKI_DATA_ST
typedef struct PKI_DATA_st {
int size;
char *value;
}PKI_DATA, *PKI_PDATA;
#endif extern "C"
{
TESTDLL double Add(double a, double b); TESTDLL double Subtract(double a, double b); TESTDLL int TestDn(PKI_DATA cert, PKI_DATA* dn); }

简单实现:

#include "stdafx.h"
#include "TestClass.h" double Add(double a, double b)
{
printf("Add \n");
return a + b;
} double Subtract(double a, double b)
{
printf("Subtract");
return a - b;
} int TestDn(PKI_DATA cert, PKI_DATA* dn)
{
printf("TestDn cert.value: %s\n", cert.value);
dn->size = ;
//dn->value = "helloworld"; //这个种写法需要转换
dn->value =(char*) TEXT("helloworld");//这种写法在选择unicode字符集时C#是可以直接接受的
return ;
}

C#调用,路径可以用当前程序的相对路径,也可以是系统的环境变量中的路径,声明import

        [DllImport("USBLoad.dll", EntryPoint = "Add", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
static extern double Add(double a,double b); [DllImport("USBLoad.dll", EntryPoint = "TestDn", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
static extern int TestDn(PKI_DATA cert, ref PKI_DATA dn); [DllImport("USBLoad.dll", EntryPoint = "Subtract", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
static extern double Subtract(double a, double b);

声明结构体:

        internal unsafe struct PKI_DATA
{
internal int size;
internal char* value;
}

调用:记得属性中勾上允许不安全代码

       [HandleProcessCorruptedStateExceptions]//这个可以捕获C++中的异常 
    [SecurityCritical]
static unsafe void TestUSBLoad()//加unsafe
{
try
{
var a = Add(, );
w(a);
a = Subtract(, );
w(a); PKI_DATA cert = new PKI_DATA();
cert.size = ;
char[] test = "test".ToCharArray();
string s = "";
fixed (char * v=test)//传值初始化。需要fixed关键字
{
cert.value = v;
PKI_DATA dn = new PKI_DATA();
TestDn(cert, ref dn);
var encode = Encoding.ASCII;
var c = dn.value;
List<char> list = new List<char>();
for (int i=;i<dn.size;++i,++c)
{
list.Add(*c);
}
            //兼容ansi编码,先转byte
var bytes = Encoding.Unicode.GetBytes(list.ToArray());
s = Encoding.ASCII.GetString(bytes);//转码
w(new string(dn.value));//设置unicode字符集的情况下可以直接这么写就能得到要字符
}
s = s.Replace("\0","");//转码的时候后边会有很多\0,移除
w(string.Format("[{0}]",s)); }
catch (Exception ex)
{
w(ex.Message);
} }

顺便研究了下C++的动态调用、

如果是静态调用需要头文件和lib库,直接引用头文件,加入lib的链接路径,引用后可以直接用,编译就可以了

动态调用用loadlibrary,记得freelibrary,这些函数在windows.h中,这里建的是QT的项目所以引用的是qt_windows.h:

#include "qt_windows.h"

#define DLLPATH  (LPCTSTR)"USBLoad.dll"

#ifndef PKI_DATA_ST
#define PKI_DATA_ST
typedef struct PKI_DATA_st {
int size;
char *value;
}PKI_DATA, *PKI_PDATA;
#endif //声明入口函数
typedef double(*Add_Func)(double, double); typedef int(*TestDn)(PKI_DATA, PKI_DATA*); int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv); qDebug() << "hello world!";
HINSTANCE m_hModule = LoadLibrary(DLLPATH);//加载dll
if (m_hModule == NULL)
{
printf("LoadLibrary %s failed,err %d\n", DLLPATH, GetLastError());
goto END;
}
Add_Func add;
add = (Add_Func)GetProcAddress(m_hModule,"Add");//获取方法地址,后边调用
double c = add(, );
printf("Add_Func: %lf \n", c);
TestDn test;
test = (TestDn)GetProcAddress(m_hModule, "TestDn");
PKI_DATA cert;
PKI_DATA dn;
cert.size = ;
cert.value = (char*)"test";
int res = test(cert, &dn);
printf("TestDn:%s\n", dn.value); END:
if (m_hModule != NULL)
{
FreeLibrary(m_hModule);
m_hModule = NULL;
printf("FreeLibrary\n");
}
return a.exec();
}

关于怎么把char*转码到正确的编码格式下的C#string,

 char* cchar=data
IntPtr value = new IntPtr(cchar);
var s = Marshal.PtrToStringAnsi(value);

可以用上边的方法,看fcl的源码可以看到上边的方法实质是把char*强转为sbyte*,然后直接new string,这样可以避免C++和C#的byte差异

marshal还有touni的方法,只转unicode的方法,实质是直接用char* new string,

char*和sbyte*两种初始化参数string类型都接受。

C# 调用C/C++动态链接库,结构体中的char*类型的更多相关文章

  1. C/C++中指向结构体变量的指针,调用指向的那个结构体中的成员

    设p是指向结构体变量的指针,则可以通过以下的方式,调用指向的那个结构体中的成员: (1)结构体变量.成员名.如,stu.num. (2)(*p).成员名.如,(*p).num. (3)p->成员 ...

  2. C语言 结构体中的零长度数组

    /* C语言零长度数组大小和取值问题 */ #include <stdio.h> #include <stdlib.h> #include <string.h> s ...

  3. C结构体中数据的内存对齐问题

    转自:http://www.cnblogs.com/qwcbeyond/archive/2012/05/08/2490897.html 32位机一般默认4字节对齐(32位机机器字长4字节),64位机一 ...

  4. C#调用C++ dll时,结构体引用传参的方法

    写了一个C++的LogLog Logit 四参数等算法的接口dll,给C#调用,但是发现传参有问题 如 extern "C" _declspec(dllexport)  bool ...

  5. C#调用C++DLL传递结构体数组的终极解决方案

    在项目开发时,要调用C++封装的DLL,普通的类型C#上一般都对应,只要用DllImport传入从DLL中引入函数就可以了.但是当传递的是结构体.结构体数组或者结构体指针的时候,就会发现C#上没有类型 ...

  6. 绝对好文C#调用C++DLL传递结构体数组的终极解决方案

    C#调用C++DLL传递结构体数组的终极解决方案 时间 2013-09-17 18:40:56 CSDN博客相似文章 (0) 原文  http://blog.csdn.net/xxdddail/art ...

  7. C++结构体中sizeof(1)

    sizeof sizeof操作符的作用是返回一个对象或类型名的长度,长度的单位是字节. 返回值的类型是标准库命名为size_t的类型,size_t类型定义在cstddef头文件中,该头文件是C标准库的 ...

  8. C语言中free()函数释放struct结构体中的规律

    并不是什么新鲜的事情,不过值得注意.首先我们知道,在使用struct来定义并声明一个变量时,将会自动划分出一个连续的储存空间(虽然根据某些对齐原则会出现内存间隙,但是大体上来说还是连续的)这一块连续空 ...

  9. golang 结构体中的匿名接口

    golang 结构体中的匿名接口 代码示例 golang 中,可以给结构体增加匿名field,可参考 unknwon 大神的书. 匿名字段和内嵌结构体 但,golang同时也可以给结构体定义一个匿名i ...

随机推荐

  1. 基于注解的Spring容器源码分析

    从spring3.0版本引入注解容器类之后,Spring注解的使用就变得异常的广泛起来,到如今流行的SpringBoot中,几乎是全部使用了注解.Spring的常用注解有很多,有@Bean,@Comp ...

  2. 人工鱼群算法超详细解析附带JAVA代码

    01 前言 本着学习的心态,还是想把这个算法写一写,给大家科普一下的吧. 02 人工鱼群算法 2.1 定义 人工鱼群算法为山东大学副教授李晓磊2002年从鱼找寻食物的现象中表现的种种移动寻觅特点中得到 ...

  3. docker微服务部署之:四、安装docker、docker中安装mysql和jdk1.8、手动构建镜像、部署项目

    docker微服务部署之:三,搭建Zuul微服务项目 1.Centos7安装Docker 详见:Centos7安装Docker 2.Docker中安装jdk1.8 详见:使用Docker构建jdk1. ...

  4. linux克隆后修配置

    第一步:克隆 第二步:vi /etc/sysconfig/network-scripts/ifcfg-eth0   编辑 DEVICE=eth0 TYPE=Ethernet ONBOOT=yes NM ...

  5. jQuery 事件注册

    重点事件注册.on() <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset= ...

  6. 网络编程-echo服务器

    代码: #coding="utf-8" #name=echo服务器 from socket import * #1.创建套接字 udpSocket = socket(AF_INET ...

  7. python全栈开发学习_内容目录及链接

    python全栈开发学习_day1_计算机五大组成部分及操作系统 python全栈开发学习_day2_语言种类及变量 python全栈开发_day3_数据类型,输入输出及运算符 python全栈开发_ ...

  8. Hibernate查询方式&抓取策略

    Hibernate的查询方式 1.OID查询 hibernate根据对象的OID(主键)进行检索 使用get方法 Customer customer=session.get(Customer.clas ...

  9. win7 免安装MariaDB

    1.  官网下载MariaDB的windows版本 地址:https://downloads.mariadb.org/mariadb/10.0.17/ 目前最新版本是10.0.17 2.  下载完成后 ...

  10. linux常用多线程下载工具

    1.axel 下载安装yum install axel 这个软件下载速度实时显示