Can I safely rename/move a dll that is already loaded by a process? - windows

I have a dll that is loaded and file-locked by a process, and I would like to update it with a newer version. I'm looking for an alternative to terminating the process to release the file lock before updating the dll. It is okay that the existing live processes still uses the old version, as long as newly instantiated ones pick up the new logic.
It seems that I can simply rename/move the dll and the live process still seems to work well. Is it safe to do this? If the dll's code has already been loaded into the process then why does it still need to lock the dll?

It is not always ok to move all dll's used by any random application. Some applications, like asp.net, use a shadow copy concept where they actually copy the dll and use the copy leaving you free to modify the original. In the case of asp.net, if you modify the original asp.net will automatically spool up a new app domain using the new dll and gracefully shut down the old one.
If the application you're referring to has a lock on the dll, then you can't safely change it.

It depends on your dll/application. For example, dll may use shared memory, or implement inter-process communication. New dll version may implement it differently. So once new instance will start, you'll have two conflicting versions in memory.
So it's not safe in general case, though in your particular case it may be OK.

Related

Easiest way to remove dependency on certain ActiveX library in MFC project?

I am working on greatly simplifying an old MFC application, and I'd like to use that opportunity to remove a dependency on a certain third-party ActiveX library that has been causing headaches. I first simply tried to remove all references to these controls in the cpp code. It compiles fine, but when installed on a new computer, it crashes if the library .msm file is not included in the setup project.
The problem now is that I don't know where any remaining references to these objects in the project is, and therefore have no easy way of tracking them down and removing them. Simply using the Find-functionality in VS only returns results in cpp files which I've already cleaned up, not any control instances in f.ex. dialog resource files. Is there a way to search for all these objects in the project, or check for them compile-time so that I can use compile errors to see where any library objects remain?
First of all: CoCreateInstance, CoGetClassObject are the normal ways how COM Objects are created. Should be easy to set break points here or to set a hook to monitor what's going on.
Seams that you have a bad error handling in you software. Otherwise you application should show an error message if an object could not be created.
Try to debug.... use remote debugging, even a crash dump will lead you to the code location.
Easiest approach: In your development machine. Try to look into the output window and see if any of the old ActiveX DLLs gets loaded. Trigger down to the location were any of those objects is created.
You can do the same with remote debugging on the test machine.

Can I prevent VB6 OCX controls generating OCA registry entries on compilation?

We have a project here written in VB6 (yes, I know...) which consumes some ActiveX objects also written in VB6 (OCX files).
Recently we started using a build server for this project and, with the help of the MSBuild Extension Pack we devised a build process which compiles the libraries, controls and executable all in the correct order, registers them as appropriate and then unregisters everything to leave a clean machine for the next run.
The problem is that each compilation run leaves entries in the registry for the extended type library/object cache files which the VB6 compiler appears to require, and these entries are not removed when the controls are unregistered.
i.e. for every registered component which has a CLSID entry pointing to the OCX, there exists, after we compile the project with VB6, a newly generated CLSID for the OCA.
Because we unregister the OCX controls after each build and the OCA CLSIDs are generated afresh each time, the number of OCA entries continues to grow.
Does anyone know what causes these entries, whether we can remove them through some kind of unregistration process or whether we can prevent them being created in the first place?
A few notes :
The build machine is Windows 7
Binary compatibility is enabled, so the CLSIDs of the OCX controls aren't changing.
Reg-Free COM isn't currently an option
We cannot simply register the controls and leave them as we want to run more than one build of this project.
The key is to stop trying to treat DLLs (including OCXs) like statically linked libraries. Your build process is inappropriate.
While VB6 supported a crude "project group" capability, this was only meant for small scale unstructured development efforts like those used by under-the-radar business unit coders.
Instead strive to keep application-centric logic within your EXE projects. Factor out longer-term reusable logic into DLL and OCX projects that you treat as separate, unique internal products. Maintain these (including source control) compeletely separately from consuming applications.
Normally these should be far more stable than application code where changes are driven more frequently by the business logic they contain.
Even when some of these must contain business logic, you still want to treat them as separate software entities. Try to keep them distinct from libraries that have more stability.
This requires more discipline than monolithic "tower of Bable" development but there are many rewards. Build time is quicker for one thing. And as a bonus almost all of these source control related issues disappear for the applications which have a much higher rate of tinkering and fiddling.

"Declare" statement as yet an other way to circumvent the .dll hell?

