Library tutorials & articles

Hosting Control Panel Applets using C#/C++

Introduction

Assumptions

This article assumes a basic understanding of writing unmanaged C/C++ dynamic link libraries and exporting functions from those libraries. Also basic understanding of using P/Invoke to access unmanaged libraries will benefit the reader, but I will attempt to explain as much as possible.

Abstract

The purpose of this article is to discuss several problems a developer might face when attempting to mix unmanaged and managed code. A problem that is all too often encountered when attempting to interact with the current Windows API from a managed language such as C# or VB.NET. In this article, I will discuss the problems I faced and how I solved the problems using a combination of managed and unmanaged code, C# and VC++ respectively. Here is a brief overview of what you can learn by reading this article:

  • Calling unmanaged function pointers
  • Dynamically loading unmanaged libraries at runtime
  • Acquiring function pointers to unmanaged functions
  • Translating C/C++ structures and data types to CLR compliant code
  • Finding alternatives to unsafe code for the purposes of using sizeof
  • Allocating/deallocating memory on the stack
  • Understanding how applets can be manipulated programmatically
  • Extracting strings and icons from embedded resources located in external unmanaged libraries.

Background

So let's begin by discussing why I decided to write this article and code. Being the curious coder I am, I am always intrigued by the underlying implementation of features in the Windows operating system. Control panel applets have always been a somewhat uncovered topic for some reason, yeah there is documentation on them in the MSDN library, but rarely any good working examples. Let along how they actually work. Before I set out to write this article, I already had a pretty good understanding of how applets are written, having written several as a professional developer in the past. However, it wasn't until I stepped into shell development that I became completely curious just how Windows pulled off these wonderfully useful creatures.

As days went by developing my shell, I came across many methods for actually launching control panel applets from code. Most of the implementations involved hard coding references to rundll32.exe to call the Control_RunDLL function with various arguments to launch off control panel applets. This always bothered me, because this was far from dynamic, you had to know about the applets ahead of time, at least somewhat to figure out how to launch them. I decided I wanted a means to enumerate and host the applets just like Windows.

So having said the why, let's discuss what an applet actually is. By the way, all of the information presented here is my personal dissection of the documentation found in the MSDN library. Control panel applets are nothing special, simply .dll s built with a special extension, .cpl , and placed into the Windows system directory. If you were to attempt to write one, you would have to choose a language that creates unmanaged DLLs and allows for exporting of unmanaged functions. Something that C# and VB just don't do, so look to C++ or Delphi to pull this off. It's not all that hard, but it's beyond the scope of the article.

Now that we know what an applet is, an unmanaged DLL compiled with a .cpl extension, let's look at how they work. Digging into the documentation, you will discover the CplApplet function. It is the sole function an applet must export from its library to interface with Windows. The function looks like this:

LONG CPlApplet(HWND hWnd, UINT uMsg, LPARAM lParam1, LPARAM lParam2);

The function is very similar to the WndProc functions behind all windows. All communication to applets occurs through this function. You do not need to understand anything more about this function for now. If you are interested, do a search for CPlApplet in the MSDN library and you will have the pleasure of translating this wonderful function just as the rest of us were forced to do.

Ok, so let's review what we know about applets. This will be the foundation of how we discover and communicate with all applets:

  • An unmanaged Windows dynamic link library
  • Uses the .cpl extension instead of the standard .dll extension
  • Exports a single function called CPlApplet
  • All applets should be located in the Windows System directory

Comments

  1. 10 Nov 2004 at 11:56

    Hi,


    have also tried to convert the ambigous #define MAKEINTRESOURCEW(i) (LPWSTR)((ULONGPTR)((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 MYRESID, or directly MYRESID if it is defined somewhere to reprent 129.





    Rezaul Kabir
    shuvro@yahoo.com

  2. 16 Apr 2004 at 17:20

    Sorry, I had a comment, but it was a mis-understanding of the original post.

  3. 24 Mar 2004 at 10:03

    This article is very useful to understand how to call unmanaged function from C#.net. I have to do the same thing for my project but it seems little complex as it is passing user defined data type as an argument to the calling function. I will appreciate help with this.
    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 LIBCLASSEXPORT 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 STLSTRING & S) : STLSTRING(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.





  4. 01 Jan 1999 at 00:00

    This thread is for discussions of Hosting Control Panel Applets using C#/C++.

Leave a comment

Sign in or Join us (it's free).

AddThis

Related discussion

Related podcasts

  • Looking into the C# Crystal Ball with Charlie Calvert and Bill Wagner

    One of the most exciting announcements from PDC was the news about C# 4.0 and Visual Studio 2010. With all the excitement and discussion throughout the event about these new developer tools, we reached out to two experts in the fields. Charlie Calvert and Bill Wagner sat down with Keith and Woody...

Events coming up

  • Dec 6

    Developing AJAX Web Applications with Castle Monorail

    London, United Kingdom

    Monorail is the model-view-controller engine of the Castle Project, bringing many of the best ideas of Ruby on Rails to the .NET world. In this talk, David De Florinier and Gojko Adzic show how Monorail makes it easy to develop .NET based AJAX applications, and how to use the Castle Project to build Web 2.0 applications effectively. Come to this session if you are a .NET web developer. Everyone is welcome!