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.
Comments