1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        msw/textctrl.cpp 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  17     #pragma implementation "textctrl.h" 
  20 // ---------------------------------------------------------------------------- 
  22 // ---------------------------------------------------------------------------- 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  34     #include "wx/textctrl.h" 
  35     #include "wx/settings.h" 
  44 #include "wx/module.h" 
  47     #include "wx/clipbrd.h" 
  50 #include "wx/textfile.h" 
  54 #include "wx/msw/private.h" 
  55 #include "wx/msw/winundef.h" 
  61 #include <sys/types.h> 
  66 // old mingw32 has richedit stuff directly in windows.h and doesn't have 
  68 #if !defined(__GNUWIN32_OLD__) || defined(__CYGWIN10__) 
  72 #include "wx/msw/missing.h" 
  74 #endif // wxUSE_RICHEDIT 
  76 // ---------------------------------------------------------------------------- 
  78 // ---------------------------------------------------------------------------- 
  82 DWORD CALLBACK 
wxRichEditStreamIn(DWORD dwCookie
, BYTE 
*buf
, LONG cb
, LONG 
*pcb
); 
  84 #endif // wxUSE_RICHEDIT 
  86 // ---------------------------------------------------------------------------- 
  88 // ---------------------------------------------------------------------------- 
  92 // this module initializes RichEdit DLL(s) if needed 
  93 class wxRichEditModule 
: public wxModule
 
  96     virtual bool OnInit(); 
  97     virtual void OnExit(); 
  99     // load the richedit DLL of at least of required version 
 100     static bool Load(int version 
= 1); 
 103     // the handles to richedit 1.0 and 2.0 (or 3.0) DLLs 
 104     static HINSTANCE ms_hRichEdit
[2]; 
 106     DECLARE_DYNAMIC_CLASS(wxRichEditModule
) 
 109 HINSTANCE 
wxRichEditModule::ms_hRichEdit
[2] = { NULL
, NULL 
}; 
 111 IMPLEMENT_DYNAMIC_CLASS(wxRichEditModule
, wxModule
) 
 113 #endif // wxUSE_RICHEDIT 
 115 // ---------------------------------------------------------------------------- 
 116 // event tables and other macros 
 117 // ---------------------------------------------------------------------------- 
 119 #if wxUSE_EXTENDED_RTTI 
 120 WX_DEFINE_FLAGS( wxTextCtrlStyle 
) 
 122 wxBEGIN_FLAGS( wxTextCtrlStyle 
) 
 123     // new style border flags, we put them first to 
 124     // use them for streaming out 
 125     wxFLAGS_MEMBER(wxBORDER_SIMPLE
) 
 126     wxFLAGS_MEMBER(wxBORDER_SUNKEN
) 
 127     wxFLAGS_MEMBER(wxBORDER_DOUBLE
) 
 128     wxFLAGS_MEMBER(wxBORDER_RAISED
) 
 129     wxFLAGS_MEMBER(wxBORDER_STATIC
) 
 130     wxFLAGS_MEMBER(wxBORDER_NONE
) 
 132     // old style border flags 
 133     wxFLAGS_MEMBER(wxSIMPLE_BORDER
) 
 134     wxFLAGS_MEMBER(wxSUNKEN_BORDER
) 
 135     wxFLAGS_MEMBER(wxDOUBLE_BORDER
) 
 136     wxFLAGS_MEMBER(wxRAISED_BORDER
) 
 137     wxFLAGS_MEMBER(wxSTATIC_BORDER
) 
 138     wxFLAGS_MEMBER(wxNO_BORDER
) 
 140     // standard window styles 
 141     wxFLAGS_MEMBER(wxTAB_TRAVERSAL
) 
 142     wxFLAGS_MEMBER(wxCLIP_CHILDREN
) 
 143     wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW
) 
 144     wxFLAGS_MEMBER(wxWANTS_CHARS
) 
 145     wxFLAGS_MEMBER(wxNO_FULL_REPAINT_ON_RESIZE
) 
 146     wxFLAGS_MEMBER(wxALWAYS_SHOW_SB 
) 
 147     wxFLAGS_MEMBER(wxVSCROLL
) 
 148     wxFLAGS_MEMBER(wxHSCROLL
) 
 150     wxFLAGS_MEMBER(wxTE_PROCESS_ENTER
) 
 151     wxFLAGS_MEMBER(wxTE_PROCESS_TAB
) 
 152     wxFLAGS_MEMBER(wxTE_MULTILINE
) 
 153     wxFLAGS_MEMBER(wxTE_PASSWORD
) 
 154     wxFLAGS_MEMBER(wxTE_READONLY
) 
 155     wxFLAGS_MEMBER(wxHSCROLL
) 
 156     wxFLAGS_MEMBER(wxTE_RICH
) 
 157     wxFLAGS_MEMBER(wxTE_RICH2
) 
 158     wxFLAGS_MEMBER(wxTE_AUTO_URL
) 
 159     wxFLAGS_MEMBER(wxTE_NOHIDESEL
) 
 160     wxFLAGS_MEMBER(wxTE_LEFT
) 
 161     wxFLAGS_MEMBER(wxTE_CENTRE
) 
 162     wxFLAGS_MEMBER(wxTE_RIGHT
) 
 163     wxFLAGS_MEMBER(wxTE_DONTWRAP
) 
 164     wxFLAGS_MEMBER(wxTE_LINEWRAP
) 
 165     wxFLAGS_MEMBER(wxTE_WORDWRAP
) 
 167 wxEND_FLAGS( wxTextCtrlStyle 
) 
 169 IMPLEMENT_DYNAMIC_CLASS_XTI(wxTextCtrl
, wxControl
,"wx/textctrl.h") 
 171 wxBEGIN_PROPERTIES_TABLE(wxTextCtrl
) 
 172     wxEVENT_PROPERTY( TextUpdated 
, wxEVT_COMMAND_TEXT_UPDATED 
, wxCommandEvent 
)  
 173     wxEVENT_PROPERTY( TextEnter 
, wxEVT_COMMAND_TEXT_ENTER 
, wxCommandEvent 
) 
 175     wxPROPERTY( Font 
, wxFont 
, SetFont 
, GetFont  
,, 0 /*flags*/ , wxT("Helpstring") , wxT("group") ) 
 176         wxPROPERTY( Value 
, wxString 
, SetValue
, GetValue
, wxString() , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) 
 177     wxPROPERTY_FLAGS( WindowStyle 
, wxTextCtrlStyle 
, long , SetWindowStyleFlag 
, GetWindowStyleFlag 
, , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style 
 178 wxEND_PROPERTIES_TABLE() 
 180 wxBEGIN_HANDLERS_TABLE(wxTextCtrl
) 
 181 wxEND_HANDLERS_TABLE() 
 183 wxCONSTRUCTOR_6( wxTextCtrl 
, wxWindow
* , Parent 
, wxWindowID 
, Id 
, wxString 
, Value 
, wxPoint 
, Position 
, wxSize 
, Size 
, long , WindowStyle
) 
 185 IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl
, wxControl
) 
 189 BEGIN_EVENT_TABLE(wxTextCtrl
, wxControl
) 
 190     EVT_CHAR(wxTextCtrl::OnChar
) 
 191     EVT_DROP_FILES(wxTextCtrl::OnDropFiles
) 
 194     EVT_RIGHT_UP(wxTextCtrl::OnRightClick
) 
 197     EVT_MENU(wxID_CUT
, wxTextCtrl::OnCut
) 
 198     EVT_MENU(wxID_COPY
, wxTextCtrl::OnCopy
) 
 199     EVT_MENU(wxID_PASTE
, wxTextCtrl::OnPaste
) 
 200     EVT_MENU(wxID_UNDO
, wxTextCtrl::OnUndo
) 
 201     EVT_MENU(wxID_REDO
, wxTextCtrl::OnRedo
) 
 202     EVT_MENU(wxID_CLEAR
, wxTextCtrl::OnDelete
) 
 203     EVT_MENU(wxID_SELECTALL
, wxTextCtrl::OnSelectAll
) 
 205     EVT_UPDATE_UI(wxID_CUT
, wxTextCtrl::OnUpdateCut
) 
 206     EVT_UPDATE_UI(wxID_COPY
, wxTextCtrl::OnUpdateCopy
) 
 207     EVT_UPDATE_UI(wxID_PASTE
, wxTextCtrl::OnUpdatePaste
) 
 208     EVT_UPDATE_UI(wxID_UNDO
, wxTextCtrl::OnUpdateUndo
) 
 209     EVT_UPDATE_UI(wxID_REDO
, wxTextCtrl::OnUpdateRedo
) 
 210     EVT_UPDATE_UI(wxID_CLEAR
, wxTextCtrl::OnUpdateDelete
) 
 211     EVT_UPDATE_UI(wxID_SELECTALL
, wxTextCtrl::OnUpdateSelectAll
) 
 213     EVT_ERASE_BACKGROUND(wxTextCtrl::OnEraseBackground
) 
 216     EVT_SET_FOCUS(wxTextCtrl::OnSetFocus
) 
 219 // ============================================================================ 
 221 // ============================================================================ 
 223 // ---------------------------------------------------------------------------- 
 225 // ---------------------------------------------------------------------------- 
 227 void wxTextCtrl::Init() 
 231 #endif // wxUSE_RICHEDIT 
 233     m_privateContextMenu 
= NULL
; 
 234     m_suppressNextUpdate 
= FALSE
; 
 235     m_isNativeCaretShown 
