Main Menu

Recent posts

#11
José Roca Software / Re: AfxNova progress
Last post by José Roca - February 21, 2026, 09:02:32 AM
With some tweaking, we can simulate the fashionable dark mode:

   ' // Scroll bars dark theme
   SetWindowTheme(pGrid.hwnd, "DarkMode_Explorer", NULL)
   ' // Change the foreground and background colors
   pGrid.ForeColor = RGB_WHITE
   pGrid.BackColor = RGB_BLACK
   ' // change the color of the background of the grid
   pGrid.BackColorBkg = RGB_BLACK
   ' // Change the colors of the fixed parts of the grid
   pGrid.ForeColorFixed = RGB_WHITE
   pGrid.BackColorFixed = BGR(90, 90, 90)
   ' // Color of the grid
   pGrid.GridColor = RGB_GRAY
   pGrid.GridLines = flexGridFlat
   pGrid.GridColorHeader = RGB_GRAY
   pGrid.GridLinesFixed = flexGridFlat
#12
José Roca Software / Re: AfxNova progress
Last post by José Roca - February 21, 2026, 07:08:23 AM
With the help of my OLE Container (CAxHost), I have managed to get several of the old VB6 ActiveX controls (OCXs) to work with CWindow.

One of the most interesting is the Microsoft Hyerarchical Grid Control. It works wonderfully with CWindow, my ADO classes and the Jet Database, that comes pre-installed in Windows.

The only limitation is that it is 32-bit only.

This is one of my tests:

' ########################################################################################
' Microsoft Windows
' Contents: Embedded Microsoft Hierarchical Grid Control
' Compiler: FreeBasic 32 & 64 bit
' Copyright (c) 2026 José Roca. Freeware. Use at your own risk.
' THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
' EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
' MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
' ########################################################################################

#define UNICODE
'#define _CAXH_DEBUG_ 1
#INCLUDE ONCE "AfxNova/AfxCOM.inc"
#INCLUDE ONCE "AfxNova/CAxHost.inc"
#INCLUDE ONCE "AfxNova/MSHFlexGrid.inc"
#INCLUDE ONCE "AfxNova/CADODB.inc"
USING AfxNova

DECLARE FUNCTION wWinMain (BYVAL hInstance AS HINSTANCE, _
                           BYVAL hPrevInstance AS HINSTANCE, _
                           BYVAL pwszCmdLine AS WSTRING PTR, _
                           BYVAL nCmdShow AS LONG) AS LONG
   END wWinMain(GetModuleHandleW(NULL), NULL, wCommand(), SW_NORMAL)