To my astonishment I found VB6 code that uses Declare statements to define functions in a .dll that lives in the Program Folder without it being registered on Windows. This seems like a supersimple way to avoid the .dll hell without having to resort to using Side by side manifests. Can I read some more about this somewhere? Are there snags?
The Declare statement is used to do "just in time" binding to non-ActiveX DLLs. Until your program "touches" a Declared entrypoint no attempt is made to load the library.
It basically has nothing at all to do with the topic of DLL Hell.
Muddled thinking can even lead people to plop ActiveX DLLs "next to" the EXE which actually can result in DLL Hell because people who tend to do this also use poor techniques for installing and uninstalling applications.
Poorly designed application A deployment plops a commonly shared DLL or OCX next to the EXE.
Poorly designed application is run, the VB6 runtime can't find the classes in the registry, does a DLL Search using Windows heuristics, immediately locates the DLL next to the EXE and calls its self-registration entrypoint.
Innocent, properly designed applications B, C, D are later installed that use the same DLL/OCX and their installers find the library already registered.
Poorly designed application A is uninstalled, typically by simply deleteing its folder in Program Files.
Applications B, C, and D (and any future applications using the library) are now broken - due to orphaned component registration pointing to a non-existant library.
Moral of the story:
Never, never, never put DLLs "next to" your VB6 application on installation. If you have private DLLs that are not shared with other applications even then put them into a libs, etc. folder under the application folder. Possible exception might be non-COM DLLs, such as those you expect to use Declare with.
There is also a great deal of misunderstanding about manifests, of which there are multiple kinds. The ones you are probably thinking of are application and assembly manifests.
These can be used for selecting among different versions of a library installed Side by Side, or they can be used to isolate applications and assemblies which is the part that has bearing on DLL Hell.
Of course application manifests can be used to specify quite a few other things about how Windows should run the application.
Windows searches in a well-documented sequence of folders for LoadLibrary (which VB6 uses behind the scenes to resolve Declare declarations). Since the first location on the list of search folders is the app's own folder, your discovery makes perfect sense.
It doesn't resolve the "DLL hell" issue for the most part, though. It can't work for system DLLs, for instance, because Windows preloads most of them. Also, if a DLL is already loaded into memory, Windows may use that copy of the DLL (not sharing data, but code can be reused).
That's part of the reason that manifests were created; they allow an application to strictly define required versions of system DLLs in order to provide certain functionality. VB6's technique is old fashioned (just like VB6).

Recreating a COM DLL, do I need to worry about the GUID?

A change needs to be made in a DLL. The DLL was originally coded in VB6 (not by me), and the source code lost.
It is very simple in its functionality, so I recreated it from scratch, but I only have access to VB Express 2008.
I created it first as a normal DLL then realized it had to be a COM DLL. Fortunately, an excellent article at http://www.codeproject.com/KB/COM/nettocom.aspx tells me how.
But, I don't know anything about GUIDs...
Should I use the same GUID as the original DLL or not? Does it make any difference?
Edit: Does it really matter since it's a COM DLL? It is called into by an Active X control & I can see no reference in the web page to the GUI ... (but I'm just a n00b, so what do I know? ;-)
If you want this library to be a direct replacement of the original and it is fully binary compatible (all interfaces are unchanged) - then yes, you should use the same GUIDs for the class ids and interface ids. If you don't do that users of the original library will not be able to use yours without recompiling their programs.
Beware that binary compatibility is a must for reusing the GUIDs. If you break any interface - change its id and the id of the class implementing it and recompile the client.
The GUIDs acts as a kind of identifier for your COM object and DLL. If you use the same GUID you need to register your new DLL so that the location is updated (i.e. if you don't place it exactly in the same spot and have recreated all interfaces the old DLL previously had registered).
The cleaner approach is to generate a new GUID and modify the caller to use the new GUID/DLL instead.

Should you build components every time you build a main app

We have started using Final Builder to create builds for our vb6 and .net projects. We are also using Visual Source Safe to manage our source. Some of our vb6 exe's are dependent on certain ocx's, such that a particular vb6 exe may require a particular version of an ocx.
The question is, should the final builder script for our exe project also re-build the ocx project, or is it better to simply pull a particular version of the already compiled ocx. My concern is that other developers could have broken the build (or created a bug) for the ocx which could then break the exe we are trying to build. Moreover, re-building the ocx project would result in the same version of the ocx but with a different date, resulting in confusion if dllhell(ocx hell) issues arise.
There is no difference in terms of building and maintaining your app between a ocx and a activex dll. The ocx should use binary compatibility and be part of your compile process.
This is however a general rule. You may have some components that rarely change if ever. In my own VB6 application I have a handful of components that reside at the bottomost level of my reference hierarchy that rarely get updated. They maybe get updated one or twice a year at best. Some haven't been updated for several years now.
However based on your description it sounds like the controls are still being modified. So I doubt the second case applies.
In the end use your best judgment.
There are two ways to use OCX/DLLs: code reusability vs. fragmentation of an over-large project.
Those meant for re-use would be absurd to build, build, and rebuild, and almost never should be customized to fit a new application. These are your crown jewels, and most people should have no ability to modify the source. They are the domain of your organization's "library writers" because that's what they are: libraries.
If you simply have large, monolithic, unweildy applications you may have to go the other route. Then OCXs and DLLs simply become an awkward extension of the "module" concept. This is why we have Project Groups.
Your library users should not be fiddling with libraries though. I'm sure they all fancy themselves able to "ensure they are up to date and performant" but that's a different debate entirely.

Resources