Index: subsystems/mvdm/ntvdm/dos/dos32krnl/process.c =================================================================== --- subsystems/mvdm/ntvdm/dos/dos32krnl/process.c (revision 75314) +++ subsystems/mvdm/ntvdm/dos/dos32krnl/process.c (working copy) @@ -692,6 +692,104 @@ return Result; } +/* Code taken from winevdm */ +BOOL ReadPifFile(HANDLE hFile, + LPSTR progname, + LPSTR title, + LPSTR optparams, + LPSTR startdir, + PINT closeonexit, + PINT textmode) +{ + DWORD nread; + LARGE_INTEGER filesize; + recordhead_t rhead; + pif386rec_t pif386rec; + pifhead_t pifheader; + BOOL found386rec = FALSE; + + if (!GetFileSizeEx(hFile, &filesize) || + filesize.QuadPart < (sizeof(pifhead_t) + sizeof(recordhead_t))) + { + DisplayMessage(L"Invalid PIF file size error %d.", (int)filesize.QuadPart); + return FALSE; + } + + SetFilePointer(hFile, 0, NULL, FILE_BEGIN); + + if (!ReadFile(hFile, &pifheader, sizeof(pifhead_t), &nread, NULL)) + { + DisplayMessage(L"Unable to read PIF file!"); + return FALSE; + } + + DPRINT1("header: program %s title %s startdir %s params %s\n", + pifheader.program, pifheader.windowtitle, pifheader.startdir, + pifheader.optparams); + DPRINT1("header: memory req'd %d desr'd %d drive %d videomode %d\n", + pifheader.memmin, pifheader.memmax, pifheader.startdrive, + pifheader.videomode); + DPRINT1("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)) + { + DisplayMessage(L"Invalid PIF file: magic string not found.\nUsed instead: %S\n", rhead.recordname); + 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)) + { + DisplayMessage(L"Unable to set the file pointer."); + return FALSE; + } + + if( !rhead.recordname[0]) continue; /* deleted record */ + + DPRINT1("reading record %s size %d next 0x%x\n", rhead.recordname, + rhead.sizeofdata, rhead.posofnextrecord ); + + if (!strncmp( rhead.recordname, "WINDOWS 386", 11)) + { + found386rec = TRUE; + ReadFile( hFile, &pif386rec, sizeof(pif386rec_t), &nread, NULL); + + DPRINT1("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); + DPRINT1("386rec: option 0x%x memory 0x%x video 0x%x\n", pif386rec.optflags, pif386rec.memflags, + pif386rec.videoflags); + DPRINT1("386rec: optional parameters %s\n", pif386rec.optparams); + } + } + + /* prepare the return data */ + lstrcpynA( progname, pifheader.program, sizeof(pifheader.program)+1); + lstrcpynA( title, pifheader.windowtitle, sizeof(pifheader.windowtitle)+1); + if(found386rec) + lstrcpynA(optparams, pif386rec.optparams, sizeof( pif386rec.optparams)+1); + else + lstrcpynA(optparams, pifheader.optparams, sizeof(pifheader.optparams)+1); + lstrcpynA( startdir, pifheader.startdir, sizeof(pifheader.startdir)+1); + *closeonexit = pifheader.hdrflags1 & 0x10; + *textmode = found386rec ? pif386rec.videoflags & 0x0010 + : pifheader.hdrflags1 & 0x0002; + + return TRUE; +} + DWORD DosLoadExecutable(IN DOS_EXEC_TYPE LoadType, IN LPCSTR ExecutablePath, IN PDOS_EXEC_PARAM_BLOCK Parameters, @@ -794,6 +892,70 @@ switch (BinaryType) { /* Those are handled by NTVDM */ + case SCS_PIF_BINARY: + { + HANDLE hFile; + char progpath[MAX_PATH]; + char lpProgName[64], lpTitle[31], lpOptParams[65], lpStartDir[65]; + int closeonexit, textmode; + + /* Opens the PIF file */ + if ((hFile = CreateFileA(ProgramName, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + 0, 0)) == INVALID_HANDLE_VALUE) + { + DisplayMessage(L"Could not load DOS shortcut '%S'.\n" + L"Make sure the file exists or is valid.", + ProgramName); + return ERROR_FILE_NOT_FOUND; + } + + if (!ReadPifFile(hFile, lpProgName, lpTitle, lpOptParams, lpStartDir, &closeonexit, &textmode)) + { + DisplayMessage(L"Error reading DOS shortcut '%S'.", ProgramName); + CloseHandle(hFile); + // Fall through + } + + /* Close the file since it's not being used right now */ + CloseHandle(hFile); + + /* Make sure that the path of the program actually exists */ + if (lpStartDir[0] && !SetCurrentDirectoryA(lpStartDir)) + { + DisplayMessage(L"Error changing current directory '%S'.", lpStartDir); + return ERROR_PATH_NOT_FOUND; + } + + /* Make sure that the program the shortcut is pointing to actually exists */ + if (!SearchPathA(NULL, lpProgName, NULL, MAX_PATH, progpath, NULL )) + { + DisplayMessage(L"Error finding DOS program '%S'.", lpProgName); + return ERROR_PATH_NOT_FOUND; + } + + /* If the PIF file defines a window title, then use it */ + if (textmode) + if(AllocConsole()) + SetConsoleTitleA(lpTitle); + + /* Load the executable */ + Result = DosLoadExecutable(DOS_LOAD_AND_EXECUTE, + progpath, + Parameters, + NULL, + NULL, + ReturnAddress); + if (Result != ERROR_SUCCESS) + { + DisplayMessage(L"Could not load '%S'. Error: %u", ProgramName, Result); + } + + break; + } case SCS_WOW_BINARY: { DisplayMessage(L"Trying to load '%S'.\n" Index: subsystems/mvdm/ntvdm/dos/dos32krnl/process.h =================================================================== --- subsystems/mvdm/ntvdm/dos/dos32krnl/process.h (revision 75314) +++ subsystems/mvdm/ntvdm/dos/dos32krnl/process.h (working copy) @@ -15,6 +15,73 @@ #define SEGMENT_TO_PSP(seg) ((PDOS_PSP)SEG_OFF_TO_PTR((seg), 0)) +#include + +/* header of a PIF file - Taken from winevdm */ +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 + typedef enum { DOS_LOAD_AND_EXECUTE = 0x00,