Tuesday 24 November 2009

Infragistics Intermezzo

Ok, I know I promised you some cool posts and I really was going to write them. However, I am in my own personal crisis and all because of Infragistics controls. Ok, I know that some people like to complain and blame others for their mistakes. I am tempted to do that all the time and I am not always succeeding in abstaining, but this time it is not a pointless blame shift, this is totally real.

Let me put it in no uncertain terms: Infragistics controls suck shitty balls! They are poorly made, badly documented, there is no architecture that one can talk about (except in funny anecdotes at parties) and they are a complete pain in the ass. After giving some time estimates of how long it would take me to finish up some tasks I ended up repeatedly doubling that time because of the stupidity of Infragistics controls. Have I mentioned enough the shitty balls? And the sucking? Because I don't feel completely satisfied.

A small example: class A is inherited by class B. The functionality of class B is implemented in class A as "if I am B, then...". Then other classes using the A class sometimes have checks to see if it is not B, so that they would behave in a completely different way. I am not a brilliant software architect or something, but this is simply insane!

What about the grid columns and rows that are NOT web controls, nor do they implement some events or overridable methods that control their rendering. Instead, the grid is asking questions like "is this a template column? Then add this to the rendered string" (so not even a Controls collection that one can manipulate). And if this weren't enough, I get to have to fix errors in the javascript from Infragistics by replacing whole functions, because there is no other way to get through. One step forward and two back, just like bloody Sisyphus!

I had expected this to take 5 days and it took 3 weeks and I am still not done. My self esteem is plummeting, I am losing my will to live, I feel like the only satisfaction I could have is to go to the Infragistics team and tear them limb by limb, laughing all the way. I sincerely wish all of their managers, sales people, developers and remote assholes that finished tasks without consideration for the other developers they were working for a slow and painful death.

The fixes and solutions I have found are so unavoidably ugly that I don't dare to publish them on the blog, so my advice for you if you use Infragistics controls is to throw them all away and start from scratch. It will take you longer, but in the end you get a good thing, satisfaction for a job well done and a maintainable code. Don't worry, you can be a completely useless developer and you will still do a better job.

On a brighter note, I may start some attempts to code in Mono or at least create stuff in a different domain that what I have worked so far, so good things will happen on the blog, only not in the immediate future.

Monday 23 November 2009

All Tomorrow's Parties by William Gibson

book coverAll Tomorrow's Parties is part of the Bridge trilogy, together with Virtual Light and Idoru. Placed in a world that is not too distant from our own, but changed brutally and irreversibly by the advent of new technology, it features some of the same characters as the previous books and tells the story of nodal points, as viewed through the eyes of Laney, the quantitative analyst, and of the people that are inadvertently in the middle of profound change. Laney is a guy that can sense accretions of data intuitively, because he was subjected to trials of some weird drug, and he notices a large nodal point, a place where data points to a change in the way the world works.

I will let you read it and see what this is all going towards. I must say that it felt like an easier book than Idoru, maybe because it has more action sequences and (a bit) less descriptive prose. It is a strange thing to understand the world of Gibson's imagination and feel so strongly about it, yet in the same time see that the world is not really going there. The details that the author infuses in his stories make all of his books seem part of reality and, having finished some story, I feel that the world around me is a bit fake. I believe that is a mark of a great writer.

Idoru by William Gibson

Book cover It seems that I started William Gibson's the Bridge trilogy in reverse order. I finished reading All Tomorrow's Parties and, before I could blog it, I started reading Idoru and realized that it was set in the same universe and had some of the same characters. And this only to find out by Wiki'ing that there is a third (and first) book in the series.

Well, I can't possibly hold up until I start and finish that one, and I may even not read it. Not because Gibson is not brilliant, but because the level of attention necessary to enter the atmosphere of his books is not appropriate for my daily subway trips to work. Because of this I recommend reading William Gibson books somewhere alone, in bed, well rested, ready to virtually go somewhere else and abandon reality for a while.

Back to Idoru, a book about a Japanese popular idol (hence the name of the book) who is entirely virtual, a programatic entity made for the sole purpose of entertaining. However, this inadvertently turns into a proper AI, becoming more human as the data from her fans becomes part of her being. Of course, a lot of characters are doing their thing in a typical for Gibson very detailed world that mixes the increasingly neglected realilty with emerging virtual worlds and concepts.

It is a good book, but I recommend you start with Virtual Light, go through Idoru and finish the proper way, by reading All Tomorrow's Parties.

Thursday 12 November 2009

