3

我正在.NET 3.5 中编写一个程序,在某些地方必须走出去并从硬件 API 执行代码。这一切都很好,并且可以在 32 位 Windows 7、Windows XP 等中工作。问题出现在 64 位 Windows 7 上。

我在“任何 CPU”中编译,它确实在 Windows 7 64 位上以 64 位运行。因此,要与这件硬件接口,我必须用非托管 C++ 编写自己的包装 DLL。

所以,在我全部在 32 位下工作后,我将开关切换到 64 位,这就是问题所在。我遇到的问题与 Stack Overflow 问题“试图加载格式不正确的程序”几乎完全相反,即使平台相同......在那个问题中,他正试图获取他的代码在 Windows 7 上以 32 位运行(强制运行)。

好的,现在,我不想这样做,因为这块硬件有一个 64 位 API。所以,我用 64 位编译了我的代码,然后经过大量试验和错误,我得到了64 位正确的LINK,我有一个纯 64 位本机 C++ DLL,并Depends.exe确认了这一点。现在,Depends.exe也将供应商的 DLL 文件显示为纯 64 位。这很好,因为第一次代码不起作用,我开始与制造商一起研究,他们在我的帮助下更新了很多代码,或者我应该用我的问题说...... :)

因此,长话短说,我已将其分解为尽可能简单的设置。我的 DLL 文件 HW API.dll(也是本机 C++)和一个 .NET 应用程序来调用它们,使用相同的P/Invoke语法,并作为 64 位版本调用......

我的电话,仅供参考,如下所示:

[DllImport("xBiometrics.dll", ExactSpelling=true, SetLastError=true)]
[return: MarshalAs(UnmanagedType.I4)]
public static extern Int32 bioScanOpenDevice();

现在,当我尝试从 .NET 调用此代码时,出现异常错误:

"System.BadImageFormatException: 
An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)"

这让我相信 32 位的某些东西在某种程度上会产生干扰……我怎么可能说出来呢?我的意思是,是的,我已经查看了资源浏览器,并确保 DLL 文件是从正确的位置加载的,并且再次以 64 位编译它们,并且 .NET 应用程序以 64 位运行,即使它是为“任何 CPU”编译的。我已经验证了这一切...

我对这里的某些事情完全愚蠢吗?我是否错过了它告诉我们 P/Invoke 不适用于 64 位或其他东西的段落?如果我这样做了,为什么会抛出错误的图像格式异常?

我正在做的事情是否可能?64 位 .NET 应用程序可以加载和调用 64 位本机 DLL 文件吗?那个 DLL 文件可以动态链接到另一个本机 64 位 DLL 文件吗?如果我使用托管的 64 位 DLL 文件作为楔形 DLL 文件会有所不同吗?由于硬件供应商的 DLL 文件中的一些调用,我只使用了一个楔形 DLL 文件。他们将 void 指针传递给缓冲区,并且在 C# 中这样做太复杂了(必须检查“允许不安全代码”等)所以,我的楔形想法效果更好......我做了所有C++ 中的繁重工作并将更多结构化数据传回 C# 代码。

4

5 回答 5

4

我知道我可以从使用“任何 CPU”编译并在 64 位运行时下运行的 C# 程序调用 64 位本机 DLL。

我会建议以下调试:

1) 在您的 C# 程序中,检查IntPtr.Size程序启动时的值。如果它不是 == 8,那么你不是在 64 位运行。

2) 在 DllImport 中设置 64 位 DLL 的完整路径。那是:

[DllImport(@"c:\fullpath\xBiometrics.dll", ExactSpelling=true, SetLastError=true)]

如果这有效(我怀疑它会),那么问题是在您的 DLL 搜索路径中某处存在 DLL 的 32 位副本。这不止一次让我绊倒。

于 2010-11-23T00:43:50.403 回答
3

您可能会考虑的另一个选择是围绕您的 DLL 函数编写一个进程外 COM 包装器。

然后 COM 编组将处理任何 32 到 64 位接口问题。

虽然速度较慢。

于 2010-11-23T00:53:46.013 回答
3

最可能的错误来源是您错误地声明了某些参数——例如,当您真正想要一个 IntPtr 时,却是一个 Int32。

您也可能无法编译 64 位版本。例如,我知道在更改地址大小时更改一些与位无关的项目设置之前,VS 咬了我一口。我会检查你所有的非托管项目设置,并确保它们在 32 位和 64 位之间都是相同的。

最后,尝试从非托管应用程序加载非托管 DLL。您想知道错误是在托管端还是在非托管代码中。

于 2010-11-22T22:55:50.290 回答
0

我之前遇到过类似的问题,我通过确保我的代码使用定义为 long 的指针来解决它 - 检查它们是否都是 64 位的。

于 2010-11-22T22:58:29.413 回答
0

您可能会发现出于某种原因您实际上正在运行 32 位框架。您可以通过指定备用路径来管理找到的 DLL 文件,以找到要加载的正确 DLL。查看Stack Overflow 问题的答案如何根据 CPU 架构使用正确的非托管 DLL 文件?(32 / 64 位)

于 2010-11-22T23:15:21.137 回答