WideCharToMultiByte in QB64

230 views Asked by At

Am having problems converting from ANSI to Unicode and back. The following code snip describes what I am doing. I am getting 0x57 errors..

DECLARE DYNAMIC LIBRARY "kernel32"
    FUNCTION MultiByteToWideChar& (codePage~&, dwFlags~&, lpszMbstring$, byteCount&, lpwszWcstring$, wideCount&)
    FUNCTION WideCharToMultiByte& (codePage~&, dwFlags~&, lpWideString$, BYVAL ccWideChar%, lpMultiByte$, BYVAL multibyte%, BYVAL defaultchar&, BYVAL usedchar&)
    FUNCTION GetLastError& ()
END DECLARE
DIM Filename AS STRING * 260, NewFilename AS STRING * 260, MultiByte AS STRING * 260
PRINT "Enter filename";: INPUT Filename$: 'Filename$ = Filename$ + CHR$(0)
x = MultiByteToWideChar(0, 0, Filename$, LEN(Filename$), NewFilename$, 260)
IF x = 0 THEN
    PRINT "Error 0x"; HEX$(GetLastError)
ELSE
    PRINT "Processing: "; NewFilename$
END IF
' do unicode stuff here
x = WideCharToMultiByte(65001, 0, NewFilename$, LEN(NewFilename$), MultiByte$, 0, 0, 0)
' display processed filename
IF x = 0 THEN
    PRINT "Error 0x"; HEX$(GetLastError)
ELSE
    PRINT MultiByte$
END IF
1

There are 1 answers

7
AudioBubble On BEST ANSWER

Some more args need to be passed with the BYVAL keyword:

FUNCTION MultiByteToWideChar& (BYVAL codePage~&, BYVAL dwFlags~&, lpszMbstring$, BYVAL byteCount&, lpwszWcstring$, BYVAL wideCount&)
FUNCTION WideCharToMultiByte& (BYVAL codePage~&, BYVAL dwFlags~&, lpWideString$, BYVAL ccWideChar%, lpMultiByte$, BYVAL multibyte%, BYVAL defaultchar&, BYVAL usedchar&)

Aside from that, the length of STRING * 260 is always 260, regardless of any value stored. This means Filename = Filename + CHR$(0) won't work as intended, not that either of MultiByteToWideChar or WideCharToMultiByte require null-terminated input (that's why the byteCount and ccWideChar params exist; sometimes you only want to operate on a part of a string).

Worse, even if you use _MEMFILL to set all bytes of Filename to 0 to allow you to deal with things using ASCIIZ strings, INPUT and LINE INPUT will fill any remaining bytes not explicitly entered into Filename with CHR$(32) (i.e. a blank space as if you pressed the spacebar). For example, if you enter "Hello", there would be 5 bytes for the string entered and 255 bytes of character code 32 (or &H20 if you prefer hexadecimal).

To save yourself this terrible headache ("hello world.bas" is a valid filename!), you'll want to use STRING, not STRING * 260. If the length is greater than 260, you should probably print an error message. Whether you allow a user to enter a new filename or not after that is up to you.

You'll also want to use the return value of MultiByteToWideChar since it is the number of characters in NewFilename:

DIM Filename AS STRING
DIM NewFilename AS STRING * 260
DIM MultiByte AS STRING * 260
...

' Note: LEN(NewFilename) = 260 (**always**)
' This is why the number of wide chars written
' is saved.
NewFilenameLen = MultiByteToWideChar(0, 0, Filename, LEN(Filename), NewFilename, LEN(NewFilename))

...

' Note: LEN(MultiByte) = 260 (**always**)
x = WideCharToMultiByte(65001, 0, NewFilename, NewFilenameLen, MultiByte, LEN(MultiByte), 0, 0)

...