使用 DLLImport 找不到非托管 DLL

Posted

技术标签:

【中文标题】使用 DLLImport 找不到非托管 DLL【英文标题】:Can't find unmanaged DLL using DLLImport 【发布时间】:2017-08-05 02:36:24 【问题描述】:

以上是我的文件夹结构。我有一个 Cordova 应用程序和一个 Windows 运行时组件 - IBscanUltimate。包含文件夹具有调用非托管 IBscanUltimate.dll 的 C# 代码。 Class1.cs是这样的:

using System;
namespace IBscanUltimate

    public sealed class Class1
    
        public static String getSDK()
        
            IBscanUltimate.DLL.IBSU_SdkVersion a = new DLL.IBSU_SdkVersion();
            IBscanUltimate.DLL._IBSU_GetSDKVersion(ref a);
            return "SDKVersion: " + a;
        

IBScanUltimateApi.cs 和 _IBSU_GetSDKVersion 看起来像这样:

internal partial class DLL

    [DllImport("IBScanUltimate.DLL")]
    private static extern int IBSU_GetSDKVersion(ref IBSU_SdkVersion pVerinfo);
    public static int _IBSU_GetSDKVersion(ref IBSU_SdkVersion pVerinfo)
    
        int nRc = IBSU_STATUS_OK;
        nRc = IBSU_GetSDKVersion(ref pVerinfo);
        return nRc;
    

我已将 DLL 放置在许多位置以查看它是否会被拾取,并且它们都具有上述属性。但是当我尝试运行我的应用程序时,它说无法找到 IBScanUltimate.DLL

输出是这样的:

我不确定我做错了什么以及为什么 DLLImport 找不到我的 dll。感谢您的帮助。

确切的错误是:

System.DllNotFoundException: Unable to load DLL 'IBScanUltimate.DLL': The specified module could not be found. (Exception from HRESULT: 0x8007007E)

更新 #1: 我遇到过https://msdn.microsoft.com/en-us/library/windows/desktop/hh447159(v=vs.85).aspx 这篇文章是解释LoadPackagedLibrary 函数可以用来加载dll。我没有看到任何关于如何在 C# 中使用它的示例。

更新 #2: Specify the search path for DllImport in .NET 提到可以使用SetDllDirectoryAddDllDirectory。他有一个SetDllDirectory 的代码 sn-p,但参数是 string[] paths。我将如何指定相对参数?

更新 #3:

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool SetDllDirectory(string lpPathName);
public static bool setPath(String path)

    //Windows.Storage.
    //return SetDllDirectory("ms-appx:///");
    return SetDllDirectory(path);

我尝试使用我的应用程序应该可以访问的多个位置调用 SetDllDirectory(path) 方法,但我一直在“错误”。我尝试过的几个例子:

NativeMethods.setPath(Package.Current.InstalledLocation.Path.ToString());
StorageFolder localFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
StorageFolder folder = Windows.Storage.KnownFolders.MusicLibrary;

这是我的应用程序的安装位置: C:\Users\AAA\App\hello\platforms\windows\build\windows\Debug\x64\AppX 我可以看到我的 DLL 在那里。但是我仍然遇到无法找到 DLL 的异常。我必须在清单上写一些关于这个的东西吗?

更新 #4: 我在 DLL 上运行了一个 dumpbin,我在 dumpbin 中看到了以下 DLL:

WINUSB.DLL
mfc90.dll
MSVCR90.dll
KERNEL32.dll
USER32.dll
GDI32.dll
VERSION.dll
MSVCP90.dll
SETUPAPI.dll

我想我想分别检查上面的每个 dll,看看我的 Windows 运行时是否可以选择它?其中之一可能是未加载的罪魁祸首?

更新 #5: 在看到 Peter Torr - MSFT 的答案并在 Google 上搜索 MFC 后,我发现了这篇文章 https://msdn.microsoft.com/en-us/library/d06h2x6e.aspx,其中指出:

The MFC classes and their members cannot be used in applications that execute in the Windows Runtime.

我想现在结束这场疯狂的狩猎。我将关闭它,因为我尝试加载的库依赖于 Windows 运行时不可用的库。 我有这种感觉,因为 Windows 窗体应用程序会运行,但转换为 Windows 运行时的代码会给出找不到 DLL 的错误。感谢彼得指导正确的方向。

【问题讨论】:

更改了 C# 项目。我不明白你关于文件名的问题。如果这是您想要的,我也粘贴了属性屏幕截图。它仍然给我同样的错误;找不到 DLL。 你说的是关闭的项目:IBscanUltimateWRT? 看到您关于名称冲突的评论后,我摆脱了该项目,创建了一个名为 IBsWRT 的新 Windows 运行时项目。 @Norman:你捕获了“devenv.exe”。那不是你的应用程序,那是 Visual Studio。抱歉,我帮不了你。 @Noman 你检查过这些链接吗 - ***.com/questions/28620082/… ***.com/questions/39626809/… 【参考方案1】:

您尝试加载的 DLL 显然是为桌面应用程序构建的(它具有用户、GDI 和 MFC 导入),并且不能作为 UWP 二进制文件工作。我还怀疑 DLL 没有设置 AppContainer 标志(您传递给链接器的选项)。您将需要找到另一种方法来完成您的需求(如有必要,请通过the Windows Platform UserVoice 提出任何功能请求。

【讨论】:

所以我不能在windows应用商店使用这个DLL?但是User.dll我已经可以使用了。为什么我不能使用其他的? 支持少数 User32 API(处理鼠标和键盘输入),但大多数不支持。即使它们今天“工作”,它们将来也可能会中断 - 如果您尝试使用预先构建的边界,请务必在您的应用上运行 WACK 工具。【参考方案2】:

我怀疑它可以很好地找到您的 DLL,但它无法找到它的一个或多个依赖项。不幸的是,这两种情况都会导致非常通用的 DllNotFoundException,它提到了您尝试 P/Invoke 到的 DLL。

有一种简单的方法可以找出缺少的内容! Windows 包含一个称为“加载程序快照”的功能,当启用该功能时,它将记录 Windows DLL 加载程序为您的进程所做的所有事情。这意味着它还将打印它无法加载的 DLL。要启用它,请在管理员命令提示符下运行:

gflags.exe -i "<executableName>.exe" +sls

其中可执行文件名称只是您的可执行文件的名称,不包括文件夹。要查看输出,您还需要启用本机或混合模式调试器。您可以在 Visual Studio 的项目属性调试选项卡中执行此操作。

您可以在此处阅读有关加载快照的更多信息:

https://blogs.msdn.microsoft.com/junfeng/2006/11/20/debugging-loadlibrary-failures/

【讨论】:

但是我有一个 .appx 包。我将如何在 .appx 上使用它? .appx 包最终仍然包含一个可执行文件。它可能会匹配您的主要项目名称。 不,.appx 不是“完全”一个 exe 文件。或者更确切地说,我不确定如何在 .appx 上执行 glfags,它给出的错误是它无法在 .appx 上执行 gflags。 .appx 只是一个稍作修改的 zip 文件。里面有一个.exe文件。你在那个 .exe 文件上启用 gflags,而不是在 .appx 上。 不,.appx里面没有.exe文件。

以上是关于使用 DLLImport 找不到非托管 DLL的主要内容,如果未能解决你的问题,请参考以下文章

通过 DllImport 调用非托管函数时堆损坏

在 VB.NET 中制作一个我可以用作 DllImport 的 DLL

从 C# 调用非托管 .dll 的性能

编写用于 C# 的非托管 C++ DLL

DllImport 自动选择x64或x86 dll

如何混淆非托管 dll 的函数名称