#include <windows.h>
#include <commctrl.h>
#include <commdlg.h>
#include <richedit.h>
#include <stdio.h>

#include "header.h"
#include <ctype.h>

#define EDITOR_OFFSET 35
HWND CreateDrawWindow(DWINFO *baseinfo) ;

LRESULT  CALLBACK _export YesNoProc( HWND hwnd, UINT iMessage, WPARAM wParam,
                                 LPARAM lParam ) ;
extern HINSTANCE hInstance ;
extern HWND hwndClient,hwndStatus,hwndFrame,hwndASM ;
extern HANDLE hMenuMain ;
extern int iFindMessage ;
extern char szSourceFilter[] ;
extern COLORREF keywordColor ;
extern COLORREF numberColor  ;
extern COLORREF commentColor ;
extern COLORREF stringColor ;
extern COLORREF escapeColor ;
extern COLORREF backgroundColor ;
extern COLORREF textColor ;
extern int custColors[16] ;
extern int txtFontHeight ;
extern enum DebugState uState ;

extern int tabs ;
HWND hwndFind ;
static char szDrawClassName[] = "xccDrawClass" ;
int childxpos,childypos ; 
int numberofdrawwindows ;
int editFlags = BACKUP_FILES|BACKUP_PROJECTS ;

static HBITMAP pcBitmap, stopBitmap ;
static char szUntitled[] = "Untitled" ;
static DWINFO *newInfo ;
static	char finding,findbuffer[256],replacebuffer[256] ;
static	FINDREPLACE find ;
static	FINDREPLACE replace ;
static int findpos,found ;
HANDLE children[MAX_CHILDREN] ;

