syswin.inc 24 KB

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