从 C# 调用 C++ DLib 导致错误分配异常

Posted

技术标签:

【中文标题】从 C# 调用 C++ DLib 导致错误分配异常【英文标题】:Calling C++ DLib from C# results in bad allocation exception 【发布时间】:2019-01-22 05:36:59 【问题描述】:

如果我直接在 C++ 中运行我的代码,它运行得很好。但是,当我从 C# 调用它时,我收到一条错误的分配消息。我的 C++ 经验非常低,但根据我阅读和修改的所有内容,我觉得这应该可行。

我的情况

通过面部识别传递图像路径,然后将结果保存/序列化到磁盘并返回图像在数组中的索引(函数:int AddImageToCollection)

如果我使用 main 函数运行我的代码,我会得到完美的结果(图 1),但如果我通过 C# 运行它(图 2),我会得到以下结果:

我得到的是日志 4-1 但不是日志 4-2,并且 e.what() 中的唯一错误是“分配错误”。我创建了一个无参数测试函数,它被硬编码为返回 5 并且可以工作,因此它与这个更复杂的函数隔离,我相信它必须与将数据传递给 const char* 相关。

图 1

frontal_face_detector detector = get_frontal_face_detector();
shape_predictor sp;
anet_type net;

bool fileExists(const std::string& name) 
ifstream f(name.c_str());
return f.good();


void log(std::string name) 



int main(int argc, char** argv) try

string str = "C:\\images\\Me.jpg";
const char* c = str.c_str();

int whatIsMyIdx = AddImageToCollection(c);

cout << whatIsMyIdx << endl;

cin.get();

catch (std::exception& e)

    cout << e.what() << endl;


int AddImageToCollection(const char* imagePath)

    deserialize("shape_predictor_5_face_landmarks.dat") >> sp;
    deserialize("dlib_face_recognition_resnet_model_v1.dat") >> net;

    matrix<rgb_pixel> image;
    string imagePathStr(imagePath);

    load_image(image, imagePathStr);

    std::vector<matrix<rgb_pixel>> faces;

    if (fileExists("faces_in_collection.dat")) 
        deserialize("faces_in_collection.dat") >> faces;
    

    auto facesDetected = detector(image);

    if (facesDetected.size() == 0)  return -1; 
    if (facesDetected.size() > 1)  return -2; 

    auto shape = sp(image, facesDetected[0]);

    log("4-1");

    matrix<rgb_pixel> face_chip;
    extract_image_chip(image, get_face_chip_details(shape, 150, 0.25), face_chip);

    log("4-2");

    faces.push_back(move(face_chip));
    serialize("faces_in_collection.dat") << faces;

    std::vector<matrix<float, 0, 1>> face_descriptors;

    if (fileExists("face_descriptors_in_collection.dat")) 
        deserialize("face_descriptors_in_collection.dat") >> face_descriptors;
    

    face_descriptors.push_back(net(faces[faces.size() - 1]));

    serialize("face_descriptors_in_collection.dat") << face_descriptors;

    return faces.size() - 1; //Return Image's Index in Array

图2

    [DllImport("FacialRecognition.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern int TestImageToCollection();

    [DllImport("FacialRecognition.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
    public static extern int AddImageToCollection([MarshalAs(UnmanagedType.LPStr)]string imagePath);

    private void Form1_Load(object sender, EventArgs e)
    
        int whatIsMyTestIdx = TestImageToCollection();

        int whatIsMyIdx = AddImageToCollection(@"C:\images\Me.jpg");

        MessageBox.Show(whatIsMyIdx.ToString());
    

【问题讨论】:

您可能想要使用 uint 而不是 int。文件可能非常大。 LPStr 是以 '\0' 结尾的字节。然而,您正在将它与 jpg 文件一起使用,这没有多大意义。它应该被编组为一个字节[]。由于它是字节,因此您还需要将计数从 c++ 传递到 c#。 该函数只获取图像的路径,在 C++ 中它像这样加载图像 (matrix image; string imagePathStr(imagePath); load_image(image, imagePathStr);).. .但我可能误读了您的评论,但听起来您希望我将图像的字节发送到函数。不确定这会解决我的问题,但愿意尝试一下。 看起来你只是在传递文件名。编组 UnmanagedType.LPStr 将 c# 字符串(两个字节字符)对象转换为以 '\0' 结尾的 byte[]。 c 语言代码 [char* imagePath] 正确接受字符串。我怀疑问题出在 imagePathStr() 上。后面的编译以 '\0' 结束: string str = "C:\\images\\Me.jpg"; imagePathStr() 也应该这样做。 【参考方案1】:

你需要修改你的代码如下

在 DLL 中

extern "C" __declspec(dllexport) int AddImageToCollection(LPCWSTR imagePath) .... // you may need to convert from Unicode string to ANSI if you are calling function that accept ANSI strings

在c#应用中

[DllImport("FacialRecognition.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] public static extern int AddImageToCollection(string imagePath);

然后像

一样调用你的函数
int whatIsMyIdx = AddImageToCollection(@"C:\\images\\Me.jpg");

为了使上述工作正常,不要忘记将应用程序和 Dll 编译为 Unicode。如果它们不同,您应该调整正确的出口和进口声明。

【讨论】:

我今天早些时候尝试过,但它不起作用,然后假装我仔细看了一下,我不再传递真实的图像位置,因为我修改了我的代码以在此处发布。好吧,一旦我解决了这个问题并应用了您的更改,一切正常!谢谢!

以上是关于从 C# 调用 C++ DLib 导致错误分配异常的主要内容,如果未能解决你的问题,请参考以下文章

从 C++ 调用 C DLL 会导致访问冲突,但 C# 项目与 DllImport 工作

dlib c ++概率分配中的分段错误

尝试从 C# 调用 C++ dll 时出现格式不正确的异常

PInvokeStackImbalance C# 调用非托管 C++ 函数

使用 c# 中的 c++ 引用中的引用从 C# 错误调用 C++ 代码

*** 关于从 C# 调用本机 C++