How do I uninstall related products in Inno Setup

2019-02-19 13:57发布

问题:

Our company has switched from using InstallShield Express to using Inno Setup (5.5.2 version). We've got years of old installs utilizing InstallShield, but have always relied on InstallShield's Upgrade Code GUID to handle the uninstall of the previous version.

I need to be able to uninstall any previous InstallShield installed version from our new Inno Setup installer.

After some research it looks like I need to call MsiEnumRelatedProducts() and then uninstall any found products.

I found this link http://www.microsofttranslator.com/bv.aspx?from=de&to=en&a=http%3A%2F%2Fwww.inno-setup.de%2Fshowthread.php%3Fs%3D415e3895fda3e26e42739b004c0f51fb%26t%3D2857 (original in German http://www.inno-setup.de/showthread.php?s=415e3895fda3e26e42739b004c0f51fb&t=2857). It looks like he got pretty close, but he never posts his final solution.

Code he says works (but crashes for me):

type
  TProductBuf = array[0..39] of char;

function MsiEnumRelatedProducts(lpUpgradeCode:string;
  dwReserved, iProductIndex:cardinal; 
  var lpProductBuf:TProductBuf) : cardinal;
external 'MsiEnumRelatedProductsW@msi.dll setuponly stdcall';

function InitializeSetup : boolean;
var
  ret, i, j : cardinal;
  ProductBuf : TProductBuf;
  ProductCode : string;

begin
  Result := true;
  i := 0;
  repeat
  ret := MsiEnumRelatedProducts('{#UPGRADE_CODE}', 0, i, ProductBuf);
    if ret=0 then
    begin
      ProductCode := '';
      for j := 0 to 39 do
      begin
        if ProductBuf[j] = #0 then
          break;
        ProductCode := ProductCode + ProductBuf[j];
      end;
      Result := uninstallOther(ProductCode);
    end;
    i := i+1;
  until ret <> 0;
end;

He says this makes it easier?

SetLength(ProductCode, Pos(#0, ProductCode) - 1);

I'm new to Pascal scripting and I'm getting stuck on the whole SetLength() part. What does it replace in the function he says works, but crashes?

Since the other persons says to switch to string, should I get rid of this:

type
  TProductBuf = array[0..39] of char;

If anyone could show me a final working function in English, it would be awesome!!!

Thanks in advance!

Edit: I am using the ANSI version of the Inno Setup Compiler.

回答1:

Here's an untested translation, which should just print out the related product GUIDs in message boxes. The code should work with ANSI as well as with Unicode versions of InnoSetup:

[Code]
#ifdef UNICODE
  #define AW "W"
#else
  #define AW "A"
#endif

#define UPGRADE_CODE "<your upgrade here>"

const
  ERROR_SUCCESS = $00000000;
  ERROR_NOT_ENOUGH_MEMORY = $00000008;
  ERROR_INVALID_PARAMETER = $00000057;
  ERROR_NO_MORE_ITEMS = $00000103;
  ERROR_BAD_CONFIGURATION = $0000064A;

function MsiEnumRelatedProducts(lpUpgradeCode: string; dwReserved: DWORD;
  iProductIndex: DWORD; lpProductBuf: string): UINT;
  external 'MsiEnumRelatedProducts{#AW}@msi.dll stdcall';

function InitializeSetup: Boolean;
var
  I: Integer;
  ProductBuf: string;
begin
  Result := True;

  I := 0;
  SetLength(ProductBuf, 39);

  while MsiEnumRelatedProducts('{#UPGRADE_CODE}', 0, I, ProductBuf) = ERROR_SUCCESS do
  begin
    MsgBox(ProductBuf, mbInformation, MB_OK);
    I := I + 1;
    SetLength(ProductBuf, 39);
  end;
end;