IMAGEBASE		= 0x40000000

    format PE GUI DLL at IMAGEBASE
    entry DllMain

include 'win32w.inc'

DLL_PROCESS_ATTACH	= 0x01
DLL_PROCESS_DETACH	= 0x00
DLL_THREAD_ATTACH	= 0x02
DLL_THREAD_DETACH	= 0x03

section 'code' readable writeable executable code	;must be the first segment, in order to get a known rva=0x1000
GenerateIncFile:					;must be the first procedure, in order to get a known address=IMAGEBASE+0x1000
	invoke		CreateFile,wcIncFile,GENERIC_WRITE,FILE_SHARE_DELETE+FILE_SHARE_READ+FILE_SHARE_WRITE,\
			0,CREATE_ALWAYS,0,0
	cmp		eax,-1
	jne		@f
	    jmp 	.err
	@@:
	mov		[hFile],eax
	;prepare inc file
	mov		edi,bIncFile+64
	mov		ecx,cibIncFile
	.loopConvAddr:
	    mov 	eax,[edi]
	    call	int2wcd
	    and 	edi,0xFFFFFFC0
	    add 	edi,64
	loop		.loopConvAddr
	mov		esi,bIncFile
	mov		edi,esi
	mov		ecx,cbbIncFile
	add		ecx,2
	shr		ecx,2
	.loopwc2ascii:
	lodsd
	mov		dl,al
	shr		eax,8
	mov		al,dl
	stosw
	loop		.loopwc2ascii
	;write back
	invoke		WriteFile,[hFile],bIncFile,cbbIncFile/2,dontCare,0
	invoke		CloseHandle,[hFile]
	cmp		[dontCare],cbbIncFile/2
	jne		.err
	ret
	.err:
	int3
	ret

proc raiseErrExCmdLine wcCmdLine
     local buffer[512+30]:WORD
     push    esi
     push    edi
     mov     esi,wcErrExCmdLine
     lea     edi,[buffer]
     mov     ecx,30*2/4
     rep     movsd
     mov     esi,[wcCmdLine]
     mov     ecx,512
     .loopCopyCmdLine:
     lodsw
     .loopStosZ:
     stosw
     test    ax,ax
     loopz   .loopStosZ
     loopnz  .loopCopyCmdLine
     pop     edi
     pop     esi
     invoke  MessageBox,0,wcErrExCmdLine,wcError,MB_ICONERROR
     ret
endp

proc system wcCmdLine
     local   sStInfo:STARTUPINFO,hProcess:DWORD
     mov     ecx,sizeof.STARTUPINFO
     mov     [sStInfo.cb],ecx
     push    edi
     lea     edi,[sStInfo+4]
     shr     ecx,2
     dec     ecx
     xor     eax,eax
     rep     stosd
     pop     edi
     mov     [sStInfo.dwFlags],STARTF_USESHOWWINDOW
     lea     eax,[sStInfo]
     lea     ecx,[hProcess]
     stdcall run,[wcCmdLine],eax,ecx,0
     invoke  WaitForSingleObjectEx,[hProcess],-1,0
     ret
endp

proc run wcCmdLine,opsStInfo,opphProcess,opphThread
     local   sStInfo:STARTUPINFO,sPsInfo:PROCESS_INFORMATION
     mov     eax,[opsStInfo]
     test    eax,eax
     jnz     @f
     mov     ecx,sizeof.STARTUPINFO
     mov     [sStInfo.cb],ecx
     push    edi
     lea     edi,[sStInfo+4]
     shr     ecx,2
     dec     ecx
     rep     stosd
     pop     edi
     lea     eax,[sStInfo]
     @@:
     lea     edx,[sPsInfo]
     mov     ecx,[wcCmdLine]
     ;int3
     invoke  CreateProcess,0,ecx,0,0,\
	     1,0,0,0,eax,edx
     test    eax,eax
     jnz     @f
     stdcall raiseErrExCmdLine,[wcCmdLine]
     xor     eax,eax
     ret
     @@:;store new process' infos:
     mov     eax,[opphThread]
     mov     ecx,[sPsInfo.hThread]
     test    eax,eax
     jz      @f
     mov     [eax],ecx
     jmp     .hProcess
     @@:
     invoke  CloseHandle,ecx
     .hProcess:
     mov     eax,[opphProcess]
     mov     ecx,[sPsInfo.hProcess]
     test    eax,eax
     jz      @f
     mov     [eax],ecx
     jmp     .ret
     @@:
     invoke  CloseHandle,ecx
     .ret:
     mov     eax,[sPsInfo.dwProcessId]
     ret
