October 29, 2025, 02:34:05 AM

News:

IWBasic runs in Windows 11!


Unicode in a Rich Edit Control

Started by okchoir, June 23, 2007, 09:08:40 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

okchoir

I'm updating an old Liberty Basic program, and would like to have unicode capability in a rich edit control.  It is not obvious to me that EBasic currently supports this, as unicode communication to the Windows API requires longer-length data items.  In surfing the web, I have found C-code snippets that use SendMessageW for unicode I/O to a rich edit control, but C programming is out of my league.

Any ideas about what direction to go with this?

-okchoir

Ionic Wind Support Team

Emergence supports unicode so you would only need to declare the import for SendMessageW.  Or post the relevent C code and someone will convert it.

Paul.
Ionic Wind Support Team

okchoir

Thanks, Paul.  You have given me a glimmer of hope.

I am including the header file and the code module from a small application posted on codeguru.com at
http://www.codeguru.com/cpp/misc/misc/windowsmessaging/article.php/c10251/
A zip file with all the code for the application is available here.  This example lets the user paste a unicode string into one rich edit control, then copy the contents of that control to a second rich edit control.


// UnicodeDlg.h : header file
//

#if !defined(AFX_UNICODEDLG_H__90116872_5E31_4F4A_8476_B836DAE4374C__INCLUDED_)
#define AFX_UNICODEDLG_H__90116872_5E31_4F4A_8476_B836DAE4374C__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000


/////////////////////////////////////////////////////////////////////////////
// CUnicodeDlg dialog

class CUnicodeDlg : public CDialog
{
// Construction
public:
CUnicodeDlg(CWnd* pParent = NULL); // standard constructor

// Dialog Data
//{{AFX_DATA(CUnicodeDlg)
enum { IDD = IDD_UNICODE_DIALOG };
CRichEditCtrl m_rich2;
CRichEditCtrl m_rich1;
//}}AFX_DATA

// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CUnicodeDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL

// Implementation
protected:
HICON m_hIcon;

// Generated message map functions
//{{AFX_MSG(CUnicodeDlg)
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
afx_msg void OnCopy();
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_UNICODEDLG_H__90116872_5E31_4F4A_8476_B836DAE4374C__INCLUDED_)


And the code module, where the call to SendMessageW is near the bottom:


// UnicodeDlg.cpp : implementation file
//

#include "stdafx.h"
#include "Unicode.h"
#include "UnicodeDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
CAboutDlg();

// Dialog Data
//{{AFX_DATA(CAboutDlg)
enum { IDD = IDD_ABOUTBOX };
//}}AFX_DATA

// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CAboutDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
//}}AFX_VIRTUAL

// Implementation
protected:
//{{AFX_MSG(CAboutDlg)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
//{{AFX_DATA_INIT(CAboutDlg)
//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
// No message handlers
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CUnicodeDlg dialog

CUnicodeDlg::CUnicodeDlg(CWnd* pParent /*=NULL*/)
: CDialog(CUnicodeDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CUnicodeDlg)
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CUnicodeDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CUnicodeDlg)
DDX_Control(pDX, IDC_RICHEDIT2, m_rich2);
DDX_Control(pDX, IDC_RICHEDIT1, m_rich1);
//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CUnicodeDlg, CDialog)
//{{AFX_MSG_MAP(CUnicodeDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_COPY, OnCopy)
//ON_WM_CREATE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CUnicodeDlg message handlers



BOOL CUnicodeDlg::OnInitDialog()
{
CDialog::OnInitDialog();

// Add "About..." menu item to system menu.

// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);

CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}

// Set the icon for this dialog.  The framework does this automatically
//  when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon

// TODO: Add extra initialization here

return TRUE;  // return TRUE  unless you set the focus to a control
}

void CUnicodeDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}



}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CUnicodeDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting

SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;

// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CUnicodeDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}

void CUnicodeDlg::OnCopy()
{
GETTEXTEX  wParamIN;

SETTEXTEX wParamOUT;

wParamIN.cb = (this->m_rich1.GetWindowTextLength()+1)*2;
wParamIN.flags = GT_RAWTEXT;
wParamIN.codepage = 1200;
wParamIN.lpDefaultChar = NULL;
wParamIN.lpUsedDefChar = NULL;

wParamOUT.codepage = 1200;
wParamOUT.flags = ST_SELECTION;


WCHAR   lParam[100] = {0};



LRESULT lResult = SendMessageW(this->m_rich1.m_hWnd,  // handle to destination control
                            EM_GETTEXTEX,          // message ID     
          (WPARAM) &wParamIN,    // = (WPARAM) () wParam;   
          (LPARAM) lParam);      // = (LPARAM) () lParam;

MessageBoxW(this->m_hWnd, lParam, L"Here we go...", MB_OK|MB_ICONASTERISK);

lResult = SendMessageW(this->m_rich2.m_hWnd,    // handle to destination control
                    EM_SETTEXTEX,            // message ID     
  (WPARAM) &wParamOUT,     // = (WPARAM) () wParam;   
  (LPARAM) lParam);        // = (LPARAM) () lParam;


}


Would someone post an EBasic code snippet or point me to existing code to illustrate how to import the relevant items and use SendMessageW in this context?

okchoir

Looks like I got ahead of my self above.  After trying to find more information about this topic, I discovered that creating a Rich Edit control is another hurdle. 

In the following example, I am using CONTROLEX to create the Rich Edit control and get the handle, but this needs the correct class name; this is the big question.  What I found on the internet is information for riched32.dll (older) and riched20.dll (newer), so I chose the newer one.  According to forum comments, the class name is "RichEdit20W".  I used the tool, Create Import Library, to build the riched20.lib for linking this control.

In this code example, CONTROLEX returns a value of zero for the handle, so something is wrong.  Can anyone confirm what the correct class name should be?  Or is something else wrong?


'Unicode Rich Edit Example

AUTODEFINE "OFF"
OPENCONSOLE

'Searching on the web for richedit, the latest dll is "riched20.dll" and the class name should be "RichEdit20A" for ansi
'and "RichEdit20W" for unicode.
'So, create Import Library for "riched20.dll"

DEF main:WINDOW
DEF hRichEdit:UINT

'Create a window.
OPENWINDOW main, 0,0,345,350, @TopMost, 0, "Unicode Rich Edit Control Demo",&mainhandler

'Add Rich Edit Control.
'IS "RichEdit20W" THE CORRECT CLASS NAME HERE?
hRichEdit = CONTROLEX main, "RichEdit20W", "", 5, 20, 300, 180, 0, 0, 1

PRINT "hRichEdit = ", hRichEdit
'wait until the main window is closed, then end program
WAITUNTIL main=0
END
SUB mainhandler()
SELECT @MESSAGE
CASE @IDCLOSEWINDOW
CLOSEWINDOW main :'end the program
ENDSELECT
RETURN
ENDSUB

okchoir

Solved.  Thanks Paul for telling me that it could be done.  I got some help at CodingMonkeys.  For what it's worth, here is an example:


'Unicode Rich Edit Example

AUTODEFINE "OFF"
TYPE _settextex
WORD flags :'ST_DEFAULT
UINT codepage :'=1200 Unicode
ENDTYPE

DEF wParamOUT:_settextex
DEF lParam:WSTRING
DEF main:WINDOW
DEF hRichEdit:UINT
DEF hLibModule:INT

$INCLUDE "windows.inc"
Declare Import,SendMessageW(hWnd:Uint,message:Uint,wParam:Int,lparam:Uint),Uint
DECLARE "kernel32",LoadLibraryA(name:STRING),INT
hLibModule = LoadLibraryA( "Riched20.dll" )

CONST EM_SETTEXTEX = 1121 :'(WM_USER + 97)

wParamOUT.flags = 0 :'ST_DEFAULT
wParamOUT.codepage = 1200 :'=1200 Unicode

'Create a window.
OPENWINDOW main, 0,0,345,350, 0, 0, "Unicode Rich Edit Control Demo",&mainhandler

'Add the Rich Edit Control.
hRichEdit = CONTROLEX main, "RichEdit20W", "", 5, 20, 325, 280, @CTEDITMULTI, @EXCLIENTEDGE, 1

lParam = L"THIS IS A UNICODE STRING"
SendMessageW(hRichEdit,EM_SETTEXTEX,&wParamOUT,&lParam)
WAIT 1 :'Allow Window to update

'wait until the main window is closed, then end program
WAITUNTIL main=0
END

SUB mainhandler()
SELECT @MESSAGE
CASE @IDCLOSEWINDOW
'end the program
CLOSEWINDOW main
ENDSELECT
RETURN
ENDSUB