Determine which DLL and/or OCX files are actually used by my program? - dll

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.)

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.

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. :)

Related

VB6 compile against side-by-side assembly

I have a DLL written in C# and set for COM visibility. I have it setup as a side-by-side assembly and can successfully deploy the application to client PCs registration free. My question is related to the development PC. Is it possible to compile against the DLL in a similar registration-free manner or is registration required on the development machine? I have tried adding the DLL directly though the Project -> References menu and get an error stating "Can't add a reference to the specific file." The DLL is sitting in the same directory as the .vbp file and I have tried adding the DLL both with and without the client app manifest being present.
I have tried adding the DLL directly though the Project -> References menu
That adds a reference to a type library. A type library is a language-independent description of the types in a COM component, VB6 uses it to know how generate efficient code and to provide type checking and auto-completion. A type library is the exact equivalent of metadata in a .NET assembly.
Traditionally, and the way VB6 did it, the type library was embedded as a resource in a DLL. So you are probably used to picking a DLL in the dialog. That however doesn't work so well when the DLL is generated by C#, the type library can only be generated after the C# code is compiled. You have to pick the .tlb file in the VB6 dialog. The traditional way starts with the COM component being described in the IDL language, the type library can be generated before the code is compiled so can easily be embedded in the final DLL. It is technically possible to do it in C# as well, but the build steps are very laborious and painful, you essentially have to build the DLL twice with different build commands.
The type library for a C# library is normally generated in one of three ways:
Using Project + Properties, Build tab, "Register for COM interop" option. This requires VS to run elevated so it can write to the registry. You start VS elevated by right-clicking its shortcut and picking "Run as Administrator"
By running Regasm.exe, using the /tlb:filename option. An alternative for the 1st bullet and necessary if you don't want to run VS elevated for some reason. Using the /codebase option on your dev machine is also wise to make it work exactly like the 1st bullet and not require putting the DLL into the GAC with gacutil.exe
By running the Tlbexp.exe utility, the type library exporter for .NET assemblies. No registration is done, it only generates the .tlb file.
The first bullet is the normal choice and very desirable because you can never forget to update the type library this way. It is perfectly fine on a dev machine since you only really care about reg-free deployment on the user's machine. You probably got into trouble by not doing this anymore.
Using the 3rd choice is okay and more compatible with your goals, run Tlbexp from the Visual Studio Command Prompt. Just keep in mind that you have to do it again when you make changes to your C# code. Forgetting this once and losing clumps of head-hair trying to figure out why your C# changes don't seem to be effective or getting hard-to-diagnose error codes gives you lots of reasons to consider the 1st bullet again :) You can emulate the reg-free scenario by running Regasm.exe with the /uninstall option.

LoadLibrary MSVCRT Issue

There are two questions that confuse me:
I read from the Microsoft website that we can not use different C runtime in the same project. Say I have a dll compiled with /MT flag, then I can not use the dll in a /MD compiled project. My question is that if I use LoadLibrary() to load the dll, is it also necessary that I have the same C Runtime? What's the potential danger if I don't?
I think with the /MT flag, the runtime is statically linked into the binary file. But for one of my dll project, I made a dll with /MT. However, when I dumpbin.exe /dependents mydll, it shows that MSVCR100.dll is a dependent. My question is that why the dll is still dependent on MSVCR100.dll?
1) No, that's not a requirement. This happens in any program, the Windows DLLs use their own CRT for example. Mixing CRTs in one program is however very dangerous and can cause very hard to diagnose problems. The Windows apis were carefully designed to avoid those problems, they never require code to release memory that was allocated in a DLL, don't use exceptions, don't use standard C++ library classes, don't depend on locale or any other kind of shared CRT state. The kind of things that go wrong when you mix. Restricting yourself to a C or COM api helps a lot to avoid these traps.
2) This will happen when you link code that was compiled with /MD. Common with .libs you link.
You stay out of trouble by always using /MD when you have DLLs in your project and compiling all code with the exact same compiler and options. Static libraries you didn't build yourself are very troublesome, avoid them.
Regarding your 2. question, the dependency is indirect. Your DLL uses a DLL which depends on MSVCR100.dll. Using Dependency walker you can see the dependency tree of your component and see which library is directly and indirectly dependent.

JNA try to Access native DLL and get module not found error, Dependencies are missing

