问题描述

今天在做项目的时候碰到一个问题,就是用C++编写CLR类库dll的时候,C++的函数参数列表中包含一个char*的输出型参数,然而在C#调用该dll时候,会自动将函数的中的char*参数“翻译”为sbyte*, 使用了各种方法都不能调用函数,主要是不能合适的转换为sbyte*。

简单示例

举个简单的例子,比如我有一个CLR的类库为MyDll.dll, 其中头文件为Mydll.h,简单的只有一个函数,其中我想要为char*的作为输出参数, 代码如下

 // MyDll.h

 #pragma once
#include <cstdio>
#include <cstring>
using namespace System; namespace MyDll { public ref class MyClass
{
// TODO: 在此处添加此类的方法。
public:
MyClass()
{}
public:
static bool TestFunc(char* outPutStr, int *p)
{
*p = ;
char* s = "Hello world";
strcpy_s(outPutStr, , s);
return true;
}
};
}

源文件内容MyDll.cpp为空。【生成解决方案】后,得到MyDll.dll库。

 // 这是主 DLL 文件, MyDll.cpp

 #include "stdafx.h"

 #include "MyDll.h"

然后新建一个C# WPF项目,右键 【引用】->【添加引用...】->左侧Tab【浏览】->右下角【浏览...】选择刚才生成的 MyDll.dll 文件后,点击【确定】。这样我们就可以在WPF项目中调用 TestFunc 函数了。

我们在 WPF 的 MainWidnow 中随便加入一个 Button,然后在 Button 的 Click 事件中尝试调用 TestFunc 函数,Mainwindow 的 cs 文件如下:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Runtime.InteropServices; namespace MyWPF
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
} private void Button_Click(object sender, RoutedEventArgs e)
{
unsafe
{
string str = new string('A', );
IntPtr intPtrStr = (IntPtr)Marshal.StringToHGlobalAnsi(str);
sbyte* sbyteStr = (sbyte*)intPtrStr; int p = ;
MyDll.MyClass.TestFunc(sbyteStr, &p); String tmp = new String(sbyteStr);
MessageBox.Show(tmp);
MessageBox.Show(p.ToString());
}
}
}
}

注意引入第 15 行的命名空间, 同时【项目】->【属性】->【生成】->勾选 【允许不安全代码】。 主要转换的部分出现在 33-35 行,首先建立一个普通的 string 变量,然后新建一个指针,指向该 string的内容,再讲该指针强制类型转化为sbyte*, 从而实现从 char* 中获取内容。

问题讨论

问题1: 为什么 C# 会将 C++ 中的 char* 转换为 sbyte* 呢?

这是因为 C++ 中的 char 占用一个字节,而 C#中 char 占用两个字节,所以不能讲 char* 直接转换为 C# 中的 char*,  而 sbyte 是有符号单字节,取值区间 [-128, 127],所以 C# 将 char* 转换成 sbyte* 是合理的。

问题2:CLR 的 dll 和普通的 dll (Native dll) 有什么区别呢?

CLR 有点类似于 java 的 “虚拟机” , 提供运行环境,负责检查 内存管理、安全、异常等比较容易出错的问题,提高程序的安全性和健壮性,是 .NET Framework 的主要引擎。在 CLR 监视下的代码称为 “托管代码 (managed)”,  而其他的不在其监管下的代码称为 “非托管代码 (unmanaged)”。在 CLR 环境下生成的代码是中间代码,有点类似于 java 的字节码。所以通过 CLR Dll 生成的 dll 类库是中间代码,普通的 dll 则是直接是本机化的二进制文件, 通过 CLR DLL 生成的 dll 是程序集 (Assembly), 可以在直接在C#工程中【添加引用】就可以直接调用,从前面的例子也可以看出来,不需要任何的 DllImport 之类的包含与结构体重定义,函数指针定义等等复杂的操作,使得调用更加简单。

源码下载

http://files.cnblogs.com/files/python27/MyWPF.zip

http://files.cnblogs.com/files/python27/MyDll.zip

