使用回调,显示外部DECOM pression DLL(Inno Setup的)文件名 [英] Using callback to display filenames from external decompression dll (Inno Setup)
问题描述
最初问<一个href=\"http://stackoverflow.com/questions/18521921/how-to-compile-c-program-as-dll-in-mingw-for-use-with-inno-setup-callback\">here,但被要求提交其作为一个单独的问题。
我有以下的dll $ C $用C低于CD我使用在Inno Setup的安装程序解压游戏文件。这是一个游戏,最初使用一个16位的安装程序和文件复制从CD-ROM更换安装。我希望能够使用 InnoTools InnoCallback 显示提取的文件名用我的DLL,但是这是我的第一次创业成C代码,我不知道该怎么做。此功能的一个例子可以在这里找到: http://freearc.org/InnoSetup.aspx
我希望能够使用的文件名从我的外部DLL设置WizardForm.FilenameLabel.Caption。
我的Inno Setup的脚本的有关章节:
函数豪利士(文件名,outputpath:字符串):整数;外部豪利士@文件:volex.dll STDCALL';
(驱动器号是CD-ROM,即路径D:\\,所以目前输出读取D:\\世界\\ archive.vol。我的目标输出为C:\\游戏 - 路径\\世界\\存档\\ file.ext)
程序VolExtract();
开始
如果不是DirExists(WizardDirValue()+\\+世界[W]),然后
开始
CreateDir(WizardDirValue()+\\+世界[W]);
结束;
对于n:= 0至3开始做
WizardForm.FilenameLabel.Caption:=驱动器号+世界[W] +\\+ Reslists [N] +'.vol'; 如果豪利士(驱动器号+世界[W] +\\+ Reslists [N] +'.vol',WizardDirValue()+\\+世界[W] +\\+ Reslists [N])LT;&GT; 0,则
开始
//处理失败
MSGBOX(CUSTOMMESSAGE('FileErr'),mbInformation,MB_OK);
WizardForm.Close;
结束;
VolEx.c(包括从这里blast.c和blast.h: HTTPS ://github.com/madler/zlib/tree/master/contrib/blast )
的#include&LT;&stdio.h中GT;
#包括LT&;&stdlib.h中GT;
#包括LT&;&string.h中GT;
#包括LT&;&limits.h中GT;
#包括LT&; SYS / stat.h&GT;
#包括LT&;&time.h中GT;
#包括LT&;&utime.h GT;
#包括blast.h#定义本地静态
#定义VOLIDRESLIST结构INBUF {
无符号长左右;
无符号字符* BUF;
无符号的大小;
FILE *的;
};结构统计statbuf;
time_t的修改时间;
time_t的voltime;
结构utimbuf new_times;当地无符号INF(void *的怎么样,unsigned char型** BUF)
{
无符号LEN;
结构INBUF * INB =如何; LEN = INB-&GT;大小&GT; INB-&GT;剩下什么? INB-&GT;左:INB-&GT;大小;
LEN =的fread(INB-&GT; buf中,1,LEN,INB-&gt;在);
INB-&GT;左 - = LEN;
* BUF = INB-&GT; BUF;
返回LEN;
}当地INT OUTF(void *的怎么样,无符号的char * buf中,无符号LEN)
{
返回FWRITE(BUF,1,LEN(FILE *)如何)= LEN!;
}的#define BUFSIZE 16384 / *必须符合无符号* /当地INT提取物(字符*名称,无符号长LEN,FILE *中,为const char *路径,time_t的prevtime)
{
INT犯错;
FILE *出;
结构INBUF INB;
unsigned char型BUF [BUFSIZE]; inb.left = LEN;
inb.buf = BUF;
inb.size = BUFSIZE;
inb.in =中;
MKDIR(路径);
焦炭outpath中[strlen的(路径)+ 20];
的strcpy(outpath中,路径);
的strcat(outpath中,\\\\);
strcat的(outpath中,名);
OUT = FOPEN(outpath中,WB);
如果(出== NULL)
返回2;
ERR =爆炸(INF,和放大器; INB,OUTF,淘汰);
FCLOSE(出);
如果(统计(outpath中,&放大器; statbuf)小于0){
PERROR(outpath中);
返回1;
}
的mtime = statbuf.st_mtime; / *自纪元秒* / new_times.actime = statbuf.st_atime; / *保持不变的atime * /
new_times.modtime = prevtime; / *设置的mtime当前时间* /
如果(UTIME(outpath中,&放大器; new_times)小于0){
PERROR(outpath中);
返回1;
}
返回ERR;
}INT __stdcall __declspec(dllexport)的豪利士(为const char *文件名,为const char * outputpath)
{
FILE *在FOPEN =(文件名,RB);
无符号长了,接下来的;
INT犯错;
unsigned char型头[24]; 如果(STAT(文件名,和放大器; statbuf)小于0){
PERROR(文件名);
返回1;
}
voltime = statbuf.st_mtime; / *自纪元秒* / 如果(FREAD(头,1,8,中)!= 8 || memcmp(头,VOLID,8)){
/ * fprintf中(标准错误,而不是预期的.vol格式\\ n); * /
返回1;
}
关闭= 8;
而((NEXT = FREAD(头,1,24日,))== 24){
关闭+ = 24;
接下来=头[20] +(头[21]&LT;&LT; 8)+((无符号长)(头[22])LT;&LT; 16)+
((无符号长)(头[23])LT;&LT; 24); 头[20] = 0;
ERR =提取物((字符*)头,旁边 - 关中,outputpath,voltime);
如果(ERR){
/ * fprintf中(标准错误,在%s \\ n提取错误%D,呃,头); * /
返回1;
}
关闭=下一个;
}
/ *如果(下)
fprintf中(标准错误,鲁%字节忽略末\\ n,下一个); * /
返回0;
}
看一看包含的 InnoTools回调。
这是pretty简单,你只是声明了一个过程像这样(再次,假设你使用ANSI的Inno - 某些类型的就必须改变为统一code版本):
[code]
类型
TMyCallback =程序(文件名:PChar类型);功能WrapMyCallback(回拨:TMyCallback; ParamCount:整数):长字;
外部WrapCallback @文件:innocallback.dll STDCALL';程序DoSomethingInTheDll(布拉赫:整数;富:字符串; ...;回调:长字);
外部DoSomethingInTheDll @文件:MYDLL.DLL STDCALL';程序myCallBack函数(文件名:PChar类型);
开始
//做什么,例如。更新文件名标签
结束;//无论你将要打电话给你的DLL
VAR回调:长字;
// ...
回拨:= WrapMyCallback(@MyCallback,1); //参数1
//或者通过专门的功能回调传递给您的DLL
//或者作为现有函数的参数
DoSomethingInTheDll(胡说,富,...,回调);
在该DLL的一面:
无效的typedef(__stdcall * myCallBack函数)(为const char *文件名);
您就可以在函数的参数声明类型 myCallBack函数
的变量,然后打电话给他们,好像他们是原生的C函数,它将运行里面的code英诺脚本。
无效__stdcall __declspec(dllexport)的
DoSomethingInTheDll(INT等等,为const char * foo,那么......,myCallBack函数回调)
{
// ...
回调(富);
}
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);
}
这篇关于使用回调,显示外部DECOM pression DLL(Inno Setup的)文件名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!