Está escrito en C, usa el control RICHEDIT y ofrece la funcionalidad minima que necesito. Puedo proporcionar el código fuente si te puede resultar util.
Estaba interesado en revisar cuanta funcionalidad puede ofrecer RichEdit como un editor de código fuente proporcionado por el propio Windows. Recordaba que el coloreado de syntaxis en el RichEdit era lento para ficheros grandes y que ese era su principal problema. Asi que decidí investigarlo un poco más. La primera información interesante que encontré fué esta:
http://bcbjournal.org/articles/vol3/9910/Faster_rich_edit_syntax_highlighting.htm
Su autor usa C++ Builder y ha encontrado algunas maneras de optimizarlo. Asi que decidí crear un ejemplo auto contenido en lenguaje C para probar como de rápido sus optimizaciones son. Puedes construirlo facilmente usando Borland C:
go.bat
- Code: Select all Expand view
- set path=c:\bcc582\bin
bcc32 -W test.c
if errorlevel 0 test
test.c // Editor basado en RichEdit con coloreado automático de sintaxis
- Code: Select all Expand view
- #include <windows.h>
#include <richedit.h>
#include <stdio.h>
typedef struct
{
char * txt;
long len;
FILE * out;
} COOKIE;
#define CLR_YELLOW RGB( 255, 255, 0 )
#define CLR_HCYAN RGB( 0, 255, 255 )
#define CLR_HGREEN RGB( 0, 255, 0 )
#define CLR_WHITE RGB( 255, 255, 255 )
void ParseAllText( HWND hRichEdit )
{
LONG pos = 0, start = 1;
CHARFORMAT cf;
TEXTRANGE tr;
char buffer[ 256 ];
int eventMask = SendMessage( hRichEdit, EM_SETEVENTMASK, 0, 0 );
SendMessage( hRichEdit, WM_SETREDRAW, FALSE, 0 );
memset( &cf, 0, sizeof( cf ) );
cf.cbSize = sizeof( cf );
cf.dwMask = CFM_COLOR;
while( pos != start )
{
start = pos;
pos = SendMessage( hRichEdit, EM_FINDWORDBREAK, WB_MOVEWORDRIGHT, pos );
SendMessage( hRichEdit, EM_SETSEL, start, pos );
tr.chrg.cpMin = start;
tr.chrg.cpMax = pos;
tr.lpstrText = buffer; // malloc( pos - start + 1 + 1 );
SendMessage( hRichEdit, EM_GETTEXTRANGE, 0, ( LPARAM ) &tr );
if( strstr( "# define ifdef ifndef endif pragma include ", tr.lpstrText ) )
{
cf.crTextColor = CLR_YELLOW;
SendMessage( hRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, ( LPARAM ) &cf );
}
else if( strstr( "local static extern public private nil for next if else endif do case endcase ", tr.lpstrText ) )
{
cf.crTextColor = CLR_HCYAN;
SendMessage( hRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, ( LPARAM ) &cf );
}
else if( strstr( "function CLASS DATA INIT METHOD INLINE VIRTUAL SETGET ENDCLASS procedure return ", tr.lpstrText ) )
{
cf.crTextColor = CLR_HGREEN;
SendMessage( hRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, ( LPARAM ) &cf );
}
else if( strstr( "= + - ++ -- += -= *= /= / * < > <= >= % $ | ! ^ @ {} {}, { } {| [ ] ]: ( ) (- ), ): ); ),; () (): :: := != == += -= . , ; ,; .,; ", tr.lpstrText ) )
{
cf.crTextColor = CLR_WHITE;
SendMessage( hRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, ( LPARAM ) &cf );
}
// free( tr.lpstrText );
}
SendMessage( hRichEdit, WM_SETREDRAW, TRUE, 0 );
SendMessage( hRichEdit, EM_SETEVENTMASK, 0, eventMask );
InvalidateRect( hRichEdit, 0, TRUE );
}
#pragma argsused
DWORD CALLBACK StreamIn( DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG FAR *pcb )
{
COOKIE * Cookie = ( COOKIE * ) dwCookie;
if( cb > Cookie->len )
cb = Cookie->len;
if( cb > 0 )
{
memcpy( ( char * ) pbBuff, Cookie -> txt, cb );
Cookie->txt += cb;
Cookie->len -= cb;
}
* pcb = cb;
return 0;
}
BOOL LoadText( HWND hRichEdit, const char * FileName )
{
FILE * in = fopen( FileName, "rb" );
int len;
if( ! in )
return FALSE;
fseek( in, 0, SEEK_END );
len = ftell( in );
fseek( in, 0, SEEK_SET );
if( len > 0 )
{
COOKIE Cookie;
EDITSTREAM es;
char * txt = malloc( len + 1 );
fread( txt, 1, len, in );
Cookie.txt = txt;
Cookie.len = len;
es.dwCookie = ( DWORD ) &Cookie;
es.pfnCallback = StreamIn;
SendMessage( hRichEdit, EM_STREAMIN, SF_TEXT, ( LPARAM ) &es );
free( txt );
}
fclose( in );
return TRUE;
}
LRESULT WINAPI ParentWindowProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
static HWND hRichEdit;
static HFONT hFont;
switch( msg )
{
case WM_CREATE:
{
RECT r;
GetClientRect( hWnd, &r );
hRichEdit = CreateWindow( "RICHEDIT", "",
WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_MULTILINE | ES_SUNKEN,
0, 30, r.right - r.left, r.bottom - r.top - 50,
hWnd, NULL, NULL, NULL );
hFont = CreateFont( 18, 0, 0, 0, 0, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Courier New" );
SendMessage( hRichEdit, WM_SETFONT, ( WPARAM ) hFont, 0 );
LoadText( hRichEdit, "window.prg" );
SendMessage( hRichEdit, EM_EXLIMITTEXT, 0, 0xFFFFFFF );
ParseAllText( hRichEdit );
SetFocus( hRichEdit );
}
break;
case WM_CLOSE:
DeleteObject( hFont );
DestroyWindow( hWnd );
break;
case WM_LBUTTONDOWN:
break;
case WM_SIZE:
MoveWindow( hRichEdit, 0, 30, LOWORD( lParam ), HIWORD( lParam ) - 50, FALSE );
break;
case WM_DESTROY:
PostQuitMessage( 0 );
break;
}
return DefWindowProc( hWnd, msg, wParam, lParam );
}
int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE prev, LPSTR cmdline, int show )
{
WNDCLASS cls;
HWND hWnd;
MSG msg;
HINSTANCE hDll = LoadLibrary( "riched32" );
cls.style = CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS;
cls.lpfnWndProc = ParentWindowProc;
cls.cbClsExtra = 0;
cls.cbWndExtra = 0;
cls.hInstance = hInstance;
cls.hIcon = LoadIcon( 0, IDI_APPLICATION );
cls.hCursor = LoadCursor( 0, IDC_ARROW );
cls.hbrBackground = GetStockObject( WHITE_BRUSH );
cls.lpszMenuName = 0;
cls.lpszClassName = "parentclass";
if( ! RegisterClass( &cls ) )
return FALSE;
hWnd = CreateWindow( "parentClass", "RichEdit syntax highlight", WS_OVERLAPPEDWINDOW ,
100, 100, 1100, 600, 0, NULL, hInstance, 0 );
ShowWindow( hWnd, SW_MAXIMIZE );
UpdateWindow( hWnd );
while( GetMessage( &msg, 0, 0, 0 ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
FreeLibrary( hDll );
return 0;
}
Nada de Harbour, ni FWH, puro lenguaje C para probar su velocidad, pero desafortunadamente aún lento para grandes ficheros PRG. Así que decidí seguir googleando y encontré esto:
http://win32assembly.online.fr/tut35.html
Puede asustar en un principio pues está desarrollado en ensamblador (ouch!) pero su autor tiene una interesante idea: hacer "subclass" del control RichEdit y hacer el coloreado él mismo. Bien, decidí pasarlo desde ensamblador a lenguaje C para probarlo. Algunas partes las he implementado yo una vez entendí su intención. Aqui está:
fresh.c // Se me ocurrió este nombre como acrónimo de "Free RichEdit Editor Syntax Highlighted"
- Code: Select all Expand view
- #pragma resource "fresh.res"
#include <windows.h>
#include <richedit.h>
#include <stdio.h>
typedef struct
{
DWORD WordLen; // the length of the word: used as a quick comparison
char * pszWord; // pointer to the word
COLORREF * pColor; // point to the dword that contains the color used to hilite the word
void * NextLink; // point to the next WORDINFO structure
} WORDINFO;
#define IDR_MAINMENU 101
#define IDM_OPEN 40001
#define IDM_SAVE 40002
#define IDM_CLOSE 40003
#define IDM_SAVEAS 40004
#define IDM_EXIT 40005
#define IDM_COPY 40006
#define IDM_CUT 40007
#define IDM_PASTE 40008
#define IDM_DELETE 40009
#define IDM_SELECTALL 40010
#define IDM_OPTION 40011
#define IDM_UNDO 40012
#define IDM_REDO 40013
#define IDD_OPTIONDLG 101
#define IDC_BACKCOLORBOX 1000
#define IDC_TEXTCOLORBOX 1001
#define IDR_MAINACCEL 105
#define IDD_FINDDLG 102
#define IDD_GOTODLG 103
#define IDD_REPLACEDLG 104
#define IDC_FINDEDIT 1000
#define IDC_MATCHCASE 1001
#define IDC_REPLACEEDIT 1001
#define IDC_WHOLEWORD 1002
#define IDC_DOWN 1003
#define IDC_UP 1004
#define IDC_LINENO 1005
#define IDM_FIND 40014
#define IDM_FINDNEXT 40015
#define IDM_REPLACE 40016
#define IDM_GOTOLINE 40017
#define IDM_FINDPREV 40018
#define RichEditID 300
#define CLR_HRED RGB( 255, 0, 0 )
#define CLR_HGREEN RGB( 0, 255, 0 )
#define CLR_HBLUE RGB( 0, 0, 255 )
#define CLR_BLACK RGB( 0, 0, 0 )
#define CLR_WHITE RGB( 255, 255, 255 )
char FindBuffer[ 256 ];
char ReplaceBuffer[ 256 ];
HWND hWndRichEdit;
WNDPROC OldWndProc;
int RichEditVersion;
COLORREF BackGroundColor = CLR_WHITE;
COLORREF TextColor = CLR_BLACK;
COLORREF CommentColor = CLR_HBLUE;
COLORREF ColorArray[ 10 ] = { CLR_HRED, CLR_HGREEN, CLR_HBLUE, CLR_WHITE, CLR_BLACK,
CLR_BLACK, CLR_BLACK, CLR_BLACK, CLR_BLACK, CLR_BLACK };
BOOL FileOpened = FALSE;
char * szFileFilter = "PRG source code (*.prg)\0*.prg\0All Files (*.*)\0*.*\0";
char FileName[ 256 ];
char AlternateFileName[ 256 ];
HANDLE hSearch = NULL;
char * OpenFileFail = "Cannot open the file";
char * AppName = "Fresh 1.0";
char * WordFileName = "wordfile.txt";
FINDTEXTEX findtext;
char * WannaSave = "The data in the control is modified. Want to save it ?";
HFONT hFont;
WORDINFO SyntaxArray[ 256 ];
void SetColor( void )
{
CHARFORMAT cfm;
SendMessage( hWndRichEdit, EM_SETBKGNDCOLOR, 0, BackGroundColor );
memset( &cfm, 0, sizeof( cfm ) );
cfm.cbSize = sizeof( cfm );
cfm.dwMask = CFM_COLOR;
cfm.crTextColor = TextColor;
SendMessage( hWndRichEdit, EM_SETCHARFORMAT, SCF_ALL, ( LPARAM ) &cfm );
}
void CenterWindow( HWND hWnd )
{
RECT rWnd, rDsk;
LONG Left, Top, Width, Height;
GetWindowRect( hWnd, &rWnd );
GetWindowRect( GetDesktopWindow(), &rDsk );
Width = rWnd.right - rWnd.left;
Height = rWnd.bottom - rWnd.top;
Left = ( rDsk.right / 2 ) - ( Width / 2 );
Top = ( rDsk.bottom / 2 ) - ( Height / 2 );
MoveWindow( hWnd, Left, Top, Width, Height, FALSE );
}
void ParseBuffer( char * pszTokens, DWORD dwGroup )
{
char buffer[ 128 ];
char * pStart = pszTokens;
// BOOL InProgress = FALSE;
BOOL bFound = FALSE;
WORDINFO * pWordInfo;
if( ! strlen( pszTokens ) )
return;
CharLower( pszTokens );
while( * pszTokens )
{
if( ( ( * pszTokens ) == ' ' ) || ( ( * pszTokens ) == 9 ) ) // tab
bFound = TRUE;
if( * pszTokens && bFound )
{
pWordInfo = SyntaxArray + pStart[ 0 ];
if( SyntaxArray[ pStart[ 0 ] ].WordLen )
{
while( pWordInfo->NextLink )
pWordInfo = pWordInfo->NextLink;
pWordInfo->NextLink = ( WORDINFO * ) malloc( sizeof( WORDINFO ) );
memset( ( void * ) pWordInfo->NextLink, 0, sizeof( WORDINFO ) );
}
pWordInfo->WordLen = pszTokens - pStart;
pWordInfo->pszWord = ( char * ) malloc( pWordInfo->WordLen + 1 );
strncpy( pWordInfo->pszWord, pStart, pWordInfo->WordLen );
pWordInfo->pszWord[ pWordInfo->WordLen ] = 0;
pWordInfo->pColor = ColorArray + dwGroup - 1;
pWordInfo->NextLink = NULL;
bFound = FALSE;
// MessageBox( 0, pWordInfo->pszWord, "token", 0 );
while( ( ( ( * pszTokens ) == ' ' ) || ( ( * pszTokens ) == 9 ) ) && ( * pszTokens ) )
pszTokens++;
pStart = pszTokens;
}
if( * pszTokens )
pszTokens++;
}
}
void FillHiliteInfo( void )
{
char filename[ 1024 ];
char buffer[ 1024 ];
char * pTemp;
RtlZeroMemory( SyntaxArray, sizeof( SyntaxArray ) );
GetModuleFileName( GetModuleHandle( NULL ), filename, sizeof( filename ) );
pTemp = filename + lstrlen( filename );
while( ( pTemp > filename ) && ( ( * pTemp ) != '\\' ) )
pTemp--;
* ++pTemp = 0;
lstrcat( pTemp, WordFileName );
if( GetFileAttributes( filename ) != INVALID_FILE_ATTRIBUTES )
{
if( GetPrivateProfileString( "ASSEMBLY", "C1", NULL, buffer, sizeof( buffer ), filename ) )
ParseBuffer( buffer, 1 );
if( GetPrivateProfileString( "ASSEMBLY", "C2", NULL, buffer, sizeof( buffer ), filename ) )
ParseBuffer( buffer, 2 );
if( GetPrivateProfileString( "ASSEMBLY", "C3", NULL, buffer, sizeof( buffer ), filename ) )
ParseBuffer( buffer, 3 );
if( GetPrivateProfileString( "ASSEMBLY", "C4", NULL, buffer, sizeof( buffer ), filename ) )
ParseBuffer( buffer, 4 );
if( GetPrivateProfileString( "ASSEMBLY", "C5", NULL, buffer, sizeof( buffer ), filename ) )
ParseBuffer( buffer, 5 );
if( GetPrivateProfileString( "ASSEMBLY", "C6", NULL, buffer, sizeof( buffer ), filename ) )
ParseBuffer( buffer, 6 );
if( GetPrivateProfileString( "ASSEMBLY", "C7", NULL, buffer, sizeof( buffer ), filename ) )
ParseBuffer( buffer, 7 );
if( GetPrivateProfileString( "ASSEMBLY", "C8", NULL, buffer, sizeof( buffer ), filename ) )
ParseBuffer( buffer, 8 );
if( GetPrivateProfileString( "ASSEMBLY", "C9", NULL, buffer, sizeof( buffer ), filename ) )
ParseBuffer( buffer, 9 );
if( GetPrivateProfileString( "ASSEMBLY", "C10", NULL, buffer, sizeof( buffer ), filename ) )
ParseBuffer( buffer, 10 );
}
else
MessageBox( 0, "wordfile.txt does not exist", "Attention", MB_ICONINFORMATION );
}
BOOL CheckModifyState( HWND hWnd )
{
int nResult;
if( SendMessage( hWndRichEdit, EM_GETMODIFY, 0, 0 ) )
if( ( nResult = MessageBox( hWnd, WannaSave, AppName, MB_YESNOCANCEL ) ) == IDYES )
SendMessage( hWnd, WM_COMMAND, IDM_SAVE, 0 );
else if( nResult == IDCANCEL )
return FALSE;
return TRUE;
}
void PrepareEditMenu( HMENU hSubMenu )
{
CHARRANGE chrg;
if( ! SendMessage( hWndRichEdit, EM_CANPASTE, CF_TEXT, 0 ) )
EnableMenuItem( hSubMenu, IDM_PASTE, MF_GRAYED );
else
EnableMenuItem( hSubMenu, IDM_PASTE, MF_ENABLED );
if( ! SendMessage( hWndRichEdit, EM_CANUNDO, 0, 0 ) )
EnableMenuItem( hSubMenu, IDM_UNDO, MF_GRAYED );
else
EnableMenuItem( hSubMenu, IDM_UNDO, MF_ENABLED );
if( ! SendMessage( hWndRichEdit, EM_CANREDO, 0, 0 ) )
EnableMenuItem( hSubMenu, IDM_REDO, MF_GRAYED );
else
EnableMenuItem( hSubMenu, IDM_REDO, MF_ENABLED );
chrg.cpMin = SendMessage( hWndRichEdit, EM_EXGETSEL, 0, ( LPARAM ) &chrg );
if( chrg.cpMin == chrg.cpMax )
{
EnableMenuItem( hSubMenu, IDM_COPY, MF_GRAYED );
EnableMenuItem( hSubMenu, IDM_CUT, MF_GRAYED );
EnableMenuItem( hSubMenu, IDM_DELETE, MF_GRAYED );
}
else
{
EnableMenuItem( hSubMenu, IDM_COPY, MF_ENABLED );
EnableMenuItem( hSubMenu, IDM_CUT, MF_ENABLED );
EnableMenuItem( hSubMenu, IDM_DELETE, MF_ENABLED );
}
}
#pragma argsused
static INT_PTR CALLBACK OptionProc( HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam )
{
switch( wMsg )
{
case WM_INITDIALOG:
CenterWindow( hDlg );
return TRUE;
case WM_COMMAND:
switch( wParam )
{
case IDOK:
EndDialog( hDlg, IDOK );
break;
case IDCANCEL:
EndDialog( hDlg, IDCANCEL );
break;
}
break;
}
return FALSE;
}
#pragma argsused
static INT_PTR CALLBACK SearchProc( HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam )
{
switch( wMsg )
{
case WM_INITDIALOG:
CenterWindow( hDlg );
return TRUE;
case WM_COMMAND:
switch( wParam )
{
case IDOK:
EndDialog( hDlg, IDOK );
break;
case IDCANCEL:
EndDialog( hDlg, IDCANCEL );
break;
}
break;
}
return FALSE;
}
#pragma argsused
static INT_PTR CALLBACK ReplaceProc( HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam )
{
switch( wMsg )
{
case WM_INITDIALOG:
CenterWindow( hDlg );
return TRUE;
case WM_COMMAND:
switch( wParam )
{
case IDOK:
EndDialog( hDlg, IDOK );
break;
case IDCANCEL:
EndDialog( hDlg, IDCANCEL );
break;
}
break;
}
return FALSE;
}
#pragma argsused
static INT_PTR CALLBACK GoToProc( HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam )
{
switch( wMsg )
{
case WM_INITDIALOG:
CenterWindow( hDlg );
return TRUE;
case WM_COMMAND:
switch( wParam )
{
case IDOK:
EndDialog( hDlg, IDOK );
break;
case IDCANCEL:
EndDialog( hDlg, IDCANCEL );
break;
}
break;
}
return FALSE;
}
LRESULT WINAPI NewRichEditProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
HDC hDC;
HFONT hOldFont;
RECT rect;
TEXTRANGE txtrange;
char buffer[ 1024 * 10 ];
HRGN hRgn, hOldRgn;
POINT pt;
DWORD nChar, nLine, dwPos;
WORDINFO * pWordInfo;
BOOL bExit;
switch( msg )
{
case WM_PAINT:
HideCaret( hWnd );
CallWindowProc( OldWndProc, hWnd, msg, wParam, lParam );
hDC = GetDC( hWnd );
SetBkMode( hDC, TRANSPARENT );
hOldFont = SelectObject( hDC, hFont );
SendMessage( hWnd, EM_GETRECT, 0, ( LPARAM ) &rect );
nChar = SendMessage( hWnd, EM_CHARFROMPOS, 0, ( LPARAM ) &rect );
nLine = SendMessage( hWnd, EM_LINEFROMCHAR, nChar, 0 );
txtrange.chrg.cpMin = SendMessage( hWnd, EM_LINEINDEX, nLine, 0 );
txtrange.chrg.cpMax = SendMessage( hWnd, EM_CHARFROMPOS, 0, ( LPARAM ) &rect.right );
hRgn = CreateRectRgn( rect.left, rect.top, rect.right, rect.bottom );
hOldRgn = SelectObject( hDC, hRgn );
txtrange.lpstrText = buffer;
if( SendMessage( hWnd, EM_GETTEXTRANGE, 0, ( LPARAM ) &txtrange ) )
{
char * pPos = buffer;
char * pStart = buffer;
char * pToken;
while( * pPos )
{
if( * pPos == ' ' || * pPos == 9 || * pPos == 0xD || * pPos == 0xA )
{
pToken = ( char * ) malloc( pPos - pStart + 1 );
strncpy( pToken, pStart, pPos - pStart );
pToken[ pPos - pStart ] = 0;
// MessageBox( 0, pToken, "token", 0 );
if( RichEditVersion == 3 )
SendMessage( hWnd, EM_POSFROMCHAR, ( WPARAM ) &rect, ( LPARAM ) ( pStart - buffer ) + nChar );
else
{
dwPos = SendMessage( hWnd, EM_POSFROMCHAR, ( WPARAM ) pStart, 0 );
rect.left = LOWORD( dwPos );
rect.top = HIWORD( dwPos );
}
if( pToken[ 0 ] >= 'A' && pToken[ 0 ] <= 'Z' )
pWordInfo = SyntaxArray + pToken[ 0 ] - 'A' + 'a';
else
pWordInfo = SyntaxArray + pToken[ 0 ];
bExit = FALSE;
while( pWordInfo->WordLen && ! bExit )
{
if( strlen( pToken ) == pWordInfo->WordLen &&
lstrcmpi( pWordInfo->pszWord, pToken ) == 0 )
{
bExit = TRUE;
SetTextColor( hDC, * pWordInfo->pColor );
DrawText( hDC, pToken, -1, &rect, 0 );
}
else
{
if( pWordInfo->NextLink )
pWordInfo= pWordInfo->NextLink;
else
bExit = TRUE;
}
}
free( pToken );
while( * pPos == ' ' || * pPos == 9 || * pPos == 0xD || * pPos == 0xA && * pPos )
pPos++;
if( ! * pPos )
pPos++;
pStart = pPos;
}
pPos++;
}
}
SelectObject( hDC, hOldRgn );
DeleteObject( hRgn );
SelectObject( hDC, hOldFont );
ReleaseDC( hWnd, hDC );
ShowCaret( hWnd );
return 0;
case WM_CLOSE:
SetWindowLong( hWnd, GWL_WNDPROC, ( LONG ) OldWndProc );
break;
}
return CallWindowProc( OldWndProc, hWnd, msg, wParam, lParam );
}
DWORD CALLBACK StreamInProc( DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG FAR * pcb )
{
ReadFile( ( HANDLE ) dwCookie, ( LPVOID ) pbBuff, ( DWORD ) cb, ( LPDWORD ) pcb, 0 );
return 0;
}
DWORD CALLBACK StreamOutProc( DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG FAR * pcb )
{
WriteFile( ( HANDLE ) dwCookie, ( LPVOID ) pbBuff, ( DWORD ) cb, ( LPDWORD ) pcb, 0 );
return 0;
}
LRESULT WINAPI WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
RECT rect;
OPENFILENAME ofn;
char buffer[ 256 ];
EDITSTREAM editstream;
FILE * hFile;
HMENU hPopup;
POINT pt;
CHARRANGE chrg;
switch( msg )
{
case WM_CREATE:
GetClientRect( hWnd, &rect );
hWndRichEdit = CreateWindowEx( WS_EX_CLIENTEDGE, "RichEdit20A", 0,
WS_CHILD | WS_VISIBLE | ES_MULTILINE | WS_VSCROLL |
WS_HSCROLL | ES_NOHIDESEL, 0, 0,
rect.right - rect.left, rect.bottom - rect.top,
hWnd, ( HMENU ) RichEditID, GetModuleHandle( NULL ), 0 );
SendMessage( hWndRichEdit, EM_SETTYPOGRAPHYOPTIONS, TO_SIMPLELINEBREAK, TO_SIMPLELINEBREAK );
if( ! SendMessage( hWndRichEdit, EM_GETTYPOGRAPHYOPTIONS, 1, 1 ) )
RichEditVersion = 2;
else
RichEditVersion = 3;
SendMessage( hWndRichEdit, EM_SETEDITSTYLE, SES_EMULATESYSEDIT, SES_EMULATESYSEDIT );
OldWndProc = ( WNDPROC ) SetWindowLong( hWndRichEdit, GWL_WNDPROC, ( LONG ) NewRichEditProc );
SendMessage( hWndRichEdit, EM_LIMITTEXT, -1, 0 );
// SetColor();
SendMessage( hWndRichEdit, EM_SETMODIFY, FALSE, 0 );
SendMessage( hWndRichEdit, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS );
SendMessage( hWndRichEdit, EM_EMPTYUNDOBUFFER, 0, 0 );
hFont = CreateFont( 18, 0, 0, 0, 0, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Courier New" );
SendMessage( hWndRichEdit, WM_SETFONT, ( WPARAM ) hFont, 0 );
FillHiliteInfo();
SetFocus( hWndRichEdit );
break;
case WM_NOTIFY:
if( ( ( NMHDR * ) lParam )->code == EN_MSGFILTER )
{
if( ( ( MSGFILTER * ) lParam )->msg == WM_RBUTTONDOWN )
{
hPopup = GetSubMenu( GetMenu( hWnd ), 1 );
PrepareEditMenu( hPopup );
pt.x = LOWORD( lParam );
pt.y = HIWORD( lParam );
ClientToScreen( hWnd, &pt );
TrackPopupMenu( hPopup, TPM_LEFTALIGN | TPM_BOTTOMALIGN, pt.x, pt.y,
NULL, hWnd, NULL );
}
}
break;
case WM_INITMENUPOPUP:
if( lParam == 0 )
{
if( FileOpened )
{
EnableMenuItem( ( HMENU ) wParam, IDM_OPEN, MF_GRAYED );
EnableMenuItem( ( HMENU ) wParam, IDM_CLOSE, MF_ENABLED );
EnableMenuItem( ( HMENU ) wParam, IDM_SAVE, MF_ENABLED );
EnableMenuItem( ( HMENU ) wParam, IDM_SAVEAS, MF_ENABLED );
}
else
{
EnableMenuItem( ( HMENU ) wParam, IDM_OPEN, MF_ENABLED );
EnableMenuItem( ( HMENU ) wParam, IDM_CLOSE, MF_GRAYED );
EnableMenuItem( ( HMENU ) wParam, IDM_SAVE, MF_GRAYED );
EnableMenuItem( ( HMENU ) wParam, IDM_SAVEAS, MF_GRAYED );
}
}
else if( lParam == 1 )
PrepareEditMenu( ( HMENU ) wParam );
else if( lParam == 2 )
{
if( FileOpened )
{
EnableMenuItem( ( HMENU ) wParam, IDM_FIND, MF_ENABLED );
EnableMenuItem( ( HMENU ) wParam, IDM_FINDNEXT, MF_ENABLED );
EnableMenuItem( ( HMENU ) wParam, IDM_FINDPREV, MF_ENABLED );
EnableMenuItem( ( HMENU ) wParam, IDM_REPLACE, MF_ENABLED );
EnableMenuItem( ( HMENU ) wParam, IDM_GOTOLINE, MF_ENABLED );
}
else
{
EnableMenuItem( ( HMENU ) wParam, IDM_FIND, MF_GRAYED );
EnableMenuItem( ( HMENU ) wParam, IDM_FINDNEXT, MF_GRAYED );
EnableMenuItem( ( HMENU ) wParam, IDM_FINDPREV, MF_GRAYED );
EnableMenuItem( ( HMENU ) wParam, IDM_REPLACE, MF_GRAYED );
EnableMenuItem( ( HMENU ) wParam, IDM_GOTOLINE, MF_GRAYED );
}
}
break;
case WM_COMMAND:
if( ! lParam ) // menu commands
{
switch( LOWORD( wParam ) )
{
case IDM_OPEN:
{
memset( &ofn, 0, sizeof( ofn ) );
ofn.lStructSize = sizeof( ofn );
ofn.hwndOwner = hWnd;
ofn.hInstance = GetModuleHandle( NULL );
ofn.lpstrFilter = szFileFilter;
FileName[ 0 ] = 0;
ofn.lpstrFile = FileName;
ofn.nMaxFile = sizeof( FileName );
ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST;
if( GetOpenFileName( &ofn ) )
{
if( ( hFile = CreateFile( FileName, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 ) ) !=
INVALID_HANDLE_VALUE )
{
editstream.dwCookie = ( DWORD_PTR ) hFile;
editstream.pfnCallback = StreamInProc;
SendMessage( hWndRichEdit, EM_STREAMIN, SF_TEXT, ( LPARAM ) &editstream );
SendMessage( hWndRichEdit, EM_SETMODIFY, FALSE, 0 );
CloseHandle( hFile );
FileOpened = TRUE;
}
else
MessageBox( hWnd, OpenFileFail, AppName, MB_OK | MB_ICONERROR );
}
}
break;
case IDM_CLOSE:
{
if( CheckModifyState( hWnd ) )
SetWindowText( hWndRichEdit, NULL );
FileOpened = FALSE;
}
break;
case IDM_SAVE:
{
if( ( hFile = CreateFile( FileName, GENERIC_WRITE, FILE_SHARE_READ, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0 ) ) !=
INVALID_HANDLE_VALUE )
{
editstream.dwCookie = ( DWORD_PTR ) hFile;
editstream.pfnCallback = StreamOutProc;
SendMessage( hWndRichEdit, EM_STREAMOUT, SF_TEXT, ( LPARAM ) &editstream );
SendMessage( hWndRichEdit, EM_SETMODIFY, FALSE, 0 );
CloseHandle( hFile );
}
else
MessageBox( hWnd, OpenFileFail, AppName, MB_OK | MB_ICONERROR );
}
break;
case IDM_COPY:
SendMessage( hWndRichEdit, WM_COPY, 0, 0 );
break;
case IDM_CUT:
SendMessage( hWndRichEdit, WM_CUT, 0, 0 );
break;
case IDM_PASTE:
SendMessage( hWndRichEdit, WM_PASTE, 0, 0 );
break;
case IDM_DELETE:
SendMessage( hWndRichEdit, EM_REPLACESEL, TRUE, 0 );
break;
case IDM_SELECTALL:
{
chrg.cpMin = 0;
chrg.cpMax = -1;
SendMessage( hWndRichEdit, EM_EXSETSEL, 0, ( LPARAM ) &chrg );
}
break;
case IDM_UNDO:
SendMessage( hWndRichEdit, EM_UNDO, 0, 0 );
break;
case IDM_REDO:
SendMessage( hWndRichEdit, EM_REDO, 0, 0 );
break;
case IDM_OPTION:
DialogBoxParam( GetModuleHandle( NULL ), ( LPCTSTR ) IDD_OPTIONDLG, hWnd, OptionProc, 0 );
break;
case IDM_SAVEAS:
{
RtlZeroMemory( &ofn, sizeof( ofn ) );
ofn.lStructSize = sizeof( ofn );
ofn.hwndOwner = hWnd;
ofn.hInstance = GetModuleHandle( NULL );
ofn.lpstrFilter = szFileFilter;
AlternateFileName[ 0 ] = 0;
ofn.lpstrFile = AlternateFileName;
ofn.nMaxFile = sizeof( AlternateFileName );
ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST;
if( GetSaveFileName( &ofn ) )
{
if( CreateFile( AlternateFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0 ) !=
INVALID_HANDLE_VALUE )
{
}
}
}
break;
case IDM_FIND:
if( ! hSearch )
CreateDialogParam( GetModuleHandle( NULL ), ( LPCTSTR ) IDD_FINDDLG, hWnd, SearchProc, 0 );
break;
case IDM_REPLACE:
if( ! hSearch )
CreateDialogParam( GetModuleHandle( NULL ), ( LPCTSTR ) IDD_REPLACEDLG, hWnd, ReplaceProc, 0 );
break;
case IDM_GOTOLINE:
if( ! hSearch )
CreateDialogParam( GetModuleHandle( NULL ), ( LPCTSTR ) IDD_GOTODLG, hWnd, GoToProc, 0 );
break;
case IDM_FINDNEXT:
if( lstrlen( FindBuffer ) )
{
SendMessage( hWndRichEdit, EM_EXGETSEL, 0, ( LPARAM ) &findtext.chrg );
if( findtext.chrg.cpMin != findtext.chrg.cpMax )
findtext.chrg.cpMin = findtext.chrg.cpMax;
findtext.chrg.cpMax = -1;
findtext.lpstrText = FindBuffer;
if( SendMessage( hWndRichEdit, EM_FINDTEXTEX, FR_DOWN, ( LPARAM ) &findtext ) != -1 )
SendMessage( hWndRichEdit, EM_EXSETSEL, 0, ( LPARAM ) &findtext.chrgText );
}
break;
case IDM_FINDPREV:
if( lstrlen( FindBuffer ) )
{
SendMessage( hWndRichEdit, EM_EXGETSEL, 0, ( LPARAM ) &findtext.chrg );
findtext.chrg.cpMax = 0;
findtext.lpstrText = FindBuffer;
if( SendMessage( hWndRichEdit, EM_FINDTEXTEX, 0, ( LPARAM ) &findtext ) != -1 )
SendMessage( hWndRichEdit, EM_EXSETSEL, 0, ( LPARAM ) &findtext.chrgText );
}
break;
case IDM_EXIT:
SendMessage( hWnd, WM_CLOSE, 0, 0 );
break;
}
}
break;
case WM_CLOSE:
if( CheckModifyState( hWnd ) )
{
DeleteObject( hFont );
DestroyWindow( hWnd );
}
break;
case WM_SIZE:
MoveWindow( hWndRichEdit, 0, 0, LOWORD( lParam ), HIWORD( lParam ), TRUE );
break;
case WM_DESTROY:
PostQuitMessage( 0 );
break;
}
return DefWindowProc( hWnd, msg, wParam, lParam );
}
#pragma argsused
int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE prev, LPSTR cmdline, int show )
{
WNDCLASSEX wc;
MSG msg;
HWND hWnd;
char * szClassName = "FreshClass";
HACCEL hAccel;
HINSTANCE hDll = LoadLibrary( "riched32" );
wc.cbSize = sizeof( WNDCLASSEX );
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hbrBackground = GetStockObject( WHITE_BRUSH );
wc.lpszMenuName = ( LPCTSTR ) IDR_MAINMENU;
wc.lpszClassName = szClassName;
wc.hIcon = wc.hIconSm = LoadIcon( NULL, IDI_APPLICATION );
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
RegisterClassEx( &wc );
hWnd = CreateWindowEx( NULL, szClassName, "Fresh 1.0",
WS_OVERLAPPEDWINDOW, 70, 70,
1130, 630, 0, NULL, hInstance, NULL );
ShowWindow( hWnd, SW_SHOWNORMAL );
UpdateWindow( hWnd );
hAccel = LoadAccelerators( hInstance, ( LPCTSTR ) IDR_MAINACCEL );
while( GetMessage( &msg, 0, 0, 0 ) )
{
if( IsDialogMessage( hSearch, &msg ) )
TranslateAccelerator( hWnd, hAccel, &msg );
else
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
FreeLibrary( hDll );
return 0;
}
fresh.rc
- Code: Select all Expand view
- // #include "resource.h"
#define IDC_NEXT 1003
#define IDR_MAINMENU 101
#define IDD_OPTIONDLG 101
#define IDD_FINDDLG 102
#define IDD_GOTODLG 103
#define IDD_REPLACEDLG 104
#define IDR_MAINACCEL 105
#define IDC_BACKCOLORBOX 1000
#define IDC_FINDEDIT 1000
#define IDC_TEXTCOLORBOX 1001
#define IDC_MATCHCASE 1001
#define IDC_REPLACEEDIT 1001
#define IDC_WHOLEWORD 1002
#define IDC_DOWN 1003
#define IDC_UP 1004
#define IDC_LINENO 1005
#define IDM_OPEN 40001
#define IDM_SAVE 40002
#define IDM_CLOSE 40003
#define IDM_SAVEAS 40004
#define IDM_EXIT 40005
#define IDM_COPY 40006
#define IDM_CUT 40007
#define IDM_PASTE 40008
#define IDM_DELETE 40009
#define IDM_SELECTALL 40010
#define IDM_OPTION 40011
#define IDM_UNDO 40012
#define IDM_REDO 40013
#define IDM_FIND 40014
#define IDM_FINDNEXT 40015
#define IDM_REPLACE 40016
#define IDM_GOTOLINE 40017
#define IDM_FINDPREV 40018
IDR_MAINMENU MENU DISCARDABLE
BEGIN
POPUP "&File"
BEGIN
MENUITEM "&Open", IDM_OPEN
MENUITEM "&Close", IDM_CLOSE
MENUITEM "&Save", IDM_SAVE
MENUITEM "Save &As", IDM_SAVEAS
MENUITEM SEPARATOR
MENUITEM "E&xit", IDM_EXIT
END
POPUP "&Edit"
BEGIN
MENUITEM "&Undo", IDM_UNDO
MENUITEM "&Redo", IDM_REDO
MENUITEM "&Copy", IDM_COPY
MENUITEM "C&ut", IDM_CUT
MENUITEM "&Paste", IDM_PASTE
MENUITEM SEPARATOR
MENUITEM "&Delete", IDM_DELETE
MENUITEM SEPARATOR
MENUITEM "Select &All", IDM_SELECTALL
END
POPUP "&Search"
BEGIN
MENUITEM "&Find...\tCtrl+F", IDM_FIND
MENUITEM "Find &Next\tF3", IDM_FINDNEXT
MENUITEM "Find &Prev.\tCtrl+F3", IDM_FINDPREV
MENUITEM "&Replace..\tCtrl+R", IDM_REPLACE
MENUITEM SEPARATOR
MENUITEM "&Go To Line\tCtrl+G", IDM_GOTOLINE
END
MENUITEM "Options", IDM_OPTION
END
IDD_OPTIONDLG DIALOG DISCARDABLE 0, 0, 183, 54
STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION |
WS_SYSMENU
CAPTION "Options"
FONT 8, "MS Sans Serif"
BEGIN
DEFPUSHBUTTON "OK",IDOK,137,7,39,14
PUSHBUTTON "Cancel",IDCANCEL,137,25,39,14
GROUPBOX "",IDC_STATIC,5,0,124,49
LTEXT "Background Color:",IDC_STATIC,20,14,60,8
LTEXT "",IDC_BACKCOLORBOX,85,11,28,14,SS_NOTIFY | WS_BORDER
LTEXT "Text Color:",IDC_STATIC,20,33,35,8
LTEXT "",IDC_TEXTCOLORBOX,85,29,28,14,SS_NOTIFY | WS_BORDER
END
IDD_FINDDLG DIALOG DISCARDABLE 0, 0, 186, 54
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "Find.."
FONT 8, "MS Sans Serif"
BEGIN
EDITTEXT IDC_FINDEDIT,42,3,94,12,ES_AUTOHSCROLL
CONTROL "Match Case",IDC_MATCHCASE,"Button",BS_AUTOCHECKBOX |
WS_TABSTOP,6,24,54,10
CONTROL "Whole Word",IDC_WHOLEWORD,"Button",BS_AUTOCHECKBOX |
WS_TABSTOP,6,37,56,10
CONTROL "Down",IDC_DOWN,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,
83,27,35,10
CONTROL "Up",IDC_UP,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,83,
38,25,10
DEFPUSHBUTTON "OK",IDOK,141,3,39,12
PUSHBUTTON "Cancel",IDCANCEL,141,18,39,12
LTEXT "Find what:",IDC_STATIC,5,4,34,8
GROUPBOX "Direction",IDC_STATIC,70,18,64,32
END
IDD_GOTODLG DIALOGEX 0, 0, 106, 30
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_TOOLWINDOW
CAPTION "Go To Line"
FONT 8, "MS Sans Serif", 0, 0
BEGIN
EDITTEXT IDC_LINENO,29,4,35,11,ES_AUTOHSCROLL | ES_NUMBER,
WS_EX_CLIENTEDGE
DEFPUSHBUTTON "OK",IDOK,70,4,31,11
PUSHBUTTON "Cancel",IDCANCEL,70,17,31,11
LTEXT "Line :",IDC_STATIC,8,5,18,8
END
IDD_REPLACEDLG DIALOG DISCARDABLE 0, 0, 186, 33
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "Replace"
FONT 8, "MS Sans Serif"
BEGIN
EDITTEXT IDC_FINDEDIT,51,3,84,12,ES_AUTOHSCROLL
EDITTEXT IDC_REPLACEEDIT,51,17,84,11,ES_AUTOHSCROLL
DEFPUSHBUTTON "OK",IDOK,142,3,39,11
PUSHBUTTON "Cancel",IDCANCEL,142,17,39,11
LTEXT "Find what:",IDC_STATIC,3,4,34,8
LTEXT "Replace with",IDC_STATIC,3,18,42,8
END
IDR_MAINACCEL ACCELERATORS DISCARDABLE
BEGIN
"F", IDM_FIND, VIRTKEY, CONTROL, NOINVERT
"G", IDM_GOTOLINE, VIRTKEY, CONTROL, NOINVERT
"R", IDM_REPLACE, VIRTKEY, CONTROL, NOINVERT
VK_F3, IDM_FINDNEXT, VIRTKEY, NOINVERT
VK_F3, IDM_FINDPREV, VIRTKEY, CONTROL, NOINVERT
END
go.bat:
- Code: Select all Expand view
- set path=c:\bcc582\bin
brc32 -r fresh.rc
bcc32 -W fresh.c
if errorlevel 0 fresh
Usa un fichero wordfile.txt para indicar los tokens que resaltar:
- Code: Select all Expand view
- [ASSEMBLY]
C1=CLASS ENDCLASS DATA METHOD INLINE
C2=#include #pragma #ifdef #endif #define another
C3=local static public private
C4=if else endif return do case end endcase
C5=
C6=
C7=
C8=
C9=
C10=
Ya funciona aunque no está completo y aún tiene algunos bugs al analizar las palabras. Pero el concepto está ahí y es muy interesante
El código fuente original (en ensamblador) y la idea pertenecen a Iczelion@win32asm.cjb.net.