98

我正在通过用 C# 编写代码来构建 C++ dll。

我得到一个错误,说

检测到 LoaderLock 消息:尝试在 OS Loader 锁内进行托管执行。不要尝试在 DllMain 或图像初始化函数中运行托管代码,因为这样做会导致应用程序挂起。

我尝试搜索此错误的确切含义,但我正在绘制毫无意义的文章,主要是说这只是一个警告,我应该在 Visual Studio 中将其关闭。其他解决方案似乎是由于 iTunes,或者使用 DirectX 编程时出现的这个问题。我的问题与这两个都没有关系。

谁能解释一下,这实际上意味着什么?

4

9 回答 9

72

you need to go to menu Debug -> Exceptions, open the Managed Debugging Assistants, find LoaderLock and uncheck

http://goo.gl/TGAHV

于 2010-11-04T08:04:27.303 回答
52

加载器锁的一般思想:系统在DllMain中运行代码在一个锁内(如同步锁)。因此,在 DllMain 中运行重要的代码是“要求死锁”,如此所述。

问题是,你为什么要在 DllMain 中运行代码?此代码在 DllMain 的上下文中运行是否至关重要,或者您是否可以生成一个新线程并在其中运行代码,而不是等待代码在 DllMain 中完成执行?

我认为托管代码的问题在于,运行托管代码可能涉及加载 CLR 等,并且不知道那里会发生什么会导致死锁......我不会听从“禁用此警告”的建议“如果我是你,因为大多数情况下你会发现你的应用程序在某些情况下会意外挂起。

于 2008-09-11T14:18:36.723 回答
19

.NET 4.0 和更多最新框架的更新

这是 .Net 2.0 时提出的一个老问题,当时对混合模式 DLL 的支持存在严重的初始化问题,容易出现随机死锁。从 .Net 4.0 开始,混合模式 DLL 的初始化发生了变化。现在有两个独立的初始化阶段:

  1. 本机初始化,在 DLL 的入口点调用,包括本机 C++ 运行时设置和 DllMain 方法的执行。
  2. 托管初始化,由系统加载程序自动执行。

由于第 2 步是在 Loader Lock 之外执行的,因此没有死锁。详细信息在混合程序集的初始化中进行了描述。

为了确保您的混合模式程序集可以从本机可执行文件加载,您唯一需要检查的是 DllMain 方法是否被声明为本机代码。#pragma unmanaged可以在这里提供帮助:

#pragma unmanaged

BOOL APIENTRY DllMain(HMODULE hModule,
    DWORD  ul_reason_for_call,
    LPVOID lpReserved
    )
{
    ... // your implementation here
}

同样重要的是,DllMain 可能直接或间接调用的任何代码也是非托管的。限制 DllMain 使用的功能类型是有意义的,因此您可以跟踪从 DllMain 可访问的所有代码,并确保所有代码都使用#pragma unmanaged.

如果编译器检测到 DllMain 未声明为非托管,编译器会通过警告 C4747 来帮助您:

1>  Generating Code...
1>E:\src\mixedmodedll\dllmain.cpp : warning C4747: Calling managed 'DllMain': Managed code may not be run under loader lock, including the DLL entrypoint and calls reached from the DLL entrypoint

但是,如果 DllMain 间接调用一些其他托管函数,编译器不会生成任何警告,因此您需要确保永远不会发生,否则您的应用程序可能会随机死锁。

于 2016-03-20T23:29:12.470 回答
6

按 ctr d+e 然后展开 Managed Debugging Assistants 节点。然后取消选中LoaderLock。

希望这会帮助你。

于 2012-07-18T06:37:09.540 回答
6

温馨提示VS2017用户需要禁用“异常助手”而不是“异常助手”(VS2017之前)以防止加载器锁定错误,设置路径为Debug->Exception。刚刚遇到这个问题并浪费了2个小时寻找解决方案......

于 2018-05-19T10:44:27.030 回答
4

我最近在创建用本机代码编写的 COM-Object 实例时遇到了这个错误:

m_ComObject = Activator.CreateInstance(Type.GetTypeFromProgID("Fancy.McDancy"));

这导致了所描述的错误。“检测到 LoaderLock”- 抛出异常。

我通过在一个额外的线程中创建对象实例克服了这个错误:

ThreadStart threadRef = new ThreadStart(delegate { m_ComObject = Activator.CreateInstance(Type.GetTypeFromProgID("Fancy.McDancy")); });
Thread myThread = new Thread(threadRef);

myThread.Start();
myThread.Join(); // for synchronization
于 2015-07-09T15:41:58.463 回答
3

我正在构建一个 C++ CLR DLL (MSVS2015),它必须调用非托管 DLL 并定义非托管代码。我使用#pragma managed 和#pragma unmanaged 来控制给定代码区域的模式。

就我而言,我只是将#pragma unmanaged 放在我的 DllMain() 前面,这就解决了问题。它似乎在想我想要一个 DllMain() 的托管版本。

于 2016-07-15T13:10:59.143 回答
2

出现此问题的原因是 Visual Studio 中的调试器运行在一个或多个 DLL 文件中使用 Microsoft 基础类 8.0 版的托管应用程序的方式。

仔细阅读: http: //msdn.microsoft.com/en-us/library/aa290048 (vs.71).aspx

于 2012-07-13T00:18:46.637 回答
2

我的 Visual Studio 2017 实例中的设置路径是 Debug -> Windows -> Exception Settings 。例外设置“窗口”显示在底部选项卡组中(而不是单独的窗口),我花了一段时间才注意到它。搜索“装载机”。

于 2018-10-22T18:11:19.660 回答