1

当我使用 C# DllImport C++ dll 时,我有一个问题,我使用 Visual Studio 2010 并检查了“启用非托管代码调试”,当它运行时,总是显示消息“检测到缓冲区溢出!...缓冲区溢出已经检测到损坏了程序的内部状态。程序无法安全地继续执行,现在必须终止。”

这个dll是第三方供应商提供的,他们说运行这个dll没有错误,我该如何修复它?

我的 M++ dll 函数是,

int  avc_to_avi_convert(char* chPath_avc, char* chPath_avi, int pPrivate, PROGRESS_CALLBACK progress_callback);

void avc_to_avi_close(int* pFd_avi);

typedef void (*PROGRESS_CALLBACK)(int iPercent, int pPrivate);

我在我的 C# dllimport 中使用它,如下所示:

public delegate void PROGRESS_CALLBACK(int _iPercent, int _pPrivate);

[DllImportAttribute(@"..\xxx.dll", EntryPoint = "avc_to_avi_convert", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]

public static extern unsafe int avc_to_avi_convert([MarshalAs(UnmanagedType.LPStr)] StringBuilder _inputAVC, [MarshalAs(UnmanagedType.LPStr)] StringBuilder _ouputAVI, int pPrivate, PROGRESS_CALLBACK _pg);

[DllImportAttribute(@"..\xxx.dll", EntryPoint = "avc_to_avi_close", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]

public static extern unsafe void avc_to_avi_close(int pFd_avi);

private void button1_Click(object sender, EventArgs e)
{
    int i = 0;
    StringBuilder inputFile = new StringBuilder(Application.StartupPath + @"\avc\abc.avc");//(@"C:\avc\abc.avc");
    StringBuilder outputFile = new StringBuilder(Application.StartupPath + @"\avi\abc.avi");//(@"C:\avi\abc.avi");

    if (avc_to_avi_convert(
        inputFile,
        outputFile,
        1,
        progress_func) > 0) { 

    }
}

public void progress_func(int iProgress, int pPrivate)
{
     if (iProgress == 100)
     {
         //success
     }
     else if (iProgress == -1)
     {
         //convert error
     }
     else if (iProgress == -2)
     {
         //Not enough disk space
     }
     else
     {
         //update progress
     }
}

我将代码更改为,

[DllImportAttribute(@"..\xxx.dll", EntryPoint = "avc_to_avi_convert", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode)]

public static extern unsafe int avc_to_avi_convert([MarshalAs(UnmanagedType.BStr)] String _inputAVC, [MarshalAs(UnmanagedType.BStr)] String _ouputAVI, int pPrivate, PROGRESS_CALLBACK _pg);

[DllImportAttribute(@"..\xxx.dll", EntryPoint = "avc_to_avi_close", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode)]

public static extern void avc_to_avi_close(ref int avi);

并运行它,我仍然得到同样的错误。

4

2 回答 2

2

1.) 你确定调用约定吗?试试CallingConvention.StdCall。读这个:

http://blogs.msdn.com/b/adam_nathan/archive/2003/05/21/56690.aspx

2.) 为属性尝试不同的值CharSet并使用String而不是StringBuilder路径参数。这是一个很好的参考:

http://msdn.microsoft.com/en-us/library/s9ts558h.aspx

3.) 此外,该avc_to_avi_close方法应如下所示:

[DllImportAttribute("xxx.dll", EntryPoint="avc_to_avi_close")]
public static extern void avc_to_avi_close(ref int avi);

4.)您想尝试的其他事情:

  • CharSet使用和的不寻常组合MarshalAs。例如,您从上面的链接中知道Unicode应该与LPWStrAnsi一起使用,LPStr但您当然可以尝试其他组合。
  • 您的外部方法不需要标记unsafe

如果您已经用尽了所有其他选项,为什么不尝试编写一个类似于您的 C# 代码的 C++ 程序:

  • 如果它崩溃,则证明错误在库中。
  • 如果它没有崩溃,您就知道错误出在您使用 PInovke 时,您可以从我的答案中一一浏览所有 12 种以上的组合。
于 2012-10-07T05:49:55.063 回答
0

您将委托传递给 p/invoke,然后让垃圾收集器释放它。这会导致崩溃,因为当委托对象最终确定时,设置为允许从本机代码调用的蹦床被释放。然后本机代码调用一个悬空函数指针。

垃圾收集器完全不知道从本机代码内部使用的任何对象。您必须在通话期间保持对代理的引用。尝试添加一个委托变量(不要使用会创建临时变量的隐式转换),然后GCHandle只要本机代码正在使用它,就可以使用它来使委托保持活动状态。

于 2012-10-08T04:35:50.273 回答