使用 PInvoke 连接 C/C++ DLL 的调试断言失败

Posted

技术标签:

【中文标题】使用 PInvoke 连接 C/C++ DLL 的调试断言失败【英文标题】:Debug assertion failed using PInvoke to interface C/C++ DLL 【发布时间】:2015-01-12 03:54:47 【问题描述】:

我有一个 C/C++ dll 并尝试使用 PInvoke 连接到 C# 应用程序。 我收到Debug assertion failed 错误。 dll 在与 C++ 应用程序接口时起作用,问题仅在与 C# 应用程序接口时起作用。 我的 DLL 的 .h 和 .cpp 文件是

头文件

#include <string>
#include <fstream>
#include <iostream>

#ifdef DLL_EXPORTS
#define DLL_EXPORTS __declspec(dllexport) 
#else
#define DLL_EXPORTS __declspec(dllimport) 
#endif

#define   PASS              0
#define   FILECREATE_FAIL   1
#define   CAMERA_ERROR      2
#define   MAX_NUM_FRAMES    10000

using namespace std;

#ifdef __cplusplus
extern "C"

#endif

    // Returns pass  0
    //         Fails 1
    // Open the file at the path and start acquisition
    DLL_EXPORTS int start_acquisition(string path); 
    DLL_EXPORTS int stop_acquisition();

#ifdef __cplusplus

#endif

CPP 文件

#include "stdafx.h"
#include "IntensityDll.h"
#include <sstream>


ofstream fileout;
int counter;
char Header[64];
short Image[MAX_NUM_FRAMES][6400]; 
int ret;
int acquisition();

int start_acquisition(std::string path)

        ret = PASS;
        try
        
            fileout.open(path);//fstream
            if (fileout.is_open())                 
                 ret = acquisition();
            


        
        catch(fstream::failure e)
        
            cout << "Exception opening/reading file. " << endl;;
            return FILECREATE_FAIL;             
        


    return ret;

错误信息如附图所示。

我使用 PInvoke 如下

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsFormsApplication1

    public partial class Form1 : Form
    
        [DllImport("C:\\WindowsFormsApplication1\\WindowsFormsApplication1\\Wavelength_MaxIntensityDll.dll")]
        public static extern int start_acquisition(string path);
        [DllImport("C:\\WindowsFormsApplication1\\Wavelength_MaxIntensityDll.dll")]
        public static extern int stop_acquisition();
        public Form1()
        
            InitializeComponent();
        

        private void button1_Click(object sender, EventArgs e)
        
            int ret = start_acquisition("C:\\Users\\nyan2012\\Desktop\\Wavelength_test\\test1.txt");
        
    

编辑 1: 我展示了一个使用PInvoke 的示例。和我的有什么区别?

class PlatformInvokeTest

   [DllImport("user32.dll")]
   public static extern int MessageBoxA(
      int h, string m, string c, int type);

   public static int Main() 
   
      return MessageBoxA(0, "Hello World!", "My Message Box", 0);
   

【问题讨论】:

头文件中的__cplusplus 测试完全没用,因为这些函数使用C 中不存在的类型。 问题中的非托管函数使用 cdecl 调用约定。 p/invoke 的默认值为 stdcall。 【参考方案1】:

您没有显示您的 p/invoke 声明,但有 100% 的机会您弄错了,因为没有正确的声明。这些函数不能直接从 C# 调用,因为它们的签名是 C++ 特定的。

调试断言失败是因为 C++ 函数试图将其参数用作std::string,而实际上它不是一个。 std::string 析构函数在作用域的末尾运行,试图释放内存......但由于std::string 构造函数没有分配内存而失败,因为不存在std::string 对象在这里

您可以添加一个接受某些 p/invoke 兼容字符串类型(例如 const char*BSTR)的包装器,创建一个 std::string,然后调用真正的函数。

事实上,从其他 C++ 编译器或版本调用它也会有问题。

【讨论】:

我在 EDIT 1 中进行了更新。我觉得我理解你试图解释的内容。但是根据我更新的例子,和我的有什么区别呢? 区别在于the MessageBoxA function uses const char*不是C++std::string。 C# 中没有任何东西可以调用使用std::string 参数的函数。 现在有点奇怪了。现在我对 dll 调用没有任何参数,并且在 C++ dll 代码中分配了路径“C:\\Users\\nyan2012\\Desktop\\Wavelength_test\\test1.txt”。所以 C# 代码只调用 dll 但没有参数传递。对于 dll,如果从 C# 应用程序调用,则会出现“附加信息:尝试读取或写入受保护内存。这通常表明其他内存已损坏”的错误。但是从 C++ 应用程序调用时没有错误。背后的想法是什么? 现在您要问为什么我们看不到的代码是错误的。你为什么不坚持你问的问题?本已经给了你正确的答案。你现在可以接受他的回答,然后再担心你的新问题。

以上是关于使用 PInvoke 连接 C/C++ DLL 的调试断言失败的主要内容,如果未能解决你的问题,请参考以下文章

VS2008打开SQLite数据库时出错无法找到 PInvoke DLL“SQLite.Interop.DLL”。

反编译 c dll 以使用 pinvoke

C#通过PInvoke调用c++函数的备忘录

在具有 ui/非 ui 线程差异的 WPF 中使用 PInvoke

Windows Mobile 平台上的 PInvoke

vs2008 用c#设计的智能设备,在模拟骑上运行是提示无法找到 PInvoke DLL SCNAPI32.dll 怎么处理 急用 谢谢