在PInvoke友好结构/类中拥有私有数据是否合法?

时间:2014-04-03 01:17:50

标签: c# pinvoke

我想知道,对于将与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#中我们的保护级别。关于PInvoke友好结构/类的C#数据成员是否隐私,我还能看到其他问题。

1 个答案:

答案 0 :(得分:1)

你问题中的代码很好。编组人员忽略了数据成员的可见性并将其全部编组。私人成员与公共成员一样被编组。

在整个模块边界中,重要的是结构的二进制表示匹配。并且成员的可见性未在二进制表示中编码。结构的二进制表示没有表明成员是私有的。这由具有类型知识的编译器处理。