= true; 
 238 wxTextCtrl::~wxTextCtrl() 
 240     if (m_privateContextMenu
) 
 242         delete m_privateContextMenu
; 
 243         m_privateContextMenu 
= NULL
; 
 247 bool wxTextCtrl::Create(wxWindow 
*parent
, wxWindowID id
, 
 248                         const wxString
& value
, 
 252                         const wxValidator
& validator
, 
 253                         const wxString
& name
) 
 255     // base initialization 
 256     if ( !CreateBase(parent
, id
, pos
, size
, style
, validator
, name
) ) 
 260         parent
->AddChild(this); 
 262     // translate wxWin style flags to MSW ones 
 263     WXDWORD msStyle 
= MSWGetCreateWindowFlags(); 
 265     // do create the control - either an EDIT or RICHEDIT 
 266     wxString windowClass 
= wxT("EDIT"); 
 269     if ( m_windowStyle 
& wxTE_AUTO_URL 
) 
 271         // automatic URL detection only works in RichEdit 2.0+ 
 272         m_windowStyle 
|= wxTE_RICH2
; 
 275     if ( m_windowStyle 
& wxTE_RICH2 
) 
 277         // using richedit 2.0 implies using wxTE_RICH 
 278         m_windowStyle 
|= wxTE_RICH
; 
 281     // we need to load the richedit DLL before creating the rich edit control 
 282     if ( m_windowStyle 
& wxTE_RICH 
) 
 284         static bool s_errorGiven 
= FALSE
;// MT-FIXME 
 286         // Which version do we need? Use 1.0 by default because it is much more 
 287         // like the the standard EDIT or 2.0 if explicitly requested, but use 
 288         // only 2.0 in Unicode mode as 1.0 doesn't support Unicode at all 
 290         // TODO: RichEdit 3.0 is apparently capable of emulating RichEdit 1.0 
 291         //       (and thus EDIT) much better than RichEdit 2.0 so we probably 
 292         //       should use 3.0 if available as it is the best of both worlds - 
 293         //       but as I can't test it right now I don't do it (VZ) 
 295         const int verRichEdit 
= 2; 
 296 #else // !wxUSE_UNICODE 
 297         int verRichEdit 
= m_windowStyle 
& wxTE_RICH2 
? 2 : 1; 
 298 #endif // wxUSE_UNICODE/!wxUSE_UNICODE 
 300         // only give the error msg once if the DLL can't be loaded 
 303             // try to load the RichEdit DLL (will do nothing if already done) 
 304             if ( !wxRichEditModule::Load(verRichEdit
) ) 
 307                 // try another version? 
 308                 verRichEdit 
= 3 - verRichEdit
; // 1 <-> 2 
 310                 if ( !wxRichEditModule::Load(verRichEdit
) ) 
 311 #endif // wxUSE_UNICODE 
 313                     wxLogError(_("Impossible to create a rich edit control, using simple text control instead. Please reinstall riched32.dll")); 
 320         // have we managed to load any richedit version? 
 323             m_verRichEdit 
= verRichEdit
; 
 324             if ( m_verRichEdit 
== 1 ) 
 326                 windowClass 
= wxT("RICHEDIT"); 
 330 #ifndef RICHEDIT_CLASS 
 331                 wxString RICHEDIT_CLASS
; 
 332                 RICHEDIT_CLASS
.Printf(_T("RichEdit%d0"), m_verRichEdit
); 
 334                 RICHEDIT_CLASS 
+= _T('W'); 
 336                 RICHEDIT_CLASS 
+= _T('A'); 
 337 #endif // Unicode/ANSI 
 338 #endif // !RICHEDIT_CLASS 
 340                 windowClass 
= RICHEDIT_CLASS
; 
 344 #endif // wxUSE_RICHEDIT 
 346     // we need to turn '\n's into "\r\n"s for the multiline controls 
 348     if ( m_windowStyle 
& wxTE_MULTILINE 
) 
 350         valueWin 
= wxTextFile::Translate(value
, wxTextFileType_Dos
); 
 357     if ( !MSWCreateControl(windowClass
, msStyle
, pos
, size
, valueWin
) ) 
 360     SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
)); 
 365         // enable the events we're interested in: we want to get EN_CHANGE as 
 366         // for the normal controls 
 367         LPARAM mask 
= ENM_CHANGE
; 
 369         if ( GetRichVersion() == 1 ) 
 371             // we also need EN_MSGFILTER for richedit 1.0 for the reasons 
 372             // explained in its handler 
 373            mask 
|= ENM_MOUSEEVENTS
; 
 375         else if ( m_windowStyle 
& wxTE_AUTO_URL 
) 
 379             ::SendMessage(GetHwnd(), EM_AUTOURLDETECT
, TRUE
, 0); 
 382         ::SendMessage(GetHwnd(), EM_SETEVENTMASK
, 0, mask
); 
 384 #endif // wxUSE_RICHEDIT 
 389 // Make sure the window style (etc.) reflects the HWND style (roughly) 
 390 void wxTextCtrl::AdoptAttributesFromHWND() 
 392     wxWindow::AdoptAttributesFromHWND(); 
 394     HWND hWnd 
= GetHwnd(); 
 395     long style 
= ::GetWindowLong(hWnd
, GWL_STYLE
); 
 397     // retrieve the style to see whether this is an edit or richedit ctrl 
 399     wxString classname 
= wxGetWindowClass(GetHWND()); 
 401     if ( classname
.IsSameAs(_T("EDIT"), FALSE 
/* no case */) ) 
 408         if ( wxSscanf(classname
, _T("RichEdit%d0%c"), &m_verRichEdit
, &c
) != 2 ) 
 410             wxLogDebug(_T("Unknown edit control '%s'."), classname
.c_str()); 
 415 #endif // wxUSE_RICHEDIT 
 417     if (style 
& ES_MULTILINE
) 
 418         m_windowStyle 
|= wxTE_MULTILINE
; 
 419     if (style 
& ES_PASSWORD
) 
 420         m_windowStyle 
|= wxTE_PASSWORD
; 
 421     if (style 
& ES_READONLY
) 
 422         m_windowStyle 
|= wxTE_READONLY
; 
 423     if (style 
& ES_WANTRETURN
) 
 424         m_windowStyle 
|= wxTE_PROCESS_ENTER
; 
 425     if (style 
& ES_CENTER
) 
 426         m_windowStyle 
|= wxTE_CENTRE
; 
 427     if (style 
& ES_RIGHT
) 
 428         m_windowStyle 
|= wxTE_RIGHT
; 
 431 WXDWORD 
wxTextCtrl::MSWGetStyle(long style
, WXDWORD 
*exstyle
) const 
 433     long msStyle 
= wxControl::MSWGetStyle(style
, exstyle
); 
 435     // styles which we alaways add by default 
 436     if ( style 
& wxTE_MULTILINE 
) 
 438         wxASSERT_MSG( !(style 
& wxTE_PROCESS_ENTER
), 
 439                       wxT("wxTE_PROCESS_ENTER style is ignored for multiline text controls (they always process it)") ); 
 441         msStyle 
|= ES_MULTILINE 
| ES_WANTRETURN
; 
 442         if ( !(style 
& wxTE_NO_VSCROLL
) ) 
 444             // always adjust the vertical scrollbar automatically if we have it 
 445             msStyle 
|= WS_VSCROLL 
| ES_AUTOVSCROLL
; 
 448             // we have to use this style for the rich edit controls because 
 449             // without it the vertical scrollbar never appears at all in 
 450             // richedit 3.0 because of our ECO_NOHIDESEL hack (search for it) 
 451             if ( style 
& wxTE_RICH2 
) 
 453                 msStyle 
|= ES_DISABLENOSCROLL
; 
 455 #endif // wxUSE_RICHEDIT 
 458         style 
|= wxTE_PROCESS_ENTER
; 
 462         // there is really no reason to not have this style for single line 
 464         msStyle 
|= ES_AUTOHSCROLL
; 
 467     // styles which we add depending on the specified wxWindows styles 
 468     if ( style 
& wxHSCROLL 
) 
 470         // automatically scroll the control horizontally as necessary 
 471         msStyle 
|= WS_HSCROLL
;// | ES_AUTOHSCROLL; 
 474     if ( style 
& wxTE_READONLY 
) 
 475         msStyle 
|= ES_READONLY
; 
 477     if ( style 
& wxTE_PASSWORD 
) 
 478         msStyle 
|= ES_PASSWORD
; 
 480     if ( style 
& wxTE_NOHIDESEL 
) 
 481         msStyle 
|= ES_NOHIDESEL
; 
 483     // note that we can't do do "& wxTE_LEFT" as wxTE_LEFT == 0 
 484     if ( style 
& wxTE_CENTRE 
) 
 485         msStyle 
|= ES_CENTER
; 
 486     else if ( style 
& wxTE_RIGHT 
) 
 489         msStyle 
|= ES_LEFT
; // ES_LEFT if 0 as well but for consistency... 
 494 void wxTextCtrl::SetWindowStyleFlag(long style
) 
 497     // we have to deal with some styles separately because they can't be 
 498     // changed by simply calling SetWindowLong(GWL_STYLE) but can be changed 
 499     // using richedit-specific EM_SETOPTIONS 
 501             ((style 
& wxTE_NOHIDESEL
) != (GetWindowStyle() & wxTE_NOHIDESEL
)) ) 
 503         bool set 
