News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

About TCHAR support and bugs

Started by qWord, September 10, 2012, 12:49:39 AM

Previous topic - Next topic

qWord

Hello,

Some time back I've recognize that the TCHAR support in the current SDK is insufficient. For example there are no macros for conversion between TCHAR <> Unicode and TCHAR <> Ascii. Also the conversion macros like udword$(),real4$(),... are not TCHAR aware.
Here are my suggestions:
WCharToAscii proc pBufferAscii:PCHAR,ccBuffer:DWORD,pszWChar:PWCHAR
LOCAL szCodePage[8]:CHAR
   
    invoke GetLocaleInfoA,LOCALE_USER_DEFAULT,LOCALE_IDEFAULTANSICODEPAGE,ADDR szCodePage,SIZEOF szCodePage
    .if eax
        lea edx,szCodePage
        xor eax,eax
        .while CHAR ptr [edx]
            movzx ecx,CHAR ptr [edx]
            imul eax,eax,10
            lea eax,[eax+ecx-'0']
            lea edx,[edx+1]
        .endw
    .endif
    invoke WideCharToMultiByte,eax,0,pszWChar,-1,pBufferAscii,ccBuffer,0,0
    mov eax,pBufferAscii
    ret
   
WCharToAscii endp

AsciiToWChar proc pBufferWChar:PWCHAR,ccBuffer:DWORD,pszAscii:PCHAR
LOCAL szCodePage[8]:CHAR
   
    invoke GetLocaleInfoA,LOCALE_USER_DEFAULT,LOCALE_IDEFAULTANSICODEPAGE,ADDR szCodePage,SIZEOF szCodePage
    .if eax
        lea edx,szCodePage
        xor eax,eax
        .while CHAR ptr [edx]
            movzx ecx,CHAR ptr [edx]
            imul eax,eax,10
            lea eax,[eax+ecx-'0']
            lea edx,[edx+1]
        .endw
    .endif
    invoke MultiByteToWideChar,eax,MB_PRECOMPOSED,pszAscii,-1,pBufferWChar,ccBuffer
    mov eax,pBufferWChar
    ret
   
AsciiToWChar endp

; TCHAR-macros
; pBuffer must not be pszTChar
tc2a macro pBuffer:req,ccBuffer:=<7fffffffh>,pszTChar:req
    IFNDEF __UNICODE__
        push pBuffer
        fn szCopy,pszTChar,pBuffer
        pop eax
    ELSE
        fn WCharToAscii,pBuffer,ccBuffer,pszTChar
    ENDIF
    EXITM <eax>
endm

; pBuffer must not be pszAscii
a2tc macro pBuffer:req,ccBuffer:=<7fffffffh>,pszAscii:req
    IFNDEF __UNICODE__
        push pBuffer
        fn szCopy,pszAscii,pBuffer
        pop eax
    ELSE
        fn AsciiToWChar,pBuffer,ccBuffer,pszAscii
    ENDIF
    EXITM <eax>
endm

; pBuffer must not be pszTChar
tc2uc macro pBuffer:req,ccBuffer:=<7fffffffh>,pszTChar:req
    IFDEF __UNICODE__
        push pBuffer
        fn ucCopy,pszTChar,pBuffer
        pop eax
    ELSE
        fn AsciiToWChar,pBuffer,ccBuffer,pszTChar
    ENDIF
    EXITM <eax>
endm

; pBuffer must not be pszWChar
uc2tc macro pBuffer:req,ccBuffer:=<7fffffffh>,pszWChar:req
    IFDEF __UNICODE__
        push pBuffer
        fn ucCopy,pszWChar,pBuffer
        pop eax
    ELSE
        fn WCharToAscii,pBuffer,ccBuffer,pszWChar
    ENDIF
    EXITM <eax>
endm

