Archived Forum Post

Index of archived forum posts

Question:

A Case of ActiveX DLL Hell

Oct 22 '12 at 18:12

I am a developer working on a Delphi XE2 application, which is distributed among hundreds of users.

It uses chilkatzip2.dll (activex) 32 bit. Version 12.9.9.0

In the case of at least one user (windows 7) we face a difficult and not well-understood problem.

The unzip function works well, the zip function seems to work faulty. At least unzipping a zipped file does not work. Note this is only one out of ~1000 users.

We placed the DLL in the application directory.

However we noticed that in the case of this user a chilkatzip2.dll is loaded from another directory: windowssyswow64, so this is apparently 64 bit?

Apparently installed by other software and loaded before ours. This dll has a somewhat lower version.

My question is: what to do to load our DLL, which would probably solve the problem?


Answer

Welcome to DLL Hell...

All ActiveX object are instantiated by a "CreateObject" statement where the argument is a name, such as "Chilkat.Zip". The "CreateObject" looks up some keys in the Windows registry to find the path of the DLL that is to be loaded. The purpose of ActiveX registration is to insert the appropriate registry keys so that "CreateObject" will be able to map the name to a DLL file location (see http://www.chilkatsoft.com/p/p_177.asp ).

Each programming language's "CreateObject" might be different in name or syntax, but they're all the same thing. In Delphi, it's something like this:

zip := TChilkatZip2.Create(Self);

When an ActiveX DLL is imported into Delphi, wrappers are generated (see http://www.chilkatsoft.com/p/p_230.asp ) that define and implement a unit for the ActiveX object. The TChilkatZip2.Create method is using the name ("Chilkat.Zip") or alternatively something called a CLSID to do the registry lookup, find the location of the DLL and load it. In this case there are two issues that cause what's known as DLL Hell (see http://en.wikipedia.org/wiki/DLL_Hell) :

1) The class name and CLSID do not typically change with new versions of the object.
2) The only way to create the object instance is via the class name or CLSID. In other words, in Delphi, the only way to create an instance of the ActiveX is via the Create function in the generated wrapper.

The problem in your case is that some other application is using a different version of Chilkat Zip, and it's installer creates the registry entries that points to the Chilkat DLL that was included in that product's install. However, your product wants to use a different version of Chilkat Zip. The two versions should be compatible -- but as with any software, bugs are fixed over the years and the newer version is likely to have solved problems that may still exist in the older version.

The only solution for your product is to make sure that the newer version of the Chilkat Zip DLL is registered last. Of course, this means the other product will implicitly also be using the newer version, and hopefully all will go well.

One interesting idea to make sure your app's DLL is registered last is to register it from within your program itself. This is an idea that came from another Chilkat customer a few years back using FoxPro: http://www.cknotes.com/?p=321

Your Delphi program should be able to call the ChilkatZip2.dll's DllRegisterServer function, which is a standard exported function of all self-registering ActiveX DLL's.

Finally, there is an alternative option to use the Chilkat DLL for Delphi instead of the ActiveX. This eliminates DLL Hell altogether. See:

http://www.chilkatsoft.com/delphiDll.asp
http://www.example-code.com/delphiDll/default.asp
http://www.chilkatsoft.com/refdoc/dd.asp