;@goto translate


.586P

.MODEL            FLAT, STDCALL

   OPTION         CASEMAP: NONE

   INCLUDE        WINDOWS.inc
   UNICODE        = FALSE
   INCLUDE        APIMACRO.mac

   INCLUDELIB     KERNEL32
   INCLUDELIB     TlsDll

   OPTION         NOKEYWORD:<INVOKE,ADDR>
   INVOKE         EQU       iWin32@
   invoke         EQU       iWin32@
   ADDR           EQU       OFFSET
   addr           EQU       OFFSET


.CONST
_tls_array EQU    2CH      ;FS:[2CH] - pointer to array of pointers to copied tls blocks

.DATA?
_tls_index DWORD  ?

;pro forma create section with name .tls
;(but tls can be placed anywhere)
   OPTION         DOTNAME
.tls   SEGMENT
_tls_start LABEL  DWORD
 DWORD     80H    DUP ("slt.") 
_tls_end   LABEL  DWORD
.tls   ENDS
   OPTION         NODOTNAME

.DATA
__xl_a DWORD TlsCallBack0, TlsCallBack1, TlsCallBack2, TlsCallBack3
__xl_z DWORD 0    ;null terminated list of pointers to callback procedures

TLS_DIRECTORY    STRUCT
 lpTlsDataStart LPDWORD ? ;copy block starting here
 lpTlsDataEnd   LPDWORD ? ;and ending here + block (size=ZeroFillSize) filled with 0 to
 lpTlsIndex     LPDWORD ? ;DS:[FS:[2CH]]+TlsIndex*4
 lpTlsCallbacks LPDWORD ? ;pointer to 0 terminated array of pointers to callbacks
 ZeroFillSize     DWORD ? ;overall size=lpTlsDataEnd-lpTlsDataStart+ZeroFillSize
 Characteristic   DWORD ? ;reserved
TLS_DIRECTORY      ENDS

PUBLIC _tls_used ;this name is required and must be PUBLIC!!!!
_tls_used TLS_DIRECTORY <_tls_start, _tls_end, _tls_index, __xl_a, 0, ?>

.CODE

 TlsCallBack0   PROC    hinstImg, fdwReason, lpvReserved
   INVOKE  GiveRegards, sCB0, hinstImg, fdwReason, lpvReserved
   MOV     EAX, TRUE
   RET
 TlsCallBack0   ENDP

 TlsCallBack1   PROC    hinstImg, fdwReason, lpvReserved
   INVOKE  GiveRegards, sCB1, hinstImg, fdwReason, lpvReserved
   MOV     EAX, TRUE
   RET
 TlsCallBack1   ENDP

 TlsCallBack2   PROC    hinstImg, fdwReason, lpvReserved
   INVOKE  GiveRegards, sCB2, hinstImg, fdwReason, lpvReserved
   MOV     EAX, TRUE
   RET
 TlsCallBack2   ENDP

 TlsCallBack3   PROC    hinstImg, fdwReason, lpvReserved
   INVOKE  GiveRegards, sCB3, hinstImg, fdwReason, lpvReserved
   MOV     EAX, TRUE
   RET
 TlsCallBack3   ENDP

 TlsCallBack4   PROC    hinstImg, fdwReason, lpvReserved
   INVOKE  GiveRegards, sCB3, hinstImg, fdwReason, lpvReserved
   MOV     EAX, TRUE
   RET
 TlsCallBack4   ENDP
  
   TEXTA   CB0, <EXE Tls Callback #0/0> 
   TEXTA   CB1, <EXE Tls Callback #1/0> 
   TEXTA   CB2, <EXE Tls Callback #2/0> 
   TEXTA   CB3, <EXE Tls Callback #3/0> 
   TEXTA   EXE, <EXE ---------- Main/0>

 ExeMain   PROC
   ;do WinMain like DllMain
   INVOKE  GetModuleHandleA, NULL
   INVOKE  GiveRegards, sEXE, EAX, DLL_PROCESS_ATTACH, NULL
   ;create new thread (for watching DLL_THREAD_ATTACH/DETACH)
   PUSH    EAX
   INVOKE  CreateThread, NULL, NULL, OFFSET Thread, ESP, NULL, ESP
   POP     ECX
   INVOKE  CloseHandle, EAX
   ;every console program i met uses GetStdHandle or CreateFile("CONIN$"/"CONOUT$")
   ;with Read/WriteFile or Read/WriteConsole
   ;but i've found the fastest way: do file operations with standard handles ;)
   INVOKE  FlushFileBuffers, STD_INPUT_HANDLE
   INVOKE  ReadFile,    STD_INPUT_HANDLE, ESP, 1, ESP, NULL
   INVOKE  ExitProcess, EAX
 ExeMain   ENDP

 Thread    PROC Tparam
   RET
 Thread    ENDP

END ExeMain

:translate
@echo off
ML   /c /coff /nologo TlsExe.bat
LINK TlsExe /nologo /SUBSYSTEM:CONSOLE /MERGE:.rdata=.text /MERGE:.idata=.text /IGNORE:4078
DEL  TlsExe.obj
PAUSE
CLS