;; TCHAR-macros
;tc2a macro pBuffer:req,ccBuffer:=<7fffffffh>,pszTChar:req
;    IFNDEF __UNICODE__
;        EXITM <pszTChar>
;    ENDIF
;    fn WCharToAscii,pBuffer,ccBuffer,pszTChar
;    EXITM <eax>
;endm
;
;a2tc macro pBuffer:req,ccBuffer:=<7fffffffh>,pszAscii:req
;    IFNDEF __UNICODE__
;        EXITM <pszAscii>
;    ENDIF
;    fn AsciiToWChar,pBuffer,ccBuffer,pszAscii
;    EXITM <eax>
;endm
;
;tc2uc macro pBuffer:req,ccBuffer:=<7fffffffh>,pszTChar:req
;    IFDEF __UNICODE__
;        EXITM <pszTChar>
;    ENDIF
;    fn AsciiToWChar,pBuffer,ccBuffer,pszTChar
;    EXITM <eax>
;endm
;
;uc2tc macro pBuffer:req,ccBuffer:=<7fffffffh>,pszWChar:req
;    IFDEF __UNICODE__
;        EXITM <pszWChar>
;    ENDIF
;    fn WCharToAscii,pBuffer,ccBuffer,pszWChar
;    EXITM <eax>
;endm

; declare TCHAR-strings
TCHR macro lbl,literals:VARARG
    IFDEF __UNICODE__
        UCSTR lbl,literals
    ELSE
        lbl db literals
    ENDIF
endm

CTCHR macro lbl,literals:VARARG
    IFDEF __UNICODE__
        UCCSTR lbl,literals
    ELSE
        ?cstr? lbl,literals
    ENDIF
