Windows has always had a ton of Dynamic Link Libraries (DLL) files that it uses as a collection of related functions bound up into a single file. DLLs are accessed for finding open windows, accessing files, changing graphical elements of a system like the desktop or controlling where windows appear on screen. Many applications make use of these files as well and just at the beginning of the decade we coined the term “DLL Hell” to refer to a problem with applications needing a bunch of DLLs and accessing the wrong versions of those DLL files. This caused a nightmare with applications using outdated DLL files with their new application versions and leading to bugs. Microsoft even mentioned that there was a problem. In recent versions of the Visual Studio IDE they fixed up most of this DLL hell. But even today the idea of a DLL is still in use and developers continue to make them as a convenient way of bundling together several functions for use by multiple applications. In this entry we will show you how to find out what is inside a system DLL (user32.dll), how to import it into a C# project, and how to access a fun little function called “SetDeskWallpaper” to change the wall paper on the user’s computer. Grab your afternoon tea or morning coffee and enjoy another episode of the Programming Underground!
In this example we will be working with user32.dll. This is a system DLL that contains A LOT of functions and is in heavy use by windows for managing several system functions related to a user on the computer, such as their desktop. It works hand in hand with other system DLLs like shell32.dll and kernel32.dll to name a few. You can locate user32.dll typically in the C:\Windows\System32 folder or C:\WINNT\System32 folder. Take a copy of it and move it to the C:\ folder just for experimentation and reading using the “dumpbin” tool.
The dumpbin tool is a tool that can be used for analyzing a DLL file and determining which types of functions the DLL has exported for the world to use and see. As you can imagine not all functions in a DLL will want to be seen by applications because they could be helper functions or private functions dedicated to supporting other publicly seen functions. Perhaps in another entry I will show you how to setup a DLL in VC++ and export it to be seen and used in an application done in C# or VB.NET.
The dumpbin tool can be found in the C:\Program Files\Microsoft Visual Studio 8\VC\BIN folder or wherever you installed visual studio. This path is related to Visual Studio 2005, so it might be Visual Studio 9 or something for 2008. If you have trouble finding it, do a search and locate it. Typically this file needs one other file to work properly for our example. This file is called “mspdb80.dll” (might be mspdb90.dll for 2008 or something similar) and is commonly found in the C:\Program Files\Microsoft Visual Studio 8\Common7\IDE folder. Copy that and put it in the BIN folder with the dumpbin.exe file so that dumpbin can easily find it. Now you are ready to do some analyzing!
Special note: Just remember that after you are done with the dumpbin tool that you remove mspdb80.dll from the folder you copied it too or it may cause a “program database mismatch” error during compiles of some C++ programs etc.
Go into a command prompt using the Start >> Run menu and typing “cmd”. This should bring up the old style MS-DOS command prompt. Change to the folder where dumpbin.exe is located by typing C:\>cd c:\program files\Microsoft Visual Studio 8\VC\BIN (again changing the path to reflect where you have things installed). Once there you can run dumpbin using the command C:\>dumpbin /exports c:\user32.dll. If successful, you should see a long list of function names go scrolling by. These are all the functions that applications can see in the DLL and you can access from C#. One of these entries should be “SetDeskWallpaper”
So you look through the list and find a function that appears to be something you want. Other functions you can play with are things like FlashWindow for flashing a window in the taskbar or SetWindowText to rename the text in a window (like putting your own name in FireFox’s Main window).
Once you find one you like, you have to know what parameters it takes and what datatypes they are. How do you figure this out? Well one great site for checking this out is pinvoke.net which allows you to lookup some of your favorite DLLs and their functions. They will show you the function signatures and perhaps even a demo using C# or VB.NET. You can find the link here PInvoke.net.
Now of course you may not find all of the functions listed there, but a great majority of them are. Once we cover building your own DLL files, you will be able to then look at it with dumpbin and see what has been exposed and can be used by .NET.
Ok, so we have our DLL, we see what it has to offer using dumpbin, we know its signature, now all is left is the C# import. Below is a VERY simplistic but working demo of how we import and use the function.
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; // Make sure we include the InteropServices so we have access to DllImport attribute. using System.Runtime.InteropServices; namespace DLLExample { public partial class Form1 : Form { public Form1() { InitializeComponent(); } // Define our DLLImport attribute and the signature of the function we are trying to use. [DllImport("user32.dll")] public static extern int SetDeskWallpaper(string filename); private void btnExecute_Click(object sender, EventArgs e) { // Call our DLL function and pass it the bmp file we want to set our desktop to. SetDeskWallpaper("c:\\background.bmp"); } } }
A few things to notice is that we put in a using statement for the “System.Runtime.InteropServices”. This namespace will give us access to an function attribute called “DllImport” which is used for importing our DLL. We mark our function with this attribute and then define the signature for our function we want to call. Notice that we tell the DllImport the DLL to use. Without a path it should be checking the C:\WINDOWS\system32 folder as a default and using the version there, not the one in c:\. That was only for analyzing purposes.
In our example we designate the function as publicly available, static, external source returning an integer. Its name is SetDeskWallpaper and takes one string which is the filename to a BMP file to set the desktop to.
That is all you need for the actual importing of the file. Now we have a button called btnExecute which has the click event. In it we call this new function we have defined and give it the path to our bmp file called “background.bmp” (use whatever file you have setup for the new desktop picture). As with all C# and C++ style syntax (oh and yes user32.dll is not even written in C#) case sensitivity is important. So make sure you spell and use correct capitalization.
Run your application and click the button. This should now change your desktop. I have tested this in Windows XP with SP2, but this function should work for most of the other Windows OS versions as well. If it doesn’t work for something like Windows 2000, check out the user32.dll using dumpbin and see if maybe it has a different function name or something that you could use instead.)
Use this demo above as a rough template for creating your own projects that use a DLL. That is all there is to it to get started working with DLLs. The only other notes I have for you is to keep track of the data types that the function expects. Since most DLL files for the system are written in C++, they may require C++ style parameters or structs. Most of C# can mimic these types, if not all, and always make sure you pass the function the right type of data it expects. If it asks for a struct, define and build the struct, fill it and then give it to the function. Data types like lpstring etc can typically be called from C# with just the regular old “string” data type.
Also keep in mind that these are DLL files that the system uses as well. So if you don’t know exactly what you are doing you could screw up some part of windows. So keep this in mind and if you don’t know what the function does, don’t throw it bad data as a test. Research the function and then if you understand it, feel free to access it.
Enjoy making windows obey your every command! 🙂