Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
display unicode text(by windows api)
#1
Wink 
Hello everyone, I'm a beginner, and QBasic was the first programming language I learned during my student days, although my knowledge of it was quite basic. I'm delighted to see how powerful it has become today. In this forum, I've learned a lot, but I've noticed that most discussions are quite advanced, with relatively few resources suitable for beginners—especially regarding localization, which is rarely addressed. Through my own exploration, I’ve managed to create a program that displays Chinese text in graphics mode. The core mechanism involves calling the Windows API to convert GBK to UTF-16. Please don’t laugh at my amateurish code—I’m still learning, and I welcome any feedback or corrections on its shortcomings.Big Grin
Code: (Select All)
'$Console
_Title "Display Unicode Character - Test"
Declare Dynamic Library "kernel32"
    FUNCTION MultiByteToWideChar& (BYVAL CodePage AS LONG, BYVAL dwFlags AS LONG,_
                                  BYVAL lpMultiByteStr AS _OFFSET, BYVAL cbMultiByte AS LONG,_
                                  BYVAL lpWideCharStr AS _OFFSET, BYVAL cchWideChar AS LONG)
End Declare
'You can modify the path to point to their local font directory.
Const FONT_PATH = "c:\windows\fonts\"
'Define global font IDs (handles) for four fonts to be loaded
Dim Shared As Long fN3 'fn, fn1, fn2, fn3

text$ = "美丽中国Beautiful China"
mk_data$ = StringToUnicodeMK(text$)

'Dim As String inputStrSc, inputStrCon
'Use input,QBpe IDE shows garbled (ANSI display), but data stores correctly.
'Line Input "Input texts in the screen:", inputStrSc
'Initializes the screen and loads fonts.
initinput
'Switch to console (native Unicode support) for clean input
'_ScreenHide
'_Console On
'_Dest _Console
'Line Input "Input texts in the console:", inputStrCon
'_Console Off
'_ScreenShow
'_ScreenMove _Middle
'_Dest 0

'_UPrintString (50, 50), StringToUnicodeMK(inputStrSc + inputStrCon), , 16, fn
'_UPrintString (50, 80), mk_data$, , 16, fn
'_UPrintString (50, 110), mk_data$, , 16, fn1
'_UPrintString (50, 150), mk_data$, , 16, fn2
If fN3 > 0 Then
    _UPrintString (50, 200), mk_data$, , 16, fN3
Else
    _PrintString (50, 40), "Font load false._UPrintString may not work, use _PrintString for English"
End If
Sleep
_Font 16
'_FreeFont fn
'_FreeFont fn1
'_FreeFont fn2
_FreeFont fN3
System

'Initializes the screen and loads fonts.
Sub initinput
    Screen _NewImage(1000, 760, 32)
    _ScreenMove _Middle
    Cls , _RGB32(155, 155, 155)
    _PrintMode _KeepBackground
    Color _RGB32(0, 0, 0)
    'You may substitute simsun.ttc... with a locally supported font file.
    'fn = _LoadFont(FONT_PATH + "simsun.ttc", 20, "automono")
    'fn1 = _LoadFont(FONT_PATH + "KTGB2312.ttf", 30, "automono")
    'fn2 = _LoadFont(FONT_PATH + "STLITI.TTF", 40, "automono")
    fN3 = _LoadFont(FONT_PATH + "STHUPO.TTF", 50, "automono")
    If fN3 <= 0 Then
        ' Second fallback also failed
        Print "Fallback font also unavailable."
        Print "Using system default font (English only)."
        ' Use system default font (won't display Chinese properly)
        _Font 16
        ' Note: System font handle cannot be obtained directly
    End If
End Sub

