PDA

View Full Version : Bug in "Shared" Component handling during major upgrades



alorbach
07-06-2007, 10:34 AM
Hi all,

I create a new topic for this as I believe I may found a bug in the "Shared" handling of InstallShield 2008.

Let me explain how to reproduce the problem.
1. First create a project with 2 component, containing an exe or dll file. One component has the "Shared" option enabled, the other not.
2. Now create a 1.0 Version of the project and install it on a test machine (i recommend VMWare).
3. Now create a 2.0 Version of your project, assume that you reorganized the components and assign new GUIDs to them. Enable the Shared Option on both components. For major upgrades select Install first, the removed unused files.
4. Now perform an upgrade installation on your testmachine and monitor the following registry key:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\SharedDLLs
5. You will see that InstallShield sets the Count to 2 on the exe/dll files of BOTH components.
6. At the end the old setup is being removed, and now the following happens! The component that had the Shared Option enabled in the OLD setup gets decremented to the count 1. But the other component which didn't have the Shared Option enabled is not being decremented, it remains at 2.

The following error of this is, that the component is NOT uninstalled during uninstallation, as the Installer still thinks it is needed somewhere. I know this is a rather rare condition, but I believe it is a bug within InstallShield.

MichaelU
07-06-2007, 12:48 PM
This is Windows Installer behavior. By changing component GUIDs yet delivering the same file to the same place, one is breaking component rules, opening the door for this undesirable result.

alorbach
07-09-2007, 03:40 AM
Hrm so what I am supposed to do? Not changing the components guids? I have no other choice!

The reason is I want to change the setup to install a win32 and x64 Version of the core component based on the System Version.
This works well, I could manage to enable the right component on the right system using conditions.
But one of the components of course has to have a new GUID.

alorbach
07-09-2007, 06:24 AM
I found threads with simular problems in InstallShield 12 from other peoples:
http://community.macrovision.com/showthread.php?t=170424&highlight=shared+registry
http://community.macrovision.com/showthread.php?t=170598&highlight=SharedDLLs+registry

So if nothing else comes I have to find a workaround, again.

bryanwolf
07-09-2007, 09:06 AM
A single component (identified by its component code) is defined by a single resource installing to a single location. Any new versions of the component should also not break previous versions of the component. By changing the component code of a file installing to the same location, you've violated those rules and created a state where this can happen.

If a single file is installing to a single location then the component code should and must remain the same.

Further, in your testing using something like process monitor, you'd see that the responsible process is msiexec.exe and not setup.exe (installshield). Thus, this is likely behavior from Windows Installer based on component rules being violated.


At the end the old setup is being removed, and now the following happens! The component that had the Shared Option enabled in the OLD setup gets decremented to the count 1. But the other component which didn't have the Shared Option enabled is not being decremented, it remains at 2.

This leads me to believe that you've selected the option to "Install Setup then Remove Unneeded files", which doesn't allow you to violate component rules at-will as we warn in the little bit of help text in the Upgrades view.

alorbach
07-09-2007, 09:42 AM
I need to use the option "Install Setup then Remove Unneeded files" as otherwise the whole registry gets removed during the remove of the old setup - which kills all my old application settings. Wether or not I am breaking any rules, I need this to be working, I can't tell all the customers to manually backup there settings before installing the new major version, this is just ****.



So I created a workaround myself which works pretty well in my environment with all kind of tests. For all others who run into the same problem, here is a dirty workaround.

1. Create a new new Installscript like this:



#include "ifx.h"

export prototype ExFn_ResetReferenceCount(HWND);
export prototype RealResetReferenceCount(STRING, STRING, STRING, STRING);

// REALFUNCTION
function RealResetReferenceCount(szFeature, szComponent, szFileType, szInstallDir)
STRING sQuery, sFile, szFilePath, sRegKey, sCount;
NUMBER nListPos, nCount, nSize, nvType, nReturn;
LIST IncrementList;
begin

IncrementList = ListCreate(STRINGLIST);
sRegKey = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\SharedDLLs";
sCount = "0";

// Get list of files within a component ....
sQuery = szComponent ^ szFileType;
if(FeatureFileEnum(MEDIA, szFeature, sQuery, IncrementList, NO_SUBDIR) == 0) then
// Set new Count number default
nCount = 1;
nvType = REGDB_NUMBER;
RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE);

// Iterate through the list, and increment reference count ..
nListPos = ListGetFirstString(IncrementList, sFile);
while(nListPos != END_OF_LIST)
// Create registry value name
szFilePath = szInstallDir + sFile; // already contains backslash "\\"

// Only write if available
nReturn = RegDBGetKeyValueEx(sRegKey, szFilePath, nvType, sCount, nSize);
if(nReturn == 0) then
// Write new value into registry
NumToStr(sCount, nCount);
RegDBSetKeyValueEx(sRegKey, szFilePath, nvType, sCount, -1);
endif;

// Next file
nListPos = ListGetNextString(IncrementList, sFile);
endwhile;
endif;

end;

function ExFn_ResetReferenceCount(hMSI)
// To Do: Declare local variables.
begin
// Call da real function
RealResetReferenceCount("Feature1\\Subfeature1", "Component1", "*.exe", INSTALLDIR);
end;


In short RealResetReferenceCount can be used on any component in any feature with any file extension you need to. In my sample I only use it on one.
ExFn_ResetReferenceCount will be the function that can called in a custom action.

2. Create a new Custom Installscript Action, function name will be "ExFn_ResetReferenceCount". Only use it in Install Exec Sequence, I selected "After RemoveExistingProducts" to make sure it will be executed at the very last.

What the script does, it loops trough all files within the given component, checks if there is a value in the ShareDLLs key. If there is a value, it will reset the count back to 1. Works perfectly in my case, as only one version of the application can be installed.