Mega Code Archive

 
Categories / Delphi / Examples
 

Turbo Pascal Compatibility DOS

Title: Turbo Pascal Compatibility: DOS A DOS unit for Delphi, which should give some TP compatibility, which hopefully all should work, save the issues. Again if anything is not implemented, either it wasn't a good idea, or I didn't know how (I included empty function prototypes and the relevant data types). The big standing issue: NTFS drives seem to not store short file names for everything, which means you can not get compatible SFNs for all files in the system. In that case, you will get LFNs returned, which may or may not be what your program is ready for (I defined the SearchRec record to have a String type instead of String[12] like the original). Double-check your program if you use FindFirst/FindNext to see if this won't be a problem. Hope this helps someone, if not by its direct use, to see how to do something from the DOS unit in Delphi/Win32. CODE unit dos; { unit for DOS functions in Delphi - coded by Glenn9999 under Delphi 3. Used helps from the Internet for Turbo Pascal references and the Free Pascal sources. } interface uses sysutils, windows; const { file attribute constants } ReadOnly = faReadOnly; Hidden = faHidden; SysFile = faSysFile; VolumeID = faVolumeID; Directory = faDirectory; Archive = faArchive; AnyFile = faAnyFile; type Int64 = Comp; { comment out if you have Int64 type } { data types and records that were defined in the DOS unit } PathStr = String[79]; DirStr = String[67]; NameStr = String[8]; ExtStr = String[4]; ComStr = string[128]; { used for PackTime and UnPackTime } DateTime = record Year, Month, Day, Hour, Min, Sec: Word; end; { searchrec type. Changed in certain respects to ease functionality in Windows, since the exact record format shouldn't matter too much as long the record is not accessed directly, as opposed to access by the record type definition. Also, NTFS file systems do not necessarily store and return short file names, so you may get LFNs out of FindFirst if run against such systems. - check your TP program before you try using FindFirst } SearchRec = record Attr: Byte; { attribute of file returned } Time: Longint; { packed timestamp } Size: Longint; { size of file } Name: string; { name of file (short name if available } { variables following are necessary for continued functionality of findfirst/FindNext } FindHandle: THandle; { saved search handle } ExcludeAttr: Integer; { saved attribute parm } Path: PathStr; { saved path parm } end; Registers = record { for the do-nothing calls } case Integer of 0: (AX, BX, CX, DX, BP, SI, DI, DS, ES, Flags: Word); 1: (AL, AH, BL, BH, CL, CH, DL, DH: Byte); end; var doserror: integer; DosExitCode: DWord; { these two functions are not in the DOS unit, but are here if needed, otherwise the regular functions as defined in the DOS unit will only report a maximum of 2GB. } function DiskSizeEx(Drive: Byte): Int64; // addl functions added function DiskFreeEx(Drive: Byte): Int64; // these work for 2GB function fexpand(filename: string): string; procedure GetFAttr(var f; var attr: word); procedure SetFAttr(var F; Attr: Word); procedure FSplit(Path: PathStr; var Dir: DirStr; var Name: NameStr; var Ext: ExtStr); procedure PackTime(var T: DateTime; var P: Longint); procedure UnpackTime(P: Longint; var T: DateTime); procedure FindFirst(Path: PathStr; Attr: Word; var F: SearchRec); procedure FindNext(var F: SearchRec); function DiskFree(Drive: Byte): Longint; function DiskSize(Drive: Byte): Longint; function DosVersion: Word; function FSearch(Path: PathStr; DirList: String): PathStr; procedure GetFTime(var F; var Time: Longint); procedure SetFTime(var F; Time: Longint); procedure GetDate(var Year,Month,Day, DayOfWeek: Word); procedure GetTime(var Hour,Minute,Second,Sec100: Word); procedure SetDate(Year,Month,Day: Word); procedure SetTime(Hour,Minute,Second,Sec100: Word); function EnvCount: Integer; function EnvStr(Index: Integer): String; function GetEnv(EnvVar: String): String; procedure Exec(Path: PathStr; ComLine: ComStr); { do nothing functions - generally incompatible for Windows, included here both for documentation and to not break compilation of programs that might not otherwise work. } procedure GetVerify(var Verify: Boolean); procedure Intr(IntNo: Byte; var Regs: Registers); procedure Keep(ExitCode: Word); procedure MsDos(var Regs: Registers); procedure GetCBreak(var Break: Boolean); procedure SetCBreak(Break: Boolean); procedure GetIntVec(IntNo: Byte; var Vector: Pointer); procedure SetIntVec(IntNo: Byte; Vector: Pointer); procedure SetVerify(Verify: Boolean); procedure SwapVectors; { crossover DOS unit, allows some functions to go through sysutils unit } implementation uses messages; { *********************************************************************** Service functions for the other functions listed in the interface unit *********************************************************************** } function GetShortName(sLongName: string): string; begin Result := sLongName; end; function getvolname(input: string): string; { returns Volume Name of the drive that is inputted adapted from http://www.delphicorner.f9.co.uk/articles/wapi2.htm MAX_PATH is a dword defined to be 260 } var nVNameSer: PDWORD; pVolName: PChar; FSSysFlags, maxCmpLen: DWord; pFSBuf: PChar; begin GetMem(pVolName, MAX_PATH); GetMem(pFSBuf, MAX_PATH); GetMem(nVNameSer, MAX_PATH); GetVolumeInformation(PChar(input), pVolName, MAX_PATH, nVNameSer, maxCmpLen, FSSysFlags, pFSBuf, MAX_PATH); GetVolName := String(pVolName); FreeMem(pVolName, MAX_PATH); FreeMem(pFSBuf, MAX_PATH); FreeMem(nVNameSer, MAX_PATH); end; function DiskFreeEx(Drive: Byte): Int64; { redone DiskFree function which reports amount free on a disk 2GB - original from Delphi 3 sources, changed to increase size of variable returned. Can be called if real size is necessary. } var RootPath: array[0..4] of Char; RootPtr: PChar; SectorsPerCluster, BytesPerSector, FreeClusters, TotalClusters: Integer; OutInt64: Int64; begin RootPtr := nil; if Drive 0 then begin StrCopy(RootPath, 'A:\'); RootPath[0] := Char(Drive + $40); RootPtr := RootPath; end; if GetDiskFreeSpace(RootPtr, SectorsPerCluster, BytesPerSector, FreeClusters, TotalClusters) then begin OutInt64 := SectorsPerCluster; Result := OutInt64 * BytesPerSector * FreeClusters; end else Result := -1; end; function DiskSizeEx(Drive: Byte): Int64; { redone DiskSize function which reports size of disk 2GB - original from Delphi 3 sources, changed to increase size of variable returned. Can be called if real size is necessary. } var RootPath: array[0..4] of Char; RootPtr: PChar; SectorsPerCluster, BytesPerSector, FreeClusters, TotalClusters: Integer; OutInt64: Int64; begin RootPtr := nil; if Drive 0 then begin StrCopy(RootPath, 'A:\'); RootPath[0] := Char(Drive + $40); RootPtr := RootPath; end; if GetDiskFreeSpace(RootPtr, SectorsPerCluster, BytesPerSector, FreeClusters, TotalClusters) then begin OutInt64 := SectorsPerCluster; Result := OutInt64 * BytesPerSector * TotalClusters; end else Result := -1; end; function ProcessAMsg: Boolean; { service function for ProcessMessage } var Msg: TMsg; msg_proc: boolean; begin msg_proc := False; if PeekMessage(Msg, 0, 0, 0, PM_REMOVE) then begin msg_proc := True; if Msg.Message WM_QUIT then begin TranslateMessage(Msg); DispatchMessage(Msg); end; end; ProcessAMsg := msg_proc; end; procedure ProcessMessage; { this should be an equivalent to TApplication.ProcessMessages } begin while ProcessAMsg do; end; function os_is_nt: Boolean; { returns whether the OS is NT based or not } var osvinfo: TOsVersionInfo; begin { get windows version } osvinfo.dwOSVersionInfoSize := Sizeof(osvinfo); GetVersionEx(osvinfo); os_is_nt := (osvinfo.dwPlatformId = VER_PLATFORM_WIN32_NT); end; function NTSetPrivilege(sMachine, sPrivilege: string; bEnabled: Boolean): Boolean; { set privilege on remote computer. Define sMachine to be null if you want local machine. Modified from something on SwissCenter. } var hToken: THandle; TokenPriv: TTokenPrivileges; PrevTokenPriv: TTokenPrivileges; ReturnLength: DWord; begin // Only for Windows NT/2000/XP and later. if not (os_is_nt) then begin Result := true; Exit; end; // obtain the processes token if OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, hToken) then begin try // Get the locally unique identifier (LUID) . if LookupPrivilegeValue(PChar(sMachine), PChar(sPrivilege), TokenPriv.Privileges[0].Luid) then begin TokenPriv.PrivilegeCount := 1; // one privilege to set case bEnabled of True: TokenPriv.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED; False: TokenPriv.Privileges[0].Attributes := 0; end; ReturnLength := 0; // replaces a var parameter PrevTokenPriv := TokenPriv; // enable or disable the privilege AdjustTokenPrivileges(hToken, False, TokenPriv, SizeOf(PrevTokenPriv), PrevTokenPriv, ReturnLength); end; finally CloseHandle(hToken); end; end; // test the return value of AdjustTokenPrivileges. Result := GetLastError = ERROR_SUCCESS; if not Result then raise Exception.Create(SysErrorMessage(GetLastError)); end; { *********************************************************************** Dos Compatibility Functions listed after this point *********************************************************************** } function fexpand(filename: string): string; { returns the fully qualified path for a file } var test: string; test_len: integer; begin // we need a string for ExpandFileName if there is not one if filename = '' then filename := '*.*'; test := GetShortName(ExpandFileName(Filename)); { check for trailing . - we want the path as TP returns, not the base directory identifier as well } test_len := length(test); if test[test_len] = '.' then begin test := copy(test, 1, test_len-1); dec(test_len, 1); end; // ExpandFileName returns *.* on the path. The TP FExpand did not. if pos('\*.*', test) 0 then test := copy(test, 1, test_len-4); // if test[test_len] = '\' then // test := test + '*.*'; fexpand := test; end; procedure GetFAttr(var f; var attr: word); { gets the file attribute for a file variable } begin doserror := 0; attr := FileGetAttr(TFileRec(f).Name); if attr = -1 then doserror := GetLastError; end; procedure SetFAttr(var F; Attr: Word); { sets the file attribute for a file variable } begin doserror := 0; doserror := FileSetAttr(TFileRec(f).Name, attr); end; procedure FSplit(Path: PathStr; var Dir: DirStr; var Name: NameStr; var Ext: ExtStr); { splits a full file path into the directory, name, and extension } var filename: string; begin Path := GetShortName(Path); Dir := ExtractFilePath(Path); filename := ExtractFileName(Path); Name := copy(filename, 1, pos('.', filename)-1); Ext := ExtractFileExt(Path); end; procedure PackTime(var T: DateTime; var P: Longint); { datetime type to packed DOS Timestamp } var MSec: Word; DateTime: TDateTime; begin MSec := 0; With T Do begin DateTime := EncodeDate(Year, Month, Day) + EncodeTime(Hour, Min, Sec, MSec); end; P := DateTimeToFileDate(DateTime); end; procedure UnpackTime(P: Longint; var T: DateTime); { Packed DOS Timestamp to datetime type } var MSec: Word; MyDateTime: TDateTime; begin MyDateTime := FileDateToDateTime(p); With T Do begin DecodeDate(MyDateTime, Year, Month, Day); DecodeTime(MyDateTime, Hour, Min, Sec, MSec); end; end; procedure move_sr(F: TSearchRec; var O: SearchRec); { moves information from TSearchRec to SearchRec } begin if F.FindData.cAlternateFileName '' then O.Name := F.FindData.cAlternateFileName else O.Name := F.Name; O.Size := F.Size; O.Attr := F.Attr; O.Time := F.Time; O.FindHandle := F.FindHandle; O.excludeattr := F.ExcludeAttr; end; procedure FindFirst(Path: PathStr; Attr: Word; var F: SearchRec); { revised FindFirst. TP returned volume attribute, so we must handle that first, and return it first } var tempsr: TSearchRec; return_volid: boolean; expf: string; begin DosError := 0; { determine whether to return VolumeID } return_volid := false; if (Attr and VolumeID) = VolumeID then begin expf := ExpandFileName(Path); if Copy(expf, 2, 5) = ':\*.*' then return_volid := true; end; { handle volume ID if it is called for } if return_volid then begin F.name := GetVolName(expf[1] + ':\'); if F.name '' then { if there is a volumeID to return } begin if Length(F.Name) 8 then // format in the way DOS does F.Name := Copy(F.name, 1, 8) + '.' + Copy(F.Name, 9, 20); F.ExcludeAttr := Attr; { save attr } F.Attr := VolumeID; { indicate VolumeID attr } F.FindHandle := INVALID_HANDLE_VALUE; { have not opened FindFirst } F.Path := Path; { store path } end else if Attr = VolumeID then { if we are supposed to only return VolumeID} DosError := 18; end else begin { not supposed to return VolumeID } DosError := SysUtils.FindFirst(Path, Attr, tempsr); Move_SR(tempsr, F); end; end; procedure FindNext(var F: SearchRec); { revised FindNext } var tempsr: TSearchRec; begin { check if FindFirst actually called - i.e. first call was for VolumeID } if F.FindHandle = INVALID_HANDLE_VALUE then begin DosError := SysUtils.FindFirst(F.Path, F.ExcludeAttr, tempsr); F.Path := ''; Move_SR(tempsr, F); end else begin tempsr.FindHandle := F.FindHandle; tempsr.ExcludeAttr := F.ExcludeAttr; DosError := SysUtils.FindNext(tempsr); Move_SR(tempsr, F); if DosError 0 then SysUtils.FindClose(tempsr); end; end; function DiskFree(Drive: Byte): Longint; { TP DOS unit compatible function. Calls the working Diskfree function and then returns a maximum of 2GB. } var DF: Int64; begin DF := DiskFreeEx(Drive); if DF MAXLONGINT then Result := MAXLONGINT else Result := Trunc(DF); end; function DiskSize(Drive: Byte): Longint; { TP DOS unit compatible function. Calls the working DiskSize function and then returns a maximum of 2GB. } var DS: Int64; begin DS := DiskSizeEx(Drive); if DS MAXLONGINT then Result := MAXLONGINT else Result := Trunc(DS); end; function DosVersion: Word; { uses Win32 version in same format as expected in DOS unit, lo byte = major hi byte = minor. Values come from sysutils unit } begin DosVersion := (Win32MinorVersion shl 8) + Win32MajorVersion; end; function FSearch(Path: PathStr; DirList: String): PathStr; { searches for the Path in the Directory List given } begin FSearch := GetShortName(FileSearch(Path, DirList)); end; procedure GetFTime(var F; var Time: Longint); { return file time. Takes file id and packed time } begin doserror := 0; Time := FileGetDate(TFileRec(F).Handle); if Time = -1 then doserror := GetLastError; end; procedure SetFTime(var F; Time: Longint); { Set file time. Takes file id and packed time } begin doserror := 0; FileSetDate(TFileRec(f).Handle, time); doserror := GetLastError; end; function EnvCount: Integer; { returns the number of environment strings. Is resource-intensive, be careful in calling this function } var Env1, Env2: PChar; envi_count: integer; begin envi_count := 0; Env1 := GetEnvironmentStrings; Env2 := Env1; if Env2 nil then repeat inc(Env2, StrLen(Env2) + 1); inc(envi_count); until Env2^ = #0; FreeEnvironmentStrings(Env1); EnvCount := envi_count; end; function EnvStr(Index: Integer): String; { returns an environment string with specific index. Is resource-intensive, be careful in calling this function } var Env1, Env2: PChar; envi_count: integer; begin envi_count := 1; Env1 := GetEnvironmentStrings; Env2 := Env1; if Env2 nil then while (envi_count index) and (Env2^ #0) do begin inc(Env2, StrLen(Env2) + 1); inc(envi_count); end; EnvStr := StrPas(Env2); FreeEnvironmentStrings(Env1); end; function GetEnv(EnvVar: String): String; { gets an environment string with a specific name } var PathName: PChar; Buffer: array[0..255] of char; begin PathName := PChar(EnvVar); GetEnvironmentVariable(PathName, @Buffer, Sizeof(Buffer)); GetEnv := String(Buffer); end; procedure Exec(Path: PathStr; ComLine: ComStr); { executes a program, and waits for completion } var StartInfo : TStartupInfo; ProcInfo : TProcessInformation; CreateOK : Boolean; ErrorCode : DWord; AppDone : DWord; begin ErrorCode := 0; FillChar(StartInfo,SizeOf(TStartupInfo),#0); FillChar(ProcInfo,SizeOf(TProcessInformation),#0); StartInfo.cb := SizeOf(TStartupInfo); CreateOK := Windows.CreateProcess(nil, PChar(String(Path) + ' ' + String(ComLine)), nil, nil, False, CREATE_NEW_PROCESS_GROUP+IDLE_PRIORITY_CLASS+SYNCHRONIZE, nil, nil, StartInfo, ProcInfo); WaitForInputIdle(ProcInfo.hProcess, INFINITE); if CreateOK then repeat AppDone := WaitForSingleObject(ProcInfo.hProcess, 10); ProcessMessage; until AppDone WAIT_TIMEOUT; CloseHandle(ProcInfo.hProcess); CloseHandle(ProcInfo.hThread); GetExitCodeProcess(ProcInfo.hProcess, ErrorCode); DosExitCode := GetLastError; end; procedure GetDate(var Year,Month,Day,DayOfWeek: Word); { returns the system date } var MySystemTime: TSystemTime; begin GetLocalTime(MySystemTime); with MySystemTime do begin Year := wYear; Month := wMonth; Day := wDay; DayOfWeek := wDayOfWeek; end; end; procedure GetTime(var Hour,Minute,Second,Sec100: Word); { returns the system time } var MySystemTime: TSystemTime; begin GetLocalTime(MySystemTime); with MySystemTime do begin Hour := wHour; Minute := wMinute; Second := wSecond; Sec100 := wMilliseconds; end; end; procedure SetDate(Year,Month,Day: Word); { sets the system date } const SE_SYSTEMTIME_NAME = 'SeSystemtimePrivilege'; var MySystemTime: TSystemTime; begin GetLocalTime(MySystemTime); NTSetPrivilege('',SE_SYSTEMTIME_NAME, true); with mysystemtime do begin wYear := Year; wMonth := Month; wDay := Day; end; SetLocalTime(MySystemTime); NTSetPrivilege('',SE_SYSTEMTIME_NAME, false); end; procedure SetTime(Hour,Minute,Second,Sec100: Word); { sets the system time } const SE_SYSTEMTIME_NAME = 'SeSystemtimePrivilege'; var MySystemTime: TSystemTime; begin GetLocalTime(MySystemTime); NTSetPrivilege('',SE_SYSTEMTIME_NAME, true); with mysystemtime do begin wHour := Hour; wMinute := Minute; wSecond := Second; wMilliseconds := Sec100; end; SetLocalTime(MySystemTime); NTSetPrivilege('', SE_SYSTEMTIME_NAME, false); end; { *********************************************************************** do nothing functions follow. These are things that were in the DOS unit, but do not have any applicability to Windows (or were not implemented yet in this unit for some reason) - they are included more for compatibility than functionality *********************************************************************** } procedure GetVerify(var Verify: Boolean); { do nothing function} begin end; procedure Intr(IntNo: Byte; var Regs: Registers); { do nothing function} begin end; procedure Keep(ExitCode: Word); { do nothing function} begin end; procedure MsDos(var Regs: Registers); { do nothing function} begin end; procedure GetCBreak(var Break: Boolean); { do nothing function} begin end; procedure SetCBreak(Break: Boolean); { do nothing function} begin end; procedure GetIntVec(IntNo: Byte; var Vector: Pointer); { do nothing function} begin end; procedure SetIntVec(IntNo: Byte; Vector: Pointer); { do nothing function} begin end; procedure SetVerify(Verify: Boolean); { do nothing function} begin end; procedure SwapVectors; { do nothing function} begin end; end.