= (style 
& wxTE_NOHIDESEL
) != 0; 
 505         ::SendMessage(GetHwnd(), EM_SETOPTIONS
, set 
? ECOOP_OR 
: ECOOP_AND
, 
 506                       set 
? ECO_NOHIDESEL 
: ~ECO_NOHIDESEL
); 
 508 #endif // wxUSE_RICHEDIT 
 510     wxControl::SetWindowStyleFlag(style
); 
 513 // ---------------------------------------------------------------------------- 
 514 // set/get the controls text 
 515 // ---------------------------------------------------------------------------- 
 517 wxString 
wxTextCtrl::GetValue() const 
 519     // range 0..-1 is special for GetRange() and means to retrieve all text 
 520     return GetRange(0, -1); 
 523 wxString 
wxTextCtrl::GetRange(long from
, long to
) const 
 527     if ( from 
>= to 
&& to 
!= -1 ) 
 529         // nothing to retrieve 
 536         int len 
= GetWindowTextLength(GetHwnd()); 
 540                 // alloc one extra WORD as needed by the control 
 541                 wxStringBuffer 
tmp(str
, ++len
); 
 545                 textRange
.chrg
.cpMin 
= from
; 
 546                 textRange
.chrg
.cpMax 
= to 
== -1 ? len 
: to
; 
 547                 textRange
.lpstrText 
= p
; 
 549                 (void)SendMessage(GetHwnd(), EM_GETTEXTRANGE
, 
 550                                   0, (LPARAM
)&textRange
); 
 552                 if ( m_verRichEdit 
> 1 ) 
 554                     // RichEdit 2.0 uses just CR ('\r') for the 
 555                     // newlines which is neither Unix nor Windows 
 556                     // style - convert it to something reasonable 
 559                         if ( *p 
== _T('\r') ) 
 565             if ( m_verRichEdit 
== 1 ) 
 567                 // convert to the canonical form - see comment below 
 568                 str 
= wxTextFile::Translate(str
, wxTextFileType_Unix
); 
 571         //else: no text at all, leave the string empty 
 574 #endif // wxUSE_RICHEDIT 
 577         str 
= wxGetWindowText(GetHWND()); 
 579         // need only a range? 
 582             str 
= str
.Mid(from
, to 
- from
); 
 585         // WM_GETTEXT uses standard DOS CR+LF (\r\n) convention - convert to the 
 586         // canonical one (same one as above) for consistency with the other kinds 
 587         // of controls and, more importantly, with the other ports 
 588         str 
= wxTextFile::Translate(str
, wxTextFileType_Unix
); 
 594 void wxTextCtrl::SetValue(const wxString
& value
) 
 596     // if the text is long enough, it's faster to just set it instead of first 
 597     // comparing it with the old one (chances are that it will be different 
 598     // anyhow, this comparison is there to avoid flicker for small single-line 
 599     // edit controls mostly) 
 600     if ( (value
.length() > 0x400) || (value 
!= GetValue()) ) 
 602         DoWriteText(value
, FALSE 
/* not selection only */); 
 606         // still send an event for consistency 
 610     // we should reset the modified flag even if the value didn't really change 
 612     // mark the control as being not dirty - we changed its text, not the 
 616     // for compatibility, don't move the cursor when doing SetValue() 
 617     SetInsertionPoint(0); 
 620 #if wxUSE_RICHEDIT && (!wxUSE_UNICODE || wxUSE_UNICODE_MSLU) 
 622 DWORD CALLBACK 
wxRichEditStreamIn(DWORD dwCookie
, BYTE 
*buf
, LONG cb
, LONG 
*pcb
) 
 626     wchar_t *wbuf 
= (wchar_t *)buf
; 
 627     const wchar_t *wpc 
= *(const wchar_t **)dwCookie
; 
 632         cb 
-= sizeof(wchar_t); 
 633         (*pcb
) += sizeof(wchar_t); 
 636     *(const wchar_t **)dwCookie 
= wpc
; 
 642 extern WXDLLIMPEXP_BASE 
