Sync to Wine-0_9_3:
[reactos.git] / reactos / lib / riched20 / editor.c
index eec9847..1383bcf 100644 (file)
@@ -2,6 +2,7 @@
  * RichEdit - functions dealing with editor object
  *
  * Copyright 2004 by Krzysztof Foltman
+ * Copyright 2005 by Cihan Altinay
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
   
   Messages (ANSI versions not done yet)
   - EM_AUTOURLDETECT 2.0
-  - EM_CANPASTE
+  + EM_CANPASTE
   + EM_CANREDO 2.0
   + EM_CANUNDO
-  - EM_CHARFROMPOS
+  + EM_CHARFROMPOS
   - EM_DISPLAYBAND
   + EM_EMPTYUNDOBUFFER
   + EM_EXGETSEL
   - EM_EXLIMITTEXT
-  - EM_EXLINEFROMCHAR
+  + EM_EXLINEFROMCHAR
   + EM_EXSETSEL
-  - EM_FINDTEXT
-  - EM_FINDTEXTEX
+  + EM_FINDTEXT (only FR_DOWN flag implemented)
+  + EM_FINDTEXTEX (only FR_DOWN flag implemented)
   - EM_FINDWORDBREAK
   - EM_FMTLINES
   - EM_FORMATRANGE
+  - EM_GETAUTOURLDETECT 2.0
+  - EM_GETBIDIOPTIONS 3.0
   - EM_GETCHARFORMAT (partly done)
+  - EM_GETEDITSTYLE
   + EM_GETEVENTMASK
-  - EM_GETFIRSTVISIBLELINE
+  + EM_GETFIRSTVISIBLELINE (can be optimized if needed)
   - EM_GETIMECOLOR 1.0asian
   - EM_GETIMECOMPMODE 2.0
   - EM_GETIMEOPTIONS 1.0asian
   - EM_GETLANGOPTIONS 2.0
   - EM_GETLIMITTEXT
   - EM_GETLINE        
-  - EM_GETLINECOUNT   returns number of rows, not of paragraphs
+  + EM_GETLINECOUNT   returns number of rows, not of paragraphs
   + EM_GETMODIFY
   - EM_GETOLEINTERFACE
   - EM_GETOPTIONS
   + EM_GETPARAFORMAT
+  - EM_GETPASSWORDCHAR 2.0
   - EM_GETPUNCTUATION 1.0asian
-  - EM_GETRECT
+  + EM_GETRECT
   - EM_GETREDONAME 2.0
   + EM_GETSEL
   + EM_GETSELTEXT (ANSI&Unicode)
+  - EM_GETSCROLLPOS 3.0
 ! - EM_GETTHUMB
+  - EM_GETTEXTEX 2.0
+  + EM_GETTEXTLENGTHEX (GTL_PRECISE unimplemented)
   - EM_GETTEXTMODE 2.0
 ? + EM_GETTEXTRANGE (ANSI&Unicode)
+  - EM_GETTYPOGRAPHYOPTIONS 3.0
   - EM_GETUNDONAME
   - EM_GETWORDBREAKPROC
   - EM_GETWORDBREAKPROCEX
   - EM_GETWORDWRAPMODE 1.0asian
+  + EM_GETZOOM 3.0
   - EM_HIDESELECTION
   - EM_LIMITTEXT
-  - EM_LINEFROMCHAR
-  - EM_LINEINDEX
-  - EM_LINELENGTH
-  - EM_LINESCROLL
+  + EM_LINEFROMCHAR
+  + EM_LINEINDEX
+  + EM_LINELENGTH
+  + EM_LINESCROLL
   - EM_PASTESPECIAL
-  - EM_POSFROMCHARS
-  - EM_REDO 2.0
-  - EM_REQUESTRESIZE
+  + EM_POSFROMCHAR
+  + EM_REDO 2.0
+  + EM_REQUESTRESIZE
   + EM_REPLACESEL (proper style?) ANSI&Unicode
   - EM_SCROLL
   - EM_SCROLLCARET
   - EM_SELECTIONTYPE
+  - EM_SETBIDIOPTIONS 3.0
   + EM_SETBKGNDCOLOR
   - EM_SETCHARFORMAT (partly done, no ANSI)
+  - EM_SETEDITSTYLE
   + EM_SETEVENTMASK (few notifications supported)
+  - EM_SETFONTSIZE
   - EM_SETIMECOLOR 1.0asian
   - EM_SETIMEOPTIONS 1.0asian
   - EM_SETLANGOPTIONS 2.0
   + EM_SETMODIFY (not sure if implementation is correct)
   - EM_SETOLECALLBACK
   - EM_SETOPTIONS
+  - EM_SETPALETTE 2.0
   + EM_SETPARAFORMAT
+  - EM_SETPASSWORDCHAR 2.0
   - EM_SETPUNCTUATION 1.0asian
   + EM_SETREADONLY no beep on modification attempt
-  - EM_SETRECT
-  - EM_SETRECTNP (EM_SETRECT without repainting) - not supported in RICHEDIT
+  + EM_SETRECT
+  + EM_SETRECTNP (EM_SETRECT without repainting)
   + EM_SETSEL
+  - EM_SETSCROLLPOS 3.0
+  - EM_SETTABSTOPS 3.0
   - EM_SETTARGETDEVICE
+  + EM_SETTEXTEX 3.0 (unicode only, no rich text insertion handling, proper style?)
   - EM_SETTEXTMODE 2.0
+  - EM_SETTYPOGRAPHYOPTIONS 3.0
   - EM_SETUNDOLIMIT 2.0
   - EM_SETWORDBREAKPROC
   - EM_SETWORDBREAKPROCEX
   - EM_SETWORDWRAPMODE 1.0asian
+  + EM_SETZOOM 3.0
+  - EM_SHOWSCROLLBAR 2.0
   - EM_STOPGROUPTYPING 2.0
-  - EM_STREAMIN
-  - EM_STREAMOUT
-  - EM_UNDO
+  + EM_STREAMIN
+  + EM_STREAMOUT
+  + EM_UNDO
   + WM_CHAR
   + WM_CLEAR
-  - WM_COPY (lame implementation, no RTF support)
-  - WM_CUT (lame implementation, no RTF support)
+  + WM_COPY
+  + WM_CUT
   + WM_GETDLGCODE (the current implementation is incomplete)
   + WM_GETTEXT (ANSI&Unicode)
   + WM_GETTEXTLENGTH (ANSI version sucks)
-  - WM_PASTE
+  + WM_PASTE
   - WM_SETFONT
   + WM_SETTEXT (resets undo stack !) (proper style?) ANSI&Unicode
   - WM_STYLECHANGING
   - EN_MSGFILTER
   - EN_OLEOPFAILED
   - EN_PROTECTED
-  - EN_REQUESTRESIZE
+  + EN_REQUESTRESIZE
   - EN_SAVECLIPBOARD
   + EN_SELCHANGE 
   + EN_SETFOCUS
 /*
  * RICHED20 TODO (incomplete):
  *
- * - font caching
+ * - messages/styles/notifications listed above 
+ * - Undo coalescing 
  * - add remaining CHARFORMAT/PARAFORMAT fields
  * - right/center align should strip spaces from the beginning
- * - more advanced navigation (Ctrl-arrows, PageUp/PageDn)
+ * - more advanced navigation (Ctrl-arrows)
  * - tabs
- * - pictures (not just smiling faces that lack API support ;-) )
- * - OLE objects
+ * - pictures/OLE objects (not just smiling faces that lack API support ;-) )
+ * - COM interface (looks like a major pain in the TODO list)
  * - calculate heights of pictures (half-done)
- * - EM_STREAMIN/EM_STREAMOUT
  * - horizontal scrolling (not even started)
- * - fix scrollbars and refresh (it sucks bigtime)
  * - hysteresis during wrapping (related to scrollbars appearing/disappearing)
- * - should remember maximum row width for wrap hysteresis
  * - find/replace
  * - how to implement EM_FORMATRANGE and EM_DISPLAYBAND ? (Mission Impossible)
- * - italic cursor with italic fonts
+ * - italic caret with italic fonts
  * - IME
  * - most notifications aren't sent at all (the most important ones are)
  * - when should EN_SELCHANGE be sent after text change ? (before/after EN_UPDATE?)
  * - WM_SETTEXT may use wrong style (but I'm 80% sure it's OK)
  * - EM_GETCHARFORMAT with SCF_SELECTION may not behave 100% like in original (but very close)
- * - bugs in end-of-text handling (the gray bar) could get me in jail ;-)
- * - determination of row size
- * - end-of-paragraph marks should be of reasonable size
+ * - full justification
+ * - hyphenation
+ * - tables
+ * - ListBox & ComboBox not implemented
  *
  * Bugs that are probably fixed, but not so easy to verify:
  * - EN_UPDATE/EN_CHANGE are handled very incorrectly (should be OK now)
  */
 
 #include "editor.h"
-#include <ole2.h>
-#include <richole.h>
-#include <winreg.h>
+#include "commdlg.h"
+#include "ole2.h"
+#include "richole.h"
+#include "winreg.h"
 #define NO_SHLWAPI_STREAM 
-#include <shlwapi.h>
+#include "shlwapi.h"
 
 #include "rtf.h"
  
@@ -216,7 +237,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(richedit);
 int me_debug = 0;
 HANDLE me_heap = NULL;
 