Your Silverlight developer components are out of date

For a few weeks I have been having problems running Silverlight on my machine, especially since I had SL3 installed and also Expression Blend, version 3. I didn't mind much, because I don't need Silverlight most of the time. But since sometimes I do, here is the solution for the "Your Silverlight developer components are out of date" error when trying to install Silverlight.

Go to http://go.microsoft.com/?linkid=9394666 and install the Silverlight tools. Yes, they are version 2. No, I don't know why Silverlight 3 would have problems because of version 2 Silverlight tools. However, installing the tools solved my problem.

Thursday 5 November 2009

Use CSS expression to initialize html elements

Internet Explorer added something called expression to CSS, something purists have booed at for mingling javascript and CSS. Well, boo back! I happen to like stuff that can solve problems. If I were at Microsoft I would create an entire subset of javascript and css functionality. But hey, that's just me.

Anyway, I have decided to use expression to run an initialize function on newly created elements. It would work like this:
initialize:expression(window.initializeElement?initializeElement(this):null);
This CSS bit tells Internet Explorer (and none of the other browsers) that the initialize style property should get the value of the initializeElement function every time the browser refreshes the layout of the element. In the function itself I would do something like this:
function initializeElement(elem) {
if (!elem.style.initialize) {
doSomethingWith(elem);
}
return true;
}
This basically executes doSomethingWith on each element matched by the CSS rule and only once.

Good theory, but in practice it was terribly slow and, after a while, it managed to kill Internet Explorer with a strange System.AccessViolationException: Attempted to read or write protected memory error.

What happened? The slowness, I gathered after a while, was caused by the function doSomethingWith because it changed the style of the element. That meant that the css rule was being applied again before the function ended and returned true. Changing things to:
function initializeElement(elem) {
if (!elem.style.initialize) {
elem.style.initialize=true;
doSomethingWith(elem);
}
return true;
}
fixed it.

The error that killed Internet Explorer was even stranger. After a while I narrowed it down to using jQuery. I have no idea what it did, probably trying to access computedStyle or something like that. The thing is that changing an $(elem).height() with elem.offsetHeight solved it.

Wednesday 4 November 2009

Get Visual Studio to use (better) more than 2GB of memory

I actually didn't know that a 32bit program could not use more than 2Gb of virtual memory by default. It makes sense, now that I think of it, but I just didn't make the connection. My office computer has 3Gb of memory and there is also the swap file, so having a program using more than 2GB of memory would be beneficial. And I am talking about Visual Studio here, especially since today I got an error I've never seen before: "Not enough storage is available to complete this operation".

So I've stumbled upon this article: Hacking Visual Studio to Use More Than 2Gigabytes of Memory which told me how to convince Visual Studio to use more than 2GB of memory. Also, since I am a ReSharper user, I found this little wrapper for Visual Studio that makes it use a different memory allocation method that reduces memory fragmentation: OutOfMemoryException Fix.


