Porting a Client Server Application To Web / ActiveX – Part 2

This is part II which continues from things I learned since the last posting (here).

This information was learned while working in Codegear C++ Builder 2007. I was/am tasked to port a large Win32 application to run inside an ActiveX Container that loads inside a larger Web Application. Here are items I came across:

– Changing the container of the Win32 Application from a Win32 EXE to a TActiveForm (the Borland ActiveX wrapper object to hold UI objects) can be picky and tricky. I learned quickly that memory leaks and memory corruption seems to get exposed much more quickly in the active X world. Memory management has some issues when it comes to Borland’s implementation of the ActiveX wrappers. For example I tried to minimize changes to the Win32 suite of products and just make a simple ActiveX Panel type of container that I could “parent” the existing applications to as a replacement of the typical win32 EXE main form. That appeared to work (and does work fine). This Win32 Suite of products includes plugin DLL’s which also get loaded and add on features and additional UI components. When loading these plugins it was necessary (even BEFORE moving to Active X) to set the Borland Forms::Application->Handle global variable to the main object’s handle of the loading container (in the Win32 world was the Exe’s mainform, while in the ActiveX environment was NOT the mainform but a TPanel that was parented to the TActivForm). Additionally when movng to Active X you must (right after setting the Application->Handle in any DLL’s) add the following lines of code (to avoid random EInvalid Pointeror EAccessViolation errors related to pop-up hints):

Forms::Application->ShowHints = false;

Forms::Application->ShowHints = true;

This fixes a known VCL bug that if reloading the web page serving up the ActiveX control and passing a NEW handle to the DLL’s the VCL still uses the old handle and thus you get insanity when hovering over controls that want to show popup hints.

– Another key thing to watch out for is be very careful how you manage object destruction. At least in terms of the VCL you have to Close forms then have the destructor get called or you may have EAccessViolations on reload or even on closing of the webpage serving up the control. Here are some rules I found that should be followed:

– Add javascript on the page serving up the ActiveX control to call a method on your activeX control during the onbeforeunload event of the page. This method could be called something like ShutdownClean() or something. Have the code in that method of your activeX control do a clean shutdown of your application(s) components (remember closing forms, cleaning up memory in proper order). In your ActiveX containers destructor allow some cycles for the VCL to actually do its internal cleanup or you will see more random crashes with EAccessViolation and similar hard recursive types of crashes. That means in the Destructor of the Main Active X container at some point do an Application->ProcessMessages(). This is critical as it appears to allow pending internal VCL cleanup to occur while pointers are still valid. In the Active X Container Close event (which is called before the destructor) set the Application->Handle = NULL; This too was important for me, not sure if you will require that step?

– How do you get the Actual path where the Active X control is executing at runtime? The typical VCL Application->ExeName mechanism does not give it to you. Simply call (and store for later use as required):

GetModuleFileName(HInstance,….)  should get you what you need. The physical location always seems to be located somewhere in c:\windows\Downloaded Program files\ (substitue the windows folder for your version as required)

– To get modal dialogs to properly show modal inside the Active X container you must set OLE initialization COINIT to ApartmentThreaded, while Threading Model should be single.

– One solution for the LACK of support in Codegears ActiveX wrapper for TMenu related items could be (which works):

– At runtime detect whenever the menu structure changes and dynamically build TLabel’s with associate Popup menu items which give a similar appearance as regular VCL menus. This can be all done dynamically at runtime (keep you existing menu logic that merges and unmerges menu items etc.. and build the new “web” based menu structure based on the existing menus.

– For Marking your Cab or OCX Safe for scripting edit the Active X Projects MAIN project file and replacer the method looking like this:

// Entry point of your Server invoked to instruct the server to create
// registry entries for all classes supported by the module
//
STDAPI __export DllRegisterServer(void)
{
//return _Module.RegisterServer(TRUE);
HRESULT ret_val = 0;
std::auto_ptr<TRegistry> myRegistry(new TRegistry());

ret_val = _Module.RegisterServer(TRUE);

if( ret_val == S_OK) // change ret_val if your code is critical
{
try
{
myRegistry->RootKey = HKEY_CLASSES_ROOT;
if( myRegistry->OpenKey(
“\\CLSID\\” + Comobj::GUIDToString(CLSID_<INSERT YOUR SPECIFIC CLID HERE>) +
“\\Implemented Categories”, true )) // create and open
{
myRegistry->WriteString( “”, “”); // Set (Default) value to null
myRegistry->CreateKey( Comobj::GUIDToString( CATID_SafeForScripting));
myRegistry->CreateKey( Comobj::GUIDToString( CATID_SafeForInitializing));
myRegistry->CloseKey();
}
}

catch(ERegistryException &E)
{
ShowMessage(E.Message);
}
}

return ret_val;
}

Likewise you can add two registry entries to your INF file if you have one (for good measure):

[AddToRegistry]
HKLM,”SOFTWARE\Classes\CLSID\{<INSERT YOUR SPECIFIC Active X Control GUID HERE>}\Implemented Categories\{7DD95802-9882-11CF-9FA9-00AA006C42C4}”
HKLM,”SOFTWARE\Classes\CLSID\{<INSERT YOUR SPECIFIC Active X Control GUID HERE>}\Implemented Categories\{7DD95801-9882-11CF-9FA9-00AA006C42C4}”
– Signing your Active X control or CAB file simply tells the world a 3rd party was paid money to make you believe the control is coming from the Company name listed when the Browser prompts you to download it. You need a certificate from someone like verisign and just execute:

SignCode -spc <You company’s Certificate>.spc -v <You company’s Private Key>.pvk -n “<Your control or cab file>” -i http://www.<yourwebsite>.com -t http://timestamp.verisign.com/scripts/timstamp.dll -tr 10 <Your control or cab file>

If you do things right and the design is flexible enough you could get away with shipping a container that runs your application components via Win32 EXE and/or ActiveX container and/or some other container like automated testing tools such as FIT or CppUnit etc.

The main thing to remember is to be patient and be prepared to spend time figuring out what is happening before you give up and blame a framework or vendor for some “catastrophic failure”.  If our suite can run in this environment it gives me a lot of hope for many others.

– To Debug your active X control simply run this as the host application:

C:\Program Files\Internet Explorer\iexplore.exe

passing as a commandline parameter the html document that loads the Active X control. ie:

C:\Program Files\Internet Explorer\iexplore.exe c:\code\myfile.html

In Codegears IDE you would likely select the Register ActiveX server menu item to force IE to load the version of the control that the IDE builds for proper debugging.

Hope that helps you.

Overlooking the Shuswap near Kamloops BC


Comments are closed.