'  Main function: Converts entire string at once, then unpacks
Function StringToUnicodeMK$ (teXt As String)
    Const CP_ACP = 0 ' Code page: ANSI (default system locale)
    Const UTF16_WIDTH = 2 'Character width in bytes for UTF-16 (little-endian)
    Dim As String result, buffer, str_null
    Dim As _Unsigned Long needed, written
    Dim As _Unsigned Integer i, posC
    Dim hi As _Unsigned _Byte
    If Len(teXt) = 0 Then Exit Function
    result = ""
    ' Convert entire string to Unicode in one operation
    str_null = teXt + Chr$(0)
    needed = MultiByteToWideChar(CP_ACP, 0, _Offset(str_null$), Len(str_null$), 0, 0)
    If needed <= 1 Then Exit Function
    buffer = Space$(needed * UTF16_WIDTH) ' Allocate buffer for wide chars
    written = MultiByteToWideChar(CP_ACP, 0, _Offset(str_null$), Len(str_null$), _Offset(buffer), needed)
    If written <= 1 Then Exit Function
    ' Unpack wide characters and pack into MK$ format (skip final null)
    For i = 1 To written - 1
        posC = (i - 1) * UTF16_WIDTH + 1 'Position in byte buffer (1-based)
        ' Asc(buffer, posC + 1)  High byte (for Chinese characters)
        ' If hi = 0, character is ASCII, value is low byte only
        ' Pack as little-endian 16-bit integer (QB64 uses little-endian architecture)
        result = result + _MK$(Integer, Asc(buffer, posC + 1) * 256 + Asc(buffer, posC))
    Next
    StringToUnicodeMK = result
End Function
[Image: 2025-12-06-100059.png]




Attached Files
.ttf   STHUPO.TTF (Size: 3.54 MB / Downloads: 16)
Reply
#2
Hi @qbfans, your code looks pretty advanced to me, welcome to the forum!

Well I tried your code it doesn't work, I suspect the fonts aren't loading and maybe more...

I am wondering about the line that starts fn = ... because fn is old QB command word so the IDE editor is highlighting fn like a command word.

I am going to try a font load test function that will alert me if a font doesn't load.
  724  855  599  923  575  468  400  206  147  564  878  823  652  556 bxor cross forever
Reply
#3
Well yes the fonts aren't loading except first?

Didn't get anywhere with Chinese Text.
Code: (Select All)
$Console
_Title "Display Unicode Character - Test"
Declare Dynamic Library "kernel32"
    FUNCTION MultiByteToWideChar& (BYVAL CodePage AS LONG, BYVAL dwFlags AS LONG,_
                                  BYVAL lpMultiByteStr AS _OFFSET, BYVAL cbMultiByte AS LONG,_
                                  BYVAL lpWideCharStr AS _OFFSET, BYVAL cchWideChar AS LONG)
End Declare
'You can modify the path to point to their local font directory.
Const FONT_PATH = "c:\windows\fonts\"

Dim Shared As Long fn, fn1, fn2, fn3

text$ = "????Beautiful China"
mk_data$ = StringToUnicodeMK(text$)

Dim As String inputStrSc, inputStrCon
'Use input,QBpe IDE shows garbled (ANSI display), but data stores correctly.
'Line Input "Input texts in the screen:",
inputStrSc = "Hi qbfans!"
'Initializes the screen and loads fonts.
initinput
'Switch to console (native Unicode support) for clean input
_ScreenHide
_Console On
_Dest _Console
'Line Input "Input texts in the console:",
inputStrCon = " testing code..."
_Console Off
_ScreenShow
_Delay .3
_ScreenMove _Middle
_Dest 0

_UPrintString (50, 50), StringToUnicodeMK(inputStrSc + inputStrCon), , 16, fn
_UPrintString (50, 80), mk_data$, , 16, fn
'_UPrintString (50, 110), mk_data$, , 16, fn1
'_UPrintString (50, 150), mk_data$, , 16, fn2
'_UPrintString (50, 200), mk_data$, , 16, fn3

Sleep
_Font 16
_FreeFont fn
'_FreeFont fn1  ' not found
'_FreeFont fn2  ' ditto
'_FreeFont fn3  ' ditto
System

'Initializes the screen and loads fonts.
Sub initinput
    Screen _NewImage(1000, 760, 32)
    _ScreenMove _Middle
    Cls , _RGB32(155, 155, 155)
    _PrintMode _KeepBackground
    Color _RGB32(0, 0, 0)
    'You may substitute simsun.ttc... with a locally supported font file.
    fn = OKFont&(FONT_PATH + "simsun.ttc", 20, "automono")
    'fn1 = OKFont&(FONT_PATH + "KTGB2312.ttf", 30, "automono")
    'fn2 = OKFont&(FONT_PATH + "STLITI.TTF", 40, "automono")
    'fn3 = OKFont&(FONT_PATH + "STHUPO.TTF", 50, "automono")
End Sub

'  Main function: Converts entire string at once, then unpacks
Function StringToUnicodeMK$ (teXt As String)
    Const CP_ACP = 0 ' Code page: ANSI (default system locale)
    Const UTF16_WIDTH = 2 'Character width in bytes for UTF-16 (little-endian)
    Dim As String result, buffer, str_null
    Dim As _Unsigned Long needed, written
    Dim As _Unsigned Integer i, posC
    Dim hi As _Unsigned _Byte
    If Len(teXt) = 0 Then Exit Function
    result = ""
    ' Convert entire string to Unicode in one operation
    str_null = teXt + Chr$(0)
    needed = MultiByteToWideChar(CP_ACP, 0, _Offset(str_null$), Len(str_null$), 0, 0)
    If needed <= 1 Then Exit Function
    buffer = Space$(needed * UTF16_WIDTH) ' Allocate buffer for wide chars
    written = MultiByteToWideChar(CP_ACP, 0, _Offset(str_null$), Len(str_null$), _Offset(buffer), needed)
    If written <= 1 Then Exit Function
    ' Unpack wide characters and pack into MK$ format (skip final null)
    For i = 1 To written - 1
        posC = (i - 1) * UTF16_WIDTH + 1 'Position in byte buffer (1-based)
        ' Asc(buffer, posC + 1)  High byte (for Chinese characters)
        ' If hi = 0, character is ASCII, value is low byte only
        ' Pack as little-endian 16-bit integer (QB64 uses little-endian architecture)
        result = result + _MK$(Integer, Asc(buffer, posC + 1) * 256 + Asc(buffer, posC))
    Next
    StringToUnicodeMK = result
End Function

Function OKFont& (pathFile$, size%, style$)
    result& = _LoadFont(pathFile$, size%, style$)
    If result& > 0 Then OKFont& = result& Else Print pathFile$ + " not found, goodbye": End
End Function

At least it runs without error for me.
   

Actually the font looks unchanged so maybe even the first font, fn = OKFont&(FONT_PATH + "simsun.ttc", 20, "automono"), didn't load right either???
  724  855  599  923  575  468  400  206  147  564  878  823  652  556 bxor cross forever
Reply
#4
Thank you, bplus, for pointing that out. You're absolutely right — I made a serious mistake by not providing any error handling when the font fails to load.I have already updated the original post with corrections.

Let me clarify a few points:

The purpose of this program is to demonstrate a method for correctly displaying local/national characters (rather than garbled text) in QB64 applications. English users typically don't encounter this issue. On Chinese Windows systems where I've tested it, the display works correctly.

Variables like fn, fn1, etc., are simply font handles used by the _LoadFont function. I'm not sure why fn appears highlighted, but pressing F1 doesn't bring up help information. The multiple fonts are loaded only for demonstration purposes.

Since my testing was done on Chinese Windows systems, I didn't initially include Chinese font files, as they wouldn't be meaningful for most users and might affect testing results. However, I did leave comments in the code indicating that users should replace the font paths with their own local fonts and directories.

The LINE INPUT section addresses a quirk in QB64's graphical mode where typed characters appear garbled on screen (though stored correctly in memory), making it hard for users to review or edit their input. Console mode provides a more user-friendly input experience. The dual INPUT sections are merely for comparison and are optional — they're included for anyone interested in testing the difference. Note that using the console requires the $CONSOLE metacommand.

Following bplus's suggestion, I've revised the code by removing unnecessary portions and have now uploaded the STHUPO.TTF font file. If you place it in your Windows\Fonts directory, you should see it render correctly.

I hope this approach helps non-English speakers display their native characters properly in QB64.

Thank you all again for your feedback and corrections.
Reply
#5
Ok here is translation of edited post:
   

Thats Russian?

Anyway I tested edited post that qbfans did, see attached zip as I didn't want to load the font file into Windows Fonts Folder, see attached. 

Here is result:
   

Dang lost the Chinese Text but ran without error. @qbfans notice the screen is not in the middle. I recommend before using _ScreenMove _Middle to put a: _Delay [fraction of second], to allow time for the screen to load before it is moved. This is usually the problem with that particular command, oddly _ScreenMove with actual numbers works faster, for me anyway and no _Delay is needed.

+1 @qbfans thanks for sharing and fixing.

Edit: oops forgot to save the edited filed before zipping, new zip file now.

.zip   Test qbfans code.zip (Size: 2.39 MB / Downloads: 24)
  724  855  599  923  575  468  400  206  147  564  878  823  652  556 bxor cross forever
Reply
#6
I haven't had a chance to look closely over this, and from what I see just scrolling above, there appears to be as much code remarked out as there is code active, so I can't really follow it much on my browser. 

Let me give a quick demo of displaying chinese characters for you.  I'm not fluent in the language so have no idea if I'm missing something here, but here's how to get a simplified chinese to display:

Code: (Select All)
Screen _NewImage(800, 600, 32)
chinese$ = _ReadFile$("Chinese-Simplified8.txt") 'read out chinese file
Screen _NewImage(800, 600, 32) '32-bit screen for custom font
f = _LoadFont("msyh.ttc", 16, "monospace") 'load the windows built in chinese font
_Font f 'swap to that font
_UPrintString (0, 0), chinese$, 800, 8, f 'print the file

'note that there are no breakpoints in this file and no wordwrap.  You'd need to detect those and split them yourself.

The font used is the one packaged for windows and should be readily available for most systems (I think).
The file with the chinese is below. Feel free to grab and test it.


Attached Files
.txt   Chinese-Simplified8.txt (Size: 29.28 KB / Downloads: 24)
Reply
#7
AI generated? It appears that way to me.

Pete
Reply
#8
Well Steves version is way simpler than qbfans. As Pete commented I had same suspecions, if qbfans was testing his AI code with us? But he did originally post all that code with only very few commented lines and his original graphic of his successful result remains in OP.

I have no experience in Unicode so don't know squat but qbfans mentioned extra wide character handling in his code so it didn't look like just a straight font load and print thing to me in the middle of the night, last.
  724  855  599  923  575  468  400  206  147  564  878  823  652  556 bxor cross forever
Reply
#9
My English is quite basic, so all the program descriptions and code comments I posted were translated into English using Deepseek.

Actually, the core issue is that most members on this forum are from Latin language backgrounds, and they don't face the same Chinese character display problems that I do. There were no existing posts on this topic in the forum, so I had to explore and test everything myself. I studied lots of documentation and Unicode articles, and only posted after successfully getting it to work. Some experts might even think this simple code isn't worth mentioning.

The code itself doesn't contain any advanced technical concepts for forum experts—it's just that no one had posted about this before. Steven's solution is excellent—he saves text as UTF-8 files, reads UTF-8 formatted text, and displays it using _UPrintString with parameter 8.

However, as I mentioned earlier, my problem is that I need to display Chinese character strings that are assigned within my code and entered by users in graphics mode. Clearly, Steven's high-quality code can't solve this, because strings assigned in QB or obtained via INPUT use ANSI encoding by default. These need to be converted to Unicode16 or UTF-8 encoding before they can be displayed using _UPrintString with parameter 8 or 16. That's why I even wrote a UTF-16 → UTF-8 conversion function in QB for testing, to confirm this approach would work.

Of course, this explanation is also translated by Deepseek. I'm not even sure if the translation accurately conveys what I mean. This code is just meant to provide a reference for others who have similar needs and are at a similar skill level as me.
Reply
#10
Hi qbfans,

The Deepseek translations seem excellent to me, very clear, hopefully they are doing as well with your meaning as they do with the English.

And though I am fortunate to have QB64pe in my primary language I do appreciate the efforts made by folks who don't use English as their primary to help others with what they learn while overcoming word representations and symbols. Thats what forums are about, good efforts @qbfans!
  724  855  599  923  575  468  400  206  147  564  878  823  652  556 bxor cross forever
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Inkey Literal Key Display Pete 5 564 01-07-2026, 03:57 AM
Last Post: Pete
  Text Effects 2 2112 6 644 10-30-2025, 11:13 PM
Last Post: Unseen Machine
  Text Encryption-Decryption 2112 6 709 10-21-2025, 11:51 AM
Last Post: euklides
  Vacuum Flourescent Display Clock With Alarm SierraKen 5 1,168 06-07-2025, 11:02 PM
Last Post: SierraKen
  Upside-Down Big Text SierraKen 2 664 02-22-2025, 01:52 AM
Last Post: SierraKen

Forum Jump:


Users browsing this thread: 1 Guest(s)