首页 > 解决方案 > 调用外部 dll 时出现 InnoSetup 错误“无法调用 proc”

问题描述

我们的 InnoSetup 使用外部 dll 来抓取并检查 xml 文件中的数据文件路径。这在大多数情况下都可以正常工作,Windows XP、7、10(32/64 位)。但对于少数用户来说,这失败了,对我来说,它在 macOS 10.15 的 Crossover 19 中失败了。所以首先我在 inno 脚本中添加了一个延迟加载,以克服“无法导入 dll”运行时错误。

但后来我得到“无法调用proc”运行时错误。InnoSetup 调试器将我指向procedure GetExultGamePaths我们的脚本。

我们的dll中的代码:

extern "C" {
__declspec(dllexport) void __stdcall GetExultGamePaths(char *ExultDir, char *BGPath, char *SIPath, int MaxPath) {
    MessageBoxDebug(nullptr, ExultDir, "ExultDir", MB_OK);
    MessageBoxDebug(nullptr, BGPath, "BGPath", MB_OK);
    MessageBoxDebug(nullptr, SIPath, "SIPath", MB_OK);

    int p_size = strlen(ExultDir) + strlen("/exult.cfg") + MAX_STRLEN;
    char *p = new char[p_size];

    // Get the complete path for the config file
    Path config_path(ExultDir);
    config_path.AddString("exult.cfg");
    config_path.GetString(p, p_size);
    setup_program_paths();

    const static char *si_pathdef = CFG_SI_NAME;
    const static char *bg_pathdef = CFG_BG_NAME;

    MessageBoxDebug(nullptr, ExultDir, p, MB_OK);

    try {
        // Open config file
        Configuration config;
        if (get_system_path("<CONFIG>") == ".")
            config.read_config_file(p);
        else
            config.read_config_file("exult.cfg");

        std::string dir;

        // SI Path
        config.value("config/disk/game/serpentisle/path", dir, si_pathdef);
        if (dir != si_pathdef) {
            Path si(ExultDir);
            si.AddString(dir.c_str());
            si.GetString(SIPath, MaxPath);
        } else {
            std::strncpy(SIPath, si_pathdef, MaxPath);
        }

        // BG Path
        config.value("config/disk/game/blackgate/path", dir, bg_pathdef);
        if (dir != bg_pathdef) {
            Path bg(ExultDir);
            bg.AddString(dir.c_str());
            bg.GetString(BGPath, MaxPath);
        } else {
            std::strncpy(BGPath, bg_pathdef, MaxPath);
        }
    } catch (...) {
        std::strncpy(BGPath, bg_pathdef, MaxPath);
        std::strncpy(SIPath, si_pathdef, MaxPath);
    }

    delete [] p;
}

InnoSetup 脚本部分

procedure GetExultGamePaths(sExultDir, sBGPath, sSIPath: String; iMaxPath: Integer);
external 'GetExultGamePaths@files:exconfig.dll stdcall delayload';

procedure CurPageChanged(CurPageID: Integer);
var
  sBGPath: String;
  sSIPath: String;
begin
  if CurPageID = DataDirPage.ID then begin
    if bSetPaths = False then begin
      setlength(sBGPath, 1024);
      setlength(sSIPath, 1024);
      GetExultGamePaths(ExpandConstant('{app}'), sBGPath, sSIPath, 1023 );

      BGEdit.Text := sBGPath;
      SIEdit.Text := sSIPath;
    end;
  end;

end;

GetExultGamePaths(ExpandConstant('{app}'), sBGPath, sSIPath, 1023 );就是产生“无法调用proc”运行时错误的原因。

我不知道为什么只有少数系统会失败。我们的 dll 和脚本的完整代码位于https://github.com/exult/exult/blob/master/win32/ dll 的代码位于 exconfig.* 中,InnoSetup 脚本位于 exult_installer.iss

标签: windowsinno-setup

解决方案


通过 Piotr 在我们的 Wine 错误报告https://bugs.winehq.org/show_bug.cgi?id=49033中的帮助,发现使用 mingw 工具“dllwrap”被破坏并添加了无效的重定位数据。

不使用 dllwrap 是解决方案,并为我的 Wine/Crossover 安装修复了它。仍在等待最后一个用户报告在实际安装 Windows 10 时遇到此问题的用户。

谢谢你的帮助


推荐阅读