0

Basically, I have written a program in C# that grabs text and the current caret position from any window handle using user32.dll. After manipulating the text, the program sets the text of the control to the new string and also resets the caret position.

The issue I am running into is that EM_GETSEL returns an caret position for RichEdit controls based on the number of CR+LF proceeding the caret position.

Edit controls treat these as two characters, while RichEdit controls treat them as one "character".

Is there anyway that I can detect which of these two a control may be by windows messages?

Or is there a better way that I can detect caret position for unmanaged controls?

Joshua
  • 31
  • 5
  • It shouldn't really matter here if the RichEdit counts CRLF as one or two characters, as long as it's consistent in doing so: when reporting the position, but also with length and updates. In that case, there should be no issue. Are you seeing actual issues with this? – MicroVirus Mar 11 '16 at 17:28
  • Use GetClassName() – Hans Passant Mar 11 '16 at 18:36
  • GetClassName() will not report a meaningful class name when the control was subclassed which most controls in Windows applications are. – NineBerry Mar 11 '16 at 20:30

2 Answers2

2

Your observation is imprecise.

Rich Edit does not count CRLF as 1 character, but it does not use CRLF (\r\n) for a newline, but only LF (\n). You will see that when you examine the text content of the Rich Edit. Line breaks are returned as \n only, not \r\n.

You can see the same behaviour in the .net Winforms RichEdit control:

    var before = "Line1\r\nLine2";
    richTextBox1.Text = before;
    var after = richTextBox1.Text;

    MessageBox.Show(string.Format("Before: {0} After: {1}", before.Length, after.Length));

This will show "Before: 12 After: 11". The line break \r\n in the text is converted to \n when the text is assigned to the rich edit.

NineBerry
  • 26,306
  • 3
  • 62
  • 93
  • Okay, that makes sense! – Joshua Mar 14 '16 at 12:00
  • Would this cause \n to be converted to \r\n? `StringBuilder builder = new StringBuilder(bufferSize + 1);` `SendMessage(focused, WM_GETTEXT, builder.Capacity, builder);` – Joshua Mar 14 '16 at 12:17
  • Depending on the type of the control. If it is an edit, it will return \r\n, if it is a richedit, it will return \n. – NineBerry Mar 14 '16 at 13:41
  • For some reason, when I use that code, the string builder has \r\n for every newline even from a RichEdit. Also, that code is part of a method, so at the end: `return builder.ToString();` Is something in this causing \n to be converted to \r\n? – Joshua Mar 14 '16 at 13:56
  • I changed the functionality to return just the stringbuilder object, and even still the characters are recorded as \r\n. I'm totally lost here, should I open this up as a new question? – Joshua Mar 14 '16 at 16:29
  • It seems that WM_GETTEXT returns the original string, not the internal representation in the richedit control where \n is used for line breaks. .net itself uses the EM_STREAMOUT message to get the content of the richedit, which delivers the internal text version. Maybe you can try EM_STREAMOUT() on the handle you have. If this succeeds, you have a richedit control. – NineBerry Mar 14 '16 at 18:03
  • If I'm not mistaken EM_STREAMOUT only works on local memory, would I have to inject into the active process to determine if the control is RichEdit? Or is there a way to use EM_STREAMOUT on external processes? – Joshua Mar 16 '16 at 16:01
  • Yes, I forgot that you are out of process. Sorry, I have no more ideas. – NineBerry Mar 16 '16 at 17:33
1

Alright everyone, thank you for your help! This explanation is a little off the cuff, so bear with me.

I had a breakthrough today, and I was able to determine a simple way to tell the difference between an Edit or RichEdit control.

Since we know that WM_GETTEXT returns the original string, and EM_GETSEL will be off by 1 for every newline, all we have to do is check for the following:

  1. Are we off of the the first line (line 0)?
  2. If we are greater than line zero, use EM_LINEINDEX (I use a loop here to increase wParam and I'll explain why in just a second) to get a substring from character 0 to EM_LINEINDEX
  3. Check if that substring contains a \r (If not, then you have a wordwrap somewhere. This is why I use the loop in step 2)
  4. Once you find a substring \r, does that substring also contain \n?

Again, this works because even EM_LINEINDEX is off by 1 character in a RichEdit against WM_GETTEXT and therefore a substring from character 0 until the EM_LINEINDEX after your first newline will not contain a \n if your control is a RichEdit.

Joshua
  • 31
  • 5