【问题标题】:How do I uninstall related products in Inno Setup using an InstallShield Upgrade Code GUID如何使用 InstallShield 升级代码 GUID 在 Inno Setup 中卸载相关产品
【发布时间】:2013-08-07 03:58:09
【问题描述】:

我们公司已从使用 InstallShield Express 转为使用 Inno Setup(5.5.2 版本)。我们已经使用 InstallShield 进行了多年的旧安装,但始终依赖 InstallShield 的升级代码 GUID 来处理先前版本的卸载。

我需要能够从我们新的 Inno Setup 安装程序中卸载任何以前安装的 InstallShield 版本。

经过一些研究,我似乎需要调用 MsiEnumRelatedProducts() 然后卸载任何找到的产品。

我找到了这个链接http://www.microsofttranslator.com/bv.aspx?from=de&to=en&a=http%3A%2F%2Fwww.inno-setup.de%2Fshowthread.php%3Fs%3D415e3895fda3e26e42739b004c0f51fb%26t%3D2857(德语原文http://www.inno-setup.de/showthread.php?s=415e3895fda3e26e42739b004c0f51fb&t=2857)。看起来他已经很接近了,但他从未发布过他的最终解决方案。

他说的代码有效(但对我来说崩溃了):

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;

他说这样更容易?

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

我是 Pascal 脚本的新手,我被整个 SetLength() 部分困住了。它在他所说的有效但崩溃的功能中取代了什么?

既然其他人说要切换到字符串,我应该摆脱这个吗:

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

如果有人能用英语给我展示一个最终的工作函数,那就太棒了!!!

提前致谢!

编辑: 我使用的是 ANSI 版本的 Inno Setup Compiler。

【问题讨论】:

    标签: windows-installer inno-setup installshield pascalscript


    【解决方案1】:

    这是一个未经测试的翻译,它应该只是在消息框中打印出相关的产品 G​​UID。该代码应与 ANSI 以及 InnoSetup 的 Unicode 版本一起使用:

    [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;
    

    【讨论】:

    • 抱歉,我花了一些时间才回复这个问题,但我出于个人原因暂时离开了。
    • 没问题 :-) 也许我也应该回到这篇文章并进行测试。到目前为止,我至少对原始代码中的 ANSI/Unicode 不匹配进行了更正。您正在导入函数的 Unicode 版本,但传递了 ANSI 字符串(因为 string 代表 ANSI InnoSetup 中的 ANSI 字符串)。
    • 我在完成之前点击了 CR 并发布了。感谢您的代码示例,但我仍然有一个问题。 user32.dll 的导入应该是 msi.dll,我修好了。之后,我在 while MsiEnumRelatedProducts 循环中的某处遇到两个访问冲突错误。我得到了其中两个,但我只安装了一个以前的产品。我不得不猜测它在 SetLength(ProductBuf, 39) 调用中,因为安装程序执行得很好,没有安装任何以前的产品。
    • 请注意,此访问冲突在德语原帖的 cmets 中有所提及。
    • 嗯,奇怪...在你链接的帖子中写到,你不应该使用var作为参数lpProductBuf,但根据documentation你应该(这是一个输出参数)。但是好吧,这似乎是另一个文档失败......即使JEDI library,一个非常坚固的代码库,在没有var 的情况下定义它。而且,对不起那个图书馆的名字。这是我的复制/粘贴错误...
    猜你喜欢
    • 1970-01-01
    • 2013-05-15
    • 2011-03-13
    • 1970-01-01
    • 1970-01-01
    • 2012-11-16
    • 2017-08-15
    • 2013-07-05
    • 2011-01-28
    相关资源
    最近更新 更多