syswin.inc 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794
  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({$if not defined(ver3_0) and not defined(ver3_2)}PClass(imagebase+CurFilt^.RvaClass)^{$else}TClass(imagebase+CurFilt^.RvaClass){$endif})) then
  177. begin
  178. result:=Pointer(imagebase+CurFilt^.RvaHandler);
  179. exit;
  180. end;
  181. end;
  182. end;
  183. {*****************************************************************************
  184. Parameter Handling
  185. *****************************************************************************}
  186. var
  187. argvw: PPWideChar;
  188. procedure setup_arguments;
  189. var
  190. CmdLineW, pw: PWideChar;
  191. c: WideChar;
  192. buf: array[0..MaxPathLen] of WideChar;
  193. i, len, argvw_size: longint;
  194. s: RawByteString;
  195. quote: boolean;
  196. begin
  197. // Get the unicode command line
  198. CmdLineW:=GetCommandLineW;
  199. // Create the ansi command line
  200. s:=ansistring(CmdLineW);
  201. len:=Length(s) + 1;
  202. CmdLine:=SysGetMem(len);
  203. Move(PAnsiChar(s)^, CmdLine^, len);
  204. // Alloc initial space for argvw
  205. if CmdLineW^ = #0 then
  206. argvw_size:=2
  207. else
  208. argvw_size:=10;
  209. argvw:=SysGetMem(argvw_size*SizeOf(pointer));
  210. // Get the full module name to be used as the first argument
  211. len:=GetModuleFileNameW(0, @buf, Length(buf));
  212. // Alloc maximum possible space for all arguments
  213. pw:=SysGetMem((len + IndexWord(CmdLineW^, High(longint), 0) + 2)*SizeOf(WideChar));
  214. // Copy the module name as the first argument. It will be nil terminated later
  215. Move(buf, pw^, len*SizeOf(WideChar));
  216. argvw[0]:=pw;
  217. Inc(pw, len);
  218. // Parse the command line
  219. argc:=0;
  220. quote:=False;
  221. while True do
  222. begin
  223. c:=CmdLineW^;
  224. Inc(CmdLineW);
  225. case c of
  226. #0..#32:
  227. if not quote or (c = #0) then
  228. begin
  229. // Are there any chars of an argument?
  230. if argvw[argc] <> pw then
  231. begin
  232. // End of an argument found
  233. pw^:=#0;
  234. Inc(pw);
  235. Inc(argc);
  236. if argc = argvw_size then
  237. begin
  238. // Increase the argvw space
  239. Inc(argvw_size, argvw_size shr 1);
  240. SysReAllocMem(argvw, argvw_size*SizeOf(pointer));
  241. end;
  242. if c = #0 then
  243. break;
  244. argvw[argc]:=pw;
  245. continue;
  246. end
  247. else
  248. if c = #0 then
  249. break
  250. else
  251. continue; // Skip whitespace
  252. end;
  253. '"':
  254. begin
  255. quote:=not quote;
  256. continue;
  257. end;
  258. end;
  259. // Ignore the first argument, it is already copied
  260. if argc <> 0 then
  261. begin
  262. // Copy the argument's char
  263. pw^:=c;
  264. Inc(pw);
  265. end;
  266. end;
  267. // Finalization
  268. // argvw is terminated by nil
  269. argvw[argc]:=nil;
  270. // Trim the memory
  271. SysReAllocMem(argvw, (argc + 1)*SizeOf(pointer));
  272. SysReAllocMem(argvw[0], ptruint(pw) - ptruint(argvw[0]));
  273. // Construct the ansi argv
  274. argv:=SysGetMem((argc + 1)*SizeOf(pointer));
  275. for i:=0 to argc - 1 do
  276. begin
  277. // Convert argvw[i] to argv[i]
  278. s:=ansistring(argvw[i]);
  279. len:=Length(s) + 1;
  280. argv[i]:=SysGetMem(len);
  281. Move(s[1], argv[i]^, len);
  282. end;
  283. // argv is terminated by nil
  284. argv[argc]:=nil;
  285. end;
  286. procedure finalize_arguments;
  287. var
  288. i: longint;
  289. begin
  290. SysFreeMem(CmdLine);
  291. // Free unicode arguments
  292. SysFreeMem(argvw[0]);
  293. SysFreeMem(argvw);
  294. // Free ansi arguments
  295. for i:=0 to argc - 1 do
  296. SysFreeMem(argv[i]);
  297. SysFreeMem(argv);
  298. end;
  299. function paramcount : longint;
  300. begin
  301. paramcount := argc - 1;
  302. end;
  303. Function ParamStrU(l:Longint): UnicodeString; [public,alias:'_FPC_ParamStrU'];
  304. begin
  305. if (l >= 0) and (l < argc) then
  306. Result:=argvw[l]
  307. else
  308. Result:='';
  309. end;
  310. Function ParamStrA(l:Longint): AnsiString; [public,alias:'_FPC_ParamStrA'];
  311. begin
  312. Result:=AnsiString(ParamStrU(l));
  313. end;
  314. Function ParamStr(l:Longint): string;
  315. begin
  316. if (l >= 0) and (l < argc) then
  317. Result:=argv[l]
  318. else
  319. Result:='';
  320. end;
  321. {*****************************************************************************}
  322. procedure randomize;
  323. begin
  324. randseed:=GetTickCount;
  325. end;
  326. Var
  327. DLLInitState : Longint = -1;
  328. DLLBuf : Jmp_buf;
  329. {$if defined(FPC_USE_WIN32_SEH) or defined(FPC_USE_WIN64_SEH)}
  330. {$define FPC_USE_SEH}
  331. {$endif}
  332. function Dll_entry{$ifdef FPC_HAS_INDIRECT_ENTRY_INFORMATION}(constref info : TEntryInformation){$endif FPC_HAS_INDIRECT_ENTRY_INFORMATION} : longbool; [public,alias:'_FPC_DLL_Entry'];
  333. begin
  334. {$ifdef FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  335. SetupEntryInformation(info);
  336. {$endif FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  337. IsLibrary:=true;
  338. DllInitState:=DLLreason;
  339. Dll_entry:=false; { return value is ignored, except when DLLreason=DLL_PROCESS_ATTACH }
  340. case DLLreason of
  341. DLL_PROCESS_ATTACH :
  342. begin
  343. MainThreadIdWin32 := Win32GetCurrentThreadId;
  344. If SetJmp(DLLBuf) = 0 then
  345. begin
  346. {$ifdef FPC_USE_SEH}
  347. try
  348. {$endif}
  349. {$ifdef FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  350. EntryInformation.PascalMain();
  351. {$else FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  352. PascalMain;
  353. {$endif FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  354. Dll_entry:=true;
  355. {$ifdef FPC_USE_SEH}
  356. except
  357. DoUnHandledException;
  358. Dll_entry:=false;
  359. end;
  360. {$endif}
  361. end
  362. else
  363. Dll_entry:=(ExitCode=0);
  364. end;
  365. DLL_THREAD_ATTACH :
  366. begin
  367. { SysInitMultithreading must not be called here,
  368. see comments in exec_tls_callback below }
  369. { Allocate Threadvars }
  370. SysAllocateThreadVars;
  371. { NS : no idea what is correct to pass here - pass dummy value for now }
  372. { passing a dummy is ok, the correct value is read from the coff header of SysInstance (FK) }
  373. InitThread($1000000); { Assume everything is idempotent there, as the thread could have been created with BeginThread... }
  374. if assigned(Dll_Thread_Attach_Hook) then
  375. Dll_Thread_Attach_Hook(DllParam);
  376. end;
  377. DLL_THREAD_DETACH :
  378. begin
  379. if assigned(Dll_Thread_Detach_Hook) then
  380. Dll_Thread_Detach_Hook(DllParam);
  381. { Release Threadvars }
  382. if TlsGetValue(TLSKey^)<>nil then
  383. DoneThread; { Assume everything is idempotent there }
  384. end;
  385. DLL_PROCESS_DETACH :
  386. begin
  387. if MainThreadIDWin32=0 then // already been here.
  388. exit;
  389. If SetJmp(DLLBuf) = 0 then
  390. begin
  391. if assigned(Dll_Process_Detach_Hook) then
  392. Dll_Process_Detach_Hook(DllParam);
  393. InternalExit;
  394. end;
  395. SysReleaseThreadVars;
  396. { Free TLS resources used by ThreadVars }
  397. SysFiniMultiThreading;
  398. MainThreadIDWin32:=0;
  399. end;
  400. end;
  401. DllInitState:=-1;
  402. end;
  403. {****************************************************************************
  404. Error Message writing using messageboxes
  405. ****************************************************************************}
  406. function MessageBox(w1:THandle;l1,l2:pointer;w2:longint):longint;
  407. stdcall;external 'user32' name 'MessageBoxA';
  408. const
  409. ErrorBufferLength = 1024;
  410. var
  411. ErrorBuf : array[0..ErrorBufferLength] of char;
  412. ErrorLen : SizeInt;
  413. procedure ErrorWrite(Var F: TextRec);
  414. {
  415. An error message should always end with #13#10#13#10
  416. }
  417. var
  418. i : SizeInt;
  419. Begin
  420. while F.BufPos>0 do
  421. begin
  422. begin
  423. if F.BufPos+ErrorLen>ErrorBufferLength then
  424. i:=ErrorBufferLength-ErrorLen
  425. else
  426. i:=F.BufPos;
  427. Move(F.BufPtr^,ErrorBuf[ErrorLen],i);
  428. inc(ErrorLen,i);
  429. ErrorBuf[ErrorLen]:=#0;
  430. end;
  431. if ErrorLen=ErrorBufferLength then
  432. begin
  433. if not NoErrMsg then
  434. MessageBox(0,@ErrorBuf,pchar('Error'),0);
  435. ErrorLen:=0;
  436. end;
  437. Dec(F.BufPos,i);
  438. end;
  439. End;
  440. procedure ErrorClose(Var F: TextRec);
  441. begin
  442. if ErrorLen>0 then
  443. begin
  444. MessageBox(0,@ErrorBuf,pchar('Error'),0);
  445. ErrorLen:=0;
  446. end;
  447. ErrorLen:=0;
  448. end;
  449. procedure ErrorOpen(Var F: TextRec);
  450. Begin
  451. TextRec(F).InOutFunc:=@ErrorWrite;
  452. TextRec(F).FlushFunc:=@ErrorWrite;
  453. TextRec(F).CloseFunc:=@ErrorClose;
  454. ErrorLen:=0;
  455. End;
  456. procedure AssignError(Var T: Text);
  457. begin
  458. Assign(T,'');
  459. TextRec(T).OpenFunc:=@ErrorOpen;
  460. Rewrite(T);
  461. end;
  462. procedure SysInitStdIO;
  463. begin
  464. { Setup stdin, stdout and stderr, for GUI apps redirect stderr,stdout to be
  465. displayed in a messagebox }
  466. { WARNING: this should be done only once at startup,
  467. not for DLL entry code, as the standard handles might
  468. have been redirected }
  469. if StdInputHandle=0 then
  470. StdInputHandle:=THandle(GetStdHandle(cardinal(STD_INPUT_HANDLE)));
  471. if StdOutputHandle=0 then
  472. StdOutputHandle:=THandle(GetStdHandle(cardinal(STD_OUTPUT_HANDLE)));
  473. if StdErrorHandle=0 then
  474. StdErrorHandle:=THandle(GetStdHandle(cardinal(STD_ERROR_HANDLE)));
  475. if not IsConsole then
  476. begin
  477. AssignError(stderr);
  478. AssignError(StdOut);
  479. Assign(Output,'');
  480. Assign(Input,'');
  481. Assign(ErrOutput,'');
  482. end
  483. else
  484. begin
  485. OpenStdIO(Input,fmInput,StdInputHandle);
  486. OpenStdIO(Output,fmOutput,StdOutputHandle);
  487. OpenStdIO(ErrOutput,fmOutput,StdErrorHandle);
  488. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  489. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  490. end;
  491. end;
  492. { ProcessID cached to avoid repeated calls to GetCurrentProcess. }
  493. var
  494. ProcessID: SizeUInt;
  495. function GetProcessID: SizeUInt;
  496. begin
  497. GetProcessID := ProcessID;
  498. end;
  499. {******************************************************************************
  500. Unicode
  501. ******************************************************************************}
  502. const
  503. { MultiByteToWideChar }
  504. MB_PRECOMPOSED = 1;
  505. WC_NO_BEST_FIT_CHARS = $400;
  506. function MultiByteToWideChar(CodePage:UINT; dwFlags:DWORD; lpMultiByteStr:PChar; cchMultiByte:longint; lpWideCharStr:PWideChar;cchWideChar:longint):longint;
  507. stdcall; external 'kernel32' name 'MultiByteToWideChar';
  508. function WideCharToMultiByte(CodePage:UINT; dwFlags:DWORD; lpWideCharStr:PWideChar; cchWideChar:longint; lpMultiByteStr:PChar;cchMultiByte:longint; lpDefaultChar:PChar; lpUsedDefaultChar:pointer):longint;
  509. stdcall; external 'kernel32' name 'WideCharToMultiByte';
  510. function CharUpperBuff(lpsz:LPWSTR; cchLength:DWORD):DWORD;
  511. stdcall; external 'user32' name 'CharUpperBuffW';
  512. function CharLowerBuff(lpsz:LPWSTR; cchLength:DWORD):DWORD;
  513. stdcall; external 'user32' name 'CharLowerBuffW';
  514. procedure Win32Unicode2AnsiMove(source:punicodechar;var dest:RawByteString;cp : TSystemCodePage;len:SizeInt);
  515. var
  516. destlen: SizeInt;
  517. begin
  518. // retrieve length including trailing #0
  519. // not anymore, because this must also be usable for single characters
  520. destlen:=WideCharToMultiByte(cp, 0, source, len, nil, 0, nil, nil);
  521. // this will null-terminate
  522. setlength(dest, destlen);
  523. if destlen>0 then
  524. begin
  525. WideCharToMultiByte(cp, 0, source, len, @dest[1], destlen, nil, nil);
  526. PAnsiRec(pointer(dest)-AnsiFirstOff)^.CodePage:=cp;
  527. end;
  528. end;
  529. procedure Win32Ansi2UnicodeMove(source:pchar;cp : TSystemCodePage;var dest:UnicodeString;len:SizeInt);
  530. var
  531. destlen: SizeInt;
  532. dwflags: DWORD;
  533. begin
  534. // retrieve length including trailing #0
  535. // not anymore, because this must also be usable for single characters
  536. case cp of
  537. // Under https://docs.microsoft.com/en-us/windows/desktop/api/stringapiset/nf-stringapiset-multibytetowidechar
  538. CP_UTF8, CP_UTF7, 50220, 50221, 50222, 50225, 50227, 50229, 57002..57011, 42:
  539. dwFlags:=0
  540. else
  541. dwFlags:=MB_PRECOMPOSED;
  542. end;
  543. destlen:=MultiByteToWideChar(cp, dwFlags, source, len, nil, 0);
  544. { destlen=0 means that Windows cannot convert, so call the default
  545. handler. This is similiar to what unix does and is a good fallback
  546. if rawbyte strings are passed }
  547. if destlen=0 then
  548. begin
  549. DefaultAnsi2UnicodeMove(source,DefaultSystemCodePage,dest,len);
  550. exit;
  551. end;
  552. // this will null-terminate
  553. setlength(dest, destlen);
  554. if destlen>0 then
  555. begin
  556. MultiByteToWideChar(cp, dwFlags, source, len, @dest[1], destlen);
  557. PUnicodeRec(pointer(dest)-UnicodeFirstOff)^.CodePage:=CP_UTF16;
  558. end;
  559. end;
  560. function Win32UnicodeUpper(const s : UnicodeString) : UnicodeString;
  561. begin
  562. result:=s;
  563. UniqueString(result);
  564. if length(result)>0 then
  565. CharUpperBuff(LPWSTR(result),length(result));
  566. end;
  567. function Win32UnicodeLower(const s : UnicodeString) : UnicodeString;
  568. begin
  569. result:=s;
  570. UniqueString(result);
  571. if length(result)>0 then
  572. CharLowerBuff(LPWSTR(result),length(result));
  573. end;
  574. {******************************************************************************
  575. Widestring
  576. ******************************************************************************}
  577. procedure Win32Ansi2WideMove(source:pchar;cp : TSystemCodePage;var dest:widestring;len:SizeInt);
  578. var
  579. destlen: SizeInt;
  580. dwFlags: DWORD;
  581. begin
  582. // retrieve length including trailing #0
  583. // not anymore, because this must also be usable for single characters
  584. if cp=CP_UTF8 then
  585. dwFlags:=0
  586. else
  587. dwFlags:=MB_PRECOMPOSED;
  588. destlen:=MultiByteToWideChar(cp, dwFlags, source, len, nil, 0);
  589. // this will null-terminate
  590. setlength(dest, destlen);
  591. if destlen>0 then
  592. MultiByteToWideChar(cp, dwFlags, source, len, @dest[1], destlen);
  593. end;
  594. function Win32WideUpper(const s : WideString) : WideString;
  595. begin
  596. result:=s;
  597. if length(result)>0 then
  598. CharUpperBuff(LPWSTR(result),length(result));
  599. end;
  600. function Win32WideLower(const s : WideString) : WideString;
  601. begin
  602. result:=s;
  603. if length(result)>0 then
  604. CharLowerBuff(LPWSTR(result),length(result));
  605. end;
  606. type
  607. PWStrInitEntry = ^TWStrInitEntry;
  608. TWStrInitEntry = record
  609. addr: PPointer;
  610. data: Pointer;
  611. end;
  612. PWStrInitTablesTable = ^TWStrInitTablesTable;
  613. TWStrInitTablesTable = packed record
  614. count : {$ifdef VER2_6}longint{$else}sizeint{$endif};
  615. tables : packed array [1..32767] of PWStrInitEntry;
  616. end;
  617. var
  618. {$ifdef FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  619. WStrInitTablesTable: PWStrInitTablesTable;
  620. {$else FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  621. WStrInitTablesTableVar: TWStrInitTablesTable; external name 'FPC_WIDEINITTABLES';
  622. WStrInitTablesTable: PWStrInitTablesTable = @WStrInitTablesTableVar;
  623. {$endif FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  624. function GetACP:UINT; stdcall; external 'kernel32' name 'GetACP';
  625. function GetConsoleCP:UINT; stdcall; external 'kernel32' name 'GetConsoleCP';
  626. function Win32GetStandardCodePage(const stdcp: TStandardCodePageEnum): TSystemCodePage;
  627. begin
  628. case stdcp of
  629. scpAnsi,
  630. scpFileSystemSingleByte: Result := GetACP;
  631. scpConsoleInput: Result := GetConsoleCP;
  632. scpConsoleOutput: Result := GetConsoleOutputCP;
  633. end;
  634. end;
  635. { there is a similiar procedure in sysutils which inits the fields which
  636. are only relevant for the sysutils units }
  637. procedure InitWin32Widestrings;
  638. var
  639. i: longint;
  640. ptable: PWStrInitEntry;
  641. begin
  642. {$if not(defined(VER2_2) or defined(VER2_4))}
  643. { assign initial values to global Widestring typed consts }
  644. for i:=1 to WStrInitTablesTable^.count do
  645. begin
  646. ptable:=WStrInitTablesTable^.tables[i];
  647. while Assigned(ptable^.addr) do
  648. begin
  649. fpc_widestr_assign(ptable^.addr^, ptable^.data);
  650. Inc(ptable);
  651. end;
  652. end;
  653. {$endif}
  654. { Note: since WideChar=UnicodeChar and PWideChar=PUnicodeChar,
  655. Wide2AnsiMoveProc is identical to Unicode2AnsiStrMoveProc. }
  656. { Widestring }
  657. widestringmanager.Wide2AnsiMoveProc:=@Win32Unicode2AnsiMove;
  658. widestringmanager.Ansi2WideMoveProc:=@Win32Ansi2WideMove;
  659. widestringmanager.UpperWideStringProc:=@Win32WideUpper;
  660. widestringmanager.LowerWideStringProc:=@Win32WideLower;
  661. { Unicode }
  662. widestringmanager.Unicode2AnsiMoveProc:=@Win32Unicode2AnsiMove;
  663. widestringmanager.Ansi2UnicodeMoveProc:=@Win32Ansi2UnicodeMove;
  664. widestringmanager.UpperUnicodeStringProc:=@Win32UnicodeUpper;
  665. widestringmanager.LowerUnicodeStringProc:=@Win32UnicodeLower;
  666. { Codepage }
  667. widestringmanager.GetStandardCodePageProc:=@Win32GetStandardCodePage;
  668. DefaultSystemCodePage:=GetACP;
  669. DefaultUnicodeCodePage:=CP_UTF16;
  670. DefaultFileSystemCodePage:=CP_UTF8;
  671. DefaultRTLFileSystemCodePage:=DefaultSystemCodePage;
  672. end;
  673. type
  674. WINBOOL = longbool;
  675. PHANDLER_ROUTINE = function (dwCtrlType:DWORD):WINBOOL; stdcall;
  676. function SetConsoleCtrlHandler(HandlerRoutine:PHANDLER_ROUTINE; Add:WINBOOL):WINBOOL; stdcall;
  677. external 'kernel32' name 'SetConsoleCtrlHandler';
  678. function WinCtrlBreakHandler(dwCtrlType:DWORD): WINBOOL;stdcall;
  679. const
  680. CTRL_BREAK_EVENT = 1;
  681. begin
  682. if Assigned(CtrlBreakHandler) then
  683. Result:=CtrlBreakHandler((dwCtrlType and CTRL_BREAK_EVENT > 0))
  684. else
  685. Result:=false;
  686. end;
  687. function SysSetCtrlBreakHandler (Handler: TCtrlBreakHandler): TCtrlBreakHandler;
  688. begin
  689. (* Return either nil or previous handler *)
  690. if (Assigned(CtrlBreakHandler)) and (not Assigned(Handler)) then
  691. SetConsoleCtrlHandler(@WinCtrlBreakHandler, false)
  692. else if (not Assigned(CtrlBreakHandler)) and (Assigned(Handler)) then
  693. SetConsoleCtrlHandler(@WinCtrlBreakHandler, true);
  694. SysSetCtrlBreakHandler := CtrlBreakHandler;
  695. CtrlBreakHandler := Handler;
  696. end;
  697. procedure WinFinalizeSystem;
  698. begin
  699. finalize_arguments;
  700. end;