Getting closer to 1.0

Posted by Julien on February 23rd, 2007

Today I corrected a bunch of remaining issues with LogonSwitcher. The logon preview now shows the password box correctly, the main logon list has better looking borders, etc. I tested a little bit more under VPC to make sure it applies a full logon (not only a new background) I also added some new logons using nice images from Flickr (I’m using images under CC BY or CC BY-NC-SA, so it’s to distribute them).

It still need to be tested thoroughly, and that’s why I recruited two beta testers to get some feedback and to help me refine the UI. The poor ones don’t know what they are getting into :P

On another matter, I finally updated my project page, adding the remaining pages. I still need to write descriptions for some projects, but at least nobody is going to get a 404 error anymore.

Updating resources files with BMP and PNG files (with managed code)

Posted by Julien on February 23rd, 2007

This only concerns Bitmap resources (RT_BITMAP). Updating others type of resources is easier and doesn’t require specific code.

  • BMP files

Inserting BMP files is quite easy. You only have to remove the header and you are good to go.

int BMP_HEADER_BYTES = 14;
FileStream stream = new FileStream(file, 

                                   FileMode.Open,
                                   FileAccess.Read,
                                   FileShare.Read);

BinaryReader reader = new BinaryReader(stream);
byte[] data = reader.ReadBytes((int)reader.BaseStream.Length);

GCHandle gcHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
IntPtr bitmap = Marshal.UnsafeAddrOfPinnedArrayElement(data, BMP_HEADER_BYTES);

uint size = (uint)(data.GetLength(0) - BMP_HEADER_BYTES);
UpdateResource(hDll, 2, resourceId, LANG_ENGLISH_ID, bitmap, size);

gcHandle.Free();
stream.Close();
  • PNG files

It’s a bit more difficult with PNG files. You must add a header before inserting the image data. You also need to rotate the image before inserting because of the bitmap is copied and read (alternatively, you can insert a negative height into the header, but I haven’t tested it).

Also note that we do not set the compression to BI_PNG (5) and the size of the image in the BITMAPINFO header.

[StructLayout(LayoutKind.Sequential)] 
class BITMAPINFO {
public int biSize;
public int biWidth;
public int biHeight;
public short biPlanes;
public short biBitCount;     
public int biCompression;     
public int biSizeImage;     
public int biXPelsPerMeter;
public int biYPelsPerMeter;
public int biClrUsed;
public int biClrImportant; }

// Load file 
Bitmap pngFile = new Bitmap(file);
// Required due to the way bitmap is copied and read
pngFile.RotateFlip(RotateFlipType.RotateNoneFlipY);
BitmapData data = pngFile.LockBits(new Rectangle(0, 0,
                                                 pngFile.Width, pngFile.Height),
                                   ImageLockMode.ReadOnly,
                                   PixelFormat.Format32bppArgb); 

byte[] dataBuffer = new byte[data.Height * data.Stride]; 
Marshal.Copy(data.Scan0, dataBuffer, 0, data.Height * data.Stride); 
pngFile.UnlockBits(data);
// Setup Header 
BITMAPINFO header = new BITMAPINFO(); 
header.biSize = Marshal.SizeOf(typeof(BITMAPINFO));
header.biWidth = pngFile.Width; 
header.biHeight = pngFile.Height;
header.biPlanes = 1; 
header.biBitCount = 32; 

// Convert the structure to an array 
byte[] buffer = new byte[header.biSize];
GCHandle h = GCHandle.Alloc(buffer , GCHandleType.Pinned); 
Marshal.StructureToPtr(header, h.AddrOfPinnedObject(), false);
h.Free(); 

// Write header + data 
MemoryStream memory = new MemoryStream(); 
memory.Write(buffer, 0, buffer.Length);
memory.Write(dataBuffer, 0, dataBuffer.Length);
byte[] imageData = memory.GetBuffer(); 
GCHandle gcHandle = GCHandle.Alloc(imageData, GCHandleType.Pinned); 
IntPtr firstCopyElement = Marshal.UnsafeAddrOfPinnedArrayElement(imageData, 0);

UpdateResource(hDll, 2, resourceId, LANG_ENGLISH_ID,                
	       firstCopyElement, (uint)imageData.GetLength(0));

gcHandle.Free(); 
memory.Close();

Updating bitmap resources (with png files)

Posted by Julien on February 20th, 2007

Today’s probably the worst day I’ve had for quite some time. I didn’t sleep well last night. I’ve been feeling dizzy since this morning. I haven’t had much appetite for breakfast or lunch. And yet, today I finally resolved the problem that’s been bugging me for at least two weeks. How ironic !

To replace the logon screen, LogonSwitcher is modifying several images in resource dlls (I’m preparing an article on that). Some of the images in those resources are stored as “Image” resources and others as “Bitmap” resources. The first kind is easy to replace. Just open the file, map the contents and copy the bits to the resource. Done ! But the latter is a little bit more complicated.

You can have store several formats in “Bitmap” resources. The two I’m using are BMP and PNG. BMP are easy, you just have to remove the header and copy the contents of the file to the resource. But with PNG files, that doesn’t work…

I’ve been trying to make it work for more than a week with no luck, trying several things… What doesn’t help is that I haven’t been able to find any documentation on that precise subject. There is a lot of info on updating resources, but nothing specifically for PNG files. Or at least I couldn’t find it.

