【问题标题】:PInvoke problemPInvoke 问题
【发布时间】:2011-06-19 23:34:08
【问题描述】:

这是原生 c 方法的签名:

bool nativeMethod1
(unsigned char *arrayIn,
unsigned int arrayInSize,
unsigned char *arrayOut,
unsigned int *arrayOutSize);

我不知道为什么 arrayOutSize 是指向 unsigned int 而不是 int 本身的指针。

这就是我从 C# 调用它的方式:

byte[] arrayIn= Encoding.UTF8.GetBytes(source);
uint arrayInSize = (uint)arrayIn.Length;
byte[] arrayOut = new byte[100];
uint[] arrayOutSize = new uint[1];
arrayOutSize[0] = (uint)arrayOut.Length;

fixed (byte* ptrIn = arrayIn, ptrOut = arrayOut)
{
    if (nativeMethod1(ptrIn, arrayInSize, ptrOut, arrayOutSize))
    {
        Console.WriteLine("True");
    }
    else
    {
        Console.WriteLine("False");
    }
}

还有一些DllImport代码

[DllImport(@"IcaCert.dll", EntryPoint = "CreateCert2", CallingConvention = CallingConvention.Cdecl)]<br>
public unsafe static extern bool CreateCert2WithArrays(
        byte* data, uint dataSize,<br>
        byte* result, uint[] resultSize);

根据文档,本机方法应返回 arrayOut,其值取决于 arrayIn。如果它的大小小于需要,则返回 false。否则为真。我认为它需要 arrayOut 中的 850 个元素。所以,当我创建新的 byte[100] 数组时,函数应该返回 false,但它总是返回 true。为什么?

【问题讨论】:

  • 你为什么使用不安全的代码并修复。这里不需要。
  • 但是我用的是byte*指针,需要不安全,而且这部分byte* ptrIn = arrayIn需要固定。
  • 你不需要使用byte* - 看我的回答
  • 您不能使用 fixed 关键字来生成传递给本机代码的指针,数组未固定。大卫的声明是正确的。使用 Project + Properties 调试本机代码,调试,启用非托管代码调试。

标签: c# pinvoke


【解决方案1】:

您不需要不安全的代码并在此处修复。标准的 P/Invoke 编组器可以胜任这项任务:

[DllImport(@"IcaCert.dll", EntryPoint = "CreateCert2", CallingConvention = CallingConvention.Cdecl)]
public static extern bool CreateCert2WithArrays(
    byte[] arrayIn, 
    uint arrayInSize,
    byte[] arrayOut,
    ref uint arrayOutSize
);

byte[] arrayIn = Encoding.UTF8.GetBytes(source);
uint arrayInSize = (uint)arrayIn.Length;
uint arrayOutSize = 0;

CreateCert2WithArrays(arrayIn, arrayInSize, null, ref arrayOutSize);
byte[] arrayOut = new byte[arrayOutSize];
CreateCert2WithArrays(arrayIn, arrayInSize, arrayOut, ref arrayOutSize);

我不确定函数的协议是什么,但是如果输出数组的大小为0,这些函数能够接收NULL是正常的。

【讨论】:

  • 我知道它会起作用,我的也适用于普通的 arrayOutSizes。但我很好奇的是为什么如果 arrayOutSize 小于需要它就不起作用。它应该返回 false,但事实并非如此。我在 C++ 上检查了它,如果 arrayOutSize 小于需要,它总是返回 false。我不知道。
  • 原生代码是对的,我用java和c++测试过,只有c#失败
  • 正如汉斯所说,您的原始代码是错误的。上面的代码是如何做到的。以此为起点,向前迈进。
  • 你不需要在arrayIn和arrayOut上设置MarshalAsAttribute.SizeParamIndex属性吗?
  • @Simon 我不这么认为,因为分配是在 C# 端完成的。
【解决方案2】:

我不认为数组是您正在寻找的。它是指向数组大小的指针,而不是指向大小数组的指针。试试这个:

[DllImport(@"IcaCert.dll", EntryPoint = "CreateCert2", CallingConvention = CallingConvention.Cdecl)]
public unsafe static extern bool CreateCert2WithArrays(
byte* data, uint dataSize,
byte* result, ref uint resultSize);

byte[] arrayIn= Encoding.UTF8.GetBytes(source);

uint arrayInSize = (uint)arrayIn.Length;
byte[] arrayOut = new byte[100];
uint arrayOutSize = (uint)arrayOut.Length; 
CreateCert2WithArrays (arrayIn, (uint) arrayIn.Length, arrayOut, ref arrayOutSize);
uint[] arrayOutSize = new uint[1];
arrayOut = new byte[(int)arrayOut];
CreateCert2WithArrays (arrayIn, (uint) arrayIn.Length, arrayOut, ref arrayOutSize);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多