syswin.inc 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2008 by Florian Klaempfl and Pavel Ozerski
  4. member of the Free Pascal development team.
  5. FPC Pascal system unit part shared by win32/win64.
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. {
  13. Error code definitions for the Win32 API functions
  14. Values are 32 bit values layed out as follows:
  15. 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
  16. 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
  17. +---+-+-+-----------------------+-------------------------------+
  18. |Sev|C|R| Facility | Code |
  19. +---+-+-+-----------------------+-------------------------------+
  20. where
  21. Sev - is the severity code
  22. 00 - Success
  23. 01 - Informational
  24. 10 - Warning
  25. 11 - Error
  26. C - is the Customer code flag
  27. R - is a reserved bit
  28. Facility - is the facility code
  29. Code - is the facility's status code
  30. }
  31. const
  32. SEVERITY_SUCCESS = $00000000;
  33. SEVERITY_INFORMATIONAL = $40000000;
  34. SEVERITY_WARNING = $80000000;
  35. SEVERITY_ERROR = $C0000000;
  36. const
  37. STATUS_SEGMENT_NOTIFICATION = $40000005;
  38. DBG_TERMINATE_THREAD = $40010003;
  39. DBG_TERMINATE_PROCESS = $40010004;
  40. DBG_CONTROL_C = $40010005;
  41. DBG_CONTROL_BREAK = $40010008;
  42. STATUS_GUARD_PAGE_VIOLATION = $80000001;
  43. STATUS_DATATYPE_MISALIGNMENT = $80000002;
  44. STATUS_BREAKPOINT = $80000003;
  45. STATUS_SINGLE_STEP = $80000004;
  46. DBG_EXCEPTION_NOT_HANDLED = $80010001;
  47. STATUS_ACCESS_VIOLATION = $C0000005;
  48. STATUS_IN_PAGE_ERROR = $C0000006;
  49. STATUS_INVALID_HANDLE = $C0000008;
  50. STATUS_NO_MEMORY = $C0000017;
  51. STATUS_ILLEGAL_INSTRUCTION = $C000001D;
  52. STATUS_NONCONTINUABLE_EXCEPTION = $C0000025;
  53. STATUS_INVALID_DISPOSITION = $C0000026;
  54. STATUS_ARRAY_BOUNDS_EXCEEDED = $C000008C;
  55. STATUS_FLOAT_DENORMAL_OPERAND = $C000008D;
  56. STATUS_FLOAT_DIVIDE_BY_ZERO = $C000008E;
  57. STATUS_FLOAT_INEXACT_RESULT = $C000008F;
  58. STATUS_FLOAT_INVALID_OPERATION = $C0000090;
  59. STATUS_FLOAT_OVERFLOW = $C0000091;
  60. STATUS_FLOAT_STACK_CHECK = $C0000092;
  61. STATUS_FLOAT_UNDERFLOW = $C0000093;
  62. STATUS_INTEGER_DIVIDE_BY_ZERO = $C0000094;
  63. STATUS_INTEGER_OVERFLOW = $C0000095;
  64. STATUS_PRIVILEGED_INSTRUCTION = $C0000096;
  65. STATUS_STACK_OVERFLOW = $C00000FD;
  66. STATUS_CONTROL_C_EXIT = $C000013A;
  67. STATUS_FLOAT_MULTIPLE_FAULTS = $C00002B4;
  68. STATUS_FLOAT_MULTIPLE_TRAPS = $C00002B5;
  69. STATUS_REG_NAT_CONSUMPTION = $C00002C9;
  70. { Exceptions raised by RTL use this code }
  71. FPC_EXCEPTION_CODE = $E0465043;
  72. EXCEPTION_EXECUTE_HANDLER = 1;
  73. EXCEPTION_CONTINUE_EXECUTION = -1;
  74. EXCEPTION_CONTINUE_SEARCH = 0;
  75. { exception flags (not everything applies to Win32!) }
  76. EXCEPTION_NONCONTINUABLE = $01;
  77. EXCEPTION_UNWINDING = $02;
  78. EXCEPTION_EXIT_UNWIND = $04;
  79. EXCEPTION_STACK_INVALID = $08;
  80. EXCEPTION_NESTED_CALL = $10;
  81. EXCEPTION_TARGET_UNWIND = $20;
  82. EXCEPTION_COLLIDED_UNWIND = $40;
  83. CONTEXT_X86 = $00010000;
  84. CONTEXT_CONTROL = CONTEXT_X86 or $00000001;
  85. CONTEXT_INTEGER = CONTEXT_X86 or $00000002;
  86. CONTEXT_SEGMENTS = CONTEXT_X86 or $00000004;
  87. CONTEXT_FLOATING_POINT = CONTEXT_X86 or $00000008;
  88. CONTEXT_DEBUG_REGISTERS = CONTEXT_X86 or $00000010;
  89. CONTEXT_EXTENDED_REGISTERS = CONTEXT_X86 or $00000020;
  90. CONTEXT_FULL = CONTEXT_CONTROL or CONTEXT_INTEGER or CONTEXT_SEGMENTS;
  91. MAXIMUM_SUPPORTED_EXTENSION = 512;
  92. type
  93. EXCEPTION_DISPOSITION=(
  94. ExceptionContinueExecution,
  95. ExceptionContinueSearch,
  96. ExceptionNestedException,
  97. ExceptionCollidedUnwind
  98. );
  99. TUnwindProc=procedure(frame: PtrUInt);
  100. PFilterRec=^TFilterRec;
  101. TFilterRec=record
  102. RvaClass: DWord;
  103. RvaHandler: DWord;
  104. end;
  105. TExceptObjProc=function(code: Longint; const rec: TExceptionRecord): Pointer; { Exception }
  106. TExceptClsProc=function(code: Longint): Pointer; { ExceptClass }
  107. procedure RaiseException(
  108. dwExceptionCode: DWORD;
  109. dwExceptionFlags: DWORD;
  110. dwArgCount: DWORD;
  111. lpArguments: Pointer); // msdn: *ULONG_PTR
  112. stdcall; external 'kernel32.dll' name 'RaiseException';
  113. function RunErrorCode(const rec: TExceptionRecord): longint;
  114. begin
  115. { negative result means 'FPU reset required' }
  116. case rec.ExceptionCode of
  117. STATUS_INTEGER_DIVIDE_BY_ZERO: result := 200; { reDivByZero }
  118. STATUS_FLOAT_DIVIDE_BY_ZERO: result := -208; { !!reZeroDivide }
  119. STATUS_ARRAY_BOUNDS_EXCEEDED: result := 201; { reRangeError }
  120. STATUS_STACK_OVERFLOW: result := 202; { reStackOverflow }
  121. STATUS_FLOAT_OVERFLOW: result := -205; { reOverflow }
  122. STATUS_FLOAT_DENORMAL_OPERAND,
  123. STATUS_FLOAT_UNDERFLOW: result := -206; { reUnderflow }
  124. STATUS_FLOAT_INEXACT_RESULT,
  125. STATUS_FLOAT_INVALID_OPERATION,
  126. STATUS_FLOAT_STACK_CHECK: result := -207; { reInvalidOp }
  127. STATUS_INTEGER_OVERFLOW: result := 215; { reIntOverflow }
  128. STATUS_ILLEGAL_INSTRUCTION: result := -216;
  129. STATUS_ACCESS_VIOLATION: result := 216; { reAccessViolation }
  130. STATUS_CONTROL_C_EXIT: result := 217; { reControlBreak }
  131. STATUS_PRIVILEGED_INSTRUCTION: result := 218; { rePrivilegedInstruction }
  132. STATUS_FLOAT_MULTIPLE_TRAPS,
  133. STATUS_FLOAT_MULTIPLE_FAULTS: result := -255; { indicate FPU reset }
  134. else
  135. result := 255; { reExternalException }
  136. end;
  137. end;
  138. procedure TranslateMxcsr(mxcsr: longword; var code: longint);
  139. begin
  140. { we can return only one value, further one's are lost }
  141. { InvalidOp }
  142. if (mxcsr and 1)<>0 then
  143. code:=-207
  144. { Denormal }
  145. else if (mxcsr and 2)<>0 then
  146. code:=-206
  147. { !!reZeroDivide }
  148. else if (mxcsr and 4)<>0 then
  149. code:=-208
  150. { reOverflow }
  151. else if (mxcsr and 8)<>0 then
  152. code:=-205
  153. { Underflow }
  154. else if (mxcsr and 16)<>0 then
  155. code:=-206
  156. { Precision }
  157. else if (mxcsr and 32)<>0 then
  158. code:=-207
  159. else { this should not happen }
  160. code:=-255
  161. end;
  162. function FilterException(var rec:TExceptionRecord; imagebase: PtrUInt; filterRva: DWord; errcode: Longint): Pointer;
  163. var
  164. ExClass: TClass;
  165. i: Longint;
  166. Filter: Pointer;
  167. curFilt: PFilterRec;
  168. begin
  169. result:=nil;
  170. if rec.ExceptionCode=FPC_EXCEPTION_CODE then
  171. ExClass:=TObject(rec.ExceptionInformation[1]).ClassType
  172. else if Assigned(ExceptClsProc) then
  173. ExClass:=TClass(TExceptClsProc(ExceptClsProc)(errcode))
  174. else
  175. Exit; { if we cannot determine type of exception, don't handle it }
  176. Filter:=Pointer(imagebase+filterRva);
  177. for i:=0 to PLongint(Filter)^-1 do
  178. begin
  179. CurFilt:=@PFilterRec(Filter+sizeof(Longint))[i];
  180. if (CurFilt^.RvaClass=$FFFFFFFF) or
  181. { TODO: exception might be coming from another module, need more advanced comparing }
  182. (ExClass.InheritsFrom(TClass(imagebase+CurFilt^.RvaClass))) then
  183. begin
  184. result:=Pointer(imagebase+CurFilt^.RvaHandler);
  185. exit;
  186. end;
  187. end;
  188. end;
  189. {*****************************************************************************
  190. Parameter Handling
  191. *****************************************************************************}
  192. procedure setup_arguments;
  193. var
  194. arglen,
  195. count : longint;
  196. argstart,
  197. pc,arg : pchar;
  198. quote : Boolean;
  199. argvlen : longint;
  200. buf: array[0..259] of char; // need MAX_PATH bytes, not 256!
  201. procedure allocarg(idx,len:longint);
  202. var
  203. oldargvlen : longint;
  204. begin
  205. if idx>=argvlen then
  206. begin
  207. oldargvlen:=argvlen;
  208. argvlen:=(idx+8) and (not 7);
  209. sysreallocmem(argv,argvlen*sizeof(pointer));
  210. fillchar(argv[oldargvlen],(argvlen-oldargvlen)*sizeof(pointer),0);
  211. end;
  212. { use realloc to reuse already existing memory }
  213. { always allocate, even if length is zero, since }
  214. { the arg. is still present! }
  215. sysreallocmem(argv[idx],len+1);
  216. end;
  217. begin
  218. { create commandline, it starts with the executed filename which is argv[0] }
  219. { Win32 passes the command NOT via the args, but via getmodulefilename}
  220. count:=0;
  221. argv:=nil;
  222. argvlen:=0;
  223. ArgLen := GetModuleFileName(0, @buf[0], sizeof(buf));
  224. buf[ArgLen] := #0; // be safe
  225. allocarg(0,arglen);
  226. move(buf,argv[0]^,arglen+1);
  227. { Setup cmdline variable }
  228. cmdline:=GetCommandLine;
  229. { process arguments }
  230. pc:=cmdline;
  231. {$IfDef SYSTEM_DEBUG_STARTUP}
  232. Writeln(stderr,'Win32 GetCommandLine is #',pc,'#');
  233. {$EndIf }
  234. while pc^<>#0 do
  235. begin
  236. { skip leading spaces }
  237. while pc^ in [#1..#32] do
  238. inc(pc);
  239. if pc^=#0 then
  240. break;
  241. { calc argument length }
  242. quote:=False;
  243. argstart:=pc;
  244. arglen:=0;
  245. while (pc^<>#0) do
  246. begin
  247. case pc^ of
  248. #1..#32 :
  249. begin
  250. if quote then
  251. inc(arglen)
  252. else
  253. break;
  254. end;
  255. '"' :
  256. if pc[1]<>'"' then
  257. quote := not quote
  258. else
  259. inc(pc);
  260. else
  261. inc(arglen);
  262. end;
  263. inc(pc);
  264. end;
  265. { copy argument }
  266. { Don't copy the first one, it is already there.}
  267. If Count<>0 then
  268. begin
  269. allocarg(count,arglen);
  270. quote:=False;
  271. pc:=argstart;
  272. arg:=argv[count];
  273. while (pc^<>#0) do
  274. begin
  275. case pc^ of
  276. #1..#32 :
  277. begin
  278. if quote then
  279. begin
  280. arg^:=pc^;
  281. inc(arg);
  282. end
  283. else
  284. break;
  285. end;
  286. '"' :
  287. if pc[1]<>'"' then
  288. quote := not quote
  289. else
  290. inc(pc);
  291. else
  292. begin
  293. arg^:=pc^;
  294. inc(arg);
  295. end;
  296. end;
  297. inc(pc);
  298. end;
  299. arg^:=#0;
  300. end;
  301. {$IfDef SYSTEM_DEBUG_STARTUP}
  302. Writeln(stderr,'dos arg ',count,' #',arglen,'#',argv[count],'#');
  303. {$EndIf SYSTEM_DEBUG_STARTUP}
  304. inc(count);
  305. end;
  306. { get argc }
  307. argc:=count;
  308. { free unused memory, leaving a nil entry at the end }
  309. sysreallocmem(argv,(count+1)*sizeof(pointer));
  310. argv[count] := nil;
  311. end;
  312. function paramcount : longint;
  313. begin
  314. paramcount := argc - 1;
  315. end;
  316. function paramstr(l : longint) : string;
  317. begin
  318. if (l>=0) and (l<argc) then
  319. paramstr:=strpas(argv[l])
  320. else
  321. paramstr:='';
  322. end;
  323. procedure randomize;
  324. begin
  325. randseed:=GetTickCount;
  326. end;
  327. Var
  328. DLLInitState : Longint = -1;
  329. DLLBuf : Jmp_buf;
  330. {$if defined(FPC_USE_WIN32_SEH) or defined(FPC_USE_WIN64_SEH)}
  331. {$define FPC_USE_SEH}
  332. {$endif}
  333. function Dll_entry{$ifdef FPC_HAS_INDIRECT_ENTRY_INFORMATION}(constref info : TEntryInformation){$endif FPC_HAS_INDIRECT_ENTRY_INFORMATION} : longbool; [public,alias:'_FPC_DLL_Entry'];
  334. begin
  335. {$ifdef FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  336. SetupEntryInformation(info);
  337. {$endif FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  338. IsLibrary:=true;
  339. DllInitState:=DLLreason;
  340. Dll_entry:=false; { return value is ignored, except when DLLreason=DLL_PROCESS_ATTACH }
  341. case DLLreason of
  342. DLL_PROCESS_ATTACH :
  343. begin
  344. MainThreadIdWin32 := Win32GetCurrentThreadId;
  345. If SetJmp(DLLBuf) = 0 then
  346. begin
  347. {$ifdef FPC_USE_SEH}
  348. try
  349. {$endif}
  350. {$ifdef FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  351. EntryInformation.PascalMain();
  352. {$else FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  353. PascalMain;
  354. {$endif FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  355. Dll_entry:=true;
  356. {$ifdef FPC_USE_SEH}
  357. except
  358. DoUnHandledException;
  359. Dll_entry:=false;
  360. end;
  361. {$endif}
  362. end
  363. else
  364. Dll_entry:=(ExitCode=0);
  365. end;
  366. DLL_THREAD_ATTACH :
  367. begin
  368. { SysInitMultithreading must not be called here,
  369. see comments in exec_tls_callback below }
  370. { Allocate Threadvars }
  371. SysAllocateThreadVars;
  372. { NS : no idea what is correct to pass here - pass dummy value for now }
  373. { passing a dummy is ok, the correct value is read from the coff header of SysInstance (FK) }
  374. InitThread($1000000); { Assume everything is idempotent there, as the thread could have been created with BeginThread... }
  375. if assigned(Dll_Thread_Attach_Hook) then
  376. Dll_Thread_Attach_Hook(DllParam);
  377. end;
  378. DLL_THREAD_DETACH :
  379. begin
  380. if assigned(Dll_Thread_Detach_Hook) then
  381. Dll_Thread_Detach_Hook(DllParam);
  382. { Release Threadvars }
  383. if TlsGetValue(TLSKey^)<>nil then
  384. DoneThread; { Assume everything is idempotent there }
  385. end;
  386. DLL_PROCESS_DETACH :
  387. begin
  388. if MainThreadIDWin32=0 then // already been here.
  389. exit;
  390. If SetJmp(DLLBuf) = 0 then
  391. begin
  392. if assigned(Dll_Process_Detach_Hook) then
  393. Dll_Process_Detach_Hook(DllParam);
  394. InternalExit;
  395. end;
  396. SysReleaseThreadVars;
  397. { Free TLS resources used by ThreadVars }
  398. SysFiniMultiThreading;
  399. MainThreadIDWin32:=0;
  400. end;
  401. end;
  402. DllInitState:=-1;
  403. end;
  404. {****************************************************************************
  405. Error Message writing using messageboxes
  406. ****************************************************************************}
  407. function MessageBox(w1:THandle;l1,l2:pointer;w2:longint):longint;
  408. stdcall;external 'user32' name 'MessageBoxA';
  409. const
  410. ErrorBufferLength = 1024;
  411. var
  412. ErrorBuf : array[0..ErrorBufferLength] of char;
  413. ErrorLen : SizeInt;
  414. procedure ErrorWrite(Var F: TextRec);
  415. {
  416. An error message should always end with #13#10#13#10
  417. }
  418. var
  419. i : SizeInt;
  420. Begin
  421. while F.BufPos>0 do
  422. begin
  423. begin
  424. if F.BufPos+ErrorLen>ErrorBufferLength then
  425. i:=ErrorBufferLength-ErrorLen
  426. else
  427. i:=F.BufPos;
  428. Move(F.BufPtr^,ErrorBuf[ErrorLen],i);
  429. inc(ErrorLen,i);
  430. ErrorBuf[ErrorLen]:=#0;
  431. end;
  432. if ErrorLen=ErrorBufferLength then
  433. begin
  434. if not NoErrMsg then
  435. MessageBox(0,@ErrorBuf,pchar('Error'),0);
  436. ErrorLen:=0;
  437. end;
  438. Dec(F.BufPos,i);
  439. end;
  440. End;
  441. procedure ErrorClose(Var F: TextRec);
  442. begin
  443. if ErrorLen>0 then
  444. begin
  445. MessageBox(0,@ErrorBuf,pchar('Error'),0);
  446. ErrorLen:=0;
  447. end;
  448. ErrorLen:=0;
  449. end;
  450. procedure ErrorOpen(Var F: TextRec);
  451. Begin
  452. TextRec(F).InOutFunc:=@ErrorWrite;
  453. TextRec(F).FlushFunc:=@ErrorWrite;
  454. TextRec(F).CloseFunc:=@ErrorClose;
  455. ErrorLen:=0;
  456. End;
  457. procedure AssignError(Var T: Text);
  458. begin
  459. Assign(T,'');
  460. TextRec(T).OpenFunc:=@ErrorOpen;
  461. Rewrite(T);
  462. end;
  463. procedure SysInitStdIO;
  464. begin
  465. { Setup stdin, stdout and stderr, for GUI apps redirect stderr,stdout to be
  466. displayed in a messagebox }
  467. { WARNING: this should be done only once at startup,
  468. not for DLL entry code, as the standard handles might
  469. have been redirected }
  470. if StdInputHandle=0 then
  471. StdInputHandle:=THandle(GetStdHandle(cardinal(STD_INPUT_HANDLE)));
  472. if StdOutputHandle=0 then
  473. StdOutputHandle:=THandle(GetStdHandle(cardinal(STD_OUTPUT_HANDLE)));
  474. if StdErrorHandle=0 then
  475. StdErrorHandle:=THandle(GetStdHandle(cardinal(STD_ERROR_HANDLE)));
  476. if not IsConsole then
  477. begin
  478. AssignError(stderr);
  479. AssignError(StdOut);
  480. Assign(Output,'');
  481. Assign(Input,'');
  482. Assign(ErrOutput,'');
  483. end
  484. else
  485. begin
  486. OpenStdIO(Input,fmInput,StdInputHandle);
  487. OpenStdIO(Output,fmOutput,StdOutputHandle);
  488. OpenStdIO(ErrOutput,fmOutput,StdErrorHandle);
  489. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  490. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  491. end;
  492. end;
  493. { ProcessID cached to avoid repeated calls to GetCurrentProcess. }
  494. var
  495. ProcessID: SizeUInt;
  496. function GetProcessID: SizeUInt;
  497. begin
  498. GetProcessID := ProcessID;
  499. end;
  500. {******************************************************************************
  501. Unicode
  502. ******************************************************************************}
  503. const
  504. { MultiByteToWideChar }
  505. MB_PRECOMPOSED = 1;
  506. WC_NO_BEST_FIT_CHARS = $400;
  507. function MultiByteToWideChar(CodePage:UINT; dwFlags:DWORD; lpMultiByteStr:PChar; cchMultiByte:longint; lpWideCharStr:PWideChar;cchWideChar:longint):longint;
  508. stdcall; external 'kernel32' name 'MultiByteToWideChar';
  509. function WideCharToMultiByte(CodePage:UINT; dwFlags:DWORD; lpWideCharStr:PWideChar; cchWideChar:longint; lpMultiByteStr:PChar;cchMultiByte:longint; lpDefaultChar:PChar; lpUsedDefaultChar:pointer):longint;
  510. stdcall; external 'kernel32' name 'WideCharToMultiByte';
  511. function CharUpperBuff(lpsz:LPWSTR; cchLength:DWORD):DWORD;
  512. stdcall; external 'user32' name 'CharUpperBuffW';
  513. function CharLowerBuff(lpsz:LPWSTR; cchLength:DWORD):DWORD;
  514. stdcall; external 'user32' name 'CharLowerBuffW';
  515. procedure Win32Unicode2AnsiMove(source:punicodechar;var dest:RawByteString;cp : TSystemCodePage;len:SizeInt);
  516. var
  517. destlen: SizeInt;
  518. begin
  519. // retrieve length including trailing #0
  520. // not anymore, because this must also be usable for single characters
  521. destlen:=WideCharToMultiByte(cp, 0, source, len, nil, 0, nil, nil);
  522. // this will null-terminate
  523. setlength(dest, destlen);
  524. if destlen>0 then
  525. begin
  526. WideCharToMultiByte(cp, 0, source, len, @dest[1], destlen, nil, nil);
  527. PAnsiRec(pointer(dest)-AnsiFirstOff)^.CodePage:=cp;
  528. end;
  529. end;
  530. procedure Win32Ansi2UnicodeMove(source:pchar;cp : TSystemCodePage;var dest:UnicodeString;len:SizeInt);
  531. var
  532. destlen: SizeInt;
  533. dwflags: DWORD;
  534. begin
  535. // retrieve length including trailing #0
  536. // not anymore, because this must also be usable for single characters
  537. case cp of
  538. // Under https://docs.microsoft.com/en-us/windows/desktop/api/stringapiset/nf-stringapiset-multibytetowidechar
  539. CP_UTF8, CP_UTF7, 50220, 50221, 50222, 50225, 50227, 50229, 57002..57011, 42:
  540. dwFlags:=0
  541. else
  542. dwFlags:=MB_PRECOMPOSED;
  543. end;
  544. destlen:=MultiByteToWideChar(cp, dwFlags, source, len, nil, 0);
  545. // this will null-terminate
  546. setlength(dest, destlen);
  547. if destlen>0 then
  548. begin
  549. MultiByteToWideChar(cp, dwFlags, source, len, @dest[1], destlen);
  550. PUnicodeRec(pointer(dest)-UnicodeFirstOff)^.CodePage:=CP_UTF16;
  551. end;
  552. end;
  553. function Win32UnicodeUpper(const s : UnicodeString) : UnicodeString;
  554. begin
  555. result:=s;
  556. UniqueString(result);
  557. if length(result)>0 then
  558. CharUpperBuff(LPWSTR(result),length(result));
  559. end;
  560. function Win32UnicodeLower(const s : UnicodeString) : UnicodeString;
  561. begin
  562. result:=s;
  563. UniqueString(result);
  564. if length(result)>0 then
  565. CharLowerBuff(LPWSTR(result),length(result));
  566. end;
  567. {******************************************************************************
  568. Widestring
  569. ******************************************************************************}
  570. procedure Win32Ansi2WideMove(source:pchar;cp : TSystemCodePage;var dest:widestring;len:SizeInt);
  571. var
  572. destlen: SizeInt;
  573. dwFlags: DWORD;
  574. begin
  575. // retrieve length including trailing #0
  576. // not anymore, because this must also be usable for single characters
  577. if cp=CP_UTF8 then
  578. dwFlags:=0
  579. else
  580. dwFlags:=MB_PRECOMPOSED;
  581. destlen:=MultiByteToWideChar(cp, dwFlags, source, len, nil, 0);
  582. // this will null-terminate
  583. setlength(dest, destlen);
  584. if destlen>0 then
  585. MultiByteToWideChar(cp, dwFlags, source, len, @dest[1], destlen);
  586. end;
  587. function Win32WideUpper(const s : WideString) : WideString;
  588. begin
  589. result:=s;
  590. if length(result)>0 then
  591. CharUpperBuff(LPWSTR(result),length(result));
  592. end;
  593. function Win32WideLower(const s : WideString) : WideString;
  594. begin
  595. result:=s;
  596. if length(result)>0 then
  597. CharLowerBuff(LPWSTR(result),length(result));
  598. end;
  599. type
  600. PWStrInitEntry = ^TWStrInitEntry;
  601. TWStrInitEntry = record
  602. addr: PPointer;
  603. data: Pointer;
  604. end;
  605. PWStrInitTablesTable = ^TWStrInitTablesTable;
  606. TWStrInitTablesTable = packed record
  607. count : {$ifdef VER2_6}longint{$else}sizeint{$endif};
  608. tables : packed array [1..32767] of PWStrInitEntry;
  609. end;
  610. var
  611. {$ifdef FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  612. WStrInitTablesTable: PWStrInitTablesTable;
  613. {$else FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  614. WStrInitTablesTableVar: TWStrInitTablesTable; external name 'FPC_WIDEINITTABLES';
  615. WStrInitTablesTable: PWStrInitTablesTable = @WStrInitTablesTableVar;
  616. {$endif FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  617. function GetACP:UINT; stdcall; external 'kernel32' name 'GetACP';
  618. function GetConsoleCP:UINT; stdcall; external 'kernel32' name 'GetConsoleCP';
  619. function Win32GetStandardCodePage(const stdcp: TStandardCodePageEnum): TSystemCodePage;
  620. begin
  621. case stdcp of
  622. scpAnsi,
  623. scpFileSystemSingleByte: Result := GetACP;
  624. scpConsoleInput: Result := GetConsoleCP;
  625. scpConsoleOutput: Result := GetConsoleOutputCP;
  626. end;
  627. end;
  628. { there is a similiar procedure in sysutils which inits the fields which
  629. are only relevant for the sysutils units }
  630. procedure InitWin32Widestrings;
  631. var
  632. i: longint;
  633. ptable: PWStrInitEntry;
  634. begin
  635. {$if not(defined(VER2_2) or defined(VER2_4))}
  636. { assign initial values to global Widestring typed consts }
  637. for i:=1 to WStrInitTablesTable^.count do
  638. begin
  639. ptable:=WStrInitTablesTable^.tables[i];
  640. while Assigned(ptable^.addr) do
  641. begin
  642. fpc_widestr_assign(ptable^.addr^, ptable^.data);
  643. Inc(ptable);
  644. end;
  645. end;
  646. {$endif}
  647. { Note: since WideChar=UnicodeChar and PWideChar=PUnicodeChar,
  648. Wide2AnsiMoveProc is identical to Unicode2AnsiStrMoveProc. }
  649. { Widestring }
  650. widestringmanager.Wide2AnsiMoveProc:=@Win32Unicode2AnsiMove;
  651. widestringmanager.Ansi2WideMoveProc:=@Win32Ansi2WideMove;
  652. widestringmanager.UpperWideStringProc:=@Win32WideUpper;
  653. widestringmanager.LowerWideStringProc:=@Win32WideLower;
  654. { Unicode }
  655. widestringmanager.Unicode2AnsiMoveProc:=@Win32Unicode2AnsiMove;
  656. widestringmanager.Ansi2UnicodeMoveProc:=@Win32Ansi2UnicodeMove;
  657. widestringmanager.UpperUnicodeStringProc:=@Win32UnicodeUpper;
  658. widestringmanager.LowerUnicodeStringProc:=@Win32UnicodeLower;
  659. { Codepage }
  660. widestringmanager.GetStandardCodePageProc:=@Win32GetStandardCodePage;
  661. DefaultSystemCodePage:=GetACP;
  662. DefaultUnicodeCodePage:=CP_UTF16;
  663. DefaultFileSystemCodePage:=CP_UTF8;
  664. DefaultRTLFileSystemCodePage:=DefaultSystemCodePage;
  665. end;
  666. type
  667. WINBOOL = longbool;
  668. PHANDLER_ROUTINE = function (dwCtrlType:DWORD):WINBOOL; stdcall;
  669. function SetConsoleCtrlHandler(HandlerRoutine:PHANDLER_ROUTINE; Add:WINBOOL):WINBOOL; stdcall;
  670. external 'kernel32' name 'SetConsoleCtrlHandler';
  671. function WinCtrlBreakHandler(dwCtrlType:DWORD): WINBOOL;stdcall;
  672. const
  673. CTRL_BREAK_EVENT = 1;
  674. begin
  675. if Assigned(CtrlBreakHandler) then
  676. Result:=CtrlBreakHandler((dwCtrlType and CTRL_BREAK_EVENT > 0))
  677. else
  678. Result:=false;
  679. end;
  680. function SysSetCtrlBreakHandler (Handler: TCtrlBreakHandler): TCtrlBreakHandler;
  681. begin
  682. (* Return either nil or previous handler *)
  683. if (Assigned(CtrlBreakHandler)) and (not Assigned(Handler)) then
  684. SetConsoleCtrlHandler(@WinCtrlBreakHandler, false)
  685. else if (not Assigned(CtrlBreakHandler)) and (Assigned(Handler)) then
  686. SetConsoleCtrlHandler(@WinCtrlBreakHandler, true);
  687. SysSetCtrlBreakHandler := CtrlBreakHandler;
  688. CtrlBreakHandler := Handler;
  689. end;