endm



    ; internal macro for converting integer and floating point values to strings
    ; _value = register or memory expression
    ; mname = name of convertion-macro
    ; pszTChrFrmt = pointer to format string (TCHAR)
    ; opr_size = size of type
    ; ccBufferSize = size of buffer in TCHARs
    ; _type = type-specifier: BYTE,SBYTE,...
    ; use_wsprintf    = 0 => use crt_sprintf (CRT)
    ;                != 0 => use wsprintf (user32.dll)
    ???To$ macro _value:req,mname:req,pszTChrFrmt:req,opr_size:req,ccBufferSize:req,_type:req,use_wsprintf:=<0>
        LOCAL buffer,tmp,val
        .data?
            buffer TCHAR ccBufferSize dup(?)
        .code
            IFE issize(_value, opr_size)
                echo ----------------------
                echo mname - requires _type
                echo ----------------------
                .ERR
            ENDIF               
            mov buffer[0], 0
            IF opr_size EQ 1 OR opr_size EQ 2
                IF type _type EQ type SBYTE OR type _type EQ type SWORD
                    movsx eax,_value
                ELSE
                    movzx eax,_value
                ENDIF
                val TEXTEQU <eax>
            ELSEIF opr_size EQ 4
                IF type _type EQ type REAL4
                    sub esp,8
                    finit
                    fld _value
                    fstp REAL8 ptr [esp]
                    mov eax,DWORD ptr [esp]
                    mov edx,DWORD ptr [esp+4]
                    add esp,8
                    val TEXTEQU <edx::eax>
                ELSE
                    val TEXTEQU <&_value>
                ENDIF
            ELSEIF opr_size EQ 8
                IF @InStr(1,<_value>,<::>) EQ 0
                    mov eax,DWORD ptr (_value)
                    mov edx,DWORD ptr (_value)[4]
                    val TEXTEQU <edx::eax>
                ELSE
                    val TEXTEQU <_value>
                ENDIF
            ELSEIF opr_size EQ 10 AND type _type EQ type REAL10
                sub esp,8
                finit
                fld _value
                fstp REAL8 ptr [esp]
                mov eax,DWORD ptr [esp]
                mov edx,DWORD ptr [esp+4]
                add esp,8
                val TEXTEQU <edx::eax>
            ELSE
                .err <invalid usage>
                EXITM <0>
            ENDIF
           
            IF use_wsprintf EQ 0
                IFNDEF __UNICODE__
                    invoke crt_sprintf, ADDR buffer, pszTChrFrmt, val
                ELSE
                    invoke crt_swprintf, ADDR buffer, pszTChrFrmt, val
                ENDIF
            ELSE
                invoke wsprintf,ADDR buffer, pszTChrFrmt, val
            ENDIF
           
            EXITM <OFFSET buffer>
    endm

    ubyte$ MACRO ubytevalue:req
        IFNDEF ??ubfmt
            .data
                TCHR ??ubfmt,"%u",0
            .code
        ENDIF
        EXITM ???To$(ubytevalue,<ubyte$>,ADDR ??ubfmt,1,4,BYTE)
    endm

    sbyte$ MACRO sbytevalue:req
        IFNDEF ??sbfmt
            .data
                TCHR ??sbfmt,"%d",0
            .code
        ENDIF
        EXITM ???To$(sbytevalue,<sbyte$>,ADDR ??sbfmt,1,5,SBYTE)
    endm
   
    xbyte$ MACRO xbytevalue:req
        IFNDEF ??xbfmt
            .data
                TCHR ??xbfmt,"%X",0
            .code
        ENDIF
        EXITM ???To$(xbytevalue,<xbyte$>,ADDR ??xbfmt,1,3,BYTE)
    endm
   
    uword$ MACRO uwordvalue:req
        IFNDEF ??uwfmt
            .data
                TCHR ??uwfmt,"%u",0
            .code
        ENDIF
        EXITM ???To$(uwordvalue,<uword$>,ADDR ??uwfmt,2,6,WORD)
    endm
   
    sword$ MACRO swordvalue:req
        IFNDEF ??swfmt
            .data
                TCHR ??swfmt,"%d",0
            .code
        ENDIF
        EXITM ???To$(swordvalue,<sword$>,ADDR ??swfmt,2,7,SWORD)
    endm

    xword$ MACRO xwordvalue:req
        IFNDEF ??xwfmt
            .data
                TCHR ??xwfmt,"%X",0
            .code
        ENDIF
        EXITM ???To$(xwordvalue,<xword$>,ADDR ??xwfmt,2,5,WORD)
    endm
   
    udword$ MACRO udwordvalue:req
        IFNDEF ??udfmt
            .data
                TCHR ??udfmt,"%u",0
            .code
        ENDIF
        EXITM ???To$(udwordvalue,<udword$>,ADDR ??udfmt,4,11,DWORD)
    endm
   
    sdword$ MACRO sdwordvalue:req
        IFNDEF ??sdfmt
            .data
                TCHR ??sdfmt,"%d",0
            .code
        ENDIF
        EXITM ???To$(sdwordvalue,<sdword$>,ADDR ??sdfmt,4,12,SDWORD)
    endm
   
    xdword$ MACRO xdwordvalue:req
        IFNDEF ??xdfmt
            .data
                TCHR ??xdfmt,"%X",0
            .code
        ENDIF
        EXITM ???To$(xdwordvalue,<xdword$>,ADDR ??xdfmt,4,9,DWORD)
    endm
   
    uqword$ MACRO uqwordvalue:req
        IFNDEF ??uqwfmt
            .data
                TCHR ??uqwfmt,"%I64u",0
            .code
        ENDIF
        EXITM ???To$(uqwordvalue,<uqword$>,ADDR ??uqwfmt,8,21,QWORD)
    endm
   
    sqword$ MACRO sqwordvalue:req
        IFNDEF ??sqwfmt
            .data
                TCHR ??sqwfmt,"%I64d",0
            .code
        ENDIF
        EXITM ???To$(sqwordvalue,<sqword$>,ADDR ??sqwfmt,8,22,QWORD)
    endm

    xqword$ MACRO xqwordvalue:req
        IFNDEF ??xqwfmt
            .data
                TCHR ??xqwfmt,"%I64X",0
            .code
        ENDIF
        EXITM ???To$(xqwordvalue,<xqword$>,ADDR ??xqwfmt,8,17,QWORD)
    endm
   
    real4$ MACRO r4value:req
        LOCAL tmp
        IFNDEF ??r8fmt
            .data
                TCHR ??r8fmt,"%f",0
            .code
        ENDIF
        IFE (OPATTR r4value) AND 2
            IF issize(r4value, 4)
                push r4value
                lea edx,[esp]
                tmp TEXTEQU ???To$(REAL4 ptr [edx],<real4$>,ADDR ??r8fmt,4,32,REAL4)
                add esp,4
                EXITM tmp
            ELSE
                .err <real4$ - requires memory expression>
                EXITM <0>
            ENDIF
        ENDIF
        EXITM ???To$(r4value,<real4$>,ADDR ??r8fmt,4,32,REAL4)
    ENDM
   
    real8$ MACRO r8value:req
        IFNDEF ??r8fmt
            .data
                TCHR ??r8fmt,"%f",0
            .code
        ENDIF
        IFE (OPATTR r8value) AND 2
            .err <real8$ - requires memory expression>
            EXITM <0>
        ENDIF
        EXITM ???To$(r8value,<real8$>,ADDR ??r8fmt,8,32,REAL8)
    ENDM
   
    real10$ MACRO r10value:req
        IFNDEF ??r8fmt
            .data
                TCHR ??r8fmt,"%f",0
            .code
        ENDIF
        IFE (OPATTR r10value) AND 2
            .err <real10$ - requires memory expression>
            EXITM <0>
        ENDIF
        EXITM ???To$(r10value,<real10$>,ADDR ??r8fmt,10,32,REAL10)
    ENDM


    udb$ MACRO ubytevalue:req
        IFNDEF ??ubfmt
            .data
                TCHR ??ubfmt,"%u",0
            .code
        ENDIF
        EXITM ???To$(ubytevalue,<ubyte$>,ADDR ??ubfmt,1,4,BYTE,1)
    endm

    sdb$ MACRO sbytevalue:req
        IFNDEF ??sbfmt
            .data
                TCHR ??sbfmt,"%d",0
            .code
        ENDIF
        EXITM ???To$(sbytevalue,<sbyte$>,ADDR ??sbfmt,1,5,SBYTE,1)
    endm

    xdb$ MACRO xbytevalue:req
        IFNDEF ??xbfmt
            .data
                TCHR ??xbfmt,"%X",0
            .code
        ENDIF
        EXITM ???To$(xbytevalue,<xbyte$>,ADDR ??xbfmt,1,3,BYTE,1)
    endm
   
    udw$ MACRO uwordvalue:req
        IFNDEF ??uwfmt
            .data
                TCHR ??uwfmt,"%u",0
            .code
        ENDIF
        EXITM ???To$(uwordvalue,<uword$>,ADDR ??uwfmt,2,6,WORD,1)
    endm
   
    sdw$ MACRO swordvalue:req
        IFNDEF ??swfmt
            .data
                TCHR ??swfmt,"%d",0
            .code
        ENDIF
        EXITM ???To$(swordvalue,<sword$>,ADDR ??swfmt,2,7,SWORD,1)
    endm

    xdw$ MACRO xwordvalue:req
        IFNDEF ??xwfmt
            .data
                TCHR ??xwfmt,"%X",0
            .code
        ENDIF
        EXITM ???To$(xwordvalue,<xword$>,ADDR ??xwfmt,2,5,WORD,1)
    endm
   
   
    udd$ MACRO udwordvalue:req
        IFNDEF ??udfmt
            .data
                TCHR ??udfmt,"%u",0
            .code
        ENDIF
        EXITM ???To$(udwordvalue,<udword$>,ADDR ??udfmt,4,11,DWORD,1)
    endm
   
    sdd$ MACRO sdwordvalue:req
        IFNDEF ??sdfmt
            .data
                TCHR ??sdfmt,"%d",0
            .code
        ENDIF
        EXITM ???To$(sdwordvalue,<sdword$>,ADDR ??sdfmt,4,12,SDWORD,1)
    endm
   
    xdd$ MACRO xdwordvalue:req
        IFNDEF ??xdfmt
            .data
                TCHR ??xdfmt,"%X",0
            .code
        ENDIF
        EXITM ???To$(xdwordvalue,<xdword$>,ADDR ??xdfmt,4,9,DWORD,1)
    endm
   
    udq$ MACRO uqwordvalue:req
        IFNDEF ??uqwfmt
            .data
                TCHR ??uqwfmt,"%I64u",0
            .code
        ENDIF
        EXITM ???To$(uqwordvalue,<uqword$>,ADDR ??uqwfmt,8,21,QWORD,1)
    endm
   
    sdq$ MACRO sqwordvalue:req
        IFNDEF ??sqwfmt
            .data
                TCHR ??sqwfmt,"%I64d",0
            .code
        ENDIF
        EXITM ???To$(sqwordvalue,<sqword$>,ADDR ??sqwfmt,8,22,QWORD,1)
    endm

    xdq$ MACRO xqwordvalue:req
        IFNDEF ??xqwfmt
            .data
                TCHR ??xqwfmt,"%I64X",0
            .code
        ENDIF
        EXITM ???To$(xqwordvalue,<xqword$>,ADDR ??xqwfmt,8,17,QWORD,1)
    endm

