使用回调从外部解压缩dll显示文件名(Inno Setup)

最初在这里被问到,但被要求将其作为一个单独的问题提交。

我在下面的C中编写了以下dll,我在Inno Setup Installer中使用它来提取游戏文件。 这是一个最初使用16位安装程序的游戏的替换安装程序,文件从CD-ROM中复制。 我希望能够使用InnoTools InnoCallback来显示使用我的dll提取的文件名,但由于这是我第一次尝试使用C编码,我不知道该怎么做。 可以在此处找到此function的示例: http : //freearc.org/InnoSetup.aspx

我希望能够使用外部DLL中的文件名设置WizardForm.FilenameLabel.Caption。

我的Inno安装脚本的相关部分:

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

(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(包括blast.c和blast.h来自这里: https : //github.com/madler/zlib/tree/master/contrib/blast )

 #include  #include  #include  #include  #include  #include  #include  #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; } 

看看InnoTools Callback附带的示例脚本。

它非常简单,您只需声明一个这样的过程(再次假设您正在使用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); 

在DLL方面:

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

然后,您可以在函数参数中声明MyCallback类型的变量,然后将它们称为原生C函数,它将运行Inno脚本中的代码。

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