' // Forward declaration
DECLARE FUNCTION WndProc (BYVAL hwnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT

CONST IDC_GRID = 1001

' ========================================================================================
' Main
' ========================================================================================
FUNCTION wWinMain (BYVAL hInstance AS HINSTANCE, _
                   BYVAL hPrevInstance AS HINSTANCE, _
                   BYVAL pwszCmdLine AS WSTRING PTR, _
                   BYVAL nCmdShow AS LONG) AS LONG

   ' // Set process DPI aware
   ' // The recommended way is to use a manifest file
   AfxSetProcessDPIAware

   ' // Creates the main window
   DIM pWindow AS CWindow
   ' -or- DIM pWindow AS CWindow = "MyClassName" (use the name that you wish)
   DIM hwndMain AS HWND = pWindow.Create(NULL, "Microsoft Hierarchical Flex Grid", @WndProc)
   ' // Sizes it by setting the wanted width and height of its client area
   pWindow.SetClientSize(800, 450)
   ' // Centers the window
   pWindow.Center

   DIM wszLibName AS WSTRING * 260 = ExePath & "\MSHFLXGD.OCX"
   DIM pHost AS CAxHost = CAxHost(@pWindow, IDC_GRID, wszLibName, AFX_CLSID_MSHFlexGrid, _
       AFX_IID_IMSHFlexGrid, RTLKEY_MSHFlexGrid, 0, 0, pWindow.ClientWidth, pWindow.ClientHeight)
   pWindow.AnchorControl(IDC_GRID, AFX_ANCHOR_HEIGHT_WIDTH)
   SetFocus pHost.hWindow

   DIM pGrid AS CMSHFlexGrid = pHost.OcxDispObj
   ' // Set the width of the columns (in twips)
   pGrid.ColWidth(0) = 300
   pGrid.ColWidth(1) = 1100
   pGrid.ColWidth(2) = 3000
   pGrid.ColWidth(3) = 2000
   pGrid.ColWidth(4) = 2000
   pGrid.ColWidth(5) = 3000
   pGrid.ColWidth(6) = 1500
   pGrid.ColWidth(7) = 700
   pGrid.ColWidth(8) = 1200
   pGrid.ColWidth(9) = 1200
   pGrid.ColWidth(10) = 1500
   pGrid.ColWidth(11) = 1500
   ' Change the foreground and background colors
   pGrid.ForeColor = BGR(0, 0, 0)
   pGrid.BackColor = BGR(255,255,235)

   ' Open an ADO connection
   DIM pConnection AS CAdoConnection PTR = NEW CAdoConnection
   pConnection->ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & ExePath & $"\nwind.mdb"
   pConnection->Open
   ' Open a recordset
   DIM pRecordset AS CAdoRecordset PTR = NEW CAdoRecordset
   DIM dvSource AS DVARIANT = "SELECT * FROM Customers"
   pRecordset->Open(dvSource, pConnection, adOpenKeyset, adLockOptimistic, adCmdText)
   ' Set the Datasource property of the recordset
   pGrid.DataSource = cast(ANY PTR, pRecordset->DataSource)
   ' Close the recordset
   pRecordset->Close
   ' Close the connection
   pConnection->Close
   ' // Delete the recordset
   Delete pRecordset
   ' // Delete the connection
   Delete pConnection

   ' // Display the window
   ShowWindow(hwndMain, nCmdShow)
   UpdateWindow(hwndMain)

   ' // Dispatch Windows messages
   DIM uMsg AS MSG
   WHILE (GetMessageW(@uMsg, NULL, 0, 0) <> FALSE)
      IF AfxCAxHostForwardMessage(GetFocus, @uMsg) = FALSE THEN
         IF IsDialogMessageW(hwndMain, @uMsg) = 0 THEN
            TranslateMessage(@uMsg)
            DispatchMessageW(@uMsg)
         END IF
      END IF
   WEND
   FUNCTION = uMsg.wParam

END FUNCTION
' ========================================================================================

' ========================================================================================
' Main window procedure
' ========================================================================================
FUNCTION WndProc (BYVAL hwnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT

   SELECT CASE uMsg

      ' // If an application processes this message, it should return zero to continue
      ' // creation of the window. If the application returns –1, the window is destroyed
      ' // and the CreateWindowExW function returns a NULL handle.
      CASE WM_CREATE
         AfxEnableDarkModeForWindow(hwnd)
         RETURN 0

      ' // Theme has changed
      CASE WM_THEMECHANGED
         AfxEnableDarkModeForWindow(hwnd)
         RETURN 0

      CASE WM_COMMAND
         SELECT CASE LOWORD(wParam)
            CASE IDCANCEL
               ' // If ESC key pressed, close the application by sending an WM_CLOSE message
               IF HIWORD(wParam) = BN_CLICKED THEN
                  SendMessageW hwnd, WM_CLOSE, 0, 0
                  EXIT FUNCTION
               END IF
         END SELECT

    CASE WM_DESTROY
         ' // Ends the application by sending a WM_QUIT message
         PostQuitMessage(0)
         EXIT FUNCTION

   END SELECT

   ' // Default processing of Windows messages
   FUNCTION = DefWindowProcW(hwnd, uMsg, wParam, lParam)

END FUNCTION
' ========================================================================================

Notice that instead of pWindow.DoEvents I'm using a message pump:

   ' // Dispatch Windows messages
   DIM uMsg AS MSG
   WHILE (GetMessageW(@uMsg, NULL, 0, 0) <> FALSE)
      IF AfxCAxHostForwardMessage(GetFocus, @uMsg) = FALSE THEN
         IF IsDialogMessageW(hwndMain, @uMsg) = 0 THEN
            TranslateMessage(@uMsg)
            DispatchMessageW(@uMsg)
         END IF
      END IF
   WEND

In it, AfxCAxHostForwardMessage gives the hosted grid to process keyboard messages.
#13
José Roca Software / Re: DWString problem help
Last post by José Roca - February 21, 2026, 02:34:21 AM
Yes. An ansi string can contain text that use different code pages, not just utf-8. It can contain ansi text, utf-8, OEM and ansi with different code pages. DWSTRING supports them by allowing to specify the code page.  For example, the code page for utf8 is CP_UTF8 and for OEM it is CP_OEMCP. UTF-16 strings don't need conversion because there is a FreeBasic native type that supports it, WSTRING, which is a fixed-length unicode data type. DWSTRING extends WSTRING to provide methods that allow it to behave like a dynamic unicode string.
#14
José Roca Software / Re: DWString problem help
Last post by fbfans - February 20, 2026, 10:05:50 PM
Thank you for your reply; the explanation is clear and easy to understand.
Is this the reason for my problem?
When the file is in ANSI format, it reads text as ANSI by default, and DWString correctly converts ANSI to UTF-8.
When the file is in UTF-8 format, the text is already UTF-8, but since it is not specified as UTF-8, FreeBASIC still reads the UTF-8 string as ANSI by default, which results in garbled text because it cannot be parsed correctly.
Therefore, I need to use DWString("你好 围棋", CP_UTF8) to explicitly specify that the text is UTF-8, so that DWString can parse it correctly.
The core point is exactly what you said:
QuoteSince FreeBASIC does not provide a separate data type for UTF-8 (it only has STRING), if you do not specify that it is UTF‑8 or CP_UTF8, the constructor will assume you are passing an ANSI string and use the CP_ACP code page to process it. Keep in mind that all characters in a UTF-8 string are treated as ANSI characters.
Thanks again.
#15
PlanetSquires Software / Re: Some questions about usin...
Last post by fbfans - February 20, 2026, 09:50:47 PM
Hi Paul, thanks for your reply.
QuoteCheck this option: Environment Options / Code Editor / "Click margin to toggle breakpoints instead of bookmarks".
What I mean is, the current program logic is that clicking the line number area either sets a breakpoint or a bookmark—you can only choose one. Why not set breakpoints with a left click and bookmarks with a right click, or use a double click and other mouse actions instead?
Another point is about the real-time sync and refresh issue of the sidebar. I closed some files, but their entries still remain in the sidebar. Theoretically, the closed files should no longer be displayed there.
I downloaded the tiko.exe file from the development branch directory on GitHub at https://github.com/PaulSquires/tiko/tree/development, and it prompts an incompatibility with my system. I'm using 64-bit Windows 11.
Also, I just noticed there are so many discussions about Tiko on the FreeBASIC forum. Should I post my questions there from now on?
#16
José Roca Software / Re: DWString problem help
Last post by José Roca - February 20, 2026, 02:24:15 PM
> Does utf8Str here mean a UTF‑8 string?
> The same direct assignment does NOT work correctly (garbled text):
> I have to use this instead to display properly:

As FreeBasic does not have a separate data type for utf-8 (it only has STRING), if you don't specify that it is utf with CP_UTF8, the constructor thinks that you're passing an ansi string and it does the conversión using the CP_ACP code page. Keep in mind that all the characters in an utf-8 string are ANSI characters.

The constructor calls this method:

PRIVATE FUNCTION DWSTRING.Add (BYREF ansiStr AS STRING, BYVAL nCodePage AS UINT = 0) AS BOOLEAN
   DWSTRING_DP("STRING - buffer: " & ..WSTR(m_pBuffer) & " - codepage: " & ..WSTR(nCodePage))
   IF .LEN(ansiStr) = 0 THEN RETURN FALSE
   ' // Create the wide string from the incoming ansi string
   DIM dwLen AS UINT, pbuffer AS ANY PTR
   DIM bRes AS BOOLEAN = TRUE   ' // assume success for now
   IF nCodePage = CP_UTF8 THEN   ' // check if it is really valid utf-8
      IF this.IsUtf8(ansiStr) = FALSE THEN nCodePage = CP_ACP
   END IF
   IF nCodePage = CP_UTF8 THEN
      dwLen = MultiByteToWideChar(CP_UTF8, 0, STRPTR(ansiStr), -1, NULL, 0)
      IF dwLen = 0 THEN RETURN FALSE
      pbuffer = Allocate(dwLen * 2)
      dwLen = MultiByteToWideChar(CP_UTF8, 0, STRPTR(ansiStr), -1, pbuffer, dwLen)
      IF dwLen = 0 THEN bRes = FALSE
   ELSE
      dwLen = MultiByteToWideChar(nCodePage, MB_PRECOMPOSED, STRPTR(ansiStr), -1, NULL, 0)
      IF dwLen = 0 THEN RETURN FALSE
      pbuffer = Allocate(dwLen * 2)
      dwLen = MultiByteToWideChar(nCodePage, MB_PRECOMPOSED, STRPTR(ansiStr), -1, pbuffer, dwLen)
      IF dwLen = 0 THEN bRes = FALSE
   END IF
   IF bRes = FALSE THEN
      IF pBuffer THEN Deallocate(pbuffer)
      RETURN bRes
   END IF
   ' // Copy the string into the buffer
   IF pbuffer THEN
      ' Copy the string into the buffer and update the length
      bRes = this.AppendBuffer(pbuffer, dwLen)
      ' // Deallocate the buffer
      IF pBuffer THEN Deallocate(pbuffer)
   END IF
   RETURN bRes
END FUNCTION

That checks if it is really utf-8 only if you have specified CP_UTF8.

   IF nCodePage = CP_UTF8 THEN   ' // check if it is really valid utf-8
      IF this.IsUtf8(ansiStr) = FALSE THEN nCodePage = CP_ACP
   END IF

With the utf-8 property you don't need to specify CP_UTF8 because it assumes that it is a utf-8 string.

BTW, you're saying "When source file is ANSI", but you can't have dim as wstring * 8 txt = "你好 世界" in an ANSI file. It must be utf-16 (Unicode). If you write "你好 世界" in Tiko in ANSI mode, it will become dim as wstring * 8 txt = "?? ??".

#17
PlanetSquires Software / Re: Some questions about usin...
Last post by Paul Squires - February 20, 2026, 02:22:30 PM
Quote from: fbfans on February 20, 2026, 01:16:03 PMI'm just not entirely sure why this became a problem in the first place.
It is a well known Tiko parsing problem. The "end" interferes with the parser determining where the Sub/Function ends because the parser expects an End Sub or an End Function.

Quote1、Regarding the function list for files: Shouldn't clicking on it allow you to expand or collapse the list for each file? Next to the filename, there's an arrow, but clicking it jumps to the function list of the corresponding file instead of collapsing it. In contrast, the bookmark list follows the expected behavior—clicking expands or collapses it properly.
Yes, you're probably right about this one. I will look to see why I implemented it the current way and change it if necessary.

Quote2、The scrollbar's drag activation area is too narrow. When dragging the scrollbar, if the mouse moves even slightly outside of it, it immediately loses focus and the scrollbar disappears from view, even though it can still be dragged.
This was actually fixed (finally) yesterday. See this post: https://www.freebasic.net/forum/viewtopic.php?p=310481#p310481

Quote3、Regarding bookmarks: Normally, when a bookmark is set, it should appear in the sidebar's bookmark tab. Currently, only bookmarks set via Ctrl+F2 appear automatically. Bookmarks set with the mouse do not—they only show up if I click the "..." next to the sidebar bookmarks and select "Expand All."
Yes, there does seem to be something strange going on there.

QuoteIn your version 1.3 update, you added the option to set breakpoints. If you intend for a mouse click to set a breakpoint, I suggest either disabling the option to set bookmarks with the mouse (by removing the relevant setting) or assigning mouse double-click or another key to set breakpoints to avoid conflicts. Otherwise, a logic for adding mouse-set bookmarks to the list should be implemented.
Check out the option:  Environment Options / Code Editor / "Margin click toggles Breakpoint rather than Bookmark".

QuoteAdditionally, I revisited the translation and am unsure if "clear bookmarks" in the sidebar and menu bar are meant to have the same meaning. However, the menu bar option only clears bookmarks for the current file, while the sidebar option clears bookmarks for all files. The difference is quite significant—they are not performing the same action, so the translation should reflect that distinction.
Clicking the "..." and selecting "clear bookmarks" should remove all bookmarks from ALL files. Right clicking on a filename within the list and selecting "clear bookmarks" should remove bookmarks from that file only. Maybe I should rename them "Clear Bookmarks All Files", and " Clear Bookmarks Selected File", or something similar.

#18
PlanetSquires Software / Re: Some questions about usin...
Last post by fbfans - February 20, 2026, 01:16:03 PM
@Paul, José
Thanks.
I have received your reply. The issue with the function name not being recognized is actually quite simple—I can resolve it by using "system." I'm just not entirely sure why this became a problem in the first place.

I'm not sure why I seem to be encountering so many issues, while other users don't seem to have any problems with tiko. I hope this doesn't come across the wrong way, Paul.

1、Regarding the function list for files: Shouldn't clicking on it allow you to expand or collapse the list for each file? Next to the filename, there's an arrow, but clicking it jumps to the function list of the corresponding file instead of collapsing it. In contrast, the bookmark list follows the expected behavior—clicking expands or collapses it properly.

2、The scrollbar's drag activation area is too narrow. When dragging the scrollbar, if the mouse moves even slightly outside of it, it immediately loses focus and the scrollbar disappears from view, even though it can still be dragged.

3、Regarding bookmarks: Normally, when a bookmark is set, it should appear in the sidebar's bookmark tab. Currently, only bookmarks set via Ctrl+F2 appear automatically. Bookmarks set with the mouse do not—they only show up if I click the "..." next to the sidebar bookmarks and select "Expand All." In your version 1.3 update, you added the option to set breakpoints. If you intend for a mouse click to set a breakpoint, I suggest either disabling the option to set bookmarks with the mouse (by removing the relevant setting) or assigning mouse double-click or another key to set breakpoints to avoid conflicts. Otherwise, a logic for adding mouse-set bookmarks to the list should be implemented.
    Additionally, I revisited the translation and am unsure if "clear bookmarks" in the sidebar and menu bar are meant to have the same meaning. However, the menu bar option only clears bookmarks for the current file, while the sidebar option clears bookmarks for all files. The difference is quite significant—they are not performing the same action, so the translation should reflect that distinction.

I feel that José's dwstring is very powerful. The transcoding function he demonstrated is logically clear, concise, robust, and almost like a tutorial—definitely worth learning from. I suggest Paul consider adopting this approach, as it could greatly simplify Unicode-related issues. It's highly recommendable.

Regarding Chinese character encoding conversion, Paul may not have the conditions to test it. If you need me to assist with testing, feel free to reach out—I'm more than happy to help. Email: erliwuwei@gmail.com.
#19
José Roca Software / DWString problem help
Last post by fbfans - February 20, 2026, 12:59:54 PM
hi José!
I'm learning DWString and I have some confusion about its behavior with different source file encodings.
From the documentation, my understanding is:
DWString stores text internally in Unicode
We can get .ansi, .utf8, .ptr, etc., depending on the usage scenario
But I get different results when the source file is saved as ANSI vs UTF‑8:
1. When source file is ANSI
This code displays Chinese correctly:
dim as dwstring txt  = "围棋"
plutovg_text(pluto, txt.utf8, 32, 128)
plutovg_fill(pluto)
2. When source file is UTF‑8
The same direct assignment does NOT work correctly (garbled text):
dim as dwstring txt = "你好 围棋"
plutovg_text(pluto, txt.utf8, 330, 128)
plutovg_fill(pluto)
I have to use this instead to display properly:
DIM AS DWSTRING dtxt = dwstring("你好 围棋", CP_UTF8)
plutovg_text(pluto, dtxt.utf8, 330, 128)
plutovg_fill(pluto)
From an earlier example:
QuoteUtf8ToAnsi
DIM dws AS DWSTRING = DWSTRING(utf8Str, CP_UTF8)
DIM ansiStr AS STRING = dws
My questions:
Does utf8Str here mean a UTF‑8 string?
When the source file is saved as UTF‑8, the literal string inside "..." should already be UTF‑8.
So what exactly does DWSTRING(utf8Str, CP_UTF8) do internally?
Why do I need to explicitly specify CP_UTF8 when the file is already UTF‑8?

#define unicode
#include "plutovg.bi"
#include "afxnova/Dwstring.inc"
using afxnova

' draw vector font's on FBGFX Image

const as long iWidth  = 640
const as long iHeight = 480
const as double FONT_SIZE = 40

screenres iWidth,iHeight,32

var img = ImageCreate(iWidth, iHeight, 0)
dim as ubyte ptr imgPixels
dim as long imgWidth,imgHeight,imgBytes,imgPitch
ImageInfo(img, imgWidth, imgHeight, imgBytes, imgPitch, imgPixels)

var surface = plutovg_surface_create_for_data(imgPixels,imgWidth,imgHeight,imgPitch)
var pluto   = plutovg_create(surface)
var font    = plutovg_font_load_from_file("c:/windows/fonts/simhei.ttf",FONT_SIZE)
plutovg_set_font(pluto,font)
plutovg_set_source_rgb(pluto, 1, 1, 0)

dim as wstring * 8 txt = "你好 世界"

plutovg_text(pluto, txt, 20, 128)
'plutovg_fill(pluto)

DIM AS DWSTRING dtxt = dwstring("你好 围棋", CP_UTF8)
plutovg_text(pluto, dtxt.utf8, 330, 128)
plutovg_fill(pluto)

plutovg_text(pluto, txt, 32, 256)
plutovg_text(pluto, "你好 中国", 330, 256)
plutovg_stroke(pluto)

plutovg_save(pluto)
plutovg_text(pluto, txt, 90, 344)
plutovg_text(pluto, dtxt.utf8, 390, 344)
plutovg_rotate(pluto,.2)
plutovg_fill(pluto)
plutovg_restore(pluto)

put (0,0),img,PSET 'ALPHA
sleep
plutovg_surface_destroy(surface)
plutovg_destroy(pluto)
plutovg_font_destroy(font)

thanks!
#20
PlanetSquires Software / Re: Some questions about usin...
Last post by José Roca - February 17, 2026, 10:11:56 PM
I have asked to CoPilot about porting DWSTRING to Linux to end with the UTF-8 headaches that the users of that platform have.

And it has replied:

🌟 Why a Linux version of DWSTRING is straightforward
1. FreeBasic already gives you UTF‑32 on Linux
This is the jackpot.

WSTRING on Linux = UCS‑4 = UTF‑32.

So your internal buffer becomes:

one code point per element

no surrogate pairs

no variable‑length sequences

no special cases

It's even simpler than UTF‑16.

2. Linux already provides the conversion functions you need
Windows:

MultiByteToWideChar

WideCharToMultiByte

Linux equivalents:

mbstowcs / wcstombs

or iconv for more control

These do the same job.

3. The rest of DWSTRING is platform‑neutral
Your class logic:

constructors

operators

buffer management

UTF‑8 validation

integration with FB string functions

...all of that stays exactly the same.

4. No external dependencies means no obstacles
Because DWSTRING is:

one file

no DLLs

no libraries

no Windows‑only baggage

...it ports cleanly.

🌱 Why it feels too easy
Because most developers approach UTF‑8 the hard way:

manipulating UTF‑8 directly

rewriting MID, LEFT, RIGHT, INSTR

building ULeft, URight, UInstr, UReplace, URemove, UInsert

getting stuck on UMid

fighting variable‑length encodings

You avoided all of that by stepping outside the UTF‑8 trap entirely.

Your model:

UTF‑8 → fixed‑width Unicode → process → fixed‑width Unicode → UTF‑8
...is the same one used by:

Windows

.NET

Java

Qt

Python (on Linux)

ICU

It's easy because it's correct.

🎯 And yes — with or without AI, it's absolutely doable
An AI tool could help generate the Linux version, but the truth is:

your design is already portable

the platform‑specific parts are tiny

the logic is universal

the class is dependency‑free

So whether you do it manually or with assistance, the path is clear.