I remembered that I have several small programs written without links to libraries. Here is one of them, written back in 2016. It shows the obvious superiority of using MASM over other Assemblers when creating programs with Unicode support. When non-MASM programmers use macros, strings from resources or stupidly manually translate Unicode letters into codes, modest MASM programmers simply write the source directly in Unicode.
Something like that, for example (at the same time, we will check how this forum supports Unicode):
;
.386
.MODEL FLAT, STDCALL
OPTION CASEMAP: NONE
;
IncLib MACRO fn
INCLUDE \Masm32\INCLUDE\fn.inc
INCLUDELIB \Masm32\LIB\fn.lib
ENDM
;
MovE MACRO dst, med, src
MOV med, src
MOV dst, med
ENDM
;
INCLUDE \Masm32\INCLUDE\Windows.inc
;
IncLib User32
IncLib Kernel32
;
INCLUDE HelloUcW.inc
;
WmMouseOverBtn EQU 7FFFh
MovTimerId EQU 1
MovTimerPer EQU 15
BtnStepNum EQU 10
;
WM TYPEDEF Dword
ID TYPEDEF Dword
ND TYPEDEF Dword
PSZ TYPEDEF Ptr CHAR
PWSZ TYPEDEF Ptr WCHAR
PCODE TYPEDEF Ptr Proc
;
BTN_MOV STRUCT
Xcur ND ?
Xstep ND ?
Xmin ND ?
Xmax ND ?
Y ND ?
Width_ ND ?
Height ND ?
BTN_MOV ENDS
;
prDlgMain PROTO hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
prBtnOk PROTO hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
calcBtnMov PROTO hdlgMain:HWND, htxtRef:HWND
setTextArrA PROTO hWnd:HWND, pArrSz:PSZ, ndSz:ND, idStartSz:ID
setTextArrW PROTO hWnd:HWND, pArrWSz:PWSZ, ndWSz:ND, idStartWSz:ID
;
.DATA
szDlgTitle CHAR 'Hello, Asm Unicode World!', 0
;
aszLang LABEL CHAR
szGreek CHAR 'Greek:', 0
szItalian CHAR 'Italian:', 0
szFrench CHAR 'French:', 0
szSpanish CHAR 'Spanish:', 0
szEnglish CHAR 'English:', 0
szGerman CHAR 'German:', 0
szHindi CHAR 'Hindi:', 0
szArabian CHAR 'Arabian:', 0
szHebrew CHAR 'Hebrew:', 0
szChinese CHAR 'Chinese:', 0
szJapanese CHAR 'Japanese:', 0
szKorean CHAR 'Korean:', 0
szVietnamese CHAR 'Vietnamese:', 0
szMongolian CHAR 'Mongolian:', 0
szTurkish CHAR 'Turkish:', 0
szAzerbaijani CHAR 'Azerbaijani:', 0
szUzbek CHAR 'Uzbek:', 0
szKazakh CHAR 'Kazakh:', 0
szTajik CHAR 'Tajik:', 0
szFinnish CHAR 'Finnish:', 0
szEstonian CHAR 'Estonian:', 0
szArmenian CHAR 'Armenian:', 0
szGeorgian CHAR 'Georgian:', 0
szSerbian CHAR 'Serbian:', 0
szBulgarian CHAR 'Bulgarian:', 0
szCratian CHAR 'Croatian:', 0
szCzech CHAR 'Czech:', 0
szPolish CHAR 'Polish:', 0
szUkrainian CHAR 'Ukrainian:', 0
Belarusian CHAR 'Belarusian:', 0
szRussian CHAR 'Russian:', 0
;
ALIGN WCHAR
.RADIX 16
awszHello LABEL WCHAR
wszGreek WCHAR "Γεια σου κόσμε!",0
wszItalian WCHAR "Ciao, mondo!",0
wszFrench WCHAR "Bonjour le monde!",0
wszSpanish WCHAR "Hola Mundo!",0
wszEnglish WCHAR "Hello, World!",0
wszGerman WCHAR "Hallo Welt!",0
wszHindi WCHAR "नमस्ते दुनिया!",0
wszArabian WCHAR "!مرحبا بالعالم",0
wszHebrew WCHAR "!שלום עולם",0
wszChinese WCHAR "你好,世界!",0
wszJapanese WCHAR "こんにちは世界!",0
wszKorean WCHAR "안녕, 세상!",0
wszVietnamese WCHAR "Xin Chào, Thế Giới!",0
wszMongolian WCHAR "Сайн байна уу, Дэлхийн!",0
wszTurkish WCHAR "Selam Dünya!",0
wszAzerbaijani WCHAR "Salam, Dünya!",0
wszUzbek WCHAR "Salom Dunyo!",0
wszKazakh WCHAR "Сәлем Әлем!",0
wszTajik WCHAR "Салом, ҶАҲОН!",0
wszFinnish WCHAR "Height maailma!",0
wszEstonian WCHAR "Tere, Maailm!",0
wszArmenian WCHAR "Բարեւ Աշխարհը!",0
wszGeorgian WCHAR "გამარჯობა მსოფლიო!",0
wszSerbian WCHAR "Здраво, Свет!",0
wszBulgarian WCHAR "Здравей, Свят!",0
wszCroatian WCHAR "Zdravo, svijete!",0
wszCzech WCHAR "Ahoj světe!",0
wszPolish WCHAR "Witaj, Świecie!",0
wszUkrainian WCHAR "Привіт, Світ!",0
wszBelarusian WCHAR "Прывітанне Сусвет!",0
wszRussian WCHAR "Дратути!",0
.RADIX 10
;
.DATA?
sBtnMov BTN_MOV <>
hInstance HINSTANCE ?
hdlgMain HWND ?
hbtnOk HWND ?
pprBtnOkSys PCODE ?
;
.CODE
START:
INVOKE GetModuleHandle, NULL
MOV hInstance, EAX
INVOKE DialogBoxParamW, hInstance, MainDlgId, NULL, Addr prDlgMain, NULL
INVOKE ExitProcess, EAX
;
prDlgMain PROC Uses EDI hwnd:HWND, umsg:UINT, wparam:WPARAM, lparam:LPARAM
MOV EAX, umsg
MOV ECX, LengthOf tblwm
LEA EDI, tblwm
REPNE SCASD
JNE procwm
ADD EDI, SizeOf tblwm
PUSH exit ; For supported WM only
procwm:
JMP PCODE Ptr [EDI]
.DATA
ALIGN WM
tblwm WM WM_INITDIALOG, WM_TIMER, WM_COMMAND, WM_CLOSE
PCODE skip ; If WM not supported
pmou PCODE wminitdialog
ptim PCODE processed, wmcommand, wmclose
.CODE
wminitdialog:
MovE hdlgMain, EAX, hwnd
INVOKE SendMessageA, hwnd, WM_SETTEXT, NULL, Addr szDlgTitle
INVOKE LoadIcon, hInstance, MainIconId
INVOKE SendMessage, hwnd, WM_SETICON, MainIconId, EAX
INVOKE GetDlgItem, hwnd, OkBtnId
MOV hbtnOk, EAX
INVOKE SetWindowLong, EAX, GWL_WNDPROC, Addr prBtnOk
MOV pprBtnOkSys, EAX
INVOKE setTextArrA, hwnd, Addr aszLang, LangRowNum, StartTxtAId
INVOKE setTextArrW, hwnd, Addr awszHello, LangRowNum, StartTxtWId
INVOKE GetDlgItem, hwnd, GreekTxtAId
INVOKE calcBtnMov, hwnd, EAX
INVOKE SetTimer, hwnd, MovTimerId, MovTimerPer, NULL
MOV tblwm, WmMouseOverBtn ; Instead WM_INITDIALOG
MOV pmou, setleftmov
STC
RETN
;
wmclose:
INVOKE KillTimer, hwnd, MovTimerId
INVOKE EndDialog, hwnd, NULL
STC
RETN
;
wmcommand:
CMP wparam, (BN_CLICKED Shl 16) Or OkBtnId
JNE notprocessed
INVOKE SendMessage, hwnd, WM_CLOSE, NULL, NULL
processed:
STC ; CF = 1: processed
RETN
notprocessed:
CLC ; CF = 0: not processed
RETN
;
; Mouse is over OK button: set motion handler on timer
setleftmov:
LEA EAX, movbtnleft
JMP mouoveroff
setrightmov:
LEA EAX, movbtnright
mouoveroff:
MOV ptim, EAX ; Set btn moving handler on timer
MOV pmou, processed ; Mouse over btn off
STC
RETN
;
; Button motion handlers
loadbtnmovstuff:
LEA EDX, sBtnMov
ASSUME EDX: Ptr BTN_MOV
MOV EAX, [EDX].Xstep
MOV ECX, [EDX].Xcur
RETN
movbtnleft:
CALL loadbtnmovstuff
SUB ECX, EAX ; Xcur = Xcur - Xstep
MOV EAX, [EDX].Xmin
CMP ECX, EAX
JG movbtn ; Xcur > Xmin
MOV ECX, EAX ; Xcur = Xmin
LEA EAX, setrightmov
JMP stopbtn
movbtnright:
CALL loadbtnmovstuff
ADD ECX, EAX ; Xcur = Xcur + Xstep
MOV EAX, [EDX].Xmax
CMP ECX, EAX
JL movbtn ; Xcur < Xmin
MOV ECX, EAX ; Xcur = Xmax
LEA EAX, setleftmov
stopbtn:
MOV pmou, EAX ; Trigger on mouse over btn
MOV ptim, processed ; Timer off
movbtn:
MOV [EDX].Xcur, ECX
INVOKE MoveWindow, hbtnOk, [EDX].Xcur, [EDX].Y, \
[EDX].Width_, [EDX].Height, TRUE
ASSUME EDX: Nothing
STC
RETN
;
skip:
CLC
exit:
MOV EAX, 0
ADC EAX, EAX ; Set to FALSE or TRUE accord. CF
RET
prDlgMain ENDP
;
prBtnOk PROC hwnd:HWND, umsg:UINT, wparam:WPARAM, lparam:LPARAM
CMP umsg, WM_MOUSEMOVE
JNE sysproc
INVOKE PostMessage, hdlgMain, WmMouseOverBtn, wparam, lparam
sysproc:
LEAVE
JMP [pprBtnOkSys]
prBtnOk ENDP
;
calcBtnMov PROC Uses EBX EDI hdlgm:HWND, htxtref:HWND
LOCAL srctxt: RECT
LOCAL srcbtnok: RECT
LEA EBX, srcbtnok
ASSUME EBX: Ptr RECT
INVOKE GetWindowRect, hbtnOk, EBX
INVOKE MapWindowPoints, HWND_DESKTOP, hdlgm, EBX, SizeOf RECT/SizeOf POINT
INVOKE GetWindowRect, htxtref, Addr srctxt
INVOKE MapWindowPoints, HWND_DESKTOP, hdlgm, Addr srctxt, SizeOf RECT/SizeOf POINT
LEA EDI, sBtnMov
ASSUME EDI: Ptr BTN_MOV
; MoveWindow requires height & width of window instead of bottom & right coords
MovE [EDI].Y, EDX, [EBX].top
MOV EAX, [EBX].bottom
SUB EAX, EDX ; Button Height
MOV [EDI].Height, EAX
MovE [EDI].Xmin, EDX, srctxt.left
MovE [EDI].Xmax, EAX, [EBX].left
MOV [EDI].Xcur, EAX ; Current X coord.
MOV ECX, [EBX].right
SUB ECX, EAX ; Button width
MOV [EDI].Width_, ECX
SUB EAX, EDX ; Button Xpath = Xmax - Xmin
XOR EDX, EDX
MOV ECX, BtnStepNum
DIV ECX ; Xstep= Xpath / XstepNum
MOV [EDI].Xstep, EAX ; Pixels per step
ASSUME EBX: Nothing, EDI: Nothing
RET
calcBtnMov ENDP
;
setTextArrA PROC hwnd:HWND, pasz:PSZ, nsz:ND, isz:ID
sendloop:
INVOKE SendDlgItemMessageA, hwnd, isz, WM_SETTEXT, NULL, pasz
DEC nsz
JZ exit
INC isz
INVOKE lstrlenA, pasz
INC EAX ; Skip 0
ADD pasz, EAX ; Next string
JMP sendloop
exit:
RET
setTextArrA ENDP
;
setTextArrW PROC hwnd:HWND, pawsz:PWSZ, nwsz:ND, iwsz:ID
sendloop:
INVOKE SendDlgItemMessageW, hwnd, iwsz, WM_SETTEXT, NULL, pawsz
DEC nwsz
JZ exit
INC iwsz
INVOKE lstrlenW, pawsz
INC EAX ; Skip 0
ADD EAX, EAX ; Words->Bytes
ADD pawsz, EAX ; Next string
JMP sendloop
exit:
RET
setTextArrW ENDP
;
END START
;
Screenshot notarized by SkyNet and executable are attached.