C# 调用C++ CLR dll类库时,实现从 string 到 sbyte* 的转换的更多相关文章

  1. PB调用C#编写的Dll类库

    在c# 中编写com组件,供PB调用实例 前言:c#中写的dll直接是不能被pb调用的,只有写成com组件才可以调用,所以用c#写dll时要注意. c#中新建类库 类库类型为通用类库,项目名为AddC ...

  2. 利用C#的反射机制动态调用DLL类库

    最近由于业务要求,需要动态调用DLL类库,所以研究了一下,感觉还好也不太难,今天就把自己理解的写了一个小例子(已经通过VS2005跑通),供大家一起研究和探讨,有理解不当的地方还请高手们多多指正,谢谢 ...

  3. CLR调试时的sos.dll/clr.dll/mscorwks.dll/mscordacwks.dll等动态库的版本对应

    大家都知道,在调试托管代码时,一定会加载到sos/clr/mscorwks/mscordacwks这些动态库,才能够很好的完成我们的调试工作,那么他们的版本对应关系是怎样的呢,特别是clr.dll/m ...

  4. .Net DLL类库引用时没有注释信息

    自己编写的类库提供给别人引用时,别人获取不到DLL内部的方法.变量的注释信息,无法了解内部情况和使用方法. 原因:没有随DLL类库一同输出注释文档 解决方案: 在VS界面中选中提供给别人的类库项目 在 ...

  5. C#创建dll类库

    类库让我们的代码可复用,我们只需要在类库中声明变量一次,就能在接下来的过程中无数次地使用,而无需在每次使用前都要声明它.这样一来,就节省了我们的内存空间.而想要在类库添加什么类,还需取决于类库要实现哪 ...

  6. 浅谈C++调用C#的DLL程序方法

    把C#编译成DLL或者Axtive控件,再由C调用!比如使用C++调用C#的DLL. SwfDotNet是.net下输出flash的类库.SwfDotNet是C#编写的,作者的C#水平,真是令我佩服. ...

  7. 在C#调用C++的DLL方法(二)生成托管的DLL

    写操作之前,还是扼要的说一下托管与非托管C++的区别好了,其实我也并没有深入了解过托管C++的特点所在,其最大的特征就是可以由系统来调试回收相关的代码资源,跟C#的特性一样,只是编程风格跟C++类似而 ...

  8. java调用C#的dll

    链接地址:http://www.cnblogs.com/yinhaiming/articles/1712463.html .net产生的比java晚,其类库的封装在某些方面也比java更优秀,更全面. ...

  9. Python调用C# Com dll组件实战

    之前公司有套C# AES加解密方案,但是方案加密用的是Rijndael类,而非AES的四种模式(ECB.CBC.CFB.OFB,这四种用的是RijndaelManaged类),Python下Crypt ...

随机推荐

  1. php 利用迭代器遍历文件夹

    1.遍历文件夹 scandir 2.原生的迭代器Iterrate $scan_dir = "txtDir"; //下面会遍历txtDir 下面所有字文件夹中的文件哦 $dir_it ...

  2. AtomEye的使用

    网易博客粗略地在转载的基础上对AtomEye补充了概述: AtomEye: Atomistic configuration viewer developed by J. Li. This progra ...

  3. oracle 使用正则表达式获取字符串中包含的数字

    select REGEXP_REPLACE('字符串中包含的数字123,提取后就是123', '[^0-9]', '') from dual;

  4. 什么是Shell、Shell脚本

    Shell本身是一个用C语言编写的程序,它是用户使用Linux的桥梁.Shell既是一种命令语言,又是一种程序设计语言.作为命令语言,它交互式地解释和执行用户输入的命令:作为程序设计语言,它定义了各种 ...

  5. MVC仓储执行存储过程报错“未提供该参数”

    今天做的时候出现错误: "过程或函数 'sp_ProcName' 需要参数 '@uid',但未提供该参数. 可是我参数都传了,然后调试也是一样,然后对照参数列表, 后来发现执行的时候还要加入 ...

  6. 测试rar/bz2/tar.gz/gz压缩文档完整性

    #gz文件gzip -t *.gz#bz2文件tar jtvf archive.tar.bz2#tar.gz文件tar jtvf archive.tar.gz#rar文件unrar t 1.rar

  7. JavaScript跨域总结与解决办法(转)

    什么是跨域 1.document.domain+iframe的设置 2.动态创建script 3.利用iframe和location.hash 4.window.name实现的跨域数据传输 5.使用H ...

  8. PHP-GTK的demo在windows下运行出现的问题

    I am trying to use Firebird 2.5.2.26539 with wamp,When i enable the extensions of firebird in php: - ...

  9. 白盒静态自动化测试工具:PMD使用指南

    参考文献:http://www.oschina.net/p/pmd/http://www.cnblogs.com/flyme/archive/2011/09/09/2172548.htmlhttp:/ ...

  10. OSGi 系列(十六)之 JDBC Service

    OSGi 系列(十六)之 JDBC Service compendium 规范提供了 org.osgi.service.jdbc.DataSourceFactory 服务 1. 快速入门 1.1 环境 ...