zoukankan      html  css  js  c++  java
  • P/Invoke各种总结(三、与字符串交互char*,wchar_t*)

    现在还在做桌面这一块的,可能非常少了。昨天在调用封装的加密狗模块时,遇到了一些问题。查了一些资料,这里做一些总结。

    C#与C++进行互操作时,字符串这一块需要注意几个地方。

    使用char*(多字节)的情况

    1、不需要修改字符串的情况,直接用string类型即可(不需要提前分配空间),这里提供一段示例代码。

    先用C++封装一个导出函数 PrintName(char* strName) (C#与C++交互可参考https://www.cnblogs.com/zhaotianff/p/8991847.html)

    1 #include "stdafx.h"
    2 #include<iostream>
    3 
    4 using namespace std;
    5 
    6 void PrintName(char* strName)
    7 {
    8     cout << strName<< endl;
    9 }

    在C#中调用

     1 using System.Text;
     2 using System.Runtime.InteropServices;
     3 
     4 namespace ConsoleApplication1
     5 {
     6     class Program
     7     {
     8         [DllImport("Win32Project2.dll")]
     9         public static extern void PrintName(string name);
    10 
    11         static void Main(string[] args)
    12         {            
    13             PrintName("Jack");
    14         }
    15     }
    16 }

    运行结果如下

    2、需要修改字符串的情况,使用StringBuilder(需要提前分配空间),这里提供一段示例代码。

    使用C++封装一个导出函数ModifyName(char* strName),这个函数会对传入的字符串进行修改

    1 void ModifyName(char* strName)
    2 {
    3     char* name = "David";
    4 
    5     strcpy_s(strName, sizeof(strName), name);
    6 }

    C#调用

    如果使用string类型,会发现执行ModifyName后并不会修改字符串里的内容

    改成StringBuilder类型,如下

     1 using System;
     2 using System.Text;
     3 using System.Runtime.InteropServices;
     4 
     5 namespace ConsoleApplication1
     6 {
     7     class Program
     8     {
     9         [DllImport("Win32Project2.dll")]
    10         public static extern void ModifyName(StringBuilder name);
    11 
    12         static void Main(string[] args)
    13         {         
    14             var name = new StringBuilder(100);
    15 
    16             ModifyName(name);
    17 
    18             Console.WriteLine(name);
    19         }
    20     }
    21 }

    运行结果如下,运行结果正常

    这里还发现一件有趣的事,就是当我把StringBuilder的容量写小一点,当这个容量不足以容纳字符串时,CLR会改变StringBuider的容量,使它刚好能装下这些字符串。如果我直接不分配容量,CLR会分配一个稍微大一点的容量。为啥会这样我也没有去深入研究了。

    分配Capacity=3的情况

    不指定Capacity的情况

    使用wchar_t*[LPWSTR、LPCWSTR、PWSTR、PCWSTR ](Unicode)的情况

     这种情况跟上面所述一致,不修改字符串内容的,用string,需要修改并传出的,用StringBuilder,但是需要使用 MarshalAsAttribute 特性修饰或使用 DllImportAttribute 特性时指定 CharSet = CharSet.Unicode

     这里不封装导出函数了,直接用API函数GetCurrentDirectory为例

    GetCurrentDirectoryA是多字节字符集版本,GetCurrentDirectoryW是Unicode字符集版本

     1 using System;
     2 using System.Text;
     3 using System.Runtime.InteropServices;
     4 
     5 namespace ConsoleApplication1
     6 {
     7     class Program
     8     {
     9         [DllImport("Kernel32.dll",CharSet = CharSet.Unicode)]
    10         public static extern int GetCurrentDirectoryW(int nBufferLength,StringBuilder lpBuffer);
    11 
    12         //或者声明成下面这种
    13         //[DllImport("Kernel32.dll")]
    14         //public static extern int GetCurrentDirectoryW(int nBufferLength, 
    [MarshalAs(UnmanagedType.LPWStr)]StringBuilder lpBuffer);
    15 16 17 [DllImport("Kernel32.dll", CharSet = CharSet.Ansi)] 18 public static extern int GetCurrentDirectoryA(int nBufferLength, StringBuilder lpBuffer); 19 20 private const int MAX_PATH = 260; 21 22 static void Main(string[] args) 23 { 24 25 StringBuilder sb1 = new StringBuilder(MAX_PATH); 26 StringBuilder sb2 = new StringBuilder(MAX_PATH); 27 28 GetCurrentDirectoryA(MAX_PATH,sb1); 29 GetCurrentDirectoryW(MAX_PATH,sb2); 30 31 Console.WriteLine(sb1); 32 Console.WriteLine(sb2); 33 34 } 35 } 36 }

    运行结果如下:

  • 相关阅读:
    Python—模块
    Python之路_Day5
    Python之路_Day4
    Py获取本机指定网卡的ip地址
    Python之路_Day3
    Python之路—Day2作业
    Python之路—Day2
    Python之路—Day1作业
    Python之路—Day1
    Python数据类型
  • 原文地址:https://www.cnblogs.com/zhaotianff/p/12524947.html
Copyright © 2011-2022 走看看