小众知识

首页 > 编程开发 > C/C++ > C# > 正文

C#调用C++编写的DLL如何进行字符串传递
2016-08-03 22:19:43   来源:   评论:0 点击:

可以说新手使用P-INVOKE最开始的头疼就是C 和C++的字符串传递,因为这里涉及到两个问题。 第一:C 的string和C++的字符串首指针如何对应。 第二:字符串还有ANSI和UNICODE(宽字符串)之分。

说新手使用P-INVOKE最开始的头疼就是C#和C++的字符串传递,因为这里涉及到两个问题。
第一:C#的string和C++的字符串首指针如何对应。
第二:字符串还有ANSI和UNICODE(宽字符串)之分。
 
本文分三部分阐述:
第一:字符串指针当输入参数,
第二:字符串指针作为返回值,
第三:字符串指针作为输入输出参数。
 
C++++部分的测试代码很简单这里就全部贴出来了:
 
#include "stdafx.h"
#include "TestDll.h"
#include
#include
#include


staticchar *_hello = "Hello,World!!";
static TC++HAR *_helloW = TEXT("Hello,World!!");

void __stdcall PrintString(char *hello)
{
    printf("%s\n", hello);
}

void __stdcall PrintStringW(TC++HAR *hello)
{
    _tprintf(TEXT("%s\n"), hello);
}


char  *__stdcall GetStringReturn()
{
    return _hello;
}

TC++HAR *__stdcall GetStringReturnW()
{
    return _helloW;
}


void __stdcall GetStringParam(char *outHello, int len)
{
    //output "aaaaaaaa"
    for(int i = 0; i < len - 1 ; i++) outHello[i] = 'a';
    outHello[len - 1] = '\0';
}

void __stdcall GetStringParamW(TC++HAR *outHello, int len)
{
    //output "aaaaaaaa" unicode version.
    for(int i = 0; i < len - 1 ; i++) outHello[i] = TEXT('a');
    outHello[len - 1] = TEXT('\0');
}
 
 
 
下面看C#如何调用。
 
第一:字符串指针作为输入参数,可以使用byte[] 和MarshalAs来解决。(注意四个P-INVOKE,两个ANSI版本,和两个UNICODE版本),推荐使用MarshalAs方法简单明了。
 
[DllImport("TestDll", EntryPoint = "PrintString")]
public static extern void PrintStringByBytes(byte[] hello);

[DllImport("TestDll", EntryPoint = "PrintString")]
public static extern void PrintStringByMarshal([MarshalAs(UnmanagedType.LPStr)]string hello);

[DllImport("TestDll", EntryPoint = "PrintStringW")]
public static extern void PrintStringByBytesW(byte[] hello);

[DllImport("TestDll", EntryPoint = "PrintStringW")]
public static extern void PrintStringByMarshalW([MarshalAs(UnmanagedType.LPWStr)]string hello);


publicvoid Run()
{
    PrintStringByBytes(Encoding.ASCII.GetBytes("use byte[]"));
    PrintStringByMarshal("use MarshalAs");
    PrintStringByBytesW(Encoding.Unicode.GetBytes("use byte[]"));
    PrintStringByMarshalW("use MarshalAs");
}

 

第二:字符串指针作为返回值,和上面一样也有两种声明方法,同样也包含两个版本。注意:Marshal.PtrToStringAnsi()函数的使用,把字符串指针转变为C#的string.推荐使用MarshalAs方法简单明了。
 
[DllImport("TestDll", EntryPoint = "GetStringReturn")]
public static extern IntPtr GetStringReturnByBytes();

[DllImport("TestDll", EntryPoint = "GetStringReturn")]
[return: MarshalAs(UnmanagedType.LPStr)]
public static externstring GetStringReturnByMarshal();

[DllImport("TestDll", EntryPoint = "GetStringReturnW")]
public static extern IntPtr GetStringReturnByBytesW();

[DllImport("TestDll", EntryPoint = "GetStringReturnW")]
[return: MarshalAs(UnmanagedType.LPWStr)]
public static extern string GetStringReturnByMarshalW();


publicvoid Run()
{
    //Marshal.PtrToStringAuto(GetStringReturnByBytes()); 自动判断类型不错。
    Console.WriteLine(Marshal.PtrToStringAnsi(GetStringReturnByBytes()));
    Console.WriteLine(GetStringReturnByMarshal());
    Console.WriteLine(Marshal.PtrToStringUni(GetStringReturnByBytesW()));
    Console.WriteLine(GetStringReturnByMarshalW());
}
 
 
 
第三:字符串指针作为输入输出参数时,因为要求有固定的容量,所以这里使用的是StringBuilder,大家仔细看了,当然也有byte[]版本。这个看大家喜欢那个版本就是用那个.
 
[DllImport("TestDll", EntryPoint = "GetStringParam")]
public static extern void GetStringParamByBytes(byte[] outHello, int len);

[DllImport("TestDll", EntryPoint = "GetStringParam")]
public static extern void GetStringParamByMarshal([Out, MarshalAs(UnmanagedType.LPStr)]StringBuilder outHello, int len);

[DllImport("TestDll", EntryPoint = "GetStringParamW")]
public static extern void GetStringParamByBytesW(byte[] outHello, int len);

[DllImport("TestDll", EntryPoint = "GetStringParamW")]
public static extern void GetStringParamByMarshalW([Out, MarshalAs(UnmanagedType.LPWStr)]StringBuilder outHello, int len);


publicbyte[] _outHello = newbyte[10];
publicbyte[] _outHelloW = newbyte[20];
public StringBuilder _builder = new StringBuilder(10); //很重要设定string的容量。

publicvoid Run()
{
    //
    GetStringParamByBytes(_outHello, _outHello.Length);
    GetStringParamByMarshal(_builder, _builder.Capacity);
    GetStringParamByBytesW(_outHelloW, _outHelloW.Length / 2);
    GetStringParamByMarshalW(_builder, _builder.Capacity);

    //
    Console.WriteLine(Encoding.ASCII.GetString(_outHello));
    Console.WriteLine(_builder.ToString());
    Console.WriteLine(Encoding.Unicode.GetString(_outHelloW));
    Console.WriteLine(_builder.ToString());
}

相关热词搜索:C C++ DLL 字符串

上一篇:函数调用导致堆栈不对称。原因可能是托管的 PInvoke 签名与
下一篇:C#使用RegistryKey 操作注册表以及添加引用

分享到: 收藏
评论排行
最新发布