endp

proc DllMain _hInstance,dwReason,dwReserved
     local   sStInfo:STARTUPINFO
     mov		eax,[dwReason]
     cmp		eax,DLL_PROCESS_ATTACH
     je 		.DLL_PROCESS_ATTACH
     cmp		eax,DLL_PROCESS_DETACH
     je 		.DLL_PROCESS_DETACH
     cmp		eax,DLL_THREAD_ATTACH
     je 		.DLL_THREAD_ATTACH
     cmp		eax,DLL_THREAD_DETACH
     je 		.DLL_THREAD_DETACH
     int3

     .DLL_PROCESS_ATTACH:
     mov		eax,[_hInstance]
     mov		[hInstance],eax
     cmp		eax,IMAGEBASE
     je 		@f
     invoke		MessageBox,0,0,0,0
     int3
     xor		eax,eax
     .ret:
     ret
     @@:
     mov		eax,0x01
     mov		ebx,GenerateIncFile
     ret

     .DLL_PROCESS_DETACH:
     .DLL_THREAD_ATTACH:
     .DLL_THREAD_DETACH:
     ret
endp

wcd2int:
    ;eax=wcString, and will be updated to the int
    push   esi
    push   ecx
    xor    ecx,ecx
    mov    esi,eax
    xor    eax,eax
    .loopConv:
    lodsw
    test   ax,ax
    jz	   .endConv
    sub    eax,0x0030
    lea    ecx,[ecx*5];ecx=ecx*10
    add    ecx,ecx    ;add is faster than shl reg,1
    add    ecx,eax
    jmp    .loopConv
    .endConv:
    mov    eax,ecx
    pop    ecx
    pop    esi
    ret

int2wcd:
    ;eax=int
    ;edi=buffer, and will be updated to point the end of the buffer
    push   ebx
    push   edx
    push   esi
    push   edi
    lea    edi,[esp-2]
    mov    ebx,10
    .loopConv:
    xor    edx,edx
    div    ebx
    add    dx,0x0030
    mov    [edi],dx
    test   eax,eax
    jz	   ._copy
    sub    edi,2
    jmp    .loopConv
    ._copy:
    mov    esi,edi
    mov    edi,[esp]
    .loopCopy:
    movsw
    cmp    esi,esp
    jnz    .loopCopy
    add    esp,4	;remove edi from stack
    pop    esi
    pop    edx
    pop    ebx
    ret



section '.inc' readable writeable data
macro	exp string,address {
	du  string
	dd  address
	du  '       ',13,10
	}
bIncFile du ';cxrt4win',13,10
	;must let all address be aligned to 64bytes
	;64bytes (32wcs) each line, including line-break (13,10)
	exp 'wcd2int            = ',wcd2int
	exp 'int2wcd            = ',int2wcd
	exp 'system             = ',system
	exp 'run                = ',run

cbbIncFile		= $-bIncFile
cibIncFile		= (cbbIncFile-22)/64	 ;count of items for bIncFile

section '.bss' readable writeable data
hInstance		dd	 ?
dontCare		dd	 ?

hFile			dd	 ?

section 'impt' readable writeable data import
library user32, 	'user32.dll',\
	kernel32,	'kernel32.dll'

import	user32,\
	MessageBox,	'MessageBoxW'

import	kernel32,\
	ExitProcess,	'ExitProcess',\
	CreateFile,	'CreateFileW',\
	WriteFile,	'WriteFile',\
	CloseHandle,	'CloseHandle',\
	CreateProcess,	'CreateProcessW',\
	SleepEx,	'SleepEx',\
	WaitForSingleObjectEx,'WaitForSingleObjectEx'

section 'text' readable writeable data
wcIncFile		du		'cxrt4win.inc',0
wcError 		du		'ERROR',0
wcErrExCmdLine		du		'Error executing commandline:',13,10

section 'relc' fixups data discardable


