如何在C++-CLI (.net)应用程序中延迟加载.dll文件?

5
我正在尝试延迟加载C++/CLI应用程序的依赖.dll文件,以便我可以测试其是否存在并警告用户,而不是直接崩溃。我已经尝试将dll文件添加到MyProject->属性->配置属性->链接器->输入->延迟加载DLLS中...但这只会给我一个警告,表示它没有引用它们:
5>LINK : warning LNK4199: /DELAYLOAD:Util.dll ignored; no imports found from Util.dll
如果我删除一个.dll文件并运行应用程序,它就会崩溃,并要求向Microsoft发送有关缺少.dll文件的信息,因此看起来它仍然在启动时尝试加载所有模块,并因此出现问题。
FYI,我的应用程序启动看起来像这样:
using namespace System;
using namespace System::Collections::ObjectModel;
using namespace Microsoft::Win32;

[STAThreadAttribute]
int main(array<System::String ^> ^args)
{
    try
    {
        // Enabling Windows XP visual effects before any controls are created
        Application::EnableVisualStyles();
        Application::SetCompatibleTextRenderingDefault(false); 

        // First make sure we have all the .dlls we need
        ArrayList^ missingDlls = gcnew ArrayList();
        Assembly^ assembly = Assembly::GetEntryAssembly();
        array<System::Reflection::AssemblyName^>^ referencedAssemblies = assembly->GetReferencedAssemblies();
        for each(System::Reflection::AssemblyName^ referencedAssemblyName in referencedAssemblies)
        {
            try
            {
                Assembly^ a = assembly->Load(referencedAssemblyName);
                if( a == nullptr )
                {
                    missingDlls->Add(referencedAssemblyName->Name);
                }
            }
            catch(System::Exception^ e)
            {
                MessageBox::Show("Error loading "+referencedAssemblyName->Name);
            }
        }

        ...
1个回答

8
连接器的/delayload选项只对包含编译为本机机器代码的函数的DLL起作用。连接器已经告诉你没有任何函数。
在这里可能的情况是,您的DLL实际上包含IL而不是机器代码。当您在编译源代码时使用/ clr,并且未使用#pragma managed关闭IL生成时,就会发生这种情况。Jitter需要将IL代码转换为机器代码。
与/delayload相同,您的DLL将动态加载,一旦Jitter需要从程序集的元数据中获取类型信息来生成机器代码。为避免对DLL的依赖性,您必须仔细设计代码,以使Jitter永远不需要从程序集加载类型。这与避免执行延迟加载函数的问题不同。异常的InnerException的堆栈跟踪应该会给你一个强烈的提示如何发生这种情况。

"IL" 代表什么?我有一个怀疑,这可能需要比它值得的更多的努力,从你所说的来看,很可能是这样。 - Jon Cage
不幸的是,我从未有机会捕获异常并展开它,所以我只看到了 Miscrosoft 想要发送给自己的错误报告中的外部部分。 - Jon Cage
1
IL是Intermediate Language的缩写,当您使用/clr编译时,代码将被翻译成IL。Jitter将其翻译为机器码。订阅AppDomain.CurrentDomain.UnhandledException以记录未处理的异常,例如此类异常。如果该方法使用来自这样的程序集的类型,则在Main()方法开始运行之前,它可以在技术上被引发。 - Hans Passant
4
如果在Main()方法中使用程序集的类型,很难避免依赖于该程序集。将代码移入单独的方法并应用[MethodImpl]以抑制内联。顺便说一下,奇怪的是你似乎没有发现这些信息有任何帮助。我需要停止提供“坏消息”答案了。 - Hans Passant
搬移方法调用到另一个方法中,解决了问题。这是有用的背景信息,但我不理解你所暗示的含义。最后一个建议确实解决了问题。 - Jon Cage
显示剩余2条评论

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