4

可能是一个菜鸟问题,但在过去的几个小时(或几天)里,这让我陷入了困境......

我在 .NET Framework 4.0 的代码中从 DLL 调用方法

  [DllImport("xeneth.dll")]
    public static extern ErrorCode XC_GetFrame(Int32 h, FrameType type, ulong ulFlags, IntPtr buff, uint size);

然后在这里使用它:

if (XC_GetFrame(myCam, XC_GetFrameType(myCam), 0, IntPtr.Zero, (uint)fs) != ErrorCode.E_NO_FRAME)

但是,当我在 .NET 4.0 中运行它时,我得到一个 P/INVOKE 错误,但是......在 3.5 中运行它不会触发这个错误。在我和另一个程序员检查了代码之后,我们似乎把它归结为 IntPtr 在 4.0 上运行的方式不同。

我的应用程序需要在 .NET 4.0 中运行,因为应用程序所需的一些功能仅在 4.0 中可用...

有什么我可能忽略或忘记包含的内容吗?

任何想法都非常感谢!

汤姆

更新:

原生声明:

virtual ErrCode XCamera::GetFrame(FrameType type, unsigned long ulFlags, void *buffer, unsigned int size)

错误:对 PInvoke 函数 'DLLTest!DLLTest.Form1::XC_GetFrameType' 的调用使堆栈不平衡。这可能是因为托管 PInvoke 签名与非托管目标签名不匹配。检查 PInvoke 签名的调用约定和参数是否与目标非托管签名匹配。

4

3 回答 3

9

造成这种情况的两个常见原因:

  1. 调用约定不匹配。您的 C# 代码使用默认的stdcall. 也许本机代码使用cdecl. 尝试添加CallingConvention=CallingConvention.CdeclDllImport属性。
  2. 参数列表不匹配(见下文)。

不要自欺欺人地认为你的代码没问题,因为 .net 3.5 不会引发此错误。.net 4 中的错误检测更好,这就是为什么您只看到那里的错误。但是您的代码在所有 .net 版本中都被破坏了。


C++ 虚拟方法的本机定义是:

virtual ErrCode XCamera::GetFrame(FrameType type, unsigned long ulFlags, 
    void * buffer, unsigned int size);

看起来您将对象指针作为 pinvoke 调用中的第一个参数传递。我认为这可以工作,尽管我对导出时如何处理虚函数知之甚少,不知道这是否是一个问题。大概您已经导出了一个普通的 C 函数来实例化对象。

我看到的另一个问题是,在 Windows 上,C/C++long是 32 位的。AC#long是 64 位。这意味着正确的声明ulFlagsuint您的 C# 代码中的一样。

于 2012-03-27T21:37:04.950 回答
3

你有没有检查过这两个项目的重要性?如果一个是 64 位而另一个是 32 位,则会出现错误。请注意,在最近的版本中,C# 项目的默认设置从 Any CPU 更改为 x86。这在 x86 操作系统上无关紧要,但在 x64 操作系统上会产生显着差异。

此外,您通常应该尽可能多地包含错误的文本,审查以保护私人信息很好,但错误编号和文本可能会很有帮助。此外,在使用时extern,包含任何类型的两个定义struct以确保它们是等效的会很有帮助。(另一个常见问题)。

于 2012-03-27T21:27:42.417 回答
1

也许一个更好的问题是为什么它以前有效。您提供的声明:

virtual ErrCode XCamera::GetFrame(FrameType type, unsigned long ulFlags, void * buffer, unsigned int size)

.NET 类型对应于:FrameType, uint, IntPtr, uint.

在 Windows 上unsigned long是 32 位类型,而在 C#ulong中是 64 位类型。

于 2012-03-27T21:42:27.023 回答