简体   繁体   English

如何从C ++ dll在C#函数中传递大小未知的数组?

[英]How to pass an array with unknown size in C# function from C++ dll?

I have a C++ dll file which contains an exported function named fn(double* p, int* pLength) , where, p is a pointer (is an out array used in C#), pLength which is calculated in this function is the length (size) of p . 我有一个C ++ dll文件,其中包含一个名为fn(double* p, int* pLength)的导出函数,其中p是一个指针(是C#中使用的out数组),在此函数中计算出的pLength是长度(的大小)。 Code here: 代码在这里:

void _stdcall fn(double* p, int* pLength)
{
    int i=0;
    double p_=0;
    do
    {
        p[i]=p_;
        p_=an expression!!!!!;
        i++;
    }
    while (condition with p_);  //Condition of loop

    *pLength=i;

    return;
}

I compile to dll file successfuly. 我成功编译为dll文件。 This file is named "testFile.dll" and move it to System32 folder. 该文件名为“ testFile.dll”,并将其移至System32文件夹。 Now, I start C# console project and declare that exported function fn() from "testFile.dll", and this code is: 现在,我启动C#控制台项目,并声明从“ testFile.dll”导出的函数fn() ,此代码为:

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace ConsoleApplication1
{
    class Program
    {
        [DllImport("testFile.dll")]
        public static extern void fn(double[] p, ref int pLength);
        static void Main(string[] args)
        {
            // I want to declare an array with unknown length (size),
            // because the length is calculated from fn() function!!!
            // And pass to fn() function to get p[i].....
            double[] p;
            int pLength;
            fn(p, ref pLength);

            // Display pLength and p[i]
            Console.WriteLine(pLength);
            for (int i = 0; i < pLength; i++)
                Console.WriteLine(p[i]);
            Console.ReadKey();
        }
    }
}

I run and get two errors: 我运行并得到两个错误:

Error 1 Use of unassigned local variable 'p' 错误1使用未分配的局部变量'p'

Error 2 Use of unassigned local variable 'pLength' 错误2使用未分配的局部变量'pLength'

How to fix them?, and I want to get pLength and p[i] fully from fn() function in "testFile.dll". 如何修复它们?我想从“ testFile.dll”中的fn()函数中完全获取pLengthp[i] Thanks in advance. 提前致谢。

As I understand it, you will need to call the function twice. 据我了解,您将需要两次调用该函数。 Once you will pass an empty array and ask the function to calculate the required length. 一旦您将传递一个空数组,并要求函数计算所需的长度。 And then again you call with an allocated array which the function will populate. 然后再次调用该函数将填充的已分配数组。

The unmanaged code might look like this: 非托管代码可能如下所示:

void __stdcall fn(double p[], int* pLength)
{
    int i = 0;
    double p_ = 0;
    do
    {
        if (p) p[i] = p_;
        p_ = ...;
        i++;
    }
    while (...);
    *pLength = i;
}

Note that the code checks whether or not p is assigned, and only writes to the array if it is. 请注意,该代码检查是否分配了p ,并且仅在分配给p情况下才写入该数组。

On the managed side the code looks like this: 在托管方面,代码如下所示:

[DllImport(...)]
public static extern void fn(double[] p, out int pLength);
....
int pLength;
fn(null, out pLength);
double[] p = new double[pLength];
fn(p, out pLength);

A safer version of this would be to pass the length of the array to the function. 一个更安全的版本是将数组的长度传递给函数。 That would allow the function to make sure that it does not write off the end. 这将使该函数确保不注销结尾。

void __stdcall fn(double p[], int* pLength)
{
    int i = 0;
    double p_ = 0;
    do
    {
        if (p)
        {
            if (i >= *pLength) return -1; // or some other error code
            p[i] = p_;
        }
        p_ = ...;
        i++;
    }
    while (...);
    *pLength = i;
}

And the managed side: 和托管方:

[DllImport(...)]
public static extern void fn(double[] p, ref int pLength);
....
int pLength = 0;
fn(null, ref pLength);
double[] p = new double[pLength];
fn(p, ref pLength);

If you only want to call the function once then you need to do the following: 如果只想调用一次函数,则需要执行以下操作:

  1. Allocate memory dynamically in the unmanaged code. 在非托管代码中动态分配内存。 Use GlobalAlloc so that the managed code can deallocate it. 使用GlobalAlloc以便托管代码可以取消分配它。
  2. Be prepared to re-allocate in the unmanaged code if your initial allocation proved to be of insufficient length. 如果您证明初始分配的长度不足,请准备在非托管代码中重新分配。
  3. Use an out parameter of type IntPtr in the managed code to get the pointer to unmanaged memory. 在托管代码中使用IntPtr类型的out参数来获取指向非托管内存的指针。
  4. Use Marshal.Copy to copy the array contents into your managed double[] object. 使用Marshal.Copy将数组内容复制到托管double[]对象中。
  5. Call Marshal.FreeHGlobal to free the unmanaged memory. 调用Marshal.FreeHGlobal释放非托管内存。

This technique is much more complex and involves a lot more boiler-plate. 这种技术要复杂得多,涉及的锅炉板要多得多。 You only take this approach when there is a significant performance overhead in the first approach that I outlined. 只有在我概述的第一种方法中有显着的性能开销时,才采用这种方法。


An aside. 放在一边。 Please don't put your files in the system directory. 请不要将文件放在系统目录中。 It belongs to the system and you are expected not to modify it. 它属于系统,您应该不要对其进行修改。 Place the DLL in the same directory as the host executable. 将DLL与主机可执行文件放在同一目录中。

The error you are getting is to do with the fact that you are not assigning an array any value. 您得到的错误与您没有为数组分配任何值有关。 Though the function doesn't care how large the array is it still needs to work on valid memory. 尽管该函数不在乎数组有多大,但仍需要在有效内存上工作。

Try the following: 请尝试以下操作:

int pLength = 20;
double[] p = new double[pLength];
fn(p, ref pLength);

And see if the error goes away. 并查看错误是否消失。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM