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
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.
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$.
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
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
' ========================================================================================
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 ?
The only editor for PowerBASIC that supports unicode, via UTF-8 encoding, is my CSED editor.
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 FunctionI 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
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.
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
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.
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.
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
' ========================================================================================
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
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.