在 PInvoke 友好的结构/类中使用私有数据是否合法
本文关键字:数据 是否 PInvoke 结构 | 更新日期: 2023-09-27 17:56:23
我想知道为将与 PInvoke 一起使用的结构/类private
数据成员是否在任何意义上都是非法的。动机是我需要使用的 API 中有一些相当大的 C 结构,我宁愿避免为每个 PInvoke 友好结构制作包装器来隐藏数据。同时,我不想公开所有数据成员。
尝试一个例子:
C/C++ 代码:
//PInvokeProvider.h
#include "stdafx.h"
typedef struct Animal_s
{
char Name[10000];
} Animal;
extern "C" void __declspec(dllexport) ChangeName(Animal* pAnimal);
//PInvokeProvider.cpp
#include "stdafx.h"
#include <stdio.h>
#include "PInvokeProvider.h"
extern "C" {
void ChangeName(Animal* pAnimal)
{
printf("Entered C++'n");
printf("Recieved animal : %s'n", pAnimal->Name);
printf("This function will change the first letter of animal to 'A''n");
pAnimal->Name[0] = 'A';
printf("Animal changed to : %s'n", pAnimal->Name);
printf("Leaving C++'n");
}
}
C#:
namespace PInvokeConsumer
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct Animal
{
/// char[10000]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10000)]
private string _name;
public Animal(string name)
{
_name = name;
}
public string Name
{
get { return _name; }
}
}
public partial class NativeMethods
{
[DllImportAttribute("PInvokeProvider.dll", EntryPoint = "ChangeName", CallingConvention = CallingConvention.Cdecl)]
public static extern void ChangeName(ref Animal pAnimal);
}
internal class Program
{
public static void Main(string[] args)
{
Animal animal = new Animal("Gorilla");
NativeMethods.ChangeName(ref animal);
Console.WriteLine(animal.Name);
Console.Read();
}
}
}
输出:
Entered C++
Recieved animal : Gorilla
This function will change the first letter of animal to 'A'
Animal changed to : Aorilla
Leaving C++
Aorilla
因此,在此示例中,在 C# 中使用结构体与私有数据没有任何问题(只要私有数据与 C 结构体的公共数据匹配即可)。
此外,当我检查动物结构Marshal.SizeOf()
时,返回的大小10,000
等于动物类中存在的唯一数据成员,这让我认为根本没有空间容纳传递给 PInvoke 调用的任何元数据,只传递数据位置,这将允许 C/C++ 代码完全忽略我们在 C# 中的保护级别。问题仍然存在,通过在 C# 中将数据成员设为私有以用于 PInvoke 友好的结构/类,我是否忽略了其他内容。
您问题中的代码很好。编组程序忽略数据成员的可见性,并封送所有成员。私有成员的编组与公共成员相同。
跨越模块边界,重要的是结构的二进制表示形式是否匹配。并且成员的可见性不是在二进制表示中编码的。结构的二进制表示形式不指示成员是私有的。这由具有类型知识的编译器处理。