Friday, August 06, 2004

Hangover

Well, today has been an interesting day at work. On one hand, although I still have a little hangover because of yesterday's working excesses, I've discovered something interesting and I've used a tool that until now I didn't have the opportunity (or the need) to use. Let me explain.

The .NET CF program that our client wants requires that some functions are done after rotating the desktop: being a mobile application, some guy more intelligent than me thought during design time that it would be nice to be able to rotate the desktop so some screens had a different, sleeker design. Of course, doing this with a 21'' screen is complicated, but with a PDA is done with a simple wrist turn. The thing is that the manufacturer of our chosen PDAs (Gotive) has kindly sent us (and it's the least they could do, taking into account the price of each of the machines and the amount we've bought) their propietary SDK, a single DLL file with a CHM help file.

Taking a look at the help file I realize that the DLL is little else that a wrapper for the API functions of Windows CE. A quite complete wrapper, because it includes functions to handle screen rotation, screen backlight, bar-code reading with the integrated reader, and so on. Of all those functions, I only wanted to use the one that changes the screen rotation and the one that returns the current screen rotation angle. How could I call only those functions and forget the rest of the wrapper functions? The answer: ILDASM.

Microsoft's ILDASM is included with VS .NET 2003 (although I believe it was included also in the first version), and allows us to de-compile an .EXE, .DLL, .OBJ or .LIB file created with any .NET language. Not so fast, kid. This is not going to give you the source code of anything. What it does is extracting from a compiled file the intermediate language from Microsoft, or MSIL, and display it on screen or to a file.

Let's do an example: this is an embarrassingly simple piece of code, which just writes on screen a "Hello, World!" string 5 times:



using System;
namespace ILDASM_Test
{
class HiBoring
{
[STAThread]
static void Main(string[] args)
{
for(int i=0; i<5; i++)
{
Console.Write("Hello, world!!\n");
}
Console.Write("Press any key to finish\n");
Console.ReadLine();
}
}
}


We build the solution for obtaining an .EXE file, in this case; and then we open the .NET console. We head for the folder where the .EXE resides and type ildasm <file_name.exe> where file_name should be the name of our compiled code. And we get the following window:








On it we can see how from an .EXE we have a namespace called ILDASM_Test, which contains a class called HiBoring, with a Main() method which is the one that interests us. If we double-click on the Main() method we get a window with the following code flush:



.method private hidebysig static void Main(string[] args)
cil managed
{
.entrypoint
.custom instance void
[mscorlib]System.STAThreadAttribute::.ctor() = ( 01 00 00 00 )
// Code size 39 (0x27)
.maxstack 2
.locals init ([0] int32 i)
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: br.s IL_0012
IL_0004: ldstr "Hello, world!!\n"
IL_0009: call void [mscorlib]System.Console::Write(string)
IL_000e: ldloc.0
IL_000f: ldc.i4.1
IL_0010: add
IL_0011: stloc.0
IL_0012: ldloc.0
IL_0013: ldc.i4.5
IL_0014: blt.s IL_0004
IL_0016: ldstr "Press any key to finish\n"
IL_001b: call void [mscorlib]System.Console::Write(string)
IL_0020: call string [mscorlib]System.Console::ReadLine()
IL_0025: pop
IL_0026: ret
} // end of method HiBoring::Main


As you can see is no crystal-clear code but you can find out interesting things.

Well, after this mini-class about Microsoft de-compiler, let's get on with it. I opened the .DLL file containing the SDK for our PDA (remember?) and I double-clicked on the method SetRotation() 'cause my intuition ;-) told me that that method may have something to do with the ability I want to invoke, which is rotating the desktop. And I find out on the MSIL code an obvious P/Invoke API calling to a function located in the DLL lcdapi.dll. API which, by the way, is not documented and displays no Google results as of today. Luckily, its signature is quite simple, and the needed P/Invoke is like this:



[DllImport("lcdapi.dll")]
static extern bool GLCDSetRotation(int Degrees);


Very simple. And voilá, thanks to this I've saved 52 Kbs of unnecessary DLL file, extracting just the function I need via the de-compiling of a manufacturer's DLL file which is just a wrapper. I've had some curious problems with the function (and which function is problem free on .NET CF?), but I'll talk about that tomorrow, when it's solved.

Important note: this post, and the rest containing source code, look so pretty thanks to Jean-Claude Manoli and his amazing on-line tool for C# code formatting, the c# code format. To each his due.

0 Comments:

Post a Comment

<< Home