Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I delay loading .dlls in a C++-CLI (.net) application?

I'm trying to delay loading my dependent .dlls for a C++/CLI application so that I can test for their existence and warn the user instead of just crashing out.

I've tried adding the dlls to MyProject->Properties->ConfigurationProperties->Linker->Input->Delay Loaded DLLS ...but that just gives me a warning that it's not referencing them:

5>LINK : warning LNK4199: /DELAYLOAD:Util.dll ignored; no imports found from Util.dll

If I delete a .dll and run the application it crashes and wants to send information to microsoft about the missing .dll so it looks like it's still trying to load all the modules at startup and having a fit as a result.

FYI, my app startup looks something like this:

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);
            }
        }

        ...
like image 838
Jon Cage Avatar asked Jan 21 '11 12:01

Jon Cage


1 Answers

The linker's /delayload option only works for DLLs that contain functions compiled to native machine code. The linker already told you that you don't have any.

The likely scenario here is that your DLL actually contains IL, not machine code. Which will happen when you compile the source code with /clr in effect and haven't used #pragma managed to turn off IL generation. IL code needs to be converted to machine code by the jitter.

Your DLL is going to get loaded dynamically, same as /delayload, as soon as the jitter needs type info from the assembly's metadata to generate machine code. To avoid the dependency on the DLL, you'd have to carefully craft your code so the jitter never needs to load types from your assembly. Which is a different problem from avoiding executing a delay-loaded function. The exception's InnerException's stack trace should give you a strong hint how that happened.

like image 155
Hans Passant Avatar answered Sep 22 '22 13:09

Hans Passant