|
||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionMicrosoft, in their infinite wisdom, decided to hide the application main message loop from programmers working with VC++ .NET Forms. Unfortunately, sometimes a programmer requires access to the loop. Fortunately, Microsoft provides a mechanism for doing so. Unfortunately, their documentation is sparse and provides little support for C++. Presenting a clear and well-documented C++ example of using this mechanism is the goal of this article. Along the way, we have the perfect opportunity to illustrate the use of delegate methods serving as callback functions. Using the codeThere are actually two projects in the example code. The first project is called "Commander" (see illustration above). It is launched with the mouse, and enables the user to launch and kill other applications (.exe files). The "Launch Client" button will bring up the normal OpenFileDialog panel. The user can then browse for any .exe file, select it, and it will be launched. The "Normal Close" button will send a What’s unusual about this? Well, in the old unmanaged code environment, probably nothing. Programmers have been working with the application main message loop to intercept user-defined messages since the beginning of time. But in the managed code environment, the message loop is completely hidden from the programmer, i.e., the actual code is never exposed anywhere so the programmer can modify it. So, how did "Commander Client" receive and respond to a user-defined message? Well, the answer is, we installed a message filter in the message loop of "Commander Client". First, we created an object called " public: bool PreFilterMessage(System::Windows::Forms::Message *m)
This is the method that is called by the application’s main message loop to do the actual message filtering. Next, we install a newly instantiated " Application::AddMessageFilter(CAST(IMessageFilter*,this->shutdownTrap));
OK, that explains how our user-defined message is intercepted in the message loop. But once the message has been intercepted, how does it shutdown the application? Well, that’s accomplished using a delegate callback. Delegate functions are the equivalent of function pointers, in unmanaged code. When we instantiate the " private: System::Void alienShutdown(ShutdownMessage *e);
So, using the __delegate System::Void ShutdownDelegate(ShutdownMessage *e);
Next, we instantiate a delegate of that type: ShutdownDelegate *delegate;
delegate = new ShutdownDelegate(this,alienShutdown);
Finally, when we instantiate the " this->shutdownTrap = new ShutdownMessageFilter(delegate);
When the application message loop receives any message, it passes that message to our filter by invoking the filter’s I sub-classed Points of interestNothing demonstrated in this code is conceptually new in the old unmanaged code world. But implementing parallel instrumentation in the new managed code world is somewhat cryptic and seldom seen. Making it understandable is the point of this article. As a final note, I want to mention that similar instrumentation can be implemented to invoke any method in an application, even those that don’t have corresponding GUI controls. I spent many years designing and implementing GPIB interfaces for real-time embedded projects on UNIX hosts, and I have always lamented that Windows applications are, well, how can I put this, so "Windows oriented". The absence of command line possibilities and remote control interfaces in the Windows programming environment is irritating (to me at least). Using the methods illustrated in my example, one could theoretically create an entire "message" interface to any .NET Forms application, completely independent of the GUI. Such an interface offers the possibility of third-party code controlling your app without a formal API or .dll (all that is needed is to publish the table of messages and their corresponding actions). It also doesn’t care about such considerations as whether or not the application’s window is maximized, minimized, off-screen etc., or which control (if any) in its main window is focused. The message can be directed to any method that you desire, bypassing the GUI altogether.
|
|||||||||||||||||||||||||||||||||||||||||||||||