无法加载DLL(找不到模块HRESULT:0x8007007E)

154

我有一个带有非托管C++ API代码的dll库,我需要在我的.NET 4.0应用程序中使用它。但是每次我尝试加载我的dll时,我都会收到以下错误:

无法加载DLL'MyOwn.dll':找不到指定的模块。(来自HRESULT的异常:0x8007007E)

我已经阅读并尝试了在互联网上找到的几种解决方案。但没有任何作用。

我已经尝试使用以下方法:

[DllImport("MyOwn.dll",  CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs((UnmanagedType.I4))]
public static extern Int32 MyProIni(string DBname, string DBuser_pass,
    string WorkDirectory, ref StringBuilder ErrorMessage);
当我尝试遵循这篇文章并运行从下载的代码中获取的示例时,它可以顺利运行(使用的dll文件位于bin/debug文件夹中)。
我已经将我的dll文件(以及它所依赖的所有文件)复制到了我的bin文件夹中。
我还尝试了这种方法,但是得到了相同的错误:
[DllImportAttribute(MyOwnLibDllPath, EntryPoint="TMproIni")]
[return: MarshalAs(UnmanagedType.I4)]
public static extern  int MyproIni(string DBname, string DBuser_pass, 
    string WorkDirectory, ref StringBuilder ErrorMessage);

有什么建议吗?

20个回答

105

据我所记,在Windows中,搜索dll的顺序是:

  1. 当前目录
  2. 系统文件夹,C:\windows\system32 或 c:\windows\SysWOW64(对于64位系统上的32位进程)。
  3. Path环境变量中读取

此外,我会检查DLL的依赖项,Visual Studio提供的依赖项工具可以帮助您进行检查,也可以免费下载:http://www.dependencywalker.com


5
发现一些依赖关系缺失(来自Oracle和IE的某些dll)。需要安装Oracle,因为我的dll依赖于它。然后我就会知道 :)通过DependencyWalker找到了问题的所在 ;) - Ingimar Andresson
没问题,这个小工具为我节省了很多时间和精力,太棒了! :-) - display101
1
感谢Keith Halligan推荐DependencyWalker。它告诉我并非所有依赖项都具有相同的CPU类型(x86/x64)。我将所有具有相同CPU类型的文件复制到我的应用程序的bin文件夹中,问题得到了解决。 - DiligentKarma
7
我会尽力为您翻译。以下是需要翻译的内容:我能找到的每个 dll 文件 DependencyWalker 都声称存在不同 CPU 类型的错误 - 甚至 System.Web.Mvc.dll 也有错误。这里似乎有一种误报情况。 - PandaWood
3
我的问题是尝试加载一个用Debug编译的C++ DLL。这需要C++调试运行库,也就是必须安装Visual Studio。或者重新编译DLL为Release版,并安装C++运行库分发包。 - RenniePet

63

您可以使用dumpbin工具查找所需的DLL依赖项:

dumpbin /DEPENDENTS my.dll

这将告诉您需要加载哪些DLL文件。特别留意MSVCR*.dll文件,如果未安装正确的Visual C++ Redistributable,则可能会出现错误代码。

您可以从微软网站获取“Visual Studio 2013的Visual C++ Redistributable Packages”。它会安装c:\windows\system32\MSVCR120.dll文件。

在文件名中,120 = 12.0 = Visual Studio 2013。

请注意,您需要选择正确的Visual Studio版本(例如10.0 = VS 10、11 = VS 2012、12.0 = VS 2013...)、目标平台的正确架构(x64或x86),并小心处理调试版本。DLL的调试版本依赖于MSVCR120d.dll库,它是Visual Studio自带但不包含在Redistributable Package中的调试版本库。


6
对我来说,只需添加VS C++可再发行组件即可!需要v10.0(2010年)。谢谢!!! - Thiago Silva
有没有办法判断需要哪个版本的可再发行组件,是 64 位还是 32 位? - BVB
1
dumpbin /ALL 命令可以告诉你 my.dll 是 x86 还是 x64。 - Anthony Hayward
1
对于那些仍然遭受这个问题的人,如果您使用debug二进制文件,则C++运行时可再发行版本需要与构建它的版本完全相同。 - ljk321
@skyline75489的评论为我解决了问题。C++库在我的机器上运行良好,但由于VS将其链接到msvcr的调试版本,在其他地方无法加载。 - spy

23

DLL文件必须位于bin文件夹中。

在Visual Studio中,我将DLL文件添加到项目中,而不是在“引用”中添加。然后将DLL文件的“复制到输出目录”属性设置为“如果较新则复制”。


这适用于我的情况,我使用JLinkArm.dll。 - somejhereandthere

20

