FF_RichEdit_GetText/FF_RichEdit_SetText with Unicode

Started by Roy Chan, December 02, 2011, 07:30:20 AM

Previous topic - Next topic

Roy Chan

Dear Sir,

Can I input different languages text into the same RichEdit ? And use FF_RichEdit_GetText function to get the string as unicode. I also want to load the UTF-8 Data from database and directly assign to the RichEdit.

Roy Chan
iniSoft System Technology Limited
Lenovo ThinkPad SL410 4GB Ram,
Windows XP SP3 / PBWin 10 & FireFly 3.51

Paul Squires

I doubt that the FF functions will work with unicode... they were built using the ansi version of Windows api functions. You may need to modify them to use the unicode versions.
Paul Squires
PlanetSquires Software

José Roca

Quote
Can I input different languages text into the same RichEdit ? And use FF_RichEdit_GetText function to get the string as unicode.

You can #INCLUDE "RichEditCtrl.inc" and use RichEdit_GetTextW and RichEdit_SetTextW.

Quote
I also want to load the UTF-8 Data from database and directly assign to the RichEdit.

Use RichEdit_SetTextW after converting the UTF-8 data to unicode with UtfToChr$.

Roy Chan

#3
I replaced the RichEdit with Textbox. So I use the the function "Edit_setutf8Text" to try again.
The original data of slFN("contents") ="Бесплатная интерактивная служба переводов"


Edit_setutf8Text( HWND_FRMMAIN_TEXT1,slFN("contents"))
The Contents of Textbox --- >"?????????? ????????????? ?????? ?????????"

Edit_setTextw( HWND_FRMMAIN_TEXT1,slFN("contents"))
The Contents of Textbox --- > "?迮?郈郅訄?郇訄? 邽郇?迮?訄郕?邽赲郇訄? ?郅?"



Do I need to use the SQLitening Unicode Version ?




Sub FRMMAIN_LoadQrDataRecord (ByVal tmpAction As Integer)
    Dim tmpSQL As String
    Dim tmpData As String
    Dim lngErrNum As Long
   
    Select Case tmpaction
      Case -1
        tmpsql="select * from qrdatarecord where autoid<" & Str$(pudtqrdatarecord.AutoID ) & " order by autoid desc limit 1"
       
      Case -2
        tmpsql="select * from qrdatarecord order by autoid asc limit 1"
     
      Case 1
         tmpsql="select * from qrdatarecord where autoid>" & Str$(pudtqrdatarecord.AutoID) & " order by autoid asc limit 1"
                 
      Case 2
         tmpsql="select * from qrdatarecord order by autoid desc limit 1"
                 
      Case Else
         tmpsql="select * from qrdatarecord where autoid=" & Str$(glngSelectedAutoID)
     
    End Select
   
    slSel tmpsql
   
    lngErrNum = slGetErrorNumber
    If lngErrNum <> 0 Then
        MsgBox "Error Number is: " & Str$(lngErrNum), 0, "Error"
    Else
       If slGetRow Then
          pudtQrDataRecord.AutoID = Val( slFN("autoid"))
          pudtqrdatarecord.DataType =Val(slFN("datatype"))
          pudtqrdatarecord.OutputType =Val(slFN("outputtype"))
          pudtqrdatarecord.Contents = Utf8ToChr$(Trim$(slFN("contents")))
          pudtqrdatarecord.LastUpdate = Val(slFN("lastupdate"))

          Edit_setutf8Text( HWND_FRMMAIN_TEXT1,slFN("contents"))   'The Contents of Textbox --- >"?????????? ????????????? ?????? ?????????"

       
       Else
          If tmpaction=0 Then
            pudtQrDataRecord.AutoID =  -1
            pudtqrdatarecord.DataType =  0
            pudtqrdatarecord.OutputType =0
            pudtqrdatarecord.Contents =""
            pudtqrdatarecord.LastUpdate = 0
         
          End If
       End If
   
    End If
 
    slCloseSet

End Sub


iniSoft System Technology Limited
Lenovo ThinkPad SL410 4GB Ram,
Windows XP SP3 / PBWin 10 & FireFly 3.51

José Roca

Quote
The original data of slFN("contents") ="Бесплатная интерактивная служба переводов"

