I have two products - product A and product B.
Product A contains file A.dll with version 1.0.0. Or any other type of file (.config with text 1.0.0).
Product B updates file A.dll with version 2.0.0 (or config with text 2.0.0).
After uninstallation of Product B, it removes A.dll.
If I mark A.dll in product B as "rermanent" it will not be removed.
But I need to restore A.dll version 1.0.0 after product B has been uninstalled.
As a possible workaround, I can run Product A in "restore" installation mode.
Is there any other solution?
P.S: Case example:
Product A has been released, and due to some bugs, required hot-fixes come next as a Product B (to have additional entry in Programs and Features list).
The Product B (hot-fix) replaces A.dll with newer one.
I want to support uninstallation of Product B (hot-fix) and return to state before it is installed (A.dll with version 1.0.0).
If these are separate products, why do you install one on top of the other? Is this a UAT / QA construct for temporary use? Could you install these products side-by-side (in separate folders for each product) and then just pull back whichever version you don't need anymore? Your scenario of pulling back bits and pieces of your "new" install that is mixed in with your original install does not work well with Windows Installer.
Is this a released product or are you still in development? Why not just pull back what is on the box and install a new version of your setup which cleans up everything. You could author the upgrade table to uninstall both existing products you have already deployed. For safety reasons i would change the path you install to for the new version of your setup, and I would uninstall the existing packages early in the InstallExecuteSequence.
The overall message: you are not supposed to mix different products in the same installation location. Each product is supposed to have its own installation folder, and if you have several setups installing to the same location the files should be installed with the same component guids.
See if this makes some sense to you: Change my component GUID in wix?
If you're really talking about data files (such as config files) that you want to restore when Product B is uninstalled, I think we're looking at a custom action when A is installed which backs up the data used by A. When B is uninstalled it restores the data from the backup location.
Either way, the issue seems to be the application design where A and B both apparently share some common set of data files, except that they only share when both are installed.
NOTE: this answer was written before the OP modified his question.
In my opinion this indicates an error in application design. What you are dealing with is a shared file that is required in two different versions - or so it seems? Can product A use version 2.0.0 of the dll or does it absolutely require version 1.0.0?
Short answer:
Either install the dll that you have shared now as a private dll in the main application's installation folder (for each product, in the version they require), or...
Make sure both products can use the most updated dll in the shared location (shared deployment requiring full backwards compatibility).
You can also install the two dll versions side-by-side (in the GAC for .NET assemblies, or in WinSxS for Win32 files) or somewhere else on disk where both applications can access them (they load the one they need - and leave the other version alone on uninstall). Which version loads depends on the application manifest (some find messing up the manifest to be the second coming of dll-hell - the wrong stuff is loaded).
Finally you can statically link the dll's into your main executable (my least preferred option for large corporation deployment - details below). Static linking in .NET is a little bit different from native, Win32 binaries: Static Linking of libraries created on C# .NET. I am not sure of the performance implications of static .NET linking (I only ever do Win32 static linking).
As a rule of thumb shared files must be rather stable with few updates to really be useful as shared. They are typically "libraries". I might chose to deploy private copies for a while during development until I reach a more stable state and switch to shared files (side-by-side or global, whichever fits).
If you are dealing with COM, then the technology's overall "global registration nature" makes it necessary to maintain backwards compatibility (files are always shared) or you can try "registration-less COM" -
essentially COM with the registry information embedded in manifest files and local copies of all files in the main application installation directory - everything happens in one folder in an "isolated" fashion. COM is old, but since it is used for .NET via COM Interop it will continue to be a headache for everyone for years to come.
Below is a more elaborate discussion of these options. It got a little messy - like it gets when you just write off the top of your head. I will try to clean it up as soon as I get some distance to it and can see clearer what is wrong with it.
If product A can use version 2.0.0, then you have a basic shared file between applications, and the normal way to install it would be a merge module included by both setups. You should have backwards compatibility so that product A can use any version of the file, including version 2.0.0. Product B should also be able to use any version of the shared dll, and you should be able to deploy an upgrade to the shared dll that both products can handle. A genuinely shared file. During product installation higher versions of the file should always be installed, and all products using the file should be able to handle the new version (backwards compatibility). Great if you have security hot-fixes that you want to deploy to many products quickly and reliably without rebuilding all products individually. This is obviously what shared files are for.
If product A can't use version 2.0.0 of the dll, then you likely have a side-by-side installation scenario (like the global assembly cache - different versions of the same assembly installed at the same time and applications load the one they need). You should install both versions of the dll in different places (with different file names), and your product A and product B should load the one they need. Or you should install to the GAC - this is what the GAC is for (.NET assemblies only). There is also a side-by-side concept for normal Win32 files (Windows side-by-side assemblies). You must never mess around in the WinSxS folder directly (the Windows assembly folder for Win32 dlls), see this excellent explanation from Advanced Istaller - just like for the GAC files are registered for installation to WinSxS). When you uninstall either product A or product B the dll needed by the other application is left untouched (there could also be other products using them). Side by side files can also be shared between products, but they won't be uninstalled if there are other products registered that need them on your product's uninstall and there are several different versions of the file to choose from so you crucially do not need to maintain backwards compatibility between the different "branches" (backwards compatibility must still be maintained for each branch - i.e version 1.0.1 must be compatible with 1.0.0 but not 2.0.0).
The most obvious option might be to include your now shared DLL in your product's main application folder - making it a "private file" that is never attempted shared between other applications / products. This works best for Win32 dll's or .NET assemblies (no registry impact or global registration - unless the .NET assembly is registered for COM Interop). COM files are registered system-wide in the registry and should be installed to a shared location with genuine backwards compatibility or delivered in a brand new versions side-by-side with the old one (with new interfaces - rarely done). .NET assemblies can be installed side-by-side in the GAC if you need side-by-side deployment, or you can deployed them into the main application's directory as "private copies" of the assembly.
So for files used by many products you have shared files, shared side by side files, installing private copies of the dll in the application's main installation folder and a final option is static linking - compiling the dll's into your product's main executable. Just mentioning this since some people prefer this option. It does not allow deployment of updates to the shared files (or your private copy of the file for that matter), but any updates to the libraries require a full recompile and redeployment of both products (or however many products we are talking about) - a lot of work. People may find this option appealing at first, but tire of it quickly. It all depends how many updates will be made to your application and the shared components (now statically linked). We repeat that too often: it all depends, but it does.
It all depends :-) on how you have designed your application and how much you want to deploy files that are shared between products and that can be updated on their own. The great benefit of deploying a private copy of your dll next to your main application exe (instead of static linking) is that you can deliver an updated dll without recompiling your whole application exe (which could be huge). You minimize the risk of new bugs being introduce in other parts of the application, and you deliver "a little hotfix" of your product, and not a full blown recompile with all the QA work that entails. You have a targeted dll-fix and a new setup to UAT / QA (if you do it well, that setup can be delivered as a patch as well).
What I like about (genuinely) shared files is that I can deliver them with a separate setup that can be updated on its own, without affecting your main product's setup at all (when I say genuinely I mean files that are used by dozens of applications, not just a couple). This decouples things nicely and all that is needed is some QA / UAT of the main application after the shared files have been "hot-fixed". There is no full recompile of your main product AND a new setup for it to QA / UAT. If you deliver many large products this is very important. You could face some excruciatingly important security hot-fixes for your shared files that are used by dozens of other applications. I see this a lot in large corporations, for example banks - you could spend weeks or months updating the same problem in dozens of products otherwise. A nightmare for everyone.
I should add, and this is a personal opinion, that I don't really like merge modules that much. It is an OK concept, but for all intents and purposes it amounts to static linking for your setup. Not quite, but almost - all files are included at compile time is what I mean. The good news, however, is that an upgraded version of the merge module can be included in another setup that will upgrade the same files as long as you have higher version files in your upgraded merge module (in your new setup). So it is not quite "static linking", but it sort of feels like it.
My personal preference: do use shared files if they really help keeping lots of products updated and hot-fixed. In most cases these shared files are very stable with few(er) updates, and because of this work well as shared (you will thank yourself at some point - when something really hits security-wise). Deploy the shared files via their own setup and set that setup as a prerequisite for your own product's setup. This is what has proved most flexible and feature complete for me - especially in large corporations (for in-house software). You can chain it all together with a bootstrapper like WiX's Burn (in corporations you would use a deployment system like SCCM instead to set up dependencies), and you can deliver updates separately for your shared files and your application files. If your application is simple and your shared files are not too stable, just deploy a private copy of the dll(s) in your main installation directory (unless it is a COM file). I would avoid too much static linking (I only prefer static linking for minimal dependency scenarios - like when you make a custom action dll for your WiX setup and you want it to run on any machines without dependencies).
Good deployment depends on good development decisions. It is all cohesion and coupling. There are only rules of thumbs and no way that is right for everyone. It will be a lot of work no matter what you do, but try to avoid small changes affecting too many applications requiring a full development / deployment release cycle for all of them - it is the overall goal of shared files.
Related
I have 10 services and they share a few of the same .dll-s. When I install those services, dll-s are installed in the same folder and the ones that are shared are not duplicated (which is what i want), but when i uninstall of of the services. lets say service number 5, The msi also uninstalls all the dll-s for that service, including the shared ones. How can I uninstall just the ones that are not shared for each service?
One Line Answer: You must make sure that the shared files are not assigned to single features only - as this will remove them on uninstall
if no other features register them as "clients" or "users" of the files.
Long Version: You must have several features since you allow services to be installed and uninstalled individually. Have you perhaps assigned some of the shared components / files to only one feature? If so, then the above problem could show up. There are a few options:
Shared Feature: Perhaps create a hidden, common feature and move all shared components / files there? You can then hide it from the GUI so they won't be uninstalled until complete uninstall of the whole product. The end user can never select them for uninstall (msiexec.exe commands can still uninstall them unless you prohibit that too).
Update all Features: You should also be able to add all the shared components to each and every feature so each feature lists all shared files in addition to the individual service files. I would prefer a shared, hidden feature like described above. However if you want some shared files to go away when you uninstall individual services, then you can add the components / files to only those (service) features. As that feature gets uninstalled no other features report "I need those files" and the files get uninstalled.
Burn: Just mentioning that you could deliver a separate MSI per service and a shared MSI with shared files using a Burn bootstrapper / bundle. Based on your comment above this is not what you want to do. This does allow you, though, to update individual services without recompiling the big setup with all services in there: Use a single setup or several smaller ones? (and also to update the common files, without recompiling all service setups).
As an example for point 2 above: if you uninstall services 1, 2 and 3 and they are the only ones that point to some of the shared files, those shared files will be uninstalled as the last service using it gets uninstalled.
I have a couple of MSI files installing different applications. All these packages share the same underlying runtime which basically is a set of DLLs. This runtime is pulled in each of the installers as a merge module. Installing a couple of these packages works just fine, always the latest version of the runtime stays on the system and when the last package is removed everything is removed from the system.
Now I had to split one of the DLLs into 2 and added a new component to the runtime installing the new DLL. This new DLL is linked with other libs of the runtime. Now assume the following scenario:
install an old package with the merge module for the runtime without the new DLL
install a new different package with a newer version of the merge module for the runtime. Now there are 2 packages on the system
remove the new package again
Now the old package is broken because:
the new component for the new DLL had a reference count of one as the old package didn't have it and therefore gets removed
the other runtime DLLs stay on the system because they are still referenced by the older package. However as they are new they are already linked with the new DLL that is now no longer present
So my question is:
Is there either a way to explicitly state in the WiX code that file A depends on file B so that it stays on the system until all references have been uninstalled?
or is there a way to explicitly downgrade the dependees in a way the dependency does not longer exists?
Am I doing something fundamentally wrong?
What I did try on a clean machine was to follow Stein Åsmul suggestion like this:
<Component Id='OldLibsNowDependingOnNewLib' Guid='C8DCD2AB-CBE5-4853-9B25-9D6FE1F678DD'>
<File Id='LibOne' Name='LibOne.dll' Source='$(var.SourceDir)/LibOne.dll' />
<File Id='LibTwo' Name='LibTwo.dll' Source='$(var.SourceDir)/LibTwo.dll' />
</Component>
<Component Id='NewLibComponent' Guid='CD2DB93D-1952-4788-A537-CE5FFDE5F0C8' Shared='yes'>
<File Id='LibNew' Name='LibNew.dll' Source='$(var.SourceDir)/LibNew.dll' />
</Component>
However unfortunately this doesn't change the behaviour.
UPDATE: Looking in the SDK again, I see the flag msidbComponentAttributesShared for components. This
looks promising for the problem you describe. Please try to enable
this flag and recompile the version 2 of your setup (unless it is
live).
Enable the Shared flag for the component in question (last part):
<Component Feature="Product" Shared="yes">
This seems to be for patch support, but maybe it will work for your case too. From the MSI SDK:
"If a component is marked with this attribute value in at least one package installed on the system, the installer treats the component as marked in all packages. If a package that shares the marked component is uninstalled, Windows Installer 4.5 can continue to share the highest version of the component on the system, even if that highest version was installed by the package that is being uninstalled."
I think the above should work, but don't have time to test right now. Leaving the below for review.
Short Answer: Use WiX's Burn (setup chainer) to install in sequence the application setup and a new, separate runtime setup that can be handled
independently of your application setup versions.
Prerequisite Setup: Interesting case. This is why I like to split prerequisites into its own MSI package and deploy it via a Burn Bundle Bootstrapper. Burn is WiX's bootstrapper / downloader / chainer - essentially a way to run several setups in sequence - in a few different formats such as MSI, EXE, MSU, MSP. When doing this - putting the runtime in its own MSI - there are no entanglements and you get good decoupling of your runtime and application-specific files. In other words: you can update the runtime files on its own - with their own MSI. The files will even have a reference count of 1 meaning you can easily uninstall them all (not if you install via a merge module that also can be included in other packages - more below).
Merge Modules - Semi-Static Linking?: In a weird way merge modules are sort of semi-static linking. The whole merge module is a version - a binary bundle (think COM) - but its installation behavior is one of "higher version wins" only. Hence a single newer MSI with the newest merge module in it will update the shared files for all applications that use them. Uninstalling will then do what you see: preserve the files that were originally installed by older setups.
Options: One "solution" in your case could be to re-compile the older setup with the newer merge module and then reistall, which I understand you don't like. I don't like it either. I guess it is no solution at all. Some other suggestions:
Permanent component: You can set the hosting component for the new file to be permanent on the system. This is very easy, but also quite silly and not always very desirable. Uninstall will then not remove the file at all.
Prerequisite: This is my favorite option mentioned above. You compile a prerequisite MSI setup that installs the runtime components. This MSI can deliver updates to itself without affecting the main application. This is the primary benefit I am after: Cohesion & Coupling benefits.
Merge Modules: I would avoid merge modules altogether, but it is common to merge the same merge module into the prerequisite setup - if you have a merge module already.
In most cases merging a merge module is fine since you then install the prerequisite and then you can install and uninstall application versions at will without affecting the runtime since a different product (prerequisite MSI) installed the runtime - and that setup should stay behind and not be uninstalled.
If the merge module does not work and brings along the conflict that you already had, maybe try to combine with the msidbComponentAttributesShared "solution" mentioned above. Not tested by me so far. Always risky to suggest things like this, but it is "best effort".
WiX Include Files: I prefer to use WiX include files which allows me to pull in new files without re-authoring a whole merge module in binary format (think C++ include files as opposed to a merge module's COM-style binary reuse).
Side-By-Side: Many people prefer to install prerequisites side-by-side so that several versions of the runtime can co-exist. This may or may not involve the GAC. Switching runtime versions would then be a manifest-manipulation task. Generally somewhat confusing, but doable. You can use both merge modules and separate MSI files to deploy such runtimes - as described above. I would definitely use a prerequisite MSI.
I can't think of more right now, but I know I have forgotten something important this time. Let me persist what I have for now in case it sparks ideas for you.
Cumbersome Prerequisite Setups: Note that prerequisite MSI files are not so bad for corporate deployment since deployment systems will allow one to define relationships between MSI files and to set up deployment chains. For home users you can easily wrap everything in a large setup.exe.
Nonsense Options: Options that don't make sense would be to roll the new file into both setup versions. No gain, lots of overhead. Some people like to copy new files locally to the main installation folder. Does not work since the files it is linked to are likely elsewhere (runtime location). Static linking wouldn't be relevant in this case I think. Only as a last resort to solve a live problem I guess. Setting the SharedDllRefCounter flag will not affect MSI reference counting, it is for legacy reference counting (non-MSI setups), though tweaking this manually is an emergency "solution". The last resort people end up with is typically to abandon the runtime installation and install everything to the same installation folder. Then you have to always recompile everything for every release - which is what you want to avoid?
Some Links:
WiX (Windows Installer Xml), Create universal variables
Pre-Processor constructs, features, Burn Bundles and beyond
I am building a MSI installer using WiX. As the product that is supposed to be installed requires a VC++ runtime I found the two option of doing that which are (a) using the corresponding merge module and (b) using burn to run vcredist prior to the actual product's MSI. To differ between those two options I have some questions I didn't find the information on.
1) If using the merge module the runtime is not installed separately (no entry in add and remove programs) but as far as I understand just copies the required files to their corresponding locations.
1.1) If there already is an installation of vcredist present on the system I suppose the merge module does nothing during the product's installation?
1.2) If there was a vcredist installation present as mentioned in 1.1) what happens if the user just uninstalls that runtime via add and remove programs? I suppose the product does not work anymore (at least until a repair installation is performed which causes the merge module stuff in the MSI to re-add the necessary files?)
1.3) If the vcredist was not yet installed and the MSI installer copies the files to the system and after that another installer or the user is calling the vcredist.exe what is happening then? Does vcredist reports the runtime as already being installed?
1.4) If uninstalling the product are the files copied to the system via the merge module being removed?
1.5) If the answer to 1.4) yes (VC++ runtime files are removed): If there are two different products are installed on the system both using the same merge module internally and one of the two products is uninstalled what happens to the installed runtime files? Are they removed and the other product is not working anymore due to the missing runtime files?
Thanks in advance for your help and information.
Regards,
Gunnar
A merge module is just a consistent way to install (usually shared) files properly by including them in a build. As an analogy, the C++ compilers build .obj files that are combined into an exe, but you can no longer talk about an obj having a separate existence after the exe is built and running. It's the same with merge modules. Once they are in the MSI they are just files to install, and they follow the standard rules. If a file is already installed (in the shared location) it will be overwritten if the incoming version is higher than the already installed version. Its containing component will be ref counted up by one, and uninstalling other products (including the VC redist) using the component will ref count down so that any products using the file don't break - there is still a version for them to use.This is just the standard sharing method for files shared amongst products, and it makes no difference that one product is a VC redist and the other is your MSI. It could just as easily be several of your products that each install the files using merge modules and each can be uninstalled without breaking the others because of the ref counting and that fact that the shared location and common component ID makes the sharing work as intended. So forget that one product is the VC redist and the other is yours (or another that uses the same files) - it's all just the Windows Installer's shared file/ref counting mechanism.
This is for the recent merge modules that install the files to the system folder. There have been other schemes using WinSxS and policy redirects that don't seem to be used now (VS 2015).
When products A and B each install several MSIs and some of the MSIs are the same, will uninstalling either A or B affect the other? Does install location matter?
Also, what happens when common MSI C's version is higher in Product B and B upgrades C on install? Now uninstalling B will remove the common MSI C which breaks Product A. How do you handle this gracefully without using the Permanent flag?
The first thing that comes to mind with this question is whether the products in question are decomposed the way they should be.
As a general rule all MSI files think they own whatever they install, and they will uninstall everything attached to a component GUID inside the MSI on uninstall if the reference count (number of products using the component) is zero.
There are some qualifications to this rule:
If the component is marked permanent it is never uninstalled
If the file / registry item has no component GUID at all, it is installed, never tracked by Windows Installer, and won't get uninstalled either
Finally the reference counting for MSI allows the same component to be shared between several products and it will persist on disk during uninstall if it is registered in use by several other installer packages
The mechanisms for creating shared components between MSI packages are generally:
Merge modules allow you to install shared components that are reference counted and that will remain on disk after uninstall of a related product if there are other clients using the GUID on the system. A merge module is merged into other MSI packages at compile time. A form of binary early binding if you like. It can be merged into any package.
With the advent of Wix (xml based installer source files), it is possible to include the same segment of files from several setups via an XML source include file instead of a merge module. This is vastly superior in my opinion due to the fact that Wix works better for source control (see Wix link for explanation). It is crucially important to realize that a "Wix source include file" has the exact same effect as a merge module - its components are reference counted properly for sharing between different installer packages, provided the GUIDs in the source file are hard coded (I recommend not to use auto-generated guids for this particular purpose). It is my personal opinion that you should use third party merge modules for generic runtime files, but only Wix includes for your own shared files. Merge modules are harder to manage than Wix includes imho.
Updating and file replacement:
As to update scenarios the MSI file replacement rules will take care of updating newer files, dependent upon the overall setting in the special Windows Installer property REINSTALLMODE.
In general higher version files overwrite lower version files. Non-versioned files are overwritten if they are unmodified. If they are modified the create and modified date stamps are different and the file is left alone.
Keep in mind that the issue of downgrading files is actively discouraged by the overall MSI design. If you need to downgrade files (shared or not), there is something deployment smelly about your design.
At this point I would thoroughly read these answers:
Windows Installer and the creation of WiX - for a short Wix history and context
Change my component GUID in wix? - for component reference counting
Wix installation, server, client or both - for client / server packaging
Wix to Install multiple Applications - for changing requirements and setup problems
WiX tricks and tips - for community Wix tips and tricks
How to include wxi file into wxs? - for a simple idea of how to deal with Wix include files
Provided you use Wix, or you are willing to use Wix, I would think the best way to deal with your overlapping products would be to decompose your installer into Wix segment source files that you include as needed in your main installers. This will allow the uninstall of one product to leave in place any components used by other applications.
With that being said, I do not like to cause too many overlapping dependencies in my installers for the reasons listed in this article (also listed above): Wix to Install multiple Applications .
For stability it is crucially important that shared components are stable before being used by too many setups as a bug fix as a general rule will require the recompilation of all setups the shared component is compiled or merged into. The easy way to say it: bundle files together that change together.
To counteract this need for massive recompilation, you can chose to deliver a stand-alone supporting setup consisting of some of the shared components. One, or a couple of such "shared components setups" that are likely to contain Wix includes that change together on a similar, slow release schedule, and then separate setups for each product should be able to account for any deployment need whilst maintaining a balance between maintainability and flexibility.
The product setup should then be the one that gets recompiled often, and the shared modules setups should be designed for minimal recompilation. Then wait for changing requirements :-).
To me it is all about cohesion and coupling, and the difficulty of balancing sales, marketing and technical needs.
If Product A and Product B has a MSI C in common then
If Product A is installed, also MSI C is installed, now when Product B is installed MSI C will not be installed since its already available in the system (if Product B is WiX Burn based, it registers a dependency). In case of uninstallation reference counting is automatically handled if Product A and Product B is WiX Burn based installer or any other Bootstrapper which supports reference counting else MSI C is removed along with Product B.
even I was looking for the answer of the above question, but in Wix v3.7 and higher, the MSI packages are automatically reference counted by the Burn engine. I have tested this, and works perfect.
The same can be checked in Rob's blog
One of our applications needs to register a COM control during installation. If a newer version of that control is already registered, we don't want to overwrite it with the older. What are the Windows MSI install conditions I would user to control this? Or is there some other 'best-practice' method I'm not aware of?
Thanks
Sounds like your main problem is that you have two controls that support the same CoClass's, but live in different file paths. That's not a great situation to be in. If at all possible, there should only be one possible file path for a binary that implements a particular COM class.
That way, file versioning rules will make sure that the latest file is installed by MSI installers. MSI won't by default overwrite newer file versions with older ones.
There are applications out there that have the problem that customers need to use the older version of a class occasionally while still having the newer version installed and available. One solution is to have a utility application that the customers can run that will "point" the COM registry entries to the correct binary.
There are definitely permissions issues with implementing that correctly on non-administrative accounts and you should avoid putting yourself in that situation if at all possible.
If you absolutely must have multiple binaries implementing the same COM CoClass GUID and if it is not too late to change old clients, you could create a master "factory" class that takes whatever data/info is available from the client and chooses the correct implementation to return. It would simply be a COM class with an interface that had methods that returned interface pointers to the actual interface the clients needs after allocating the proper implementation class and queryinterfacing for the client interface.
edit
You may choose to change the location of your application from version to version (e.g. "c:\program files\My App V2". That's okay so long as you use the MSI product code and version #, etc. attributes of your packages to force MSI to uninstall any existing versions of your application before installing new ones.
What you are missing here is merge-modules. Basicly you create a merge-module for your COMxx component. This gets recompiled with each new version 19, 20, 21, ... of your component (but keeps its GUID). Both your applications "reference" this COMxx merge-module and ship its content to the user.
This way windows installer will make sure your dll is refcounted and upgraded only if needed, provided you maintain (increase) version info in your dll.
Edit: The merge-module also hard codes install path, which usually ends up somewhere in C:\Program Files\Common Files\{My Company}\{My Component}, both applications ship it there.