Support execution of pif files - RESEND

Rein Klazes wijn at wanadoo.nl
Sun Mar 6 02:55:17 CST 2005


Hi,

Submitted on 19 Jan. Not applied, no comments...

=================================================

Hi,

This is for an old windows installer that does:
  WinExec16( "LHA.PIF e FILES.LZH");
to extract a bunch a files.

Changelog:
	dlls/kernel		: ne_module.c, process.c
	programs/winevdm	: winevdm.c
	Support execution of pif files.

Rein.
-------------- next part --------------
--- wine/dlls/kernel/ne_module.c	2004-12-29 12:09:48.000000000 +0100
+++ mywine/dlls/kernel/ne_module.c	2005-01-19 09:25:03.000000000 +0100
@@ -1827,7 +1827,7 @@ HINSTANCE16 WINAPI WinExec16( LPCSTR lpC
     HeapFree( GetProcessHeap(), 0, cmdline );
     if (name != lpCmdLine) HeapFree( GetProcessHeap(), 0, name );
 
-    if (ret == 21)  /* 32-bit module */
+    if (ret == 21 || ret == 11)  /* 32-bit module or unknown executable*/
     {
         DWORD count;
         ReleaseThunkLock( &count );
--- wine/dlls/kernel/process.c	2004-12-29 12:09:48.000000000 +0100
+++ mywine/dlls/kernel/process.c	2005-01-19 09:31:45.000000000 +0100
@@ -82,6 +82,7 @@ const WCHAR *DIR_System = NULL;
 
 static const WCHAR comW[] = {'.','c','o','m',0};
 static const WCHAR batW[] = {'.','b','a','t',0};
+static const WCHAR pifW[] = {'.','p','i','f',0};
 static const WCHAR winevdmW[] = {'w','i','n','e','v','d','m','.','e','x','e',0};
 
 extern void SHELL_LoadRegistry(void);
@@ -1952,7 +1953,7 @@ BOOL WINAPI CreateProcessW( LPCWSTR app_
         /* check for .com or .bat extension */
         if ((p = strrchrW( name, '.' )))
         {
-            if (!strcmpiW( p, comW ))
+            if (!strcmpiW( p, comW ) || !strcmpiW( p, pifW ))
             {
                 TRACE( "starting %s as DOS binary\n", debugstr_w(name) );
                 retv = create_vdm_process( name, tidy_cmdline, envW, cur_dir, process_attr, thread_attr,
--- wine/programs/winevdm/winevdm.c	2003-09-27 04:34:07.000000000 +0200
+++ mywine/programs/winevdm/winevdm.c	2005-01-18 18:56:38.000000000 +0100
@@ -19,11 +19,13 @@
  */
 
 #include <stdarg.h>
+#include <stdio.h>
 
 #include "windef.h"
 #include "winbase.h"
 #include "wine/winbase16.h"
 #include "winuser.h"
+#include "wincon.h"
 #include "wine/debug.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(winevdm);
@@ -31,6 +33,223 @@ WINE_DEFAULT_DEBUG_CHANNEL(winevdm);
 extern void WINAPI wine_load_dos_exe( LPCSTR filename, LPCSTR cmdline );
 
 
+/*** PIF file structures ***/
+#include "pshpack1.h"
+
+/* header of a PIF file */
+typedef struct {
+    BYTE unk1[2];               /* 0x00 */
+    CHAR windowtitle[ 30 ];     /* 0x02 seems to be padded with blanks*/ 
+    WORD memmax;                /* 0x20 */
+    WORD memmin;                /* 0x22 */
+    CHAR program[63];           /* 0x24 seems to be zero terminated */
+    BYTE hdrflags1;             /* 0x63 various flags:
+                                 *  02 286: text mode selected
+                                 *  10 close window at exit
+                                 */
+    BYTE startdrive;            /* 0x64 */
+    char startdir[64];          /* 0x65 */
+    char optparams[64];         /* 0xa5 seems to be zero terminated */
+    BYTE videomode;             /* 0xe5 */
+    BYTE unkn2;                 /* 0xe6 ?*/
+    BYTE irqlow;                /* 0xe7 */
+    BYTE irqhigh;               /* 0xe8 */
+    BYTE rows;                  /* 0xe9 */
+    BYTE cols;                  /* 0xea */
+    BYTE winY;                  /* 0xeb */
+    BYTE winX;                  /* 0xec */
+    WORD unkn3;                 /* 0xed 7??? */
+    CHAR unkn4[64];             /* 0xef */
+    CHAR unkn5[64];             /* 0x12f */
+    BYTE hdrflags2;             /* 0x16f */
+    BYTE hdrflags3;             /* 0x170 */
+    } pifhead_t;
+
+/* record header: present on every record */
+typedef struct {
+    CHAR recordname[16];  /* zero terminated */
+    WORD posofnextrecord; /* file offset, 0xffff if last */
+    WORD startofdata;     /* file offset */
+    WORD sizeofdata;      /* data is expected to follow directly */
+} recordhead_t;
+
+/* 386 -enhanced mode- record */
+typedef struct {
+    WORD memmax;         /* memory desired, overrides the pif header*/
+    WORD memmin;         /* memory required, overrides the pif header*/
+    WORD prifg;          /* foreground priority */
+    WORD pribg;          /* background priority */
+    WORD emsmax;         /* EMS memory limit */
+    WORD emsmin;         /* EMS memory required */
+    WORD xmsmax;         /* XMS memory limit */
+    WORD xmsmin;         /* XMS memory required */
+    WORD optflags;        /* option flags:
+                           *  0008 full screen
+                           *  0004 exclusive
+                           *  0002 background
+                           *  0001 close when active
+                           */
+    WORD memflags;       /* various memory flags*/
+    WORD videoflags;     /* video flags:
+                          *   0010 text
+                          *   0020 med. res. graphics
+                          *   0040 hi. res. graphics
+                          */
+    WORD hotkey[9];      /* Hot key info */
+    CHAR optparams[64];  /* optional params, replaces those in the pif header */
+} pif386rec_t;
+
+#include "poppack.h"
+
+/***********************************************************************
+ *           read_pif_file
+ *pif386rec_tu
+ * Read a pif file and return the header and possibly the 286 (real mode)
+ * record or 386 (enhanced mode) record. Returns FALSE if the file is
+ * invalid otherwise TRUE.
+ */
+static BOOL read_pif_file( HANDLE hFile, char *progname, char *title,
+        char *optparams, char *startdir, int *closeonexit, int *textmode)
+{
+    DWORD nread;
+    LARGE_INTEGER filesize;
+    recordhead_t rhead;
+    BOOL found386rec = FALSE;
+    pif386rec_t pif386rec;
+    pifhead_t pifheader;
+    if( !GetFileSizeEx( hFile, &filesize) ||
+            filesize.QuadPart <  (sizeof(pifhead_t) + sizeof(recordhead_t))) {
+        WINE_ERR("Invalid pif file: size error %d must be >= %d\n",
+                (int)filesize.QuadPart,
+                (sizeof(pifhead_t) + sizeof(recordhead_t)));
+        return FALSE;
+    }
+    SetFilePointer( hFile, 0, NULL, FILE_BEGIN);
+    if( !ReadFile( hFile, &pifheader, sizeof(pifhead_t), &nread, NULL))
+        return FALSE;
+    WINE_TRACE("header: program %s title %s startdir %s params %s\n",
+            wine_dbgstr_a(pifheader.program),
+            wine_dbgstr_an(pifheader.windowtitle, sizeof(pifheader.windowtitle)),
+            wine_dbgstr_a(pifheader.startdir),
+            wine_dbgstr_a(pifheader.optparams)); 
+    WINE_TRACE("header: memory req'd %d desr'd %d drive %d videomode %d\n",
+            pifheader.memmin, pifheader.memmax, pifheader.startdrive,
+            pifheader.videomode);
+    WINE_TRACE("header: flags 0x%x 0x%x 0x%x\n",
+            pifheader.hdrflags1, pifheader.hdrflags2, pifheader.hdrflags3);
+    ReadFile( hFile, &rhead, sizeof(recordhead_t), &nread, NULL);
+    if( strncmp( rhead.recordname, "MICROSOFT PIFEX", 15)) {
+        WINE_ERR("Invalid pif file: magic string not found\n");
+        return FALSE;
+    }
+    /* now process the following records */
+    while( 1) {
+        WORD nextrecord = rhead.posofnextrecord;
+        if( (nextrecord & 0x8000) || 
+                filesize.QuadPart <( nextrecord + sizeof(recordhead_t))) break;
+        if( !SetFilePointer( hFile, nextrecord, NULL, FILE_BEGIN) ||
+                !ReadFile( hFile, &rhead, sizeof(recordhead_t), &nread, NULL))
+            return FALSE;
+        if( !rhead.recordname[0]) continue; /* deleted record */
+        WINE_TRACE("reading record %s size %d next 0x%x\n",
+                wine_dbgstr_a(rhead.recordname), rhead.sizeofdata,
+                rhead.posofnextrecord );
+        if( !strncmp( rhead.recordname, "WINDOWS 386", 11)) {
+            found386rec = TRUE;
+            ReadFile( hFile, &pif386rec, sizeof(pif386rec_t), &nread, NULL);
+            WINE_TRACE("386rec: memory req'd %d des'd %d EMS req'd %d des'd %d XMS req'd %d des'd %d\n",
+                    pif386rec.memmin, pif386rec.memmax,
+                    pif386rec.emsmin, pif386rec.emsmax,
+                    pif386rec.xmsmin, pif386rec.xmsmax);
+            WINE_TRACE("386rec: option 0x%x memory 0x%x video 0x%x \n",
+                    pif386rec.optflags, pif386rec.memflags,
+                    pif386rec.videoflags);
+            WINE_TRACE("386rec: optional parameters %s\n",
+                    wine_dbgstr_a(pif386rec.optparams));
+        }
+    }
+    /* prepare the return data */
+    strncpy( progname, pifheader.program, sizeof(pifheader.program));
+    memcpy( title, pifheader.windowtitle, sizeof(pifheader.windowtitle));
+    title[ sizeof(pifheader.windowtitle) ] = '\0';
+    if( found386rec)
+        strncpy( optparams, pif386rec.optparams, sizeof( pif386rec.optparams));
+    else
+        strncpy( optparams, pifheader.optparams, sizeof(pifheader.optparams));
+    strncpy( startdir, pifheader.startdir, sizeof(pifheader.startdir));
+    *closeonexit = pifheader.hdrflags1 & 0x10;
+    *textmode = found386rec ? pif386rec.videoflags & 0x0010
+                            : pifheader.hdrflags1 & 0x0002;
+    return TRUE;
+}
+
+/***********************************************************************
+ *              pif_cmd
+ *
+ * execute a pif file.
+ */
+static VOID pif_cmd( char *filename, char *cmdline)
+{ 
+    HANDLE hFile;
+    char progpath[MAX_PATH];
+    char buf[128];
+    char progname[64];
+    char title[31];
+    char optparams[64];
+    char startdir[64];
+    char *p;
+    int closeonexit;
+    int textmode;
+    if( (hFile = CreateFileA( filename, GENERIC_READ, FILE_SHARE_READ,
+                    NULL, OPEN_EXISTING, 0, 0 )) == INVALID_HANDLE_VALUE)
+    {
+        WINE_ERR("open file %s failed\n", wine_dbgstr_a(filename));
+        return;
+    }
+    if( !read_pif_file( hFile, progname, title, optparams, startdir,
+                &closeonexit, &textmode)) {
+        WINE_ERR( "failed to read %s\n", wine_dbgstr_a(filename));
+        CloseHandle( hFile);
+        sprintf( buf, "%s\nInvalid file format. Check your pif file.", 
+                filename);
+        MessageBoxA( NULL, buf, "16 bit DOS subsystem", MB_OK|MB_ICONWARNING);
+        SetLastError( ERROR_BAD_FORMAT);
+        return;
+    }
+    CloseHandle( hFile);
+    if( (p = strrchr( progname, '.')) && !strcasecmp( p, ".bat"))
+        WINE_FIXME(".bat programs in pif files are not supported.\n"); 
+    /* first change dir, so the search below can start from there */
+    if( startdir[0] && !SetCurrentDirectory( startdir)) {
+        WINE_ERR("Cannot change directory %s\n", wine_dbgstr_a( startdir));
+        sprintf( buf, "%s\nInvalid startup directory. Check your pif file.", 
+                filename);
+        MessageBoxA( NULL, buf, "16 bit DOS subsystem", MB_OK|MB_ICONWARNING);
+    }
+    /* search for the program */
+    if( !SearchPathA( NULL, progname, NULL, MAX_PATH, progpath, NULL )) {
+        sprintf( buf, "%s\nInvalid program file name. Check your pif file.", 
+                filename);
+        MessageBoxA( NULL, buf, "16 bit DOS subsystem", MB_OK|MB_ICONERROR);
+        SetLastError( ERROR_FILE_NOT_FOUND);
+        return;
+    }
+    if( textmode)
+        if( AllocConsole())
+            SetConsoleTitleA( title) ;
+    /* if no arguments on the commandline, use them from the pif file */
+    if( !cmdline[0] && optparams[0])
+        cmdline = optparams;
+    /* FIXME: do something with:
+     * - close on exit
+     * - graphic modes
+     * - hot key's
+     * - etc.
+     */ 
+    wine_load_dos_exe( progpath, cmdline );
+    return;
+}
+
 /***********************************************************************
  *           build_command_line
  *
@@ -164,6 +383,7 @@ int main( int argc, char *argv[] )
     char buffer[MAX_PATH];
     STARTUPINFOA info;
     char *cmdline, *appname, **first_arg;
+    char *p;
 
     if (!argv[1]) usage();
 
@@ -217,10 +437,15 @@ int main( int argc, char *argv[] )
 
     if ((instance = LoadModule16( appname, &params )) < 32)
     {
-        if (instance == 11)  /* try DOS format */
+        if (instance == 11)
         {
-            /* loader expects arguments to be regular C strings */
-            wine_load_dos_exe( appname, cmdline + 1 );
+            /* first see if it is a .pif file */
+            if( ( p = strrchr( appname, '.' )) && !strcasecmp( p, ".pif"))
+                pif_cmd( appname, cmdline + 1);
+            else 
+                /* try DOS format */
+                /* loader expects arguments to be regular C strings */
+                wine_load_dos_exe( appname, cmdline + 1 );
             /* if we get back here it failed */
             instance = GetLastError();
         }
@@ -229,7 +454,7 @@ int main( int argc, char *argv[] )
         switch (instance)
         {
         case  2: WINE_MESSAGE("file not found\n" ); break;
-        case 11: WINE_MESSAGE("invalid exe file\n" ); break;
+        case 11: WINE_MESSAGE("invalid program file\n" ); break;
         default: WINE_MESSAGE("error=%d\n", instance ); break;
         }
         ExitProcess(instance);


More information about the wine-patches mailing list