Finally, the actual working solution is 23 lines long :( Gahhhhhhhh !

I learned way more that I would have liked about win32 resources, PE, DIB, bitmaps formats. Not that there is anything wrong with learning new things, but with pure win32 programming, the more you learn about it, the more you realize that you know almost nothing. And that’s discouraging.

PS: if that sounds like incoherent rambling, re-read the first paragraph :)

Apply and Export animation

Posted by Julien on February 20th, 2007

The animation on Apply & Export is now done.

Almost there…

More UI work and a few other things

Posted by Julien on February 20th, 2007

I finished the Details panel yesterday and corrected the open animation. There is still a small bug with the description that is not cleared when you select another logon and the new logon doesn’t have any description.

I also replaced the old scrollbar with a new one that is better integrated with the application. The extra aero border will hopefully go when I start handling WM_NCCALCSIZE correctly. The code is deactivated as it’s not working correctly yet.

I moved all the logic when applying a logon into it’s own thread, so that the application doesn’t freeze when you click Apply. The two buttons along with the textbox and the slider are disabled when applying a logon.

I wanted to have a nice animation when applying the logon. Right now, the main list fades to white but I still need to add the actual animation.

Export, Glass buttons & MS Samples

Posted by Julien on February 17th, 2007

I’m now using the VistaBridge dll to get the native windows dialogs. I removed my own helper class for TaskDialogs to use the one included in the VistaBridge dll. Turns out the MS samples are full of TODO’s… Fortunately, I only needed a few things that weren’t implemented (filters in particular), so I simply added them.

Here is the new export dialog:

Much better :)

It took a bit longer to get going than I though it would because of a problem with the common controls dll.

To get that dialog, you have to load version 6 and the version that get loaded by default is the old version. I thought I had it fixed earlier, but one of my dll was still loading an old version, with not so nice results down the line. 

I also worked a bit on the main UI. I am now using a new template for the buttons, done by Martin Grayson. I modified it a bit so that it looks good on a glass surface. It still needs a little bit of tweaking to be perfect, but it’s ok for now. 

 

It nicely glows on mouse over (and it’s transparent, of course).

Testing (in VPC): logon background working

Posted by Julien on February 15th, 2007

Corrected a bunch of problems with file and directory security today. The restore function (used when uninstalling or applying the default logon) is now working correctly.

Updated logon replacement functions. They are now working a little bit better.

Applying a logon with a background and branding images is now working. PNG files (in Bitmap section) are still resisting me, but not for long :)

Program for the next few days:

  • Move the apply function into a thread
  • Add an animation when applying a logon
  • Finish the details panel
  • Add the wait animation to the supported resources

WPF File Dialogs

Posted by Julien on February 13th, 2007

Arghhhhhh. What is that ? Are they kidding or what ? WPF is supposed to be the next generation API and the only thing they provide out of the box is that ?

  • Crappy Windows 95 era icons ? CHECK
  • “classic” style drop down boxes and buttons ? CHECK

What a shame really. On Vista this is so lame. I hope they provide something better in the next version of WPF ! Ah well, let’s pinvoke into the new Vista APIs then… 

Luckily, they are providing samples just for that. But why not include it then? Time & quality constraints aren’t really a good excuse when it comes to things used as much as a file dialog.

Drag&Drop Support, Capabilities for FileSupport Dll

Posted by Julien on February 13th, 2007

Today I added drag&drop support. Now you can simply drop a logon file and it will be added to the list of logons. I also added support for logonxp format. It only took me 20 minutes from start to finish, and now logonxp files can be imported and loaded.

I had to modify the interface a bit to add capabilities support. Basically it’s a flag that the dll sets to inform the app what kind of operations it can do. The operations available are:

  • Register (register and un-register the file format)
  • Load (load a logon from a folder)
  • Save (save a logon to a folder)
  • Import (import a compressed logon file)
  • Export (export a logon to a compressed file)

 For example, the logonxp dll supports loading, importing and registering.

I also worked a bit on resource replacement. Basically, as you can have HighDPI images and normal images, if one variant is available and not the other, I automatically use the one provided for both scenarios. The same is true for backgrounds. You can provide several resolutions and it will automatically choose the closest match for other resolutions. The function that does it for backgrounds is kind of limited right now and need a bit of testing but that will do it for the time being.

LogonSwitcher: Logon Preview & more backend work

Posted by Julien on February 13th, 2007

Not much visual work done yesterday, at least not as much as I would have wanted. I added an error background (shown when the file linked in the logon configuration doesn’t exist). I also corrected the footer (now with a correctly aligned Apply button). Finally, I added some elements to the logon preview: the user name and tile.

It’s actually the later that took me quite a lot of time. Somehow, there doesn’t seems to be a public API to programmatically get the user picture. Well, after a bit of tracing I found an exported function in shell32.dll that does just that. The only problem is that it’s not documented…

After quite a long time in the debugger, I finally had something working. Nothing surprising on the way it works, but my relative inexperience with pure win32 programming prevented me to to “get it” much sooner. And I still don’t know what one of the parameters is for. I’ll figure it out later (maybe).

On the backend side, I reorganized the class to apply an existing logon, consolidating it with the one that managed logon resources. I finally added file security & token management (I took a MS sample that nicely encapsulate token & privilege management, and added a class to take care of file access modification).