The two procedures, WCharToAscii and AsciiToWChar, are using the user's current code page for conversion between Unicode and Ascii. Feedback about the macros and function would be great.

I've also discovered some bugs:

issize-macro:
The macro uses the SIZE operator. This operator rejects valid, typecast expressions like DWORD pr [reg32]. The TYPE operator should be used instead, because it also return the number of bytes and does not reject typecast expressions. This was/is problem with conversion macros type$():
    issize MACRO var:req, bytes:req
        LOCAL rval
        rval = regsize(var)
        IFE rval ; if not a register use TYPE <== previously: SIZE
            IF TYPE var EQ bytes
                EXITM <1>
            ELSE
                EXITM <0>
            ENDIF
        ELSE   ; it's a register       
            IF rval EQ bytes
                EXITM <1>       
            ELSE
                EXITM <0>
            ENDIF   
        ENDIF
    ENDM


UCCSTR and ?cstr?:
The macros emit 10, 13 instead of 13, 10 for "\n". This can easily fixed by replacing the strikingly line (the same in both macros):
Quote... SUBSTR <  5ch00h28h29h3ch3eh21h22h09h25h26h0ah,0dh>,...
==>
... SUBSTR <  5ch00h28h29h3ch3eh21h22h09h25h26h0dh,0ah>,...

