It is written in C, uses the RICHEDIT control and offers the minimal functionality I need. I can give you the source code if it can be useful for you.
I was interested to review how much functionality RichEdit could offer as a Windows built-in source code editor. I remembered that RichEdit coloring was very slow for large files and that was the main problem about it. So I decided to do some more research about it. First interesting info I found was this one:
http://bcbjournal.org/articles/vol3/9910/Faster_rich_edit_syntax_highlighting.htm
Its author uses C++ Builder and found some ways to speed it up. So I decided to create a plain C language self contained example to test how fast his optimizations are. You can easily build it using Borland C:
go.bat
- Code: Select all Expand view
- set path=c:\bcc582\bin
bcc32 -W test.c
if errorlevel 0 test
test.c // RichEdit based editor with automatic syntax highligthing
- 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;
}
No Harbour, no FWH, just pure C language speed to test it, but unfortunately still slow for large PRG files. So I decided to keep googling and then found this:
http://win32assembly.online.fr/tut35.html
It may result scaring at a first review as it is developed using assembler (ouch!) but his author had a very interesting concept: to subclass RichEdit and do the coloring himself. Well, I decided to convert it from assembler to C to test it. Some code I implemented it myself, once I understood its purpouse. Here it is:
fresh.c // I thought about this name for a "Free RichEdit Editor Syntax Highlighted" acronym
- 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
It uses a wordfile.txt to specify the tokens to highlight:
- 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=
It already works though it is not complete and still has some bugs while parsing. But the concept is there and it is quite interesting
Original source code and idea belongs to Iczelion@win32asm.cjb.net.