用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. eclipse如何汉化,把eclipse改成中文版

    eclipse默认是英文版的,对于中国人来说使用英文语言的软件是件痛苦的事情.下面我来详细说一下如何把eclipse改成中文版的. 工具/原料   eclipse英文版 eclipse中文插件 方法/ ...

  2. 使用unordered_map提升查找效率

    在对网络数据包流(Flow)进行处理的时候,一开始为了简单使用了vector做为Flow信息的存储容器,当其中的元素达到几十万时,程序的执行速度让人无法忍受.已经对vector进行过合理的预先rese ...

  3. Linux 环境变量加强

    Linux 环境变量加强 # 前言 今天,主要是之前搭建 GO 环境包的使用发现自己对 Linux 环境变量还不是很熟悉. 遇到环境变量的问题还是会有些懵逼.所以,今天写点Linux 环境变量的文章, ...

  4. MySQL之查看数据库编码

    MySQL之查看数据库编码

  5. mysql工具——perror(mysql错误代码,查看错误号释义)

    mysql工具——perror(mysql查看错误代码,查看错误号释义) 关键词:mysql错误代码,mysql错误号,perror

  6. [HNOI2019]鱼

    Luogu5286 \(2019.4.14\),新生第一题,改了\(3\)个小时 题解-租酥雨,和出题人给的正解一模一样 枚举\(AD\),分别考虑鱼身\(BC\)和鱼尾\(EF\) 到\(E\),\ ...

  7. Maven 安装jar文件到本地repository

    Reference: https://maven.apache.org/general.html#importing-jars mvn install:install-file \ -Dfile=&l ...

  8. gerapy的初步使用(管理分布式爬虫)

    一.简介与安装 Gerapy 是一款分布式爬虫管理框架,支持 Python 3,基于 Scrapy.Scrapyd.Scrapyd-Client.Scrapy-Redis.Scrapyd-API.Sc ...

  9. 比特 字节 兆 GB转换

    bit:比特byte:拜特(字节) 1字节=8比特k:千KB:千字节 1KB = 1024 byteMB:兆字节GB:千兆字节 //少用 Kb:千比特 Mb:兆比特 Gb:千兆比特

  10. vertical-aligin

    垂直对齐元素只应用于行内元素(图像.文本)和表单元素 垂直对齐文本会影响行高 默认值为baseline