syswin.inc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  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. Const
  13. DLL_PROCESS_ATTACH = 1;
  14. DLL_THREAD_ATTACH = 2;
  15. DLL_PROCESS_DETACH = 0;
  16. DLL_THREAD_DETACH = 3;
  17. DLLExitOK : boolean = true;
  18. Var
  19. DLLBuf : Jmp_buf;
  20. function Dll_entry{$ifdef FPC_HAS_INDIRECT_MAIN_INFORMATION}(const info : TEntryInformation){$endif FPC_HAS_INDIRECT_MAIN_INFORMATION} : longbool; [public,alias:'_FPC_DLL_Entry'];
  21. begin
  22. {$ifdef FPC_HAS_INDIRECT_MAIN_INFORMATION}
  23. EntryInformation:=info;
  24. {$endif FPC_HAS_INDIRECT_MAIN_INFORMATION}
  25. IsLibrary:=true;
  26. Dll_entry:=false;
  27. case DLLreason of
  28. DLL_PROCESS_ATTACH :
  29. begin
  30. MainThreadIdWin32 := Win32GetCurrentThreadId;
  31. If SetJmp(DLLBuf) = 0 then
  32. begin
  33. {$ifdef FPC_HAS_INDIRECT_MAIN_INFORMATION}
  34. EntryInformation.PascalMain();
  35. {$else FPC_HAS_INDIRECT_MAIN_INFORMATION}
  36. PascalMain;
  37. {$endif FPC_HAS_INDIRECT_MAIN_INFORMATION}
  38. Dll_entry:=true;
  39. end
  40. else
  41. Dll_entry:=DLLExitOK;
  42. end;
  43. DLL_THREAD_ATTACH :
  44. begin
  45. if Win32GetCurrentThreadId <> MainThreadIdWin32 then
  46. begin
  47. { Initialize multithreading if not done }
  48. SysInitMultithreading;
  49. { Allocate Threadvars }
  50. SysAllocateThreadVars;
  51. { NS : no idea what is correct to pass here - pass dummy value for now }
  52. { passing a dummy is ok, the correct value is read from the coff header of SysInstance (FK) }
  53. InitThread($1000000); { Assume everything is idempotent there, as the thread could have been created with BeginThread... }
  54. end;
  55. if assigned(Dll_Thread_Attach_Hook) then
  56. Dll_Thread_Attach_Hook(DllParam);
  57. Dll_entry:=true; { return value is ignored }
  58. end;
  59. DLL_THREAD_DETACH :
  60. begin
  61. if assigned(Dll_Thread_Detach_Hook) then
  62. Dll_Thread_Detach_Hook(DllParam);
  63. { Release Threadvars }
  64. if Win32GetCurrentThreadId<>MainThreadIdWin32 then
  65. DoneThread; { Assume everything is idempotent there }
  66. Dll_entry:=true; { return value is ignored }
  67. end;
  68. DLL_PROCESS_DETACH :
  69. begin
  70. Dll_entry:=true; { return value is ignored }
  71. if MainThreadIDWin32=0 then // already been here.
  72. exit;
  73. If SetJmp(DLLBuf) = 0 then
  74. FPC_Do_Exit;
  75. if assigned(Dll_Process_Detach_Hook) then
  76. Dll_Process_Detach_Hook(DllParam);
  77. DoneThread;
  78. { Free TLS resources used by ThreadVars }
  79. SysFiniMultiThreading;
  80. MainThreadIDWin32:=0;
  81. end;
  82. end;
  83. end;
  84. Procedure ExitDLL(Exitcode : longint);
  85. begin
  86. DLLExitOK:=ExitCode=0;
  87. LongJmp(DLLBuf,1);
  88. end;
  89. {$ifdef FPC_USE_TLS_DIRECTORY}
  90. { Process TLS callback function }
  91. { This is only useful for executables
  92. for DLLs, DLL_Entry gets called. PM }
  93. const
  94. Thread_count : longint = 0;
  95. procedure Exec_Tls_callback(Handle : pointer; reason : Dword; Reserved : pointer);
  96. stdcall; [public,alias:'_FPC_Tls_Callback'];
  97. begin
  98. if IsLibrary then
  99. Exit;
  100. case reason of
  101. DLL_PROCESS_ATTACH :
  102. begin
  103. MainThreadIdWin32 := Win32GetCurrentThreadId;
  104. end;
  105. DLL_THREAD_ATTACH :
  106. begin
  107. inclocked(Thread_count);
  108. if Win32GetCurrentThreadId <> MainThreadIdWin32 then
  109. begin
  110. { Initialize multithreading if not done }
  111. SysInitMultithreading;
  112. { Allocate Threadvars }
  113. SysAllocateThreadVars;
  114. { NS : no idea what is correct to pass here - pass dummy value for now }
  115. { passing a dummy is ok, the correct value is read from the coff header of SysInstance (FK) }
  116. InitThread($1000000); { Assume everything is idempotent there, as the thread could have been created with BeginThread... }
  117. end;
  118. if assigned(Dll_Thread_Attach_Hook) then
  119. Dll_Thread_Attach_Hook(DllParam);
  120. end;
  121. DLL_THREAD_DETACH :
  122. begin
  123. declocked(Thread_count);
  124. if assigned(Dll_Thread_Detach_Hook) then
  125. Dll_Thread_Detach_Hook(DllParam);
  126. { Release Threadvars }
  127. if Win32GetCurrentThreadId<>MainThreadIdWin32 then
  128. DoneThread; { Assume everything is idempotent there }
  129. end;
  130. DLL_PROCESS_DETACH :
  131. begin
  132. if MainThreadIDWin32=0 then // already been here.
  133. exit;
  134. If SetJmp(DLLBuf) = 0 then
  135. FPC_Do_Exit;
  136. if assigned(Dll_Process_Detach_Hook) then
  137. Dll_Process_Detach_Hook(DllParam);
  138. DoneThread;
  139. { Free TLS resources used by ThreadVars }
  140. SysFiniMultiThreading;
  141. MainThreadIDWin32:=0;
  142. end;
  143. end;
  144. end;
  145. const
  146. FreePascal_TLS_callback : pointer = @Exec_Tls_callback;
  147. public name '__FPC_tls_callbacks' section '.CRT$XLFPC';
  148. FreePascal_end_of_TLS_callback : pointer = nil;
  149. public name '__FPC_end_of_tls_callbacks' section '.CRT$XLZZZ';
  150. var
  151. tls_callbacks : pointer; external name '___crt_xl_start__';
  152. tls_data_start : pointer; external name '___tls_start__';
  153. tls_data_end : pointer; external name '___tls_end__';
  154. {$ifdef win32}
  155. tls_index : dword; external name '__tls_index';
  156. {$else not win32}
  157. tls_index : dword; external name '_tls_index';
  158. {$endif not win32}
  159. const
  160. _tls_used : TTlsDirectory = (
  161. data_start : @tls_data_start;
  162. data_end : @tls_data_end;
  163. index_pointer : @tls_index;
  164. callbacks_pointer : @tls_callbacks;
  165. zero_fill_size : 0;
  166. flags : 0;
  167. ); public name
  168. { This should be the same name as in mingw/tlsup.c code }
  169. {$ifdef win32}
  170. '__tls_used';
  171. {$else }
  172. '_tls_used';
  173. {$endif not win32}
  174. {$endif FPC_USE_TLS_DIRECTORY}
  175. {****************************************************************************
  176. Error Message writing using messageboxes
  177. ****************************************************************************}
  178. function MessageBox(w1:longint;l1,l2:pointer;w2:longint):longint;
  179. stdcall;external 'user32' name 'MessageBoxA';
  180. const
  181. ErrorBufferLength = 1024;
  182. var
  183. ErrorBuf : array[0..ErrorBufferLength] of char;
  184. ErrorLen : SizeInt;
  185. Function ErrorWrite(Var F: TextRec): Integer;
  186. {
  187. An error message should always end with #13#10#13#10
  188. }
  189. var
  190. i : SizeInt;
  191. Begin
  192. while F.BufPos>0 do
  193. begin
  194. begin
  195. if F.BufPos+ErrorLen>ErrorBufferLength then
  196. i:=ErrorBufferLength-ErrorLen
  197. else
  198. i:=F.BufPos;
  199. Move(F.BufPtr^,ErrorBuf[ErrorLen],i);
  200. inc(ErrorLen,i);
  201. ErrorBuf[ErrorLen]:=#0;
  202. end;
  203. if ErrorLen=ErrorBufferLength then
  204. begin
  205. MessageBox(0,@ErrorBuf,pchar('Error'),0);
  206. ErrorLen:=0;
  207. end;
  208. Dec(F.BufPos,i);
  209. end;
  210. ErrorWrite:=0;
  211. End;
  212. Function ErrorClose(Var F: TextRec): Integer;
  213. begin
  214. if ErrorLen>0 then
  215. begin
  216. MessageBox(0,@ErrorBuf,pchar('Error'),0);
  217. ErrorLen:=0;
  218. end;
  219. ErrorLen:=0;
  220. ErrorClose:=0;
  221. end;
  222. Function ErrorOpen(Var F: TextRec): Integer;
  223. Begin
  224. TextRec(F).InOutFunc:=@ErrorWrite;
  225. TextRec(F).FlushFunc:=@ErrorWrite;
  226. TextRec(F).CloseFunc:=@ErrorClose;
  227. ErrorLen:=0;
  228. ErrorOpen:=0;
  229. End;
  230. procedure AssignError(Var T: Text);
  231. begin
  232. Assign(T,'');
  233. TextRec(T).OpenFunc:=@ErrorOpen;
  234. Rewrite(T);
  235. end;
  236. procedure SysInitStdIO;
  237. begin
  238. { Setup stdin, stdout and stderr, for GUI apps redirect stderr,stdout to be
  239. displayed in a messagebox }
  240. StdInputHandle:=longint(GetStdHandle(cardinal(STD_INPUT_HANDLE)));
  241. StdOutputHandle:=longint(GetStdHandle(cardinal(STD_OUTPUT_HANDLE)));
  242. StdErrorHandle:=longint(GetStdHandle(cardinal(STD_ERROR_HANDLE)));
  243. if not IsConsole then
  244. begin
  245. AssignError(stderr);
  246. AssignError(StdOut);
  247. Assign(Output,'');
  248. Assign(Input,'');
  249. Assign(ErrOutput,'');
  250. end
  251. else
  252. begin
  253. OpenStdIO(Input,fmInput,StdInputHandle);
  254. OpenStdIO(Output,fmOutput,StdOutputHandle);
  255. OpenStdIO(ErrOutput,fmOutput,StdErrorHandle);
  256. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  257. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  258. end;
  259. end;
  260. { ProcessID cached to avoid repeated calls to GetCurrentProcess. }
  261. var
  262. ProcessID: SizeUInt;
  263. function GetProcessID: SizeUInt;
  264. begin
  265. GetProcessID := ProcessID;
  266. end;
  267. {******************************************************************************
  268. Unicode
  269. ******************************************************************************}
  270. procedure Win32Unicode2AnsiMove(source:punicodechar;var dest:ansistring;len:SizeInt);
  271. var
  272. destlen: SizeInt;
  273. begin
  274. // retrieve length including trailing #0
  275. // not anymore, because this must also be usable for single characters
  276. destlen:=WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, source, len, nil, 0, nil, nil);
  277. // this will null-terminate
  278. setlength(dest, destlen);
  279. WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, source, len, @dest[1], destlen, nil, nil);
  280. end;
  281. procedure Win32Ansi2UnicodeMove(source:pchar;var dest:UnicodeString;len:SizeInt);
  282. var
  283. destlen: SizeInt;
  284. begin
  285. // retrieve length including trailing #0
  286. // not anymore, because this must also be usable for single characters
  287. destlen:=MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, source, len, nil, 0);
  288. // this will null-terminate
  289. setlength(dest, destlen);
  290. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, source, len, @dest[1], destlen);
  291. end;
  292. function Win32UnicodeUpper(const s : UnicodeString) : UnicodeString;
  293. begin
  294. result:=s;
  295. UniqueString(result);
  296. if length(result)>0 then
  297. CharUpperBuff(LPWSTR(result),length(result));
  298. end;
  299. function Win32UnicodeLower(const s : UnicodeString) : UnicodeString;
  300. begin
  301. result:=s;
  302. UniqueString(result);
  303. if length(result)>0 then
  304. CharLowerBuff(LPWSTR(result),length(result));
  305. end;
  306. type
  307. PWStrInitEntry = ^TWStrInitEntry;
  308. TWStrInitEntry = record
  309. addr: PPointer;
  310. data: Pointer;
  311. end;
  312. PWStrInitTablesTable = ^TWStrInitTablesTable;
  313. TWStrInitTablesTable = packed record
  314. count : longint;
  315. tables : packed array [1..32767] of PWStrInitEntry;
  316. end;
  317. {$if not(defined(VER2_2) or defined(VER2_4))}
  318. var
  319. WStrInitTablesTable: TWStrInitTablesTable; external name 'FPC_WIDEINITTABLES';
  320. {$endif}
  321. { there is a similiar procedure in sysutils which inits the fields which
  322. are only relevant for the sysutils units }
  323. procedure InitWin32Widestrings;
  324. var
  325. i: longint;
  326. ptable: PWStrInitEntry;
  327. begin
  328. {$if not(defined(VER2_2) or defined(VER2_4))}
  329. { assign initial values to global Widestring typed consts }
  330. for i:=1 to WStrInitTablesTable.count do
  331. begin
  332. ptable:=WStrInitTablesTable.tables[i];
  333. while Assigned(ptable^.addr) do
  334. begin
  335. fpc_widestr_assign(ptable^.addr^, ptable^.data);
  336. Inc(ptable);
  337. end;
  338. end;
  339. {$endif}
  340. { Note: since WideChar=UnicodeChar and PWideChar=PUnicodeChar,
  341. Wide2AnsiMoveProc is identical to Unicode2AnsiStrMoveProc. }
  342. { Widestring }
  343. widestringmanager.Wide2AnsiMoveProc:=@Win32Unicode2AnsiMove;
  344. widestringmanager.Ansi2WideMoveProc:=@Win32Ansi2WideMove;
  345. widestringmanager.UpperWideStringProc:=@Win32WideUpper;
  346. widestringmanager.LowerWideStringProc:=@Win32WideLower;
  347. {$ifndef VER2_2}
  348. { Unicode }
  349. widestringmanager.Unicode2AnsiMoveProc:=@Win32Unicode2AnsiMove;
  350. widestringmanager.Ansi2UnicodeMoveProc:=@Win32Ansi2UnicodeMove;
  351. widestringmanager.UpperUnicodeStringProc:=@Win32UnicodeUpper;
  352. widestringmanager.LowerUnicodeStringProc:=@Win32UnicodeLower;
  353. {$endif VER2_2}
  354. end;