int xstricmpz(char *str1, char *str2)
{
	while (*str2)
		if (toupper(*str1++) != toupper(*str2++))
			return 1 ;
	return *str1 != *str2 ;
}
int xstricmp(char *str1, char *str2)
{
	while (*str2)
		if (toupper(*str1++) != toupper(*str2++))
			return 1 ;
	return 0 ;
}
char *stristr(char *str1, char *str2)
{
	int l = strlen(str2) ;
	while(*str1) {
		if (!xstricmp(str1,str2))
			return str1 ;
		str1++ ;
	}
	return 0 ;
}
int ReadNum(char **p)
{
	int rv ;
	if (!**p)
		return 0 ;
	while (**p == ' ')
		(*p)++ ;
	rv = atoi(*p) ;
	while (**p && **p != ' ')
		(*p)++ ;
	return rv ;
}
int RestoreWindows(FILE *in)
{
	MDICREATESTRUCT mc ;
	static DWINFO info ;
	char buf[256] ;
	int i ;
	if (ReadString(buf,in,"<COLORS>"))
		return 1 ;
	if (ReadString(buf,in,0))
		return 1 ;
	sscanf(buf,"%X",&keywordColor );
	if (ReadString(buf,in,0))
		return 1 ;
	sscanf(buf,"%X",&numberColor );
	if (ReadString(buf,in,0))
		return 1 ;
	sscanf(buf,"%X",&commentColor );
	if (ReadString(buf,in,0))
		return 1 ;
	sscanf(buf,"%X",&stringColor );
	if (ReadString(buf,in,0))
		return 1 ;
	sscanf(buf,"%X",&escapeColor );
	if (ReadString(buf,in,0))
		return 1 ;
	sscanf(buf,"%X",&backgroundColor );
	if (ReadString(buf,in,0))
		return 1 ;
	sscanf(buf,"%X",&textColor );
	for (i=0; i < 16; i++) {
		if (ReadString(buf,in,0))
			return 1 ;
		sscanf(buf,"%X",&custColors[i] );
	}
	if (ReadString(buf,in,"</COLORS>"))
		return 1 ;
	if (ReadString(buf,in,"<TABS"))
		return 1 ;
	tabs = atoi(buf + 6) ;
	if (ReadString(buf,in,"<EDITOR "))
		return 1 ;
	sscanf(buf+ 8,"%x",&editFlags );
	if (ReadString(buf,in,"<WINDOWS>"))
		return 1 ;
	while (1) {
		int i = 0 ;
		char *p = buf ;
		
		if (ReadString(buf,in,0))
			return 1 ;
		if (buf[0] == '<')
			break ;
		memset(&info,0,sizeof(info)) ;
		while (*p && *p != ';')
			info.dwName[i++] = *p++ ;
		i = 0 ;
		if (*p)
			p++ ;
		while (*p && *p != ' ')
			info.dwTitle[i++] = *p++ ;
		newInfo = &info ;

		mc.szClass = szDrawClassName ;
		mc.szTitle = szUntitled ;
		mc.hOwner = hInstance ;
		mc.x = ReadNum(&p) ;
		mc.y = ReadNum(&p) ;
		mc.cx = ReadNum(&p);
		mc.cy = ReadNum(&p);
		mc.style = WS_CHILD | WS_VISIBLE | WS_CAPTION | WS_SYSMENU;
		mc.lParam = 0 ;
      newInfo->dwLineNo = ReadNum(&p) ;
		SendMessage(hwndClient,WM_MDICREATE,0,(LPARAM)&mc) ;
		Sleep(250) ;	
	}
	if (xstricmp(buf,"</WINDOWS>"))
		return 1 ;
}
void SaveWindows(FILE *out)
{
	int i;
	fprintf(out,"<COLORS>\n") ;
	fprintf(out,"%08x\n",keywordColor) ;
	fprintf(out,"%08x\n",numberColor) ;
	fprintf(out,"%08x\n",commentColor) ;
	fprintf(out,"%08x\n",stringColor) ;
	fprintf(out,"%08x\n",escapeColor) ;
	fprintf(out,"%08x\n",backgroundColor) ;
	fprintf(out,"%08x\n",textColor) ;
	for (i=0; i < 16; i++)
		fprintf(out,"%08x\n",custColors[i]) ;
	fprintf(out,"</COLORS>\n") ;
	fprintf(out,"<TABS %d>\n",tabs) ;
	fprintf(out,"<EDITOR %x>\n",editFlags) ;
	fprintf(out,"<WINDOWS>\n") ;
	for (i=0; i < numberofdrawwindows; i++) {
		RECT r ;
		POINT p ;
		int startpos ;
      struct minmax {
         int min,max ;
      } charinfo ;
      WINDOWPLACEMENT placement ;
		DWINFO *info = (DWINFO *)GetWindowLong(children[i],0) ;
      SendMessage(GetDlgItem(children[i],ID_EDITCHILD),EM_EXGETSEL,0,(WPARAM) &charinfo) ;
      startpos = SendMessage(GetDlgItem(children[i],ID_EDITCHILD),EM_LINEFROMCHAR, charinfo.min,0 ) ;
      placement.length = sizeof(placement) ;
      GetWindowPlacement(children[i],&placement) ;
      p.x = placement.rcNormalPosition.left ;
      p.y = placement.rcNormalPosition.top ;
//      ScreenToClient(hwndClient,&p) ;
      fprintf(out,"%s;%s %d %d %d %d %d\n",info->dwName,info->dwTitle,
            p.x,p.y,placement.rcNormalPosition.right-placement.rcNormalPosition.left,
            placement.rcNormalPosition.bottom-placement.rcNormalPosition.top,startpos+1) ;    
	}
	fprintf(out,"</WINDOWS>\n") ;
}
void ApplyEditSettings(void)
{
	int i ;
	for (i=0; i < numberofdrawwindows; i++) 
      PostMessage(GetDlgItem(children[i],ID_EDITCHILD),WM_SETEDITORSETTINGS,0,0) ;

}
void CheckEditWindowChanged(void)
{
	int i ;
	for (i=0; i < numberofdrawwindows; i++) 
      PostMessage(children[i],WM_CHECKCHANGE,0,0) ;
}
int ApplyBreakAddress(char *module, int linenum)
{
   char nmodule[260] ;
	int i ;
   nmodule[0] = 0 ;
   if (linenum) {
      char *p ;
      static DWINFO x ;
      FindModuleName(nmodule, module) ;
      strcpy(x.dwName, nmodule) ;
      p = strrchr(nmodule, '\\') ;
      if (p)
         strcpy(x.dwTitle,p+1) ;
      else
         strcpy(x.dwTitle,nmodule) ;
      x.dwLineNo = 1 ;
      x.breakpointLine = linenum ;
      x.dwLineNo = linenum ;
      CreateDrawWindow(&x) ;
   }
   for (i=0; i < numberofdrawwindows; i++) {
      (HWND)SendMessage(children[i],WM_SETBREAKLINE,(WPARAM)nmodule, linenum) ;
   }
}
int AnyDrawChanged(void)
{
	int i;
	for (i=0 ; i < numberofdrawwindows; i++)
		if (SendMessage(children[i],WM_COMMAND,ID_QUERYSAVE,0))
			return TRUE ;
	return FALSE ;
}
void SaveDrawAll(void)
{
	int i;
	for (i=0; i < numberofdrawwindows; i++) {
		DWINFO *ptr = (DWINFO *)GetWindowLong(children[i],0) ;
		if (SendMessage(ptr->dwHandle,EM_GETMODIFY,0,0))
			SendMessage(children[i],WM_COMMAND, IDM_SAVE,0) ;
	}
}
void CloseAll(void)
{
	int i;
	for (i=0; i < numberofdrawwindows; i++)
		SendMessage(children[i],WM_CLOSE,0,0) ;
}
char *GetEditData(HWND hwnd)
{
	int l ;
	char *buf ;
	l = SendMessage(hwnd,WM_GETTEXTLENGTH,0,0) ;
	buf = malloc(l+1) ;
	if (!buf) {
		return 0;
	}
  SendMessage(hwnd,WM_GETTEXT,l+1,(LPARAM)buf) ;
	return buf ;
}
int SetEditData(HWND hwnd, char *buf)
{
	SendMessage(GetDlgItem(hwnd,ID_EDITCHILD),WM_SETTEXT,0,(LPARAM)buf) ;
	free(buf) ;
	return TRUE ;
}
void backup(char *name)
{
	char newname[256],buffer[512] ;
	char *s ;
	FILE *in,*out ;
	int size ;
	strcpy(newname,name) ;
	s = strrchr(newname,'.') ;
	if (s)
		strcpy(s,".bak") ;
	else
		strcat(newname,".bak") ;

	in = fopen(name,"rb") ;
	if (!in)
		return ;
	out = fopen(newname,"wb") ;
	while ((size = fread(buffer,1,512,in)) == 512)
		fwrite(buffer,1,512,out) ;
	fwrite(buffer,1,size,out) ;
	fclose(out) ;
	fclose(in) ;
}
int SaveFile(HWND hwnd, DWINFO *info)
{
	char *buf  = GetEditData(GetDlgItem(hwnd,ID_EDITCHILD)) ;
	FILE *out ;
	int l,i ;
	
	if (editFlags &  BACKUP_FILES)
		backup(info->dwName) ;
	if (!buf)
		return FALSE ;
	out = fopen(info->dwName,"wb") ;
	if (!out) {
		free(buf) ;
		return FALSE ;
	}
	fprintf(out,"%s",buf) ;
	fclose(out) ;
	free(buf) ;
   FileTime(&info->time, info->dwName) ;
	return TRUE ;
}
int LoadFile(HWND hwnd, DWINFO *info)
{
	long size ;
	char *buf ;
  FILE *in = fopen(info->dwName,"rb") ;
	if (!in)
		return FALSE ;
	fseek(in,0L,SEEK_END) ;
	fgetpos(in,&size);
	buf = malloc(size+1) ;
	if (!buf) {
		fclose(in) ;
		return FALSE ;
	}
	fseek(in,0L,SEEK_SET) ;
	fread(buf,size,1,in) ;
	buf[size] = 0 ;
	fclose(in) ;
	SetEditData(hwnd,buf) ;
	SendMessage(info->dwHandle,EM_SETMODIFY,0,0) ;

   FileTime(&info->time, info->dwName) ;
	return TRUE ;

}
void PopFindString(HWND hwnd)
{
   char buf[256] ;
   if (GetWordFromPos(GetDlgItem(hwnd,ID_EDITCHILD),buf,-1,0,0,0))
      strcpy(findbuffer,buf) ;
	find.lStructSize = sizeof(find) ;
	find.hwndOwner = hwnd ;
	find.hInstance = hInstance ;
	find.Flags = FR_HIDEUPDOWN ;
   find.lpstrFindWhat = findbuffer ;
	find.lpstrReplaceWith = 0 ;
	find .wFindWhatLen = 256 ;
	find .wReplaceWithLen = 0 ;
	finding = TRUE ;
	hwndFind = FindText(&find ) ;
	SendMessage(GetDlgItem(hwnd,ID_EDITCHILD),EM_GETSEL, (WPARAM)&findpos,0) ;

}
void PopReplaceString(HWND hwnd)
{
   DWINFO *p = (DWINFO *)GetWindowLong(hwnd,0) ;
   char buf[256] ;
   if (GetWordFromPos(GetDlgItem(hwnd,ID_EDITCHILD),buf,-1,0,0,0))
      strcpy(findbuffer,buf) ;
	replace.lStructSize = sizeof(replace) ;
	replace.hwndOwner = hwnd ;
	replace.hInstance = hInstance ;
	replace.Flags = FR_HIDEUPDOWN ;
   replace.lpstrFindWhat = findbuffer ;
	replace.lpstrReplaceWith = replacebuffer ;
	replace .wFindWhatLen = 256 ;
	replace .wReplaceWithLen = 256 ;
	finding = FALSE ;
	hwndFind = ReplaceText(&replace ) ;
	found = FALSE ;
	SendMessage(GetDlgItem(hwnd,ID_EDITCHILD),EM_GETSEL, (WPARAM)&findpos,0) ;

}
int xfind(FINDREPLACE *find, char *buf, int pos, int *len)
{
	int flags = find->Flags ;

	if (pos < 0)
		pos = 0 ;
	
	*len = strlen(find->lpstrFindWhat ) ;
	while (TRUE) {
		if (flags & FR_MATCHCASE)
			pos = (int)strstr(buf+pos,find->lpstrFindWhat);
		else
			pos = (int)stristr(buf+pos,find->lpstrFindWhat);
		if (pos) {
			pos = (char *)pos - buf ;
			if (flags & FR_WHOLEWORD) {
				if (pos && isalnum(buf[pos-1])) 
					pos += *len ;
				else if (!buf[pos+*len] || !isalnum(buf[pos+*len]))
					return pos ;
				else
					pos += *len ; 
			}
			else return pos ;
		} else
			return -1 ;

	}
	
}
void FindNextString(HWND hwnd, FINDREPLACE *find)
{
	char *buf = GetEditData(GetDlgItem(hwnd,ID_EDITCHILD)) ;
	int len ;
	if (buf) {
		findpos = xfind(find, buf,findpos,&len) ;
		if (findpos > 0) {
			SendMessage(GetDlgItem(hwnd,ID_EDITCHILD), EM_SETSEL,findpos, findpos+len) ;
			SendMessage(GetDlgItem(hwnd,ID_EDITCHILD), EM_SCROLLCARET, 0,0 );
			UpdateWindow(GetDlgItem(hwnd,ID_EDITCHILD)) ;
			findpos += len ;
		} else {
			if (!(find->Flags & FR_REPLACEALL))
				ExtendedMessageBox("Search",0,"No more matches found") ;
			SendMessage(GetDlgItem(hwnd,ID_EDITCHILD),EM_SETSEL,-1,0) ;
		}
		free(buf) ;
	}

}
void ReplaceNextString(HWND hwnd, FINDREPLACE *replace)
{
	int flags = replace->Flags ;
	while (TRUE) {
		if (!found || (flags & FR_FINDNEXT))
			FindNextString(hwnd,replace) ;
		found = TRUE ;
		if (findpos < 0)
			return ;             
		if (flags & (FR_REPLACE | FR_REPLACEALL)) {
			SendMessage(GetDlgItem(hwnd,ID_EDITCHILD), EM_REPLACESEL, 1, (LPARAM) replace->lpstrReplaceWith) ;
			UpdateWindow(GetDlgItem(hwnd,ID_EDITCHILD)) ;
			findpos += strlen(replace->lpstrReplaceWith) - strlen(replace->lpstrFindWhat) ;
			found = FALSE ;
		}
		if (!(flags & FR_REPLACEALL))
			return ;
	}

}
void drawParams(HWND hwnd)
{
	char buf[10] ;
	int start,ins ;
	SendMessage(hwnd,EM_GETSEL,(WPARAM) &start,0) ;
	start = SendMessage(hwnd,EM_LINEFROMCHAR,start,0) ;
	ins = SendMessage(hwnd,EM_GETINSERTSTATUS,0,0) ;
	sprintf(buf,"%d",start+1) ;
	SendMessage(hwndStatus,SB_SETTEXT,1 , (LPARAM)buf) ;
	SendMessage(hwndStatus,SB_SETTEXT,2 , (LPARAM)(ins ? "INS" : "OVR")) ;
	
}
int PaintBreakpoints(HWND hwnd, HDC dc, PAINTSTRUCT *paint)
{
   LOGBRUSH lbrush,lbrush1 ;
   HBRUSH graybrush,graybrush1 ;
   if (uState != notDebugging) {
      RECT r,r1 ;
      int i ;
      int rv = FALSE ;
      HDC hMemDC = CreateCompatibleDC(dc) ;
      DWINFO *ptr = (DWINFO*)GetWindowLong(hwnd,0) ;
      int linenum = SendMessage(ptr->dwHandle,EM_GETFIRSTVISIBLELINE,0,0) + 1;
      int chpos1 = SendMessage(ptr->dwHandle, EM_LINEINDEX,linenum,0) ;
      int ypos ;
      int lines,offset = 0  ;
      short*lt ;
      int lc;
      POINTL pt ;
      SendMessage(ptr->dwHandle, EM_POSFROMCHAR,(WPARAM)&pt,chpos1) ;
      ypos = pt.y ;

      SendMessage(ptr->dwHandle,EM_GETRECT,0,(LPARAM)&r1) ;
      lines = r1.bottom / txtFontHeight ;

      if (ypos < txtFontHeight)
         offset= ypos -txtFontHeight;

      lt = GetLineTable(ptr->dwName,&lc) ;
      if (lt) {
         while (lc && *lt < linenum) {
            lc-- ;
            lt++ ;
         }
         if (lc) {
            lbrush.lbStyle = BS_SOLID ;
            lbrush.lbColor = GetSysColor(COLOR_3DSHADOW) ;
            graybrush = CreateBrushIndirect(&lbrush) ;
            lbrush1.lbStyle = BS_SOLID ;
            lbrush1.lbColor = GetSysColor(COLOR_3DFACE) ;
            graybrush1 = CreateBrushIndirect(&lbrush1) ;
            for (i=linenum; i <= linenum+lines; i++) {
               int j, drawn = FALSE; 
               r.left = 0 ;
               r.right = 32 ;
               r.top = offset + (i - linenum) * txtFontHeight ;
               r.bottom = r.top + txtFontHeight ;
               for (j = 0; j < lc; j++)
                  if (lt[j] == i) {
                     FillRect(dc,&r,graybrush) ; 
                     drawn = TRUE ;
                     break ;
                  }
               if (!drawn) 
                  FillRect(dc,&r,graybrush1) ;
            }
            DeleteObject(graybrush) ;
            DeleteObject(graybrush1) ;
            rv = TRUE ;
         }
      }
      if (ptr->breakpointLine >= linenum && ptr->breakpointLine <= linenum + lines) {
         SelectObject(hMemDC,pcBitmap) ;
         BitBlt(dc,16,(ptr->breakpointLine - linenum)*txtFontHeight + offset,16,16,hMemDC,0,0,SRCCOPY) ;
      }
      SelectObject(hMemDC,stopBitmap) ;
      for (i = linenum; i <= linenum + lines; i++)
         if (IsBreakpointLine(ptr->dwName,i))
            BitBlt(dc,0,(i - linenum)*txtFontHeight + offset,16,16,hMemDC,0,0,SRCCOPY) ;
      DeleteDC(hMemDC) ;
      return rv ;
   }
   return FALSE ;
}
LRESULT  CALLBACK _export DrawProc( HWND hwnd, UINT iMessage, WPARAM wParam,
																		LPARAM lParam)
{
   DWINFO *ptr,*ptr1 ;
	OPENFILENAME ofn ;
	HDC dc ;
	HPEN hpen,oldpen ;
	RECT r ;
	HBRUSH graybrush ;
	LOGBRUSH lbrush ;
	PAINTSTRUCT paint ;
   int childheight ;
   int startpos, endpos,flag,i ;
   HWND win ;
   FILETIME time ;
   NMHDR *nm ;
	switch(iMessage) {
      case WM_NOTIFY:
         nm = (NMHDR *)lParam ;
         if (nm->code == NM_RCLICK) {
               HMENU  menu  = LoadMenu( hInstance, "EDITMENU" ) ;
               HMENU popup = GetSubMenu( menu, 0 );
               POINT pos,pos1 ;
               ptr = (DWINFO*)GetWindowLong(hwnd,0) ;
               if (!SendMessage(ptr->dwHandle,EM_GETMODIFY,0,0))
                  EnableMenuItem(menu,IDM_SAVE,MF_GRAYED) ;
               if (uState != atBreakpoint) {
                  EnableMenuItem(menu,IDM_RUNTO,MF_GRAYED) ;
                  EnableMenuItem(menu,IDM_ADDWATCHINDIRECT,MF_GRAYED) ;
               }
  					GetCursorPos( &pos );
               pos1.x = pos.x ;
               pos1.y = pos.y ;
               ScreenToClient(ptr->dwHandle,&pos1) ;
               i = SendMessage(ptr->dwHandle,EM_CHARFROMPOS,0,(LPARAM)&pos1) & 0xffff;
               SendMessage(ptr->dwHandle,EM_SETSEL,i,i) ;
  					TrackPopupMenuEx( popup, TPM_BOTTOMALIGN | TPM_LEFTBUTTON,
                        pos.x, pos.y, hwndFrame, NULL );
  					DestroyMenu( menu );
         }
         return 0 ;
		case WM_SYSCOMMAND :
			if (wParam == SC_CLOSE)
				SendMessage(hwnd,WM_CLOSE,0,0) ;
			break ;
      case WM_CHECKCHANGE:
         ptr = (DWINFO*)GetWindowLong(hwnd,0) ;
         if (FileTime(&time,ptr->dwName)) {
            if (time.dwHighDateTime != ptr->time.dwHighDateTime ||
               time.dwLowDateTime != ptr->time.dwLowDateTime) {
               if (ExtendedMessageBox("File has changed",MB_YESNO,"File %s has changed outside the editor.  Reload?", ptr->dwTitle) == IDYES)
                  LoadFile(hwnd, ptr) ;
               else
                  FileTime(&ptr->time,ptr->dwName) ;
            }
         }
         break ;
		case WM_COMMAND:
			switch(LOWORD(wParam)) {
				case IDM_GOTO:
					ptr = (DWINFO*)GetWindowLong(hwnd,0) ;
					i = SendMessage(ptr->dwHandle,EM_LINEINDEX,lParam-1,0) ;
					SendMessage(ptr->dwHandle,EM_SETSEL,i,i) ;
					SendMessage(ptr->dwHandle,EM_SCROLLCARET,0,0) ;
					drawParams(ptr->dwHandle) ;
               InvalidateRect(hwnd,0,0) ;
               break ;
				case ID_REDRAWSTATUS:
					drawParams(GetDlgItem(hwnd,ID_EDITCHILD)) ;
               InvalidateRect(hwnd,0,0) ;
					break ;
				case ID_QUERYHASFILE:
					ptr = (DWINFO *)GetWindowLong(hwnd,0) ;
					ptr1 =(DWINFO *)lParam ;
					return !xstricmpz(ptr->dwName,ptr1->dwName) ;
				case ID_QUERYSAVE:
					ptr = (DWINFO *)GetWindowLong(hwnd,0) ;
					return SendMessage(ptr->dwHandle,EM_GETMODIFY,0,0) ;
				case IDM_SAVEAS:
dialog:
					ptr = (DWINFO*)GetWindowLong(hwnd,0) ;
					if (!SaveFileDialog(&ofn,ptr->dwName,hwnd,TRUE,szSourceFilter,"FILEDIR")) 
						break ;
					strcpy(ptr->dwTitle,ofn.lpstrFileTitle) ;
					strcpy(ptr->dwName,ofn.lpstrFile) ;
					SetWindowText(hwnd,ptr->dwTitle) ;
				case IDM_SAVE:
save:
					ptr = (DWINFO*)GetWindowLong(hwnd,0) ;
					if (ptr->dwName[0] == 0)
						goto dialog ;
					SaveFile(hwnd,(char *)GetWindowLong(hwnd,0)) ;
					SendMessage(ptr->dwHandle,EM_SETMODIFY,0,0) ;
					break ;
				case IDM_CLOSE:
					SendMessage(hwnd,WM_CLOSE,0,0) ;
					break ;
				case IDM_UNDO:
					SendMessage(GetDlgItem(hwnd,ID_EDITCHILD),WM_UNDO,0,0) ;
					break ;
				case IDM_CUT:
					SendMessage(GetDlgItem(hwnd,ID_EDITCHILD),WM_CUT,0,0) ;
					break ;
				case IDM_COPY:
					SendMessage(GetDlgItem(hwnd,ID_EDITCHILD),WM_COPY,0,0) ;
					break ;
				case IDM_PASTE:
					SendMessage(GetDlgItem(hwnd,ID_EDITCHILD),WM_PASTE,0,0) ;
					break ;
				case IDM_SELECTALL:
					SendMessage(GetDlgItem(hwnd,ID_EDITCHILD),EM_SETSEL,0,-1) ;
					break ;
				case IDM_FIND:
					PopFindString(hwnd) ;
					break ;
				case IDM_REPLACE:
					PopReplaceString(hwnd) ;
					break ;
				case IDM_FINDNEXT:
					if (finding)
						FindNextString(hwnd,&find) ;
					else
						ReplaceNextString(hwnd,&replace) ;
					break ;
				default:
					return DefMDIChildProc(hwnd,iMessage,wParam,lParam) ;
			}
			break ;
      case EM_CANUNDO:
         return SendMessage(GetDlgItem(hwnd,ID_EDITCHILD),EM_CANUNDO,0,0) ;
		case WM_SETCURSOR:
         drawParams(GetDlgItem(hwnd,ID_EDITCHILD)) ;
         GetClientRect(hwnd,&r) ;
         r.right = EDITOR_OFFSET - 3 ;
         InvalidateRect(hwnd,&r,0) ;
			break ;
      case WM_SETBREAKLINE:
         ptr = (DWINFO*)GetWindowLong(hwnd,0) ;
         win = 0 ;
         i = FALSE ;
         if (lParam == 0 ) {
            if (ptr->breakpointLine) {
               ptr->breakpointLine = 0 ;
               i = TRUE ;
            }
         } else {
            if (!xstricmpz((char *)wParam, ptr->dwName)) {
               win = hwnd ;
               ptr->breakpointLine = lParam ;
               i = TRUE ;
            } else
               if (ptr->breakpointLine) {
                  ptr->breakpointLine = 0 ;
                  i = TRUE ;
               }
         }
         if (i) {
            if (ptr->breakpointLine) {
//               i = SendMessage(ptr->dwHandle,EM_LINEINDEX,ptr->breakpointLine-1,0) ;
//               SendMessage(ptr->dwHandle,EM_SETSEL,i,i) ;
//               SendMessage(ptr->dwHandle,EM_SCROLLCARET,0,0) ;
               if (GetFocus() != hwndASM)
                  SetFocus(ptr->dwHandle) ;
            }
            GetClientRect(hwnd,&r) ;
            r.right = EDITOR_OFFSET - 3 ;
            InvalidateRect(hwnd,&r,0) ;
         }
         return win ;
		case WM_PAINT:
			GetClientRect(hwnd,&r) ;
			dc = BeginPaint(hwnd,&paint) ;
			hpen = CreatePen(PS_SOLID,1,0xcccccc),oldpen ;
			r.right = EDITOR_OFFSET-3;
			MoveToEx(dc, EDITOR_OFFSET-1,0,0) ;
			LineTo(dc,EDITOR_OFFSET-1, r.bottom) ;
			oldpen = SelectObject(dc,hpen) ;
			MoveToEx(dc,EDITOR_OFFSET-2,0,0) ;
			LineTo(dc,EDITOR_OFFSET-2,r.bottom) ;
			SelectObject(dc,oldpen) ;
			DeleteObject(hpen) ;
         if (!PaintBreakpoints(hwnd, dc,&paint)) {
            lbrush.lbStyle = BS_SOLID ;
            lbrush.lbColor = GetSysColor(COLOR_3DFACE) ;
            graybrush = CreateBrushIndirect(&lbrush) ;
            FillRect(dc,&r,graybrush) ; 
            DeleteObject(graybrush) ;
         }
			EndPaint(hwnd,&paint) ;
			return 0 ;
		case WM_CREATE:
			ptr = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWINFO)) ;
         ptr->breakpointLine = 0 ;
			SetWindowLong(hwnd,0,(int)ptr) ;
			children[numberofdrawwindows++] = hwnd ;
			if (newInfo == (DWINFO *)-1) {
				SetWindowText(hwnd,szUntitled) ;
			} else if (!newInfo) {
            if (OpenFileDialog(&ofn,0,hwnd,FALSE,FALSE, szSourceFilter,"FILEDIR")) {
					strcpy(ptr->dwTitle, ofn.lpstrFileTitle) ;
					SetWindowText(hwnd,ptr->dwTitle) ;
					strcpy(ptr->dwName,ofn.lpstrFile) ;
				} else {
					return -1 ;
				}
			} else {
					strcpy(ptr->dwTitle, newInfo->dwTitle) ;
					SetWindowText(hwnd,newInfo->dwTitle) ;
					strcpy(ptr->dwName,newInfo->dwName) ;
			}
         ptr->dwHandle = CreateWindowEx(0,"xedit",0,WS_CHILD + WS_VISIBLE +
							WS_HSCROLL + WS_VSCROLL + 
							ES_LEFT + ES_MULTILINE + ES_NOHIDESEL +
							ES_AUTOVSCROLL + ES_AUTOHSCROLL,
                     EDITOR_OFFSET,0,0,0,
                     hwnd,(HMENU)ID_EDITCHILD,hInstance,0);
         if (ptr->dwName[0])
            LoadFile(hwnd,ptr) ;
			if (newInfo != (DWINFO *)-1) {
				InsertMRU(ptr) ;
				MRUToMenu() ;
			}
         if (newInfo && newInfo != (DWINFO *)-1 && newInfo->dwLineNo != -1) {
				PostMessage(hwnd,WM_COMMAND,IDM_GOTO,newInfo->dwLineNo) ;
				newInfo->dwLineNo = -1 ;
         }
         return 0 ;
				
		case WM_CLOSE:
			if (SendMessage(hwnd,WM_COMMAND,ID_QUERYSAVE,0)) {
       	if (DialogBoxParam(hInstance,"SAVEDLG",hwndClient,(DLGPROC)YesNoProc,0))
					goto save ;
			} 
			break ;
		case WM_DESTROY:
			for (i=0 ; i < numberofdrawwindows; i++)
				if (children[i] == hwnd)
					break ;
         if (i < numberofdrawwindows-1)
            memcpy(children+i,children+i+1,numberofdrawwindows-i-1) ;
			numberofdrawwindows-- ;
			HeapFree(GetProcessHeap(),0,(void *)GetWindowLong(hwnd,0)) ;
         PostMessage(hwndFrame,WM_REDRAWTOOLBAR,0,0) ;
			break ;
		case WM_SIZE:       
         MoveWindow(GetDlgItem(hwnd,ID_EDITCHILD),EDITOR_OFFSET,0,(lParam & 65535)-EDITOR_OFFSET, lParam >> 16,1) ;
			break ;
		case WM_SETFOCUS:
			SetFocus(GetDlgItem(hwnd,ID_EDITCHILD)) ;
			drawParams(GetDlgItem(hwnd,ID_EDITCHILD)) ;
         InvalidateRect(hwnd,0,0) ;
         PostMessage(hwndFrame,WM_REDRAWTOOLBAR,0,0) ;
			return 0 ;
		case WM_INITMENUPOPUP:
			SendMessage(GetDlgItem(hwnd,ID_EDITCHILD),EM_GETSEL,(WPARAM)&startpos, (LPARAM)&endpos) ;
			flag = startpos < endpos ;
			EnableMenuItem(hMenuMain,IDM_CUT,flag) ;
			EnableMenuItem(hMenuMain,IDM_COPY,flag) ;
			EnableMenuItem(hMenuMain,IDM_PASTE,1) ;
         EnableMenuItem(hMenuMain,IDM_UNDO, SendMessage(GetDlgItem(hwnd,ID_EDITCHILD),EM_CANUNDO,0,0)) ;
			return 0 ;
      case WM_WORDUNDERCURSOR:  
         ptr = (DWINFO*)GetWindowLong(hwnd,0) ;
         return SendMessage(ptr->dwHandle,iMessage,wParam,lParam) ;
		default: 
			if (iMessage == iFindMessage) {
				if (finding) {
					if (find.Flags & FR_FINDNEXT)
						FindNextString(hwnd,&find) ;
					if (find.Flags & FR_DIALOGTERM)
						hwndFind = 0 ;
				} else {
					if (replace.Flags & (FR_FINDNEXT | FR_REPLACE | FR_REPLACEALL))
						ReplaceNextString(hwnd,&replace );
					if (replace.Flags & FR_DIALOGTERM)
						hwndFind = 0 ;
				}
			
			}
			break ;
	}
	return DefMDIChildProc(hwnd,iMessage,wParam,lParam) ;
}
void RegisterDrawWindow(void)
{
		WNDCLASS wc ;
      wc.style = 0;
		wc.lpfnWndProc = &DrawProc ;
		wc.cbClsExtra = 0;
		wc.cbWndExtra = sizeof(void *) ;
		wc.hInstance = hInstance ;
		wc.hIcon = LoadIcon(0,IDI_APPLICATION) ;
		wc.hCursor = LoadCursor(0,IDC_ARROW) ;
		wc.hbrBackground = GetStockObject(WHITE_BRUSH) ;
		wc.lpszMenuName = 0 ;
		wc.lpszClassName = szDrawClassName ;
      pcBitmap = LoadBitmap(hInstance, "ID_PCBMP") ;
      stopBitmap = LoadBitmap(hInstance, "ID_STOPBMP") ;
      ChangeBitmapColor(pcBitmap,0xffffff,GetSysColor(COLOR_3DSHADOW)) ;
      ChangeBitmapColor(stopBitmap,0,GetSysColor(COLOR_3DSHADOW)) ;
		RegisterClass(&wc) ;
}
HWND CreateDrawWindow(DWINFO *baseinfo)
{
	MDICREATESTRUCT mc ;
	HWND rv ;
	int i ;
	if (baseinfo && baseinfo != (DWINFO *)-1)
		for (i=0; i < MAX_CHILDREN; i++)
			if (children[i] && SendMessage(children[i],WM_COMMAND,ID_QUERYHASFILE,(LPARAM)baseinfo)) {
				BringWindowToTop(children[i]) ;
				SetFocus(children[i]) ;
				if (baseinfo->dwLineNo != -1)
					PostMessage(children[i],WM_COMMAND,IDM_GOTO,baseinfo->dwLineNo) ;
				return children[i] ;
			}

	if (numberofdrawwindows >= MAX_CHILDREN) {
		ExtendedMessageBox("Error",0,"Too many edit windows open") ;
		return 0 ;
	}

	newInfo = baseinfo ;

	mc.szClass = szDrawClassName ;
	mc.szTitle = szUntitled ;
	mc.hOwner = hInstance ;
	mc.x = childxpos ;
	mc.y = childypos ;
	mc.cx = 0;
	mc.cy = 0;
	mc.style = WS_CHILD | WS_VISIBLE | WS_BORDER | WS_THICKFRAME | WS_SYSMENU | WS_SIZEBOX|WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
	mc.lParam = 0 ;
	rv = (HWND) SendMessage(hwndClient,WM_MDICREATE,0,(LPARAM)&mc) ;
	childxpos += 20 ;
	childypos += 20 ;
	if (childxpos > 120)
      childxpos = childypos = 0 ;
	return rv ;
}