سؤال

I have the following program that's been written with lots of help. It will explode PKWare DCL compressed .vol archives (file id RESLIST) and extract the files to the specified output folder giving the extracted files the modification date of the original .vol file. It's meant to be used in an Inno Setup installer and I'd like to see if I can compile it as a .dll library I can import in my .iss script ie:

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

I read through http://www.mingw.org/wiki/sampleDLL but was having a hard time understanding all the ifdefs and extern "C" stuff.

Additionally I'd like it to be able to change the WizardForm.FilenameLabel.Caption in my installer to match the file currently being extracted (I understand this needs InnoTools InnoCallback http://www.sherlocksoftware.org/page.php?id=54 ; something similar was done with FreeArc http://freearc.org/InnoSetup.aspx)

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, 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 main(int argc, char *argv[])
{
    if ( argc != 3 )
    {
        printf( "Usage: %s <vol> <output path>", argv[0] );
        return 1;
    }
    else
    {
        FILE *in = fopen(argv[1],"rb");
        unsigned long off, next;
        int err;
        unsigned char head[24];

        if (stat(argv[1], &statbuf) < 0) {
            perror(argv[1]);
            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, argv[2], 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;
    }
}
هل كانت مفيدة؟

المحلول

Assuming that you are using ANSI Inno Setup, the following Inno signature:

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

will require the following C signature in your DLL code:

int __stdcall __declspec(dllexport) VolExA(const char *filename, const char *outputpath);

(If you're compiling the DLL as C++ rather than C then you will also need an extern "C" at the beginning.)

You will need to declare this function in your DLL and move the appropriate code from "main" above into it, then remove the main function and compile as a DLL instead of a console app.

Get this part working first before worrying about feedback via callbacks -- submit a separate question for that if you have trouble with it.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top