Hosting Control Panel Applets using C#/C++

Finding and loading unmanaged DLLs dynamically

Just when life is looking easy, and you are saying how hard can this be, in walks the first problem. How do we call this function from unmanaged code? As you know, you can call unmanaged functions from DLLs using System.Runtime.InteropServices.DllImportAttribute , the problem lies in the fact that you have to know the name of the library while coding. So how do we load unmanaged DLLs on the fly and call that unmanaged function if we can't define its entry point ahead of time.

The answer lies in several functions. LoadLibrary , FreeLibrary , and GetProcAddress . We will use LoadLibrary to load the applet's .cpl file (a.k.a. nothing more than a .dll ) by its filename, and use GetProcAddress to get an unmanaged function pointer to the CplApplet function. FreeLibrary will be used to release the DLL once we are finished using it. This is a standard practice, and any of you who have done dynamic function pointers can probably skip ahead just a bit. However, I can remember when this was a magic bag of voodoo magic, and needed a little explanation.

Let's look at how we can do this. First we will need to search the Windows System directory for all files ending with the .cpl extension. This is very easy to do using the methods and classes in the System.IO namespace. Here is the method that will do the grunt work of discovering these on the fly. Let's take a look. But first let me break down the classes that we will be working with, the classes I have created to make the magic happen. Very briefly they are…

  • AppletEngine
  • AppletLibrary
  • Applet

The AppletEngine class contains the following method that will allow us to find the applet libraries.

public FileInfo[] FindAppletLibraries(string path)
{
          DirectoryInfo di = new DirectoryInfo(path);
          if (di != null)
          {
                  return di.GetFiles("*.cpl");
          }
          return new FileInfo[] {};
}

This will allow us to be returned an array of FileInfo objects that contain information about the files that fit our search. This is all pretty standard stuff and shouldn't cause any questions as of yet. If it does, refer to the docs on MSDN or my source code and I'm sure the lights will come on quickly.

Now that we have discovered the files that end with .cpl , we will assume them to be all applet libraries. Let's look at how we can use LoadLibrary and GetProcAddress to load them and get that function pointer so we can communicate with the applets. We simply need to loop through the FileInfo objects and call LoadLibrary on the filename to load the DLL, and assuming that succeeds, we can call GetProcAddress to return a function pointer to the CplApplet function. Here is a snippet from the AppletLibrary constructor that implements this algorithm.

public AppletLibrary(string path, IntPtr hWndCpl)
{
    _path = path;
    _hWndCpl = hWndCpl;
    _applets = new ArrayList();
    if (!System.IO.File.Exists(path))
          throw new System.IO.FileNotFoundException("No applet could be found in the specified path.", path);
    _library = LoadLibrary(path);
    if (base.IsNullPtr(_library))
          throw new Exception("Failed to load the library '" + _path + "'");
    _appletProc = GetProcAddress(_library, "CPlApplet");
    if (base.IsNullPtr(_appletProc))
          throw new Exception("Failed to load CPlApplet proc for the library '" + _path + "'");
    this.Initialize();
}

Let's discuss just what this code snippet is doing. First off, it will try and call LoadLibrary on the path to the file, this should be something like C:\Windows\System\SomeApplet.cpl . The method will return an IntPtr which is a handle to the library. Look at the MSDN docs for more info on this, I'd rather let the creators explain it. If the function succeeds, the IntPtr will be something other than IntPtr.Zero . Once we have a handle to the library, we can call GetProcAddress with the handle and the name of the function to get yet another IntPtr which is an unmanaged function pointer.

You might also like...

Comments

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“I have always wished for my computer to be as easy to use as my telephone; my wish has come true because I can no longer figure out how to use my telephone” - Bjarne Stroustrup