This is not UTF8. With UTF8 it should be "БеÃ'Ð¿Ð»Ð°Ã'‚наÃ' инÃ'‚еÃ'â,¬ÃÂ°ÃÂºÃ'‚ивнаÃ' Ã'Ð»Ã'Æ'жба пеÃ'â,¬ÃÂµÃÂ²ÃÂ¾ÃÂ´ÃÂ¾ÃÂ²"

Besides, it won't work unless the edit control is created with CreateWindowExW, and FireFly is not yet Unicode ready.

This example produces the wanted result. See attached picture.


' ########################################################################################
' Microsoft Windows
' File: CW_Button.pbtpl
' Contents: Template - CWindow with a button
' Compilers: PBWIN 10.02+, PBCC 6.02+
' Headers: Windows API headers 2.03+
' Copyright (c) 2011 Jose 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.
' ########################################################################################
#COMPILE EXE
#DIM ALL
%UNICODE = 1

' // Include files for external files
#INCLUDE ONCE "CWindow.inc"   ' // CWindow class
#INCLUDE ONCE "EditCtrl.inc"

%IDC_TEXTBOX = 1001

' ========================================================================================
' Main
' ========================================================================================
FUNCTION WinMain (BYVAL hInstance AS DWORD, BYVAL hPrevInstance AS DWORD, BYVAL lpszCmdLine AS WSTRINGZ PTR, BYVAL nCmdShow AS LONG) AS LONG

   ' // Set process DPI aware
'   SetProcessDPIAware

   ' // Create an instance of the class
   LOCAL pWindow AS IWindow
   pWindow = CLASS "CWindow"
   IF ISNOTHING(pWindow) THEN EXIT FUNCTION

   ' // Create the main window
   ' // Note: CW_USEDEFAULT is used as the default value When passing 0's as the width and height
   pWindow.CreateWindow(%NULL, "CWindow with a button", 0, 0, 0, 0, 0, 0, CODEPTR(WindowProc))
   ' // Set the client size
   pWindow.SetClientSize 500, 320
   ' // Center the window
   pWindow.CenterWindow

   ' // Add an edit control
   LOCAL hEdit AS DWORD
   hEdit = pWindow.AddTextBox(pWindow.hwnd, %IDC_TEXTBOX, "", 100, 150, 300, 23)
   Edit_SetUtf8Text hEdit, "БеÃ'Ð¿Ð»Ð°Ã'‚наÃ' инÃ'‚еÃ'â,¬ÃÂ°ÃÂºÃ'‚ивнаÃ' Ã'Ð»Ã'Æ'жба пеÃ'â,¬ÃÂµÃÂ²ÃÂ¾ÃÂ´ÃÂ¾ÃÂ²"
   

   ' // Add a button
   pWindow.AddButton(pWindow.hwnd, %IDCANCEL, "&Close", 350, 250, 75, 23)

   

   ' // Default message pump (you can replace it with your own)
   pWindow.DoEvents(nCmdShow)

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

