It’s not very often that I have something to Rant about that’s also Geek-related, but we’ve got a winner, and it’s all about Whidbey and the .NET Framework 2.0. It’s probably a good thing for application security, but from a programming point of view, I feel hog-tied. Oh, and if you’ve never heard of Whidbey, skip this Rant – it’s not for you!
An old “trick” that I picked up from my days in C++ is that of a static pointer to one’s self. Most applications have one main window – not all, of course, but this is from a Windows application programmer’s point of view – and there would be times in C++ that you’d want a modeless dialog or a multi-threaded environment, but you’d still want to access the main window. Access it, without any major coding issues or stumbling blocks, which is usually the tricky part.
Enter the static pointer:
// .h
class ImAClass
{
public:
static ImAClass *thePointer;
}
// .cpp
ImAClass *ImAClass::thePointer = NULL;
ImAClass::ImAClass()
{
thePointer = this;
}
Oh shit, my spell checker just screamed at me. Anyway, the thought is that anywhere else in your codebase, you can reference the main object by using thePointer->method(). Of course, you had to be careful of reentrant code and because C++ is very unforgiving, but it worked.
And guess what? In C# 1.x… well, it worked there. too. And as I quickly learned, as I’ve been attempting to port SharpMT over to Whidbey, it doesn’t work very well anymore. In fact, it doesn’t work at all. The method would sometimes get call and then give you an exception at the Application level. Other times it wouldn’t work at all. Took a while to figure out what was going wrong, actually, seeing as the IDE and Framework are in beta, but they’ve both been behaving well. I eventually found that it was a cross-thread access related error.
This was a key thing for me. I come from the old school of socket theory, where you spin out a thread with a blocking socket. If the socket fails as it finds a server, connects to the server, makes a request, gets a response, or reads a response, then the UI is updated with a “oops, there was a problem”. If the socket succeeds in its task, then the UI does a happy dance of joy. Either way, I believe in threads, blocking sockets, and updating UI as things work (or don’t work). This notion was not a very happy one in .NET 2.0 land.
So I started looking for an alternative, and found one… sort of. HttpWebRequest objects have a BeginGetResponse method that takes in a callback method. When that callback is called, you get to create a HttpWebResponse object, and from that you can call the BeginRead method. BeginRead takes in a fixed-size array of bytes to read in data and issues a callback when it finishes reading. It’s all supposed to be threaded, but when I tried it, it hung my UI. Not only that but what the hell is with a fixed array for this call?! That’s so 1995 it made me ill. I’m hoping that I’m a bonehead and missed something with this technique, so I opted to look online. Occasionally there are helpful Whidbey examples, after all… that was when I discovered that this stuff was in the 1.x Framework and it’s not very well documented!
I don’t think many people use this, actually. Case in point: I’ve coded in .NET for a long while now, yet I’v never had to use this callback stuff because I’ve used threads for HTTP-based data collection. I did find a couple of examples but both of them contradicted each other. One said that this process would be completely asynchronus (and threaded); another put the whole thing into its own thread. Go figure – all these hoops to jump thru and not only do you still have to throw a thread out there but you’re right back to the first problem.
And that problem is pretty simple. The main window is in one thread; the socket thread is in another. Calls from the socket thread cannot impact anything on the UI that is running on that first thread. If you do, you’ll get an exception at the Application level… usually.
That is, unless you use a delegate. I’ve had to use delegates before, while working on SharpMT 2.2. The feature that caused me some issues was the “open a draft by double clicking on it and don’t open a new instance” one. This meant that I had to intercept the open command (from the double click) and tell an already running process (in it’s own thread, of course!) that it should do something UI related. This is what a delegate is for – you put a delegate member in the main form. The second form/thread/process then Invokes the delegate. The delegate is tapped to call a method within the first object, on the main object’s thread.
Of course, this too could lead into massive “code readability” issues, with a bunch of delegates running around, but there’s a simple work around for that, too. Instead of creating your own delegates, you can do the following:
private void ThreadProc() { Invoke((MethodInvoker) delegate { SomeMethodOnTheMain("yay!"); }); }
And it works, now. Which means I can continue in my coding in the off hours! I don’t know how it impacts resources or calls, but I hear MethodInvoker has little overhead and is pretty high up on the priority list for calls… should be interesting to see if it carries through to the official release of the Framework, thought.
Did I mention… it works???
Upgraded to .NET 2.0 about a week ago. Doing so broke most all my code that had multiple threads in it, because the prior version was forgiving about touching UI objects from child threads.
Not so 2.0.
I’d like to see a more complete example of your solution. Thanx!
I can expand on it a bit, but I actually got it out of a sample in the Beta.
What language are you using?