regards, qWord

EIDT: add new version of a2tc,tc2a,uc2tc and tc2uc
MREAL macros - when you need floating point arithmetic while assembling!

TouEnMasm

Quote
Some time back I've recognize that the TCHAR support in the current SDK is insufficient. For example there are no macros for conversion between TCHAR, Unicode and Ascii
There is functions for that:
WideCharToMultiByte
MultiByteToWideChar
SysAllocString ......
Seems also you (or one another ) have made a macro for ascii >> unicode


Fa is a musical note to play with CL

qWord

Quote from: ToutEnMasm on September 10, 2012, 01:23:47 AM
Quote
Some time back I've recognize that the TCHAR support in the current SDK is insufficient. For example there are no macros for conversion between TCHAR, Unicode and Ascii
There is functions for that:
WideCharToMultiByte
MultiByteToWideChar
SysAllocString ......
Seems also you (or one another ) have made a macro for ascii >> unicode
you didn't look at the code?
MREAL macros - when you need floating point arithmetic while assembling!

TouEnMasm


A macro who can just interpret the masm natural syntax will be good for me.
  (dw) "fghjkl",13,10,"56486',0
Why use \n ....
Fa is a musical note to play with CL

qWord

Quote from: ToutEnMasm on September 10, 2012, 01:53:17 AM

A macro who can just interpret the masm natural syntax will be good for me.
  (dw) "fghjkl",13,10,"56486',0
there allready a macro in the SDK: UCSTR
MREAL macros - when you need floating point arithmetic while assembling!

jj2007

... not to mention a wealth of Unicode support in MasmBasic ;-)

TouEnMasm


One BSTR is more often many BSTR and many useless lines to read.
A usefull tool for masm can be to create as many BSTR needed and just free them at the end.
Fa is a musical note to play with CL

qWord

Quote from: ToutEnMasm on September 10, 2012, 03:14:50 AM
One BSTR is more often many BSTR and many useless lines to read.
A usefull tool for masm can be to create as many BSTR needed and just free them at the end.
A screwdriver is a good tool! And what is useless? - Your posts in this thread!
MREAL macros - when you need floating point arithmetic while assembling!

TouEnMasm


Quote
A screwdriver is a good tool! And what is useless? - Your posts in this thread
Sorry,I leave you
Fa is a musical note to play with CL