【问题标题】:Error calling an unmanaged windows DLL from a C# WPF application从 C# WPF 应用程序调用非托管 Windows DLL 时出错
【发布时间】:2011-12-21 07:14:14
【问题描述】:

我正在开发一个需要实现非托管 Windows DLL 的项目。 DLL 用于与 USB 设备进行通信。我的代码在 C# 和 WPF 中。 为了初始化 DLL,我调用了一个函数:

InitTimerDll(Int32 wHandle, ref dllInitParams initParams);

调用此函数时,我必须传递一个名为 dllInitParams 的结构和控件绑定到的句柄。 我正在使用 DllImport 作为函数指针:

[DllImport("myDll.dll")]
public static extern void InitTimerDll(Int32 wHandle, ref dllInitParams initParams);

这是我的结构:

public struct dllInitParams
{
    public UInt16 simp;

    public UInt16 simt;
}

以上所有内容都在一个名为 myDllInterface.cs 的单独类中。以下是我从 WPF 表单中调用 InitTimerDll 函数的方法:

public IntPtr Handle
{
    get { return (new System.Windows.Interop.WindowInteropHelper(this)).Handle; }
}

private void initTime_Click(object sender, RoutedEventArgs e)
{   
    myDllInterface.dllInitParams initParams = new myDllInterface.dllInitParams();
    initParams.simp = 0;
    myDllInterface.InitTimerDll(this.Handle.ToInt32(), ref initParams);
}

上述代码的第一部分解释了我如何获取句柄,initTime_Click 显示了我如何初始化结构,通过将句柄和结构传递给它来调用 initTimeDll 函数。我已将 dll 文件复制到代码运行所在的目录中。我的代码编译得很好,但是当我单击 initTime 按钮时会产生错误。 错误:

ProbeCTRL.exe 中出现“System.AccessViolationException”类型的未处理异常

附加信息:试图读取或写入受保护的内存。这通常表明其他内存已损坏。

为什么会这样?

【问题讨论】:

  • 很难说,崩溃的代码不是您发布的代码。您需要调试本机代码。项目+属性,调试选项卡,勾选“启用非托管代码调试”。在 C 或 C++ 源代码中的 InitTimerDll 函数上设置断点。
  • 使用Int32 而不是IntPtr 作为句柄值可能会在64 位操作系统中引起问题。您的调用约定也可能是错误的(.NET 中的默认值是 StdCall)。

标签: c# .net wpf pinvoke


【解决方案1】:

在不确切知道 InitTimerDll() 函数对“this”指针的作用的情况下,我将专注于 params 结构。尝试添加如下结构布局标记:

[StructLayout(LayoutKind.Sequential, Pack=1)]
public struct dllInitParams
{
    public UInt16 simp;
    public UInt16 simt;
}

另外,请仔细检查您的结构是否完整且准确。

【讨论】:

  • 感谢您的 cmets。如上所述,我在我的结构中添加了一个 layoutKind,并初始化了该结构的所有成员。我也更改尝试将句柄作为 int64 和 IntPtr 传递。在所有情况下都发生了相同的错误。你认为问题可能是由于结构或句柄造成的吗?不幸的是,我不知道调用 initTimerDll 函数时 Dll 会做什么,但我知道这是初始化与设备的通信并允许调用其他方法并来回发送数据的原因。任何其他建议将不胜感激。
  • 我不会将句柄扩展为 Int64,除非这是 DLL API 实际需要的。前面关于混合模式 32/64 位问题的评论不会出现,因为您将无法将 32 位 DLL 加载到 64 位进程中。我还要确保您在拥有控件的同一线程上调用此函数,因为对 UI 元素的跨线程调用可能会引发异常。你确定你的 DllImport 正确吗?第二个参数是输入/输出参数吗?尝试从该参数中删除“ref”。
  • 我删除了“ref”并发送了结构而不是指针,但我遇到了同样的错误。我没有做任何多线程。所以我假设该函数在同一个线程上运行。是否有任何方法可以在 Visual Studio 2008 中验证这一点?
  • 您能否发布 InitTimerDll() 函数的原始 C/C++ 函数声明,以及有关它对传入参数的作用的任何其他信息?它是否重新分配了 init params 结构?该结构应该在非托管堆上分配,还是应该通过 fixed() 不安全的 pin 方法传入?这些是我希望回答的问题。
【解决方案2】:

我发现了问题。代码很好,问题是dll文件已损坏。一个正确的 dll 文件副本解决了这个问题。在您的代码中使用 dll 时,确保您有准确的信息、函数调用、要传递的数据类型等非常重要。 感谢大家的帮助。

【讨论】:

    【解决方案3】:

    查看 PInvoke 教程:http://msdn.microsoft.com/en-us/library/aa288468%28v=vs.71%29.aspx

    正如吉姆·戈麦斯指出的那样:

    [StructLayout(LayoutKind.Sequential)]
    

    或类似的东西肯定很重要。

    此外,您只是在初始化结构中的一个变量。

    【讨论】:

      猜你喜欢
      • 2013-05-23
      • 2011-05-26
      • 2011-06-13
      • 1970-01-01
      • 2010-10-03
      • 1970-01-01
      • 1970-01-01
      • 2016-08-25
      • 2012-11-19
      相关资源
      最近更新 更多