-ME_TextBuffer *ME_MakeText() {
+static BOOL ME_ListBoxRegistered = FALSE;
+static BOOL ME_ComboBoxRegistered = FALSE;
+
+static ME_TextBuffer *ME_MakeText(void) {
   
   ME_TextBuffer *buf = ALLOC_OBJ(ME_TextBuffer);
 
@@ -238,96 +262,555 @@ ME_TextBuffer *ME_MakeText() {
   return buf;
 }
 
-#define STREAMIN_BUFFER_SIZE 4096 /* M$ compatibility */
 
-static LRESULT ME_StreamInText(ME_TextEditor *editor, DWORD dwFormat, EDITSTREAM *stream, ME_Style *style)
+static LRESULT ME_StreamInText(ME_TextEditor *editor, DWORD dwFormat, ME_InStream *stream, ME_Style *style)
 {
-  BYTE buffer[STREAMIN_BUFFER_SIZE+1];
   WCHAR wszText[STREAMIN_BUFFER_SIZE+1];
+  WCHAR *pText;
   
   TRACE("%08lx %p\n", dwFormat, stream);
-  stream->dwError = 0;
   
   do {
-    long nDataSize = 0, nWideChars = 0;
-    stream->dwError = stream->pfnCallback(stream->dwCookie, 
-      (dwFormat & SF_UNICODE ? (BYTE *)wszText : buffer), 
-      STREAMIN_BUFFER_SIZE, &nDataSize);
-    
-    if (stream->dwError)
-      break;
-    if (!nDataSize)
-      break;
+    long nWideChars = 0;
+
+    if (!stream->dwSize)
+    {
+      ME_StreamInFill(stream);
+      if (stream->editstream->dwError)
+        break;
+      if (!stream->dwSize)
+        break;
+    }
       
     if (!(dwFormat & SF_UNICODE))
     {
       /* FIXME? this is doomed to fail on true MBCS like UTF-8, luckily they're unlikely to be used as CP_ACP */
-      nWideChars = MultiByteToWideChar(CP_ACP, 0, buffer, nDataSize, wszText, STREAMIN_BUFFER_SIZE);
+      nWideChars = MultiByteToWideChar(CP_ACP, 0, stream->buffer, stream->dwSize, wszText, STREAMIN_BUFFER_SIZE);
+      pText = wszText;
     }
     else
-      nWideChars = nDataSize>>1;
-    ME_InsertTextFromCursor(editor, 0, wszText, nWideChars, style);
-    if (nDataSize<STREAMIN_BUFFER_SIZE)
+    {
+      nWideChars = stream->dwSize >> 1;
+      pText = (WCHAR *)stream->buffer;
+    }
+    
+    ME_InsertTextFromCursor(editor, 0, pText, nWideChars, style);
+    if (stream->dwSize == 0)
       break;
+    stream->dwSize = 0;
   } while(1);
-  ME_CommitUndo(editor);    
+  ME_CommitUndo(editor);
+  ME_Repaint(editor);
   return 0;
 }
 
+static void ME_RTFCharAttrHook(RTF_Info *info)
+{
+  CHARFORMAT2W fmt;
+  fmt.cbSize = sizeof(fmt);
+  fmt.dwMask = 0;
+  
+  switch(info->rtfMinor)
+  {
+    case rtfPlain:
+      /* FIXME add more flags once they're implemented */
+      fmt.dwMask = CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE | CFM_STRIKEOUT | CFM_COLOR | CFM_BACKCOLOR | CFM_SIZE | CFM_WEIGHT;
+      fmt.dwEffects = CFE_AUTOCOLOR | CFE_AUTOBACKCOLOR;
+      fmt.yHeight = 12*20; /* 12pt */
+      fmt.wWeight = 400;
+      break;
+    case rtfBold:
+      fmt.dwMask = CFM_BOLD;
+      fmt.dwEffects = info->rtfParam ? fmt.dwMask : 0;
+      break;
+    case rtfItalic:
+      fmt.dwMask = CFM_ITALIC;
+      fmt.dwEffects = info->rtfParam ? fmt.dwMask : 0;
+      break;
+    case rtfUnderline:
+      fmt.dwMask = CFM_UNDERLINE;
+      fmt.dwEffects = info->rtfParam ? fmt.dwMask : 0;
+      fmt.bUnderlineType = CFU_CF1UNDERLINE;
+      break;
+    case rtfNoUnderline:
+      fmt.dwMask = CFM_UNDERLINE;
+      fmt.dwEffects = 0;
+      break;
+    case rtfStrikeThru:
+      fmt.dwMask = CFM_STRIKEOUT;
+      fmt.dwEffects = info->rtfParam ? fmt.dwMask : 0;
+      break;
+    case rtfSubScript:
+    case rtfSuperScript:
+    case rtfSubScrShrink:
+    case rtfSuperScrShrink:
+    case rtfNoSuperSub:
+      fmt.dwMask = CFM_SUBSCRIPT|CFM_SUPERSCRIPT;
+      if (info->rtfMinor == rtfSubScrShrink) fmt.dwEffects = CFE_SUBSCRIPT;
+      if (info->rtfMinor == rtfSuperScrShrink) fmt.dwEffects = CFE_SUPERSCRIPT;
+      if (info->rtfMinor == rtfNoSuperSub) fmt.dwEffects = 0;
+      break;
+    case rtfBackColor:
+      fmt.dwMask = CFM_BACKCOLOR;
+      fmt.dwEffects = 0;
+      if (info->rtfParam == 0)
+        fmt.dwEffects = CFE_AUTOBACKCOLOR;
+      else if (info->rtfParam != rtfNoParam)
+      {
+        RTFColor *c = RTFGetColor(info, info->rtfParam);
+        fmt.crTextColor = (c->rtfCBlue<<16)|(c->rtfCGreen<<8)|(c->rtfCRed);
+      }
+      break;
+    case rtfForeColor:
+      fmt.dwMask = CFM_COLOR;
+      fmt.dwEffects = 0;
+      if (info->rtfParam == 0)
+        fmt.dwEffects = CFE_AUTOCOLOR;
+      else if (info->rtfParam != rtfNoParam)
+      {
+        RTFColor *c = RTFGetColor(info, info->rtfParam);
+        fmt.crTextColor = (c->rtfCBlue<<16)|(c->rtfCGreen<<8)|(c->rtfCRed);
+      }
+      break;
+    case rtfFontNum:
+      if (info->rtfParam != rtfNoParam)
+      {
+        RTFFont *f = RTFGetFont(info, info->rtfParam);
+        if (f)
+        {
+          MultiByteToWideChar(CP_ACP, 0, f->rtfFName, -1, fmt.szFaceName, sizeof(fmt.szFaceName)/sizeof(WCHAR));
+          fmt.szFaceName[sizeof(fmt.szFaceName)/sizeof(WCHAR)-1] = '\0';
+          fmt.bCharSet = f->rtfFCharSet;
+          fmt.dwMask = CFM_FACE | CFM_CHARSET;
+        }
+      }
+      break;
+    case rtfFontSize:
+      fmt.dwMask = CFM_SIZE;
+      if (info->rtfParam != rtfNoParam)
+        fmt.yHeight = info->rtfParam*10;
+      break;
+  }
+  if (fmt.dwMask) {
+    ME_Style *style2;
+    RTFFlushOutputBuffer(info);
+    /* FIXME too slow ? how come ? */
+    style2 = ME_ApplyStyle(info->style, &fmt);
+    ME_ReleaseStyle(info->style);
+    info->style = style2;
+    info->styleChanged = TRUE;
+  }
+}
+
+/* FIXME this function doesn't get any information about context of the RTF tag, which is very bad,
+   the same tags mean different things in different contexts */
+static void ME_RTFParAttrHook(RTF_Info *info)
+{
+  PARAFORMAT2 fmt;
+  fmt.cbSize = sizeof(fmt);
+  fmt.dwMask = 0;
+  
+  switch(info->rtfMinor)
+  {
+  case rtfParDef: /* I'm not 100% sure what does it do, but I guess it restores default paragraph attributes */
+    fmt.dwMask = PFM_ALIGNMENT | PFM_TABSTOPS | PFM_OFFSET | PFM_STARTINDENT;
+    fmt.wAlignment = PFA_LEFT;
+    fmt.cTabCount = 0;
+    fmt.dxOffset = fmt.dxStartIndent = 0;
+    break;
+  case rtfFirstIndent:
+    ME_GetSelectionParaFormat(info->editor, &fmt);
+    fmt.dwMask = PFM_STARTINDENT;
+    fmt.dxStartIndent = info->rtfParam + fmt.dxOffset;
+    break;
+  case rtfLeftIndent:
+  {
+    int first, left;
+    ME_GetSelectionParaFormat(info->editor, &fmt);
+    first = fmt.dxStartIndent;
+    left = info->rtfParam;
+    fmt.dwMask = PFM_STARTINDENT|PFM_OFFSET;
+    fmt.dxStartIndent = first + left;
+    fmt.dxOffset = -first;
+    break;
+  }
+  case rtfRightIndent:
+    fmt.dwMask = PFM_RIGHTINDENT;
+    fmt.dxRightIndent = info->rtfParam;
+    break;
+  case rtfQuadLeft:
+  case rtfQuadJust:
+    fmt.dwMask = PFM_ALIGNMENT;
+    fmt.wAlignment = PFA_LEFT;
+    break;
+  case rtfQuadRight:
+    fmt.dwMask = PFM_ALIGNMENT;
+    fmt.wAlignment = PFA_RIGHT;
+    break;
+  case rtfQuadCenter:
+    fmt.dwMask = PFM_ALIGNMENT;
+    fmt.wAlignment = PFA_CENTER;
+    break;
+  case rtfTabPos:
+    ME_GetSelectionParaFormat(info->editor, &fmt);
+    if (!(fmt.dwMask & PFM_TABSTOPS))
+    {
+      fmt.dwMask |= PFM_TABSTOPS;
+      fmt.cTabCount = 0;
+    }
+    if (fmt.cTabCount < MAX_TAB_STOPS)
+      fmt.rgxTabs[fmt.cTabCount++] = info->rtfParam;
+    break;
+  }  
+  if (fmt.dwMask) {
+    RTFFlushOutputBuffer(info);
+    /* FIXME too slow ? how come ?*/
+    ME_SetSelectionParaFormat(info->editor, &fmt);
+  }
+}
+
+static void ME_RTFReadHook(RTF_Info *info) {
+  switch(info->rtfClass)
+  {
+    case rtfGroup:
+      switch(info->rtfMajor)
+      {
+        case rtfBeginGroup:
+          if (info->stackTop < maxStack) {
+            memcpy(&info->stack[info->stackTop].fmt, &info->style->fmt, sizeof(CHARFORMAT2W));
+            info->stack[info->stackTop].codePage = info->codePage;
+            info->stack[info->stackTop].unicodeLength = info->unicodeLength;
+          }
+          info->stackTop++;
+          info->styleChanged = FALSE;
+          break;
+        case rtfEndGroup:
+        {
+          ME_Style *s;
+          RTFFlushOutputBuffer(info);
+          if (info->stackTop<=1) {
+            info->rtfClass = rtfEOF;
+            return;
+          }
+          info->stackTop--;
+          assert(info->stackTop >= 0);
+          if (info->styleChanged)
+          {
+            /* FIXME too slow ? how come ? */
+            s = ME_ApplyStyle(info->style, &info->stack[info->stackTop].fmt);
+            ME_ReleaseStyle(info->style);
+            info->style = s;
+            info->codePage = info->stack[info->stackTop].codePage;
+            info->unicodeLength = info->stack[info->stackTop].unicodeLength;
+          }
+          break;
+        }
+      }
+      break;
+    case rtfControl:
+      switch(info->rtfMajor)
+      {
+        case rtfCharAttr:
+          ME_RTFCharAttrHook(info);
+          break;
+        case rtfParAttr:
+          ME_RTFParAttrHook(info);
+          break;
+      }
+      break;
+  }
+}
+
+void
+ME_StreamInFill(ME_InStream *stream)
+{
+  stream->editstream->dwError = stream->editstream->pfnCallback(stream->editstream->dwCookie,
+                                                                (BYTE *)stream->buffer,
+                                                                sizeof(stream->buffer),
+                                                                (LONG *)&stream->dwSize);
+  stream->dwUsed = 0;
+}
+
 static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stream)
 {
   RTF_Info parser;
   ME_Style *style;
+  int from, to, to2, nUndoMode;
+  ME_UndoItem *pUI;
+  int nEventMask = editor->nEventMask;
+  ME_InStream inStream;
 
-  TRACE("%p %p\n", stream, editor->hWnd);
+  TRACE("stream==%p hWnd==%p format==0x%X\n", stream, editor->hWnd, (UINT)format);
+  editor->nEventMask = 0;
   
+  ME_GetSelection(editor, &from, &to);
   if (format & SFF_SELECTION) {
     style = ME_GetSelectionInsertStyle(editor);
-    SendMessageW(editor->hWnd, WM_CLEAR, 0, 0);
+
+    ME_InternalDeleteText(editor, from, to-from);
   }
   else {
     style = editor->pBuffer->pDefaultStyle;
     ME_AddRefStyle(style);
     SendMessageA(editor->hWnd, EM_SETSEL, 0, 0);    
-    SetWindowTextA(editor->hWnd, "");
+    ME_InternalDeleteText(editor, 0, ME_GetTextLength(editor));
+    from = to = 0;
     ME_ClearTempStyle(editor);
+    /* FIXME restore default paragraph formatting ! */
+  }
+  
+  nUndoMode = editor->nUndoMode;
+  editor->nUndoMode = umIgnore;
+
+  inStream.editstream = stream;
+  inStream.editstream->dwError = 0;
+  inStream.dwSize = 0;
+  inStream.dwUsed = 0;
+
+  if (format & SF_RTF)
+  {
+    /* Check if it's really RTF, and if it is not, use plain text */
+    ME_StreamInFill(&inStream);
+    if (!inStream.editstream->dwError)
+    {
+      if (strncmp(inStream.buffer, "{\\rtf1", 6) && strncmp(inStream.buffer, "{\\urtf", 6))
+      {
+        format &= ~SF_RTF;
+        format |= SF_TEXT;
+      }
+    }
   }
 
-  if (format & SF_RTF) {
-    /* setup the RTF parser */
-    memset(&parser, 0, sizeof parser);
-    RTFSetEditStream(&parser, stream);
-    parser.rtfFormat = format&(SF_TEXT|SF_RTF);
-    parser.hwndEdit = editor->hWnd;
-    WriterInit(&parser);
-    RTFInit(&parser);
-    BeginFile(&parser);
+  if (!inStream.editstream->dwError)
+  {
+    if (format & SF_RTF) {
+      /* setup the RTF parser */
+      memset(&parser, 0, sizeof parser);
+      RTFSetEditStream(&parser, &inStream);
+      parser.rtfFormat = format&(SF_TEXT|SF_RTF);
+      parser.hwndEdit = editor->hWnd;
+      parser.editor = editor;
+      parser.style = style;
+      WriterInit(&parser);
+      RTFInit(&parser);
+      RTFSetReadHook(&parser, ME_RTFReadHook);
+      BeginFile(&parser);
   
-    /* do the parsing */
-    RTFRead(&parser);
-    RTFFlushOutputBuffer(&parser);
+      /* do the parsing */
+      RTFRead(&parser);
+      RTFFlushOutputBuffer(&parser);
+      RTFDestroy(&parser);
+
+      style = parser.style;
+    }
+    else if (format & SF_TEXT)
+      ME_StreamInText(editor, format, &inStream, style);
+    else
+      ERR("EM_STREAMIN without SF_TEXT or SF_RTF\n");
+    ME_GetSelection(editor, &to, &to2);
+    /* put the cursor at the top */
+    if (!(format & SFF_SELECTION))
+      SendMessageA(editor->hWnd, EM_SETSEL, 0, 0);
+    else
+    {
+      /* FIXME where to put cursor now ? */
+    }
   }
-  else if (format & SF_TEXT)
-    ME_StreamInText(editor, format, stream, style);
-  else
-    ERR("EM_STREAMIN without SF_TEXT or SF_RTF\n");
-  /* put the cursor at the top */
-  if (!(format & SFF_SELECTION))
-    SendMessageA(editor->hWnd, EM_SETSEL, 0, 0);
-  else
+  
+  editor->nUndoMode = nUndoMode;
+  pUI = ME_AddUndoItem(editor, diUndoDeleteRun, NULL);
+  TRACE("from %d to %d\n", from, to);
+  if (pUI && from < to)
   {
-    /* FIXME where to put cursor now ? */
+    pUI->nStart = from;
+    pUI->nLen = to-from;
+  }
+  ME_CommitUndo(editor);
+  ME_ReleaseStyle(style); 
+  editor->nEventMask = nEventMask;
+  if (editor->bRedraw)
+  {
+    InvalidateRect(editor->hWnd, NULL, TRUE);
+    ME_UpdateRepaint(editor);
   }
-  ME_ReleaseStyle(style);
+  if (!(format & SFF_SELECTION)) {
+    ME_ClearTempStyle(editor);
+  }
+  ME_MoveCaret(editor);
+  ME_SendSelChange(editor);
+  ME_SendRequestResize(editor, FALSE);
 
   return 0;
 }
 
+
+ME_DisplayItem *
+ME_FindItemAtOffset(ME_TextEditor *editor, ME_DIType nItemType, int nOffset, int *nItemOffset)
+{
+  ME_DisplayItem *item = ME_FindItemFwd(editor->pBuffer->pFirst, diParagraph);
+  
+  while (item && item->member.para.next_para->member.para.nCharOfs <= nOffset)
+    item = ME_FindItemFwd(item, diParagraph);
+
+  if (!item)
+    return item;
+
+  nOffset -= item->member.para.nCharOfs;
+  if (nItemType == diParagraph) {
+    if (nItemOffset)
+      *nItemOffset = nOffset;
+    return item;
+  }
+  
+  do {
+    item = ME_FindItemFwd(item, diRun);
+  } while (item && (item->member.run.nCharOfs + ME_StrLen(item->member.run.strText) <= nOffset));
+  if (item) {
+    nOffset -= item->member.run.nCharOfs;
+    if (nItemOffset)
+      *nItemOffset = nOffset;
+  }
+  return item;
+}
+
+
+static int
+ME_FindText(ME_TextEditor *editor, DWORD flags, CHARRANGE *chrg, WCHAR *text, CHARRANGE *chrgText)
+{
+  int nStart, nEnd;
+  int nLen = lstrlenW(text);
+  int nMin, nMax;
+  ME_DisplayItem *item;
+  ME_DisplayItem *para;
+
+  TRACE("flags==0x%08lx, chrg->cpMin==%ld, chrg->cpMax==%ld text==%s\n",
+        flags, chrg->cpMin, chrg->cpMax, debugstr_w(text));
+  
+  if (!(flags & FR_MATCHCASE))
+    FIXME("Case-insensitive search not implemented\n");
+  if (flags & ~(FR_DOWN | FR_MATCHCASE))
+    FIXME("Flags 0x%08lx not implemented\n", flags & ~(FR_DOWN | FR_MATCHCASE));
+
+  if (chrg->cpMax == -1)
+  {
+    nMin = chrg->cpMin;
+    nMax = ME_GetTextLength(editor);
+  }
+  else
+  {
+    nMin = min(chrg->cpMin, chrg->cpMax);
+    nMax = max(chrg->cpMin, chrg->cpMax);
+  }
+  
+  if (!nLen)
+  {
+    if (chrgText)
+      chrgText->cpMin = chrgText->cpMax = ((flags & FR_DOWN) ? nMin : nMax);
+    return chrgText->cpMin;
+  }
+  if (flags & FR_DOWN) /* Forward search */
+  {
+    nStart = nMin;
+    item = ME_FindItemAtOffset(editor, diRun, nStart, &nStart);
+    if (!item)
+      return -1;
+
+    para = ME_GetParagraph(item);
+    while (item
+           && para->member.para.nCharOfs + item->member.run.nCharOfs + nStart + nLen < nMax)
+    {
+      ME_DisplayItem *pCurItem = item;
+      int nCurStart = nStart;
+      int nMatched = 0;
+    
+      while (pCurItem && pCurItem->member.run.strText->szData[nCurStart + nMatched] == text[nMatched])
+      {
+        nMatched++;
+        if (nMatched == nLen)
+        {
+          nStart += para->member.para.nCharOfs + item->member.run.nCharOfs;
+          if (chrgText)
+          {
+            chrgText->cpMin = nStart;
+            chrgText->cpMax = nStart + nLen;
+          }
+          TRACE("found at %d-%d\n", nStart, nStart + nLen);
+          return nStart;
+        }
+        if (nCurStart + nMatched == ME_StrLen(pCurItem->member.run.strText))
+        {
+          pCurItem = ME_FindItemFwd(pCurItem, diRun);
+          para = ME_GetParagraph(pCurItem);
+          nCurStart = -nMatched;
+        }
+      }
+      nStart++;
+      if (nStart == ME_StrLen(item->member.run.strText))
+      {
+        item = ME_FindItemFwd(item, diRun);
+        para = ME_GetParagraph(item);
+        nStart = 0;
+      }
+    }
+  }
+  else /* Backward search */
+  {
+    nEnd = nMax;
+    item = ME_FindItemAtOffset(editor, diRun, nEnd, &nEnd);
+    if (!item)
+      return -1;
+    
+    para = ME_GetParagraph(item);
+    
+    while (item
+           && para->member.para.nCharOfs + item->member.run.nCharOfs + nEnd - nLen >= nMin)
+    {
+      ME_DisplayItem *pCurItem = item;
+      int nCurEnd = nEnd;
+      int nMatched = 0;
+      
+      while (pCurItem && pCurItem->member.run.strText->szData[nCurEnd - nMatched - 1] == text[nLen - nMatched - 1])
+      {
+        nMatched++;
+        if (nMatched == nLen)
+        {
+          nStart = para->member.para.nCharOfs + item->member.run.nCharOfs + nCurEnd - nMatched;
+          if (chrgText)
+          {
+            chrgText->cpMin = nStart;
+            chrgText->cpMax = nStart + nLen;
+          }
+          TRACE("found at %d-%d\n", nStart, nStart + nLen);
+          return nStart;
+        }
+        if (nCurEnd - nMatched == 0)
+        {
+          pCurItem = ME_FindItemBack(pCurItem, diRun);
+          para = ME_GetParagraph(pCurItem);
+          nCurEnd = ME_StrLen(pCurItem->member.run.strText) + nMatched;
+        }
+      }
+      nEnd--;
+      if (nEnd < 0)
+      {
+        item = ME_FindItemBack(item, diRun);
+        para = ME_GetParagraph(item);
+        nEnd = ME_StrLen(item->member.run.strText);
+      }
+    }
+  }
+  TRACE("not found\n");
+  return -1;
+}
+
+
 ME_TextEditor *ME_MakeEditor(HWND hWnd) {
   ME_TextEditor *ed = ALLOC_OBJ(ME_TextEditor);
   HDC hDC;
   int i;
   ed->hWnd = hWnd;
+  ed->bEmulateVersion10 = FALSE;
   ed->pBuffer = ME_MakeText();
   hDC = GetDC(hWnd);
   ME_MakeFirstParagraph(hDC, ed->pBuffer);
@@ -340,10 +823,10 @@ ME_TextEditor *ME_MakeEditor(HWND hWnd) {
   ed->pCursors[1].pRun = ME_FindItemFwd(ed->pBuffer->pFirst, diRun);
   ed->pCursors[1].nOffset = 0;
   ed->nLastTotalLength = ed->nTotalLength = 0;
-  ed->nScrollPos = 0;
   ed->nUDArrowX = -1;
   ed->nSequence = 0;
   ed->rgbBackColor = -1;
+  ed->hbrBackground = GetSysColorBrush(COLOR_WINDOW);
   ed->bCaretAtEnd = FALSE;
   ed->nEventMask = 0;
   ed->nModifyStep = 0;
@@ -351,6 +834,10 @@ ME_TextEditor *ME_MakeEditor(HWND hWnd) {
   ed->nUndoMode = umAddToUndo;
   ed->nParagraphs = 1;
   ed->nLastSelStart = ed->nLastSelEnd = 0;
+  ed->nScrollPosY = 0;
+  ed->nZoomNumerator = ed->nZoomDenominator = 0;
+  ed->bRedraw = TRUE;
+  GetClientRect(hWnd, &ed->rcFormat);
   for (i=0; i<HFONT_CACHE_SIZE; i++)
   {
     ed->pFontCache[i].nRefs = 0;
@@ -361,6 +848,71 @@ ME_TextEditor *ME_MakeEditor(HWND hWnd) {
   return ed;
 }
 
+typedef struct tagME_GlobalDestStruct
+{
+  HGLOBAL hData;
+  int nLength;
+} ME_GlobalDestStruct;
+
+static DWORD CALLBACK ME_AppendToHGLOBAL(DWORD_PTR dwCookie, LPBYTE lpBuff, LONG cb, LONG *pcb)
+{
+  ME_GlobalDestStruct *pData = (ME_GlobalDestStruct *)dwCookie;
+  int nMaxSize;
+  BYTE *pDest;
+  
+  nMaxSize = GlobalSize(pData->hData);
+  if (pData->nLength+cb+1 >= cb)
+  {
+    /* round up to 2^17 */
+    int nNewSize = (((nMaxSize+cb+1)|0x1FFFF)+1) & 0xFFFE0000;
+    pData->hData = GlobalReAlloc(pData->hData, nNewSize, 0);
+  }
+  pDest = (BYTE *)GlobalLock(pData->hData);
+  memcpy(pDest + pData->nLength, lpBuff, cb);
+  pData->nLength += cb;
+  pDest[pData->nLength] = '\0';
+  GlobalUnlock(pData->hData);
+  *pcb = cb;
+  
+  return 0;
+}
+
+static DWORD CALLBACK ME_ReadFromHGLOBALUnicode(DWORD_PTR dwCookie, LPBYTE lpBuff, LONG cb, LONG *pcb)
+{
+  ME_GlobalDestStruct *pData = (ME_GlobalDestStruct *)dwCookie;
+  int i;
+  WORD *pSrc, *pDest;
+  
+  cb = cb >> 1;
+  pDest = (WORD *)lpBuff;
+  pSrc = (WORD *)GlobalLock(pData->hData);
+  for (i = 0; i<cb && pSrc[pData->nLength+i]; i++) {
+    pDest[i] = pSrc[pData->nLength+i];
+  }    
+  pData->nLength += i;
+  *pcb = 2*i;
+  GlobalUnlock(pData->hData);
+  return 0;
+}
+
+static DWORD CALLBACK ME_ReadFromHGLOBALRTF(DWORD_PTR dwCookie, LPBYTE lpBuff, LONG cb, LONG *pcb)
+{
+  ME_GlobalDestStruct *pData = (ME_GlobalDestStruct *)dwCookie;
+  int i;
+  BYTE *pSrc, *pDest;
+  
+  pDest = lpBuff;
+  pSrc = (BYTE *)GlobalLock(pData->hData);
+  for (i = 0; i<cb && pSrc[pData->nLength+i]; i++) {
+    pDest[i] = pSrc[pData->nLength+i];
+  }    
+  pData->nLength += i;
+  *pcb = i;
+  GlobalUnlock(pData->hData);
+  return 0;
+}
+
+
 void ME_DestroyEditor(ME_TextEditor *editor)
 {
   ME_DisplayItem *pFirst = editor->pBuffer->pFirst;
@@ -380,77 +932,243 @@ void ME_DestroyEditor(ME_TextEditor *editor)
     if (editor->pFontCache[i].hFont)
       DeleteObject(editor->pFontCache[i].hFont);
   }
-    
+  DeleteObject(editor->hbrBackground);
+
   FREE_OBJ(editor);
 }
 
+static WCHAR wszClassName[] = {'R', 'i', 'c', 'h', 'E', 'd', 'i', 't', '2', '0', 'W', 0};
+static WCHAR wszClassName50[] = {'R', 'i', 'c', 'h', 'E', 'd', 'i', 't', '5', '0', 'W', 0};
+static WCHAR wszClassNameListBox[] = {'R','E','L','i','s','t','B','o','x','2','0','W', 0};
+static WCHAR wszClassNameComboBox[] = {'R','E','C','o','m','b','o','B','o','x','2','0','W', 0};
+
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+    TRACE("\n");
+    switch (fdwReason)
+    {
+    case DLL_PROCESS_ATTACH:
+      DisableThreadLibraryCalls(hinstDLL);
+      me_heap = HeapCreate (0, 0x10000, 0);
+      ME_RegisterEditorClass(hinstDLL);
+      break;
+
+    case DLL_PROCESS_DETACH:
+      UnregisterClassW(wszClassName, 0);
+      UnregisterClassW(wszClassName50, 0);
+      UnregisterClassA("RichEdit20A", 0);
+      UnregisterClassA("RichEdit50A", 0);
+      if (ME_ListBoxRegistered)
+          UnregisterClassW(wszClassNameListBox, 0);
+      if (ME_ComboBoxRegistered)
+          UnregisterClassW(wszClassNameComboBox, 0);
+      HeapDestroy (me_heap);
+      me_heap = NULL;
+      break;
+    }
+    return TRUE;
+}
+
+
 #define UNSUPPORTED_MSG(e) \
   case e: \
     FIXME(#e ": stub\n"); \
     return DefWindowProcW(hWnd, msg, wParam, lParam);
 
+static const char * const edit_messages[] = {
+  "EM_GETSEL",
+  "EM_SETSEL",
+  "EM_GETRECT",
+  "EM_SETRECT",
+  "EM_SETRECTNP",
+  "EM_SCROLL",
+  "EM_LINESCROLL",
+  "EM_SCROLLCARET",
+  "EM_GETMODIFY",
+  "EM_SETMODIFY",
+  "EM_GETLINECOUNT",
+  "EM_LINEINDEX",
+  "EM_SETHANDLE",
+  "EM_GETHANDLE",
+  "EM_GETTHUMB",
+  "EM_UNKNOWN_BF",
+  "EM_UNKNOWN_C0",
+  "EM_LINELENGTH",
+  "EM_REPLACESEL",
+  "EM_UNKNOWN_C3",
+  "EM_GETLINE",
+  "EM_LIMITTEXT",
+  "EM_CANUNDO",
+  "EM_UNDO",
+  "EM_FMTLINES",
+  "EM_LINEFROMCHAR",
+  "EM_UNKNOWN_CA",
+  "EM_SETTABSTOPS",
+  "EM_SETPASSWORDCHAR",
+  "EM_EMPTYUNDOBUFFER",
+  "EM_GETFIRSTVISIBLELINE",
+  "EM_SETREADONLY",
+  "EM_SETWORDBREAKPROC",
+  "EM_GETWORDBREAKPROC",
+  "EM_GETPASSWORDCHAR",
+  "EM_SETMARGINS",
+  "EM_GETMARGINS",
+  "EM_GETLIMITTEXT",
+  "EM_POSFROMCHAR",
+  "EM_CHARFROMPOS"
+};
+
+static const char * const richedit_messages[] = {
+  "EM_CANPASTE",
+  "EM_DISPLAYBAND",
+  "EM_EXGETSEL",
+  "EM_EXLIMITTEXT",
+  "EM_EXLINEFROMCHAR",
+  "EM_EXSETSEL",
+  "EM_FINDTEXT",
+  "EM_FORMATRANGE",
+  "EM_GETCHARFORMAT",
+  "EM_GETEVENTMASK",
+  "EM_GETOLEINTERFACE",
+  "EM_GETPARAFORMAT",
+  "EM_GETSELTEXT",
+  "EM_HIDESELECTION",
+  "EM_PASTESPECIAL",
+  "EM_REQUESTRESIZE",
+  "EM_SELECTIONTYPE",
+  "EM_SETBKGNDCOLOR",
+  "EM_SETCHARFORMAT",
+  "EM_SETEVENTMASK",
+  "EM_SETOLECALLBACK",
+  "EM_SETPARAFORMAT",
+  "EM_SETTARGETDEVICE",
+  "EM_STREAMIN",
+  "EM_STREAMOUT",
+  "EM_GETTEXTRANGE",
+  "EM_FINDWORDBREAK",
+  "EM_SETOPTIONS",
+  "EM_GETOPTIONS",
+  "EM_FINDTEXTEX",
+  "EM_GETWORDBREAKPROCEX",
+  "EM_SETWORDBREAKPROCEX",
+  "EM_SETUNDOLIMIT",
+  "EM_UNKNOWN_USER_83",
+  "EM_REDO",
+  "EM_CANREDO",
+  "EM_GETUNDONAME",
+  "EM_GETREDONAME",
+  "EM_STOPGROUPTYPING",
+  "EM_SETTEXTMODE",
+  "EM_GETTEXTMODE",
+  "EM_AUTOURLDETECT",
+  "EM_GETAUTOURLDETECT",
+  "EM_SETPALETTE",
+  "EM_GETTEXTEX",
+  "EM_GETTEXTLENGTHEX",
+  "EM_SHOWSCROLLBAR",
+  "EM_SETTEXTEX",
+  "EM_UNKNOWN_USER_98",
+  "EM_UNKNOWN_USER_99",
+  "EM_SETPUNCTUATION",
+  "EM_GETPUNCTUATION",
+  "EM_SETWORDWRAPMODE",
+  "EM_GETWORDWRAPMODE",
+  "EM_SETIMECOLOR",
+  "EM_GETIMECOLOR",
+  "EM_SETIMEOPTIONS",
+  "EM_GETIMEOPTIONS",
+  "EM_CONVPOSITION",
+  "EM_UNKNOWN_USER_109",
+  "EM_UNKNOWN_USER_110",
+  "EM_UNKNOWN_USER_111",
+  "EM_UNKNOWN_USER_112",
+  "EM_UNKNOWN_USER_113",
+  "EM_UNKNOWN_USER_114",
+  "EM_UNKNOWN_USER_115",
+  "EM_UNKNOWN_USER_116",
+  "EM_UNKNOWN_USER_117",
+  "EM_UNKNOWN_USER_118",
+  "EM_UNKNOWN_USER_119",
+  "EM_SETLANGOPTIONS",
+  "EM_GETLANGOPTIONS",
+  "EM_GETIMECOMPMODE",
+  "EM_FINDTEXTW",
+  "EM_FINDTEXTEXW",
+  "EM_RECONVERSION",
+  "EM_SETIMEMODEBIAS",
+  "EM_GETIMEMODEBIAS"
+};
+
+static const char *
+get_msg_name(UINT msg)
+{
+  if (msg >= EM_GETSEL && msg <= EM_SETLIMITTEXT)
+    return edit_messages[msg - EM_GETSEL];
+  if (msg >= EM_CANPASTE && msg <= EM_GETIMEMODEBIAS)
+    return richedit_messages[msg - EM_CANPASTE];
+  return "";
+}
+
 /******************************************************************
  *        RichEditANSIWndProc (RICHED20.10)
  */
 LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
-  HDC hDC;
-  PAINTSTRUCT ps;
   SCROLLINFO si;
   ME_TextEditor *editor = (ME_TextEditor *)GetWindowLongW(hWnd, 0);
-  TRACE("msg %d %08x %08lx\n", msg, wParam, lParam);
+  
+  TRACE("hWnd %p msg %04x (%s) %08x %08lx\n",
+        hWnd, msg, get_msg_name(msg), wParam, lParam);
+  
   switch(msg) {
   
   UNSUPPORTED_MSG(EM_AUTOURLDETECT)
-  UNSUPPORTED_MSG(EM_CANPASTE)
-  UNSUPPORTED_MSG(EM_CHARFROMPOS)
   UNSUPPORTED_MSG(EM_DISPLAYBAND)
   UNSUPPORTED_MSG(EM_EXLIMITTEXT)
-  UNSUPPORTED_MSG(EM_EXLINEFROMCHAR)
-  UNSUPPORTED_MSG(EM_FINDTEXT)
-  UNSUPPORTED_MSG(EM_FINDTEXTEX)
   UNSUPPORTED_MSG(EM_FINDWORDBREAK)
   UNSUPPORTED_MSG(EM_FMTLINES)
   UNSUPPORTED_MSG(EM_FORMATRANGE)
-  UNSUPPORTED_MSG(EM_GETFIRSTVISIBLELINE)
+  UNSUPPORTED_MSG(EM_GETAUTOURLDETECT)
+  UNSUPPORTED_MSG(EM_GETBIDIOPTIONS)
+  UNSUPPORTED_MSG(EM_GETEDITSTYLE)
   UNSUPPORTED_MSG(EM_GETIMECOMPMODE)
   /* UNSUPPORTED_MSG(EM_GETIMESTATUS) missing in Wine headers */
   UNSUPPORTED_MSG(EM_GETLANGOPTIONS)
   UNSUPPORTED_MSG(EM_GETLIMITTEXT)
   UNSUPPORTED_MSG(EM_GETLINE)
-  UNSUPPORTED_MSG(EM_GETLINECOUNT)
   /* UNSUPPORTED_MSG(EM_GETOLEINTERFACE) separate stub */
   UNSUPPORTED_MSG(EM_GETOPTIONS)
-  UNSUPPORTED_MSG(EM_GETRECT)
+  UNSUPPORTED_MSG(EM_GETPASSWORDCHAR)
   UNSUPPORTED_MSG(EM_GETREDONAME)
+  UNSUPPORTED_MSG(EM_GETSCROLLPOS)
   UNSUPPORTED_MSG(EM_GETTEXTMODE)
+  UNSUPPORTED_MSG(EM_GETTYPOGRAPHYOPTIONS)
   UNSUPPORTED_MSG(EM_GETUNDONAME)
   UNSUPPORTED_MSG(EM_GETWORDBREAKPROC)
   UNSUPPORTED_MSG(EM_GETWORDBREAKPROCEX)
   UNSUPPORTED_MSG(EM_HIDESELECTION)
   UNSUPPORTED_MSG(EM_LIMITTEXT) /* also known as EM_SETLIMITTEXT */
-  UNSUPPORTED_MSG(EM_LINEFROMCHAR)
-  UNSUPPORTED_MSG(EM_LINEINDEX)
-  UNSUPPORTED_MSG(EM_LINELENGTH)
-  UNSUPPORTED_MSG(EM_LINESCROLL)
   UNSUPPORTED_MSG(EM_PASTESPECIAL)
-/*  UNSUPPORTED_MSG(EM_POSFROMCHARS) missing in Wine headers */
-  UNSUPPORTED_MSG(EM_REQUESTRESIZE)
   UNSUPPORTED_MSG(EM_SCROLL)
   UNSUPPORTED_MSG(EM_SCROLLCARET)
   UNSUPPORTED_MSG(EM_SELECTIONTYPE)
+  UNSUPPORTED_MSG(EM_SETBIDIOPTIONS)
+  UNSUPPORTED_MSG(EM_SETEDITSTYLE)
+  UNSUPPORTED_MSG(EM_SETFONTSIZE)
   UNSUPPORTED_MSG(EM_SETLANGOPTIONS)
   UNSUPPORTED_MSG(EM_SETOLECALLBACK)
   UNSUPPORTED_MSG(EM_SETOPTIONS)
-  UNSUPPORTED_MSG(EM_SETRECT)
-  UNSUPPORTED_MSG(EM_SETRECTNP)
+  UNSUPPORTED_MSG(EM_SETPALETTE)
+  UNSUPPORTED_MSG(EM_SETPASSWORDCHAR)
+  UNSUPPORTED_MSG(EM_SETSCROLLPOS)
+  UNSUPPORTED_MSG(EM_SETTABSTOPS)
   UNSUPPORTED_MSG(EM_SETTARGETDEVICE)
   UNSUPPORTED_MSG(EM_SETTEXTMODE)
+  UNSUPPORTED_MSG(EM_SETTYPOGRAPHYOPTIONS)
   UNSUPPORTED_MSG(EM_SETUNDOLIMIT)
   UNSUPPORTED_MSG(EM_SETWORDBREAKPROC)
   UNSUPPORTED_MSG(EM_SETWORDBREAKPROCEX)
-  UNSUPPORTED_MSG(EM_STREAMOUT)
+  UNSUPPORTED_MSG(EM_SHOWSCROLLBAR)
   UNSUPPORTED_MSG(WM_SETFONT)
-  UNSUPPORTED_MSG(WM_PASTE)
   UNSUPPORTED_MSG(WM_STYLECHANGING)
   UNSUPPORTED_MSG(WM_STYLECHANGED)
 /*  UNSUPPORTED_MSG(WM_UNICHAR) FIXME missing in Wine headers */
@@ -459,6 +1177,8 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
   
   case EM_STREAMIN:
    return ME_StreamIn(editor, wParam, (EDITSTREAM*)lParam);
+  case EM_STREAMOUT:
+   return ME_StreamOut(editor, wParam, (EDITSTREAM *)lParam);
   case WM_GETDLGCODE:
   {
     UINT code = DLGC_WANTCHARS|DLGC_WANTARROWS;
@@ -469,6 +1189,7 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
   case WM_NCCREATE:
   {
     CREATESTRUCTW *pcs = (CREATESTRUCTW *)lParam;
+    TRACE("WM_NCCREATE: style 0x%08lx\n", pcs->style);
     editor = ME_MakeEditor(hWnd);
     SetWindowLongW(hWnd, 0, (long)editor);
     pcs = 0; /* ignore */
@@ -479,21 +1200,27 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
     return 0;
   case EM_GETSEL:
   {
-    ME_GetSelection(editor, (int *)wParam, (int *)lParam);
-    if (!((wParam|lParam) & 0xFFFF0000))
-      return (lParam<<16)|wParam;
-    return -1;
+    /* Note: wParam/lParam can be NULL */
+    UINT from, to;
+    PUINT pfrom = wParam ? (PUINT)wParam : &from;
+    PUINT pto = lParam ? (PUINT)lParam : &to;
+    ME_GetSelection(editor, (int *)pfrom, (int *)pto);
+    if ((*pfrom|*pto) & 0xFFFF0000)
+      return -1;
+    return MAKELONG(*pfrom,*pto);
   }
   case EM_EXGETSEL:
   {
     CHARRANGE *pRange = (CHARRANGE *)lParam;
     ME_GetSelection(editor, (int *)&pRange->cpMin, (int *)&pRange->cpMax);
+    TRACE("EM_EXGETSEL = (%ld,%ld)\n", pRange->cpMin, pRange->cpMax);
     return 0;
   }
   case EM_CANUNDO:
     return editor->pUndoStack != NULL;
   case EM_CANREDO:
     return editor->pRedoStack != NULL;
+  case WM_UNDO: /* FIXME: actually not the same */
   case EM_UNDO:
     ME_Undo(editor);
     return 0;
@@ -510,21 +1237,64 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
   case EM_EXSETSEL:
   {
     CHARRANGE *pRange = (CHARRANGE *)lParam;
+    TRACE("EM_EXSETSEL (%ld,%ld)\n", pRange->cpMin, pRange->cpMax);
     ME_SetSelection(editor, pRange->cpMin, pRange->cpMax);
     /* FIXME optimize */
     ME_Repaint(editor);
     ME_SendSelChange(editor);
     return 0;
   }
+  case EM_SETTEXTEX:
+  {
+    LPWSTR wszText = (LPWSTR)lParam;
+    SETTEXTEX *pStruct = (SETTEXTEX *)wParam;
+    size_t len = lstrlenW(wszText);
+    int from, to;
+    ME_Style *style;
+    TRACE("EM_SETTEXEX - %s, flags %d, cp %d\n", debugstr_w(wszText), (int)pStruct->flags, pStruct->codepage);
+    if (pStruct->codepage != 1200) {
+      FIXME("EM_SETTEXTEX only supports unicode right now!\n"); 
+      return 0;
+    }
+    /* FIXME: this should support RTF strings too, according to MSDN */
+    if (pStruct->flags & ST_SELECTION) {
+      ME_GetSelection(editor, &from, &to);
+      style = ME_GetSelectionInsertStyle(editor);
+      ME_InternalDeleteText(editor, from, to - from);
+      ME_InsertTextFromCursor(editor, 0, wszText, len, style);
+      ME_ReleaseStyle(style);
+    }
+    else {
+      ME_InternalDeleteText(editor, 0, ME_GetTextLength(editor));
+      ME_InsertTextFromCursor(editor, 0, wszText, -1, editor->pBuffer->pDefaultStyle);
+      len = 1;
+    }
+    ME_CommitUndo(editor);
+    if (!(pStruct->flags & ST_KEEPUNDO))
+      ME_EmptyUndoStack(editor);
+    ME_UpdateRepaint(editor);
+    return len;
+  }
   case EM_SETBKGNDCOLOR:
   {
     LRESULT lColor = ME_GetBackColor(editor);
+    if (editor->rgbBackColor != -1)
+      DeleteObject(editor->hbrBackground);
     if (wParam)
+    {
       editor->rgbBackColor = -1;
+      editor->hbrBackground = GetSysColorBrush(COLOR_WINDOW);
+    }
     else
-      editor->rgbBackColor = lParam; 
-    InvalidateRect(hWnd, NULL, TRUE);
-    UpdateWindow(hWnd);
+    {
+      editor->rgbBackColor = lParam;
+      editor->hbrBackground = CreateSolidBrush(editor->rgbBackColor);
+    }
+    if (editor->bRedraw)
+    {
+      InvalidateRect(hWnd, NULL, TRUE);
+      UpdateWindow(hWnd);
+    }
     return lColor;
   }
   case EM_GETMODIFY:
@@ -550,44 +1320,104 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
     return 0;
   }
   case EM_SETEVENTMASK:
+  {
+    DWORD nOldMask = editor->nEventMask;
+    
     editor->nEventMask = lParam;
-    return 0;
+    return nOldMask;
+  }
   case EM_GETEVENTMASK:
     return editor->nEventMask;
   case EM_SETCHARFORMAT:
   {
     CHARFORMAT2W buf, *p;
+    BOOL bRepaint = TRUE;
     p = ME_ToCF2W(&buf, (CHARFORMAT2W *)lParam);
     if (!wParam)
       ME_SetDefaultCharFormat(editor, p);
     else if (wParam == (SCF_WORD | SCF_SELECTION))
-      FIXME("word selection not supported\n");
+      FIXME("EM_SETCHARFORMAT: word selection not supported\n");
     else if (wParam == SCF_ALL)
       ME_SetCharFormat(editor, 0, ME_GetTextLength(editor), p);
-    else
+    else {
+      int from, to;
+      ME_GetSelection(editor, &from, &to);
+      bRepaint = (from != to);
       ME_SetSelectionCharFormat(editor, p);
+    }
     ME_CommitUndo(editor);
-    ME_UpdateRepaint(editor);
+    if (bRepaint)
+      ME_UpdateRepaint(editor);
     return 0;
   }
   case EM_GETCHARFORMAT:
   {
-    CHARFORMAT2W tmp;
+    CHARFORMAT2W tmp, *dst = (CHARFORMAT2W *)lParam;
+    if (dst->cbSize != sizeof(CHARFORMATA) &&
+        dst->cbSize != sizeof(CHARFORMATW) &&
+        dst->cbSize != sizeof(CHARFORMAT2A) &&
+        dst->cbSize != sizeof(CHARFORMAT2W))
+      return 0;
     tmp.cbSize = sizeof(tmp);
     if (!wParam)
       ME_GetDefaultCharFormat(editor, &tmp);
     else
       ME_GetSelectionCharFormat(editor, &tmp);
-    ME_CopyToCFAny((CHARFORMAT2W *)lParam, &tmp);
-    return 0;
+    ME_CopyToCFAny(dst, &tmp);
+    return tmp.dwMask;
   }
   case EM_SETPARAFORMAT:
     ME_SetSelectionParaFormat(editor, (PARAFORMAT2 *)lParam);
+    ME_UpdateRepaint(editor);
     ME_CommitUndo(editor);
     return 0;
   case EM_GETPARAFORMAT:
     ME_GetSelectionParaFormat(editor, (PARAFORMAT2 *)lParam);
     return 0;
+  case EM_GETFIRSTVISIBLELINE:
+  {
+    ME_DisplayItem *p = editor->pBuffer->pFirst;
+    int y = editor->nScrollPosY;
+    int ypara = 0;
+    int count = 0;
+    int ystart, yend;
+    while(p) {
+      p = ME_FindItemFwd(p, diStartRowOrParagraphOrEnd);
+      if (p->type == diTextEnd)
+        break;
+      if (p->type == diParagraph) {
+        ypara = p->member.para.nYPos;
+        continue;
+      }
+      ystart = ypara + p->member.row.nYPos;
+      yend = ystart + p->member.row.nHeight;
+      if (y < yend) {
+        break;
+      }
+      count++;
+    }
+    return count;
+  }
+  case EM_LINESCROLL:
+  {
+    int nPos = editor->nScrollPosY, nEnd= editor->nTotalLength - editor->sizeWindow.cy;
+    nPos += 8 * lParam; /* FIXME follow the original */
+    if (nPos>=nEnd)
+      nPos = nEnd;
+    if (nPos<0)
+      nPos = 0;
+    if (nPos != editor->nScrollPosY) {
+      int dy = editor->nScrollPosY - nPos;
+      editor->nScrollPosY = nPos;
+      SetScrollPos(hWnd, SB_VERT, nPos, TRUE);
+      if (editor->bRedraw)
+      {
+        ScrollWindow(hWnd, 0, dy, NULL, NULL);
+        UpdateWindow(hWnd);
+      }
+    }
+    return TRUE; /* Should return false if a single line richedit control */
+  }
   case WM_CLEAR:
   {
     int from, to;
@@ -624,23 +1454,69 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
   }
   case WM_SETTEXT:
   {
-    LPWSTR wszText = ME_ToUnicode(hWnd, (void *)lParam);
-    TRACE("WM_SETTEXT - %s\n", (char *)(wszText)); /* debugstr_w() */
     ME_InternalDeleteText(editor, 0, ME_GetTextLength(editor));
-    /* uses default style! */
-    ME_InsertTextFromCursor(editor, 0, wszText, -1, editor->pBuffer->pDefaultStyle);
-    ME_EndToUnicode(hWnd, wszText);
+    if (lParam)
+    {
+      LPWSTR wszText = ME_ToUnicode(hWnd, (void *)lParam);
+      TRACE("WM_SETTEXT lParam==%lx\n",lParam);
+      TRACE("WM_SETTEXT - %s\n", debugstr_w(wszText)); /* debugstr_w() */
+      if (lstrlenW(wszText) > 0)
+      {
+        /* uses default style! */
+        ME_InsertTextFromCursor(editor, 0, wszText, -1, editor->pBuffer->pDefaultStyle);
+      }
+      ME_EndToUnicode(hWnd, wszText);
+    }
+    else
+      TRACE("WM_SETTEXT - NULL\n");
     ME_CommitUndo(editor);
     ME_EmptyUndoStack(editor);
     ME_UpdateRepaint(editor);
     return 0;
   }
+  case EM_CANPASTE:
+  {
+    UINT nRTFFormat = RegisterClipboardFormatA("Rich Text Format");
+    if (IsClipboardFormatAvailable(nRTFFormat))
+      return TRUE;
+    if (IsClipboardFormatAvailable(CF_UNICODETEXT))
+      return TRUE;
+    return FALSE;
+  }
+  case WM_PASTE:
+  {    
+    DWORD dwFormat = 0;
+    EDITSTREAM es;
+    ME_GlobalDestStruct gds;
+    UINT nRTFFormat = RegisterClipboardFormatA("Rich Text Format");
+    UINT cf = 0;
+
+    if (IsClipboardFormatAvailable(nRTFFormat))
+      cf = nRTFFormat, dwFormat = SF_RTF;
+    else if (IsClipboardFormatAvailable(CF_UNICODETEXT))
+      cf = CF_UNICODETEXT, dwFormat = SF_TEXT|SF_UNICODE;
+    else
+      return 0;
+
+    if (!OpenClipboard(hWnd))
+      return 0;
+    gds.hData = GetClipboardData(cf);
+    gds.nLength = 0;
+    es.dwCookie = (DWORD)&gds;
+    es.pfnCallback = dwFormat == SF_RTF ? ME_ReadFromHGLOBALRTF : ME_ReadFromHGLOBALUnicode;
+    SendMessageW(hWnd, EM_STREAMIN, dwFormat|SFF_SELECTION, (LPARAM)&es);
+    
+    CloseClipboard();
+    return 0;
+  }
   case WM_CUT:
   case WM_COPY:
   {
     int from, to, pars;
     WCHAR *data;
     HANDLE hData;
+    EDITSTREAM es;
+    ME_GlobalDestStruct gds;
     
     if (!OpenClipboard(hWnd))
       return 0;
@@ -652,7 +1528,17 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
     data = (WCHAR *)GlobalLock(hData);
     ME_GetTextW(editor, data, from, to-from, TRUE);
     GlobalUnlock(hData);
-    SetClipboardData(CF_UNICODETEXT, hData);
+
+    gds.hData = GlobalAlloc(GMEM_MOVEABLE, 0);
+    gds.nLength = 0;
+    es.dwCookie = (DWORD)&gds;
+    es.pfnCallback = ME_AppendToHGLOBAL;
+    SendMessageW(hWnd, EM_STREAMOUT, SFF_SELECTION|SF_RTF, (LPARAM)&es);
+    GlobalReAlloc(gds.hData, gds.nLength+1, 0);
+    
+    SetClipboardData(CF_UNICODETEXT, hData);    
+    SetClipboardData(RegisterClipboardFormatA("Rich Text Format"), gds.hData);
+    
     CloseClipboard();
     if (msg == WM_CUT)
     {
@@ -664,6 +1550,8 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
   }
   case WM_GETTEXTLENGTH:
     return ME_GetTextLength(editor);
+  case EM_GETTEXTLENGTHEX:
+    return ME_GetTextLengthEx(editor, (GETTEXTLENGTHEX *)wParam);
   case WM_GETTEXT:
   {
     TEXTRANGEW tr; /* W and A differ only by rng->lpstrText */
@@ -672,6 +1560,47 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
     tr.lpstrText = (WCHAR *)lParam;
     return RichEditANSIWndProc(hWnd, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
   }
+  case EM_GETTEXTEX:
+  {
+    GETTEXTEX *ex = (GETTEXTEX*)wParam;
+    int nStart, nCount;
+
+    if (ex->flags & ~(GT_SELECTION | GT_USECRLF))
+      FIXME("GETTEXTEX flags 0x%08lx not supported\n", ex->flags & ~(GT_SELECTION | GT_USECRLF));
+
+    if (ex->flags & GT_SELECTION)
+    {
+      ME_GetSelection(editor, &nStart, &nCount);
+      nCount -= nStart;
+      nCount = min(nCount, ex->cb - 1);
+    }
+    else
+    {
+      nStart = 0;
+      nCount = ex->cb - 1;
+    }
+    if (ex->codepage == 1200 || IsWindowUnicode(hWnd))
+    {
+      nCount = min(nCount, ex->cb / sizeof(WCHAR) - 1);
+      return ME_GetTextW(editor, (LPWSTR)lParam, nStart, nCount, ex->flags & GT_USECRLF);
+    }
+    else
+    {
+      /* potentially each char may be a CR, why calculate the exact value with O(N) when
+        we can just take a bigger buffer? :) */
+      int crlfmul = (ex->flags & GT_USECRLF) ? 2 : 1;
+      LPWSTR buffer = HeapAlloc(GetProcessHeap(), 0, (crlfmul*nCount + 1) * sizeof(WCHAR));
+      DWORD buflen = ex->cb;
+      LRESULT rc;
+      DWORD flags = 0;
+
+      buflen = ME_GetTextW(editor, buffer, nStart, nCount, ex->flags & GT_USECRLF);
+      rc = WideCharToMultiByte(ex->codepage, flags, buffer, buflen, (LPSTR)lParam, ex->cb, ex->lpDefaultChar, ex->lpUsedDefaultChar);
+
+      HeapFree(GetProcessHeap(),0,buffer);
+      return rc;
+    }
+  }
   case EM_GETSELTEXT:
   {
     int from, to;
@@ -685,13 +1614,16 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
   case EM_GETTEXTRANGE:
   {
     TEXTRANGEW *rng = (TEXTRANGEW *)lParam;
+    TRACE("EM_GETTEXTRANGE min=%ld max=%ld unicode=%d emul1.0=%d length=%d\n",
+      rng->chrg.cpMin, rng->chrg.cpMax, IsWindowUnicode(hWnd), 
+      editor->bEmulateVersion10, ME_GetTextLength(editor));
     if (IsWindowUnicode(hWnd))
-      return ME_GetTextW(editor, rng->lpstrText, rng->chrg.cpMin, rng->chrg.cpMax-rng->chrg.cpMin, FALSE);
+      return ME_GetTextW(editor, rng->lpstrText, rng->chrg.cpMin, rng->chrg.cpMax-rng->chrg.cpMin, editor->bEmulateVersion10);
     else
     {
       int nLen = rng->chrg.cpMax-rng->chrg.cpMin;
       WCHAR *p = ALLOC_N_OBJ(WCHAR, nLen+1);
-      int nChars = ME_GetTextW(editor, p, rng->chrg.cpMin, nLen, FALSE);
+      int nChars = ME_GetTextW(editor, p, rng->chrg.cpMin, nLen, editor->bEmulateVersion10);
       /* FIXME this is a potential security hole (buffer overrun) 
          if you know more about wchar->mbyte conversion please explain
       */
@@ -699,7 +1631,140 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
       FREE_OBJ(p);
       return nChars;
     }
-    return ME_GetTextW(editor, rng->lpstrText, rng->chrg.cpMin, rng->chrg.cpMax-rng->chrg.cpMin, FALSE);
+  }
+  case EM_GETLINECOUNT:
+  {
+    ME_DisplayItem *item = editor->pBuffer->pFirst->next;
+    int nRows = 0;
+
+    while (item != editor->pBuffer->pLast)
+    {
+      assert(item->type == diParagraph);
+      nRows += item->member.para.nRows;
+      item = item->member.para.next_para;
+    }
+    TRACE("EM_GETLINECOUNT: nRows==%d\n", nRows);
+    return max(1, nRows);
+  }
+  case EM_LINEFROMCHAR:
+  {
+    if (wParam == -1)
+      return ME_RowNumberFromCharOfs(editor, ME_GetCursorOfs(editor, 1));
+    else
+      return ME_RowNumberFromCharOfs(editor, wParam);
+  }
+  case EM_EXLINEFROMCHAR:
+  {
+    return ME_RowNumberFromCharOfs(editor, lParam);
+  }
+  case EM_LINEINDEX:
+  {
+    ME_DisplayItem *item, *para;
+    int nCharOfs;
+    
+    if (wParam == -1)
+      item = ME_FindItemBack(editor->pCursors[0].pRun, diStartRow);
+    else
+      item = ME_FindRowWithNumber(editor, wParam);
+    if (!item)
+      return -1;
+    para = ME_GetParagraph(item);
+    item = ME_FindItemFwd(item, diRun);
+    nCharOfs = para->member.para.nCharOfs + item->member.run.nCharOfs;
+    TRACE("EM_LINEINDEX: nCharOfs==%d\n", nCharOfs);
+    return nCharOfs;
+  }
+  case EM_LINELENGTH:
+  {
+    ME_DisplayItem *item, *item_end;
+    int nChars = 0, nThisLineOfs = 0, nNextLineOfs = 0;
+    
+    if (wParam > ME_GetTextLength(editor))
+      return 0;
+    if (wParam == -1)
+    {
+      FIXME("EM_LINELENGTH: returning number of unselected characters on lines with selection unsupported.\n");
+      return 0;
+    }
+    item = ME_FindItemAtOffset(editor, diRun, wParam, NULL);
+    item = ME_RowStart(item);
+    nThisLineOfs = ME_CharOfsFromRunOfs(editor, ME_FindItemFwd(item, diRun), 0);
+    item_end = ME_FindItemFwd(item, diStartRow);
+    if (item_end)
+      nNextLineOfs = ME_CharOfsFromRunOfs(editor, ME_FindItemFwd(item_end, diRun), 0);
+    else
+      nNextLineOfs = ME_FindItemFwd(item, diParagraphOrEnd)->member.para.nCharOfs
+       - (editor->bEmulateVersion10?2:1);
+    nChars = nNextLineOfs - nThisLineOfs;
+    TRACE("EM_LINELENGTH(%d)==%d\n",wParam, nChars);
+    return nChars;
+  }
+  case EM_FINDTEXT:
+  {
+    FINDTEXTA *ft = (FINDTEXTA *)lParam;
+    int nChars = MultiByteToWideChar(CP_ACP, 0, ft->lpstrText, -1, NULL, 0);
+    WCHAR *tmp;
+    
+    if ((tmp = ALLOC_N_OBJ(WCHAR, nChars)) != NULL)
+      MultiByteToWideChar(CP_ACP, 0, ft->lpstrText, -1, tmp, nChars);
+    return ME_FindText(editor, wParam, &ft->chrg, tmp, NULL);
+  }
+  case EM_FINDTEXTEX:
+  {
+    FINDTEXTEXA *ex = (FINDTEXTEXA *)lParam;
+    int nChars = MultiByteToWideChar(CP_ACP, 0, ex->lpstrText, -1, NULL, 0);
+    WCHAR *tmp;
+    
+    if ((tmp = ALLOC_N_OBJ(WCHAR, nChars)) != NULL)
+      MultiByteToWideChar(CP_ACP, 0, ex->lpstrText, -1, tmp, nChars);
+    return ME_FindText(editor, wParam, &ex->chrg, tmp, &ex->chrgText);
+  }
+  case EM_FINDTEXTW:
+  {
+    FINDTEXTW *ft = (FINDTEXTW *)lParam;
+    return ME_FindText(editor, wParam, &ft->chrg, ft->lpstrText, NULL);
+  }
+  case EM_FINDTEXTEXW:
+  {
+    FINDTEXTEXW *ex = (FINDTEXTEXW *)lParam;
+    return ME_FindText(editor, wParam, &ex->chrg, ex->lpstrText, &ex->chrgText);
+  }
+  case EM_GETZOOM:
+    if (!wParam || !lParam)
+      return FALSE;
+    *(int *)wParam = editor->nZoomNumerator;
+    *(int *)lParam = editor->nZoomDenominator;
+    return TRUE;
+  case EM_SETZOOM:
+    return ME_SetZoom(editor, wParam, lParam);
+  case EM_CHARFROMPOS:
+    return ME_CharFromPos(editor, ((POINTL *)lParam)->x, ((POINTL *)lParam)->y);
+  case EM_POSFROMCHAR:
+  {
+    ME_DisplayItem *pRun;
+    int nCharOfs, nOffset, nLength;
+    POINTL pt = {0,0};
+    
+    nCharOfs = wParam; 
+    /* detect which API version we're dealing with */
+    if (wParam >= 0x40000)
+        nCharOfs = lParam;
+    nLength = ME_GetTextLength(editor);
+    
+    if (nCharOfs < nLength) { 
+        ME_RunOfsFromCharOfs(editor, nCharOfs, &pRun, &nOffset);
+        assert(pRun->type == diRun);
+        pt.y = pRun->member.run.pt.y;
+        pt.x = pRun->member.run.pt.x + ME_PointFromChar(editor, &pRun->member.run, nOffset);
+        pt.y += ME_GetParagraph(pRun)->member.para.nYPos;
+    } else {
+        pt.x = 0;
+        pt.y = editor->pBuffer->pLast->member.para.nYPos;
+    }
+    if (wParam >= 0x40000) {
+        *(POINTL *)wParam = pt;
+    }
+    return MAKELONG( pt.x, pt.y );
   }
   case WM_CREATE:
     ME_CommitUndo(editor);
@@ -724,9 +1789,15 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
       ReleaseCapture();
     break;
   case WM_PAINT:
-    hDC = BeginPaint(hWnd, &ps);
-    ME_PaintContent(editor, hDC, FALSE, &ps.rcPaint);
-    EndPaint(hWnd, &ps);
+    if (editor->bRedraw)
+    {
+      HDC hDC;
+      PAINTSTRUCT ps;
+
+      hDC = BeginPaint(hWnd, &ps);
+      ME_PaintContent(editor, hDC, FALSE, &ps.rcPaint);
+      EndPaint(hWnd, &ps);
+    }
     break;
   case WM_SETFOCUS:
     ME_ShowCaret(editor);
@@ -738,14 +1809,14 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
     return 0;
   case WM_ERASEBKGND:
   {
-    HDC hDC = (HDC)wParam;
-    RECT rc;
-    COLORREF rgbBG = ME_GetBackColor(editor);
-    if (GetUpdateRect(hWnd,&rc,TRUE))
+    if (editor->bRedraw)
     {
-      HBRUSH hbr = CreateSolidBrush(rgbBG);
-      FillRect(hDC, &rc, hbr);
-      DeleteObject(hbr);
+      HDC hDC = (HDC)wParam;
+      RECT rc;
+      if (GetUpdateRect(hWnd,&rc,TRUE))
+      {
+        FillRect(hDC, &rc, editor->hbrBackground);
+      }
     }
     return 1;
   }
@@ -779,13 +1850,39 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
     goto do_default;
   case WM_CHAR: 
   {
-    WCHAR wstr;
+    WCHAR wstr = LOWORD(wParam);
+
+    switch (wstr)
+    {
+    case 3: /* Ctrl-C */
+      SendMessageW(editor->hWnd, WM_COPY, 0, 0);
+      return 0;
+    }
+    
     if (GetWindowLongW(editor->hWnd, GWL_STYLE) & ES_READONLY) {
       MessageBeep(MB_ICONERROR);
       return 0; /* FIXME really 0 ? */
     }
-    wstr = LOWORD(wParam);
-    if (((unsigned)wstr)>=' ' || wstr=='\r') {
+
+    switch (wstr)
+    {
+    case 1: /* Ctrl-A */
+      ME_SetSelection(editor, 0, -1);
+      return 0;
+    case 22: /* Ctrl-V */
+      SendMessageW(editor->hWnd, WM_PASTE, 0, 0);
+      return 0;
+    case 24: /* Ctrl-X */
+      SendMessageW(editor->hWnd, WM_CUT, 0, 0);
+      return 0;
+    case 25: /* Ctrl-Y */
+      SendMessageW(editor->hWnd, EM_REDO, 0, 0);
+      return 0;
+    case 26: /* Ctrl-Z */
+      SendMessageW(editor->hWnd, EM_UNDO, 0, 0);
+      return 0;
+    }
+    if (((unsigned)wstr)>=' ' || wstr=='\r' || wstr=='\t') {
       /* FIXME maybe it would make sense to call EM_REPLACESEL instead ? */
       ME_Style *style = ME_GetInsertStyle(editor, 0);
       ME_SaveTempStyle(editor);
@@ -798,23 +1895,113 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
   }
   case WM_VSCROLL: 
   {
+    int nPos = editor->nScrollPosY;
     si.cbSize = sizeof(SCROLLINFO);
     si.fMask = SIF_PAGE|SIF_POS|SIF_RANGE|SIF_TRACKPOS;
     GetScrollInfo(hWnd, SB_VERT, &si);
     switch(LOWORD(wParam)) {
+    case SB_LINEUP:
+      nPos -= 24; /* FIXME follow the original */
+      if (nPos<0) nPos = 0;
+      break;
+    case SB_LINEDOWN:
+    {
+      int nEnd = editor->nTotalLength - editor->sizeWindow.cy;
+      nPos += 24; /* FIXME follow the original */
+      if (nPos>=nEnd) nPos = nEnd;
+      break;
+    }
+    case SB_PAGEUP:
+      nPos -= editor->sizeWindow.cy;
+      if (nPos<0) nPos = 0;
+      break;
+    case SB_PAGEDOWN:
+      nPos += editor->sizeWindow.cy;
+      if (nPos>=editor->nTotalLength) nPos = editor->nTotalLength-1;
+      break;
     case SB_THUMBTRACK:
-      SetScrollPos(hWnd, SB_VERT, si.nTrackPos, FALSE);
-      ScrollWindow(hWnd, 0, si.nPos-si.nTrackPos, NULL, NULL);
-      /* InvalidateRect(hWnd, NULL, TRUE); */
-      UpdateWindow(hWnd);
+    case SB_THUMBPOSITION:
+      nPos = si.nTrackPos;
       break;
     }
+    if (nPos != editor->nScrollPosY) {
+      int dy = editor->nScrollPosY - nPos;
+      editor->nScrollPosY = nPos;
+      SetScrollPos(hWnd, SB_VERT, nPos, TRUE);
+      if (editor->bRedraw)
+      {
+        ScrollWindow(hWnd, 0, dy, NULL, NULL);
+        UpdateWindow(hWnd);
+      }
+    }
     break;
   }
+  case WM_MOUSEWHEEL:
+  {
+    int gcWheelDelta = 0, nPos = editor->nScrollPosY, nEnd = editor->nTotalLength - editor->sizeWindow.cy; 
+    UINT pulScrollLines;
+    SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
+    gcWheelDelta -= GET_WHEEL_DELTA_WPARAM(wParam);
+    if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines)
+      nPos += pulScrollLines * (gcWheelDelta / WHEEL_DELTA) * 8; /* FIXME follow the original */
+    if (nPos>=nEnd)
+      nPos = nEnd;
+    if (nPos<0)
+      nPos = 0;
+    if (nPos != editor->nScrollPosY) {
+      int dy = editor->nScrollPosY - nPos;
+      editor->nScrollPosY = nPos;
+      SetScrollPos(hWnd, SB_VERT, nPos, TRUE);
+      if (editor->bRedraw)
+      {
+        ScrollWindow(hWnd, 0, dy, NULL, NULL);
+        UpdateWindow(hWnd);
+      }
+    }
+    break;
+  }
+  case EM_GETRECT:
+  {
+    *((RECT *)lParam) = editor->rcFormat;
+    return 0;
+  }
+  case EM_SETRECT:
+  case EM_SETRECTNP:
+  {
+    if (lParam)
+    {
+      RECT *rc = (RECT *)lParam;
+      
+      if (wParam)
+      {
+        editor->rcFormat.left += rc->left;
+        editor->rcFormat.top += rc->top;
+        editor->rcFormat.right += rc->right;
+        editor->rcFormat.bottom += rc->bottom;
+      }
+      else
+      {
+        editor->rcFormat = *rc;
+      }
+    }
+    else
+    {
+      GetClientRect(hWnd, &editor->rcFormat);
+    }
+    if (msg != EM_SETRECTNP)
+      ME_RewrapRepaint(editor);
+    return 0;
+  }
+  case EM_REQUESTRESIZE:
+    ME_SendRequestResize(editor, TRUE);
+    return 0;
+  case WM_SETREDRAW:
+    editor->bRedraw = wParam;
+    return 0;
   case WM_SIZE:
   {
-    ME_MarkAllForWrapping(editor);
-    ME_Repaint(editor);
+    GetClientRect(hWnd, &editor->rcFormat);
+    ME_RewrapRepaint(editor);
     return DefWindowProcW(hWnd, msg, wParam, lParam);
   }
   case EM_GETOLEINTERFACE:
@@ -830,13 +2017,24 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
   return 0L;
 }
 
+
 /******************************************************************
  *        RichEdit10ANSIWndProc (RICHED20.9)
  */
 LRESULT WINAPI RichEdit10ANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
+  LRESULT result;
+  
   /* FIXME: this is NOT the same as 2.0 version */
-  return RichEditANSIWndProc(hWnd, msg, wParam, lParam);
+  result = RichEditANSIWndProc(hWnd, msg, wParam, lParam);
+  if (msg == WM_NCCREATE)
+  {
+    ME_TextEditor *editor = (ME_TextEditor *)GetWindowLongW(hWnd, 0);
+    
+    editor->bEmulateVersion10 = TRUE;
+    editor->pBuffer->pLast->member.para.nCharOfs = 2;
+  }
+  return result;
 }
 
 void ME_SendOldNotify(ME_TextEditor *editor, int nCode)
@@ -861,25 +2059,17 @@ int ME_CountParagraphsBetween(ME_TextEditor *editor, int from, int to)
   return i;
 }
 
+
 int ME_GetTextW(ME_TextEditor *editor, WCHAR *buffer, int nStart, int nChars, int bCRLF)
 {
-  ME_DisplayItem *item = ME_FindItemFwd(editor->pBuffer->pFirst, diParagraph);
+  ME_DisplayItem *item = ME_FindItemAtOffset(editor, diRun, nStart, &nStart);
   int nWritten = 0;
+  WCHAR *pStart = buffer;
   
-  while(item && item->member.para.next_para->member.para.nCharOfs <= nStart)
-    item = ME_FindItemFwd(item, diParagraph);
   if (!item) {
     *buffer = L'\0';
     return 0;
   }
-  nStart -= item->member.para.nCharOfs;
-
-  do {  
-    item = ME_FindItemFwd(item, diRun);
-  } while(item && (item->member.run.nCharOfs + ME_StrLen(item->member.run.strText) <= nStart));
-  assert(item);    
-  
-  nStart -= item->member.run.nCharOfs;
   
   if (nStart)
   {
@@ -904,12 +2094,16 @@ int ME_GetTextW(ME_TextEditor *editor, WCHAR *buffer, int nStart, int nChars, in
       
     if (item->member.run.nFlags & MERF_ENDPARA)
     {
-      if (bCRLF) {
-        *buffer++ = '\r';
+      *buffer = '\r';
+      if (bCRLF)
+      {
+        *(++buffer) = '\n';
         nWritten++;
-      }        
-      *buffer = '\n';
+      }
       assert(nLen == 1);
+      /* our end paragraph consists of 2 characters now */
+      if (editor->bEmulateVersion10)
+        nChars--;
     }
     else      
       CopyMemory(buffer, item->member.run.strText->szData, sizeof(WCHAR)*nLen);
@@ -919,25 +2113,24 @@ int ME_GetTextW(ME_TextEditor *editor, WCHAR *buffer, int nStart, int nChars, in
       
     if (!nChars)
     {
+      TRACE("nWritten=%d, actual=%d\n", nWritten, buffer-pStart);
       *buffer = L'\0';
       return nWritten;
     }
     item = ME_FindItemFwd(item, diRun);
   }
   *buffer = L'\0';
+  TRACE("nWritten=%d, actual=%d\n", nWritten, buffer-pStart);
   return nWritten;  
 }
 
-static WCHAR wszClassName[] = {'R', 'i', 'c', 'h', 'E', 'd', 'i', 't', '2', '0', 'W', 0};
-static WCHAR wszClassName50[] = {'R', 'i', 'c', 'h', 'E', 'd', 'i', 't', '5', '0', 'W', 0};
-
 void ME_RegisterEditorClass(HINSTANCE hInstance)
 {
   BOOL bResult;
   WNDCLASSW wcW;
   WNDCLASSA wcA;
   
-  wcW.style = CS_HREDRAW | CS_VREDRAW;
+  wcW.style = CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS;
   wcW.lpfnWndProc = RichEditANSIWndProc;
   wcW.cbClsExtra = 0;
   wcW.cbWndExtra = 4;
@@ -953,7 +2146,7 @@ void ME_RegisterEditorClass(HINSTANCE hInstance)
   bResult = RegisterClassW(&wcW);  
   assert(bResult);
 
-  wcA.style = CS_HREDRAW | CS_VREDRAW;
+  wcA.style = CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS;
   wcA.lpfnWndProc = RichEditANSIWndProc;
   wcA.cbClsExtra = 0;
   wcA.cbWndExtra = 4;
@@ -969,30 +2162,6 @@ void ME_RegisterEditorClass(HINSTANCE hInstance)
   bResult = RegisterClassA(&wcA);  
   assert(bResult);
 }
-
-BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
-{
-    TRACE("\n");
-    switch (fdwReason)
-    {
-    case DLL_PROCESS_ATTACH:
-      DisableThreadLibraryCalls(hinstDLL);
-      me_heap = HeapCreate (0, 0x10000, 0);
-      ME_RegisterEditorClass(hinstDLL);
-      break;
-
-    case DLL_PROCESS_DETACH:
-      UnregisterClassW(wszClassName, 0);
-      UnregisterClassW(wszClassName50, 0);
-      UnregisterClassA("RichEdit20A", 0);
-      UnregisterClassA("RichEdit50A", 0);
-      HeapDestroy (me_heap);
-      me_heap = NULL;
-      break;
-    }
-    return TRUE;
-}
-
 /******************************************************************
  *        CreateTextServices (RICHED20.4)
  *
@@ -1009,12 +2178,62 @@ HRESULT WINAPI CreateTextServices(IUnknown *punkOuter, void *pITextHost,
   return E_FAIL; /* E_NOTIMPL isn't allowed by MSDN */
 }
 
+LRESULT WINAPI REComboWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
+  /* FIXME: Not implemented */
+  TRACE("hWnd %p msg %04x (%s) %08x %08lx\n",
+        hWnd, msg, get_msg_name(msg), wParam, lParam);
+  return DefWindowProcW(hWnd, msg, wParam, lParam);
+}
+
+LRESULT WINAPI REListWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
+  /* FIXME: Not implemented */
+  TRACE("hWnd %p msg %04x (%s) %08x %08lx\n",
+        hWnd, msg, get_msg_name(msg), wParam, lParam);
+  return DefWindowProcW(hWnd, msg, wParam, lParam);
+}
+
 /******************************************************************
  *        REExtendedRegisterClass (RICHED20.8)
  *
  * FIXME undocumented
+ * Need to check for errors and implement controls and callbacks 
  */
-void WINAPI REExtendedRegisterClass(void)
+LRESULT WINAPI REExtendedRegisterClass(void)
 {
-  FIXME("stub\n");
+  WNDCLASSW wcW;
+  UINT result;
+
+  FIXME("semi stub\n");
+
+  wcW.cbClsExtra = 0;
+  wcW.cbWndExtra = 4;
+  wcW.hInstance = NULL;
+  wcW.hIcon = NULL;
+  wcW.hCursor = NULL;
+  wcW.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
+  wcW.lpszMenuName = NULL;
+
+  if (!ME_ListBoxRegistered)
+  {
+      wcW.style = CS_PARENTDC | CS_DBLCLKS | CS_GLOBALCLASS;
+      wcW.lpfnWndProc = REListWndProc;
+      wcW.lpszClassName = wszClassNameListBox;
+      if (RegisterClassW(&wcW)) ME_ListBoxRegistered = TRUE;
+  }
+
+  if (!ME_ComboBoxRegistered)
+  {
+      wcW.style = CS_PARENTDC | CS_DBLCLKS | CS_GLOBALCLASS | CS_VREDRAW | CS_HREDRAW;
+      wcW.lpfnWndProc = REComboWndProc;
+      wcW.lpszClassName = wszClassNameComboBox;
+      if (RegisterClassW(&wcW)) ME_ComboBoxRegistered = TRUE;  
+  }
+
+  result = 0;
+  if (ME_ListBoxRegistered)
+      result += 1;
+  if (ME_ComboBoxRegistered)
+      result += 2;
+
+  return result;
 }