' ========================================================================================
' Main callback function.
' ========================================================================================
FUNCTION WindowProc (BYVAL hwnd AS DWORD, BYVAL uMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG

   ' // Process window mesages
   SELECT CASE uMsg

      CASE %WM_COMMAND
         SELECT CASE LO(WORD, wParam)
            CASE %IDCANCEL
               ' // If the Escape key has been pressed...
               IF HI(WORD, wParam) = %BN_CLICKED THEN
                  ' // ... close the application by sending a WM_CLOSE message
                  SendMessage hwnd, %WM_CLOSE, 0, 0
                  EXIT FUNCTION
               END IF
         END SELECT

      CASE %WM_DESTROY
         ' // End the application
         PostQuitMessage 0
         EXIT FUNCTION

   END SELECT

   ' // Pass unprocessed messages to Windows
   FUNCTION = DefWindowProc(hwnd, uMsg, wParam, lParam)

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


Roy Chan

 Dear Jose ,

Thank you very much. If I want to produce a fully Unicode support software, that I need to use the PBEdit or PBForms at this moment.
Could you recommend the other IDE tools of PowerBasic which support Unicode now ?
iniSoft System Technology Limited
Lenovo ThinkPad SL410 4GB Ram,
Windows XP SP3 / PBWin 10 & FireFly 3.51

José Roca

The only editor for PowerBASIC that supports unicode, via UTF-8 encoding, is my CSED editor.

David Kenny

#7
Paul,

I got bored again and decided to look into this one.  I have attached a copy of my test project.

I created one textbox.  To have two that are identical, I copied the first and then pasted the second (declining the option to create a control array). Skipping all the steps to narrow down the problem, here is what I found:

Compiling the project through FF, I get what Roy found.  Both Text1 and Text2 contain "?????????? ????????????? ?????? ?????????" (Preview shows these question marks fine  :P)
Manually editing the _Form.inc, and changing the AllowSubclass flag to FALSE for the Text2 textbox:
Quoteff = FLY_SetControlData( hWndControl, %FALSE, %TRUE, _
Then, compiling manually, the Text2 textbox looks as Roy wants. I have included a picture of the screen capture after manual edit and compile also.

Here's where I got stuck. My thinking is that not subclassing the control would be equivalent to subclassing, but not doing anything in the subclass routine except passing it on to the original window procedure. So, instead of changing AllowSubclass to FALSE, I commented all of the code in the Form1_Codeprocedure (except the call to retrieve the FLY_DATA and the call to the original window procedure):'------------------------------------------------------------------------------
' FORM1_CODEPROCEDURE
'------------------------------------------------------------------------------
Function FORM1_CODEPROCEDURE( _
                 ByVal hWndControl As Dword, _
                 ByVal wMsg        As Dword, _
                 ByVal wParam      As Long, _
                 ByVal lParam      As Long _
                 ) As Long
 
    ' All messages for every control on the the FORM1 form are processed
    ' in this function.
   
    Local FLY_ProcAddress  As Long       
    Local FLY_hFont        As Long
    Local FLY_hBackBrush   As Long
    Local FLY_nResult      As Long
    Local FLY_tempLong     As Long
    Local FLY_TopForm      As Long
    Local FLY_ControlIndex As Dword
    Local FLY_TCITEM       As TC_ITEM
    Local uVersion         As OSVERSIONINFO
    Local FLY_zTempString  As Asciiz * %MAX_PATH
    Local FLY_Rect         As Rect

    Local ff As FLY_DATA Ptr
    Local FLY_parent As FLY_DATA Ptr
    If hWndControl Then ff = GetProp(hWndControl, "FLY_PTR")
'    If ff Then FLY_ControlIndex = @ff.ControlIndex Else FLY_ControlIndex = -1
'   
'
'    ' The following CASE processes the internal FireFly requirements prior
'    ' to processing the user-defined events (These are handled in a
'    ' separate CASE following this one).
'    Select Case wMsg
'      Case %WM_DESTROY
'         
'         
'         ' Unsublass the Control
'         If ff Then
'         
'             ' Delete the brushes used for this Control
'             If @ff.hBackBrush Then Call DeleteObject(@ff.hBackBrush)
'             
'             FLY_ProcAddress = @ff.OldProc
'
'             ' Re-claim the memory used by the type structure
'             If ff Then HeapFree(GetProcessHeap(), 0, ByVal ff)
'             RemoveProp hWndControl, "FLY_PTR"
'             
'             ' Remove the properties holding the Tag property strings.
'             FLY_tempLong = GetProp(hWndControl, "FLY_TAGPROPERTY")
'             If FLY_tempLong Then
'                HeapFree GetProcessHeap(), 0, ByVal FLY_tempLong
'                RemoveProp hWndControl, "FLY_TAGPROPERTY"
'             End If
'             FLY_tempLong = GetProp(hWndControl, "FLY_TAGPROPERTY2")
'             If FLY_tempLong Then
'                HeapFree GetProcessHeap(), 0, ByVal FLY_tempLong
'                RemoveProp hWndControl, "FLY_TAGPROPERTY2"
'             End If
'             
'             ' Allow the WM_DESTROY message to be processed by the control.
'             SetWindowLong hWndControl, %GWL_WNDPROC, FLY_ProcAddress
'             CallWindowProc FLY_ProcAddress, hWndControl, wMsg, wParam, lParam
'
'         End If
'         
'         Function = 0: Exit Function
'     
'
'
'
'
'      Case %WM_SETFOCUS                                                         
'         ' If this is a TextBox, we check to see if we need to highlight the text.
'         If ff Then
'            If @ff.SelText Then
'               SendMessage hWndControl, %EM_SETSEL, 0, -1
'            Else
'               SendMessage hWndControl, %EM_SETSEL, -1, 0
'            End If   
'         End If
'         
'         ' Store the focus control in the parent form
'         ' If this Form is a TabControl child Form then we need to store the CtrlFocus
'         ' in the parent of this child Form.
'         FLY_nResult = GetWindowLong(GetParent(hWndControl), %GWL_STYLE)
'         If (FLY_nResult And %WS_CHILD) = %WS_CHILD Then
'            ' must be a TabControl child dialog
'            FLY_parent = GetProp(GetParent(GetParent(hWndControl)), "FLY_PTR")
'         Else   
'            FLY_parent = GetProp(GetParent(hWndControl), "FLY_PTR")
'         End If   
'         If FLY_parent Then @FLY_parent.CtrlFocus = hWndControl
'       
'
'      Case %WM_SIZE, %WM_MOVE
'         ' Handle any TabControl child pages that are autosize. If the TabControl changes
'         ' size then it is caught here. We only need to deal with TabControlChildAutoSize
'         ' forms because other forms stay at the fixed size.   
'
'       
'    End Select
'       

'    ' The following case calls each user defined function.
'    Select Case wMsg
'
'       Case 0
'     
'    End Select
 
    ' Handle any custom messages if necessary.

 
    ' This control is subclassed, therefore we must send all unprocessed messages
    ' to the original window procedure.
    Function = CallWindowProc( @ff.OldProc, hWndControl, wMsg, wParam, lParam )

End Function


I expected it to work as if it wasn't subclassed at all... allowing me to narrow down what subclass code was causing the problem.  It did not.  I'm not sure where to take it from here.  Anyway, I thought it time to share what I found in the hopes that you could take it from here.

David

José Roca

It is much simpler than that. What is needed is to add %UNICODE = 1 before the #INCLUDEs and use WSTRINGZ and WSTRING instead of ASCIIZ and STRING.

David Kenny

Jose, until now, the only one it was simple for is you.  :)  (well... maybe not true for anyone but me)

I would feel much smarter if I just possessed half your knowledge. Thanks for the info.

David

José Roca

The attached file contains the code generated by FireFly of your test. I have added %UNICODE = 1 and changed the ASCIIZ to WSTRINGZ and one STRING to WSTRING. See the result in the attached picture.

You can compile the code with the PB IDE or my editor, using my headers.

Roy Chan

Jose,

I have tried to follow your indication to modify my QrCode project. But it is not so easy. The items inside the listbox become some strange characters. Each time I click the listbox. It will crash at once. Maybe I will use your CSED editor to rewrite my project again for the unicode purpose.
iniSoft System Technology Limited
Lenovo ThinkPad SL410 4GB Ram,
Windows XP SP3 / PBWin 10 & FireFly 3.51

José Roca

Who knows what else are you doing? Practize first with simple unicode tests, instead of mixing third party libraries such QrCode. We can't help you with third party libraries that we don't use.

This simple test demonstrates the use of Unicode with a ListBox:


' ########################################################################################
' Microsoft Windows
' File: CW_ListBox.pbtpl
' Contents: Template - CWindow with a Listbox
' Compilers: PBWIN 10.02+, PBCC 6.02+
' Headers: Windows API headers 2.03+
' Copyright (c) 2011 Jose 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.
' ########################################################################################
#COMPILE EXE
#DIM ALL
%UNICODE = 1

' // Include files for external files
#INCLUDE ONCE "CWindow.inc"        ' // CWindow class
#INCLUDE ONCE "ListBoxCtrl.inc"    ' // ListBox wrappers

%IDC_LISTBOX = 1001

' ========================================================================================
' Main
' ========================================================================================
FUNCTION WinMain (BYVAL hInstance AS DWORD, BYVAL hPrevInstance AS DWORD, BYVAL lpszCmdLine AS WSTRINGZ PTR, BYVAL nCmdShow AS LONG) AS LONG

   ' // Set process DPI aware
'   SetProcessDPIAware

   ' // Create an instance of the class
   LOCAL pWindow AS IWindow
   pWindow = CLASS "CWindow"
   IF ISNOTHING(pWindow) THEN EXIT FUNCTION

   ' // Create the main window
   LOCAL hwndMain AS DWORD
   hwndMain = pWindow.CreateWindow(%NULL, "CWindow with a ListBox", 0, 0, 0, 0, 0, 0, CODEPTR(WindowProc))
   ' // Change the window style to avoid flicker
   pWindow.ClassStyle = %CS_DBLCLKS
   ' // Set the client size
   pWindow.SetClientSize(350, 375)
   ' // Center the window
   pWindow.CenterWindow

   ' // Add a listbox
   LOCAL hListBox AS DWORD
   hListBox = pWindow.AddListbox(hwndMain, %IDC_LISTBOX, "", 0, 0, 0, 0)
   pWindow.SetWindowPos hListBox, %NULL, 8, 8, 330, 320, %SWP_NOZORDER

   ' // Fill the list box
   LOCAL i AS LONG
   FOR i = 1 TO 50
      ListBox_AddString(hListBox, "Item " & FORMAT$(i, "00") & " " & Utf8ToChr$("БеÃ'Ð¿Ð»Ð°Ã'‚наÃ' инÃ'‚еÃ'â,¬ÃÂ°ÃÂºÃ'‚ивнаÃ' Ã'Ð»Ã'Æ'жба пеÃ'â,¬ÃÂµÃÂ²ÃÂ¾ÃÂ´ÃÂ¾ÃÂ²"))
   NEXT

   ' // Select the first item
   ListBox_SetCurSel hListBox, 0

   ' // Add buttons
   pWindow.AddButton(hwndMain, %IDCANCEL, "&Cancel", 263, 338, 75, 23)

   ' // Default message pump (you can replace it with your own)
   pWindow.DoEvents(nCmdShow)

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

' ========================================================================================
' Main callback function.
' ========================================================================================
FUNCTION WindowProc (BYVAL hwnd AS DWORD, BYVAL uMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG

   ' // Process window mesages
   SELECT CASE uMsg

      CASE %WM_COMMAND
         SELECT CASE LO(WORD, wParam)

            CASE %IDCANCEL
               ' // If the Escape key has been pressed...
               IF HI(WORD, wParam) = %BN_CLICKED THEN
                  ' // ... close the application by sending a WM_CLOSE message
                  SendMessage hwnd, %WM_CLOSE, 0, 0
                  EXIT FUNCTION
               END IF

            CASE %IDC_LISTBOX
               SELECT CASE HI(WORD, wParam)
                  CASE %LBN_DBLCLK
                     ' // Get the handle of the Listbox
                     LOCAL hListBox AS DWORD
                     hListBox = GetDlgItem(hwnd, %IDC_LISTBOX)
                     ' // Get the current selection
                     LOCAL curSel AS LONG
                     curSel = ListBox_GetCurSel(hListBox)
                     MSGBOX ListBox_GetText(hListBox, curSel)
                     EXIT FUNCTION
               END SELECT

         END SELECT

      CASE %WM_DESTROY
         ' // End the application
         PostQuitMessage 0
         EXIT FUNCTION

   END SELECT

   ' // Pass unprocessed messages to Windows
   FUNCTION = DefWindowProc(hwnd, uMsg, wParam, lParam)

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


David Kenny

Roy,

After Jose set me straight regarding my last post in this thread, I changed my test FF program successfully using this method:

1) Build and compile as normal with FF3.5
2) Using your favorite editor (I used JellyFishPro), open the ...MAIN.bas FF just generated.
3) Add "%UNICODE = 1" just above the first Include statement as such:
Quote%UNICODE = 1
#Include Once "Windows.inc"
#Include Once "CommCtrl.inc"
4) Compile in the editor.
5) For each compile time error, the variable with the problem will be to the left of the cursor (in JFP and PBEdit anyway).  Double-click on it to select it, and do a find-up (shift-F3 in JFP).
6) Change the definition for that variable as Jose indicated (ASCIIZ to WStringZ and String to WString).
7) Compile again.  If you get another error, go back to step 5.

It took only a minute or two to fix the test program.  But yours will take more than that.  I wouldn't want to build like this normally, but it can at least be done.  If I were looking at needing Unicode in the short term, I would create a search and replace program using the PB REGREPL command.

David

José Roca

Note that we need to use UTF-8 with string literals because source PowerBASIC files must be ansi, i.e. the compiler will fail if we save them as unicode. But we don't have to use Utf8ToChr$ or other UTF-8 wrapper functions with WSTRING or WSTRINGZ variables.

As shown in post 6, my editor allows you to type and see unicode characters, that are converted to UTF-8 when saved.