在 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 友好的结构/类,我是否忽略了其他内容。

在 PInvoke 友好的结构/类中使用私有数据是否合法

您问题中的代码很好。编组程序忽略数据成员的可见性,并封送所有成员。私有成员的编组与公共成员相同。

跨越模块边界,重要的是结构的二进制表示形式是否匹配。并且成员的可见性不是在二进制表示中编码的。结构的二进制表示形式不指示成员是私有的。这由具有类型知识的编译器处理。