Short story shorter (for XP users with Visual Studio 2008 only - read the full articles for other configuration):
  1. Edit boot.ini to have the /3GB option
  2. Use editbin /LARGEADDRESSAWARE devenv.exe to change Visual Studio to have IMAGE_FILE_LARGE_ADDRESS_AWARE in the process header (editbin can be found in \Program Files\Microsoft Visual Studio 9.0\VC\bin\
  3. Download the Jetbrains devenv wrappers and change the signature of the Visual Studio shortcut to point to devenv2008_wrap.exe instead of devenv.exe
  4. (of course) Restart the computer


Update:
Thanks to the warnings from Lex Li, I went to study the /3G switch some more. The most important thing seems to be to also use the /USERVA switch to tune the /3G functionality.

More details here:
Memory Management - Demystifying /3GB
Summary of the recent spate of /3GB articles.

Monday 2 November 2009

Things I've learned from HotBabe.NET

Rebecca Romijn as the icon of HotBabe
Today I've released version 1.2 of the HotBabe.NET application. It is a program that stays in the traybar, showing a transparent picture, originally of a woman, sitting on top of your other applications. Clicks go through the image and the opacity of the picture is set so that it doesn't bother the use of the computer. When the CPU use or the memory use or other custom measurements change, the image changes as well. The original would show a girl getting naked as the use of CPU went up. Since I couldn't use what images it should use, I did my own program in .NET. This blog post is about what I have learned about Windows Forms while creating this application.

Step 1: Making the form transparent



Making a Windows Form transparent is not as simple as setting the background transparent. It needs to have:
  • FormBorderStyle = FormBorderStyle.None
  • AllowTransparency = true
  • TransparencyKey = BackColor
However, when changing the Opacity of the form, I noticed that the background color would start showing! The solution for this is to set the BackColor to Color.White, as White is not affected by opacity when set as TransparencyKey, for some reason.

Step 2: Making the form stay on top all other windows



That is relatively easy. Set TopMost = true. You have to set it to true the first time, during load, otherwise you won't be able to set it later on. I don't know why, it just happened.

Update: I noticed that, even when TopMost was set, the image would vanish beneath other windows. I've doubled the property with setting WS_EX_TopMost on the params ExStyle (see step 4).

Step 3: Show the application icon in the traybar and hide the taskbar



Hiding the taskbar is as easy as ShowInTaskbar = false and putting a notification icon in the traybar is simple as well:
_icon = new NotifyIcon(new Container())
{
Visible = true
};
Set the ContextMenu to _icon and you have a tray icon with a menu. There is a catch, though. A NotifyIcon control needs an Icon, an image of a certain format. My solution was, instead of bundling an icon especially for this, to convert the main girl image into an icon, so I used this code.

Step 4: Hide the application from Alt-Tab, make it not get focus and make it so that the mouse clicks through



In order to do that, something must be done at the PInvoke level, in other words, using unsafe system libraries. At first I found out that I need to change a flag value which can be read and written to using GetWindowLong and SetWindowLong from user32.dll. I needed to set the window style with the following attributes:
WS_EX_Layered (Windows Xp/2000+ layered window)
WS_EX_Transparent (Allows the windows to be transparent to the mouse)
WS_EX_ToolWindow (declares the window as a tool window, therefore it does not appear in the Alt-Tab application list)
WS_EX_NoActivate (Windows 2000/XP: A top-level window created with this style does not become the foreground window when the user clicks it).

Then I found out that Form has a virtual method called CreateParams giving me access to the style flag value. Here is the complete code:
protected override CreateParams CreateParams
{
get
{
CreateParams ws = base.CreateParams;

if (ClickThrough)
{
ws.ExStyle |= UnsafeNativeMethods.WS_EX_Layered;
ws.ExStyle |= UnsafeNativeMethods.WS_EX_Transparent;
}
// do not show in Alt-tab
ws.ExStyle |= UnsafeNativeMethods.WS_EX_ToolWindow;
// do not make foreground window
ws.ExStyle |= UnsafeNativeMethods.WS_EX_NoActivate;
return ws;
}
}


However, the problem was that if I changed ClickThrough, it didn't seem to do anything. It was set once and that was it. I noticed that changing Opacity would also set the click through style, so I Reflector-ed the System.Windows.Forms.dll and looked in the source of Opacity. Something called UpdateStyles was used (This method calls the CreateParams method to get the styles to apply) so I used it.

Update: Apparently, the no activate behaviour can also be set by overriding ShowWithoutActivation and returning true. I've set it, too, just to be sure.

Step 5: Now that the form is transparent and has no border or control box, I can't move the window around. I need to make it draggable from anywhere



There is no escape from native methods this time:
private void mainMouseDown(object sender, MouseEventArgs e)
{
// Draggable from anywhere
if (e.Button == MouseButtons.Left)
{
UnsafeNativeMethods.ReleaseCapture();
UnsafeNativeMethods.SendMessage(Handle,
UnsafeNativeMethods.WM_NCLBUTTONDOWN,
UnsafeNativeMethods.HT_CAPTION, 0);
}
}
Both ReleaseCapture and SendMessage are user32.dll functions. What this mouse down event handler does is say to the Window that no matter where it was clicked, it actually clicked the draggable area.

Step 6: Remove flicker



Well, I am getting a bit ahead of myself, here, the flickering becomes annoying only when I implement the blending of an image into another, but since it is also a style setting, I am putting it here:
SetStyle(ControlStyles.AllPaintingInWmPaint 
| ControlStyles.UserPaint
| ControlStyles.OptimizedDoubleBuffer, true);
This piece of code, placed in the Form constructor, tells the form to use a double buffer for drawing and to not clear the form before drawing something else.

Update: It seems the same thing can be achieved by setting the Control property DoubleBuffer to true as it seems to be setting ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint and ControlStyles.UserPaint seems to be set by default.

Step 7: Blend the images one into the other



Well, in order to make an image blend nicely into the next, I used a Timer. 10 times a second I would decrease the opacity of the first, increase the opacity of the second and draw them one over the other.

A small detour: if you think about it, this is not absolutely correct. A 70% opacity pixel blocks 70% of the light and lets 30% of the image behind show. If the image underneath has 30% opacity, then it shows 30% left from 30% of the image and it doesn't get opaque. But if I just set the opacity of the bakground image to 100%, it shows really strong on the parts of the images that are not overlapping, where image1 is transparent and image2 is not.

Unfortunately there is no resource friendly way to read write/pixels. It's either GetPixel/SetPixel in a Bitmap class (which are very slow) or using pinvoke again. I prefered to use the opacity hack which looks ok.

I was already using an extension method to invoke any change on the form on its own thread (as the Timer ran on its own thread and I would have gotten the "Cross-thread operation not valid: Control [...] accessed from a thread other than the thread it was created on" exception or "Invoke or BeginInvoke cannot be called on a control until the window handle has been created"):
public static void SafeInvoke(this Control control, Action action)
{
if (control.IsDisposed)
{
return;
}
if (!control.IsHandleCreated)
{
try
{
action();
}
catch (InvalidOperationException ex)
{
}
return;
}
if (control.InvokeRequired)
{
control.BeginInvoke(action);
}
else
{
action();
}
}

This is where I got the "Object is currently in use elsewhere" InvalidOperationException. Apparently the Image class is not thread-safe, so both the timer and the form were trying to access it. I tried locking the setter and getter of the Image property on the class responsible with the image blending effect, with no real effect. Strangely enough, the only solution was to Clone the image when I move it around. I am still looking for a solution that makes sense!

Step 8: Showing the window while dragging it



Using WS_EX_NOACTIVATE was great, but there is a minor inconvenience when trying to move the form around. Not only that the image is not shown while moving the form (On my computer it is set to not show the window contents while dragging it), but the rectangular hint that normally shows is not displayed either. The only way to know where your image ended up was to release the mouse button.

It appears that fixing this is not so easy as it seems. One needs to override WndProc and handle the WM_MOVING message. While handling it, a manual redraw of the form must be initiated via the user32.dll SetWindowPos method.

The nice part is that in this method you can actually specify how you want the form draw. I have chosen SWP_NoActivate, SWP_ShowWindow and SWP_NoSendChanging as flags, where NoActivate is similar with the exstyle flag, ShowWindow shows the entire form (not only the rectangle hint) and NoSendChanging seems to improve the movement smoothness.

Quirky enough, if I start the application without Click through set, then the rectangle hint DOES appear while dragging the window. And with my fix, both the image and the rectangle are shown, but not at the same time. It is a funny effect I don't know how to fix and I thought it was strange enough to not bother me: the rectangle is trying to keep up with the hot babe and never catches on :)

Step 9: Dragging custom images



I am a programmer, that means that it is likely to add too many features in my creations and never make any money out of them. That's why I've decided to add a new feature to HotBabe.NET: droppping your own images on it to display over your applications.

At first I have solved this via ExStyle, where a flag tells Windows the form accepts files dragged over it. A WndProc override handling the WM_DROPFILES message would do the rest. But then I've learned that Windows Forms have their own mechanism for handling file drops.

Here are the steps. First set AllowDrop to true. Then handle the DragEnter and DragDrop events. In my implementation I am checking that only one file is being dropped and that the file itself can be converted into an image BEFORE I display the mouse cursor hint telling the user a drop is allowed. That pretty much makes the ugly MessageBox that I was showing in the previous implementation unnecessary.

Step 10: Reading files from web, FTP, network, zip files, everywhere, with a single API



Reading and writing files is easy when working with local files, using System.IO classes, but when you want to expand to other sources, like web images or files bundles in archives, you get stuck. Luckily there is a general API for reading files using URI syntax in the System.Net.WebRequest class. Here is a sample code for reading any file that can be represented as an URI:
WebRequest req = WebRequest.Create(uriString);
using (var resp = req.GetResponse())
{
using(var stream= resp.GetResponseStream())
{
// do something with stream
}
}


WebRequest can also register your own classes for specific schemas, others than http, ftp, file, etc. I created my own handler for "zip:" URIs and now I can use the same code to read files, web resources of zipped files.

One point that needs clarification is that at first I wanted an URI of the format "zip://archive/file" and I got stuck when the host part of the URI, mainly the archive name, would not accept spaces in it. Instead use this format "schema:///whatever" (three slashes). This is a valid URI in any situation, as the host is empty and does not need to be validated in any way.

The rest are details and you can download the source of HotBabe.NET and see the exact implementation. Please let me know what you think and of any improvement you can imagine.