简体   繁体   English

在Inno Setup中使用回调显示来自外部解压缩dll的文件名

[英]Using callback to display filenames from external decompression dll in Inno Setup

Originally asked here , but was asked to submit it as a separate question. 最初是在这里询问的,但有人要求将其作为单独的问题提交。

I have the following dll coded in C below that I'm using in an Inno Setup Installer to extract game files. 我在Inno Setup Installer中使用以下C语言编码了以下dll,以提取游戏文件。 This is a replacement installer for a game which originally used a 16-bit installer and files are copied off a CD-ROM. 这是游戏的替代安装程序,该游戏最初使用16位安装程序,并且文件从CD-ROM复制。 I'd like to be able to use InnoTools InnoCallback to display the file names extracted using my dll, but as this is my first venture into C coding, I have no idea how to do it. 我希望能够使用InnoTools InnoCallback显示使用我的dll提取的文件名,但是由于这是我第一次涉足 C编码,因此我不知道该怎么做。 An example of this functionality may be found here: http://freearc.org/InnoSetup.aspx 可以在此处找到此功能的示例: http : //freearc.org/InnoSetup.aspx

I would like to be able to set WizardForm.FilenameLabel.Caption using the file name from my external dll. 我希望能够使用我的外部dll中的文件名设置WizardForm.FilenameLabel.Caption。

Relevant sections of my Inno Setup script: 我的Inno Setup脚本的相关部分:

function VolEx( filename, outputpath: String ): Integer; external 'VolEx@files:volex.dll stdcall';

