处理c#中指向结构的指针
本文关键字:结构 指针 处理 | 更新日期: 2023-09-27 18:17:12
我正在做一个项目,其中包括用c++编写的DLL和c#代码。假设DLL有一个函数:
MyStruct* GetPointer(); // returns pointer to MyStruct structure
MyStruct结构如下所示:
struct MyStruct
{
OtherStruct1 *data1;
OtherStruct2 *data2;
};
和OtherStruct1和OtherStruct2结构看起来像这样:
struct OtherStruct1
{
public:
double x;
char y;
};
struct OtherStruct2
{
public:
float a;
float b;
float c;
float d;
};
我的问题是——在c#代码中处理所有这些指针的最好方法是什么?所谓"处理"是指从存储器中读取和写入的操作。c#中的结构不能简单地包含指针变量。我该怎么办?最优雅的方式是什么?
您可以使用Microsoft(现在是开源的)PInvoke互操作助手工具将您的C/c++代码转换为c#或VB。运行示例代码将得到:
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct MyStruct {
/// OtherStruct1*
public System.IntPtr data1;
/// OtherStruct2*
public System.IntPtr data2;
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct OtherStruct1 {
/// double
public double x;
/// char
public byte y;
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct OtherStruct2 {
/// float
public float a;
/// float
public float b;
/// float
public float c;
/// float
public float d;
}
public partial class NativeMethods {
/// Return Type: MyStruct*
[System.Runtime.InteropServices.DllImportAttribute("<Unknown>", EntryPoint="GetPointer")]
public static extern System.IntPtr GetPointer() ;
}
将DllImportAttribute中的"Unknown"替换为您的dll名称,并确保它在项目中被引用。现在您应该能够在托管代码中访问您的结构了。
然后,要从内存中读写,你需要使用System.Runtime.InteropServices.Marshal命名空间中的方法。下面的代码片段展示了如何使用GetPointer函数将非托管结构体转换为托管结构体:
IntPtr myPtr = NativeMethods.GetPointer(); // Call native code to retrieve pointer to unmanaged memory where the struct lives
MyStruct myStruct = new MyStruct(); // Create a new managed struct
myStruct = Marshal.PtrToStructure<MyStruct>(myPtr);
下面是如何将托管结构传递给非托管方法:
MyStruct myStruct = new MyStruct(); // Create the managed struct
myStruct.data1 = new OtherStruct1(); // Create a managed OtherStruct1
myStruct.data2 = new OtherStruct2(); // Create a managed OtherStruct2
IntPtr myStructPtr = Marshal.AllocHGlobal(Marshal.SizeOf<MyStruct>()); // Allocate unmanaged memory for the struct
Marshal.StructureToPtr<MyStruct>(myStruct, myStructPtr, false);
try
{
NativeMethodThatUsesMyStructPtr(myStructPtr);
}
finally
{
Marshal.FreeHGlobal(myStructPtr); // *** You have to free unmanaged memory manually, or you will get a memory leak! ***
}
好的,我想到了一个方法。
[StructLayout(LayoutKind.Sequential)]
struct MyStruct
{
OtherStruct1 *data1;
OtherStruct2 *data2;
};
[StructLayout(LayoutKind.Sequential)]
struct OtherStruct1
{
public:
double x;
char y;
};
[StructLayout(LayoutKind.Sequential)]
struct OtherStruct2
{
public:
float a;
float b;
float c;
float d;
};
然后:
unsafe
{
MyStruct *tmp = (MyStruct*) GetPointer();
tmp->data2[0].a = 1.0F;
}
[DllImport(DLL_PATH, CallingConvention = CallingConvention.Cdecl)]
unsafe public static extern MyStruct* GetPointer();
很有魅力。:)