My software is written in VB6. For diagnostic purposes I need to determine the actual DLL / OCX files which are loaded and used by the application on a customer's computer.
Since VB6 DLLs (including OCX files) are COM libraries they are loaded indirectly based on information in the registry. This means it is possible that a different file is being used than what was used in development / testing environments. Sometimes in a client environment this can cause malfunctions which are hard to diagnose without this information.
(My plan is to build a diagnostic readout window in my program that shows the libraries that the program is using at that moment.)
There are many ways in which runtime dependencies on DLLs (or OCX files) can be established. Ideally you would need to account for all of them:
This answer is specific to VB6 but many other programming languages would work similarly.
Mechanisms which establish runtime dependencies:
At Compile time for traditional dynamically-linked libraries (DLLs which are not COM)
- Files are (as their name suggests) dynamically loaded at runtime based on the linking process done at the end of compilation
- This includes VB6 code which has used a statement like:
Declare Function … Lib …
- (In .NET this would mean calling out into “native code”)
- To identify: Inspect the source code.
- To identify without sources: These can be detected by a tool like Dependency Walker
At Compile time for COM DLLs
- In VB6 this is known as “early binding”.
- This includes VB6 code which has explicitly set a reference to a DLL or OCX.
- Note that the dependency is actually on the COM class or interface GUID, and not explicitly on the DLL file itself.
- To identify: These are listed in the project VBP.
- To identify (alternate): If you don't have the VBP or source code, these dependencies can generally be revealed by by
IMPORT
statements in OLEView. You might need to look up some GUIDs from there in the registry to see what actual DLL files are used.
At Compile time for statically-linked libraries (not COM, not DLLs)
- Library code is included in the EXE or DLL which is being compiled. Therefore there is no runtime dependency to anything external.
- As far as I am aware, this is not possible for VB6 programs. Something like a C linker could use libraries like this. A rough equivalent in .NET would be using ILMerge to combine assemblies.
At Runtime for traditional DLLs (not COM)
- DLLs can be loaded arbitrarily using Win32 API such as
LoadLibrary()
.
- To identify: You have to look at the source to know what might happen.
- Alternately if you don't have the source you could use tools like Process Explorer and/or Process Monitor to observe a running instance and see what DLLs actually get loaded.
At Runtime for COM DLLs
- Classes can be loaded arbitrarily using eg VB6
CreateObject()
calls.
- In VB6 this is known as “late binding”
- Which DLL will be used to provide the class will be determined by the process’s activation context. The activation context is established by the app manifest file (if there is one) or the Windows registry otherwise (the normal default for VB6 programs).
- To identify: You have to look at the source to know what might happen. You also need to know what the configuration state will be on the PC that runs the code - which DLL files are registered, assuming a manifest is not used.
- Alternative for no source code: as in the case above
Important: dependencies can be chained. So really you need to "walk the links" of all the dependencies until you build up a complete mapping of what is required. Somewhere in that mapping you can draw a line between what you need to deploy and what the operating system or other runtime environment can be relied on to provide. (IMO for VB6, that line should be drawn rather liberally).
You may be thinking that all this makes the task very difficult or tedious – I totally agree. :)
You can use the Dependency Walker to find which DLL your program depend on.
But the OCX are not so easy to find because they are loaded at run-time based on the application dependencies and the registered components through the Windows registry. But you have to already know which OCX components your application references - from the Tools > References and all the places you call CreateObject
.