;------------------------------------------------------------------------------------- ; ; HelloUnicode - Copyright Jeremy Gordon 2004 ; ; DEMONSTRATION OF UNICODE STRINGS - for GoAsm ; This file demonstrates the use of Unicode strings based on: ; 1. The natural format of the source script ; 2. The STRINGS directive ; 3. The A" and L" overrides ; ; Important! View this file using Internet Explorer, help ; or a Unicode editor (copy and paste it into the editor). ; ; Try it in "Unicode" format that is UTF-16LE, and try again in UTF-8. ; On both cases the output of the Unicode string will be in UTF-16 to suit ; the Windows API. ; ; If you wanted a UTF-8 string you would use the 8" override (not used here). ; ; Assemble using GoAsm HelloUnicode1 (produces PE COFF file) ; Then link as windows console program using GoLink as follows:- ; GoLink /console hellounicode1.obj kernel32.dll ; (add -debug coff if you want to watch the program in the debugger) ; ; If you see question marks instead of Russian in the MS-DOS (Command prompt) ; window (console) right click on the title bar and change font to Lucida Console. ; That font is capable of drawing Unicode characters to the console. ; This feature is only available with NT4, 2000, XP or above, which means that ; the console under Windows 9x and ME cannot display Unicode. For this reason ; this program carried out a version check to see what string should be drawn. ; ; Note that the APIs GetStdHandle, GetModuleHandleW, GetVersionExA, ; lstrlen and WriteFile are all calls are to Kernel32.dll. ; ; The API WriteConsoleW is needed to write Unicode text output to the console. ; This is the Unicode version of WriteConsole. Although WriteConsoleW ; is available on Windows 9x (in Kernel32.dll), it just wraps to WriteConsoleA ; (the ANSI version of WriteConsole). ; ; This demo uses "run-time loading" of WriteConsoleW. It is one of the ways ; you can make one version of your program to run on all platforms (it avoids ; W9x trying to load APIs which it cannot find). Another way is to use the ; ANSI versions of the APIs throughout (this has character and speed ; implications) or to use the Microsoft Layer for Unicode (this can be ; implemented using the /mslu switch in GoLink). See the help file Unicode.htm ; and the GoLink help file for more information. ;------------------------------------------------------------------------------------- ; DATA ; ;even in the absence of a STRINGS directive or an L" override the following ;string is put in the object file in Unicode UTF-16 format since the source ;script is in one of the Unicode formats read by GoAsm ie. UTF-16LE or UTF-8 UnicodeString: DB "Здравствуй Мир (change font to Lucida console if you don't see Cyrillic)" ; ;here the A" override is used to ensure the following string is put in the ;object file in ANSI format despite the format of the source script:- FUNCTIONERROR_MESS DB A'Sorry - there was an error with this application',0 ; ;but for long series of ANSI strings this will be easier to use:- STRINGS ANSI ;every string from now on to be in ANSI unless overriden ; ;because the STRINGS directive is ANSI this string is put in the object file in ANSI format VERSIONERROR_MESS DB 'Sorry - can only write Unicode to console under NT4,2000,XP',0 ; ;because of the L" override this string will be put in the object file in Unicode ;UTF-16 format and because DW is used and not DB, the carriage return (0Dh) and the ;linefeed (0Ah) will also be correctly rendered in UTF-16 format:- HelloWorldString DW L'Здравствуй Мир (Hello World in Russian from GoAsm)',0Dh,0Ah ; ;but for long series of UNICODE strings this will be easier to use:- STRINGS UNICODE ;every string from now on to be in Unicode UTF-16 unless overriden ; RCKEEP DD 0 ;temporary place to keep things OSVERSIONINFO DD 148 ;size DB 144 DUP 0 ;total size of OSVERSIONINFO structure (ANSI version)=148 bytes ; CODE ; START: PUSH -11D ;STD_OUTPUT_HANDLE CALL GetStdHandle ;get, in eax, handle to active screen buffer MOV EBX,EAX ;keep handle in ebx ;********************** MOV EDI,ADDR OSVERSIONINFO PUSH EDI CALL GetVersionExA MOV ESI,ADDR VERSIONERROR_MESS ;ready with message in case of wrong platform CMP D[EDI+10h],1 ;see if platform id is NT4,2000,XP and above JNA >L4 ;no give user the message in esi ;******* GetModuleHandleW requires a Unicode UTF-16 string and currently STRINGS are ;******* UNICODE so that is ok:- PUSH 'Kernel32.dll' CALL GetModuleHandleW ;get handle of Kernel32.dll in eax (definitely loaded) ;note: use LoadLibraryW if the dll is not yet loaded OR EAX,EAX ;see if successful JZ >L2 ;no, give 2nd error message ;******* GetProcAddress requires an ANSI string so use the A" override PUSH A'WriteConsoleW' PUSH EAX ;push handle of Kernel32.dll CALL GetProcAddress ;get address of WriteConsoleW OR EAX,EAX ;see if successful JZ >L2 ;no, give 2nd error message MOV EDI,EAX ;keep address of WriteConsoleW in edi ;******* WriteConsoleW requires a Unicode UTF-16 string .. PUSH 0,ADDR RCKEEP ;RCKEEP receives output from API PUSH 52D ;52=number of characters in the string which follows PUSH ADDR HelloWorldString PUSH EBX ;handle to active screen buffer CALL EDI ;call WriteConsoleW OR EAX,EAX ;see if successful JZ >L2 ;no, so write error message ;******** PUSH 0,ADDR RCKEEP ;RCKEEP receives output from API PUSH 72D ;72=number of characters in string which follows PUSH ADDR UnicodeString PUSH EBX ;handle to active screen buffer CALL EDI ;call WriteConsoleW OR EAX,EAX ;see if successful JZ >L2 ;no, so write error message XOR EAX,EAX ;return zero RET ;return to Windows ;****** error returns (uses only ANSI strings):- L2: MOV ESI,ADDR FUNCTIONERROR_MESS L4: PUSH ESI CALL lstrlen ;count length of ANSI string (result in eax) PUSH 0,ADDR RCKEEP ;RCKEEP receives output from API PUSH EAX,ESI ;length, address of string PUSH EBX ;handle to active screen buffer CALL WriteFile ;call WriteFile to write ANSI string to console XOR EAX,EAX ;return zero RET ;return to Windows