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,150 @@ +/* + * 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 */ +DWORD ReadPifFile(LPSTR lpFileName, LPSTR Program, LPSTR Caption, LPSTR OptParams, LPSTR StartDir, PINT CloseOnExit, PINT TextMode) +{ + DWORD nread; + LARGE_INTEGER filesize; + PIFRECORDHEAD rhead; + PIF386REC pif386rec; + PIFHEAD pifheader; + BOOL found386rec = FALSE; + HANDLE hFile; + CHAR tmpProgramName[64]; + + /* Make sure there's a file to actually work with */ + if ((hFile = CreateFileA(lpFileName, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + 0, 0)) == INVALID_HANDLE_VALUE) + { + SetLastError(ERROR_INVALID_HANDLE); + return ERROR_FILE_NOT_FOUND; + } + + /* 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 ERROR_PATH_NOT_FOUND; + } + + /* Set the file pointer to the beginning of the file so it + can be read properly */ + if (!SetFilePointer(hFile, 0, NULL, FILE_BEGIN)) + return ERROR_PATH_NOT_FOUND; + + if (!ReadFile(hFile, &pifheader, sizeof(PIFHEAD), &nread, NULL)) + { + DPRINT1("Unable to read PIF file!"); + return ERROR_PATH_NOT_FOUND; + } + + 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 ERROR_PATH_NOT_FOUND; + } + + /* 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 ERROR_PATH_NOT_FOUND; + } + + /* 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."); + CloseHandle(hFile); + return ERROR_PATH_NOT_FOUND; + } + + /* deleted record */ + if (!rhead.RecordName[0]) + continue; + + DPRINT1("reading record %s size %d next 0x%x\n", rhead.RecordName, + rhead.DataSize, rhead.NextRecordPos); + + if (!strncmp(rhead.RecordName, "WINDOWS 386", 11)) + { + found386rec = TRUE; + + if (!ReadFile(hFile, &pif386rec, sizeof(PIF386REC), &nread, NULL)) + { + CloseHandle(hFile); + return ERROR_PATH_NOT_FOUND; + } + + 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); + } + } + + /* Close the file since it's not being used right now */ + CloseHandle(hFile); + + /* prepare the return data */ + StringCchCopyA(tmpProgramName, sizeof(pifheader.AppName)+1, pifheader.AppName); + StringCchCopyA(Caption, 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; + + /* Make sure that the path of the program actually exists */ + if (StartDir[0] && !SetCurrentDirectoryA(StartDir)) + return ERROR_PATH_NOT_FOUND; + + /* Make sure that the program the shortcut is pointing to actually exists */ + if (!SearchPathA(NULL, tmpProgramName, NULL, MAX_PATH, Program, NULL )) + return ERROR_PATH_NOT_FOUND; + + return ERROR_SUCCESS; +} 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 + +DWORD ReadPifFile(LPSTR lpFileName, LPSTR Program, LPSTR Caption, 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,150 @@ +/* + * 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 */ +DWORD ReadPifFile(LPSTR lpFileName, LPSTR Program, LPSTR Caption, LPSTR OptParams, LPSTR StartDir, PINT CloseOnExit, PINT TextMode) +{ + DWORD nread; + LARGE_INTEGER filesize; + PIFRECORDHEAD rhead; + PIF386REC pif386rec; + PIFHEAD pifheader; + BOOL found386rec = FALSE; + HANDLE hFile; + CHAR tmpProgramName[64]; + + /* Make sure there's a file to actually work with */ + if ((hFile = CreateFileA(lpFileName, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + 0, 0)) == INVALID_HANDLE_VALUE) + { + SetLastError(ERROR_INVALID_HANDLE); + return ERROR_FILE_NOT_FOUND; + } + + /* 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 ERROR_PATH_NOT_FOUND; + } + + /* Set the file pointer to the beginning of the file so it + can be read properly */ + if (!SetFilePointer(hFile, 0, NULL, FILE_BEGIN)) + return ERROR_PATH_NOT_FOUND; + + if (!ReadFile(hFile, &pifheader, sizeof(PIFHEAD), &nread, NULL)) + { + DPRINT1("Unable to read PIF file!"); + return ERROR_PATH_NOT_FOUND; + } + + 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 ERROR_PATH_NOT_FOUND; + } + + /* 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 ERROR_PATH_NOT_FOUND; + } + + /* 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."); + CloseHandle(hFile); + return ERROR_PATH_NOT_FOUND; + } + + /* deleted record */ + if (!rhead.RecordName[0]) + continue; + + DPRINT1("reading record %s size %d next 0x%x\n", rhead.RecordName, + rhead.DataSize, rhead.NextRecordPos); + + if (!strncmp(rhead.RecordName, "WINDOWS 386", 11)) + { + found386rec = TRUE; + + if (!ReadFile(hFile, &pif386rec, sizeof(PIF386REC), &nread, NULL)) + { + CloseHandle(hFile); + return ERROR_PATH_NOT_FOUND; + } + + 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); + } + } + + /* Close the file since it's not being used right now */ + CloseHandle(hFile); + + /* prepare the return data */ + StringCchCopyA(tmpProgramName, sizeof(pifheader.AppName)+1, pifheader.AppName); + StringCchCopyA(Caption, 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; + + /* Make sure that the path of the program actually exists */ + if (StartDir[0] && !SetCurrentDirectoryA(StartDir)) + return ERROR_PATH_NOT_FOUND; + + /* Make sure that the program the shortcut is pointing to actually exists */ + if (!SearchPathA(NULL, tmpProgramName, NULL, MAX_PATH, Program, NULL )) + return ERROR_PATH_NOT_FOUND; + + return ERROR_SUCCESS; +} 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 + +DWORD ReadPifFile(LPSTR lpFileName, LPSTR Program, LPSTR Caption, 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 75458) +++ 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/dem.c =================================================================== --- subsystems/mvdm/ntvdm/dos/dem.c (revision 75458) +++ subsystems/mvdm/ntvdm/dos/dem.c (working copy) @@ -34,6 +34,8 @@ #include "vddsup.h" +#include + /* * EXPERIMENTAL! * Activate this line if you want to have COMMAND.COM completely external. @@ -1259,8 +1261,60 @@ /* Retrieve the command to start */ if (NtVdmArgc >= 2) { + DWORD BinaryType; + + if (!GetBinaryTypeW(NtVdmArgv[1], &BinaryType)) + { + DisplayMessage(L"Error getting filetype\n"); + EmulatorTerminate(); + return; + } + WideCharToMultiByte(CP_ACP, 0, NtVdmArgv[1], -1, AppName, sizeof(AppName), NULL, NULL); + + if (BinaryType == SCS_PIF_BINARY) + { + CHAR progpath[MAX_PATH]; + CHAR progname[64], title[31], optparams[65], startdir[65]; + INT txtMode; + /* If the PIF file fails to load, then close with an error */ + if (ReadPifFile(AppName, progname, title, optparams, startdir, 0, &txtMode) != ERROR_SUCCESS) + { + DisplayMessage(L"Error reading DOS shortcut '%S'.", AppName); + EmulatorTerminate(); + return; + } + + /* Make sure that the path of the program actually exists */ + if (startdir[0] && !SetCurrentDirectoryA(startdir)) + { + DisplayMessage(L"Error changing current directory '%S'.", startdir); + EmulatorTerminate(); + return; + } + + /* Make sure that the program the shortcut is pointing to actually exists */ + if (!SearchPathA(NULL, progname, NULL, MAX_PATH, progpath, NULL)) + { + DisplayMessage(L"Error finding DOS program '%S'.", progname); + EmulatorTerminate(); + return; + } + + /* Sets the console title */ + if (txtMode) + { + SetConsoleTitleA(title); + } + else + { + SetConsoleTitleA(progpath); + } + + strcpy(AppName, progpath); + } + if (NtVdmArgc >= 3) WideCharToMultiByte(CP_ACP, 0, NtVdmArgv[2], -1, CmdLine, sizeof(CmdLine), NULL, NULL); else