|
INPRISE Online And ZD Journals Present:
A non-visual component must occasionally respond to either Windows operating system or user-defined messages. However, a non-visual component has no window and, therefore, no window handle. And without a window handle, it cant receive messages. In this article, well explain how to create a hidden window so your non-visual components can receive messages. What youll
need
Thats really all there is to it. Since youll want to see this process in action, lets build a simple component to illustrate this concept. Creating the component Figure A: Select the
ancestor and name of your new class.
Now we have a new unit containing the basic source code for our component. (The code generated for the component will vary slightly depending on whether youre using C++Builder 1 or C++Builder 3. The differences arent important for this discussion, so we wont go over them here.) Go ahead and save your work. Choose File | Save All to open the Save As dialog box. Save Unit1.cpp and Unit1.h as TestBCB.cpp and TestBCB.h, respectively. Switch to the components header file. Place the following declarations in the private section of the class declaration: HWnd FHandle; void __fastcall WndProc(TMessage& Msg); The first line declares an HWnd variable called FHandle. This variable will hold the window handle after the window is created. The second line declares the WndProc function that will receive the messages. The function declaration must have the signature shown here in order to qualify as a WndProc. Next, move down to the public section of the class declaration and add this line below the constructor declaration: void DoIt(); This is a public function that well use to test the component. Your class declaration should now look like this (if youre using C++Builder 1, the declaration wont have the PACKAGE modifier): class PACKAGE TTest : public TComponent { private: HWnd FHandle; void __fastcall WndProc(TMessage& Msg); protected: public: __fastcall TTest(TComponent* Owner); void DoIt(); __published: }; Now switch to the components source unit. Enter the following line near the top of the unit (just above the ValidCtrCheck function is probably a good place): #define MY_MESSAGE WM_USER + 1 This line declares a user-defined message that the component will send to itself when the DoIt function is called. At this point, we must allocate a window handle for the component. This handle will provide a hidden window that we can use to catch messages in the component. Locate the components constructor, and add a line so that the constructor looks like this: __fastcall Test::Test(TComponent* Owner) : TComponent(Owner) { FHandle = AllocateHWnd(WndProc); } Thats all there is to that particular step. The AllocateHWnd function creates a hidden window and returns the window handle of the hidden window. Notice we pass the address of the WndProc function so that Windows knows where to send any messages. Speaking of WndProc, lets create that function next. Add this code to your source file: void __fastcall TTest::WndProc(TMessage& Msg) { if (Msg.Msg == MY_MESSAGE) MessageBox(0, "Got here!", "Message", 0); try { Dispatch(&Msg); } catch (...) { Application->HandleException(this); } } Windows calls this function whenever Windows sends a message to the component. The code in this function does two things. First, it checks to see whether the message received is our user-defined message, MY_MESSAGE. If it is, a message box is displayed so you can see that the message was, in fact, received. In addition, this code passes the message on for processing by the system (or by VCL). The Dispatch function performs this service. The try/catch block is used to ensure that, in the event an exception is thrown, it will be handled in the default manner. In a nutshell, the WndProc function watches for our custom message, while passing all other messages on for default handling. Now we only have to create the DoIt function, and our component will be finished. Add this code to your source unit: void TTest::DoIt() { PostMessage(FHandle, MY_MESSAGE, 0, 0); } This function simply posts a message to the components window handle (remember, the window handle was previously saved in the FHandle data member). Weve finished creating the component. Select File | Close All to save your work. Youll be prompted to save any outstanding changes. Testing the component Drop the TTest component and a regular button component on a form. Double-click the button and enter this code in the OnClick event handler for the button: Test1->DoIt(); Now, run the program. When you click the button, you should see a message box that says, "Got here!". Sure enough, the component works as advertised. Listings A and B contain the header and the source code for the TTest component. The code provided is for the C++Builder 3 version of the component. If you subscribe to C++Builder Developer's Journal, you can download both versions from our Web site at www.zdjournals.com/cpb; click on the Source Code hyperlink. Conclusion
Kent Reisdorph is a senior software engineer at TurboPower Software and a member of TeamB, Borland's volunteer online support group. He's the author of Teach Yourself C++Builder in 21 Days and Teach Yourself C++Builder in 14 Days. You can contact Kent at kentr@turbopower.com. Back to Top Back to 1998 Index of Articles Copyright © 1998, Ziff-Davis Inc. All rights reserved. ZD Journals and the ZD Journals logo are trademarks of Ziff-Davis Inc. Reproduction in whole or in part in any form or medium without express written permission of Ziff-Davis is prohibited. |