Library tutorials & articles
Hosting Control Panel Applets using C#/C++
- Introduction
- Finding and loading unmanaged DLLs dynamically
- Calling unmanaged function pointers from managed c
- What does the applet expect?
- Accessing an Applet Library
- Wrapping Up
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.
Related articles
Related discussion
-
Binary Studio | software development outsourcing Ukraine
by shane124 (4 replies)
-
Seeking developers for Montreal Office
by mazen_kt (1 replies)
-
ActiveX and plug-ins
by nisharafic (1 replies)
-
Weird problem for devenv command build failed.
by anson78 (0 replies)
-
Job in the Loop!!!
by valdbori (0 replies)
Related podcasts
-
Object-Oriented Programming in Ruby
In this episode, I talk with Scott Bellware about object-oriented programming in Ruby, and Ruby's object model. This is taken from a private conversation, and the audio quality suffers at times. Much thanks to Scott for allowing this to be released.This episode of the Alt.NET Podcast is bro...
have also tried to convert the ambigous #define MAKEINTRESOURCEW(i) (LPWSTR)((ULONG_PTR)((WORD)(i))) in C++ into C# but with no luck.
So I compiled a C++ program using MAKEINTRESOURCE and traced it to see what TYPE is really passed to UpdateResource(..) or similar resource accessing functions. What I hav efound that it actaully passes the interger value (Resource ID). For example if you have a Resource with "MY_RES_ID" with ID 129
the compiled code actaully just passes the 129 as a WORD data.
So in C# while doing DllImport, I just chaged the Data Type for the Resource Id parameter which uses MAKEINTRESOURCE.
Here is what I did with UpdateResource
[DllImport("kernel32.dll")]
static extern bool UpdateResource(IntPtr hUpdate, string lpType, int lpName, ushort wLanguage, IntPtr lpData, uint cbData);
Notice the Third param which has been chaged from String to int. And It works!!! Now you will just pass (using my example as mentioned above) 129 instead of MY_RES_ID, or directly MY_RES_ID if it is defined somewhere to reprent 129.
----
Rezaul Kabir
shuvro@yahoo.com
Unmanaged C++ function which I am trying to call from C#.net app. is as below: (from the header file)
static void LibAction(const libString& actionXML, libString& returnXML, libError& libError);
libSting is a reference to the container class - wraps Standard Teplate Library String type. declared in the header file as below:
class LIB_CLASS_EXPORT LibString : public std::string
{
typedef std::string STL_STRING;
public:
// --- Constructors/Destructor ---
LibString() { ; }
LibString(const LibString& S);
LibString(const char* s);
LibString(char s);
LibString(istream&);
LibString(const STL_STRING & S) : STL_STRING(S) { ; }
virtual ~LibString();
libError is a reference to the container class which is used for the error handling.
How do I call this function from C# windows application.
Below is how I am trying to declare above function in my C# app.
[DllImport(@"C:\Test\dlls\Lib.dll", EntryPoint="LibAction")]
public static extern void LibAction(string actionXML, string returnXML, string libError);
Instead of string I should be passing ref to the libString. I am not sure how do I do that in C#.
Please help.
This thread is for discussions of Hosting Control Panel Applets using C#/C++.