long wxEncodingToCodepage(wxFontEncoding encoding
); 
 644 #if wxUSE_UNICODE_MSLU 
 645 bool wxTextCtrl::StreamIn(const wxString
& value
, 
 646                           wxFontEncoding 
WXUNUSED(encoding
), 
 649     const wchar_t *wpc 
= value
.c_str(); 
 650 #else // !wxUSE_UNICODE_MSLU 
 651 bool wxTextCtrl::StreamIn(const wxString
& value
, 
 652                           wxFontEncoding encoding
, 
 655     // we have to use EM_STREAMIN to force richedit control 2.0+ to show any 
 656     // text in the non default charset -- otherwise it thinks it knows better 
 657     // than we do and always shows it in the default one 
 659     // first get the Windows code page for this encoding 
 660     long codepage 
= wxEncodingToCodepage(encoding
); 
 661     if ( codepage 
== -1 ) 
 667     // next translate to Unicode using this code page 
 668     int len 
= ::MultiByteToWideChar(codepage
, 0, value
, -1, NULL
, 0); 
 671     wxWCharBuffer 
wchBuf(len
); 
 673     wchar_t *wchBuf 
= (wchar_t *)malloc((len 
+ 1)*sizeof(wchar_t)); 
 676     if ( !::MultiByteToWideChar(codepage
, 0, value
, -1, 
 677                                 (wchar_t *)(const wchar_t *)wchBuf
, len
) ) 
 679         wxLogLastError(_T("MultiByteToWideChar")); 
 682     // finally, stream it in the control 
 683     const wchar_t *wpc 
= wchBuf
; 
 684 #endif // wxUSE_UNICODE_MSLU 
 688     eds
.dwCookie 
= (DWORD
)&wpc
; 
 689     // the cast below is needed for broken (very) old mingw32 headers 
 690     eds
.pfnCallback 
= (EDITSTREAMCALLBACK
)wxRichEditStreamIn
; 
 692     // we're going to receive 2 EN_CHANGE notifications if we got any selection 
 693     // (same problem as in DoWriteText()) 
 694     if ( selectionOnly 
&& HasSelection() ) 
 696         // so suppress one of them 
 697         m_suppressNextUpdate 
= TRUE
; 
 700     ::SendMessage(GetHwnd(), EM_STREAMIN
, 
 703                   (selectionOnly 
? SFF_SELECTION 
: 0), 
 708         wxLogLastError(_T("EM_STREAMIN")); 
 713 #endif // !wxUSE_WCHAR_T 
 718 #endif // wxUSE_RICHEDIT 
 720 void wxTextCtrl::WriteText(const wxString
& value
) 
 725 void wxTextCtrl::DoWriteText(const wxString
& value
, bool selectionOnly
) 
 728     if ( m_windowStyle 
& wxTE_MULTILINE 
) 
 729         valueDos 
= wxTextFile::Translate(value
, wxTextFileType_Dos
); 
 734     // there are several complications with the rich edit controls here 
 738         // first, ensure that the new text will be in the default style 
 739         if ( !m_defaultStyle
.IsDefault() ) 
 742             GetSelection(&start
, &end
); 
 743             SetStyle(start
, end
, m_defaultStyle
); 
 746 #if wxUSE_UNICODE_MSLU 
 747         // RichEdit doesn't have Unicode version of EM_REPLACESEL on Win9x, 
 748         // but EM_STREAMIN works 
 749         if ( wxUsingUnicowsDll() && GetRichVersion() > 1 ) 
 751            done 
= StreamIn(valueDos
, wxFONTENCODING_SYSTEM
, selectionOnly
); 
 753 #endif // wxUSE_UNICODE_MSLU 
 756         // next check if the text we're inserting must be shown in a non 
 757         // default charset -- this only works for RichEdit > 1.0 
 758         if ( GetRichVersion() > 1 ) 
 760             wxFont font 
= m_defaultStyle
.GetFont(); 
 766                wxFontEncoding encoding 
= font
.GetEncoding(); 
 767                if ( encoding 
!= wxFONTENCODING_SYSTEM 
) 
 769                    done 
= StreamIn(valueDos
, encoding
, selectionOnly
); 
 773 #endif // !wxUSE_UNICODE 
 777 #endif // wxUSE_RICHEDIT 
 779         // in some cases we get 2 EN_CHANGE notifications after the SendMessage 
 780         // call below which is confusing for the client code and so should be 
 783         // these cases are: (a) plain EDIT controls if EM_REPLACESEL is used 
 784         // and there is a non empty selection currently and (b) rich text 
 785         // controls in any case 
 789 #endif // wxUSE_RICHEDIT 
 790             (selectionOnly 
&& HasSelection()) ) 
 792             m_suppressNextUpdate 
= TRUE
; 
 795         ::SendMessage(GetHwnd(), selectionOnly 
? EM_REPLACESEL 
: WM_SETTEXT
, 
 796                       0, (LPARAM
)valueDos
.c_str()); 
 798         // OTOH, non rich text controls don't generate any events at all when 
 799         // we use WM_SETTEXT -- have to emulate them here 
 803 #endif // wxUSE_RICHEDIT 
 806             // Windows already sends an update event for single-line 
 808             if ( m_windowStyle 
& wxTE_MULTILINE 
) 
 816 void wxTextCtrl::AppendText(const wxString
& text
) 
 818     SetInsertionPointEnd(); 
 823     if ( IsMultiLine() && GetRichVersion() > 1 ) 
 825         // setting the caret to the end and showing it simply doesn't work for 
 826         // RichEdit 2.0 -- force it to still do what we want 
 827         ::SendMessage(GetHwnd(), EM_LINESCROLL
, 0, GetNumberOfLines()); 
 829 #endif // wxUSE_RICHEDIT 
 832 void wxTextCtrl::Clear() 
 834     ::SetWindowText(GetHwnd(), wxEmptyString
); 
 838 #endif // wxUSE_RICHEDIT 
 840         // rich edit controls send EN_UPDATE from WM_SETTEXT handler themselves 
 841         // but the normal ones don't -- make Clear() behaviour consistent by 
 842         // always sending this event 
 844         // Windows already sends an update event for single-line 
 846         if ( m_windowStyle 
& wxTE_MULTILINE 
) 
 853 bool wxTextCtrl::EmulateKeyPress(const wxKeyEvent
& event
) 
 857     size_t lenOld 
= GetValue().length(); 
 859     wxUint32 code 
= event
.GetRawKeyCode(); 
 860     ::keybd_event(code
, 0, 0 /* key press */, 0); 
 861     ::keybd_event(code
, 0, KEYEVENTF_KEYUP
, 0); 
 863     // assume that any alphanumeric key changes the total number of characters 
 864     // in the control - this should work in 99% of cases 
 865     return GetValue().length() != lenOld
; 
 870 // ---------------------------------------------------------------------------- 
 871 // Clipboard operations 
 872 // ---------------------------------------------------------------------------- 
 874 void wxTextCtrl::Copy() 
 878         ::SendMessage(GetHwnd(), WM_COPY
, 0, 0L); 
 882 void wxTextCtrl::Cut() 
 886         ::SendMessage(GetHwnd(), WM_CUT
, 0, 0L); 
 890 void wxTextCtrl::Paste() 
 894         ::SendMessage(GetHwnd(), WM_PASTE
, 0, 0L); 
 898 bool wxTextCtrl::HasSelection() const 
 901     GetSelection(&from
, &to
); 
 905 bool wxTextCtrl::CanCopy() const 
 907     // Can copy if there's a selection 
 908     return HasSelection(); 
 911 bool wxTextCtrl::CanCut() const 
 913     return CanCopy() && IsEditable(); 
 916 bool wxTextCtrl::CanPaste() const 
 924         UINT cf 
= 0; // 0 == any format 
 926         return ::SendMessage(GetHwnd(), EM_CANPASTE
, cf
, 0) != 0; 
 928 #endif // wxUSE_RICHEDIT 
 930     // Standard edit control: check for straight text on clipboard 
 931     if ( !::OpenClipboard(GetHwndOf(wxTheApp
->GetTopWindow())) ) 
 934     bool isTextAvailable 
= ::IsClipboardFormatAvailable(CF_TEXT
) != 0; 
 937     return isTextAvailable
; 
 940 // ---------------------------------------------------------------------------- 
 942 // ---------------------------------------------------------------------------- 
 944 void wxTextCtrl::SetEditable(bool editable
) 
 946     HWND hWnd 
= GetHwnd(); 
 947     SendMessage(hWnd
, EM_SETREADONLY
, (WPARAM
)!editable
, (LPARAM
)0L); 
 950 void wxTextCtrl::SetInsertionPoint(long pos
) 
 952     DoSetSelection(pos
, pos
); 
 955 void wxTextCtrl::SetInsertionPointEnd() 
 957     // we must not do anything if the caret is already there because calling 
 958     // SetInsertionPoint() thaws the controls if Freeze() had been called even 
 959     // if it doesn't actually move the caret anywhere and so the simple fact of 
 960     // doing it results in horrible flicker when appending big amounts of text 
 961     // to the control in a few chunks (see DoAddText() test in the text sample) 
 962     if ( GetInsertionPoint() == GetLastPosition() ) 
 968     if ( m_verRichEdit 
== 1 ) 
 970         // we don't have to waste time calling GetLastPosition() in this case 
 973     else // !RichEdit 1.0 
 974 #endif // wxUSE_RICHEDIT 
 976         pos 
= GetLastPosition(); 
 979     SetInsertionPoint(pos
); 
 982 long wxTextCtrl::GetInsertionPoint() const 
 990         SendMessage(GetHwnd(), EM_EXGETSEL
, 0, (LPARAM
) &range
); 
 993 #endif // wxUSE_RICHEDIT 
 995     DWORD Pos 
= (DWORD
)SendMessage(GetHwnd(), EM_GETSEL
, 0, 0L); 
 999 long wxTextCtrl::GetLastPosition() const 
1001     int numLines 
= GetNumberOfLines(); 
1002     long posStartLastLine 
= XYToPosition(0, numLines 
- 1); 
1004     long lenLastLine 
= GetLengthOfLineContainingPos(posStartLastLine
); 
1006     return posStartLastLine 
+ lenLastLine
; 
1009 // If the return values from and to are the same, there is no 
1011 void wxTextCtrl::GetSelection(long* from
, long* to
) const 
1016         CHARRANGE charRange
; 
1017         ::SendMessage(GetHwnd(), EM_EXGETSEL
, 0, (LPARAM
) &charRange
); 
1019         *from 
= charRange
.cpMin
; 
1020         *to 
= charRange
.cpMax
; 
1023 #endif // !wxUSE_RICHEDIT 
1025         DWORD dwStart
, dwEnd
; 
1026         ::SendMessage(GetHwnd(), EM_GETSEL
, (WPARAM
)&dwStart
, (LPARAM
)&dwEnd
); 
1033 bool wxTextCtrl::IsEditable() const 
1035     // strangely enough, we may be called before the control is created: our 
1036     // own Create() calls MSWGetStyle() which calls AcceptsFocus() which calls 
1041     long style 
= ::GetWindowLong(GetHwnd(), GWL_STYLE
); 
1043     return (style 
& ES_READONLY
) == 0; 
1046 // ---------------------------------------------------------------------------- 
1048 // ---------------------------------------------------------------------------- 
1050 void wxTextCtrl::SetSelection(long from
, long to
) 
1052     // if from and to are both -1, it means (in wxWindows) that all text should 
1053     // be selected - translate into Windows convention 
1054     if ( (from 
== -1) && (to 
== -1) ) 
1060     DoSetSelection(from
, to
); 
1063 void wxTextCtrl::DoSetSelection(long from
, long to
, bool scrollCaret
) 
1065     HWND hWnd 
= GetHwnd(); 
1074         SendMessage(hWnd
, EM_EXSETSEL
, 0, (LPARAM
) &range
); 
1077 #endif // wxUSE_RICHEDIT 
1079         SendMessage(hWnd
, EM_SETSEL
, (WPARAM
)from
, (LPARAM
)to
); 
1085         // richedit 3.0 (i.e. the version living in riched20.dll distributed 
1086         // with Windows 2000 and beyond) doesn't honour EM_SCROLLCARET when 
1087         // emulating richedit 2.0 unless the control has focus or ECO_NOHIDESEL 
1088         // option is set (but it does work ok in richedit 1.0 mode...) 
1090         // so to make it work we either need to give focus to it here which 
1091         // will probably create many problems (dummy focus events; window 
1092         // containing the text control being brought to foreground 
1093         // unexpectedly; ...) or to temporarily set ECO_NOHIDESEL which may 
1094         // create other problems too -- and in fact it does because if we turn 
1095         // on/off this style while appending the text to the control, the 
1096         // vertical scrollbar never appears in it even if we append tons of 
1097         // text and to work around this the only solution I found was to use 
1098         // ES_DISABLENOSCROLL 
1100         // this is very ugly but I don't see any other way to make this work 
1101         if ( GetRichVersion() > 1 ) 
1103             if ( !HasFlag(wxTE_NOHIDESEL
) ) 
1105                 ::SendMessage(GetHwnd(), EM_SETOPTIONS
, 
1106                               ECOOP_OR
, ECO_NOHIDESEL
); 
1108             //else: everything is already ok 
1110 #endif // wxUSE_RICHEDIT 
1112         SendMessage(hWnd
, EM_SCROLLCARET
, (WPARAM
)0, (LPARAM
)0); 
1115         // restore ECO_NOHIDESEL if we changed it 
1116         if ( GetRichVersion() > 1 && !HasFlag(wxTE_NOHIDESEL
) ) 
1118             ::SendMessage(GetHwnd(), EM_SETOPTIONS
, 
1119                           ECOOP_AND
, ~ECO_NOHIDESEL
); 
1121 #endif // wxUSE_RICHEDIT 
1124     // WPARAM is 0: selection is scrolled into view 
1125     SendMessage(hWnd
, EM_SETSEL
, (WPARAM
)0, (LPARAM
)MAKELONG(from
, to
)); 
1129 // ---------------------------------------------------------------------------- 
1131 // ---------------------------------------------------------------------------- 
1133 void wxTextCtrl::Replace(long from
, long to
, const wxString
& value
) 
1135     // Set selection and remove it 
1136     DoSetSelection(from
, to
, FALSE 
/* don't scroll caret into view */); 
1138     SendMessage(GetHwnd(), EM_REPLACESEL
, 
1144                 (LPARAM
)value
.c_str()); 
1147 void wxTextCtrl::Remove(long from
, long to
) 
1149     Replace(from
, to
, wxEmptyString
); 
1152 bool wxTextCtrl::LoadFile(const wxString
& file
) 
1154     if ( wxTextCtrlBase::LoadFile(file
) ) 
1156         // update the size limit if needed 
1165 bool wxTextCtrl::IsModified() const 
1167     return SendMessage(GetHwnd(), EM_GETMODIFY
, 0, 0) != 0; 
1170 // Makes 'unmodified' 
1171 void wxTextCtrl::DiscardEdits() 
1173     SendMessage(GetHwnd(), EM_SETMODIFY
, FALSE
, 0L); 
1176 int wxTextCtrl::GetNumberOfLines() const 
1178     return (int)SendMessage(GetHwnd(), EM_GETLINECOUNT
, (WPARAM
)0, (LPARAM
)0); 
1181 long wxTextCtrl::XYToPosition(long x
, long y
) const 
1183     // This gets the char index for the _beginning_ of this line 
1184     long charIndex 
= SendMessage(GetHwnd(), EM_LINEINDEX
, (WPARAM
)y
, (LPARAM
)0); 
1186     return charIndex 
+ x
; 
1189 bool wxTextCtrl::PositionToXY(long pos
, long *x
, long *y
) const 
1191     HWND hWnd 
= GetHwnd(); 
1193     // This gets the line number containing the character 
1198         lineNo 
= SendMessage(hWnd
, EM_EXLINEFROMCHAR
, 0, (LPARAM
)pos
); 
1201 #endif // wxUSE_RICHEDIT 
1203         lineNo 
= SendMessage(hWnd
, EM_LINEFROMCHAR
, (WPARAM
)pos
, 0); 
1212     // This gets the char index for the _beginning_ of this line 
1213     long charIndex 
= SendMessage(hWnd
, EM_LINEINDEX
, (WPARAM
)lineNo
, (LPARAM
)0); 
1214     if ( charIndex 
== -1 ) 
1219     // The X position must therefore be the different between pos and charIndex 
1221         *x 
= pos 
- charIndex
; 
1228 void wxTextCtrl::ShowPosition(long pos
) 
1230     HWND hWnd 
= GetHwnd(); 
1232     // To scroll to a position, we pass the number of lines and characters 
1233     // to scroll *by*. This means that we need to: 
1234     // (1) Find the line position of the current line. 
1235     // (2) Find the line position of pos. 
1236     // (3) Scroll by (pos - current). 
1237     // For now, ignore the horizontal scrolling. 
1239     // Is this where scrolling is relative to - the line containing the caret? 
1240     // Or is the first visible line??? Try first visible line. 
1241 //    int currentLineLineNo1 = (int)SendMessage(hWnd, EM_LINEFROMCHAR, (WPARAM)-1, (LPARAM)0L); 
1243     int currentLineLineNo 
= (int)SendMessage(hWnd
, EM_GETFIRSTVISIBLELINE
, (WPARAM
)0, (LPARAM
)0L); 
1245     int specifiedLineLineNo 
= (int)SendMessage(hWnd
, EM_LINEFROMCHAR
, (WPARAM
)pos
, (LPARAM
)0L); 
1247     int linesToScroll 
= specifiedLineLineNo 
- currentLineLineNo
; 
1249     if (linesToScroll 
!= 0) 
1250       (void)SendMessage(hWnd
, EM_LINESCROLL
, (WPARAM
)0, (LPARAM
)linesToScroll
); 
1253 long wxTextCtrl::GetLengthOfLineContainingPos(long pos
) const 
1255     return ::SendMessage(GetHwnd(), EM_LINELENGTH
, (WPARAM
)pos
, 0); 
1258 int wxTextCtrl::GetLineLength(long lineNo
) const 
1260     long pos 
= XYToPosition(0, lineNo
); 
1262     return GetLengthOfLineContainingPos(pos
); 
1265 wxString 
wxTextCtrl::GetLineText(long lineNo
) const 
1267     size_t len 
= (size_t)GetLineLength(lineNo
) + 1; 
1269     // there must be at least enough place for the length WORD in the 
1271     len 
+= sizeof(WORD
); 
1275         wxStringBufferLength 
tmp(str
, len
); 
1278         *(WORD 
*)buf 
= (WORD
)len
; 
1279         len 
= (size_t)::SendMessage(GetHwnd(), EM_GETLINE
, lineNo
, (LPARAM
)buf
); 
1284             // remove the '\r' returned by the rich edit control, the user code 
1285             // should never see it 
1286             if ( buf
[len 
- 2] == _T('\r') && buf
[len 
- 1] == _T('\n') ) 
1288                 buf
[len 
- 2] = _T('\n'); 
1292 #endif // wxUSE_RICHEDIT 
1294         // remove the '\n' at the end, if any (this is how this function is 
1295         // supposed to work according to the docs) 
1296         if ( buf
[len 
- 1] == _T('\n') ) 
1308 void wxTextCtrl::SetMaxLength(unsigned long len
) 
1310     ::SendMessage(GetHwnd(), EM_LIMITTEXT
, len
, 0); 
1313 // ---------------------------------------------------------------------------- 
1315 // ---------------------------------------------------------------------------- 
1317 void wxTextCtrl::Undo() 
1321         ::SendMessage(GetHwnd(), EM_UNDO
, 0, 0); 
1325 void wxTextCtrl::Redo() 
1329         // Same as Undo, since Undo undoes the undo, i.e. a redo. 
1330         ::SendMessage(GetHwnd(), EM_UNDO
, 0, 0); 
1334 bool wxTextCtrl::CanUndo() const 
1336     return ::SendMessage(GetHwnd(), EM_CANUNDO
, 0, 0) != 0; 
1339 bool wxTextCtrl::CanRedo() const 
1341     return ::SendMessage(GetHwnd(), EM_CANUNDO
, 0, 0) != 0; 
1344 // ---------------------------------------------------------------------------- 
1345 // caret handling (Windows only) 
1346 // ---------------------------------------------------------------------------- 
1348 bool wxTextCtrl::ShowNativeCaret(bool show
) 
1350     if ( show 
!= m_isNativeCaretShown 
) 
1352         if ( !(show 
? ::ShowCaret(GetHwnd()) : ::HideCaret(GetHwnd())) ) 
1354             // not an error, may simply indicate that it's not shown/hidden 
1355             // yet (i.e. it had been hidden/showh 2 times before) 
1359         m_isNativeCaretShown 
= show
; 
1365 // ---------------------------------------------------------------------------- 
1366 // implemenation details 
1367 // ---------------------------------------------------------------------------- 
1369 void wxTextCtrl::Command(wxCommandEvent 
& event
) 
1371     SetValue(event
.GetString()); 
1372     ProcessCommand (event
); 
1375 void wxTextCtrl::OnDropFiles(wxDropFilesEvent
& event
) 
1377     // By default, load the first file into the text window. 
1378     if (event
.GetNumberOfFiles() > 0) 
1380         LoadFile(event
.GetFiles()[0]); 
1384 // ---------------------------------------------------------------------------- 
1385 // kbd input processing 
1386 // ---------------------------------------------------------------------------- 
1388 bool wxTextCtrl::MSWShouldPreProcessMessage(WXMSG
* pMsg
) 
1390     MSG 
*msg 
= (MSG 
*)pMsg
; 
1392     // check for our special keys here: if we don't do it and the parent frame 
1393     // uses them as accelerators, they wouldn't work at all, so we disable 
1394     // usual preprocessing for them 
1395     if ( msg
->message 
== WM_KEYDOWN 
) 
1397         WORD vkey 
= (WORD
) msg
->wParam
; 
1398         if ( (HIWORD(msg
->lParam
) & KF_ALTDOWN
) == KF_ALTDOWN 
) 
1400             if ( vkey 
== VK_BACK 
) 
1405             // we want to process some Ctrl-foo and Shift-bar but no key 
1406             // combinations without either Ctrl or Shift nor with both of them 
1408             const int ctrl 
= wxIsCtrlDown(), 
1409                       shift 
= wxIsShiftDown(); 
1410             switch ( ctrl 
+ shift 
) 
1413                     wxFAIL_MSG( _T("how many modifiers have we got?") ); 
1421                     // either Ctrl or Shift pressed 
1436                     else // Shift is pressed 
1438                         if ( vkey 
== VK_INSERT 
|| vkey 
== VK_DELETE 
) 
1445     return wxControl::MSWShouldPreProcessMessage(pMsg
); 
1448 void wxTextCtrl::OnChar(wxKeyEvent
& event
) 
1450     switch ( event
.GetKeyCode() ) 
1453             if ( !(m_windowStyle 
& wxTE_MULTILINE
) ) 
1455                 wxCommandEvent 
event(wxEVT_COMMAND_TEXT_ENTER
, m_windowId
); 
1456                 InitCommandEvent(event
); 
1457                 event
.SetString(GetValue()); 
1458                 if ( GetEventHandler()->ProcessEvent(event
) ) 
1461             //else: multiline controls need Enter for themselves 
1466             // always produce navigation event - even if we process TAB 
1467             // ourselves the fact that we got here means that the user code 
1468             // decided to skip processing of this TAB - probably to let it 
1469             // do its default job. 
1471                 wxNavigationKeyEvent eventNav
; 
1472                 eventNav
.SetDirection(!event
.ShiftDown()); 
1473                 eventNav
.SetWindowChange(event
.ControlDown()); 
1474                 eventNav
.SetEventObject(this); 
1476                 if ( GetParent()->GetEventHandler()->ProcessEvent(eventNav
) ) 
1482     // no, we didn't process it 
1486 long wxTextCtrl::MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
) 
1488     long lRc 
= wxTextCtrlBase::MSWWindowProc(nMsg
, wParam
, lParam
); 
1490     if ( nMsg 
== WM_GETDLGCODE 
) 
1492         // we always want the chars and the arrows: the arrows for navigation 
1493         // and the chars because we want Ctrl-C to work even in a read only 
1495         long lDlgCode 
= DLGC_WANTCHARS 
| DLGC_WANTARROWS
; 
1499             // we may have several different cases: 
1500             // 1. normal case: both TAB and ENTER are used for dlg navigation 
1501             // 2. ctrl which wants TAB for itself: ENTER is used to pass to the 
1502             //    next control in the dialog 
1503             // 3. ctrl which wants ENTER for itself: TAB is used for dialog 
1505             // 4. ctrl which wants both TAB and ENTER: Ctrl-ENTER is used to go 
1506             //    to the next control 
1508             // the multiline edit control should always get <Return> for itself 
1509             if ( HasFlag(wxTE_PROCESS_ENTER
) || HasFlag(wxTE_MULTILINE
) ) 
1510                 lDlgCode 
|= DLGC_WANTMESSAGE
; 
1512             if ( HasFlag(wxTE_PROCESS_TAB
) ) 
1513                 lDlgCode 
|= DLGC_WANTTAB
; 
1519             // NB: use "=", not "|=" as the base class version returns the 
1520             //     same flags is this state as usual (i.e. including 
1521             //     DLGC_WANTMESSAGE). This is strange (how does it work in the 
1522             //     native Win32 apps?) but for now live with it. 
1530 // ---------------------------------------------------------------------------- 
1531 // text control event processing 
1532 // ---------------------------------------------------------------------------- 
1534 bool wxTextCtrl::SendUpdateEvent() 
1536     // is event reporting suspended? 
1537     if ( m_suppressNextUpdate 
) 
1539         // do process the next one 
1540         m_suppressNextUpdate 
= FALSE
; 
1545     wxCommandEvent 
event(wxEVT_COMMAND_TEXT_UPDATED
, GetId()); 
1546     InitCommandEvent(event
); 
1547     event
.SetString(GetValue()); 
1549     return ProcessCommand(event
); 
1552 bool wxTextCtrl::MSWCommand(WXUINT param
, WXWORD 
WXUNUSED(id
)) 
1559                 wxFocusEvent 
event(param 
== EN_KILLFOCUS 
? wxEVT_KILL_FOCUS
 
1562                 event
.SetEventObject(this); 
1563                 GetEventHandler()->ProcessEvent(event
); 
1572             // the text size limit has been hit -- try to increase it 
1573             if ( !AdjustSpaceLimit() ) 
1575                 wxCommandEvent 
event(wxEVT_COMMAND_TEXT_MAXLEN
, m_windowId
); 
1576                 InitCommandEvent(event
); 
1577                 event
.SetString(GetValue()); 
1578                 ProcessCommand(event
); 
1582             // the other edit notification messages are not processed 
1591 WXHBRUSH 
wxTextCtrl::OnCtlColor(WXHDC pDC
, WXHWND 
WXUNUSED(pWnd
), WXUINT 
WXUNUSED(nCtlColor
), 
1597                                WXUINT 
WXUNUSED(message
), 
1598                                WXWPARAM 
WXUNUSED(wParam
), 
1599                                WXLPARAM 
WXUNUSED(lParam
) 
1606         HBRUSH hbrush 
= Ctl3dCtlColorEx(message
, wParam
, lParam
); 
1607         return (WXHBRUSH
) hbrush
; 
1609 #endif // wxUSE_CTL3D 
1612     wxColour colBack 
= GetBackgroundColour(); 
1614     if (!IsEnabled() && (GetWindowStyle() & wxTE_MULTILINE
) == 0) 
1615         colBack 
= wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
); 
1617     ::SetBkColor(hdc
, wxColourToRGB(colBack
)); 
1618     ::SetTextColor(hdc
, wxColourToRGB(GetForegroundColour())); 
1620     wxBrush 
*brush 
= wxTheBrushList
->FindOrCreateBrush(colBack
, wxSOLID
); 
1622     return (WXHBRUSH
)brush
->GetResourceHandle(); 
1625 // In WIN16, need to override normal erasing because 
1626 // Ctl3D doesn't use the wxWindows background colour. 
1628 void wxTextCtrl::OnEraseBackground(wxEraseEvent
& event
) 
1630     wxColour 
col(m_backgroundColour
); 
1634         col 
= wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
); 
1638     ::GetClientRect(GetHwnd(), &rect
); 
1640     COLORREF ref 
= wxColourToRGB(col
); 
1641     HBRUSH hBrush 
= ::CreateSolidBrush(ref
); 
1643         wxLogLastError(wxT("CreateSolidBrush")); 
1645     HDC hdc 
= (HDC
)event
.GetDC()->GetHDC(); 
1647     int mode 
= ::SetMapMode(hdc
, MM_TEXT
); 
1649     ::FillRect(hdc
, &rect
, hBrush
); 
1650     ::DeleteObject(hBrush
); 
1651     ::SetMapMode(hdc
, mode
); 
1656 bool wxTextCtrl::AdjustSpaceLimit() 
1659     unsigned int limit 
= ::SendMessage(GetHwnd(), EM_GETLIMITTEXT
, 0, 0); 
1661     // HACK: we try to automatically extend the limit for the amount of text 
1662     //       to allow (interactively) entering more than 64Kb of text under 
1663     //       Win9x but we shouldn't reset the text limit which was previously 
1664     //       set explicitly with SetMaxLength() 
1666     //       we could solve this by storing the limit we set in wxTextCtrl but 
1667     //       to save space we prefer to simply test here the actual limit 
1668     //       value: we consider that SetMaxLength() can only be called for 
1670     if ( limit 
< 0x8000 ) 
1672         // we've got more text than limit set by SetMaxLength() 
1676     unsigned int len 
= ::GetWindowTextLength(GetHwnd()); 
1679         limit 
= len 
+ 0x8000;    // 32Kb 
1684             // as a nice side effect, this also allows passing limit > 64Kb 
1685             ::SendMessage(GetHwnd(), EM_EXLIMITTEXT
, 0, limit
); 
1688 #endif // wxUSE_RICHEDIT 
1690             if ( limit 
> 0xffff ) 
1692                 // this will set it to a platform-dependent maximum (much more 
1693                 // than 64Kb under NT) 
1697             ::SendMessage(GetHwnd(), EM_LIMITTEXT
, limit
, 0); 
1702     // we changed the limit 
1706 bool wxTextCtrl::AcceptsFocus() const 
1708     // we don't want focus if we can't be edited unless we're a multiline 
1709     // control because then it might be still nice to get focus from keyboard 
1710     // to be able to scroll it without mouse 
1711     return (IsEditable() || IsMultiLine()) && wxControl::AcceptsFocus(); 
1714 wxSize 
wxTextCtrl::DoGetBestSize() const 
1717     wxGetCharSize(GetHWND(), &cx
, &cy
, &GetFont()); 
1719     int wText 
= DEFAULT_ITEM_WIDTH
; 
1721     int hText 
= EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy
); 
1722     if ( m_windowStyle 
& wxTE_MULTILINE 
) 
1724         hText 
*= wxMax(GetNumberOfLines(), 5); 
1726     //else: for single line control everything is ok 
1728     return wxSize(wText
, hText
); 
1731 // ---------------------------------------------------------------------------- 
1732 // standard handlers for standard edit menu events 
1733 // ---------------------------------------------------------------------------- 
1735 void wxTextCtrl::OnCut(wxCommandEvent
& WXUNUSED(event
)) 
1740 void wxTextCtrl::OnCopy(wxCommandEvent
& WXUNUSED(event
)) 
1745 void wxTextCtrl::OnPaste(wxCommandEvent
& WXUNUSED(event
)) 
1750 void wxTextCtrl::OnUndo(wxCommandEvent
& WXUNUSED(event
)) 
1755 void wxTextCtrl::OnRedo(wxCommandEvent
& WXUNUSED(event
)) 
1760 void wxTextCtrl::OnDelete(wxCommandEvent
& WXUNUSED(event
)) 
1763     GetSelection(& from
, & to
); 
1764     if (from 
!= -1 && to 
!= -1) 
1768 void wxTextCtrl::OnSelectAll(wxCommandEvent
& WXUNUSED(event
)) 
1770     SetSelection(-1, -1); 
1773 void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent
& event
) 
1775     event
.Enable( CanCut() ); 
1778 void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent
& event
) 
1780     event
.Enable( CanCopy() ); 
1783 void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent
& event
) 
1785     event
.Enable( CanPaste() ); 
1788 void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent
& event
) 
1790     event
.Enable( CanUndo() ); 
1793 void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent
& event
) 
1795     event
.Enable( CanRedo() ); 
1798 void wxTextCtrl::OnUpdateDelete(wxUpdateUIEvent
& event
) 
1801     GetSelection(& from
, & to
); 
1802     event
.Enable(from 
!= -1 && to 
!= -1 && from 
!= to 
&& IsEditable()) ; 
1805 void wxTextCtrl::OnUpdateSelectAll(wxUpdateUIEvent
& event
) 
1807     event
.Enable(GetLastPosition() > 0); 
1810 void wxTextCtrl::OnRightClick(wxMouseEvent
& event
) 
1815         if (!m_privateContextMenu
) 
1817             m_privateContextMenu 
= new wxMenu
; 
1818             m_privateContextMenu
->Append(wxID_UNDO
, _("&Undo")); 
1819             m_privateContextMenu
->Append(wxID_REDO
, _("&Redo")); 
1820             m_privateContextMenu
->AppendSeparator(); 
1821             m_privateContextMenu
->Append(wxID_CUT
, _("Cu&t")); 
1822             m_privateContextMenu
->Append(wxID_COPY
, _("&Copy")); 
1823             m_privateContextMenu
->Append(wxID_PASTE
, _("&Paste")); 
1824             m_privateContextMenu
->Append(wxID_CLEAR
, _("&Delete")); 
1825             m_privateContextMenu
->AppendSeparator(); 
1826             m_privateContextMenu
->Append(wxID_SELECTALL
, _("Select &All")); 
1828         PopupMenu(m_privateContextMenu
, event
.GetPosition()); 
1836 void wxTextCtrl::OnSetFocus(wxFocusEvent
& WXUNUSED(event
)) 
1838     // be sure the caret remains invisible if the user had hidden it 
1839     if ( !m_isNativeCaretShown 
) 
1841         ::HideCaret(GetHwnd()); 
1845 // the rest of the file only deals with the rich edit controls 
1848 // ---------------------------------------------------------------------------- 
1849 // EN_LINK processing 
1850 // ---------------------------------------------------------------------------- 
1852 bool wxTextCtrl::MSWOnNotify(int idCtrl
, WXLPARAM lParam
, WXLPARAM 
*result
) 
1854     NMHDR 
*hdr 
= (NMHDR
* )lParam
; 
1855     switch ( hdr
->code 
) 
1859                 const MSGFILTER 
*msgf 
= (MSGFILTER 
*)lParam
; 
1860                 UINT msg 
= msgf
->msg
; 
1862                 // this is a bit crazy but richedit 1.0 sends us all mouse 
1863                 // events _except_ WM_LBUTTONUP (don't ask me why) so we have 
1864                 // generate the wxWin events for this message manually 
1866                 // NB: in fact, this is still not totally correct as it does 
1867                 //     send us WM_LBUTTONUP if the selection was cleared by the 
1868                 //     last click -- so currently we get 2 events in this case, 
1869                 //     but as I don't see any obvious way to check for this I 
1870                 //     leave this code in place because it's still better than 
1871                 //     not getting left up events at all 
1872                 if ( msg 
== WM_LBUTTONUP 
) 
1874                     WXUINT flags 
= msgf
->wParam
; 
1875                     int x 
= GET_X_LPARAM(msgf
->lParam
), 
1876                         y 
= GET_Y_LPARAM(msgf
->lParam
); 
1878                     HandleMouseEvent(msg
, x
, y
, flags
); 
1882             // return TRUE to process the event (and FALSE to ignore it) 
1887                 const ENLINK 
*enlink 
= (ENLINK 
*)hdr
; 
1889                 switch ( enlink
->msg 
) 
1892                         // ok, so it is hardcoded - do we really nee to 
1894                         ::SetCursor(GetHcursorOf(wxCursor(wxCURSOR_HAND
))); 
1899                     case WM_LBUTTONDOWN
: 
1901                     case WM_LBUTTONDBLCLK
: 
1902                     case WM_RBUTTONDOWN
: 
1904                     case WM_RBUTTONDBLCLK
: 
1905                         // send a mouse event 
1907                             static const wxEventType eventsMouse
[] = 
1918                             // the event ids are consecutive 
1920                                 evtMouse(eventsMouse
[enlink
->msg 
- WM_MOUSEMOVE
]); 
1922                             InitMouseEvent(evtMouse
, 
1923                                            GET_X_LPARAM(enlink
->lParam
), 
1924                                            GET_Y_LPARAM(enlink
->lParam
), 
1927                             wxTextUrlEvent 
event(m_windowId
, evtMouse
, 
1929                                                  enlink
->chrg
.cpMax
); 
1931                             InitCommandEvent(event
); 
1933                             *result 
= ProcessCommand(event
); 
1941     // not processed, leave it to the base class 
1942     return wxTextCtrlBase::MSWOnNotify(idCtrl
, lParam
, result
); 
1945 // ---------------------------------------------------------------------------- 
1946 // colour setting for the rich edit controls 
1947 // ---------------------------------------------------------------------------- 
1949 bool wxTextCtrl::SetBackgroundColour(const wxColour
& colour
) 
1951     if ( !wxTextCtrlBase::SetBackgroundColour(colour
) ) 
1953         // colour didn't really change 
1959         // rich edit doesn't use WM_CTLCOLOR, hence we need to send 
1960         // EM_SETBKGNDCOLOR additionally 
1961         ::SendMessage(GetHwnd(), EM_SETBKGNDCOLOR
, 0, wxColourToRGB(colour
)); 
1967 bool wxTextCtrl::SetForegroundColour(const wxColour
& colour
) 
1969     if ( !wxTextCtrlBase::SetForegroundColour(colour
) ) 
1971         // colour didn't really change 
1977         // change the colour of everything 
1980         cf
.cbSize 
= sizeof(cf
); 
1981         cf
.dwMask 
= CFM_COLOR
; 
1982         cf
.crTextColor 
= wxColourToRGB(colour
); 
1983         ::SendMessage(GetHwnd(), EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf
); 
1989 // ---------------------------------------------------------------------------- 
1990 // styling support for rich edit controls 
1991 // ---------------------------------------------------------------------------- 
1995 bool wxTextCtrl::SetStyle(long start
, long end
, const wxTextAttr
& style
) 
1999         // can't do it with normal text control 
2003     // the richedit 1.0 doesn't handle setting background colour, so don't 
2004     // even try to do anything if it's the only thing we want to change 
2005     if ( m_verRichEdit 
== 1 && !style
.HasFont() && !style
.HasTextColour() && 
2006         !style
.HasLeftIndent() && !style
.HasRightIndent() && !style
.HasAlignment() && 
2009         // nothing to do: return TRUE if there was really nothing to do and 
2010         // FALSE if we failed to set bg colour 
2011         return !style
.HasBackgroundColour(); 
2014     // order the range if needed 
2022     // we can only change the format of the selection, so select the range we 
2023     // want and restore the old selection later 
2024     long startOld
, endOld
; 
2025     GetSelection(&startOld
, &endOld
); 
2027     // but do we really have to change the selection? 
2028     bool changeSel 
= start 
!= startOld 
|| end 
!= endOld
; 
2032         DoSetSelection(start
, end
, FALSE 
/* don't scroll caret into view */); 
2035     // initialize CHARFORMAT struct 
2044     // we can't use CHARFORMAT2 with RichEdit 1.0, so pretend it is a simple 
2045     // CHARFORMAT in that case 
2047     if ( m_verRichEdit 
== 1 ) 
2049         // this is the only thing the control is going to grok 
2050         cf
.cbSize 
= sizeof(CHARFORMAT
); 
2055         // CHARFORMAT or CHARFORMAT2 
2056         cf
.cbSize 
= sizeof(cf
); 
2059     if ( style
.HasFont() ) 
2061         // VZ: CFM_CHARSET doesn't seem to do anything at all in RichEdit 2.0 
2062         //     but using it doesn't seem to hurt neither so leaving it for now 
2064         cf
.dwMask 
|= CFM_FACE 
| CFM_SIZE 
| CFM_CHARSET 
| 
2065                      CFM_ITALIC 
| CFM_BOLD 
| CFM_UNDERLINE
; 
2067         // fill in data from LOGFONT but recalculate lfHeight because we need 
2068         // the real height in twips and not the negative number which 
2069         // wxFillLogFont() returns (this is correct in general and works with 
2070         // the Windows font mapper, but not here) 
2072         wxFillLogFont(&lf
, &style
.GetFont()); 
2073         cf
.yHeight 
= 20*style
.GetFont().GetPointSize(); // 1 pt = 20 twips 
2074         cf
.bCharSet 
= lf
.lfCharSet
; 
2075         cf
.bPitchAndFamily 
= lf
.lfPitchAndFamily
; 
2076         wxStrncpy( cf
.szFaceName
, lf
.lfFaceName
, WXSIZEOF(cf
.szFaceName
) ); 
2078         // also deal with underline/italic/bold attributes: note that we must 
2079         // always set CFM_ITALIC &c bits in dwMask, even if we don't set the 
2080         // style to allow clearing it 
2083             cf
.dwEffects 
|= CFE_ITALIC
; 
2086         if ( lf
.lfWeight 
== FW_BOLD 
) 
2088             cf
.dwEffects 
|= CFE_BOLD
; 
2091         if ( lf
.lfUnderline 
) 
2093             cf
.dwEffects 
|= CFE_UNDERLINE
; 
2096         // strikeout fonts are not supported by wxWindows 
2099     if ( style
.HasTextColour() ) 
2101         cf
.dwMask 
|= CFM_COLOR
; 
2102         cf
.crTextColor 
= wxColourToRGB(style
.GetTextColour()); 
2106     if ( m_verRichEdit 
!= 1 && style
.HasBackgroundColour() ) 
2108         cf
.dwMask 
|= CFM_BACKCOLOR
; 
2109         cf
.crBackColor 
= wxColourToRGB(style
.GetBackgroundColour()); 
2111 #endif // wxUSE_RICHEDIT2 
2113     // do format the selection 
2114     bool ok 
= ::SendMessage(GetHwnd(), EM_SETCHARFORMAT
, 
2115                             SCF_SELECTION
, (LPARAM
)&cf
) != 0; 
2118         wxLogDebug(_T("SendMessage(EM_SETCHARFORMAT, SCF_SELECTION) failed")); 
2121     // now do the paragraph formatting 
2124     // we can't use PARAFORMAT2 with RichEdit 1.0, so pretend it is a simple 
2125     // PARAFORMAT in that case 
2127     if ( m_verRichEdit 
== 1 ) 
2129         // this is the only thing the control is going to grok 
2130         pf
.cbSize 
= sizeof(PARAFORMAT
); 
2135         // PARAFORMAT or PARAFORMAT2 
2136         pf
.cbSize 
= sizeof(pf
); 
2139     if (style
.HasAlignment()) 
2141         pf
.dwMask 
|= PFM_ALIGNMENT
; 
2142         if (style
.GetAlignment() == wxTEXT_ALIGNMENT_RIGHT
) 
2143             pf
.wAlignment 
= PFA_RIGHT
; 
2144         else if (style
.GetAlignment() == wxTEXT_ALIGNMENT_CENTRE
) 
2145             pf
.wAlignment 
= PFA_CENTER
; 
2146         else if (style
.GetAlignment() == wxTEXT_ALIGNMENT_JUSTIFIED
) 
2147             pf
.wAlignment 
= PFA_JUSTIFY
; 
2149             pf
.wAlignment 
= PFA_LEFT
; 
2152     if (style
.HasLeftIndent()) 
2154         pf
.dwMask 
|= PFM_STARTINDENT
; 
2156         // Convert from 1/10 mm to TWIPS 
2157         pf
.dxStartIndent 
= (int) (((double) style
.GetLeftIndent()) * mm2twips 
/ 10.0) ; 
2159         // TODO: do we need to specify dxOffset? 
2162     if (style
.HasRightIndent()) 
2164         pf
.dwMask 
|= PFM_RIGHTINDENT
; 
2166         // Convert from 1/10 mm to TWIPS 
2167         pf
.dxRightIndent 
= (int) (((double) style
.GetRightIndent()) * mm2twips 
/ 10.0) ; 
2170     if (style
.HasTabs()) 
2172         pf
.dwMask 
|= PFM_TABSTOPS
; 
2174         const wxArrayInt
& tabs 
= style
.GetTabs(); 
2176         pf
.cTabCount 
= wxMin(tabs
.GetCount(), MAX_TAB_STOPS
); 
2178         for (i 
= 0; i 
< (size_t) pf
.cTabCount
; i
++) 
2180             // Convert from 1/10 mm to TWIPS 
2181             pf
.rgxTabs
[i
] = (int) (((double) tabs
[i
]) * mm2twips 
/ 10.0) ; 
2187         // do format the selection 
2188         bool ok 
= ::SendMessage(GetHwnd(), EM_SETPARAFORMAT
, 
2189             0, (LPARAM
) &pf
) != 0; 
2192             wxLogDebug(_T("SendMessage(EM_SETPARAFORMAT, 0) failed")); 
2198         // restore the original selection 
2199         DoSetSelection(startOld
, endOld
, FALSE
); 
2205 bool wxTextCtrl::SetDefaultStyle(const wxTextAttr
& style
) 
2207     if ( !wxTextCtrlBase::SetDefaultStyle(style
) ) 
2210     // we have to do this or the style wouldn't apply for the text typed by the 
2212     long posLast 
= GetLastPosition(); 
2213     SetStyle(posLast
, posLast
, m_defaultStyle
); 
2218 bool wxTextCtrl::GetStyle(long position
, wxTextAttr
& style
) 
2222         // can't do it with normal text control 
2226     // initialize CHARFORMAT struct 
2235     // we can't use CHARFORMAT2 with RichEdit 1.0, so pretend it is a simple 
2236     // CHARFORMAT in that case 
2238     if ( m_verRichEdit 
== 1 ) 
2240         // this is the only thing the control is going to grok 
2241         cf
.cbSize 
= sizeof(CHARFORMAT
); 
2246         // CHARFORMAT or CHARFORMAT2 
2247         cf
.cbSize 
= sizeof(cf
); 
2249     // we can only change the format of the selection, so select the range we 
2250     // want and restore the old selection later 
2251     long startOld
, endOld
; 
2252     GetSelection(&startOld
, &endOld
); 
2254     // but do we really have to change the selection? 
2255     bool changeSel 
= position 
!= startOld 
|| position 
!= endOld
; 
2259         DoSetSelection(position
, position
, FALSE 
/* don't scroll caret into view */); 
2262     // get the selection formatting 
2263     (void) ::SendMessage(GetHwnd(), EM_GETCHARFORMAT
, 
2264                             SCF_SELECTION
, (LPARAM
)&cf
) ; 
2267     lf
.lfHeight 
= cf
.yHeight
; 
2269     lf
.lfCharSet 
= ANSI_CHARSET
; // FIXME: how to get correct charset? 
2270     lf
.lfClipPrecision 
= 0; 
2271     lf
.lfEscapement 
= 0; 
2272     wxStrcpy(lf
.lfFaceName
, cf
.szFaceName
); 
2273     if (cf
.dwEffects 
& CFE_ITALIC
) 
2275     lf
.lfOrientation 
= 0; 
2276     lf
.lfPitchAndFamily 
= cf
.bPitchAndFamily
; 
2278     if (cf
.dwEffects 
& CFE_STRIKEOUT
) 
2279         lf
.lfStrikeOut 
= TRUE
; 
2280     if (cf
.dwEffects 
& CFE_UNDERLINE
) 
2281         lf
.lfUnderline 
= TRUE
; 
2282     if (cf
.dwEffects 
& CFE_BOLD
) 
2283         lf
.lfWeight 
= FW_BOLD
; 
2285     wxFont font 
= wxCreateFontFromLogFont(& lf
); 
2288         style
.SetFont(font
); 
2290     style
.SetTextColour(wxColour(cf
.crTextColor
)); 
2293     if ( m_verRichEdit 
!= 1 ) 
2295         // cf.dwMask |= CFM_BACKCOLOR; 
2296         style
.SetBackgroundColour(wxColour(cf
.crBackColor
)); 
2298 #endif // wxUSE_RICHEDIT2 
2300     // now get the paragraph formatting 
2303     // we can't use PARAFORMAT2 with RichEdit 1.0, so pretend it is a simple 
2304     // PARAFORMAT in that case 
2306     if ( m_verRichEdit 
== 1 ) 
2308         // this is the only thing the control is going to grok 
2309         pf
.cbSize 
= sizeof(PARAFORMAT
); 
2314         // PARAFORMAT or PARAFORMAT2 
2315         pf
.cbSize 
= sizeof(pf
); 
2318     // do format the selection 
2319     (void) ::SendMessage(GetHwnd(), EM_GETPARAFORMAT
, 0, (LPARAM
) &pf
) ; 
2321     style
.SetLeftIndent( (int) ((double) pf
.dxStartIndent 
* twips2mm 
* 10.0) ); 
2322     style
.SetRightIndent( (int) ((double) pf
.dxRightIndent 
* twips2mm 
* 10.0) ); 
2324     if (pf
.wAlignment 
== PFA_CENTER
) 
2325         style
.SetAlignment(wxTEXT_ALIGNMENT_CENTRE
); 
2326     else if (pf
.wAlignment 
== PFA_RIGHT
) 
2327         style
.SetAlignment(wxTEXT_ALIGNMENT_RIGHT
); 
2328     else if (pf
.wAlignment 
== PFA_JUSTIFY
) 
2329         style
.SetAlignment(wxTEXT_ALIGNMENT_JUSTIFIED
); 
2331         style
.SetAlignment(wxTEXT_ALIGNMENT_LEFT
); 
2333     wxArrayInt tabStops
; 
2335     for (i 
= 0; i 
< (size_t) pf
.cTabCount
; i
++) 
2337         tabStops
[i
] = (int) ((double) (pf
.rgxTabs
[i
] & 0xFFFF) * twips2mm 
* 10.0) ; 
2342         // restore the original selection 
2343         DoSetSelection(startOld
, endOld
, FALSE
); 
2351 // ---------------------------------------------------------------------------- 
2353 // ---------------------------------------------------------------------------- 
2355 bool wxRichEditModule::OnInit() 
2357     // don't do anything - we will load it when needed 
2361 void wxRichEditModule::OnExit() 
2363     for ( size_t i 
= 0; i 
< WXSIZEOF(ms_hRichEdit
); i
++ ) 
2365         if ( ms_hRichEdit
[i
] ) 
2367             ::FreeLibrary(ms_hRichEdit
[i
]); 
2368             ms_hRichEdit
[i
] = NULL
; 
2374 bool wxRichEditModule::Load(int version
) 
2376     // we don't support loading richedit 3.0 as I don't know how to distinguish 
2377     // it from 2.0 anyhow 
2378     wxCHECK_MSG( version 
== 1 || version 
== 2, FALSE
, 
2379                  _T("incorrect richedit control version requested") ); 
2381     // make it the index in the array 
2384     if ( ms_hRichEdit
[version
] == (HINSTANCE
)-1 ) 
2386         // we had already tried to load it and failed 
2390     if ( ms_hRichEdit
[version
] ) 
2392         // we've already got this one 
2396     wxString dllname 
= version 
? _T("riched20") : _T("riched32"); 
2397     dllname 
+= _T(".dll"); 
2399     ms_hRichEdit
[version
] = ::LoadLibrary(dllname
); 
2401     if ( !ms_hRichEdit
[version
] ) 
2403         wxLogSysError(_("Could not load Rich Edit DLL '%s'"), dllname
.c_str()); 
2405         ms_hRichEdit
[version
] = (HINSTANCE
)-1; 
2413 #endif // wxUSE_RICHEDIT 
2415 #endif // wxUSE_TEXTCTRL