home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / vp21beta.zip / ARTLSRC.RAR / VPSYSOS2.PAS < prev    next >
Pascal/Delphi Source File  |  2000-08-15  |  65KB  |  2,414 lines

  1. //█▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀█
  2. //█                                                       █
  3. //█      Virtual Pascal Runtime Library.  Version 2.1.    █
  4. //█      System interface layer OS/2                      █
  5. //█      ─────────────────────────────────────────────────█
  6. //█      Copyright (C) 1995-2000 vpascal.com              █
  7. //█                                                       █
  8. //▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  9.  
  10. // PmWin and PmShApi function prototypes without Os2PmApi
  11.  
  12. // If CHECK_NO_PM is defined, the executable is bigger, the
  13. // program temporarily uses more resources, but does not hang
  14. // if PM-functions like SysClipCanPaste are called in an
  15. // environment without Presentation Manager
  16.  
  17. // By default, we live with this overhead:
  18. {$DEFINE CHECK_NO_PM}
  19.  
  20. type
  21.   HIni                    = LHandle;
  22.   tClipHack               = (clipInit, clipFailed, clipOk);
  23.   tPMInit                 = (pmUntested, pmOK, pmFailed);
  24.  
  25. const
  26.   HIni_UserProfile        = HIni(-1);
  27.   hwnd_Desktop            = HWnd(1);
  28.   mb_Ok                   = 0;
  29.   mb_Information          = $0030;
  30.   mb_CUACritical          = $0040;
  31.   mb_Error                = mb_CUACritical;
  32.   mb_Moveable             = $4000;
  33.   wa_Error                = 2;
  34.   cf_Text                 = 1;
  35.   cfi_Pointer             = $0400;
  36.   SIntl: PChar            = 'PM_National';
  37.  
  38.   // State constants for PM and clipboard hack
  39.   PM_Initialised: tPMInit = pmUntested;
  40.   PM_ClipboardHack: tClipHack = clipInit;
  41.  
  42. const
  43. {&Cdecl+}
  44.   PM_LoadString:            function(AB: Hab; Module: HModule; Id: ULong; MaxLen: Long; Buffer: PChar): Long = nil;
  45.   PM_CreateMsgQueue:        function(AB: Hab; CMsg: Long): Hmq = nil;
  46.   PM_Initialize:            function(Options: ULong): Hab = nil;
  47.   PM_MessageBox:            function(Parent,Owner: HWnd; Text,Caption: PChar; IdWindow,Style: ULong): ULong = nil;
  48.   PM_Alarm:                 function(Desktop: HWnd; rgfType: ULong): Bool = nil;
  49.   PM_PrfQueryProfileString: function(Ini: HIni; App,Key,Default: PChar; Buffer: Pointer; cchBufferMax: ULong): ULong = nil;
  50.   PM_PrfQueryProfileInt:    function(Ini: HIni; App,Key: PChar; Default: Long): Long = nil;
  51.   PM_WinQueryClipbrdFmtInfo:function(AB: Hab; Fmt: ULong; var FmtInfo: ULong): Bool = nil;
  52.   PM_WinOpenClipbrd:        function(AB: Hab): Bool = nil;
  53.   PM_WinCloseClipbrd:       function(AB: Hab): Bool = nil;
  54.   PM_WinSetClipbrdData:     function(AB: Hab; Data,Fmt,rgfFmtInfo: ULong): Bool = nil;
  55.   PM_WinQueryClipbrdData:   function(AB: Hab; Fmt: ULong): ULong = nil;
  56. {&Cdecl-}
  57.   // Module handles
  58.   dll_PMWIN:   HModule = 0;
  59.   dll_PMSHAPI: HModule = 0;
  60.   // Queue and Anchor block handles
  61.   PM_MsgQueue: Hmq = 0;
  62.   PM_Anchor: Hab = 0;
  63.  
  64. { Initialise Win* and Prf* entry points, if Presentation Manager is available }
  65.  
  66. procedure FreePMModules;
  67. begin
  68.   // Free modules
  69.   if dll_PMWIN <> 0 then
  70.     DosFreeModule(dll_PMWIN);
  71.   if dll_PMSHAPI <> 0 then
  72.     DosFreeModule(dll_PMSHAPI);
  73. end;
  74.  
  75. procedure InitPMModules;
  76. {$IFDEF CHECK_NO_PM}
  77. const
  78.   Dos32QuerySysState  : function(func,arg1,pid,_res_:ulong;buf:pointer;bufsz:ulong):apiret cdecl = nil;
  79.   moduleinfo_buf_size = 400000;
  80.   pm_module = 'PMSHELL.EXE'#0;
  81. {$ENDIF CHECK_NO_PM}
  82. var
  83.   FailedModule: array[0..259] of Char;
  84. {$IFDEF CHECK_NO_PM}
  85.   dll_DOSCALLS: HModule;
  86.   moduleinfo_buf: PChar;
  87.   searchpos: word;
  88. {$ENDIF CHECK_NO_PM}
  89. begin
  90.   if PM_Initialised in [pmOK,pmFailed] then
  91.     Exit;
  92.  
  93.   {$IFDEF CHECK_NO_PM}
  94.   // Full-screen session under PM ?
  95.   if (SysCtrlSelfAppType=0) then
  96.     begin
  97.       PM_Initialised:=pmFailed;
  98.       if DosLoadModule(FailedModule, SizeOf(FailedModule), 'DOSCALLS', dll_DOSCALLS) = 0 then
  99.         begin
  100.           // clean process buffer
  101.           GetMem(moduleinfo_buf,moduleinfo_buf_size);
  102.           FillChar(moduleinfo_buf^,moduleinfo_buf_size,0);
  103.  
  104.           // fill process buffer
  105.           if DosQueryProcAddr(dll_DOSCALLS, 368, nil, @Dos32QuerySysState)=0 then
  106.             Dos32QuerySysState(
  107.               $00000004,          // module data
  108.               0,                  // reserved
  109.               0,                  // all processes
  110.               0,                  // reserved
  111.               moduleinfo_buf,
  112.               moduleinfo_buf_size);
  113.  
  114.           // search PMSHELL.EXE
  115.           searchpos:=0;
  116.           while searchpos+Length(pm_module)<moduleinfo_buf_size do
  117.             if StrComp(PChar(@moduleinfo_buf[searchpos]),pm_module)=0 then
  118.               begin
  119.                 PM_Initialised:=pmOK;
  120.                 Break;
  121.               end
  122.             else
  123.               Inc(searchpos);
  124.  
  125.           DosFreeModule(dll_DOSCALLS);
  126.         end;
  127.  
  128.       end;
  129.  
  130.   // Do not hang on boot disk
  131.   if PM_Initialised=pmFailed then
  132.     Exit;
  133.   {$ENDIF CHECK_NO_PM}
  134.  
  135.   if DosLoadModule(FailedModule, SizeOf(FailedModule), 'PMWIN', dll_PMWIN) = 0 then
  136.   begin
  137.     DosQueryProcAddr(dll_PMWIN, 781, nil, @PM_LoadString);
  138.     DosQueryProcAddr(dll_PMWIN, 716, nil, @PM_CreateMsgQueue);
  139.     DosQueryProcAddr(dll_PMWIN, 763, nil, @PM_Initialize);
  140.     DosQueryProcAddr(dll_PMWIN, 789, nil, @PM_MessageBox);
  141.     DosQueryProcAddr(dll_PMWIN, 701, nil, @PM_Alarm);
  142.     DosQueryProcAddr(dll_PMWIN, 807, nil, @PM_WinQueryClipbrdFmtInfo);
  143.     DosQueryProcAddr(dll_PMWIN, 793, nil, @PM_WinOpenClipbrd);
  144.     DosQueryProcAddr(dll_PMWIN, 707, nil, @PM_WinCloseClipbrd);
  145.     DosQueryProcAddr(dll_PMWIN, 854, nil, @PM_WinSetClipbrdData);
  146.     DosQueryProcAddr(dll_PMWIN, 806, nil, @PM_WinQueryClipbrdData);
  147.   end;
  148.   if DosLoadModule(FailedModule, SizeOf(FailedModule), 'PMSHAPI', dll_PMSHAPI) = 0 then
  149.   begin
  150.     DosQueryProcAddr(dll_PMSHAPI, 115, nil, @PM_PrfQueryProfileString);
  151.     DosQueryProcAddr(dll_PMSHAPI, 114, nil, @PM_PrfQueryProfileInt);
  152.   end;
  153.   PM_Initialised := pmOK;
  154.   AddExitProc(FreePMModules);
  155. end;
  156.  
  157. function WinLoadString(AB: Hab; Module: HModule; Id: ULong; MaxLen: Long; Buffer: PChar): Long;
  158. begin
  159.   InitPMModules;
  160.   if Assigned(PM_LoadString) then
  161.     Result := PM_LoadString(AB, Module, Id, MaxLen, Buffer)
  162.   else
  163.     Result := 0;      // Return string length 0
  164. end;
  165.  
  166. function WinCreateMsgQueue(AB: Hab; CMsg: Long): Hmq;
  167. var
  168.   TB: PTIB;
  169.   PB: PPIB;
  170.   org_Pib_ulType: uLong;
  171. begin
  172.   if PM_MsgQueue <> NULLHANDLE then
  173.     Result := PM_MsgQueue
  174.   else
  175.     begin
  176.       InitPMModules;
  177.       if Assigned(PM_CreateMsgQueue) then
  178.         begin
  179.           Result := PM_CreateMsgQueue(AB, CMsg);
  180.           if (Result = NULLHANDLE) and (AB <> 0) and
  181.              (PM_Clipboardhack = clipInit) and IsConsole then
  182.             begin
  183.               // Attempt to force OS/2 into believing we're a PM app
  184.               // so we can create a message queue
  185.               PM_Clipboardhack := clipFailed;
  186.               DosGetInfoBlocks(TB, PB);
  187.  
  188.               // Save program type and override it as PM
  189.               org_Pib_ulType := PB^.Pib_ulType;
  190.               PB^.Pib_ulType := 3;
  191.  
  192.               // Create queue and restore the program type
  193.               Result := PM_CreateMsgQueue(AB, CMsg);
  194.               PB^.Pib_ulType := org_Pib_ulType;
  195.               if Result <> NULLHANDLE then
  196.                 PM_ClipboardHack := clipOK;
  197.             end;
  198.           PM_MsgQueue := Result;
  199.         end
  200.       else
  201.         Result := $1051;  // pmErr_Not_in_a_XSession
  202.     end;
  203. end;
  204.  
  205. function WinInitialize(Options: ULong): Hab;
  206. begin
  207.   Result := PM_Anchor;
  208.   if Result = 0 then
  209.     begin
  210.       InitPMModules;
  211.       if Assigned(PM_Initialize) then
  212.         begin
  213.           Result := PM_Initialize(Options);
  214.           PM_Anchor := Result;
  215.         end
  216.       else
  217.         Result := 0;
  218.     end;
  219. end;
  220.  
  221. function WinMessageBox(Parent,Owner: HWnd; Text,Caption: PChar; IdWindow,Style: ULong): ULong;
  222. begin
  223.   InitPMModules;
  224.   if Assigned(PM_MessageBox) then
  225.     Result := PM_MessageBox(Parent, Owner, Text, Caption, IdWindow, Style)
  226.   else
  227.     Result := $FFFF;   // mbid_Error
  228. end;
  229.  
  230. function WinQueryClipbrdFmtInfo(AB: Hab; Fmt: ULong; var FmtInfo: ULong): Bool;
  231. begin
  232.   InitPMModules;
  233.   if Assigned(PM_WinQueryClipbrdFmtInfo) then
  234.     Result := PM_WinQueryClipbrdFmtInfo(AB, Fmt, FmtInfo)
  235.   else
  236.     Result := False;
  237. end;
  238.  
  239. function WinOpenClipbrd(AB: Hab): Bool;
  240. begin
  241.   InitPMModules;
  242.   if Assigned(PM_WinOpenClipbrd) then
  243.     Result := PM_WinOpenClipbrd(AB)
  244.   else
  245.     Result := False;
  246. end;
  247.  
  248. function WinCloseClipbrd(AB: Hab): Bool;
  249. begin
  250.   InitPMModules;
  251.   if Assigned(PM_WinCloseClipbrd) then
  252.     Result := PM_WinCloseClipbrd(AB)
  253.   else
  254.     Result := False;
  255. end;
  256.  
  257. function WinSetClipbrdData(AB: Hab; Data,Fmt,rgfFmtInfo: ULong): Bool;
  258. begin
  259.   InitPMModules;
  260.   if Assigned(PM_WinSetClipbrdData) then
  261.     Result := PM_WinSetClipbrdData(AB, Data, Fmt, rgfFmtInfo)
  262.   else
  263.     Result := False;
  264. end;
  265.  
  266. function WinQueryClipbrdData(AB: Hab; Fmt: ULong): ULong;
  267. begin
  268.   InitPMModules;
  269.   if Assigned(PM_WinQueryClipbrdData) then
  270.     Result := PM_WinQueryClipbrdData(AB, Fmt)
  271.   else
  272.     Result := 0;
  273. end;
  274.  
  275. function WinAlarm(Desktop: HWnd; rgfType: ULong): Bool;
  276. begin
  277.   InitPMModules;
  278.   if Assigned(PM_Alarm) then
  279.     Result := PM_Alarm(Desktop, rgfType)
  280.   else
  281.     Result := False;
  282. end;
  283.  
  284. function PrfQueryProfileInt(Ini: HIni; App,Key: PChar; Default: Long): Long;
  285. begin
  286.   InitPMModules;
  287.   if Assigned(PM_PrfQueryProfileInt) then
  288.     Result := PM_PrfQueryProfileInt(Ini, App, Key, Default)
  289.   else
  290.     Result := Default;
  291. end;
  292.  
  293. function PrfQueryProfileString(Ini: HIni; App,Key,Default: PChar; Buffer: Pointer; cchBufferMax: ULong): ULong;
  294. begin
  295.   InitPMModules;
  296.   if Assigned(PM_PrfQueryProfileString) then
  297.     Result := PM_PrfQueryProfileString(Ini, App, Key, Default, Buffer, cchBufferMax)
  298.   else
  299.     begin
  300.       StrLCopy(Buffer, Default, cchBufferMax);
  301.       Result := StrLen(Buffer) + 1;
  302.     end;
  303. end;
  304.  
  305. // Other non-Presentation Manager OS/2 functions
  306.  
  307. // Protect parameters of 16 bit functions to wrap around 64KB
  308.  
  309. function Invalid16Parm(const _p: Pointer; const _Length: Longint): Boolean;
  310. begin
  311.   Result := (Longint(_p) and $0000ffff) + _Length >= $00010000;
  312. end;
  313.  
  314. function Fix_64k(const _Memory: Pointer; const _Length: Longint): pointer;
  315. begin
  316.   // Test if memory crosses segment boundary
  317.   if Invalid16Parm(_Memory, _Length) then
  318.     // It does: Choose address in next segment
  319.     Fix_64k := Ptr((Ofs(_memory) and $ffff0000) + $00010000)
  320.   else
  321.     // It doesn't: return original pointer
  322.     Fix_64k := _Memory;
  323. end;
  324.  
  325.  
  326. function SysFileStdIn: Longint;
  327. begin
  328.   Result := 0;
  329. end;
  330.  
  331. function SysFileStdOut: Longint;
  332. begin
  333.   Result := 1;
  334. end;
  335.  
  336. function SysFileStdErr: Longint;
  337. begin
  338.   Result := 2;
  339. end;
  340.  
  341. function SysFileOpen_Create(Open: Boolean;FileName: PChar; Mode,Attr,Action: Longint; var Handle: Longint): Longint;
  342. var
  343.   APIFlags: Longint;
  344.   ActionTaken: Longint;
  345. begin
  346.   APIFlags := 0;
  347.   if Open then
  348.     if Action and open_CreateIfNew <> 0 then
  349.       APIFlags := open_action_create_if_new or open_action_open_if_exists
  350.     else if Action and open_TruncateIfExists <> 0 then
  351.       APIFlags := open_action_fail_if_new or open_action_replace_if_exists
  352.     else
  353.       APIFlags := open_action_open_if_exists or open_action_fail_if_new
  354.   else
  355.     if Action and create_TruncateIfExists <> 0 then
  356.       APIFlags := open_action_create_if_new or open_action_replace_if_exists
  357.     else
  358.       APIFlags := open_action_create_if_new or open_action_fail_if_exists;
  359.  
  360.   if (Mode and $70) = 0 then
  361.     Inc(Mode, open_share_DenyNone);
  362.   Result := DosOpen(FileName, Handle, ActionTaken, 0, 0, APIFlags, Mode, nil);
  363. end;
  364.  
  365. function SysFileOpen(FileName: PChar; Mode: Longint; var Handle: Longint): Longint;
  366. var
  367.   Action: Longint;
  368. begin
  369.   if (Mode and $70) = 0 then
  370.     Inc(Mode, open_share_DenyNone);
  371.   Result := DosOpen(FileName, Handle, Action, 0, 0, file_Open, Mode, nil);
  372. end;
  373.  
  374. function SysFileCreate(FileName: PChar; Mode,Attr: Longint; var Handle: Longint): Longint;
  375. var
  376.   Action: Longint;
  377. begin
  378.   if (Mode and $70) = 0 then
  379.     Inc(Mode, open_share_DenyNone);
  380.   Result := DosOpen(FileName, Handle, Action, 0, Attr, file_Create+file_Truncate, Mode, nil);
  381. end;
  382.  
  383. function SysFileCopy(_Old, _New: PChar; _Overwrite: Boolean): Boolean;
  384. var
  385.   Flag: Longint;
  386. begin
  387.   if _Overwrite then
  388.     Flag := dcpy_existing
  389.   else
  390.     Flag := 0;
  391.   Result := (DosCopy(_Old, _New, Flag)=No_Error);
  392. end;
  393.  
  394. function SysFileSeek(Handle,Distance,Method: Longint; var Actual: Longint): Longint;
  395. begin
  396.   Result := DosSetFilePtr(Handle, Distance, Method, Actual);
  397. end;
  398.  
  399. function SysFileRead(Handle: Longint; var Buffer; Count: Longint; var Actual: Longint): Longint;
  400. begin
  401.   Result := DosRead(Handle, Buffer, Count, Actual);
  402. end;
  403.  
  404. function SysFileWrite(Handle: Longint; const Buffer; Count: Longint; var Actual: Longint): Longint;
  405. begin
  406.   Result := DosWrite(Handle, Buffer, Count, Actual);
  407. end;
  408.  
  409. function SysFileSetSize(Handle,NewSize: Longint): Longint;
  410. begin
  411.   Result := DosSetFileSize(Handle, NewSize);
  412. end;
  413.  
  414. function SysFileClose(Handle: Longint): Longint;
  415. begin
  416.   Result := 0;
  417.   if (Handle > 2) or (Handle < 0) then
  418.     Result := DosClose(Handle);
  419. end;
  420.  
  421. function SysFileFlushBuffers(Handle: Longint): Longint;
  422. begin
  423.   Result := DosResetBuffer(Handle);
  424. end;
  425.  
  426. function SysFileDelete(FileName: PChar): Longint;
  427. begin
  428.   Result := DosDelete(FileName);
  429. end;
  430.  
  431. function SysFileMove(OldName,NewName: PChar): Longint;
  432. begin
  433.   Result := DosMove(OldName, NewName);
  434. end;
  435.  
  436. function SysFileIsDevice(Handle: Longint): Longint;
  437. var
  438.   HandleType,Flags: Longint;
  439. begin
  440.   if DosQueryHType(Handle, HandleType, Flags) <> 0 then
  441.     Result := 0
  442.   else
  443.     Result := HandleType; // 0=File, 1=Character device, 2=Pipe
  444. end;
  445.  
  446. function SysDirGetCurrent(Drive: Longint; Path: PChar): Longint;
  447. var
  448.   P: PChar;
  449.   X: Longint;
  450. begin
  451.   if Drive = 0 then
  452.     DosQueryCurrentDisk(Drive, X);
  453.   P := Path;
  454.   P^ := Chr(Drive + (Ord('A') - 1));
  455.   Inc(P);
  456.   P^ := ':';
  457.   Inc(P);
  458.   P^ := '\';
  459.   Inc(P);
  460.   X := 260 - 4;         // 4: 'D:\', #0
  461.   Result := DosQueryCurrentDir(Drive, P^, X);
  462. end;
  463.  
  464. function SysDirSetCurrent(Path: PChar): Longint;
  465. var
  466.   P: PChar;
  467. begin
  468.   P := Path;
  469.   Result := 0;
  470.   if P^ <> #0 then
  471.   begin
  472.     if P[1] = ':' then
  473.     begin
  474.       Result := DosSetDefaultDisk((Ord(P^) and $DF) - (Ord('A') - 1));
  475.       if Result <> 0 then
  476.         Exit;
  477.       Inc(P, 2);
  478.       if P^ = #0 then         // "D:",0  ?
  479.         Exit;                 // yes, exit
  480.     end;
  481.     Result := DosSetCurrentDir(P);
  482.   end;
  483. end;
  484.  
  485. function SysDirCreate(Path: PChar): Longint;
  486. begin
  487.   Result := DosCreateDir(Path, nil);
  488. end;
  489.  
  490. function SysDirDelete(Path: PChar): Longint;
  491. begin
  492.   Result := DosDeleteDir(Path);
  493. end;
  494.  
  495. // from vputils.pas
  496. Function Min( a,b : Longint ) : Longint; inline;
  497.   begin
  498.     if a < b then
  499.       Min := a
  500.     else
  501.       Min := b;
  502.   end;
  503.  
  504. function SysMemAvail: Longint;
  505. var
  506.   meminfo:
  507.     record
  508.       maxavailmem,
  509.       maxprmem:ULong;
  510.     end;
  511. begin
  512.   //DosQuerySysInfo(qsv_TotAvailMem, qsv_TotAvailMem, Result, SizeOf(Result));
  513.   DosQuerySysInfo(qsv_TotAvailMem, qsv_MaxPrMem, meminfo, SizeOf(meminfo));
  514.   SysMemAvail:=Min(meminfo.maxavailmem,meminfo.maxprmem);
  515. end;
  516.  
  517. function SysMemAlloc(Size,Flags: Longint; var MemPtr: Pointer): Longint;
  518. begin
  519.   Result := DosAllocMem(MemPtr, Size, Flags);
  520. end;
  521.  
  522. function SysMemFree(MemPtr: Pointer): Longint;
  523. begin
  524.   Result := DosFreeMem(MemPtr);
  525. end;
  526.  
  527. function SysSysMsCount: Longint;
  528. begin
  529.   DosQuerySysInfo(qsv_Ms_Count, qsv_Ms_Count, Result, SizeOf(Result));
  530. end;
  531.  
  532. procedure SysSysSelToFlat(var P: Pointer); {&USES ebx} {&FRAME-}
  533. asm
  534.         mov     ebx,P
  535.         mov     eax,[ebx]
  536.         Call    DosSelToFlat
  537.         mov     [ebx],eax
  538. end;
  539.  
  540. procedure SysSysFlatToSel(var P: Pointer); {&USES ebx} {&FRAME-}
  541. asm
  542.         mov     ebx,P
  543.         mov     eax,[ebx]
  544.         Call    DosFlatToSel
  545.         mov     [ebx],eax
  546. end;
  547.  
  548. function SysCtrlSelfAppType: Longint;
  549. var
  550.   TB: PTIB;
  551.   PB: PPIB;
  552. begin
  553.   DosGetInfoBlocks(TB, PB);
  554.   Result := PB^.Pib_ulType;
  555. end;
  556.  
  557. function SysGetThreadId: Longint;
  558. var
  559.   TB: PTIB;
  560.   PB: PPIB;
  561. begin
  562.   DosGetInfoBlocks(TB, PB);
  563.   Result := TB^.tib_ordinal;
  564. end;
  565.  
  566. function SysCtrlCreateThread(Attrs: Pointer; StackSize: Longint; Func,Param: Pointer; Flags: Longint; var Tid: Longint): Longint;
  567. begin
  568.   Result := DosCreateThread(Tid, FnThread(Func), Longint(Param), Flags, StackSize);
  569.   if Result <> 0 then
  570.     Tid := 0;
  571. end;
  572.  
  573. function SysCtrlKillThread(Handle: Longint): Longint;
  574. begin
  575.   Result := DosKillThread(Handle);
  576. end;
  577.  
  578. function SysCtrlSuspendThread(Handle: Longint): Longint;
  579. begin
  580.   Result := DosSuspendThread(Handle);
  581. end;
  582.  
  583. function SysCtrlResumeThread(Handle: Longint): Longint;
  584. begin
  585.   Result := DosResumeThread(Handle);
  586. end;
  587.  
  588. procedure SysCtrlExitThread(ExitCode: Longint);
  589. begin
  590.   DosExit(exit_Thread, ExitCode);
  591. end;
  592.  
  593. procedure SysCtrlExitProcess(ExitCode: Longint);
  594. begin
  595.   DosExit(exit_Process, ExitCode);
  596. end;
  597.  
  598. function SysCtrlGetModuleName(Handle: Longint; Buffer: PChar): Longint;
  599. begin
  600.   Result := DosQueryModuleName(0, 260, Buffer);
  601. end;
  602.  
  603. procedure SysCtrlEnterCritSec;
  604. begin
  605.   DosEnterCritSec;
  606. end;
  607.  
  608. procedure SysCtrlLeaveCritSec;
  609. begin
  610.   DosExitCritSec;
  611. end;
  612.  
  613. function GetParamStr(P: PChar; var Param: String): PChar;
  614. var
  615.   Len: Longint;
  616. begin
  617.   Result := P;
  618.   repeat
  619.     while Result^ in [#1..' '] do
  620.       Inc(Result);
  621.     if PSmallWord(Result)^ = (Ord('"') shl 8 + Ord('"')) then
  622.       Inc(Result, 2)
  623.     else
  624.       Break;
  625.   until False;
  626.   Len := 0;
  627.   while Result^ > ' ' do
  628.     if Result^ = '"' then
  629.       begin
  630.         Inc(Result);
  631.         while not (Result^ in [#0,'"']) do
  632.         begin
  633.           Inc(Len);
  634.           Param[Len] := Result^;
  635.           Inc(Result);
  636.         end;
  637.         if Result^ <> #0 then
  638.           Inc(Result);
  639.       end
  640.     else
  641.       begin
  642.         Inc(Len);
  643.         Param[Len] := Result^;
  644.         Inc(Result);
  645.       end;
  646.   Param[0] := Chr(Len);
  647. end;
  648.  
  649. function SysCmdlnCount: Longint;
  650. var
  651.   P: PChar;
  652.   S: String;
  653. begin
  654.   P := SysCmdln;
  655.   Result := -1;
  656.   repeat
  657.     P := GetParamStr(P, S);
  658.     if S = '' then
  659.     begin
  660.       if Result < 0 then
  661.         Result := 0;
  662.       Exit;
  663.     end;
  664.     Inc(Result);
  665.     if Result = 0 then // Skip the first #0
  666.       Inc(P);
  667.   until False;
  668. end;
  669.  
  670. procedure SysCmdlnParam(Index: Longint; var Param: ShortString);
  671. var
  672.   P: PChar;
  673.   Len: Integer;
  674. begin
  675.   P := SysCmdln;
  676.   if Index = 0 then
  677.     begin
  678.       Len := 0;
  679.       Dec(P, 2);
  680.       while P^ <> #0 do
  681.       begin
  682.         Dec(P);
  683.         Inc(Len);
  684.       end;
  685.       SetString(Param, P + 1, Len);
  686.     end
  687.   else
  688.     begin
  689.       P := GetParamStr(P, Param);
  690.       Inc(P);
  691.       Dec(Index);
  692.       repeat
  693.         P := GetParamStr(P, Param);
  694.         if (Index = 0) or (Param = '') then
  695.           Exit;
  696.         Dec(Index);
  697.       until False;
  698.     end;
  699. end;
  700.  
  701. function SysCmdln: PChar;
  702. var
  703.   TB: PTIB;
  704.   PB: PPIB;
  705. begin
  706.   DosGetInfoBlocks(TB, PB);
  707.   Result := PB^.Pib_pchCmd;
  708. end;
  709.  
  710. function SysCtrlGetTlsMapMem: Pointer;
  711. var
  712.   TB: PTIB;
  713.   PB: PPIB;
  714.   SharedMemName: record
  715.     L0: Longint;
  716.     L1: Longint;
  717.     L2: Longint;
  718.     ID: array[0..11] of Char;
  719.   end;
  720. begin
  721.   DosGetInfoBlocks(TB, PB);
  722.   SharedMemName.L0 := Ord('\') + Ord('S') shl 8 + Ord('H') shl 16 + Ord('A') shl 24;
  723.   SharedMemName.L1 := Ord('R') + Ord('E') shl 8 + Ord('M') shl 16 + Ord('E') shl 24;
  724.   SharedMemName.L2 := Ord('M') + Ord('\') shl 8 + Ord('V') shl 16 + Ord('R') shl 24;
  725.   Str(PB^.Pib_ulPid, SharedMemName.ID);
  726.   if DosGetNamedSharedMem(Result, PChar(@SharedMemName), pag_Read + pag_Write) <> 0 then
  727.   begin
  728.     DosAllocSharedMem(Result, PChar(@SharedMemName), SharedMemSize, pag_Read+pag_Write+pag_Commit);
  729.     FillChar(Result^, SharedMemSize, $FF);
  730.     FillChar(Result^, SizeOf(TSharedMem), 0);
  731.     with PSharedMem(Result)^ do
  732.       begin
  733.         // Set up pointers to functions to use when allocating memory
  734.         TlsMemMgr := System.GetPMemoryManager;
  735.         // Set up pointer to function managing the TlsSemaphore
  736.         TlsSemMgr := @SysSysWaitSem;
  737.         // Initialise the TlsSemaphore
  738.         TlsSemaphore := 0;
  739.       end;
  740.   end;
  741. end;
  742.  
  743. function SysGetEnvironment: PChar;
  744. var
  745.   TB: PTIB;
  746.   PB: PPIB;
  747. begin
  748.   DosGetInfoBlocks(TB, PB);
  749.   Result := PB^.Pib_pchEnv;
  750. end;
  751.  
  752. function SysOsVersion: Longint;
  753. var
  754.   Version: array [0..1] of Longint;
  755. begin
  756.   DosQuerySysInfo(qsv_Version_Major, qsv_Version_Minor, Version, SizeOf(Version));
  757.   Result := Version[0] + Version[1] shl 8;
  758. end;
  759.  
  760. function SysPlatformID: Longint;
  761. begin
  762.   Result := -1; // -1 = OS/2
  763. end;
  764.  
  765. procedure SysGetDateTime(Year,Month,Day,DayOfWeek,Hour,Minute,Second,MSec: PLongint);
  766. var
  767.   DT: Os2Base.DateTime;
  768. begin
  769.   DosGetDateTime(DT);
  770.   if Year <> nil then Year^ := DT.Year;
  771.   if Month <> nil then Month^ := DT.Month;
  772.   if Day <> nil then Day^ := DT.Day;
  773.   if DayOfWeek <> nil then DayOfWeek^ := DT.WeekDay;
  774.   if Hour <> nil then Hour^ := DT.Hours;
  775.   if Minute <> nil then Minute^ := DT.Minutes;
  776.   if Second <> nil then Second^ := DT.Seconds;
  777.   if MSec <> nil then MSec^ := DT.Hundredths*10;
  778. end;
  779.  
  780. procedure SysSetDateTime(Year,Month,Day,Hour,Minute,Second,MSec: PLongint);
  781. var
  782.   DT: Os2Base.DateTime;
  783. begin
  784.   DosGetDateTime(DT);
  785.   if Year <> nil then DT.Year := Year^;
  786.   if Month <> nil then DT.Month := Month^;
  787.   if Day <> nil then DT.Day := Day^;
  788.   if Hour <> nil then DT.Hours := Hour^;
  789.   if Minute <> nil then DT.Minutes := Minute^;
  790.   if Second <> nil then DT.Seconds := Second^;
  791.   if MSec <> nil then DT.Hundredths := MSec^ div 10;
  792.   DosSetDateTime(DT);
  793. end;
  794.  
  795. function SysVerify(SetValue: Boolean; Value: Boolean): Boolean;
  796. var
  797.   Flag: LongBool;
  798. begin
  799.   if SetValue then
  800.     Result := DosSetVerify(Value) = 0
  801.   else
  802.     begin
  803.       DosQueryVerify(Flag);
  804.       Result := Flag;
  805.     end;
  806. end;
  807.  
  808. function SysDiskFreeLong(Drive: Byte): TQuad;
  809. var
  810.   Info: FsAllocate;
  811. begin
  812.   if DosQueryFSInfo(Drive, fsil_Alloc, Info, SizeOf(Info)) = 0 then
  813.     Result := 1.0 * Info.cUnitAvail * Info.cSectorUnit * Info.cbSector
  814.   else
  815.     Result := -1;
  816. end;
  817.  
  818. function SysDiskSizeLong(Drive: Byte): TQuad;
  819. var
  820.   Info: FsAllocate;
  821. begin
  822.   if DosQueryFSInfo(Drive, fsil_Alloc, Info, SizeOf(Info)) = 0 then
  823.     Result := 1.0 * Info.cUnit * Info.cSectorUnit * Info.cbSector
  824.   else
  825.     Result := -1;
  826. end;
  827.  
  828. function SysGetFileAttr(FileName: PChar; var Attr: Longint): Longint;
  829. var
  830.   Info: FileStatus3;
  831. begin
  832.   Attr := 0;
  833.   Result := DosQueryPathInfo(FileName, fil_Standard, Info, SizeOf(Info));
  834.   if Result = 0 then
  835.     Attr := Info.attrFile;
  836. end;
  837.  
  838. function SysSetFileAttr(FileName: PChar; Attr: Longint): Longint;
  839. var
  840.   Info: FileStatus3;
  841. begin
  842.   Result := DosQueryPathInfo(FileName, fil_Standard, Info, SizeOf(Info));
  843.   if Result = 0 then
  844.   begin
  845.     Info.attrFile := Attr;
  846.     Result := DosSetPathInfo(FileName, fil_Standard, Info, SizeOf(Info), dspi_WrtThru);
  847.   end;
  848. end;
  849.  
  850. function SysGetFileTime(Handle: Longint; var Time: Longint): Longint;
  851. var
  852.   Info: FileStatus3;
  853.   FDateTime: TDateTimeRec absolute Time;
  854. begin
  855.   Time := 0;
  856.   Result := DosQueryFileInfo(Handle, fil_Standard, Info, SizeOf(Info));
  857.   if Result = 0 then
  858.     with FDateTime do
  859.     begin
  860.       FTime := Info.ftimeLastWrite;
  861.       FDate := Info.fdateLastWrite;
  862.     end
  863. end;
  864.  
  865. function SysSetFileTime(Handle: Longint; Time: Longint): Longint;
  866. var
  867.   Info: FileStatus3;
  868.   FDateTime: TDateTimeRec absolute Time;
  869. begin
  870.   Result := DosQueryFileInfo(Handle, fil_Standard, Info, SizeOf(Info));
  871.   if Result = 0 then
  872.     with FDateTime do
  873.     begin
  874.       Info.ftimeLastWrite := FTime;
  875.       Info.fdateLastWrite := FDate;
  876.       Result := DosSetFileInfo(Handle, fil_Standard, Info, SizeOf(Info));
  877.     end;
  878. end;
  879.  
  880. function SysFindFirst(Path: PChar; Attr: Longint; var F: TOSSearchRec; IsPChar: Boolean): Longint;
  881. var
  882.   Count: Longint;
  883.   SR: FileFindBuf3;
  884.   Path2: array[0..259] of char;
  885. begin
  886.   Attr := Attr and not $8; // No VolumeID under OS/2
  887.   Count := 1;
  888.   F.Handle := hdir_Create;
  889.   Result := DosFindFirst(Path, F.Handle, Attr, SR, SizeOf(SR), Count, fil_Standard);
  890.  
  891.   // If a specific error occurs, and the call is to look for directories, and
  892.   // the path is a UNC name, then retry
  893.   if (Result = msg_Net_Dev_Type_Invalid) and
  894.      (Hi(Attr) = $10) and
  895.      (StrLen(Path) > Length('\\')) and
  896.      (StrLComp(Path, '\\', Length('\\')) = 0) then
  897.     begin
  898.       DosFindClose(F.Handle);
  899.       StrCat(StrCopy(Path2,Path), '\*.*');
  900.       Result := DosFindFirst(Path2, F.Handle, Attr, SR, SizeOf(SR), Count, fil_Standard);
  901.       if (Result = 0) and (Count <> 0) then
  902.         Result := 0;
  903.     end;
  904.  
  905.   if Result = 0 then
  906.     with F,SR do
  907.     begin
  908.       Attr := attrFile;
  909.       TDateTimeRec(Time).FTime := ftimeLastWrite;
  910.       TDateTimeRec(Time).FDate := fdateLastWrite;
  911.       Size := cbFile;
  912.       if IsPChar then
  913.         StrPCopy(PChar(@Name), achName)
  914.       else
  915.         Name := achName;
  916.     end
  917.   else
  918.     F.Handle := hdir_Create;
  919. end;
  920.  
  921. function SysFindNext(var F: TOSSearchRec; IsPChar: Boolean): Longint;
  922. var
  923.   Count: Longint;
  924.   SR: FileFindBuf3;
  925. begin
  926.   Count := 1;
  927.   Result := DosFindNext(F.Handle, SR, SizeOf(SR), Count);
  928.   if Result = 0 then
  929.     with F,SR do
  930.     begin
  931.       Attr := attrFile;
  932.       TDateTimeRec(Time).FTime := ftimeLastWrite;
  933.       TDateTimeRec(Time).FDate := fdateLastWrite;
  934.       Size := cbFile;
  935.       if IsPChar then
  936.         StrPCopy(PChar(@Name), achName)
  937.       else
  938.         Name := achName;
  939.     end;
  940. end;
  941.  
  942. function SysFindClose(var F: TOSSearchRec): Longint;
  943. begin
  944.   if F.Handle = hdir_Create then
  945.     Result := 0
  946.   else
  947.     Result := DosFindClose(F.Handle);
  948. end;
  949.  
  950. // Check if file exists; if it does, update FileName parameter
  951. // to include correct case of existing file
  952. function SysFileAsOS(FileName: PChar): Boolean;
  953. var
  954.   SRec: TOSSearchRec;
  955.   P: PChar;
  956. begin
  957.   Result := False;
  958.   if SysFindFirst(FileName, $37, SRec, False) = 0 then
  959.     begin
  960.       if SRec.Name[1] <> #0 then
  961.         begin
  962.           // Replace '/' with '\'
  963.           repeat
  964.             P:= StrRScan(FileName, '/');
  965.             if P = nil then Break;
  966.             P[0] := '\';
  967.           until False;
  968.  
  969.           // Replace filename part with data returned by OS
  970.           P := StrRScan(FileName, '\');
  971.           if P = nil then
  972.             P := FileName
  973.           else
  974.             inc(P); // Point to first character of file name
  975.           strPcopy(P, SRec.Name);
  976.         end;
  977.       SysFindClose(SRec );
  978.       Result := True;
  979.     end;
  980. end;
  981.  
  982. function SysFileSearch(Dest,Name,List: PChar): PChar;
  983. var
  984.   Info: FileStatus3;
  985. begin
  986.   if (DosQueryPathInfo(Name, fil_Standard, Info, SizeOf(Info)) = 0)
  987.     and ((Info.attrFile and file_Directory) = 0) then
  988.     SysFileExpand(Dest, Name)
  989.   else
  990.     if DosSearchPath(dsp_ImpliedCur+dsp_IgnoreNetErr,List,Name,Dest,260) <> 0 then Dest[0] := #0;
  991.   Result := Dest;
  992. end;
  993.  
  994. function SysFileExpand(Dest,Name: PChar): PChar;
  995. var
  996.   I,J,L: Integer;
  997.   C: Char;
  998.   CurDir: array[0..259] of Char;
  999.  
  1000.   procedure AdjustPath;
  1001.   begin
  1002.     if (Dest[J-2] = '\') and (Dest[J-1] = '.') then
  1003.       Dec(J,2)
  1004.     else
  1005.       if (j>3) and (Dest[J-3] = '\') and (Dest[J-2] = '.') and (Dest[J-1] = '.') then
  1006.       begin
  1007.         Dec(J, 3);
  1008.         if Dest[J-1] <> ':' then
  1009.         repeat
  1010.           Dec(J);
  1011.         until Dest[J] = '\';
  1012.       end;
  1013.   end;
  1014.  
  1015. begin // SysFileExpand
  1016.   L := StrLen(Name);
  1017.   if (L >= Length('\\')) and (Name[0] = '\') and (Name[1] = '\') then
  1018.     StrCopy(Dest, Name)         // '\\SERVER\DIR'
  1019.   else
  1020.     if (L >= Length('X:')) and (Name[1] = ':') then
  1021.       begin                     // Path is already in form 'X:\Path' or 'X:/Path'
  1022.         if (L >= Length('X:\')) and (Name[2] in ['\','/']) then
  1023.           StrCopy(Dest, Name)
  1024.         else
  1025.           begin                 // Path is in form 'X:Path'
  1026.             SysDirGetCurrent(Ord(UpCase(Name[0])) - (Ord('A') - 1), CurDir);
  1027.             if StrLen(CurDir) > Length('X:\') then
  1028.               StrCat(CurDir, '\');
  1029.             StrLCat(StrCopy(Dest, CurDir), @Name[2], 259);
  1030.           end;
  1031.       end
  1032.     else
  1033.       begin                         // Path is without drive letter
  1034.         SysDirGetCurrent(0, CurDir);// Get default drive & directory
  1035.         if StrLen(CurDir) > Length('X:\') then
  1036.           StrCat(CurDir, '\');
  1037.         if Name[0] in ['\','/'] then
  1038.           StrLCopy(Dest, @CurDir[0], 2) // 'X:' only
  1039.         else
  1040.           StrCopy(Dest, CurDir);
  1041.         StrLCat(Dest, Name, 259);
  1042.       end;
  1043.  
  1044.   J := 0;
  1045.   for I := 0 to StrLen(Dest)-1 do
  1046.     begin
  1047.       C := Dest[I];
  1048.       if C = '/' then
  1049.         begin
  1050.           C := '\';
  1051.           Dest[I] := C;
  1052.         end;
  1053.       if C = '\' then AdjustPath;
  1054.       Dest[J] := C;
  1055.       Inc(J);
  1056.     end;
  1057.   AdjustPath;
  1058.   if Dest[J-1] = ':' then
  1059.   begin
  1060.     Dest[J] := '\';
  1061.     Inc(J);
  1062.   end;
  1063.   Dest[J] := #0;
  1064.   Result := Dest;
  1065. end;
  1066.  
  1067. threadvar
  1068.   ExecResult: ResultCodes;
  1069.   LastAsync:  Boolean;
  1070.  
  1071. function SysExecute(Path,CmdLine,Env: PChar; Async: Boolean; PID: PLongint; StdIn,StdOut,StdErr: Longint): Longint;
  1072. var
  1073.   P,Os2CmdLine: PChar;
  1074.   I,ExecFlags: Longint;
  1075.   FailedObj:  array [0..259] of Char;
  1076.   CmdLineBuf: array [0..1024*8-1] of Char;
  1077.   StdHandles: array[0..2] of Longint;
  1078.   NewHandles: array[0..2] of Longint;
  1079.   OldHandles: array[0..2] of Longint;
  1080. begin
  1081.   StdHandles[0] := StdIn;
  1082.   StdHandles[1] := StdOut;
  1083.   StdHandles[2] := StdErr;
  1084.   LastAsync := Async;
  1085.   ExecFlags := exec_Sync;
  1086.   if Async then
  1087.     ExecFlags := exec_AsyncResult;
  1088.   Os2CmdLine := CmdLineBuf;
  1089.   // Work around a bug in OS/2: Argument to DosExecPgm should not cross 64K boundary
  1090.   if ((Longint(Os2CmdLine) + 1024) and $FFFF) < 1024 then
  1091.     Inc(Os2CmdLine, 1024);
  1092.   P := StrECopy(Os2CmdLine, Path);      // 'Path'#0
  1093.   P := StrECopy(P+1, CmdLine);          // 'Path'#0'CommandLine'#0
  1094.   P[1] := #0;                           // 'Path'#0'CommandLine'#0#0
  1095.   for I := 0 to 2 do
  1096.     if StdHandles[I] <> -1 then
  1097.     begin
  1098.       OldHandles[I] := $FFFFFFFF;       // Save original StdIn to OldIn
  1099.       NewHandles[I] := I;
  1100.       DosDupHandle(NewHandles[I], OldHandles[I]);
  1101.       DosDupHandle(StdHandles[I], NewHandles[I]);
  1102.     end;
  1103.   Result := DosExecPgm(FailedObj, SizeOf(FailedObj), ExecFlags, Os2CmdLine,
  1104.     Env, ExecResult, Path);
  1105.   for I := 0 to 2 do
  1106.     if StdHandles[I] <> -1 then
  1107.     begin
  1108.       DosDupHandle(OldHandles[I], NewHandles[I]);
  1109.       SysFileClose(OldHandles[I]);
  1110.     end;
  1111.   if Async and (PID <> nil) then
  1112.     PID^ := ExecResult.codeTerminate;
  1113. end;
  1114.  
  1115. function SysExitCode: Longint;
  1116. var
  1117.   RetPid: Longint;
  1118. begin
  1119.   if LastAsync then
  1120.     DosWaitChild(dcwa_Process, dcww_Wait, ExecResult, RetPid, ExecResult.codeTerminate);
  1121.   Result := ExecResult.codeResult;
  1122.   if ExecResult.codeTerminate <> tc_Exit then
  1123.     Result := -1;
  1124. end;
  1125.  
  1126. type
  1127.   TCharCaseTable = array[0..255] of Char;
  1128. var
  1129.   UpperCaseTable: TCharCaseTable;
  1130.   LowerCaseTable: TCharCaseTable;
  1131.   AnsiUpperCaseTable: TCharCaseTable;
  1132.   AnsiLowerCaseTable: TCharCaseTable;
  1133.   WeightTable: TCharCaseTable;
  1134. const
  1135.   CaseTablesInitialized: Boolean = False;
  1136.  
  1137. procedure InitCaseTables;
  1138. var
  1139.   I,J: Integer;
  1140. begin
  1141.   for I := 0 to 255 do
  1142.   begin
  1143.     UpperCaseTable[I] := Chr(I);
  1144.     LowerCaseTable[I] := Chr(I);
  1145.     AnsiUpperCaseTable[I] := Chr(I);
  1146.     AnsiLowerCaseTable[I] := Chr(I);
  1147.     if I in [Ord('A')..Ord('Z')] then
  1148.       LowerCaseTable[I] := Chr(I + (Ord('a')-Ord('A')));
  1149.     if I in [Ord('a')..Ord('z')] then
  1150.       UpperCaseTable[I] := Chr(I - (Ord('a')-Ord('A')));
  1151.   end;
  1152.   SysGetCaseMap(SizeOf(AnsiUpperCaseTable), AnsiUpperCaseTable);
  1153.   for I := 0 to 255 do
  1154.   begin
  1155.     J := Ord(AnsiUpperCaseTable[I]);
  1156.     if (J <> I) {and (AnsiLowerCaseTable[J] <> chr(J))} then
  1157.       AnsiLowerCaseTable[J] := Chr(I);
  1158.   end;
  1159.   SysGetWeightTable(SizeOf(WeightTable), WeightTable);
  1160.   CaseTablesInitialized := True;
  1161. end;
  1162.  
  1163. procedure ConvertCase(S1,S2: PChar; Count: Integer; var Table: TCharCaseTable); {&USES esi,edi} {&FRAME-}
  1164. asm
  1165.                 cmp     CaseTablesInitialized,0
  1166.                 jne     @@1
  1167.                 Call    InitCaseTables
  1168.               @@1:
  1169.                 xor     eax,eax
  1170.                 mov     esi,S1
  1171.                 mov     edi,S2
  1172.                 mov     ecx,Count
  1173.                 mov     edx,Table
  1174.                 jecxz   @@3
  1175.               @@2:
  1176.                 dec     ecx
  1177.                 mov     al,[esi+ecx]
  1178.                 mov     al,[edx+eax]
  1179.                 mov     [edi+ecx],al
  1180.                 jnz     @@2
  1181.               @@3:
  1182. end;
  1183.  
  1184. procedure SysChangeCase(Source, Dest: PChar; Len: Longint; NewCase: TCharCase);
  1185. begin
  1186.   case NewCase of
  1187.     ccLower:     ConvertCase(Source, Dest, Len, LowerCaseTable);
  1188.     ccUpper:     ConvertCase(Source, Dest, Len, UpperCaseTable);
  1189.     ccAnsiLower: ConvertCase(Source, Dest, Len, AnsiLowerCaseTable);
  1190.     ccAnsiUpper: ConvertCase(Source, Dest, Len, AnsiUpperCaseTable);
  1191.   end;
  1192. end;
  1193.  
  1194. function SysLowerCase(s: PChar): PChar;
  1195. begin
  1196.   ConvertCase(s, s, strlen(s), AnsiLowerCaseTable);
  1197.   Result := s;
  1198. end;
  1199.  
  1200. function SysUpperCase(s: PChar): PChar;
  1201. begin
  1202.   ConvertCase(s, s, strlen(s), AnsiUpperCaseTable);
  1203.   Result := s;
  1204. end;
  1205.  
  1206. function MemComp(P1,P2: Pointer; L1,L2: Integer; T1,T2: PChar): Integer; {&USES ebx,esi,edi,ebp} {&FRAME-}
  1207. asm
  1208.                 cmp     CaseTablesInitialized,0
  1209.                 jne     @@0
  1210.                 Call    InitCaseTables
  1211.               @@0:
  1212.                 mov     ecx,L1
  1213.                 mov     eax,L2
  1214.                 mov     esi,P1
  1215.                 mov     edi,P2
  1216.                 cmp     ecx,eax
  1217.                 jbe     @@1
  1218.                 mov     ecx,eax
  1219.               @@1:
  1220.                 mov     ebx,T1
  1221.                 mov     ebp,T2
  1222.                 xor     eax,eax
  1223.                 xor     edx,edx
  1224.                 test    ecx,ecx
  1225.                 jz      @@5
  1226.               @@2:
  1227.                 mov     al,[esi]
  1228.                 mov     dl,[edi]
  1229.                 inc     esi
  1230.                 inc     edi
  1231.                 test    ebp,ebp
  1232.                 mov     al,[ebx+eax]    // Table1
  1233.                 mov     dl,[ebx+edx]
  1234.                 jz      @@3
  1235.                 mov     al,[ebp+eax]    // Table2
  1236.                 mov     dl,[ebp+edx]
  1237.               @@3:
  1238.                 cmp     al,dl
  1239.                 jne     @@RET
  1240.                 dec     ecx
  1241.                 jnz     @@2
  1242.               @@5:
  1243.                 mov     eax,L1
  1244.                 mov     edx,L2
  1245.               @@RET:
  1246.                 sub     eax,edx
  1247. end;
  1248.  
  1249. function SysCompareStrings(s1, s2: PChar; l1, l2: Longint; IgnoreCase: Boolean): Longint;
  1250. begin
  1251.   if IgnoreCase then
  1252.     Result := MemComp(s1, s2, l1, l2, @WeightTable, nil)
  1253.   else
  1254.     Result := MemComp(s1, s2, l1, l2, @AnsiUpperCaseTable, @WeightTable);
  1255. end;
  1256.  
  1257. procedure SysGetCaseMap(TblLen: Longint; Tbl: PChar );
  1258. var
  1259.   CC: CountryCode;
  1260. begin
  1261.   CC.Country := 0;  // Use default
  1262.   CC.CodePage := 0;
  1263.   DosMapCase(TblLen, CC, Tbl);
  1264. end;
  1265.  
  1266. procedure SysGetWeightTable(TblLen: Longint; WeightTable: PChar);
  1267. var
  1268.   CC: CountryCode;
  1269.   DataLen: Longint;
  1270. begin
  1271.   CC.Country := 0;  // Use default
  1272.   CC.CodePage := 0;
  1273.   DosQueryCollate(TblLen, CC, WeightTable, DataLen);
  1274. end;
  1275.  
  1276. function SysGetCodePage: Longint;
  1277. var
  1278.   Returned: Longint;
  1279.   CC: CountryCode;
  1280.   CI: CountryInfo;
  1281. begin
  1282.   Result := 0;
  1283.   DosQueryCp(SizeOf(Result), Result, Returned);
  1284.   if Result = 0 then
  1285.   begin
  1286.     CC.Country := 0;
  1287.     CC.CodePage := 0;
  1288.     DosQueryCtryInfo(SizeOf(CountryInfo), CC, CI, Returned);
  1289.     Result := CI.CodePage;
  1290.   end;
  1291. end;
  1292.  
  1293. var
  1294.   PrevXcptProc: Pointer;
  1295.  
  1296. function SignalHandler(Report:       PExceptionReportRecord;
  1297.                        Registration: PExceptionRegistrationRecord;
  1298.                        Context:      PContextRecord;
  1299.                        P:            Pointer): Longint; cdecl;
  1300. begin
  1301.   Result := xcpt_Continue_Search;
  1302.   if Report^.ExceptionNum = xcpt_Signal then
  1303.     case Report^.ExceptionInfo[0] of
  1304.       xcpt_Signal_Intr,xcpt_Signal_Break:
  1305.        if Assigned(CtrlBreakHandler) and CtrlBreakHandler then
  1306.          Result := xcpt_Continue_Execution
  1307.     end;
  1308.   XcptProc := PrevXcptProc;
  1309. end;
  1310.  
  1311. procedure SysCtrlSetCBreakHandler;
  1312. var
  1313.   Times: Longint;
  1314. begin
  1315.   DosSetSignalExceptionFocus(True, Times);
  1316.   XcptProc := @SignalHandler;
  1317. end;
  1318.  
  1319. function SysFileIncHandleCount(Count: Longint): Longint;
  1320. var
  1321.   hDelta,hMax: Longint;
  1322. begin
  1323.   hDelta := Count;
  1324.   Result := DosSetRelMaxFH(hDelta, hMax);
  1325. end;
  1326.  
  1327. const
  1328.   CrtScanCode: Byte = 0;
  1329.  
  1330. function SysKeyPressed: Boolean;
  1331. var
  1332.   Key  : ^KbdKeyInfo;
  1333.   LKey : Array[1..2] of KbdKeyInfo;
  1334. begin
  1335.   Key := Fix_64k(@LKey, SizeOf(Key^));
  1336.   KbdPeek(Key^, 0);
  1337.   Result := (CrtScanCode <> 0) or ((Key^.fbStatus and kbdtrf_Final_Char_In) <> 0);
  1338. end;
  1339.  
  1340. procedure SysFlushKeyBuf;
  1341. begin
  1342.   CrtScanCode := 0;
  1343. end;
  1344.  
  1345. function SysPeekKey(Var Ch:Char):boolean;
  1346. Var
  1347.   ChData  : ^KbdKeyInfo;
  1348.   LChData : Array[1..2] of KbdKeyInfo;
  1349. begin
  1350.   ChData := Fix_64k(@LChData, SizeOf(ChData^));
  1351.   KbdPeek( ChData^, 0 );
  1352.   If ChData^.fbStatus and kbdtrf_Final_Char_In <> 0 then
  1353.     begin
  1354.       Ch := ChData^.ChChar;
  1355.       Result := True;
  1356.     end
  1357.   else
  1358.     Result := False;
  1359. end;
  1360.  
  1361. function SysReadKey: Char;
  1362. var
  1363.   Key  : ^KbdKeyInfo;
  1364.   LKey : Array[1..2] of KbdKeyInfo;
  1365. begin
  1366.   If CrtScanCode <> 0 then
  1367.     begin
  1368.       result:=Chr(CrtScanCode);
  1369.       CrtScanCode:=0;
  1370.     end
  1371.   else
  1372.     begin
  1373.       Key := Fix_64k(@LKey, SizeOf(Key^));
  1374.       KbdCharIn(Key^, io_Wait, 0);
  1375.       case Key^.chChar of
  1376.         #0: CrtScanCode := Key^.chScan;
  1377.         #$E0:           {   Up, Dn, Left Rt Ins Del Home End PgUp PgDn C-Home C-End C-PgUp C-PgDn C-Left C-Right C-Up C-Dn }
  1378.           if Key^.chScan in [$48,$50,$4B,$4D,$52,$53,$47, $4F,$49, $51, $77,   $75,  $84,   $76,   $73,   $74,    $8D, $91] then
  1379.           begin
  1380.             CrtScanCode := Key.chScan;
  1381.             Key^.chChar := #0;
  1382.           end;
  1383.       end;
  1384.       result:=Key^.chChar;
  1385.     end;
  1386. end;
  1387.  
  1388. procedure SysGetCurPos(var X, Y: SmallWord);
  1389. begin
  1390.   VioGetCurPos(Y, X, TVVioHandle);
  1391. end;
  1392.  
  1393. procedure SysSetCurPos(X,Y: SmallWord);
  1394. begin
  1395.   VioSetCurPos(Y, X, TVVioHandle);
  1396. end;
  1397.  
  1398. procedure SysWrtCharStrAtt(CharStr: Pointer; Len,X,Y: SmallWord; var Attr: Byte);
  1399. var
  1400.   pGood: Pointer;
  1401.   pTemp: Pointer;
  1402. begin
  1403.   if Invalid16Parm(CharStr, Len) then
  1404.     begin
  1405.       GetMem(pTemp, 2*Len);
  1406.       pGood := Fix_64k(pTemp, Len);
  1407.       Move(CharStr^, pGood^, Len);
  1408.       VioWrtCharStrAtt(pGood, Len, Y, X, Attr, TVVioHandle);
  1409.       FreeMem(pTemp);
  1410.     end
  1411.   else
  1412.     VioWrtCharStrAtt(CharStr, Len, Y, X, Attr, TVVioHandle);
  1413. end;
  1414.  
  1415. function SysReadAttributesAt(x,y: SmallWord): Byte;
  1416. var
  1417.   Cell, Size: SmallWord;
  1418. begin
  1419.   Size := Sizeof(Cell);
  1420.   VioReadCellStr(Cell, Size, y, x, 0);
  1421.   Result := Hi(Cell); // and $7f;
  1422. end;
  1423.  
  1424. function SysReadCharAt(x,y: SmallWord): Char;
  1425. var
  1426.   Cell, Size: SmallWord;
  1427. begin
  1428.   Size := Sizeof(Cell);
  1429.   if VioReadCellStr(Cell, Size, y, x, 0) = 0 then
  1430.     Result := chr(Lo(Cell))
  1431.   else
  1432.     Result := #0;
  1433. end;
  1434.  
  1435. procedure SysScrollUp(X1,Y1,X2,Y2,Lines,Cell: SmallWord);
  1436. begin
  1437.   VioScrollUp(Y1, X1, Y2, X2, Lines, Cell, TVVioHandle);
  1438. end;
  1439.  
  1440. procedure SysScrollDn(X1, Y1, X2, Y2, Lines, Cell: SmallWord );
  1441. begin
  1442.   VioScrollDn(Y1, X1, Y2, X2, Lines, Cell, TVVioHandle);
  1443. end;
  1444.  
  1445. const
  1446.   MouseHandle: SmallWord = $FFFF;
  1447. var
  1448.   ProtectArea: NoPtrRect;
  1449.   MouseEventMask: SmallWord;
  1450.   MouseMSec: Longint;
  1451.   ButtonCount: Longint;
  1452.  
  1453. function SysTVDetectMouse: Longint;
  1454. var
  1455.   MouLoc: PtrLoc;
  1456.   Buttons: SmallWord;
  1457. begin
  1458.   if MouOpen(nil, MouseHandle) = 0 then
  1459.     begin
  1460.       MouGetNumButtons(Buttons, MouseHandle);
  1461.       ButtonCount := Buttons;
  1462. {$IFNDEF NoMouseMove}
  1463.       MouLoc.Row := 0;
  1464.       MouLoc.Col := 0;
  1465.       MouSetPtrPos(MouLoc, MouseHandle);
  1466. {$ENDIF}
  1467.       Result := Buttons;
  1468.     end
  1469.   else
  1470.     Result := 0;
  1471. end;
  1472.  
  1473. procedure SysTVInitMouse(var X,Y: Integer);
  1474. var
  1475.   MouLoc: PtrLoc;
  1476.   EventMask: SmallWord;
  1477. begin
  1478.   if MouseHandle <> $FFFF then
  1479.   begin
  1480.     MouGetPtrPos(MouLoc, MouseHandle);
  1481.     X := MouLoc.Col;
  1482.     Y := MouLoc.Row;
  1483.     MouDrawPtr(MouseHandle);
  1484.     MouGetEventMask(MouseEventMask, MouseHandle);
  1485.     EventMask := $FFFF;
  1486.     MouSetEventMask(EventMask, MouseHandle);  // Select all events
  1487.   end;
  1488. end;
  1489.  
  1490. procedure SysTVDoneMouse(Close: Boolean);
  1491. begin
  1492.   if MouseHandle <> $FFFF then
  1493.   begin
  1494.     if Close then
  1495.       MouClose(MouseHandle)
  1496.     else
  1497.       begin
  1498.         SysTVHideMouse; // Restore events to original state
  1499.         MouSetEventMask(MouseEventMask, MouseHandle);
  1500.       end;
  1501.   end;
  1502. end;
  1503.  
  1504. procedure SysTVShowMouse;
  1505. begin
  1506.   if MouseHandle <> $FFFF then
  1507.     MouDrawPtr(MouseHandle);
  1508. end;
  1509.  
  1510. procedure SysTVHideMouse;
  1511. begin
  1512.   // Assume that ProtectArea does not wrap around segment boundary
  1513.   if MouseHandle <> $FFFF then
  1514.     MouRemovePtr(ProtectArea, MouseHandle);
  1515. end;
  1516.  
  1517. procedure SysTVUpdateMouseWhere(var X,Y: Integer);
  1518. var
  1519.   MouLoc: PtrLoc;
  1520.   MSec: Longint;
  1521. begin
  1522.   MSec := SysSysMsCount;
  1523.   if MSec - MouseMSec >= 5 then
  1524.   begin
  1525.     MouseMSec := MSec;
  1526.     MouGetPtrPos(MouLoc, MouseHandle);
  1527.     X := MouLoc.Col;
  1528.     Y := MouLoc.Row;
  1529.   end;
  1530. end;
  1531.  
  1532. function SysTVGetMouseEvent(var Event: TSysMouseEvent): Boolean;
  1533. var
  1534.   MouEvent  : ^MouEventInfo;
  1535.   MouQInfo  : ^MouQueInfo;
  1536.   LMouEvent : Array[1..2] of MouEventInfo;
  1537.   LMouQInfo : Array[1..2] of MouQueInfo;
  1538. const
  1539.   WaitFlag: SmallWord = mou_NoWait;
  1540. begin
  1541.   MouQInfo := Fix_64k(@LMouQInfo, SizeOf(MouQInfo^));
  1542.  
  1543.   MouGetNumQueEl(MouQInfo^, MouseHandle);
  1544.   if MouQinfo^.cEvents = 0 then
  1545.     Result := False
  1546.   else
  1547.     begin
  1548.       MouEvent := Fix_64k(@LMouEvent, SizeOf(MouEvent^));
  1549.       MouReadEventQue(MouEvent^, WaitFlag, MouseHandle);
  1550.       with Event do
  1551.         begin
  1552.           smeTime := MouEvent^.Time;
  1553.           MouseMSec := MouEvent^.Time;
  1554.           smeButtons := 0;
  1555.           if (MouEvent^.fs and (mouse_Motion_With_Bn1_Down or mouse_Bn1_Down)) <> 0 then
  1556.             Inc(smeButtons, $0001);
  1557.           if (MouEvent^.fs and (mouse_Motion_With_Bn2_Down or mouse_Bn2_Down)) <> 0 then
  1558.             Inc(smeButtons, $0002);
  1559.           smePos.X := MouEvent^.Col;
  1560.           smePos.Y := MouEvent^.Row;
  1561.         end;
  1562.       Result := True;
  1563.     end;
  1564. end;
  1565.  
  1566. procedure SysTVKbdInit;
  1567. var
  1568.   Key  : ^KbdInfo;
  1569.   LKey : Array[1..2] of KbdInfo;
  1570.  
  1571. begin
  1572.   Key := Fix_64k(@LKey, SizeOf(Key^));
  1573.   Key^.cb := SizeOf(KbdInfo);
  1574.   KbdGetStatus(Key^, 0);        { Disable ASCII & Enable raw (binary) mode}
  1575.   Key^.fsMask := (Key^.fsMask and (not keyboard_Ascii_Mode)) or keyboard_Binary_Mode;
  1576.   KbdSetStatus(Key^, 0);
  1577. end;
  1578.  
  1579. function SysTVGetPeekKeyEvent(var Event: TSysKeyEvent; _Peek: Boolean): Boolean;
  1580. var
  1581.   Key  : ^KbdKeyInfo;
  1582.   LKey : Array[1..2] of KbdKeyInfo;
  1583. begin
  1584.   Key := Fix_64k(@LKey, SizeOf(Key^));
  1585.   if _Peek then
  1586.     KbdPeek(Key^, 0)
  1587.   else
  1588.     KbdCharIn(Key^, io_NoWait, 0);
  1589.   if (Key^.fbStatus and kbdtrf_Final_Char_In) = 0 then
  1590.     Result := False
  1591.   else
  1592.     with Event do   // Key is ready
  1593.       begin
  1594.         skeKeyCode := Ord(Key^.chChar) + Key^.chScan shl 8;
  1595.         skeShiftState := Lo(Key^.fsState);
  1596.         Result := True;
  1597.       end;
  1598. end;
  1599.  
  1600. function SysTVGetKeyEvent(var Event: TSysKeyEvent): Boolean;
  1601. begin
  1602.   Result := SysTVGetPeekKeyEvent(Event, False);
  1603. end;
  1604.  
  1605. function SysTVPeekKeyEvent(var Event: TSysKeyEvent): Boolean;
  1606. begin
  1607.   Result := SysTVGetPeekKeyEvent(Event, True);
  1608. end;
  1609.  
  1610. function SysTVGetShiftState: Byte;
  1611. var
  1612.   Key  : ^KbdInfo;
  1613.   LKey : Array[1..2] of KbdInfo;
  1614.  
  1615. begin
  1616.   Key := Fix_64k(@LKey, SizeOf(Key^));
  1617.   Key^.cb := SizeOf(KbdInfo);
  1618.   KbdGetStatus(Key^, 0);
  1619.   Result := Lo(Key^.fsState);
  1620. end;
  1621.  
  1622. procedure SysTVSetCurPos(X,Y: Integer);
  1623. begin
  1624.   VioSetCurPos(Y, X, TVVioHandle);
  1625. end;
  1626.  
  1627. procedure SysTVSetCurType(Y1,Y2: Integer; Show: Boolean);
  1628. var
  1629.   CurData  : ^VioCursorInfo;
  1630.   LCurData : Array[1..2] of VioCursorInfo;
  1631. begin
  1632.   CurData := Fix_64k(@LCurData, SizeOf(CurData^));
  1633.   with CurData^ do
  1634.     begin
  1635.       yStart := Y1;
  1636.       cEnd   := Y2;
  1637.       cx := 1;
  1638.       if Show then
  1639.         attr := 0
  1640.       else
  1641.         begin
  1642.           attr := $FFFF;
  1643.           yStart := 0;
  1644.           cEnd := 1;
  1645.         end;
  1646.     end;
  1647.   VioSetCurType(CurData^, TVVioHandle);
  1648. end;
  1649.  
  1650. procedure SysTVGetCurType(var Y1,Y2: Integer; var Visible: Boolean);
  1651. var
  1652.   CurData  : ^VioCursorInfo;
  1653.   LCurData : Array[1..2] of VioCursorInfo;
  1654. begin
  1655.   CurData := Fix_64k(@LCurData, SizeOf(CurData^));
  1656.   VioGetCurType(CurData^, TVVioHandle);
  1657.   Visible := CurData^.attr <> $FFFF;
  1658.   Y1 := CurData^.yStart;
  1659.   Y2 := CurData^.cEnd;
  1660. end;
  1661.  
  1662. procedure SysTVShowBuf(Pos,Size: Integer);
  1663. begin
  1664.   VioShowBuf(Pos, Size, TVVioHandle);
  1665. end;
  1666.  
  1667. procedure SysTVClrScr;
  1668. const
  1669.   Cell: SmallWord = $0720;      // Space character, white on black
  1670. begin
  1671.   VioScrollUp(0, 0, 65535, 65535, 65535, Cell, TVVioHandle);
  1672.   SysTVSetCurPos(0, 0);
  1673. end;
  1674.  
  1675. procedure SetMouseArea(X,Y: Integer);
  1676. begin
  1677.   ProtectArea.Row := 0;
  1678.   ProtectArea.Col := 0;
  1679.   ProtectArea.cRow := Y - 1;
  1680.   ProtectArea.cCol := X - 1;
  1681. end;
  1682.  
  1683. function SysTVGetScrMode(Size: PSysPoint): Integer;
  1684. var
  1685.   VioMode  : ^VioModeInfo;
  1686.   LVioMode : Array[1..2] of VioModeInfo;
  1687. begin
  1688.   VioMode := Fix_64k(@LVioMode, SizeOf(VioMode^));
  1689.   VioMode^.cb := SizeOf(VioMode^);
  1690.   if VioGetMode(VioMode^, TVVioHandle) <> 0 then
  1691.     Result := $FF   // smNonStandard
  1692.   else
  1693.     begin
  1694.       with VioMode^ do
  1695.         begin
  1696.           if (fbType and vgmt_DisableBurst) = 0 then
  1697.             Result := 3   // smCO80
  1698.           else
  1699.             Result := 2;  // smBW80;
  1700.           if Color = 0 then
  1701.             Result := 7;  // smMono
  1702.           case Row of
  1703.             25: ;
  1704.             43,50: Inc(Result, $0100); // smFont8x8
  1705.             else   Result := $FF; // smNonStandard
  1706.           end;
  1707.           if (VioMode^.fbType and vgmt_Graphics) <> 0 then
  1708.             Result := 0;
  1709.         end;
  1710.     SetMouseArea(VioMode^.Col, VioMode^.Row);
  1711.     if Size <> nil then
  1712.       with Size^ do
  1713.         begin
  1714.           X := VioMode^.Col;
  1715.           Y := VioMode^.Row;
  1716.         end;
  1717.   end;
  1718. end;
  1719.  
  1720. procedure SysTVSetScrMode(Mode: Integer);
  1721. var
  1722.   BiosMode     : Byte;
  1723.   VioMode      : ^VioModeInfo;
  1724.   VideoConfig  : ^VioConfigInfo;
  1725.   LVioMode     : Array[1..2] of VioModeInfo;
  1726.   LVideoConfig : Array[1..2] of VioConfigInfo;
  1727. begin
  1728.   VioMode := Fix_64k(@LVioMode, SizeOf(VioMode^));
  1729.   VideoConfig := Fix_64k(@LVideoConfig, SizeOf(VideoConfig^));
  1730.  
  1731.   BiosMode := Lo(Mode);
  1732.   VideoConfig^.cb := SizeOf(VideoConfig^);
  1733.   VioGetConfig(0, VideoConfig^, TVVioHandle);
  1734.  
  1735.   with VioMode^ do
  1736.     begin
  1737.       // Indicate that we only filled important Entrys
  1738.       // the Video handler will find the best values itself
  1739.       cb := Ofs(HRes) - Ofs(cb);
  1740.  
  1741.       case Lo(Mode) of
  1742.         0, 2: fbType := vgmt_Other + vgmt_DisableBurst;
  1743.            7: fbType := 0;
  1744.       else
  1745.         fbType := vgmt_Other;
  1746.       end;
  1747.  
  1748.       if Lo(Mode) = 7 then
  1749.         Color := 0
  1750.       else
  1751.         Color := colors_16;         // Color
  1752.  
  1753.       Row := 25;
  1754.  
  1755.       if lo(Mode) < 2 then
  1756.         Col := 40
  1757.       else
  1758.         Col := 80;
  1759.  
  1760.       case VideoConfig^.Adapter of
  1761.         display_Monochrome..display_CGA: ; // only 25 Lines
  1762.         display_EGA:
  1763.           if hi(mode) = 1 then             // font 8x8
  1764.             Row := 43;                     // 350/8=43
  1765.       else // VGA
  1766.         if hi(mode) = 1 then               // font 8x8
  1767.           Row := 50;                       // 400/8=25
  1768.       end;
  1769.     end;
  1770.  
  1771.   SetMouseArea(VioMode^.Col, VioMode^.Row);
  1772.   VioSetMode(VioMode^, TVVioHandle);
  1773. end;
  1774.  
  1775. function SysTVGetSrcBuf: Pointer;
  1776. var
  1777.   BufSize: SmallWord;
  1778. begin
  1779.   VioGetBuf(Result, BufSize, TVVioHandle);
  1780.   SelToFlat(Result);
  1781. end;
  1782.  
  1783. procedure SysTVInitCursor;
  1784. var
  1785.   Font  : ^VioFontInfo;
  1786.   LFont : Array[1..2] of VioFontInfo;
  1787. begin
  1788.   Font := Fix_64k(@LFont, SizeOf(Font^));
  1789.  
  1790.   FillChar(Font^, SizeOf(Font^), 0);
  1791.   Font^.cb := SizeOf(VioFontInfo);
  1792.   Font^.rType := vgfi_GetCurFont;
  1793.   // Set underline cursor to avoid cursor shape problems
  1794.   if VioGetFont(Font^, TVVioHandle) = 0 then
  1795.     SysTVSetCurType(Font^.cyCell - 2, Font^.cyCell - 1, True);
  1796. end;
  1797.  
  1798. procedure SysCtrlSleep(Delay: Integer);
  1799. begin
  1800.   DosSleep(Delay);
  1801. end;
  1802.  
  1803. function SysGetValidDrives: Longint;
  1804. var
  1805.   CurDrive: Longint;
  1806. begin
  1807.   if DosQueryCurrentDisk(CurDrive, Result) <> 0 then
  1808.     Result := 0;
  1809. end;
  1810.  
  1811. procedure SysDisableHardErrors;
  1812. begin
  1813.   DosError(ferr_DisableHardErr);
  1814. end;
  1815.  
  1816. function SysKillProcess(Process: Longint): Longint;
  1817. begin
  1818.   Result := DosKillProcess(dkp_ProcessTree, Process);
  1819. end;
  1820.  
  1821. function SysAllocSharedMem(Size: Longint; var MemPtr: Pointer): Longint;
  1822. begin
  1823.   Result := DosAllocSharedMem(MemPtr, nil, Size, obj_Giveable + pag_Read + pag_Write + pag_Commit);
  1824. end;
  1825.  
  1826. function SysGiveSharedMem(MemPtr: Pointer): Longint;
  1827. var
  1828.   PB: PPIB;
  1829.   TB: PTIB;
  1830. begin
  1831.   DosGetInfoBlocks(TB, PB);
  1832.   Result := DosGiveSharedMem(MemPtr, PB^.Pib_ulPPid, pag_Read + pag_Write);
  1833. end;
  1834.  
  1835. function SysPipeCreate(var ReadHandle,WriteHandle: Longint; Size: Longint): Longint;
  1836. var
  1837.   PipeName: array[0..259] of Char;
  1838.   Number: array[0..10] of Char;
  1839. begin
  1840.   StrCopy(PipeName, '\PIPE\');
  1841.   Str(SysSysMsCount, Number);
  1842.   StrCopy(@PipeName[6], Number);
  1843.   Result := DosCreateNPipe(PipeName, ReadHandle, np_Access_InBound, np_NoWait + 1, 0, Size, 0);
  1844.   DosConnectNPipe(ReadHandle);
  1845.   SysFileOpen(PipeName, $41, WriteHandle);
  1846. end;
  1847.  
  1848. function SysPipePeek(Pipe: Longint; Buffer: Pointer; BufSize: Longint; var BytesRead: Longint; var IsClosing: Boolean): Longint;
  1849. var
  1850.   State: Longint;
  1851.   Avail: AvailData;
  1852. begin
  1853.   Result := DosPeekNPipe(Pipe, Buffer^, BufSize, BytesRead, Avail, State);
  1854.   IsClosing := State = np_State_Closing;
  1855. end;
  1856.  
  1857. function SysPipeClose(Pipe: Longint): Longint;
  1858. begin
  1859.   Result := SysFileClose(Pipe);
  1860. end;
  1861.  
  1862. function SysLoadResourceString(ID: Longint; Buffer: PChar; BufSize: Longint): PChar;
  1863. begin
  1864.   Buffer[0] := #0;
  1865.   WinLoadString(0, 0, ID, BufSize, Buffer);
  1866.   Result:=Buffer;
  1867. end;
  1868.  
  1869. function SysFileUNCExpand(Dest,Name: PChar): PChar;
  1870. var
  1871.   P: PChar;
  1872.   Len: Longint;
  1873.   pfsqb: pfsqBuffer2;
  1874.   DevName: array[0..2] of Char;
  1875.   Drive: String;
  1876. begin
  1877.   SysFileExpand(Dest, Name);
  1878.   if (UpCase(Dest[0]) in ['A'..'Z']) and (Dest[1] = ':') and (Dest[2] = '\') then
  1879.   begin
  1880.     DevName[0] := Dest[0];
  1881.     DevName[1] := ':';
  1882.     DevName[2] := #0;
  1883.     Len := 1024;
  1884.     GetMem(pfsqb, Len);
  1885.     FillChar(pfsqb^, Len, 0);
  1886.     DosQueryFSAttach(DevName, 1, fsail_QueryName, pfsqb, Len);
  1887.     P := pfsqb^.szName;         // Points to name of entry
  1888.     P := P + StrLen(P) + 1;     // Points to name of FS (LAN, NETWARE, etc)
  1889.     P := P + StrLen(P) + 1;     // Points to UNC name
  1890.     if P^ <> #0 then
  1891.     begin
  1892.       Len := StrLen(P);
  1893.       StrCopy(@Dest[Len], @Dest[2]);
  1894.       Move(P^, Dest^, Len);
  1895.     end;
  1896.     FreeMem(pfsqb);
  1897.   end;
  1898.   Result := Dest;
  1899. end;
  1900.  
  1901. function SysGetSystemError(Code: Longint; Buffer: PChar; BufSize: Longint; var MsgLen: Longint): PChar;
  1902. begin
  1903.   Result := Buffer;
  1904.   if DosGetMessage(nil, 0, Buffer, BufSize-1, Code, 'OSO001.MSG', MsgLen) <> 0 then
  1905.     MsgLen := 0;
  1906. end;
  1907.  
  1908. function SysGetProfileStr(Section,Entry,Default,Dest: PChar): PChar;
  1909. begin
  1910.   Dest[0] := #0;
  1911.   PrfQueryProfileString(hini_UserProfile, Section, Entry, Default, Dest, 260);
  1912.   result:=Dest;
  1913. end;
  1914.  
  1915. function SysGetProfileChar(Section, Entry: PChar; Default: Char): Char;
  1916. var
  1917.   CDefault, Buffer: array[0..1] of Char;
  1918. begin
  1919.   CDefault[0] := Default;
  1920.   CDefault[1] := #0;
  1921.   PrfQueryProfileString(hini_UserProfile, Section, Entry, CDefault, @Buffer, SizeOf(Buffer));
  1922.   Result := Buffer[0];
  1923. end;
  1924.  
  1925. procedure SysGetCurrencyFormat(CString: PChar; var CFormat, CNegFormat, CDecimals: Byte; var CThousandSep, CDecimalSep: Char);
  1926. begin
  1927.   SysGetProfileStr(SIntl, 'sCurrency', '', CString);
  1928.   CFormat := PrfQueryProfileInt(hini_UserProfile, SIntl, 'iCurrency', 0);
  1929.   CNegFormat := 0;                   { N/A under PM }
  1930.   CThousandSep := SysGetProfileChar(SIntl, 'sThousand', ',');
  1931.   CDecimalSep := SysGetProfileChar(SIntl, 'sDecimal', '.');
  1932.   CDecimals := PrfQueryProfileInt(hini_UserProfile, SIntl, 'iDigits', 2);
  1933. end;
  1934.  
  1935. procedure SysGetDateFormat(var DateSeparator: Char; ShortDateFormat,LongDateFormat: PChar);
  1936. var
  1937.   Date: Integer;
  1938. const
  1939.   DateStr: array [0..2] of PChar =
  1940.     ( 'mm/dd/yy', 'dd/mm/yy', 'yy/mm/dd' );
  1941.   LongDateStr: array [0..2] of PChar =
  1942.     ('mmmm d, yyyy', 'dd mmmm yyyy', 'yyyy mmmm d');
  1943. begin
  1944.   DateSeparator := SysGetProfileChar(SIntl, 'sDate', '/');
  1945.   Date := PrfQueryProfileInt(hini_UserProfile, SIntl, 'iDate', 0);
  1946.   if Date > 2 then
  1947.     Date := 0;
  1948.   StrCopy(ShortDateFormat, DateStr[Date]);   // No exact equivalent under PM
  1949.   StrCopy(LongDateFormat, LongDateStr[Date]);
  1950. end;
  1951.  
  1952. procedure SysGetTimeFormat(var TimeSeparator: Char; TimeAMString,TimePMString,ShortTimeFormat,LongTimeFormat: PChar);
  1953. var
  1954.   TimePostfix: PChar;
  1955. const
  1956.   SIntl: PChar = 'PM_National';
  1957. begin
  1958.   TimeSeparator := SysGetProfileChar(SIntl, 'sTime', ':');
  1959.   SysGetProfileStr(SIntl, 's1159', 'am', TimeAMString);
  1960.   SysGetProfileStr(SIntl, 's2359', 'pm', TimePMString);
  1961.   if PrfQueryProfileInt(hini_UserProfile, SIntl, 'iLzero', 0) = 0 then
  1962.     begin
  1963.       StrCopy(ShortTimeFormat, 'h:mm');
  1964.       StrCopy(LongTimeFormat, 'h:mm:ss');
  1965.     end
  1966.   else
  1967.     begin
  1968.       StrCopy(ShortTimeFormat, 'hh:mm');
  1969.       StrCopy(LongTimeFormat, 'hh:mm:ss');
  1970.     end;
  1971.   TimePostfix := '';
  1972.   if PrfQueryProfileInt(hini_UserProfile, SIntl, 'iTime', 0) = 0 then
  1973.     TimePostfix := ' AMPM';
  1974.   StrCat(ShortTimeFormat, TimePostfix);
  1975.   StrCat(LongTimeFormat, TimePostfix);
  1976. end;
  1977.  
  1978. function SysGetModuleName(var Address: Pointer; Buffer: PChar; BufSize: Longint): PChar;
  1979. var
  1980.   ModuleName: array[0..259] of Char;
  1981. begin
  1982.   DosQueryModuleName(ModuleHandle, SizeOf(ModuleName), ModuleName);
  1983.   StrLCopy(Buffer, StrRScan(ModuleName, '\') + 1, BufSize - 1);
  1984.   Result := Buffer;
  1985. end;
  1986.  
  1987. procedure SysDisplayConsoleError(PopupErrors: Boolean; Title, Msg: PChar);
  1988. var
  1989.   PopupFlags : SmallWord;
  1990.   Info       : ^KbdKeyInfo;
  1991.   LInfo      : Array[1..2] of KbdKeyInfo;
  1992.   Count      : Longint;
  1993.   pTemp      : pChar;
  1994.   pGood      : pChar;
  1995. type
  1996.   WordRec = packed record
  1997.     Lo, Hi: Byte;
  1998.   end;
  1999. const
  2000.   Cell: SmallWord = $4F20;
  2001. begin
  2002.   if PopupErrors then
  2003.     begin
  2004.       PopupFlags := 1;
  2005.       VioPopup(PopupFlags, 0);
  2006.       VioScrollUp(0, 0, 127, 127, 127, Cell, 0);
  2007.       VioSetCurPos(12, 0, 0);
  2008.       Count:=StrLen(Msg);
  2009.       if Invalid16Parm(Msg, Count) then
  2010.         begin
  2011.           GetMem(pTemp, 2*Count);
  2012.           pGood := Fix_64k(pTemp, Count);
  2013.           Move(Msg^, pGood^, Count);
  2014.           VioWrtTTy(pGood, Count, 0);
  2015.           FreeMem(pTemp);
  2016.         end
  2017.       else
  2018.         VioWrtTTy(@Msg, Count, 0);
  2019.       VioWrtNAttr(WordRec(Cell).Hi, 2000, 0,0, 0);
  2020.       Info := Fix_64k(@LInfo, SizeOf(Info^));
  2021.       if KbdCharIn(Info^, io_Wait, 0) <> 0 then
  2022.         // Wait if kbd call fails.  It does so when exception is
  2023.         // caused by Ctrl-Brk or Ctrl-C.
  2024.         DosSleep(5000);
  2025.       VioEndPopUp(0);
  2026.     end
  2027.   else
  2028.     DosWrite(1, Msg^, StrLen(Msg), Count);
  2029. end;
  2030.  
  2031. procedure SysDisplayGUIError(Title, Msg: PChar);
  2032. begin
  2033.   WinCreateMsgQueue(WinInitialize(0), 0);
  2034.   WinMessageBox(hwnd_Desktop, hwnd_Desktop, Msg, Title, 0, mb_Error+mb_Moveable);
  2035. end;
  2036.  
  2037. procedure SysBeep;
  2038. begin
  2039.   WinAlarm(hwnd_Desktop, wa_Error);
  2040. end;
  2041.  
  2042. procedure SysBeepEx(Freq,Dur: Longint);
  2043. begin
  2044.   DosBeep(Freq, Dur);
  2045. end;
  2046.  
  2047. function SysGetVolumeLabel(Drive: Char): ShortString;
  2048. var
  2049.   rc          : Longint;
  2050.   DriveNumber : Word;
  2051.   Buf: Record
  2052.     SerialNum : Word;
  2053.     VolLabel  : String[12];
  2054.   end;
  2055.  
  2056. begin
  2057.   DriveNumber := Ord( UpCase(Drive) ) - Ord( 'A' ) + 1;
  2058.  
  2059.   rc := DosQueryFSInfo( DriveNumber, fsil_VolSer, Buf, Sizeof( Buf ));
  2060.   If rc = No_Error then
  2061.     Result := Buf.VolLabel
  2062.   else
  2063.     Result := '';
  2064. end;
  2065.  
  2066. function SysSetVolumeLabel(Drive: Char; _Label: ShortString): Boolean;
  2067. var
  2068.   DriveNumber : Word;
  2069. begin
  2070.   DriveNumber := Ord( Drive ) - Ord( 'A' ) + 1;
  2071.   _Label[Length(_Label)+1] := #0;
  2072.   Result := 0 = DosSetFSInfo(DriveNumber, fsil_VolSer, _Label, Length(_Label)+1);
  2073. end;
  2074.  
  2075. function SysGetForegroundProcessId: Longint;
  2076. Var
  2077.   Res : Word;
  2078.   rc  : Longint;
  2079.  
  2080. begin
  2081.   rc := DosQuerySysInfo( qsv_foreground_process, qsv_foreground_process,
  2082.                          Res, Sizeof( Res ));
  2083.   If rc = no_Error then
  2084.     Result := Res
  2085.   else
  2086.     Result := 0;
  2087. end;
  2088.  
  2089. function SysGetBootDrive: Char;
  2090. Var
  2091.   Res : Word;
  2092.   rc  : Longint;
  2093.  
  2094. begin
  2095.   rc := DosQuerySysInfo( qsv_boot_drive, qsv_boot_drive, Res, Sizeof( Res ));
  2096.   If rc = no_Error then
  2097.     Result := Chr( Res + ord('A') - 1 )
  2098.   else
  2099.     Result := #0;
  2100. end;
  2101.  
  2102. function SysGetDriveType(Drive: Char): TDriveType;
  2103. Var
  2104.   BufLen    : Word;
  2105.   FSQb      : pFSQBuffer2;
  2106.   DrvName   : String[3];
  2107.   Ordinal   : SmallWord;
  2108.   name      : pChar;
  2109.   rc        : Word;
  2110.   DiskSize  : Word;
  2111.  
  2112. begin
  2113.   Result := dtInvalid;
  2114.   BufLen := 100;
  2115.   GetMem( FSQb, BufLen );
  2116.   DrvName := Drive+':'#0;
  2117.   Ordinal := 0;
  2118.   rc := DosQueryFSAttach( @DrvName[1], Ordinal, fsail_QueryName, FSqb, BufLen );
  2119.   if rc = 0 then
  2120.     With FsqB^ do
  2121.     begin
  2122.       Name := szName + cbName + 1;
  2123.       If strComp( Name, 'FAT' ) = 0 then
  2124.         If Drive <= 'B' then
  2125.           Result := dtFloppy
  2126.         else
  2127.           Result := dtHDFAT
  2128.       else if strComp( Name, 'HPFS' ) = 0 then
  2129.         If Drive <= 'B' then
  2130.           Result := dtFloppy
  2131.         else
  2132.           Result := dtHDHPFS
  2133.       else If StrComp( Name, 'NETWARE' ) = 0 then
  2134.         Result := dtNovellNet
  2135.       else If StrComp( Name, 'CDFS' ) = 0 then
  2136.         Result := dtCDRom
  2137.       else If StrComp( Name, 'TVFS' ) = 0 then
  2138.         Result := dtTVFS
  2139.       else If StrComp( Name, 'ext2' ) = 0 then
  2140.         Result := dtHDExt2
  2141.       else If StrComp( Name, 'LAN' ) = 0 then
  2142.         Result := dtLAN
  2143.       else If StrComp( Name, 'JFS' ) = 0 then
  2144.         Result := dtJFS;
  2145.     end;
  2146.  
  2147.   FreeMem( FSQb, 100 );
  2148. end;
  2149.  
  2150. function SysGetVideoModeInfo(Var Cols, Rows, Colours: Word ): Boolean;
  2151. Var
  2152.   vm  : ^VioModeInfo;
  2153.   Lvm : Array[1..2] of VioModeInfo;
  2154.  
  2155. begin
  2156.   vm := Fix_64k(@Lvm, SizeOf(vm^));
  2157.   vm.cb := Sizeof(vm^);
  2158.   VioGetMode( vm^, 0 );
  2159.   With vm^ do
  2160.     begin
  2161.       Rows := Row;
  2162.       Cols := Col;
  2163.       Colours := 1 shl Color;
  2164.     end;
  2165.   Result := True;
  2166. end;
  2167.  
  2168. function SysGetVisibleLines( var Top, Bottom: Longint ): Boolean;
  2169. var
  2170.   Cols, Rows, Colours: Word;
  2171. begin
  2172.   if SysGetVideoModeInfo( Cols, Rows, Colours ) then
  2173.   begin
  2174.     Result := True;
  2175.     Top := 1;
  2176.     Bottom := Rows;
  2177.   end
  2178.   else
  2179.     Result := False;
  2180. end;
  2181.  
  2182. function SysSetVideoMode(Cols, Rows: Word): Boolean;
  2183. Var
  2184.   vm  : ^VioModeInfo;
  2185.   Lvm : Array[1..2] of VioModeInfo;
  2186.  
  2187. begin
  2188.   vm := Fix_64k(@Lvm, SizeOf(vm^));
  2189.   vm^.cb := 8;          { Size of structure }
  2190.   VioGetMode(vm^, 0);
  2191.   vm^.fbType := 1;      { Text mode }
  2192.   vm^.Row := Rows;
  2193.   vm^.Col := Cols;
  2194.   vm^.Color := 4;       { 16 colors }
  2195.   Result := ( VioSetMode( vm^, 0 ) = 0 );
  2196. end;
  2197.  
  2198. function SemCreateEvent(_Name: pChar; _Shared, _State: Boolean): TSemHandle;
  2199. var
  2200.   rc: ApiRet;
  2201.   Attr: ULong;
  2202.   Buf: packed array[0..255] of char;
  2203. begin
  2204.   if _Shared then
  2205.     Attr := dc_Sem_Shared
  2206.   else
  2207.     Attr := 0;
  2208.   if (_Name<>nil) and (_Name^<>#0) then
  2209.     begin
  2210.       StrCat(StrCopy(@Buf,'\SEM32\'),_Name);
  2211.       rc := DosCreateEventSem( @Buf, Result, Attr, _State );
  2212.     end
  2213.   else
  2214.     rc := DosCreateEventSem( _Name, Result, Attr, _State );
  2215.   if rc<>No_Error then
  2216.     Result := -1;
  2217. end;
  2218.  
  2219. function SemAccessEvent(_Name: pChar): TSemHandle;
  2220. var
  2221.   Buf: packed array[0..255] of char;
  2222.   rc: ApiRet;
  2223. begin
  2224.   if (_Name<>nil) and (_Name^<>#0) then
  2225.     begin
  2226.       StrCat(StrCopy(@Buf,'\SEM32\'),_Name);
  2227.       Result := 0;
  2228.       rc := DosOpenEventSem( @Buf, Result );
  2229.       if rc<>No_Error then
  2230.         Result := -1;
  2231.     end
  2232.   else
  2233.     Result:=-1;
  2234. end;
  2235.  
  2236. function SemPostEvent(_Handle: TSemhandle): Boolean;
  2237. begin
  2238.   Result := DosPostEventSem( _Handle ) = 0;
  2239. end;
  2240.  
  2241. function SemWaitEvent(_Handle: TSemHandle; _TimeOut: Longint): Boolean;
  2242. var
  2243.   Dummy: Longint;
  2244. begin
  2245.   Result := DosWaitEventSem(_Handle, _TimeOut) = 0;
  2246.   DosResetEventSem( _Handle, Dummy );
  2247. end;
  2248.  
  2249. procedure SemCloseEvent(_Handle: TSemHandle);
  2250. begin
  2251.   DosCloseEventSem(_Handle);
  2252. end;
  2253.  
  2254. function SemCreateMutex(_Name: PChar; _Shared, _State: Boolean): TSemHandle;
  2255. var
  2256.   Flags: Longint;
  2257.   rc: ApiRet;
  2258.   Buf: packed array[0..255] of char;
  2259. begin
  2260.   Flags := 0;
  2261.   if _Shared then
  2262.     Flags := dc_sem_Shared;
  2263.   if (_Name<>nil) and (_Name^<>#0) then
  2264.     begin
  2265.       StrCat(StrCopy(@Buf,'\SEM32\'),_Name);
  2266.       rc := DosCreateMutexSem(@Buf, Result, Flags, _State);
  2267.     end
  2268.   else
  2269.     rc := DosCreateMutexSem(_Name, Result, Flags, _State);
  2270.   if rc<>No_Error then
  2271.     result := -1;
  2272. end;
  2273.  
  2274. function SemAccessMutex(_Name: PChar): TSemHandle;
  2275. var
  2276.   rc: ApiRet;
  2277.   Buf: packed array[0..255] of char;
  2278. begin
  2279.   Result := 0;
  2280.   if (_Name<>nil) and (_Name^<>#0) then
  2281.     begin
  2282.       StrCat(StrCopy(@Buf,'\SEM32\'),_Name);
  2283.       rc := DosOpenMutexSem(@Buf, Result);
  2284.     end
  2285.   else
  2286.     rc := DosOpenMutexSem(_Name, Result);
  2287.   if rc<>No_Error then
  2288.     Result := -1;
  2289. end;
  2290.  
  2291. function SemRequestMutex(_Handle: TSemHandle; _TimeOut: Longint): Boolean;
  2292. begin
  2293.   Result := DosRequestMutexSem(_Handle, _TimeOut) = 0;
  2294. end;
  2295.  
  2296. function SemReleaseMutex(_Handle: TSemHandle): Boolean;
  2297. begin
  2298.   Result := DosReleaseMutexSem( _Handle ) = 0;
  2299. end;
  2300.  
  2301. procedure SemCloseMutex(_Handle: TSemHandle);
  2302. begin
  2303.   DosCloseMutexSem(_Handle);
  2304. end;
  2305.  
  2306. function SysMemInfo(_Base: Pointer; _Size: Longint; var _Flags: Longint): Boolean;
  2307. begin
  2308.   Result := (DosQueryMem(_Base, _Size, _Flags)=No_Error);
  2309. end;
  2310.  
  2311. function SysSetMemProtection(_Base: Pointer; _Size: Longint; _Flags: Longint): Boolean;
  2312. begin
  2313.   result := (DosSetMem(_Base, _Size, _Flags)=No_Error);
  2314. end;
  2315.  
  2316. procedure SysMessageBox(_Msg, _Title: PChar; _Error: Boolean);
  2317. var
  2318.   Flag: Longint;
  2319. begin
  2320.   if _Error then
  2321.     Flag := mb_Error
  2322.   else
  2323.     Flag := mb_Information;
  2324.   WinMessageBox( hwnd_Desktop, hwnd_Desktop, _Msg, _Title, 0, Flag or mb_ok);
  2325. end;
  2326.  
  2327. function SysClipCanPaste: Boolean;
  2328. var
  2329.   Fmt: ULong;
  2330. begin
  2331.   WinCreateMsgQueue(WinInitialize(0), 0);
  2332.   // Console apps can only use the OS/2 clipboard if the "hack" works
  2333.   Result := (not IsConsole or (PM_Clipboardhack = clipOK)) and
  2334.     WinQueryClipBrdFmtInfo(WinInitialize(0), cf_Text, Fmt);
  2335. end;
  2336.  
  2337. function SysClipCopy(P: PChar; Size: Longint): Boolean;
  2338. var
  2339.   Q: pChar;
  2340.   Anchor: HAB;
  2341. begin
  2342.   Result := False;
  2343.   Anchor := WinInitialize(0);
  2344.   WinCreateMsgQueue(Anchor, 0);
  2345.   // Open PM clipboard
  2346.   if WinOpenClipBrd(Anchor) then
  2347.   begin
  2348.     // Allocate giveable block of memory
  2349.     DosAllocSharedMem(Pointer(Q), nil, Size+1, pag_Write+pag_Commit+obj_Giveable);
  2350.     if Q <> nil then
  2351.     begin
  2352.       // Copy clipboard data across
  2353.       Move(P^, Q^, Size);
  2354.       Q[Size]:=#0;
  2355.       // Insert data into clipboard
  2356.       Result := WinSetClipBrdData(Anchor, ULong(Q), cf_Text, cfi_Pointer);
  2357.     end;
  2358.     WinCloseClipBrd(Anchor);
  2359.   end;
  2360. end;
  2361.  
  2362. function SysClipPaste(var Size: Integer): Pointer;
  2363. var
  2364.   P: PChar;
  2365.   Anchor: HAB;
  2366.   Flags: Longint;
  2367. begin
  2368.   Result := nil;
  2369.   Anchor := WinInitialize(0);
  2370.   WinCreateMsgQueue(Anchor, 0);
  2371.   if WinOpenClipBrd(Anchor) then
  2372.   begin
  2373.     P := PChar(WinQueryClipBrdData(Anchor, cf_Text));
  2374.     if Assigned(P) then
  2375.       if SysMemInfo(P, 1, Flags) and (Flags and sysmem_read <> 0) then
  2376.         begin
  2377.           Size := StrLen(P) + 1;
  2378.           GetMem(Result, Size);
  2379.           Move(P^, Result^, Size);
  2380.         end;
  2381.     WinCloseClipBrd(Anchor);
  2382.   end;
  2383. end;
  2384.  
  2385. // Retrieve various system settings, bitmapped:
  2386. // 0: Enhanced keyboard installed
  2387.  
  2388. function SysGetSystemSettings: Longint;
  2389. Var
  2390.   rc    : ApiRet16;
  2391.   HwId  : ^KbdHwId;
  2392.   LHwId : Array[1..2] of KbdHwId;
  2393.  
  2394. begin
  2395.   Result := 0;
  2396.  
  2397.   // Determine if enhanced keyboard is available
  2398.   rc := KbdGetFocus(1, 0);
  2399.   If rc = No_Error then
  2400.     begin
  2401.       HwId := Fix_64k(@LHwId, SizeOf(HwId^));
  2402.       HwId^.cb := Sizeof( HwId^ );
  2403.       rc := KbdGetHwId( HwId^, 0 );
  2404.       If rc = No_Error then
  2405.         if ( HwId^.IdKbd = keyboard_Enhanced_101 ) or
  2406.            ( HwId^.IdKbd = keyboard_Enhanced_122 ) then
  2407.           Result := Result OR 1;
  2408.  
  2409.       rc := KbdFreeFocus( 0 );
  2410.     end;
  2411. end;
  2412.  
  2413.  
  2414.