(DriveLetter is the path for the CD-ROM, ie "D:\\" so the output currently reads "D:\\world\\archive.vol". The output I'm aiming for is "C:\\game-path\\world\\archive\\file.ext") (DriveLetter是CD-ROM的路径,即“ D:\\”,因此输出当前显示为“ D:\\ world \\ archive.vol”。我要输出的输出是“ C:\\ game-path \\ world \\存档\\ file.ext“)

procedure VolExtract();
begin
  if not DirExists(WizardDirValue() + '\' + Worlds[w]) then
  begin
    CreateDir(WizardDirValue() + '\' + Worlds[w]);
  end;
  for n := 0 to 3 do begin
    WizardForm.FilenameLabel.Caption := DriveLetter + Worlds[w] + '\' + Reslists[n] + '.vol';

    if VolEx(DriveLetter + Worlds[w] + '\' + Reslists[n] + '.vol', WizardDirValue() + '\' + Worlds[w] + '\' + Reslists[n]) <> 0 then
    begin
      // Handle Fail
      MsgBox(CustomMessage('FileErr'), mbInformation, MB_OK);
      WizardForm.Close;
    end;

VolEx.c (includes blast.c and blast.h from here: https://github.com/madler/zlib/tree/master/contrib/blast ) VolEx.c(从此处包括blast.c和blast.h: https : //github.com/madler/zlib/tree/master/contrib/blast

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <sys/stat.h>
#include <time.h>
#include <utime.h>
#include "blast.h"

#define local static
#define VOLID "RESLIST"

struct inbuf {
    unsigned long left;
    unsigned char *buf;
    unsigned size;
    FILE *in;
};

struct stat statbuf;
time_t mtime;
time_t voltime;
struct utimbuf new_times;

local unsigned inf(void *how, unsigned char **buf)
{
    unsigned len;
    struct inbuf *inb = how;

    len = inb->size > inb->left ? inb->left : inb->size;
    len = fread(inb->buf, 1, len, inb->in);
    inb->left -= len;
    *buf = inb->buf;
    return len;
}

local int outf(void *how, unsigned char *buf, unsigned len)
{
    return fwrite(buf, 1, len, (FILE *)how) != len;
}

#define BUFSIZE 16384   /* must fit in unsigned */

local int extract(char *name, unsigned long len, FILE *in, const char *path, time_t prevtime)
{
    int err;
    FILE *out;
    struct inbuf inb;
    unsigned char buf[BUFSIZE];

    inb.left = len;
    inb.buf = buf;
    inb.size = BUFSIZE;
    inb.in = in;
    mkdir(path);
    char outPath[strlen(path) + 20];
    strcpy(outPath, path);
    strcat(outPath, "\\");
    strcat(outPath, name);
    out = fopen(outPath, "wb");
    if (out == NULL)
        return 2;
    err = blast(inf, &inb, outf, out);
    fclose(out);
    if (stat(outPath, &statbuf) < 0) {
        perror(outPath);
        return 1;
    }
    mtime = statbuf.st_mtime; /* seconds since the epoch */

    new_times.actime = statbuf.st_atime; /* keep atime unchanged */
    new_times.modtime = prevtime;    /* set mtime to current time */
    if (utime(outPath, &new_times) < 0) {
        perror(outPath);
        return 1;
    }
    return err;
}

int __stdcall __declspec(dllexport) VolEx(const char *filename, const char *outputpath)
{
    FILE *in = fopen(filename,"rb");
    unsigned long off, next;
    int err;
    unsigned char head[24];

    if (stat(filename, &statbuf) < 0) {
        perror(filename);
        return 1;
    }
    voltime = statbuf.st_mtime; /* seconds since the epoch */

    if (fread(head, 1, 8, in) != 8 || memcmp(head, VOLID, 8)) {
        /* fprintf(stderr, "not the expected .vol format\n"); */
        return 1;
    }
    off = 8;
    while ((next = fread(head, 1, 24, in)) == 24) {
        off += 24;
        next = head[20] + (head[21] << 8) + ((unsigned long)(head[22]) << 16) +
           ((unsigned long)(head[23]) << 24);

        head[20] = 0;
        err = extract((char *)head, next - off, in, outputpath, voltime);
        if (err) {
            /* fprintf(stderr, "extraction error %d on %s\n", err, head); */
            return 1;
        }
        off = next;
    }
    /* if (next)
        fprintf(stderr, "%lu bytes ignored at the end\n", next); */
    return 0;
}

Have a look at the example script included with InnoTools Callback . 看一下InnoTools Callback附带的示例脚本。

It's pretty straightforward, you just declare a procedure like this (again, assuming that you're using ANSI Inno -- some of the types would have to be changed for the Unicode version): 这很简单,您只需声明一个这样的过程(再次,假设您使用的是ANSI Inno,则必须为Unicode版本更改某些类型):

[Code]
type
    TMyCallback = procedure(Filename: PChar);

function WrapMyCallback(Callback: TMyCallback; ParamCount: Integer): LongWord;
    external 'WrapCallback@files:innocallback.dll stdcall';

procedure DoSomethingInTheDll(Blah: Integer; Foo: String; ...; Callback: LongWord);
    external 'DoSomethingInTheDll@files:mydll.dll stdcall';

procedure MyCallback(Filename: PChar);
begin
    // do whatever, eg. update the filename label
end;

// wherever you're about to call your DLL
var Callback : LongWord;
// ...
    Callback := WrapMyCallback(@MyCallback, 1); // 1 parameter
    // pass the callback to your DLL either via a dedicated function
    // or as a parameter of your existing function
    DoSomethingInTheDll(blah, foo, ..., Callback);

On the DLL side: 在DLL方面:

typedef void (__stdcall *MyCallback)(const char *filename);

You can then declare variables of type MyCallback in function parameters and then call them as if they were native C functions, and it will run the code inside the Inno script. 然后,您可以在函数参数中声明MyCallback类型的变量,然后像调用它们是本机C函数一样对其进行调用,它将在Inno脚本中运行代码。

void __stdcall __declspec(dllexport)
    DoSomethingInTheDll(int blah, const char *foo, ..., MyCallback callback)
{
    // ...
    callback(foo);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM