UNICODE support in FreeBasic

General FreeBASIC programming questions.
Patrice Terrier
Posts: 35
Joined: Jan 06, 2006 8:27
Location: France
Contact:

UNICODE support in FreeBasic

Post by Patrice Terrier »

Trying to convert C/C++ source code, I have a hard time to figure how to use UNICODE in FB.
Using litteral L"Unicode string", and WCHAR (wchar_t)

UNICODE is a mandatory in modern Windows programming.

So far I am forced to use
Dim zSkinFile As WString * 260 => "Sony.sks"
and pass the string pointer like this: @zSkinFile

Also does there is a built-in function to retrieve the EXE path of an executable.

So far I am using this, but that doesn't work

Code: Select all

Function EXEpath() As WString Ptr
    Static usepath As WString * MAX_PATH
    Dim As DWORD result = GetModuleFileNameW(0, usepath, MAX_PATH)
    If result > 0 Then
        Dim As Long nLen = wcslen(usepath)
        For k As Long = 1 To nLen
            If wcsicmp(@usepath[nLen - k], @"\") <> 0 Then
                usepath[nLen - k] = 0
            Else
                Exit For
            End If
        Next
    End If
    Return @usepath
End Function


Here is my original C/C++ function

Code: Select all

static void ClearMemory(IN void* mem, IN long nSize) {
#ifdef _WIN64
    __stosb((PBYTE) mem, (BYTE) 0, (SIZE_T) nSize);
#elif defined(_WIN32)
    memset(mem, 0, nSize);
#endif
}

Code: Select all

#define strSize(s) ( sizeof(s) / sizeof(s[0]) )

static WCHAR* EXEpath() {
    static WCHAR zpath[MAX_PATH];
    static long done;
    if (done == 0) {
        ClearMemory(zpath, sizeof(zpath));
        if (GetModuleFileName(0, zpath, strSize(zpath))) {
            long nLen = lstrlen(zpath);
            long nPos = nLen;
            for (long K = 1; K <= nLen; K++) {
                if (_wcsicmp(&zpath[nPos - K], L"\\") != 0) { 
                    zpath[nPos - K] = NULL;
                } else {
                    break;
                }
            }
        }
        done = -1;
    }
    return zpath;
}
Imortis
Moderator
Posts: 1984
Joined: Jun 02, 2005 15:10
Location: USA
Contact:

Re: UNICODE support in FreeBasic

Post by Imortis »

Patrice Terrier wrote: Jun 17, 2025 15:58 ...
Also does there is a built-in function to retrieve the EXE path of an executable.
...
Yes. See here: Exepath
caseih
Posts: 2199
Joined: Feb 26, 2007 5:32

Re: UNICODE support in FreeBasic

Post by caseih »

If your .bas file is itself encoded in UTF-16 or UTF-8, the FB compiler will automatically convert string literals to UTF-16 (or UTF-32 on Linux) when assigning to a WSTRING, or passing to a function that requires WSTRING.

Like C and C++, FB has virtually no intrinsic support for unicode, other than WSTRING and naive, wide string-versions of mid, left, right, chr, etc. If you need to manipulate unicode encoded strings properly (if that is even possible given the complexity of unicode), you'll have to use a third-party library that works with UTF-8 or UTF-16 directly. In the future once the transition to UTF-8 by default is finished in Windows, it would make some sense to make FB's runtime library string functions UTF-8 native, and ditch WSTRING entirely.

There is a .bi file that comes with FB for doing UTF-8 encoding and decoding text files.
caseih
Posts: 2199
Joined: Feb 26, 2007 5:32

Re: UNICODE support in FreeBasic

Post by caseih »

Imortis wrote: Jun 17, 2025 16:13 Yes. See here: Exepath
If the path has any unicode characters in it, I'm not sure this will work. The runtime library source code appears to be calling GetModuleFileNameA. I suspect @Patrice Terrier will have to call the win32 GetModuleFileNameW() version directly.
Patrice Terrier
Posts: 35
Joined: Jan 06, 2006 8:27
Location: France
Contact:

Re: UNICODE support in FreeBasic

Post by Patrice Terrier »

If there is no direct support for UNICODE wchar_t (WCHAR), I think I shall give up for now on the translation of my C/C++ code.

PowerBASIC has UCODE$ that could be used like this: UCODE$("my string").
Much easier to use than this
Dim zTip As WString * 260 => "Previous skin theme"
skCreateToolTip(hCtrl, @zTip)

I would like to use directly someting like this
skCreateToolTip(hCtrl, UCODE$("Previoud skin theme"))
srvaldez
Posts: 3653
Joined: Sep 25, 2005 21:54

Re: UNICODE support in FreeBasic

Post by srvaldez »

hello Patrice Terrier :)
before you give up, please consider using José Roca https://github.com/JoseRoca/WinFBX and or https://github.com/JoseRoca/WinFBX2
have a look at https://github.com/JoseRoca/WinFBX2/blo ... 20Class.md for example and the https://github.com/JoseRoca/WinFBX/blob ... 20Class.md
Patrice Terrier
Posts: 35
Joined: Jan 06, 2006 8:27
Location: France
Contact:

Re: UNICODE support in FreeBasic

Post by Patrice Terrier »

I can't spend too much time on this, and I don't want to use third party addon, I just want plain native Windows API with built-in UNICODE support.
I shall see if I could use the core API mbstowcs and wcstombs to convert from ANSIO to UNICODE and reverse.
Josep Roca
Posts: 620
Joined: Sep 27, 2016 18:20
Location: Valencia, Spain

Re: UNICODE support in FreeBasic

Post by Josep Roca »

FreeBasic supports Unicode. What yu can't expect is that it will use the same declarations that C++. Which declaration are you using to use skCreateToolTip with FreeBasic? Show it and I will tell you how to declare it to allow passing literals and/or WSTRING.
VANYA
Posts: 1889
Joined: Oct 24, 2010 15:16
Location: Ярославль
Contact:

Re: UNICODE support in FreeBasic

Post by VANYA »

Patrice Terrier wrote: Jun 17, 2025 15:58 So far I am using this, but that doesn't work

Code: Select all

Function EXEpath() As WString Ptr
    Static usepath As WString * MAX_PATH
    Dim As DWORD result = GetModuleFileNameW(0, usepath, MAX_PATH)
    If result > 0 Then
        Dim As Long nLen = wcslen(usepath)
        For k As Long = 1 To nLen
            If wcsicmp(@usepath[nLen - k], @"\") <> 0 Then
                usepath[nLen - k] = 0
            Else
                Exit For
            End If
        Next
    End If
    Return @usepath
End Function
Hi Patrice Terrier!
Try it:

Code: Select all

#include "Windows.bi"

Function wEXEpath() As Wstring Ptr
	Static usepath As Wstring * MAX_PATH
	Dim As DWORD result = GetModuleFileNameW(0, @usepath, MAX_PATH)
	If result > 0 Then
		For i As Integer = result To 0 Step -1
			If usepath[i] = Asc("\") <> 0 Then
				usepath[i] = 0
				Exit For
			Endif
		Next
	End If
	Return @usepath
End Function

MessageBoxW(0 , wEXEpath , "" , 0)
@admins
Why is the size of the tabulation in the code so large? Have you installed 8 signs for TAB? Look at which ladder turned out above in the code, but there are only 4 indents!
Xusinboy Bekchanov
Posts: 880
Joined: Jul 26, 2018 18:28

Re: UNICODE support in FreeBasic

Post by Xusinboy Bekchanov »

Patrice Terrier wrote: Jun 17, 2025 18:34 If there is no direct support for UNICODE wchar_t (WCHAR), I think I shall give up for now on the translation of my C/C++ code.

PowerBASIC has UCODE$ that could be used like this: UCODE$("my string").
Much easier to use than this
Dim zTip As WString * 260 => "Previous skin theme"
skCreateToolTip(hCtrl, @zTip)

I would like to use directly someting like this
skCreateToolTip(hCtrl, UCODE$("Previoud skin theme"))
What is the problem here, when to save the file in UTF8 (BOM)?

Code: Select all

#define UNICODE
#include once "windows.bi"

MessageBox( 0, "你好,世界!", """Hello World!"" in chinese: 你好,世界!", MB_OK )
Josep Roca
Posts: 620
Joined: Sep 27, 2016 18:20
Location: Valencia, Spain

Re: UNICODE support in FreeBasic

Post by Josep Roca »

Hi Patrice,

So many time coding with C++ that you seem to have forgot Basic.

Code: Select all

SUB skExePath (BYREF wszPathName AS WSTRING, BYVAL nSize AS LONG)
   DIM dwRes AS DWORD = GetModuleFileNameW(NULL, wszPathName, nSize)
   IF GetLastError = ERROR_INSUFFICIENT_BUFFER THEN EXIT SUB
   DIM p AS LONG = INSTRREV(wszPathName, ANY ":/\")
   wszPathName = LEFT(wszPathName, p)
END SUB

DIM wszPath AS WSTRING * MAX_PATH
skExepath(wszPath, MAX_PATH)
print wszPath
Josep Roca
Posts: 620
Joined: Sep 27, 2016 18:20
Location: Valencia, Spain

Re: UNICODE support in FreeBasic

Post by Josep Roca »

Of course, all is easier if you have a Unicode dynamic string.

Code: Select all

' ========================================================================================
' * Returns the path of the program which is currently executing.
' ========================================================================================
PRIVATE FUNCTION AfxGetExePath () AS DWSTRING
   DIM buffer AS WSTRING * MAX_PATH, p AS LONG
   GetModuleFileNameW NULL, buffer, SIZEOF(buffer)
   p = INSTRREV(buffer, ANY ":/\")
   RETURN LEFT(buffer, p)
END FUNCTION
' ========================================================================================

Code: Select all

DIM dwsPath AS DWSTRING = AfxGetExePath
print dwsPath
Patrice Terrier
Posts: 35
Joined: Jan 06, 2006 8:27
Location: France
Contact:

Re: UNICODE support in FreeBasic

Post by Patrice Terrier »

I have done it.
Here is the code I am using

I want to keep it as close as my original C/C++ code

Code: Select all

sub ClearMemory(mem as any ptr, nSize as long)
    memset(mem, 0, nSize)
end sub

Function ExePathW() as WString ptr
    static zpath as WString * MAX_PATH
    static done as long
    if (done = 0) then
        ClearMemory(@zpath, MAX_PATH * 2)
        if (GetModuleFileNameW(0, @zpath, MAX_PATH)) then
            dim nLen as long = lstrlenW(zpath)
            dim nPos as long = nLen
            dim anti as Wstring * 2 => "\"
            for K as long = 1 to nLen
                if (lstrcmpiW(@zpath[nPos - K], @anti) <> 0) then
                    zpath[nPos - K] = 0
                else
                    exit for
                end if
            next
        end if
        done = -1
    end if
    return @zpath
end Function
BTW, I am ready to post an amazing demo, showing how to change the skin theme on the fly, altogether with custom buttons, and anchor properties.
Where is the best place to post it?
srvaldez
Posts: 3653
Joined: Sep 25, 2005 21:54

Re: UNICODE support in FreeBasic

Post by srvaldez »

I think that Projects would the right place to showcase your creation
Josep Roca
Posts: 620
Joined: Sep 27, 2016 18:20
Location: Valencia, Spain

Re: UNICODE support in FreeBasic

Post by Josep Roca »

> I want to keep it as close as my original C/C++ code

As you like it. It is your business. But all these WCHAR PTR should be WSTRING PTR. Why? Because in FreeBasic a WCHAR PTR is a pointer to a Unicode character, not to a Unicode string.

If instead of declaring

Code: Select all

declare function skCreateToolTip(byval hObj as HWND, byval zText as WCHAR ptr) as HWND
you declare it as

Code: Select all

declare function skCreateToolTip(byval hObj as HWND, byval zText as WSTRING ptr) as HWND
You can use

Code: Select all

skCreateToolTip(hCtrl, "Previous skin theme")
Instead of

Code: Select all

dim zTip as WString * 260 => "Previous skin theme"
skCreateToolTip(hCtrl, @zTip)
Post Reply