In the article, "Using a VCL Form in a DLL," we discused how to implement a VCL form contained in a DLL. However, we didn't cover the special case of an MDI child form in a DLL. Let's say your C++Builder application's main form is an MDI form. If you try to use an MDI child form contained in a DLL, you'll get the following exception from VCL: No MDI forms are currently active. "What?" you say. "But I have an MDI form in my application!" Not according to VCL you don't. Let's see why this happens.
You must also set the DLL's Application object back to its original state before the DLL unloads. Doing so lets the VCL memory manager clean up any memory allocated for the DLL. You'll have to store the DLL's Application object pointer in a variable global to the DLL so it can be restored before the DLL unloads.
| Create a global TApplication pointer. | |
| Save the DLL's Application object in the global TApplication pointer. | |
| Assign the calling application's Application object to the DLL's Application object. | |
| Create and show the MDI child form. | |
| Reset the DLL's Application object before the DLL unloads. |
The first step is easy. Place the following code at the top of your DLL's source unit:
TApplication* DllApp = 0;We set the pointer to 0 so that we can tell whether it's already been assigned. Next, create a function that will perform the TApplication switch and create the child form. The function will look something like this:
void ShowMDIChildForm
(TApplication* mainApp)
{
if (!DllApp) {
DllApp = Application;
Application = mainApp;
}
TChildForm* child =
new TChildForm
(Application->MainForm);
child->Show();
}
When you call this function, you'll pass the Application object of the calling
application. If the DllApp pointer hasn't yet been assigned, you assign the
Application object of the DLL to the temporary pointer. You then assign the
Application object of the calling application to the DLL's Application object.
This check ensures that the Application object is set only once. Next, the code
creates the MDI child form and passes the calling application's MainForm as the
owner. Finally, the form is displayed.
All that remains is to reset the DLL's Application pointer prior to unloading
the DLL. You might think you'd perform this action in the OnClose event
handler for the calling application. However, by the time OnClose fires,
it's too late--the DLL has already been unloaded. The next best thing is to
perform the action in the OnQueryClose event handler. To do so, you'll need a function in the DLL that resets the Application pointer:
void ResetDllApplication()
{
if (DllApp)
Application = DllApp;
}
Remember, you saved the DLL's Application pointer earlier; and now you restore
it. Finally, call this function from your application's OnQueryClose
event handler, and the DLL will unload without incident.