这是一个“权宜之计”,但您至少可以使用它来进行合理性测试: 在您的代码中尝试硬编码DLL的路径


在您的代码中尝试硬编码DLL的路径

[DllImport(@"C:\\mycompany\\MyDLL.dll")]

说到这里;在我的情况下,我按照 @anthony-hayward 建议的运行了 dumpbin /DEPENDENTS 命令,并将列出的 DLL 的 32 位 版本复制到我的工作目录中,这为我解决了这个问题。

这条消息有点误导人,因为无法加载的不是“我的” DLL,而是它的依赖项。


10
尝试输入DLL的完整路径。 如果不起作用,请尝试将DLL复制到system32文件夹中。

3
所有依赖项放在 System32 文件夹中,我的 DLL 放在其他地方可以吗? - Ingimar Andresson
依赖项也将按照Windows DLL搜索路径顺序进行搜索,如https://dev59.com/aWox5IYBdhLWcg3wvWwy#9003290所指定的那样。 - user4434329
你不应该将自己的DLL文件复制到System32文件夹中。该文件夹是为系统组件(如运行时、驱动程序组件等)保留的,而不是用户应用程序的随机DLL文件所用。 - Igor Levicki

9
"无法加载 DLL 'xxx.dll':指定的模块找不到。(来自 HRESULT:0x8007007E)" 意味着该文件已被找到,但是无法加载它。尝试将DLL文件复制到应用程序的根目录中,某些DLL库需要在应用程序的根目录中才能使用。或者检查是否有其他依赖的DLL文件。
"找不到 DLL 'xxx.dll':..." 意味着该文件未被找到。请尝试检查路径。例如:[DllImport(@"\Libraries\Folder\xxx.dll")]

非常感谢您包含十六进制 HRESULT。我的异常已经被翻译,而这个微小的文本差异在翻译中丢失了(这使得搜索变得更加困难)。 - Rafael
非常感谢您包含了十六进制的HRESULT。我的异常信息已经被翻译,而这个微小的文本差异在翻译中丢失了(这使得搜索变得更加困难)。 - Rafael
谢谢,这个HRESULT: 0x8007007E是非常关键的信息。我在浪费时间调整路径设置时,应该把注意力放在其他依赖于未找到的dll的dll上。 - undefined
1
如果这是真的,我删除DLL文件时就不应该出现错误代码'0x8007007E'。但是我仍然遇到了这个错误。 - undefined

6

确保您的自有dll的所有依赖项都在该dll附近或者在System32文件夹中。


4
有一件非常有趣的事情(并且具有技术相关性),可能会浪费您的时间,所以想在这里分享一下-
我创建了一个控制台应用程序项目ConsoleApplication1和一个类库项目ClassLibrary1。
所有进行p/invoke的代码都存在于ClassLibrary1.dll中。因此,在从Visual Studio调试应用程序之前,我只需将C++非托管程序集(myUnmanagedFunctions.dll)复制到ClassLibrary1项目的\bin\debug\目录中,以便CLR可以在运行时加载它。
我持续几个小时一直收到“无法加载DLL”错误。后来我意识到,所有要加载的这样的非托管程序集都需要复制到启动项目ConsoleApplication1的\bin\debug目录中,通常是窗体、控制台或Web应用程序。
因此,请谨慎使用已接受答案中的“当前目录”,实际上指的是从哪里启动应用程序进程的主可执行文件的“当前目录”。看起来很明显,但有时可能并不是这样。
得到的教训-始终将非托管dll放置在与启动可执行文件相同的目录中,以确保可以找到它。

这对我也解决了问题。不过,在主项目中放置DLL而不是实际使用它们的项目中感觉有点奇怪... - Sean Duggan
1
@SeanDuggan 这是因为它是一个“动态链接库”,意味着它在运行时使用(加载),而不是在链接时使用静态库。 - m4l490n
我已经尝试将dll添加到“bin\Debug”和“obj\Debug”目录中,但仍然出现“无法加载DLL”的错误。 - m4l490n

3
确保将构建平台目标设置为x86或x64,以便与您的DLL兼容 - 该DLL可能是为32位平台编译的。
具体来说:
  • 编译为32位平台(x86)
  • 编译为64位平台(x64或AMD64或类似)
  • 此外,正如其他答案中澄清的那样 - 根据DLL是32位还是64位,在您的计算机上,您的DLL将需要驻留在正确的文件夹中。(还请确保DLL的任何依赖项与DLL位于相同文件夹中)

    3

    在我的情况下,一个未托管的动态链接库依赖于另一个缺失的动态链接库。在这种情况下,错误会指向现有的dll而不是缺失的dll,这可能会让人感到困惑。

    这正是在我的情况下发生的。希望这可以帮助其他人。


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接