当前位置:   article > 正文

C#调用C++/Rust动态链接库 传递或返回字符串参数时避坑

C#调用C++/Rust动态链接库 传递或返回字符串参数时避坑

1、C#向C++ dll 传入字符串时,参数直接用string,设置编码格式 CharSet.Unicode或者CharSet.Ansi。

C++ dll接收使用wchar_t* 或 char*。

2、C++ dll返回字符串,使用 wchar_t 或char*。

.net 4.0 C#可以直接使用string接收,很方便。

.net 4.0+ C# 用 IntPtr 接收,使用string接收调试不行。
————————————————

C# 的 IntPtr 类型

Dec 10, 2021

C# 中,IntPtr 是一个代表内存位置指针的类型。它被用来存储一个变量或一个对象在内存中的地址。IntPtr 是一个整数类型,但它的大小与平台有关。在 32 位系统中,IntPtr 的大小为 32 比特(4字节),在 64 位系统中,它的大小为 64 比特(8字节)。

IntPtr 通常在处理非托管代码或与其他使用指针的语言相互操作时使用。例如,如果你从动态链接库(DLL)中调用一个以指针为参数的函数,你可以使用IntPtr将一个变量的地址传递给该函数。C# 中主要用它调用 C++\C 封装的 DLL 库

下面主要介绍 IntPtr 的常见用法。

1 .int 类型与 IntPtr 类型之间的转换

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Runtime.InteropServices;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. namespace MyIntPtr
  8. {
  9. class Program
  10. {
  11. static void Main(string[] args)
  12. {
  13. int nValue1 = 10;
  14. int nValue2 = 20;
  15. //AllocHGlobal(int cb):通过使用指定的字节数,从进程的非托管内存中分配内存。
  16. IntPtr ptr1 = Marshal.AllocHGlobal(sizeof(int));
  17. IntPtr ptr2 = Marshal.AllocHGlobal(sizeof(int));
  18. //WriteInt32(IntPtr ptr, int val):将 32 位有符号整数值写入非托管内存。
  19. //int->IntPtr
  20. Marshal.WriteInt32(ptr1, nValue1);
  21. Marshal.WriteInt32(ptr2, nValue2);
  22. // ReadInt32(IntPtr ptr, int ofs):从非托管内存按给定的偏移量读取一个 32 位带符号整数
  23. //IntPtr->int
  24. int nVal1 = Marshal.ReadInt32(ptr1, 0);
  25. int nVal2 = Marshal.ReadInt32(ptr2, 0);
  26. //FreeHGlobal(IntPtr hglobal):释放以前从进程的非托管内存中分配的内存。
  27. Marshal.FreeHGlobal(ptr1);
  28. Marshal.FreeHGlobal(ptr2);
  29. }
  30. }
  31. }

2.string 类型与 IntPtr 之间的转换

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Runtime.InteropServices;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. namespace MyIntPtr
  8. {
  9. class Program
  10. {
  11. static void Main(string[] args)
  12. {
  13. string str = "aa";
  14. IntPtr strPtr = Marshal.StringToHGlobalAnsi(str);
  15. string ss = Marshal.PtrToStringAnsi(strPtr);
  16. Marshal.FreeHGlobal(strPtr);
  17. }
  18. }
  19. }

3. 结构体与 IntPtr 之间的转换

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Runtime.InteropServices;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. namespace MyIntPtr
  8. {
  9. class Program
  10. {
  11. public struct stuInfo
  12. {
  13. public string Name;
  14. public string Gender;
  15. public int Age;
  16. public int Height;
  17. }
  18. static void Main(string[] args)
  19. {
  20. stuInfo stu = new stuInfo()
  21. {
  22. Name = "张三",
  23. Gender = "男",
  24. Age = 23,
  25. Height = 172,
  26. };
  27. //获取结构体占用空间的大小
  28. int nSize = Marshal.SizeOf(stu);
  29. //声明一个相同大小的内存空间
  30. IntPtr intPtr = Marshal.AllocHGlobal(nSize);
  31. //IntPtr->Struct
  32. Marshal.StructureToPtr(stu, intPtr,true);
  33. //Struct->IntPtr
  34. stuInfo Info =(stuInfo)Marshal.PtrToStructure(intPtr, typeof(stuInfo));
  35. Console.ReadKey();
  36. }
  37. }
  38. }

4. 调用 C++\C 封装的 DLL 库

  1. Copy codeusing System;
  2. using System.Runtime.InteropServices;
  3. namespace IntPtrExample
  4. {
  5. class Program
  6. {
  7. // Import the DLL function that takes an IntPtr argument
  8. [DllImport("mylibrary.dll")]
  9. static extern void MyFunction(IntPtr ptr);
  10. static void Main(string[] args)
  11. {
  12. // Create an integer variable
  13. int x = 10;
  14. // Allocate memory for the variable and get a pointer to it
  15. IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(x));
  16. Marshal.StructureToPtr(x, ptr, false);
  17. // Call the DLL function and pass the pointer to the variable
  18. MyFunction(ptr);
  19. // Free the allocated memory
  20. Marshal.FreeHGlobal(ptr);
  21. }
  22. }
  23. }

在这个例子中,MyFunction() 函数从一个DLL中导入,并接受一个 IntPtr 参数。Main() 方法使用 Marshal.AllocHGlobal() 方法为一个整数变量分配内存,然后使用一个 IntPtr 变量将该变量的地址传递给 MyFunction()

注意,当使用 IntPtr 时,正确管理被分配的内存是很重要的。在上面的例子中,内存是用 Marshal.AllocHGlobal() 分配的,然后在不再需要时用 Marshal.FreeHGlobal() 释放。未能正确管理内存会导致内存泄漏或其他问题。

参考:
https://blog.csdn.net/tinghe17/article/details/114381046

https://dqdongg.com/c%23/2021/12/10/Csharp-Intptr.html

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/寸_铁/article/detail/770950
推荐阅读
相关标签
  

闽ICP备14008679号