/// <include file='doc\RichTextBox.uex' path='docs/doc[@for="RichTextBox.CharRangeToString"]/*' /> /// <devdoc> /// Converts a CHARRANGE to a string. Note: The behavior of this is dependent on the current window /// class name being used. We have to create a CharBuffer of the type of RichTextBox DLL we're using, /// not based on the SystemCharWidth. /// </devdoc> /// <internalonly/> private string CharRangeToString(NativeMethods.CHARRANGE c) { NativeMethods.TEXTRANGE txrg = new NativeMethods.TEXTRANGE(); txrg.chrg = c; Debug.Assert((c.cpMax-c.cpMin)>0, "CHARRANGE was null or negative - can't do it!"); //Windows bug: 64-bit windows returns a bad range for us. VSWhidbey 504502. //Putting in a hack to avoid an unhandled exception. if (c.cpMax > Text.Length || c.cpMax-c.cpMin <= 0) { return string.Empty; } int characters = (c.cpMax-c.cpMin) + 1; // +1 for null termination UnsafeNativeMethods.CharBuffer charBuffer = UnsafeNativeMethods.CharBuffer.CreateBuffer(characters); IntPtr unmanagedBuffer = charBuffer.AllocCoTaskMem(); if (unmanagedBuffer == IntPtr.Zero) throw new OutOfMemoryException(SR.GetString(SR.OutOfMemory)); txrg.lpstrText = unmanagedBuffer; int len = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_GETTEXTRANGE, 0, txrg); Debug.Assert(len != 0, "CHARRANGE from RichTextBox was bad! - impossible?"); charBuffer.PutCoTaskMem(unmanagedBuffer); if (txrg.lpstrText != IntPtr.Zero) Marshal.FreeCoTaskMem(unmanagedBuffer); string result = charBuffer.GetString(); return result; }
/// <include file='doc\RichTextBox.uex' path='docs/doc[@for="RichTextBox.Find6"]/*' /> /// <devdoc> /// Searches the text in a RichTextBox control for the given characters. /// </devdoc> public int Find(char[] characterSet, int start, int end) { // Code used to support ability to search backwards and negate character sets. // The API no longer supports this, but in case we change our mind, I'm leaving // the ability in here. bool forward = true; bool negate = false; int textLength = TextLength; if (characterSet == null) throw new ArgumentNullException("characterSet"); if (start < 0 || start > textLength) throw new ArgumentOutOfRangeException("start", SR.GetString(SR.InvalidBoundArgument, "start", start, 0, textLength)); if (end < start && end != -1) throw new ArgumentOutOfRangeException("end", SR.GetString(SR.InvalidLowBoundArgumentEx, "end", end, "start")); // Don't do anything if we get nothing to look for if (characterSet.Length == 0) return -1; int textLen = SafeNativeMethods.GetWindowTextLength(new HandleRef(this, Handle)); if (start == end) { start = 0; end = textLen; } if (end == -1) { end = textLen; } NativeMethods.CHARRANGE chrg = new NativeMethods.CHARRANGE(); // The range of characters we have searched chrg.cpMax = chrg.cpMin = start; // Use the TEXTRANGE to move our text buffer forward // or backwards within the main text NativeMethods.TEXTRANGE txrg = new NativeMethods.TEXTRANGE(); // Characters we have slurped into memory in order to search txrg.chrg = new NativeMethods.CHARRANGE(); txrg.chrg.cpMin = chrg.cpMin; txrg.chrg.cpMax = chrg.cpMax; UnsafeNativeMethods.CharBuffer charBuffer; charBuffer = UnsafeNativeMethods.CharBuffer.CreateBuffer(CHAR_BUFFER_LEN + 1); txrg.lpstrText = charBuffer.AllocCoTaskMem(); if (txrg.lpstrText == IntPtr.Zero) throw new OutOfMemoryException(); try { bool done = false; // We want to loop as long as it takes. This loop will grab a // chunk of text out from the control as directed by txrg.chrg; while (!done) { if (forward) { // Move forward by starting at the end of the // previous text window and extending by the // size of our buffer txrg.chrg.cpMin = chrg.cpMax; txrg.chrg.cpMax += CHAR_BUFFER_LEN; } else { // Move backwards by anchoring at the start // of the previous buffer window, and backing // up by the desired size of our buffer txrg.chrg.cpMax = chrg.cpMin; txrg.chrg.cpMin -= CHAR_BUFFER_LEN; // We need to keep our request within the // lower bound of zero if (txrg.chrg.cpMin < 0) txrg.chrg.cpMin = 0; } if (end != -1) txrg.chrg.cpMax = Math.Min(txrg.chrg.cpMax, end); // go get the text in this range, if we didn't get any text then punt int len; len = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_GETTEXTRANGE, 0, txrg); if (len == 0) { chrg.cpMax = chrg.cpMin = -1; // Hit end of control without finding what we wanted break; } // get the data from RichTextBoxConstants into a string for us to use. charBuffer.PutCoTaskMem(txrg.lpstrText); string str = charBuffer.GetString(); // Loop through our text if (forward) { // Start at the begining of the buffer for (int x = 0; x < len; x++) { // Is it in char set? bool found = GetCharInCharSet(str[x], characterSet, negate); if (found) { done = true; break; } // Advance the buffer chrg.cpMax++; } } else { // Span reverse. int x = len; while (x-- != 0) { // Is it in char set? bool found = GetCharInCharSet(str[x], characterSet, negate); if (found) { done = true; break; } // Bring the selection back while keeping it anchored chrg.cpMin--; } } } } finally { // release the resources we got for our GETTEXTRANGE operation. if (txrg.lpstrText != IntPtr.Zero) Marshal.FreeCoTaskMem(txrg.lpstrText); } int index = (forward) ? chrg.cpMax : chrg.cpMin; return index; }