启动DLL时C#环境堆栈溢出

时间:2018-09-20 13:50:13

标签: c# c++ interface

我有一个C#程序正在加载dll函数:

[DllImport("/Users/frk/Workspaces/MySharedLibrary.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto, EntryPoint = "MyCFunction")]

public static extern int MyFunction( [In][MarshalAs(UnmanagedType.I4)]MyFormat format,  [In][MarshalAs(UnmanagedType.LPArray)] byte[] myString,  [In][MarshalAs(UnmanagedType.I4)] int myStringLength, [MarshalAs(UnmanagedType.LPArray)] byte[] output,  ref UIntPtr outputLength);

并称呼

int result = MyFunction(format, inPut, inputLength, outPut, ref outputLength);

在C ++方面,我有:

从C测试可执行文件调用时,MyCPPFunction可以完美工作。 MyCPPFunction在其依赖关系的深处包含一个在匿名命名空间中声明和初始化的全局const变量:

namespace
{
        constexpr unsigned RandTileSize = 256;

        std::array<unsigned, RandTileSize * RandTileSize> GenerateSamples()
        {
            std::array<unsigned, RandTileSize * RandTileSize> samples;

            std::mt19937 rd(0);
            std::uniform_int_distribution<unsigned> distribution(0, 255);

            for (unsigned i = 0; i < RandTileSize * RandTileSize; ++i)
            {
                samples[i] = distribution(rd);
            }

            return samples;
        };

        const auto samples = GenerateSamples();<-- Option#1 this causes a stack overflow when loading the dll in C# environment

        unsigned Sample(unsigned index)
        {
               static const auto samples = GenerateSamples();<-- Option#2 this works and dll loads correctly
               return samples[index];
        }
}

由于afaik,我在这里感到困惑,选项1应该在dll的代码部分分配内存,C#环境应该处理该代码吗?

我们如何拥有选项#1而不在加载dll时引起内存分配问题?

1 个答案:

答案 0 :(得分:0)

DLL中的函数中的静态变量的生存期是从第一次遇到该语句到DLL卸载的时间。

类或文件范围变量的生存期是从DLL加载到DLL卸载为止。

其结果是,在失败的情况下,初始化代码正在运行,而DLL正在加载过程中

在类构造函数中运行非平凡的代码通常不是一个好主意,因为在加载程序锁中可以安全完成的操作受到限制。

特别是,如果执行任何需要动态加载另一个DLL的操作(例如LoadLibrary或调用延迟加载链接函数),则这很可能会导致难以诊断的问题。

无需准确诊断出您的问题出在哪里,答案很简单:使用option2或option 3。

选项3:

void MyDLLInitialize(){
    // Initialize the dll here
}

void MyDLLUninitialize(){
   // Uninitialize the dll here
}

然后在使用任何其他DLL函数之前和完成它之后分别从C#调用这些函数。