2
This file is part of the Free Pascal run time library.
3
Copyright (c) 1999-2005 by Florian Klaempfl and Pavel Ozerski
4
member of the Free Pascal development team.
6
FPC Pascal system unit for the Win32 API.
8
See the file COPYING.FPC, included in this distribution,
9
for details about the copyright.
11
This program is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15
**********************************************************************}
20
{$define SYSTEMEXCEPTIONDEBUG}
24
{$define Set_i386_Exception_handler}
27
{$define DISABLE_NO_THREAD_MANAGER}
29
{ include system-independent routine headers }
35
DirectorySeparator = '\';
38
{ FileNameCaseSensitive is defined separately below!!! }
43
PEXCEPTION_FRAME = ^TEXCEPTION_FRAME;
44
TEXCEPTION_FRAME = record
45
next : PEXCEPTION_FRAME;
50
{ Default filehandles }
51
UnusedHandle : THandle = -1;
52
StdInputHandle : THandle = 0;
53
StdOutputHandle : THandle = 0;
54
StdErrorHandle : THandle = 0;
56
FileNameCaseSensitive : boolean = true;
57
CtrlZMarksEOF: boolean = true; (* #26 not considered as end of file *)
59
sLineBreak = LineEnding;
60
DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsCRLF;
62
{ Thread count for DLL }
63
Thread_count : longint = 0;
64
System_exception_frame : PEXCEPTION_FRAME =nil;
67
TStartupInfo=packed record
76
dwXCountChars : longint;
77
dwYCountChars : longint;
78
dwFillAttribute : longint;
82
lpReserved2 : Pointer;
89
{ C compatible arguments }
93
startupinfo : tstartupinfo;
97
DLLreason,DLLparam:longint;
98
StartupConsoleMode : DWORD;
101
TDLL_Process_Entry_Hook = function (dllparam : longint) : longbool;
102
TDLL_Entry_Hook = procedure (dllparam : longint);
105
Dll_Process_Attach_Hook : TDLL_Process_Entry_Hook = nil;
106
Dll_Process_Detach_Hook : TDLL_Entry_Hook = nil;
107
Dll_Thread_Attach_Hook : TDLL_Entry_Hook = nil;
108
Dll_Thread_Detach_Hook : TDLL_Entry_Hook = nil;
113
SysInstance : Longint;public name '_FPC_SysInstance';
116
{$define HAS_RESOURCES}
120
{ used by wstrings.inc because wstrings.inc is included before sysos.inc
121
this is put here (FK) }
123
function SysAllocStringLen(psz:pointer;len:dword):pointer;stdcall;
124
external 'oleaut32.dll' name 'SysAllocStringLen';
126
procedure SysFreeString(bstr:pointer);stdcall;
127
external 'oleaut32.dll' name 'SysFreeString';
129
function SysReAllocStringLen(var bstr:pointer;psz: pointer;
130
len:dword): Integer; stdcall;external 'oleaut32.dll' name 'SysReAllocStringLen';
133
{ include system independent routines }
136
{*****************************************************************************
138
*****************************************************************************}
141
ModuleName : array[0..255] of char;
143
function GetCommandFile:pchar;
145
GetModuleFileName(0,@ModuleName,255);
146
GetCommandFile:=@ModuleName;
150
procedure setup_arguments;
159
procedure allocarg(idx,len:longint);
161
oldargvlen : longint;
166
argvlen:=(idx+8) and (not 7);
167
sysreallocmem(argv,argvlen*sizeof(pointer));
168
fillchar(argv[oldargvlen],(argvlen-oldargvlen)*sizeof(pointer),0);
170
{ use realloc to reuse already existing memory }
171
{ always allocate, even if length is zero, since }
172
{ the arg. is still present! }
173
sysreallocmem(argv[idx],len+1);
178
{ create commandline, it starts with the executed filename which is argv[0] }
179
{ Win32 passes the command NOT via the args, but via getmodulefilename}
187
until (pc[Arglen]=#0);
188
allocarg(count,arglen);
189
move(pc^,argv[count]^,arglen+1);
190
{ Setup cmdline variable }
191
cmdline:=GetCommandLine;
192
{ process arguments }
194
{$IfDef SYSTEM_DEBUG_STARTUP}
195
Writeln(stderr,'Win32 GetCommandLine is #',pc,'#');
199
{ skip leading spaces }
200
while pc^ in [#1..#32] do
204
{ calc argument length }
219
if pchar(pc+1)^<>'"' then
234
{ Don't copy the first one, it is already there.}
237
allocarg(count,arglen);
255
if pchar(pc+1)^<>'"' then
274
{$IfDef SYSTEM_DEBUG_STARTUP}
275
Writeln(stderr,'dos arg ',count,' #',arglen,'#',argv[count],'#');
276
{$EndIf SYSTEM_DEBUG_STARTUP}
279
{ get argc and create an nil entry }
282
{ free unused memory }
283
sysreallocmem(argv,(argc+1)*sizeof(pointer));
287
function paramcount : longint;
289
paramcount := argc - 1;
292
function paramstr(l : longint) : string;
294
if (l>=0) and (l<argc) then
295
paramstr:=strpas(argv[l])
303
randseed:=GetTickCount;
307
{*****************************************************************************
308
System Dependent Exit code
309
*****************************************************************************}
311
procedure install_exception_handlers;forward;
312
procedure remove_exception_handlers;forward;
313
procedure PascalMain;stdcall;external name 'PASCALMAIN';
314
procedure fpc_do_exit;stdcall;external name 'FPC_DO_EXIT';
315
Procedure ExitDLL(Exitcode : longint); forward;
316
procedure asm_exit;stdcall;external name 'asm_exit';
318
Procedure system_exit;
320
{ don't call ExitProcess inside
322
This crashes Win95 at least PM }
325
if not IsConsole then
332
{ what about Input and Output ?? PM }
335
remove_exception_handlers;
337
{ in 2.0 asm_exit does an exitprocess }
339
{ do cleanup required by the startup code }
343
{ call exitprocess, with cleanup as required }
344
ExitProcess(exitcode);
348
{ value of the stack segment
349
to check if the call stack can be written on exceptions }
352
procedure Exe_entry;[public,alias:'_FPC_EXE_Entry'];
357
{ install the handlers for exe only ?
358
or should we install them for DLL also ? (PM) }
359
install_exception_handlers;
360
{ This strange construction is needed to solve the _SS problem
361
with a smartlinked syswin32 (PFV) }
363
{ allocate space for an exception frame }
367
but don't insert it as it doesn't
368
point to anything yet
369
this will be used in signals unit }
371
movl %eax,System_exception_frame
386
{ if we pass here there was no error ! }
393
DLL_PROCESS_ATTACH = 1;
394
DLL_THREAD_ATTACH = 2;
395
DLL_PROCESS_DETACH = 0;
396
DLL_THREAD_DETACH = 3;
400
DLLExitOK : boolean = true;
402
function Dll_entry : longbool; [public,alias:'_FPC_DLL_Entry'];
412
If SetJmp(DLLBuf) = 0 then
414
if assigned(Dll_Process_Attach_Hook) then
416
res:=Dll_Process_Attach_Hook(DllParam);
424
Dll_entry:=DLLExitOK;
428
inclocked(Thread_count);
429
{$warning Allocate Threadvars !}
430
if assigned(Dll_Thread_Attach_Hook) then
431
Dll_Thread_Attach_Hook(DllParam);
432
Dll_entry:=true; { return value is ignored }
436
declocked(Thread_count);
437
if assigned(Dll_Thread_Detach_Hook) then
438
Dll_Thread_Detach_Hook(DllParam);
439
{$warning Release Threadvars !}
440
Dll_entry:=true; { return value is ignored }
444
Dll_entry:=true; { return value is ignored }
445
If SetJmp(DLLBuf) = 0 then
447
if assigned(Dll_Process_Detach_Hook) then
448
Dll_Process_Detach_Hook(DllParam);
453
Procedure ExitDLL(Exitcode : longint);
455
DLLExitOK:=ExitCode=0;
460
function GetCurrentProcess : dword;
461
stdcall;external 'kernel32' name 'GetCurrentProcess';
463
function ReadProcessMemory(process : dword;address : pointer;dest : pointer;size : dword;bytesread : pdword) : longbool;
464
stdcall;external 'kernel32' name 'ReadProcessMemory';
466
function is_prefetch(p : pointer) : boolean;
468
a : array[0..15] of byte;
470
instrlo,instrhi,opcode : byte;
474
{ read memory savely without causing another exeception }
475
if not(ReadProcessMemory(GetCurrentProcess,p,@a,sizeof(a),nil)) then
479
while doagain and (i<15) do
482
instrlo:=opcode and $f;
483
instrhi:=opcode and $f0;
487
doagain:=(instrlo and 7)=6;
489
doagain:=(instrlo and $c)=4;
491
doagain:=instrlo in [0,2,3];
494
result:=(instrlo=$f) and (a[i+1] in [$d,$18]);
506
// Hardware exception handling
509
{$ifdef Set_i386_Exception_handler}
512
Error code definitions for the Win32 API functions
515
Values are 32 bit values layed out as follows:
516
3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
517
1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
518
+---+-+-+-----------------------+-------------------------------+
519
|Sev|C|R| Facility | Code |
520
+---+-+-+-----------------------+-------------------------------+
523
Sev - is the severity code
529
C - is the Customer code flag
530
R - is a reserved bit
531
Facility - is the facility code
532
Code - is the facility's status code
536
SEVERITY_SUCCESS = $00000000;
537
SEVERITY_INFORMATIONAL = $40000000;
538
SEVERITY_WARNING = $80000000;
539
SEVERITY_ERROR = $C0000000;
542
STATUS_SEGMENT_NOTIFICATION = $40000005;
543
DBG_TERMINATE_THREAD = $40010003;
544
DBG_TERMINATE_PROCESS = $40010004;
545
DBG_CONTROL_C = $40010005;
546
DBG_CONTROL_BREAK = $40010008;
548
STATUS_GUARD_PAGE_VIOLATION = $80000001;
549
STATUS_DATATYPE_MISALIGNMENT = $80000002;
550
STATUS_BREAKPOINT = $80000003;
551
STATUS_SINGLE_STEP = $80000004;
552
DBG_EXCEPTION_NOT_HANDLED = $80010001;
554
STATUS_ACCESS_VIOLATION = $C0000005;
555
STATUS_IN_PAGE_ERROR = $C0000006;
556
STATUS_INVALID_HANDLE = $C0000008;
557
STATUS_NO_MEMORY = $C0000017;
558
STATUS_ILLEGAL_INSTRUCTION = $C000001D;
559
STATUS_NONCONTINUABLE_EXCEPTION = $C0000025;
560
STATUS_INVALID_DISPOSITION = $C0000026;
561
STATUS_ARRAY_BOUNDS_EXCEEDED = $C000008C;
562
STATUS_FLOAT_DENORMAL_OPERAND = $C000008D;
563
STATUS_FLOAT_DIVIDE_BY_ZERO = $C000008E;
564
STATUS_FLOAT_INEXACT_RESULT = $C000008F;
565
STATUS_FLOAT_INVALID_OPERATION = $C0000090;
566
STATUS_FLOAT_OVERFLOW = $C0000091;
567
STATUS_FLOAT_STACK_CHECK = $C0000092;
568
STATUS_FLOAT_UNDERFLOW = $C0000093;
569
STATUS_INTEGER_DIVIDE_BY_ZERO = $C0000094;
570
STATUS_INTEGER_OVERFLOW = $C0000095;
571
STATUS_PRIVILEGED_INSTRUCTION = $C0000096;
572
STATUS_STACK_OVERFLOW = $C00000FD;
573
STATUS_CONTROL_C_EXIT = $C000013A;
574
STATUS_FLOAT_MULTIPLE_FAULTS = $C00002B4;
575
STATUS_FLOAT_MULTIPLE_TRAPS = $C00002B5;
576
STATUS_REG_NAT_CONSUMPTION = $C00002C9;
578
EXCEPTION_EXECUTE_HANDLER = 1;
579
EXCEPTION_CONTINUE_EXECUTION = -1;
580
EXCEPTION_CONTINUE_SEARCH = 0;
582
EXCEPTION_MAXIMUM_PARAMETERS = 15;
584
CONTEXT_X86 = $00010000;
585
CONTEXT_CONTROL = CONTEXT_X86 or $00000001;
586
CONTEXT_INTEGER = CONTEXT_X86 or $00000002;
587
CONTEXT_SEGMENTS = CONTEXT_X86 or $00000004;
588
CONTEXT_FLOATING_POINT = CONTEXT_X86 or $00000008;
589
CONTEXT_DEBUG_REGISTERS = CONTEXT_X86 or $00000010;
590
CONTEXT_EXTENDED_REGISTERS = CONTEXT_X86 or $00000020;
592
CONTEXT_FULL = CONTEXT_CONTROL or CONTEXT_INTEGER or CONTEXT_SEGMENTS;
594
MAXIMUM_SUPPORTED_EXTENSION = 512;
597
PFloatingSaveArea = ^TFloatingSaveArea;
598
TFloatingSaveArea = packed record
599
ControlWord : Cardinal;
600
StatusWord : Cardinal;
602
ErrorOffset : Cardinal;
603
ErrorSelector : Cardinal;
604
DataOffset : Cardinal;
605
DataSelector : Cardinal;
606
RegisterArea : array[0..79] of Byte;
607
Cr0NpxState : Cardinal;
610
PContext = ^TContext;
611
TContext = packed record
613
// The flags values within this flag control the contents of
616
ContextFlags : Cardinal;
619
// This section is specified/returned if CONTEXT_DEBUG_REGISTERS is
620
// set in ContextFlags. Note that CONTEXT_DEBUG_REGISTERS is NOT
621
// included in CONTEXT_FULL.
624
Dr3, Dr6, Dr7 : Cardinal;
627
// This section is specified/returned if the
628
// ContextFlags word contains the flag CONTEXT_FLOATING_POINT.
630
FloatSave : TFloatingSaveArea;
633
// This section is specified/returned if the
634
// ContextFlags word contains the flag CONTEXT_SEGMENTS.
637
SegEs, SegDs : Cardinal;
640
// This section is specified/returned if the
641
// ContextFlags word contains the flag CONTEXT_INTEGER.
644
Edx, Ecx, Eax : Cardinal;
647
// This section is specified/returned if the
648
// ContextFlags word contains the flag CONTEXT_CONTROL.
653
EFlags, Esp, SegSs : Cardinal;
656
// This section is specified/returned if the ContextFlags word
657
// contains the flag CONTEXT_EXTENDED_REGISTERS.
658
// The format and contexts are processor specific
660
ExtendedRegisters : array[0..MAXIMUM_SUPPORTED_EXTENSION-1] of Byte;
664
PExceptionRecord = ^TExceptionRecord;
665
TExceptionRecord = packed record
666
ExceptionCode : cardinal;
667
ExceptionFlags : Longint;
668
ExceptionRecord : PExceptionRecord;
669
ExceptionAddress : Pointer;
670
NumberParameters : Longint;
671
ExceptionInformation : array[0..EXCEPTION_MAXIMUM_PARAMETERS-1] of Pointer;
674
PExceptionPointers = ^TExceptionPointers;
675
TExceptionPointers = packed record
676
ExceptionRecord : PExceptionRecord;
677
ContextRecord : PContext;
680
{ type of functions that should be used for exception handling }
681
TTopLevelExceptionFilter = function (excep : PExceptionPointers) : Longint;stdcall;
683
function SetUnhandledExceptionFilter(lpTopLevelExceptionFilter : TTopLevelExceptionFilter) : TTopLevelExceptionFilter;
684
stdcall;external 'kernel32' name 'SetUnhandledExceptionFilter';
687
MaxExceptionLevel = 16;
688
exceptLevel : Byte = 0;
691
exceptEip : array[0..MaxExceptionLevel-1] of Longint;
692
exceptError : array[0..MaxExceptionLevel-1] of Byte;
693
resetFPU : array[0..MaxExceptionLevel-1] of Boolean;
695
{$ifdef SYSTEMEXCEPTIONDEBUG}
696
procedure DebugHandleErrorAddrFrame(error, addr, frame : longint);
700
write(stderr,'HandleErrorAddrFrame(error=',error);
701
write(stderr,',addr=',hexstr(addr,8));
702
writeln(stderr,',frame=',hexstr(frame,8),')');
704
HandleErrorAddrFrame(error,addr,frame);
706
{$endif SYSTEMEXCEPTIONDEBUG}
708
procedure JumpToHandleErrorFrame;
710
eip, ebp, error : Longint;
717
if (exceptLevel > 0) then
720
eip:=exceptEip[exceptLevel];
721
error:=exceptError[exceptLevel];
722
{$ifdef SYSTEMEXCEPTIONDEBUG}
724
writeln(stderr,'In JumpToHandleErrorFrame error=',error);
725
{$endif SYSTEMEXCEPTIONDEBUG}
726
if resetFPU[exceptLevel] then
728
{ build a fake stack }
735
movl ebp,%ebp // Change frame pointer
745
movl ebp,%ebp // Change frame pointer
748
{$ifdef SYSTEMEXCEPTIONDEBUG}
749
jmpl DebugHandleErrorAddrFrame
750
{$else not SYSTEMEXCEPTIONDEBUG}
751
jmpl HandleErrorAddrFrame
752
{$endif SYSTEMEXCEPTIONDEBUG}
756
function syswin32_i386_exception_handler(excep : PExceptionPointers) : Longint;stdcall;
760
must_reset_fpu: boolean;
762
res := EXCEPTION_CONTINUE_SEARCH;
763
if excep^.ContextRecord^.SegSs=_SS then begin
765
must_reset_fpu := true;
766
{$ifdef SYSTEMEXCEPTIONDEBUG}
767
if IsConsole then Writeln(stderr,'Exception ',
768
hexstr(excep^.ExceptionRecord^.ExceptionCode, 8));
769
{$endif SYSTEMEXCEPTIONDEBUG}
770
case excep^.ExceptionRecord^.ExceptionCode of
771
STATUS_INTEGER_DIVIDE_BY_ZERO,
772
STATUS_FLOAT_DIVIDE_BY_ZERO :
774
STATUS_ARRAY_BOUNDS_EXCEEDED :
777
must_reset_fpu := false;
779
STATUS_STACK_OVERFLOW :
782
must_reset_fpu := false;
784
STATUS_FLOAT_OVERFLOW :
786
STATUS_FLOAT_DENORMAL_OPERAND,
787
STATUS_FLOAT_UNDERFLOW :
789
{excep^.ContextRecord^.FloatSave.StatusWord := excep^.ContextRecord^.FloatSave.StatusWord and $ffffff00;}
790
STATUS_FLOAT_INEXACT_RESULT,
791
STATUS_FLOAT_INVALID_OPERATION,
792
STATUS_FLOAT_STACK_CHECK :
794
STATUS_INTEGER_OVERFLOW :
797
must_reset_fpu := false;
799
STATUS_ILLEGAL_INSTRUCTION:
800
{ if we're testing sse support, simply set the flag and continue }
803
os_supports_sse:=false;
804
{ skip the offending movaps %xmm7, %xmm6 instruction }
805
inc(excep^.ContextRecord^.Eip,3);
806
excep^.ExceptionRecord^.ExceptionCode := 0;
807
res:=EXCEPTION_CONTINUE_EXECUTION;
811
STATUS_ACCESS_VIOLATION:
812
{ Athlon prefetch bug? }
813
if is_prefetch(pointer(excep^.ContextRecord^.Eip)) then
815
{ if yes, then retry }
816
excep^.ExceptionRecord^.ExceptionCode := 0;
817
res:=EXCEPTION_CONTINUE_EXECUTION;
822
STATUS_CONTROL_C_EXIT:
824
STATUS_PRIVILEGED_INSTRUCTION:
827
must_reset_fpu := false;
831
if ((excep^.ExceptionRecord^.ExceptionCode and SEVERITY_ERROR) = SEVERITY_ERROR) then
838
if (err <> 0) and (exceptLevel < MaxExceptionLevel) then begin
839
exceptEip[exceptLevel] := excep^.ContextRecord^.Eip;
840
exceptError[exceptLevel] := err;
841
resetFPU[exceptLevel] := must_reset_fpu;
844
excep^.ContextRecord^.Eip := Longint(@JumpToHandleErrorFrame);
845
excep^.ExceptionRecord^.ExceptionCode := 0;
847
res := EXCEPTION_CONTINUE_EXECUTION;
848
{$ifdef SYSTEMEXCEPTIONDEBUG}
849
if IsConsole then begin
850
writeln(stderr,'Exception Continue Exception set at ',
851
hexstr(exceptEip[exceptLevel],8));
852
writeln(stderr,'Eip changed to ',
853
hexstr(longint(@JumpToHandleErrorFrame),8), ' error=', error);
855
{$endif SYSTEMEXCEPTIONDEBUG}
858
syswin32_i386_exception_handler := res;
861
procedure install_exception_handlers;
862
{$ifdef SYSTEMEXCEPTIONDEBUG}
865
newexceptaddr : Longint;
866
{$endif SYSTEMEXCEPTIONDEBUG}
869
{$ifdef SYSTEMEXCEPTIONDEBUG}
873
movl %eax,oldexceptaddr
875
{$endif SYSTEMEXCEPTIONDEBUG}
876
SetUnhandledExceptionFilter(@syswin32_i386_exception_handler);
877
{$ifdef SYSTEMEXCEPTIONDEBUG}
881
movl %eax,newexceptaddr
884
writeln(stderr,'Old exception ',hexstr(oldexceptaddr,8),
885
' new exception ',hexstr(newexceptaddr,8));
886
{$endif SYSTEMEXCEPTIONDEBUG}
889
procedure remove_exception_handlers;
891
SetUnhandledExceptionFilter(nil);
894
{$else not cpui386 (Processor specific !!)}
895
procedure install_exception_handlers;
899
procedure remove_exception_handlers;
903
{$endif Set_i386_Exception_handler}
905
{****************************************************************************
906
OS dependend widestrings
907
****************************************************************************}
910
{ MultiByteToWideChar }
914
function MultiByteToWideChar(CodePage:UINT; dwFlags:DWORD; lpMultiByteStr:PChar; cchMultiByte:longint; lpWideCharStr:PWideChar;cchWideChar:longint):longint;
915
stdcall; external 'kernel32' name 'MultiByteToWideChar';
916
function WideCharToMultiByte(CodePage:UINT; dwFlags:DWORD; lpWideCharStr:PWideChar; cchWideChar:longint; lpMultiByteStr:PChar;cchMultiByte:longint; lpDefaultChar:PChar; lpUsedDefaultChar:pointer):longint;
917
stdcall; external 'kernel32' name 'WideCharToMultiByte';
918
function CharUpperBuff(lpsz:LPWSTR; cchLength:DWORD):DWORD;
919
stdcall; external 'user32' name 'CharUpperBuffW';
920
function CharLowerBuff(lpsz:LPWSTR; cchLength:DWORD):DWORD;
921
stdcall; external 'user32' name 'CharLowerBuffW';
924
procedure Win32Wide2AnsiMove(source:pwidechar;var dest:ansistring;len:SizeInt);
928
// retrieve length including trailing #0
929
destlen:=WideCharToMultiByte(CP_ACP, 0, source, len+1, nil, 0, nil, nil);
930
setlength(dest, destlen-1);
931
WideCharToMultiByte(CP_ACP, 0, source, len+1, @dest[1], destlen, nil, nil);
934
procedure Win32Ansi2WideMove(source:pchar;var dest:widestring;len:SizeInt);
938
// retrieve length including trailing #0
939
destlen:=MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, source, len+1, nil, 0);
940
setlength(dest, destlen-1);
941
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, source, len+1, @dest[1], destlen);
945
function Win32WideUpper(const s : WideString) : WideString;
948
UniqueString(result);
949
if length(result)>0 then
950
CharUpperBuff(LPWSTR(result),length(result));
954
function Win32WideLower(const s : WideString) : WideString;
957
UniqueString(result);
958
if length(result)>0 then
959
CharLowerBuff(LPWSTR(result),length(result));
963
{ there is a similiar procedure in sysutils which inits the fields which
964
are only relevant for the sysutils units }
965
procedure InitWin32Widestrings;
967
widestringmanager.Wide2AnsiMoveProc:=@Win32Wide2AnsiMove;
968
widestringmanager.Ansi2WideMoveProc:=@Win32Ansi2WideMove;
969
widestringmanager.UpperWideStringProc:=@Win32WideUpper;
970
widestringmanager.LowerWideStringProc:=@Win32WideLower;
975
{****************************************************************************
976
Error Message writing using messageboxes
977
****************************************************************************}
979
function MessageBox(w1:longint;l1,l2:pointer;w2:longint):longint;
980
stdcall;external 'user32' name 'MessageBoxA';
983
ErrorBufferLength = 1024;
985
ErrorBuf : array[0..ErrorBufferLength] of char;
988
Function ErrorWrite(Var F: TextRec): Integer;
990
An error message should always end with #13#10#13#10
998
if F.BufPos+ErrorLen>ErrorBufferLength then
999
i:=ErrorBufferLength-ErrorLen
1002
Move(F.BufPtr^,ErrorBuf[ErrorLen],i);
1004
ErrorBuf[ErrorLen]:=#0;
1008
p:=@ErrorBuf[ErrorLen];
1012
if not(p^ in [#10,#13]) then
1016
if ErrorLen=ErrorBufferLength then
1020
MessageBox(0,@ErrorBuf,pchar('Error'),0);
1028
Function ErrorClose(Var F: TextRec): Integer;
1032
MessageBox(0,@ErrorBuf,pchar('Error'),0);
1040
Function ErrorOpen(Var F: TextRec): Integer;
1042
TextRec(F).InOutFunc:=@ErrorWrite;
1043
TextRec(F).FlushFunc:=@ErrorWrite;
1044
TextRec(F).CloseFunc:=@ErrorClose;
1049
procedure AssignError(Var T: Text);
1052
TextRec(T).OpenFunc:=@ErrorOpen;
1057
procedure SysInitStdIO;
1059
{ Setup stdin, stdout and stderr, for GUI apps redirect stderr,stdout to be
1060
displayed in a messagebox }
1061
StdInputHandle:=longint(GetStdHandle(cardinal(STD_INPUT_HANDLE)));
1062
StdOutputHandle:=longint(GetStdHandle(cardinal(STD_OUTPUT_HANDLE)));
1063
StdErrorHandle:=longint(GetStdHandle(cardinal(STD_ERROR_HANDLE)));
1064
if not IsConsole then
1066
AssignError(stderr);
1067
AssignError(stdout);
1070
Assign(ErrOutput,'');
1074
OpenStdIO(Input,fmInput,StdInputHandle);
1075
OpenStdIO(Output,fmOutput,StdOutputHandle);
1076
OpenStdIO(ErrOutput,fmOutput,StdErrorHandle);
1077
OpenStdIO(StdOut,fmOutput,StdOutputHandle);
1078
OpenStdIO(StdErr,fmOutput,StdErrorHandle);
1082
(* ProcessID cached to avoid repeated calls to GetCurrentProcess. *)
1085
ProcessID: SizeUInt;
1087
function GetProcessID: SizeUInt;
1089
GetProcessID := ProcessID;
1092
function CheckInitialStkLen(stklen : SizeUInt) : SizeUInt;
1099
Exe_entry_code : pointer = @Exe_entry;
1100
Dll_entry_code : pointer = @Dll_entry;
1104
StackLength := CheckInitialStkLen(InitialStkLen);
1105
StackBottom := StackTop - StackLength;
1106
{ get some helpful informations }
1107
GetStartupInfo(@startupinfo);
1108
{ some misc Win32 stuff }
1110
if not IsLibrary then
1111
SysInstance:=getmodulehandle(GetCommandFile);
1112
MainInstance:=HInstance;
1113
cmdshow:=startupinfo.wshowwindow;
1117
{ setup fastmove stuff }
1124
ProcessID := GetCurrentProcessID;
1127
{ Reset internal error variable }
1130
initwidestringmanager;
1131
InitWin32Widestrings;
1132
DispCallByIDProc:=@DoDispCallByIDError;