Completed! (Part Two)

| | Comments (3)

After coming up with the initial idea for the project, I decided to start simple. I made a form with a single button on it. The button's job was to display an open file dialog, and if the user selected a file (instead of cancel), then I set the wallpaper to that image file.

Laying out the button was easy -- and starting right in on the code wasn't too bad. I was happy to see that when I double clicked the button in the form editor, it took me directly to the button's action event code. Creating an open file dialog was a breeze -- the API was intuitive, and I was happily surprised by how easy the code editor's autocomplete feature is to use. One gripe about the autocompleter though is that it doesn't give suggestions about completing the local variables themselves. For example, if I have an Int32 named aVeryLongIntVariableName, then it would be nice if the autocompleter suggested that as a completion when I type aVer (or something like that). Another gripe I have is that the completer seems to be stupid about namespaces I am using. If I don't type System.IO.BlahBlahBlah (instead, just use BlahBlahBlah since I'm already using the Sytem.IO namespace), it gives me no way to complete BlahBlahBlah. I also found that failing to use the full namespace path makes the autocompleter behave kind of sporadically with completing method or properties in certain instances. But oh well, it still worked out well enough to get me on my way.

So once I had the file selection working, I dove right in to make it so that I can change the wallpaper. I was half expecting to see a Microsoft.Windows.Something class that gave me access to things like the wallpaper, but alas, there is no such beast. So I had to resort to writing a declare to SystemParametersInfo. It wasn't a large deal. I made a new class called Wallpaper (in the same namespace as the form) and gave it a static method to change the wallpaper to whatever string you passed it. One challenge to setting wallpapers is that Microsoft requires all wallpapers to be .bmp files (bitmap images). So if you're given a JPEG, you have to convert it to a bitmap and then set that bitmap as the wallpaper. Rather convoluted. So I had to figure out a way to convert a file of any type into a bitmap. It turns out that this is really easy if you can get an Image out of the file (which makes sense because GDI+ makes this easy, and I hear that .NET uses GDI+ under the hood for all graphics operations).

It turns out that converting a file consists of getting a FileStream (basically, opening the file up), and then making a new Image by calling Image.FromStream. Simple as that! And converting the image is just as easy -- just call Image.Save and pass in the format you wish to save to. So this part of the process was a breeze. Get the temp directory, and save the opened image to wallpaper.bmp in there. Done.

The next bit was actually setting the wallpaper. This is where I used my handy declare into SystemParametersInfo. I had to refer back to my .NET book to remember how to make the declare, but now that I've done one, I am pretty sure I can do any declares. They're not that hard to accomplish.

Here's where things get goofy. I was under the impression that one of the big things about .NET is how it's impossible to leak stuff because the garbage collector always collects things you can't use anymore. I took this to mean that I don't have to call any cleanup code since that all happens when the object is disposed of for me by the GC. Well, it turns out that this isn't wholly true. I had a monster leak every time I changed the wallpaper. I guess I have to call FileStream.Close and Image.Dispose to prevent this leak. Still not entirely certain why, but I don't mind too much. Cleaning up my own mess is a habit I got into with C/C++, and I'm happy to continue with it in C#, even if it is redundant.

The rest of the application sort of fell into place from here. I decided to work on the UI next so that I could have a list of wallpapers to choose from. An interesting thing that I had to work out was how to make the cancel button really cancel the changes the user just made. It wasn't too hard to figure out, but it still was one thing I ended up going back and redesigning partway thru because I didn't take it into account. Oops. ;-)

Once I had the UI functional, it was a matter of making everything work. I had to figure out how to use a folder selection dialog, which was just as easy as the open file dialog. I really like how easy it is in .NET to get full information about an entire directory -- the listing of files, and everything is right at your fingertips. Awesome!

While I was writing the code, I did stumble across two framework bugs (I mentioned this in my previous post). The first one is damn annoying. No matter what you try to do, you cannot save a RegistryKey as a multistring or binary data using SetValue. (Conversely, you cannot use GetValue to get those types either). I tried passing an ArrayList, a string[] and even a single string that had each entry double null terminated. This is contrary to what MSDN claims -- which is that you can use it for multi strings. But that's total malarky -- and if anyone can show me working code that proves me otherwise, I'll be happy. :-)

The other bug I ran into is a lot more esoteric. The numeric up-down control on the prefs window cannot have a help tag assigned to it. Doing so does nothing (no help is ever displayed). This isn't too big of a deal though since I can attach the tag to the nearby static text. But it's a framework bug nonetheless.

Aside from those issues, writing this first application was really quite easy. I am quite impressed with the language itself, as well as the framework. They are both quite elegant (mostly) to work with (but I already covered this topic once before). However, the IDE tends to leave me yearning for something better. There are a lot of things about it that seem to rub me the wrong way. In another post sometime in the future I will pick apart the IDE from a UI design (and usability) point of view. But for right now, I am mostly interested in feedback about the project itself, future improvements, comments on my source code (or ideas on how to refactor) and things of that nature. Any takers? ;-)

3 Comments

ill take a look at it when i get a chance...and btw, you can use textpad as your IDE and compile on the command line if you dont like visual studio...

I've actually thought about doing just that. TextPad is so nice and clean. The downside is the layout code has to be written by hand.

Leave a comment

Disclaimer

I'm currently an employee of REAL Software. My blog is mine. The opinions represented in this blog are mine as well and may not represent my employer's opinions. All original material is copyrighted and property of the author.

REALbasic® is a registered trademark of REAL Software, Inc. REAL SQL Server™ and Lingua™ are pending trademarks of REAL Software, Inc. All rights reserved.