I have Visual Studio 2010 installed and have a project I got from someone else which I can build successfully without any errors. I get a Wrapper.dll,
which I would like to access using JNA.
I am using Win7 64-bit.
But I get the error: java.lang.UnsatisfiedLinkError: Unable to load library 'Wrapper': The specified module could not be found.
Wrapper.dll of course is in the correct folder and it is a 32-bit dll and my Java program also uses a JRE with 32-bit, so this is not the cause of the error.
I used DependencyWalker to check whether *.dlls are missing:
MSVCP80.DLL
MSVCR80.DLL
GPSVC.DLL
IESHIMS.DLL
And yes there are some missing.
Can I conclude that the error is related with that these DLLs are missing?
But why does Visual Studio compile correctly then and does not throw an error?
How to solve this in order to access these functions in Wrapper.dll?
I also read that downloading dll's might not be the right thing to do!
(I know that Wrapper.dll relies on another dll or sourcecode which was built in Visual Studio 2005, if that is of interest.)
EDIT:
I found out, that Wrapper.dll relies on three other dlls which probably were built on MSVS2005. These require the above mentioned DLL's (checked with dependencywalker) and I guess therefore Wrapper.dll also links them.
So what do I actually do to get rid of these old dll's?
Would I need to build the other three DLLs with VS2010 or
is this a problem which always will appear, meaning, that you need to copy paste old DLLs in order to use the precompiled Libraries which are dependent on those.
Is there a way, that the program would run on any other system as well without copy pasting these DLL's?
All required DLLs must be available to the system for loading. If you define jna.library.path, that is where JNA will look for the initially loaded DLL, as well as any dependent DLLs. In addition, java.library.path (which is essentially PATH) will be searched for dependent DLLs.
MSVS often uses paths in addition to PATH when building, debugging, and running code within that environment.
Solutions:
a) remove dependencies you don't really need; this may include telling MSVS to build your DLL differently
b) include non-system DLLs next to your custom DLL (or include their location in PATH/java.library.path)
EDIT
a) you can include the offending DLLs in the same directory as yours. this is fairly low impact on the target system, but if they are DLLs that are expected to be on any system, you shouldn't have to do so. It's preferable to adjust java.library.path so that all system DLLs are accessible.
b) you can recompile your dependent DLLs and be more careful about backward compatibility and explicit linkage. Depending on features used by the DLLs, though, you may not be able to remove the dependencies.
MSVC[RP]80.DLL are C and C++ runtimes, respectively; you may or may not be able to link against a previous version.
IESHIMS.DLL is part of IE and should be on the system, but likely in a path inaccessible to your program.
GPSVC.DLL has to do with group security policy, so it should be available on the system (modulo whenever the DLL was introduced).

Best Practice - Where to place a managed assembly when real purpose is to expose TLB file

I have an environment where there is a combination of managed and non-managed executables being run for a particular suite.
I have a scenario where the only reason I have a managed assembly (in this case) is because code was easier to write in C# than in VB6.
My 'main' application, written in VB6, needs to make a call to this assembly. So I create the TLB file, so its COM callable.
Now for deployment, is it better practice to place the managed assembly 'with' the tlb in the windows system directory? to have them both in the same place? Seems to me a bit easier to manage that way.
Or the managed assembly (not-signed since it isn't to be shared among diff apps) should just go to the BIN of the application dir, and the TLB moved to the windows\system32 and registered there.
Overall it seems more straight forward to keep them together, but it doesn't seem to be the correct way to do things.
Thx for any tips.
None of the above. You only need the type library when you compile your VB6 program. It does not need to and should not be deployed on the user's machine. There's a small corner case where a type library can help with marshaling an interface across an apartment or process. That won't be the case in a VB6 app.
Personally, I'd put both of them in your application's installation folder or under the Common Files structure.
The System32 folders are ideally just for the system files. (Ignoring history for the moment :)

Registration free COM: VB6 Executable referencing VB6 DLL

So, I've got a single VB6 executable that references multiple VB6 COM DLLs. Is it possible for me to generate, on-the-fly, a manifest for the executable as well as a manifest for each of the referenced DLLs? If so, then how?
I would like to perform this operation as part of our build process without having to register the COM DLLs as part of the process.
NOTE: All the reg-free COM examples that I've found so far involve .NET interop, which is not a requirement for what I'm doing.
[EDIT]
After performing some preliminary testing using Unattended Make My Manifest, I've found that its just not as user-friendly as I would like. And, since there's only a Sample.ini file for documentation I've had a pretty hard time understanding what should be put into that file compared to what doesn't need to go into that file. Anyways, I've decided to craft manifests using my own tool. Hopefully, I'll get permission from my employers to release the code as open source.
*For now, if you're in the same position that I'm in and you would like to create a build and production environment that uses side-by-side/registration-free COM interactions, just know that its possible. I would recommend crafting them by hand with a simple DLL and consumer app at first, and then incrementally building on that until it suites your specific needs.**
We are using Unattended Make My Manifest in daily builds to create portable versions. It creates a single manifest that can be embedded to the executable with mt.exe
You could try Make my manifest which is a tool to create the manifest for a VB6 program. I don't know whether it can run automatically as part of a build process.