使用回调从外部解压缩dll(Inno Setup)显示文件名 [英] Using callback to display filenames from external decompression dll (Inno Setup)
问题描述
原来问这里,但被要求提交它作为一个单独的问题。
我有以下dll编码在C下面我正在使用一个Inno安装程序提取游戏文件。这是一个最初使用16位安装程序的游戏的替换安装程序,文件从CD-ROM中复制。我希望能够使用 InnoTools InnoCallback 显示文件名使用我的dll提取,但由于这是我第一次冒险进入C编码,我不知道该怎么做。可以在此处找到此功能的示例: http://freearc.org/InnoSetup.aspx
我希望能够使用我的外部DLL中的文件名设置WizardForm.FilenameLabel.Caption。
Inno Setup脚本的相关章节:
函数VolEx(filename,outputpath:String):Integer;外部VolEx @ files:volex.dll stdcall';
(DriveLetter是CD-ROM的路径,即D:\,所以输出目前读取的是D:\world\archive.vol,我的目标是C:\game-path\world\archive\file.ext)
procedure VolExtract();
begin
如果不是DirExists(WizardDirValue()+'\'+ Worlds [w])然后
begin
CreateDir(WizardDirValue()+'\'+ Worlds [瓦特]);
结束
for n:= 0 to 3 do begin
WizardForm.FilenameLabel.Caption:= DriveLetter + Worlds [w] +'\'+ Reslists [n] +'.vol';
如果VolEx(DriveLetter + Worlds [w] +'\'+ Reslists [n] +'.vol',WizardDirValue()+'\'+ Worlds [w] +'\ '+ Reslists [n])< 0然后
begin
//处理失败
MsgBox(CustomMessage('FileErr'),mbInformation,MB_OK);
WizardForm.Close;
结束
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>
#includeblast.h
#define本地静态
#define VOLIDRESLIST
struct inbuf {
unsigned long剩下;
unsigned char * buf;
无符号大小;
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->左? 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 * )如何)!= len;
}
#define BUFSIZE 16384 / *必须符合无符号* /
local int extract(char * name,unsigned long len,FILE * in,const char * path,time_t prevtime)
{
int err;
文件*出;
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; / *从时代开始* /
new_times.actime = statbuf.st_atime; / *保持空时不变* /
new_times.modtime = prevtime; / *将mtime设置为当前时间* /
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; / *从历元起* /
如果(fread(head,1,8,in)!= 8 || memcmp(head,VOLID,8)){
/ * fprintf (stderr,不是预期的.vol格式\); * /
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) (头[23])<< 24);
head [20] = 0;
err = extract((char *)head,next-off,in,outputpath,voltime);
if(err){
/ * fprintf(stderr,提取错误%d on%s\\\
,err,head); * /
return 1;
}
off = next;
}
/ * if(next)
fprintf(stderr,%lu bytes ignored at the end\\\
,next); * /
return 0;
}
脚本包含在 InnoTools回调中。
$ b $这很简单,你只需要声明一个这样的过程(同样,假设你使用的是ANSI Inno,一些类型的Unicode版本将被更改):
[代码]
类型
TMyCallback = procedure(文件名:PChar);
函数WrapMyCallback(回调:TMyCallback; ParamCount:Integer):LongWord;
external'WrapCallback @ files:innocallback.dll stdcall';
程序DoSomethingInTheDll(Blah:Integer; Foo:String; ...;回调:LongWord);
external'DoSomethingInTheDll @ files:mydll.dll stdcall';
程序MyCallback(文件名:PChar);
begin
// do whatever,eg。更新文件名标签
end;
//无论你要打电话给你的DLL
var回调:LongWord;
// ...
回调:= WrapMyCallback(@MyCallback,1); // 1参数
//通过专用函数
//或作为现有函数的参数将回调传递给您的DLL
DoSomethingInTheDll(blah,foo,...,Callback );
在DLL端:
typedef void(__stdcall * MyCallback)(const char * filename);
然后,您可以声明类型为 MyCallback
的变量在函数参数中,然后调用它们,就像它们是native C函数一样,它将在Inno脚本中运行代码。
void __stdcall __declspec(dllexport)
DoSomethingInTheDll(int blah,const char * foo,...,MyCallback callback)
{
// ...
callback(foo);
}
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. This is a replacement installer for a game which originally used a 16-bit installer and files are copied off a 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. An example of this functionality may be found here: http://freearc.org/InnoSetup.aspx
I would like to be able to set WizardForm.FilenameLabel.Caption using the file name from my external dll.
Relevant sections of my Inno Setup script:
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")
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)
#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.
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):
[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:
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.
void __stdcall __declspec(dllexport)
DoSomethingInTheDll(int blah, const char *foo, ..., MyCallback callback)
{
// ...
callback(foo);
}
这篇关于使用回调从外部解压缩dll(Inno Setup)显示文件名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!