Index: sdk/lib/pifio/CMakeLists.txt =================================================================== --- sdk/lib/pifio/CMakeLists.txt (nonexistent) +++ sdk/lib/pifio/CMakeLists.txt (working copy) @@ -0,0 +1,2 @@ +add_library(pifio pifio.c) +add_dependencies(pifio psdk) \ No newline at end of file Index: sdk/lib/pifio/pifio.c =================================================================== --- sdk/lib/pifio/pifio.c (nonexistent) +++ sdk/lib/pifio/pifio.c (working copy) @@ -0,0 +1,140 @@ +/* + * COPYRIGHT: See COPYING.LIB in the top level directory + * PROJECT: PIF I/O Library + * FILE: sdk/lib/pifio/pifio.c + * PURPOSE: Gives the ability to Save/Load DOS Shortcut Files + * PROGRAMMERS: Alexandre Julliard + * Lee Schroeder + */ +#include "pifio.h" + +#define NDEBUG +#include + +/* Code taken from winevdm */ +HRESULT ReadPifFile(HANDLE hFile, + LPSTR progname, + LPSTR title, + LPSTR OptParams, + LPSTR StartDir, + PINT closeonexit, + PINT textmode) +{ + DWORD nread; + LARGE_INTEGER filesize; + PIFRECORDHEAD rhead; + PIF386REC pif386rec; + PIFHEAD pifheader; + BOOL found386rec = FALSE; + + /* Make sure there's a file to actually work with */ + if (hFile == NULL) + { + SetLastError(ERROR_INVALID_HANDLE); + return E_HANDLE; + } + + /* Make sure the file is of the proper size before using it */ + if (!GetFileSizeEx(hFile, &filesize) || + filesize.QuadPart < (sizeof(PIFHEAD) + sizeof(PIFRECORDHEAD))) + { + DPRINT1("Invalid PIF file size error %d.", (int)filesize.QuadPart); + return E_FAIL; + } + + /* Set the file pointer to the beginning of the file so it + can be read properly */ + if (!SetFilePointer(hFile, 0, NULL, FILE_BEGIN)) + return E_FAIL; + + if (!ReadFile(hFile, &pifheader, sizeof(PIFHEAD), &nread, NULL)) + { + DPRINT1("Unable to read PIF file!"); + return E_FAIL; + } + + DPRINT1("header: program %s title %s startdir %s params %s\n", + pifheader.AppName, pifheader.WindowTitle, pifheader.StartDir, + pifheader.OptParams); + DPRINT1("header: memory req'd %d desr'd %d drive %d videomode %d\n", + pifheader.MinMemory, pifheader.MaxMemory, pifheader.StartDrive, + pifheader.VideoMode); + DPRINT1("header: flags 0x%x 0x%x 0x%x\n", pifheader.AppFlags, + pifheader.BitMask1, pifheader.BitMask2); + + /* Opens the file for reading from */ + if (!ReadFile(hFile, &rhead, sizeof(PIFRECORDHEAD), &nread, NULL)) + { + DPRINT1("Unable to read PIF file!"); + return E_FAIL; + } + + /* Ensure that this is actually a PIF file */ + if (strncmp(rhead.RecordName, "MICROSOFT PIFEX", 15)) + { + DPRINT1("Invalid PIF file: magic string not found. Used instead: %S\n", rhead.RecordName); + return E_FAIL; + } + + /* now process the following records */ + while(1) + { + WORD nextrecord = rhead.NextRecordPos; + + if ((nextrecord & 0x8000) || + filesize.QuadPart < (nextrecord + sizeof(PIFRECORDHEAD))) + break; + + if (!SetFilePointer(hFile, nextrecord, NULL, FILE_BEGIN) || + !ReadFile(hFile, &rhead, sizeof(PIFRECORDHEAD), &nread, NULL)) + { + DPRINT1("Unable to set the file pointer."); + return E_POINTER; + } + + /* deleted record */ + if (!rhead.RecordName[0]) + continue; + + DPRINT1("reading record %s size %d next 0x%x\n", rhead.RecordName, + rhead.sizeofdata, rhead.NextRecordPos); + + if (!strncmp(rhead.RecordName, "WINDOWS 386", 11)) + { + found386rec = TRUE; + + if (!ReadFile( hFile, &pif386rec, sizeof(PIF386REC), &nread, NULL)) + return E_FAIL; + + 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.MinMemory, pif386rec.MaxMemory, pif386rec.MinEMS, + pif386rec.MaxEMS, pif386rec.MinXMS, pif386rec.MaxXMS); + 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 */ + StringCchCopyA(progname, sizeof(pifheader.AppName)+1, pifheader.AppName); + StringCchCopyA(title, sizeof(pifheader.WindowTitle)+1, pifheader.WindowTitle); + + if(found386rec) + StringCchCopyA(OptParams, sizeof(pif386rec.OptParams)+1, pif386rec.OptParams); + else + StringCchCopyA(OptParams, sizeof(pifheader.OptParams)+1, pifheader.OptParams); + + StringCchCopyA(StartDir, sizeof(pifheader.StartDir)+1, pifheader.StartDir); + *closeonexit = pifheader.AppFlags & 0x10; + *textmode = found386rec ? pif386rec.VideoFlags & 0x0010 + : pifheader.AppFlags & 0x0002; + +#if 0 + lpPifStruct.PifHeader = rhead; + + if (found386rec) + lpPifStruct.Pif386Record = pif386rec; +#endif + + return S_OK; +} Index: sdk/lib/pifio/pifio.h =================================================================== --- sdk/lib/pifio/pifio.h (nonexistent) +++ sdk/lib/pifio/pifio.h (working copy) @@ -0,0 +1,94 @@ +/* + * COPYRIGHT: See COPYING.LIB in the top level directory + * PROJECT: PIF I/O Library + * FILE: sdk/lib/pifio/pifio.h + * PURPOSE: Gives the ability to Save/Load DOS Shortcut Files + * PROGRAMMERS: Alexandre Julliard + * Lee Schroeder + */ +#ifndef PIFLIB_H +#define PIFLIB_H + +#include +#include +#include + +#include + +/* NOTES: + * - Code taken from WINE's winevdm. + * - http://www.smsoft.ru/en/pifdoc.htm + * - http://www.drdobbs.com/architecture-and-design/undocumented-corner/184409042 + */ +typedef struct { + BYTE Checksum[2]; /* 0x00 Never checked */ + CHAR WindowTitle[30]; /* 0x02 Seems to be padded with blanks */ + WORD MaxMemory; /* 0x20 */ + WORD MinMemory; /* 0x22 */ + CHAR AppName[63]; /* 0x24 Seems to be zero terminated */ + BYTE AppFlags; /* 0x63 Various flags: + * - 01 Directly modify memory + * - 02 286: text mode selected + * - 04 Prevent program switch + * - 08 No screen exchange + * - 10 Close window at exit + * - 40 Direct interaction with COM1 + * - 80 Direct interaction with COM2 + */ + BYTE StartDrive; /* 0x64 */ + char StartDir[64]; /* 0x65 */ + char OptParams[64]; /* 0xa5 seems to be zero terminated */ + BYTE VideoMode; /* 0xe5 not used */ + BYTE VideoPageQuantity; /* 0xe6 not used */ + BYTE IrqLow; /* 0xe7 not used */ + BYTE IrqHigh; /* 0xe8 not used */ + BYTE WinWidth; /* 0xe9 not used */ + BYTE WinHeight; /* 0xea not used */ + BYTE WinYPos; /* 0xeb not used */ + BYTE WinXPos; /* 0xec not used */ + WORD LastVideoPage; /* 0xed */ + CHAR Padding1[64]; /* 0xef not used */ + CHAR Padding2[64]; /* 0x12f not used */ + BYTE BitMask1; /* 0x16f */ + BYTE BitMask2; /* 0x170 */ +} PIFHEAD, *LPPIFHEAD; + +/* record header: present on every record */ +typedef struct { + CHAR RecordName[16]; /* zero terminated */ + WORD NextRecordPos; /* file offset, 0xffff if last */ + WORD DataStart; /* file offset */ + WORD DataSize; /* data is expected to follow directly */ +} PIFRECORDHEAD, *LPPIFRECORDHEAD; + +/* 386 -enhanced mode- record */ +typedef struct { + WORD MaxMemory; /* memory desired, overrides the pif header */ + WORD MinMemory; /* memory required, overrides the pif header */ + WORD FgPriority; /* foreground priority */ + WORD BgPriority; /* background priority */ + WORD MaxEMS; /* EMS memory limit */ + WORD MinEMS; /* EMS memory required */ + WORD MaxXMS; /* XMS memory limit */ + WORD MinXMS; /* 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 medium res. graphics + * - 0040 high res. graphics + */ + WORD Hotkey[9]; /* Hot key info */ + CHAR OptParams[64]; /* optional params, replaces those in the pif header */ +} PIF386REC, *LPPIF386REC; + +#include + +HRESULT ReadPifFile(HANDLE hFile, LPSTR progname, LPSTR title, LPSTR OptParams, LPSTR startdir, PINT closeonexit, PINT textmode); + +#endif /* PIFLIB_H */ \ No newline at end of file Index: sdk/lib/pifio/CMakeLists.txt =================================================================== --- sdk/lib/pifio/CMakeLists.txt (nonexistent) +++ sdk/lib/pifio/CMakeLists.txt (working copy) @@ -0,0 +1,2 @@ +add_library(pifio pifio.c) +add_dependencies(pifio psdk) \ No newline at end of file Index: sdk/lib/pifio/pifio.c =================================================================== --- sdk/lib/pifio/pifio.c (nonexistent) +++ sdk/lib/pifio/pifio.c (working copy) @@ -0,0 +1,140 @@ +/* + * COPYRIGHT: See COPYING.LIB in the top level directory + * PROJECT: PIF I/O Library + * FILE: sdk/lib/pifio/pifio.c + * PURPOSE: Gives the ability to Save/Load DOS Shortcut Files + * PROGRAMMERS: Alexandre Julliard + * Lee Schroeder + */ +#include "pifio.h" + +#define NDEBUG +#include + +/* Code taken from winevdm */ +HRESULT ReadPifFile(HANDLE hFile, + LPSTR progname, + LPSTR title, + LPSTR OptParams, + LPSTR StartDir, + PINT closeonexit, + PINT textmode) +{ + DWORD nread; + LARGE_INTEGER filesize; + PIFRECORDHEAD rhead; + PIF386REC pif386rec; + PIFHEAD pifheader; + BOOL found386rec = FALSE; + + /* Make sure there's a file to actually work with */ + if (hFile == NULL) + { + SetLastError(ERROR_INVALID_HANDLE); + return E_HANDLE; + } + + /* Make sure the file is of the proper size before using it */ + if (!GetFileSizeEx(hFile, &filesize) || + filesize.QuadPart < (sizeof(PIFHEAD) + sizeof(PIFRECORDHEAD))) + { + DPRINT1("Invalid PIF file size error %d.", (int)filesize.QuadPart); + return E_FAIL; + } + + /* Set the file pointer to the beginning of the file so it + can be read properly */ + if (!SetFilePointer(hFile, 0, NULL, FILE_BEGIN)) + return E_FAIL; + + if (!ReadFile(hFile, &pifheader, sizeof(PIFHEAD), &nread, NULL)) + { + DPRINT1("Unable to read PIF file!"); + return E_FAIL; + } + + DPRINT1("header: program %s title %s startdir %s params %s\n", + pifheader.AppName, pifheader.WindowTitle, pifheader.StartDir, + pifheader.OptParams); + DPRINT1("header: memory req'd %d desr'd %d drive %d videomode %d\n", + pifheader.MinMemory, pifheader.MaxMemory, pifheader.StartDrive, + pifheader.VideoMode); + DPRINT1("header: flags 0x%x 0x%x 0x%x\n", pifheader.AppFlags, + pifheader.BitMask1, pifheader.BitMask2); + + /* Opens the file for reading from */ + if (!ReadFile(hFile, &rhead, sizeof(PIFRECORDHEAD), &nread, NULL)) + { + DPRINT1("Unable to read PIF file!"); + return E_FAIL; + } + + /* Ensure that this is actually a PIF file */ + if (strncmp(rhead.RecordName, "MICROSOFT PIFEX", 15)) + { + DPRINT1("Invalid PIF file: magic string not found. Used instead: %S\n", rhead.RecordName); + return E_FAIL; + } + + /* now process the following records */ + while(1) + { + WORD nextrecord = rhead.NextRecordPos; + + if ((nextrecord & 0x8000) || + filesize.QuadPart < (nextrecord + sizeof(PIFRECORDHEAD))) + break; + + if (!SetFilePointer(hFile, nextrecord, NULL, FILE_BEGIN) || + !ReadFile(hFile, &rhead, sizeof(PIFRECORDHEAD), &nread, NULL)) + { + DPRINT1("Unable to set the file pointer."); + return E_POINTER; + } + + /* deleted record */ + if (!rhead.RecordName[0]) + continue; + + DPRINT1("reading record %s size %d next 0x%x\n", rhead.RecordName, + rhead.sizeofdata, rhead.NextRecordPos); + + if (!strncmp(rhead.RecordName, "WINDOWS 386", 11)) + { + found386rec = TRUE; + + if (!ReadFile( hFile, &pif386rec, sizeof(PIF386REC), &nread, NULL)) + return E_FAIL; + + 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.MinMemory, pif386rec.MaxMemory, pif386rec.MinEMS, + pif386rec.MaxEMS, pif386rec.MinXMS, pif386rec.MaxXMS); + 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 */ + StringCchCopyA(progname, sizeof(pifheader.AppName)+1, pifheader.AppName); + StringCchCopyA(title, sizeof(pifheader.WindowTitle)+1, pifheader.WindowTitle); + + if(found386rec) + StringCchCopyA(OptParams, sizeof(pif386rec.OptParams)+1, pif386rec.OptParams); + else + StringCchCopyA(OptParams, sizeof(pifheader.OptParams)+1, pifheader.OptParams); + + StringCchCopyA(StartDir, sizeof(pifheader.StartDir)+1, pifheader.StartDir); + *closeonexit = pifheader.AppFlags & 0x10; + *textmode = found386rec ? pif386rec.VideoFlags & 0x0010 + : pifheader.AppFlags & 0x0002; + +#if 0 + lpPifStruct.PifHeader = rhead; + + if (found386rec) + lpPifStruct.Pif386Record = pif386rec; +#endif + + return S_OK; +} Index: sdk/lib/pifio/pifio.h =================================================================== --- sdk/lib/pifio/pifio.h (nonexistent) +++ sdk/lib/pifio/pifio.h (working copy) @@ -0,0 +1,94 @@ +/* + * COPYRIGHT: See COPYING.LIB in the top level directory + * PROJECT: PIF I/O Library + * FILE: sdk/lib/pifio/pifio.h + * PURPOSE: Gives the ability to Save/Load DOS Shortcut Files + * PROGRAMMERS: Alexandre Julliard + * Lee Schroeder + */ +#ifndef PIFLIB_H +#define PIFLIB_H + +#include +#include +#include + +#include + +/* NOTES: + * - Code taken from WINE's winevdm. + * - http://www.smsoft.ru/en/pifdoc.htm + * - http://www.drdobbs.com/architecture-and-design/undocumented-corner/184409042 + */ +typedef struct { + BYTE Checksum[2]; /* 0x00 Never checked */ + CHAR WindowTitle[30]; /* 0x02 Seems to be padded with blanks */ + WORD MaxMemory; /* 0x20 */ + WORD MinMemory; /* 0x22 */ + CHAR AppName[63]; /* 0x24 Seems to be zero terminated */ + BYTE AppFlags; /* 0x63 Various flags: + * - 01 Directly modify memory + * - 02 286: text mode selected + * - 04 Prevent program switch + * - 08 No screen exchange + * - 10 Close window at exit + * - 40 Direct interaction with COM1 + * - 80 Direct interaction with COM2 + */ + BYTE StartDrive; /* 0x64 */ + char StartDir[64]; /* 0x65 */ + char OptParams[64]; /* 0xa5 seems to be zero terminated */ + BYTE VideoMode; /* 0xe5 not used */ + BYTE VideoPageQuantity; /* 0xe6 not used */ + BYTE IrqLow; /* 0xe7 not used */ + BYTE IrqHigh; /* 0xe8 not used */ + BYTE WinWidth; /* 0xe9 not used */ + BYTE WinHeight; /* 0xea not used */ + BYTE WinYPos; /* 0xeb not used */ + BYTE WinXPos; /* 0xec not used */ + WORD LastVideoPage; /* 0xed */ + CHAR Padding1[64]; /* 0xef not used */ + CHAR Padding2[64]; /* 0x12f not used */ + BYTE BitMask1; /* 0x16f */ + BYTE BitMask2; /* 0x170 */ +} PIFHEAD, *LPPIFHEAD; + +/* record header: present on every record */ +typedef struct { + CHAR RecordName[16]; /* zero terminated */ + WORD NextRecordPos; /* file offset, 0xffff if last */ + WORD DataStart; /* file offset */ + WORD DataSize; /* data is expected to follow directly */ +} PIFRECORDHEAD, *LPPIFRECORDHEAD; + +/* 386 -enhanced mode- record */ +typedef struct { + WORD MaxMemory; /* memory desired, overrides the pif header */ + WORD MinMemory; /* memory required, overrides the pif header */ + WORD FgPriority; /* foreground priority */ + WORD BgPriority; /* background priority */ + WORD MaxEMS; /* EMS memory limit */ + WORD MinEMS; /* EMS memory required */ + WORD MaxXMS; /* XMS memory limit */ + WORD MinXMS; /* 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 medium res. graphics + * - 0040 high res. graphics + */ + WORD Hotkey[9]; /* Hot key info */ + CHAR OptParams[64]; /* optional params, replaces those in the pif header */ +} PIF386REC, *LPPIF386REC; + +#include + +HRESULT ReadPifFile(HANDLE hFile, LPSTR progname, LPSTR title, LPSTR OptParams, LPSTR startdir, PINT closeonexit, PINT textmode); + +#endif /* PIFLIB_H */ \ No newline at end of file Index: subsystems/mvdm/ntvdm/CMakeLists.txt =================================================================== --- subsystems/mvdm/ntvdm/CMakeLists.txt (revision 75429) +++ subsystems/mvdm/ntvdm/CMakeLists.txt (working copy) @@ -15,6 +15,7 @@ ##################################### include_directories(${REACTOS_SOURCE_DIR}/sdk/include/reactos/libs/fast486) +include_directories(${REACTOS_SOURCE_DIR}/sdk/lib/pifio) spec2def(ntvdm.exe ntvdm.spec ADD_IMPORTLIB) @@ -75,6 +76,6 @@ add_executable(ntvdm ${SOURCE} ntvdm.rc) add_pch(ntvdm ntvdm.h SOURCE) set_module_type(ntvdm win32cui UNICODE IMAGEBASE 0x0F000000) -target_link_libraries(ntvdm fast486 ${PSEH_LIB}) +target_link_libraries(ntvdm fast486 pifio ${PSEH_LIB}) add_importlibs(ntvdm user32 gdi32 advapi32 comdlg32 msvcrt kernel32 ntdll) add_cd_file(TARGET ntvdm DESTINATION reactos/system32 FOR all) Index: subsystems/mvdm/ntvdm/dos/dos32krnl/process.c =================================================================== --- subsystems/mvdm/ntvdm/dos/dos32krnl/process.c (revision 75429) +++ subsystems/mvdm/ntvdm/dos/dos32krnl/process.c (working copy) @@ -31,6 +31,8 @@ #include "vddsup.h" +#include + /* PRIVATE FUNCTIONS **********************************************************/ static VOID DosInitPsp(IN WORD Segment, @@ -794,6 +796,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) != S_OK) + { + 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 75429) +++ subsystems/mvdm/ntvdm/dos/dos32krnl/process.h (working copy) @@ -15,6 +15,8 @@ #define SEGMENT_TO_PSP(seg) ((PDOS_PSP)SEG_OFF_TO_PTR((seg), 0)) +#include + typedef enum { DOS_LOAD_AND_EXECUTE = 0x00,