English 中文(简体)
Dynamically loading a dll in C#
原标题:
  • 时间:2009-11-17 18:40:11
  •  标签:
  • c#
  • dll

I have a window to use for editing. The editor should load a dll (which I have full control of) in response to the user s selection to know how to display the information visually. (They re dll s, as a user will not necessarily want or need every single display model, and also allow new ones to be added without messing around with the main project)

They will all simply be stored in a subdirectory (for now anyway) I m pretty sure I can enumerate the available dlls but I need to do 2 more things that I m not sure on

1) Some way to get metadata fromon the dll, so I can build the lists of possible display selections...

2) Load the selected dll, and unload it as necessary

Any suggestions would be greatly appreciated.

最佳回答

OK, I;ve figured out I need to use a second AppDomain, load the dll into that, and then I can unload the AppDomain as required.

string SignalSystemDLLPath = AppDomain.CurrentDomain.BaseDirectory +  MyApp.Properties.Resources.SystemModuleFolder;     
AppDomainSetup info = new AppDomainSetup();
info.ApplicationBase = DLLPath;
DLLDomain = AppDomain.CreateDomain("EditorDomain", null, info);

DLLPath is set to the subdir that holds the dll s.

I then foreach on all the dll s to get the AssemblyName, then later I use

DLLDomain.Load(SelectedAssemblyName)

to load the DLL. I keep getting FileNotFound exceptions though. After much googling I ve decided its to much work at the moment, and I can refactor it later If I really need to do it...

Thank you for your replies though!

问题回答

If you are using raw dll s and not .NET assemblies then here are some handy P/Invokes for you:

[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
private static extern IntPtr LoadLibrary(string lpFileName);

[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
private static extern void SetDllDirectory(string lpPathName);

[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
privatestatic extern int GetModuleFileName(IntPtr module, [Out] StringBuilder fileName, int size);

[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
private static bool FreeLibrary(IntPtr module);

[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
private IntPtr GetProcAddress(IntPtr hModule, string lpProcName);

Note that SetDllDirectory may need some protection as it is not available on all versions of windows (Windows 2000, in particular doesn t have it).

And in use:

SetDllDirectory(candidateFolder);
IntPtr dllHandle = LoadLibrary(dllName);
if (dllHandle != IntPtr.Zero)
{
    _dllHandle = dllHandle;
    _location = candidateFolder;
    _fullPath = Path.Combine(candidateFolder, dllName);
    IntPtr p = GetProcAddress(_dllHandle, procName);
    if (p == IntPtr.Zero)
        throw new ArgumentException("procName");
    SomeDelegateType d = (SomeDelegateType)Marshal.GetDelegateForFunctionPointer(p, typeof(SomeDelegateType));
    d(/* args */);
}

otherwise, you will be using Assembly methods. Looking at assembly level attributes or object level attributes is a good way to get extra information, although if what you want is a plug-in system, you should use a plug-in system, like the Managed Add-In Framework at CodePlex. See also this SO question and answer.

Take a look at the Castle Windsor framework. It is designed to handle all of your requirements including DLL unloading. It s also free and open source.

I don t know if changing how your program works is an option, but, you could use dependency injection for this, as long as they adhere to a certain interface.

The user selects, you dynamically set class to be loaded, and then just get an instance of the class.

I am not dealing with the unloading, I am just thinking about how you could possibly get classes, and since plinth already gave links to the functions for actually handling the dll, I think I will just end here.

For a native module, the simplest way to get "metadata" would be to define some C-exported (non-name-mangled) functions that return the information you want. At their simplest, these would return pointers to static data within the modules, e.g.:

extern "C" const char* GetModuleDescription();
...
const char* GetModuleDescription() { return "Dummy Module"; }

You would then load each ".dll" file in the directory using LoadLibrary, load and call your known exports from it using GetProcAddress. If you can t load a file or find the exports, then it s not a valid plugin module, so skip it.

Once you re done with a module, you can call FreeLibrary. Windows will then unload the module from your address space.

Found out how to do this very easy using MEF, simply use a DirectoryCatalog pointed at your plugin dir, and as long as you have matching [Export]s and [Import]s it works great.





相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...

热门标签