【问题标题】:InnoSetup DLL UnloadInnoSetup DLL 卸载
【发布时间】:2015-01-27 14:14:27
【问题描述】:

我有一个 InnoSetup,我在其中加载了一个 C# DLL。安装程序在安装结束时挂断。 我在 stackoverflow 上找到了一个线程,其中似乎有一些很好的信息,但我没有经验来获取提供的信息......

InnoSetup hangs after install due to dll

我的 DLL 所做的基本上是:

  1. 在某些线程中解压 *.zip 文件
  2. 通过回调向 innoSetup 提供反馈。

Inno 发生了什么:

  1. 启动导出的 DLL 方法
  2. 接收回调
  3. 解压完成后卸载 DLL。

但似乎永远不会卸载 DLL。 我通过每 5 秒触发一次的 TimerEvent 对其进行了测试,并且计时器永远不会停止。

这是一个代码sn-p: 英诺:

type
TProgressCallback=procedure(progress:Integer); // ; id : String
function WrapProgressProc(callback:TProgressCallback; paramcount:integer):longword;
external 'wrapcallback@files:innocallback.dll stdcall';
function ReadZipEx(xml:String; callback:longword): longword;
external 'ReadZipEx@{src}\data\tools\ZipLib.dll stdcall loadwithalteredsearchpath';

procedure InstallData();
var
    progCallBack            : longword;
begin

    progCallBack := WrapProgressProc(@ProgressCallback,1);
    //create xml
    ReadZipEx(m_XML_String,progCallBack);
end;

procedure ProgressCallback(progress:Integer); //;id : String
begin
    pbStateZip.position := progress;
    lblState1.Caption  := IntToStr(progress);
    if(progress = 100)then begin
       UnloadDLL(ExpandConstant('{src}\data\tools\ZipLib.dll'));
       UnloadDLL(ExpandConstant('{tmp}\innocallback.dll'));
       OperationsFinished();
    end
end;

C#:

    [DllExport("ReadZipEx", CallingConvention = System.Runtime.InteropServices.CallingConvention.StdCall)]
    public static int ReadZipEx(string xml, ReportProgress repoProg)
    {
      //start threads
      //start timers which fire the callback
    }

有谁知道为什么我的设置最终会冻结以及为什么 DLL 永远不会被卸载或为什么它会继续运行?我试图释放 C# 部分使用的所有数据

【问题讨论】:

    标签: c# dll callback inno-setup


    【解决方案1】:

    实际上我认为你没有正确调用 innocallback.dll - 目录不匹配(你从 {tmp} 调用它但它被声明为@files:)。

    您在 {tmp} 文件夹中有 innocallback.dll 吗?在调用 UnloadDLL 之前立即检查它。并且不需要对 UnloadDLL 进行 2 次调用。

    正确的用法应该是:

    procedure DllFunc; external 'DllFunc@{app}\MyDll.dll stdcall uninstallonly';
    
    ...
    
    begin
      // Call DllFunc
      DllFunc;
    
      // Unload the DLL
      UnloadDLL(ExpandConstant('{app}\MyDll.dll'));
    
      // Now we can delete the DLL
      DeleteFile(ExpandConstant('{app}\MyDll.dll'));
    end;
    

    因此 dll 被复制到 {app} 文件夹(在 [Files] 部分中)。

    第二件事:

    永远不要比较浮点数、进度和类似的东西是否相等。 进度可能是非线性的,因此它可能会完成,例如值为 105。

    使用

    如果(进度 >= 100)则开始

    【讨论】:

    • 如果我有两个 DLL,我真的只需要调用一次 unload DLL 吗?在我看来这有点奇怪。随着你的进展是对的,我应该检查它是否高于或等于 100 。出于测试的目的,我创建了一个版本,它只给我 100 作为测试值,所以我只将它与它进行比较;)
    • 不,你是对的,你需要 2 次调用 2 个单独的 dll,我的错 - 我没有注意到你正在卸载两个不同的 dll :)
    • UnloadDLL() 在我的用例中不起作用。请参阅此相关问题:stackoverflow.com/questions/49447374/…
    【解决方案2】:

    我找到了我的设置最终挂起的原因。我无法描述原因,因为我无法查看他们东西的微软来源,但我将其缩小到计时器对象。

    这是我正在做的一些背景: 我写了一个 C# Dll 并在这个 DLL 的帮助下公开了一个静态方法 https://sites.google.com/site/robertgiesecke/Home/uploads/unmanagedexports

    在 Inno Setup 中,我在 sherlock 软件的 InnoCallback 库的帮助下调用了这个公开的方法 http://www.sherlocksoftware.org/page.php?id=54

    我将回调方法传递给我公开的方法,以便我可以接收状态更新。在这里,我提供了一个工作示例: Call C# DLL from Inno Setup with callback

    我的 Inno Setup 的回调是从计时器调用的。 这就是问题所在。计时器对象,即使它被停止并设置为 NULL,也会继续做一些阻止 Inno Setup 完成的事情。 我在线程对象的帮助下自己编写了一个计时器,它比计时器更好。 此解决方案并不完美,但提供了在设置过程中使用线程的可能性。

    如果将来有人有更多信息,请随时使用下面的评论部分。

    【讨论】:

    • 你还记得我told you 不能从工作线程访问 UI 控件吗?这可能是后果。您必须以某种方式将您的代码与主线程同步。您不能只提出从工作线程调用的回调并访问主线程的控件。即使在纯 C# 应用程序中,这也是你无法做到的。
    • 我知道你是对的 :( 。但是谢谢你记得我错了 :D
    • @TLama 顺便说一句。它现在可以与线程一起使用,但我的完成屏幕最终会重置它的图形。但是一点都不冻。我在想如何单独在 inno setup 中做到这一点,但 inno setup 不提供线程。当我有解决方案时,我会在这里提供
    猜你喜欢
    • 2017-09-25
    • 2013-03-11
    • 2012-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多