win_wrap/control/
edit.rs

1/*
2 * Copyright (c) 2024. The RigelA open source project team and
3 * its contributors reserve all rights.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software distributed under the
10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 * See the License for the specific language governing permissions and limitations under the License.
12 */
13
14use std::ffi::CString;
15
16pub use windows::Win32::{
17    Foundation::POINT,
18    UI::{
19        Controls::{
20            Dialogs::{
21                FINDREPLACE_FLAGS, FR_DIALOGTERM, FR_DOWN, FR_ENABLEHOOK, FR_ENABLETEMPLATE,
22                FR_ENABLETEMPLATEHANDLE, FR_FINDNEXT, FR_HIDEMATCHCASE, FR_HIDEUPDOWN,
23                FR_HIDEWHOLEWORD, FR_MATCHALEFHAMZA, FR_MATCHCASE, FR_MATCHDIAC, FR_MATCHKASHIDA,
24                FR_NOMATCHCASE, FR_NOUPDOWN, FR_NOWHOLEWORD, FR_NOWRAPAROUND, FR_RAW, FR_REPLACE,
25                FR_REPLACEALL, FR_SHOWHELP,
26            },
27            RichEdit::{
28                CHARRANGE, EM_CANPASTE, EM_EXGETSEL, EM_EXLINEFROMCHAR, EM_EXSETSEL, EM_FINDTEXT,
29                EM_GETSELTEXT, EM_GETTEXTRANGE, EM_HIDESELECTION, EM_SELECTIONTYPE,
30                ES_DISABLENOSCROLL, ES_EX_NOCALLOLEINIT, ES_NOIME, ES_NOOLEDRAGDROP, ES_SAVESEL,
31                ES_SELECTIONBAR, ES_SELFIME, ES_SUNKEN, ES_VERTICAL, REOBJECT_FLAGS,
32                REO_ALIGNTORIGHT, REO_BELOWBASELINE, REO_BLANK, REO_CANROTATE, REO_DONTNEEDPALETTE,
33                REO_DYNAMICSIZE, REO_GETMETAFILE, REO_HILITED, REO_INPLACEACTIVE,
34                REO_INVERTEDSELECT, REO_LINK, REO_LINKAVAILABLE, REO_NULL, REO_OPEN,
35                REO_OWNERDRAWSELECT, REO_RESIZABLE, REO_SELECTED, REO_STATIC, REO_USEASBACKGROUND,
36                REO_WRAPTEXTAROUND, RICH_EDIT_GET_CONTEXT_MENU_SEL_TYPE, SEL_EMPTY, SEL_MULTICHAR,
37                SEL_MULTIOBJECT, SEL_OBJECT, SEL_TEXT,
38            },
39            EM_CANUNDO, EM_CHARFROMPOS, EM_EMPTYUNDOBUFFER, EM_GETFIRSTVISIBLELINE, EM_GETLINE,
40            EM_GETLINECOUNT, EM_GETMARGINS, EM_GETMODIFY, EM_GETRECT, EM_GETSEL, EM_LINEFROMCHAR,
41            EM_LINEINDEX, EM_LINELENGTH, EM_LINESCROLL, EM_POSFROMCHAR, EM_REPLACESEL, EM_SCROLL,
42            EM_SCROLLCARET, EM_SETMARGINS, EM_SETMODIFY, EM_SETREADONLY, EM_SETSEL,
43        },
44        WindowsAndMessaging::{
45            EC_LEFTMARGIN, EC_RIGHTMARGIN, EC_USEFONTINFO, ES_AUTOHSCROLL, ES_AUTOVSCROLL,
46            ES_CENTER, ES_LEFT, ES_LOWERCASE, ES_MULTILINE, ES_NOHIDESEL, ES_NUMBER, ES_OEMCONVERT,
47            ES_PASSWORD, ES_READONLY, ES_RIGHT, ES_UPPERCASE, ES_WANTRETURN, SB_BOTTOM,
48            SB_ENDSCROLL, SB_LEFT, SB_LINEDOWN, SB_LINELEFT, SB_LINERIGHT, SB_LINEUP, SB_PAGEDOWN,
49            SB_PAGELEFT, SB_PAGERIGHT, SB_PAGEUP, SB_RIGHT, SB_THUMBPOSITION, SB_THUMBTRACK,
50            SB_TOP, SCROLLBAR_COMMAND,
51        },
52    },
53};
54use windows::{
55    core::{HSTRING, PCWSTR, PWSTR},
56    Win32::UI::Controls::RichEdit::{FINDTEXTEXW, FINDTEXTW, TEXTRANGEW},
57};
58
59use crate::{
60    common::{LPARAM, RECT, WPARAM},
61    control::WindowControl,
62    ext::StringExt,
63    memory::InProcessMemory,
64};
65
66pub trait Edit {
67    /**
68    从编辑控件复制一行文本。 可以将此消息发送到编辑控件或富编辑控件。
69    富编辑控件: Microsoft Rich Edit 1.0 及更高版本中受支持。如果未复制文本,则消息会在缓冲区的开头放置一个 null 字符。 有关丰富编辑版本与各种系统版本的兼容性的信息,请参阅 关于丰富编辑控件。
70    `index` 要从多行编辑控件检索的行的从零开始的索引。值为零指定最上面的行。 单行编辑控件会忽略此参数。
71    `len` 要获取的字符数。
72    */
73    fn get_line(&self, index: i32, len: u16) -> Option<String>;
74
75    /**
76    查询编辑控件中行的长度(以字符为单位)。
77    对于多行编辑控件,返回值是 `position` 参数指定的行的长度。 对于 ANSI 文本,这是字节数;对于 Unicode 文本,这是字符数。 不包括行末尾的回车符。
78    对于单行编辑控件,返回值是编辑控件中文本的长度。
79    使用 line_index 查询多行编辑控件中给定行号的字符索引。
80    富编辑: Microsoft Rich Edit 1.0 及更高版本中受支持。 有关丰富编辑版本与各种系统版本的兼容性的信息,请参阅 关于丰富编辑控件。
81    `position` 行中要检索其长度的字符的字符索引。 如果此参数大于控件中的字符数,则返回值为零。此参数可以为 -1。 在这种情况下,消息返回包含选定字符的行上的未选定字符数。 例如,如果所选内容从下一行末尾的第四个字符扩展到第八个字符,则返回值为 10 (第一行的 3 个字符,下一行的) 7 个字符。
82    */
83    fn line_length(&self, position: i32) -> usize;
84
85    /**
86    获取多行编辑控件中指定行的第一个字符的字符索引。 字符索引是从编辑控件开头开始的字符的从零开始的索引。 可以将此消息发送到编辑控件或富编辑控件。
87    返回值是 `line_index` 参数中指定的行的字符索引;如果指定的行号大于编辑控件中的行数,则返回值为 -1。
88    富编辑: Microsoft Rich Edit 1.0 及更高版本中受支持。 有关丰富编辑版本与各种系统版本的兼容性的信息,请参阅 关于丰富编辑控件。
89    `line_index` 从零开始的行号。 值 -1 (当前行号指定包含插入点) 的行。
90    */
91    fn line_index(&self, line_index: i32) -> i32;
92
93    /**
94    将编辑控件或富编辑控件中的选定文本替换为指定的文本。
95    使用 replace_sel 仅替换编辑控件中文本的一部分。 若要替换所有文本,请使用 set_text。
96    如果没有选择,替换文本将插入插入点处。
97    Rich Edit: 在 Microsoft Rich Edit 1.0 及更高版本中受支持。 有关 Rich Edit 版本与各种系统版本的兼容性的信息,请参阅 关于 Rich Edit 控件。
98    在丰富编辑控件中,替换文本采用插入点处的字符的格式,如果选定内容中第一个字符,则采用格式设置。
99    `allow_undo` 指定是否可以撤消替换操作。 如果为 true,则可以撤消该操作。 如果为 false ,则无法撤消操作。
100    `text` 要替换的文本。
101    */
102    fn replace_sel(&self, allow_undo: bool, text: &str);
103
104    /**
105    设置或删除只读样式 (ES_READONLY 编辑控件的) 。 可以将此消息发送到编辑控件或富编辑控件。
106    如果操作成功,则返回值为非零值。如果操作失败,则返回值为零。
107    当编辑控件具有 ES_READONLY 样式时,用户无法更改编辑控件中的文本。
108    若要确定编辑控件是否具有 ES_READONLY 样式,请使用带有 GWL_STYLE 标志的 get_window_long 函数。
109    富编辑: Microsoft Rich Edit 1.0 及更高版本中受支持。 有关丰富编辑版本与各种系统版本的兼容性的信息,请参阅 关于丰富编辑控件。
110    `enable` 指定是设置还是删除 ES_READONLY 样式。 值为 true 设置 ES_READONLY 样式;值为 false 会删除 ES_READONLY 样式。
111    */
112    fn set_readonly(&self, enable: bool) -> usize;
113
114    /**
115    从丰富编辑控件中查询指定的字符范围。
116    `min` 最小索引。
117    `max` 最大索引。
118    */
119    fn get_text_range(&self, min: i32, max: i32) -> Option<String>;
120
121    /**
122    确定编辑控件的撤消队列中是否有任何操作。 可以将此消息发送到编辑控件或富编辑控件。
123    如果撤消队列不为空,可以将 EM_UNDO 消息发送到控件以撤消最近的操作。
124    编辑控件和 Rich Edit 1.0: 撤消队列仅包含最近的操作。
125    Rich Edit 2.0 及更高版本: 撤消队列可以包含多个操作。
126    Rich Edit: 在 Microsoft Rich Edit 1.0 及更高版本中受支持。 有关 Rich Edit 版本与各种系统版本的兼容性的信息,请参阅 关于 Rich Edit 控件。
127    */
128    fn can_undo(&self) -> bool;
129
130    //noinspection SpellCheckingInspection
131    /**
132    重置编辑控件的撤消标志。 每当可撤消编辑控件中的操作时,都会设置撤消标志。 可以将此消息发送到编辑控件或富编辑控件。
133    每当编辑控件收到 WM_SETTEXT 或 EM_SETHANDLE 消息时,撤消标志都会自动重置。
134    编辑控件和 Rich Edit 1.0: 控件只能撤消或重做最近的操作。
135    Rich Edit 2.0 及更高版本:EM_EMPTYUNDOBUFFER消息清空所有撤消和重做缓冲区。 丰富的编辑控件使用户能够撤消或重做多个操作。
136    Rich Edit: 在 Microsoft Rich Edit 1.0 及更高版本中受支持。 有关 Rich Edit 版本与各种系统版本的兼容性的信息,请参阅 关于 Rich Edit 控件。
137    */
138    fn empty_undo_buffer(&self);
139
140    /**
141    获取多行编辑控件中最上面的可见行的从零开始的索引。 可以将此消息发送到编辑控件或富编辑控件。
142    返回值是多行编辑控件中最上面的可见行的从零开始的索引。
143    编辑控件: 对于单行编辑控件,返回值是第一个可见字符的从零开始的索引。
144    富编辑控件: 对于单行富编辑控件,返回值为零。
145    编辑控件中的行数和行长度取决于控件的宽度和当前 Wordwrap 设置。
146    富编辑: Microsoft Rich Edit 1.0 及更高版本中受支持。 有关丰富编辑版本与各种系统版本的兼容性的信息,请参阅 关于丰富编辑控件。
147    */
148    fn get_first_visible_line(&self) -> i32;
149
150    /**
151     获取多行编辑控件中的行数。 可以将此消息发送到编辑控件或富编辑控件。
152     返回值是一个整数,用于指定多行编辑控件或富编辑控件中的文本行总数。 如果控件没有文本,则返回值为 1。 返回值永远不会小于 1。
153     get_line_count查询文本行的总数,而不仅仅是当前可见的行数。
154     如果启用了 Wordwrap 功能,则当编辑窗口的尺寸发生更改时,行数可能会更改。
155     Rich Edit: 在 Microsoft Rich Edit 1.0 及更高版本中受支持。 有关 Rich Edit 版本与各种系统版本的兼容性的信息,请参阅 关于 Rich Edit 控件。
156    */
157    fn get_line_count(&self) -> usize;
158
159    //noinspection SpellCheckingInspection
160    /**
161    获取编辑控件的修改标志的状态。 标志指示是否已修改编辑控件的内容。 可以将此消息发送到编辑控件或富编辑控件。
162    创建控件时,系统会自动将修改标志清除为零。 如果用户更改控件的文本,系统将标志设置为非零。 可以将 EM_SETMODIFY 消息发送到编辑控件以设置或清除标志。
163    富编辑: Microsoft Rich Edit 1.0 及更高版本中受支持。 有关丰富编辑版本与各种系统版本的兼容性的信息,请参阅 关于丰富编辑控件。
164    */
165    fn get_modify(&self) -> bool;
166
167    //noinspection SpellCheckingInspection
168    /**
169    设置或清除编辑控件的修改标志。 修改标志指示是否已修改编辑控件中的文本。 可以将此消息发送到编辑控件或富编辑控件。
170    创建控件时,系统会自动将修改标志清除为零。 如果用户更改控件的文本,系统将标志设置为非零。 get_modify查询标志的当前状态。
171    Rich Edit 1.0: 在没有 REO_DYNAMICSIZE 标志的情况下创建的对象会在修改标志设置为 FALSE 时锁定其盘区。
172    富编辑: Microsoft Rich Edit 1.0 及更高版本中受支持。 有关丰富编辑版本与各种系统版本的兼容性的信息,请参阅 关于丰富编辑控件。
173    `is_modified` 修改标志的新值。 值为 true 表示文本已修改,值为 false 表示尚未修改。
174    */
175    fn set_modify(&self, is_modified: bool);
176
177    /**
178    获取编辑控件 的格式设置矩形 。 格式设置矩形是控件在其中绘制文本的限制矩形。 限制矩形与编辑控件窗口的大小无关。 可以将此消息发送到编辑控件或富编辑控件。
179    可以使用 set_rect 和 set_rect_np 来修改多行编辑控件的格式矩形。
180    在某些情况下, get_rect 可能不会返回 set_rect 或 set_rect_np 设置的确切值,该值大致正确,但可能会关闭几个像素。
181    Rich Edit: 在 Microsoft Rich Edit 1.0 及更高版本中受支持。 格式设置矩形不包括选择栏,这是每个段落左侧的未标记区域。 单击后,选择栏将选择行。 有关 Rich Edit 版本与各种系统版本的兼容性的信息,请参阅 关于 Rich Edit 控件。
182    */
183    fn get_rect(&self) -> RECT;
184
185    /**
186    获取编辑控件中当前所选内容的起始和结束字符位置。 可以将此消息发送到编辑控件或 Rich Edit 控件。
187    如果没有选择内容,则起始值和结束值都是插入点的位置。
188    Rich Edit 控件:还可以使用 get_sel_ex 来检索相同的信息。 get_sel_ex 还以 32 位值的形式返回起始字符和结束字符位置。
189    Rich Edit:在 Microsoft Rich Edit 1.0 及更高版本中受支持。 若要了解 Rich Edit 版本与各种系统版本的兼容性,请参阅关于 Rich Edit 控件。
190    */
191    fn get_sel(&self) -> (i32, i32);
192
193    /**
194    查询丰富编辑控件中所选内容的起始和结束字符位置。
195    */
196    fn get_sel_ex(&self) -> (i32, i32);
197
198    //noinspection SpellCheckingInspection
199    /**
200    在编辑控件中选择一个字符范围。 可以将此消息发送到编辑控件或富编辑控件。
201    起始值可以大于结束值。 两个值的下半部分指定所选内容中第一个字符的字符位置。 较高的值指定所选内容之外的第一个字符的位置。
202    起始值是所选内容的定位点,结束值是活动结束。 如果用户使用 SHIFT 键调整所选内容的大小,活动端可以移动,但定位点保持不变。
203    如果开头为 0,结尾为 -1,则选择编辑控件中的所有文本。 如果开始为 -1,则取消选择任何当前选择。
204    编辑控件: 无论开始和结束的相对值如何,控件都会在结束位置显示闪烁的插入点。
205    Rich Edit: 在 Microsoft Rich Edit 1.0 及更高版本中受支持。 有关 Rich Edit 版本与各种系统版本的兼容性的信息,请参阅 关于 Rich Edit 控件。
206    如果编辑控件具有 ES_NOHIDESEL 样式,则无论控件是否具有焦点,所选文本都会突出显示。 如果没有 ES_NOHIDESEL 样式,仅当编辑控件具有焦点时,才会突出显示所选文本。
207    `start` 所选内容的起始字符位置。
208    `end` 所选内容的结束字符位置。
209    */
210    fn set_sel(&self, start: i32, end: i32);
211
212    /**
213    选择一系列字符或组件对象模型 (COM) Microsoft Rich Edit 控件中的对象。
214    返回值是实际设置的选定内容。
215    `min` 最小索引。
216    `max` 最大索引。
217    */
218    fn set_sel_ex(&self, min: i32, max: i32) -> usize;
219
220    /**
221    查询格式编辑控件中当前选择的文本。
222    `len` 要获取的字符数量。
223    */
224    fn get_sel_text(&self, len: usize) -> Option<String>;
225
226    /**
227    获取包含多行编辑控件中指定字符索引的行的索引。 字符索引是从编辑控件开头开始的字符的从零开始的索引。 可以将此消息发送到编辑控件或富编辑控件。
228    返回值是包含  position  指定的字符索引的行的从零开始的行号。
229    Rich Edit:  在 Microsoft Rich Edit 1.0 及更高版本中受支持。 如果字符索引大于 64,000,请使用 line_from_char_ex。 有关 Rich Edit 版本与各种系统版本的兼容性的信息,请参阅  关于 Rich Edit 控件 。
230    `position` 要查询其编号的行中包含的字符的字符索引。 如果此参数为 -1, line_from_char  将查询当前行的行号 (包含脱字号) 或者,如果有选定内容,则查询包含所选内容的开头的行号。
231    */
232    fn line_from_char(&self, position: i32) -> i32;
233
234    /**
235    确定哪个行包含 Rich Edit 控件中的指定字符。
236    此消息返回行的从零开始的索引。
237    `position` 字符的从零开始的索引。
238    */
239    fn line_from_char_ex(&self, position: i32) -> i32;
240
241    //noinspection SpellCheckingInspection
242    /**
243     在多行编辑控件中垂直滚动文本。 此消息等效于将 WM\_VSCROLL 消息发送到编辑控件。 可以将此消息发送到编辑控件或富编辑控件。
244     如果消息成功,则返回值的  HIWORD  为 TRUE, LOWORD  是命令滚动的行数。
245     如果滚动移动到文本的开头或末尾,返回的数字可能与滚动的实际行数不同。 如果 command 参数指定的值无效,则返回值为 false。
246     要滚动到特定行或字符位置,请使用 EM_LINESCROLL 消息。 要将插入点滚动到视图中,请使用 EM_SCROLLCARET 消息。
247     Rich Edit:在 Microsoft Rich Edit 1.0 及更高版本中受支持。 有关 Rich Edit 版本与各种系统版本的兼容性的信息,请参阅关于 Rich Edit 控件。
248     `command` 滚动条要执行的操作。 此参数的取值可为下列值之一。
249     - SB_LINEDOWN 向下滚动一行。
250     - SB_LINEUP 向上滚动一行。
251     - SB_PAGEDOWN 向下滚动一页。
252     - SB_PAGEUP 向上滚动一页。
253    */
254    fn scroll(&self, command: SCROLLBAR_COMMAND) -> isize;
255
256    /**
257    滚动多行编辑控件中的文本。
258    如果消息发送到多行编辑控件,则返回值为 true。如果消息发送到单行编辑控件,则返回值为 false。
259    该控件不会垂直滚动到编辑控件中的最后一行文本。 如果当前行加上 line 参数指定的行数超过编辑控件中的总行数,则会调整该值,以便编辑控件的最后一行滚动到编辑控件窗口的顶部。
260    编辑控件:line_scroll在多行编辑控件中垂直或水平滚动文本。 line_scroll可用于水平滚动超过任何行的最后一个字符。
261    富编辑: Microsoft Rich Edit 1.0 及更高版本中受支持。 line_scroll在多行编辑控件中垂直滚动文本。 有关丰富编辑版本与各种系统版本的兼容性的信息,请参阅 关于丰富编辑控件。
262    `column` 编辑控件: 要水平滚动的字符数。富编辑控件: 不使用此参数;它必须为零。
263    `line` 要垂直滚动的行数。
264    */
265    fn line_scroll(&self, column: i32, line: i32) -> bool;
266
267    /**
268    将插入点滚动到编辑控件的视图中。 可以将此消息发送到编辑控件或富编辑控件。
269    富编辑:  Microsoft Rich Edit 1.0 及更高版本中受支持。 有关丰富编辑版本与各种系统版本的兼容性的信息,请参阅  关于丰富编辑控件 。
270    */
271    fn scroll_caret(&self);
272
273    /**
274    确定丰富的编辑控件是否可以粘贴。
275    */
276    fn can_paste(&self) -> bool;
277
278    //noinspection SpellCheckingInspection
279    /**
280    获取有关距离编辑控件客户区中指定点最近的字符的信息。 可以将此消息发送到编辑控件或富编辑控件。
281    富编辑控件:返回值指定了距指定点最近字符的从零开始的字符索引。 如果指定点超出控件中的最后一个字符,则返回值会指示编辑控件中的最后一个字符。
282    编辑控件:LOWORD 指定距指定点最近字符的从零开始的索引。 此索引相对于控件的开头,而不是行的开头。 如果指定点超出了编辑控件中的最后一个字符,则返回值将指示控件中的最后一个字符。 HIWORD 指定包含字符的行的从零开始的索引。 对于单行编辑控件,此值为零。 如果指定点超出行中的最后一个可见字符,则索引会指示行分隔符。
283    富编辑:在 Microsoft Rich Edit 1.0 及更高版本中受支持。 有关富编辑版本与各种系统版本兼容性的信息,请参阅关于富编辑控件。
284    如果某个点位于编辑控件边界之外,则 lResult 为 (65535, 65535)。
285    `x` 某个点的X坐标。
286    `y` 某个点的Y坐标。
287    */
288    fn char_from_pos(&self, x: i32, y: i32) -> i32;
289
290    /**
291    查询编辑控件中指定字符的坐标。
292    返回值是字符 (x, y) 的位置。对于单行编辑控件,y 坐标始终为零。
293    最后一个字符之外的任何索引都返回 –1。
294    如果字符已滚动到编辑控件的工作区之外,则返回的坐标可以为负数。坐标被截断为整数值。
295    如果  char_index  是行分隔符的索引,则返回的坐标位于行中最后一个可见字符刚好经过的位置。
296    如果  char_index  大于控件中最后一个字符的索引,则返回的坐标的位置刚好超过控件的最后一个字符。
297    `char_index` 指定字符的从零开始的索引。
298    */
299    fn pos_from_char(&self, char_index: i32) -> (i32, i32);
300
301    //noinspection SpellCheckingInspection
302    /**
303    确定 Rich Edit 控件的选择类型。
304    如果所选内容为空,则返回值SEL_EMPTY。
305    如果所选内容不为空,则返回值是一组包含以下一个或多个值的标志。
306    对于无底丰富编辑控件的父控件 ,此 消息在WM_SIZE处理期间非常有用。
307    - SEL_TEXT 文本。
308    - SEL_OBJECT 至少一个 COM 对象。
309    - SEL_MULTICHAR 文本的多个字符。
310    - SEL_MULTIOBJECT 多个 COM 对象。
311    */
312    fn selection_type(&self) -> RICH_EDIT_GET_CONTEXT_MENU_SEL_TYPE;
313
314    /**
315    隐藏或显示富编辑控件中的选定内容。
316    `hide` 是否隐藏。
317    */
318    fn hide_selection(&self, hide: bool);
319
320    //noinspection SpellCheckingInspection
321    /**
322    在 Rich Edit 控件中查找文本。
323    如果找到目标字符串,则返回值为匹配的第一个字符的从零开始的位置。 如果未找到目标,则返回值为 -1。
324    向后搜索时,  min  必须等于或大于  max 。 向前搜索时,  max  中的值 -1 会将搜索范围扩展到文本的末尾。
325    `flags` 指定搜索操作的参数。 此参数可使用以下一个或多个值。
326    - FR_DOWN Microsoft Rich Edit 2.0 及更高版本:如果设置,则搜索从当前所选内容的末尾到文档末尾。 如果未设置,则搜索将从当前所选内容的末尾到文档的开头。Microsoft Rich Edit 1.0:忽略FR_DOWN标志。 搜索始终从当前所选内容的末尾到文档的末尾。
327    - FR_MATCHALEFHAMZA Microsoft Rich Edit 3.0 及更高版本:如果设置,搜索将区分具有不同口音的阿拉伯语 alef。 如果未设置,则由 alef 字符单独匹配所有 alef。
328    - FR_MATCHDIAC Microsoft Rich Edit 3.0 及更高版本:如果设置,搜索操作将考虑阿拉伯语和希伯来语音调符号。 如果未设置,则忽略音调符号。
329    - FR_MATCHKASHIDA Microsoft Rich Edit 3.0 及更高版本:如果设置,则搜索操作将视为阿拉伯语 kashida。 如果未设置,则忽略 kashidas。
330    - FR_MATCHWIDTH Windows 8:如果设置,则同一字符的单字节和双字节版本被视为不相等。
331    - FR_WHOLEWORD 如果已设置,则操作仅搜索与搜索字符串匹配的整个单词。 如果未设置,该操作还会搜索与搜索字符串匹配的单词片段。
332    `text` 要查找的文本。
333    `min` 最小索引。
334    `max` 最大索引。
335    */
336    fn find_text(&self, flags: FINDREPLACE_FLAGS, text: &str, min: i32, max: i32) -> i32;
337
338    //noinspection SpellCheckingInspection
339    /**
340    查找格式编辑控件中的文本。
341    `flags` 指定搜索操作的行为。 此参数可使用以下一个或多个值。
342    - FR_DOWN Microsoft Rich Edit 2.0 及更高版本:如果设置,则从 min 向前搜索;如果未设置,则从 min 向后搜索。 Microsoft Rich Edit 1.0:忽略FR_DOWN标志。 搜索始终向前。
343    - FR_MATCHALEFHAMZA Microsoft Rich Edit 3.0 及更高版本:如果设置,搜索将区分具有不同重音的阿拉伯语和希伯来语。 如果未设置,则所有 alef 都单独与 alef 字符匹配。
344    - FR_MATCHCASE 如果设置,则搜索操作区分大小写。 如果未设置,则搜索操作不区分大小写。
345    - FR_MATCHDIAC Microsoft Rich Edit 3.0 及更高版本:如果设置,则搜索操作将考虑阿拉伯语和希伯来语音调符号。 如果未设置,则忽略音调符号。
346    - FR_MATCHKASHIDA Microsoft Rich Edit 3.0 及更高版本:如果设置,则搜索操作将考虑阿拉伯语和希伯来语 kashidas。 如果未设置,则忽略 kashidas。
347    - FR_WHOLEWORD 如果已设置,则操作仅搜索与搜索字符串匹配的整个单词。 如果未设置,该操作还会搜索与搜索字符串匹配的单词片段。
348    如果找到目标字符串,则返回值是匹配项的第一个字符的从零开始的位置。 如果未找到目标,则返回值为 -1。
349    向后搜索时, min 必须等于或大于 max。 向前搜索时, max 中的值 -1 会将搜索范围扩展到文本的末尾。
350    `text` 要查找的文本。
351    `min` 最小索引。
352    `max` 最大索引。
353    */
354    fn find_text_ex(&self, flags: FINDREPLACE_FLAGS, text: &str, min: i32, max: i32) -> (i32, i32);
355
356    //noinspection SpellCheckingInspection
357    /**
358    获取编辑控件的左边距和右边距的宽度。
359    返回 LOWORD 中左边距的宽度,以及 HIWORD 中右边距的宽度。
360    Rich Edit:  不支持  EM_GETMARGINS  消息。
361    */
362    fn get_margins(&self) -> i32;
363
364    //noinspection SpellCheckingInspection
365    /**
366    设置编辑控件的左边距和右边距的宽度。该消息将重新绘制控件以反映新的边距。
367    `margin` 指定要设置的边距。下表显示了可以组合的可能值。
368    - EC_LEFTMARGIN 设置左边距。
369    - EC_RIGHTMARGIN 设置右边距。
370    `value` LOW指定左边距的宽度(以像素为单位)。如果 margin 不包括 EC_LEFTMARGIN,则忽略此值。HIGH 指定右边距的宽度(以像素为单位)。如果 margin 不包括 EC_RIGHTMARGIN,则忽略此值。
371    */
372    fn set_margins(&self, margin: u32, value: i32);
373}
374
375impl Edit for WindowControl {
376    fn get_line(&self, index: i32, len: u16) -> Option<String> {
377        let mem = InProcessMemory::new(self.get_process_handle(), (len * 2 + 1) as usize).unwrap();
378        mem.write(&len as *const u16 as _, 1);
379        let (_, _) = self.send_message(
380            EM_GETLINE,
381            WPARAM(index as usize),
382            LPARAM(mem.as_ptr() as isize),
383        );
384        mem.read(|buf| (buf as *const u16).to_string_utf16())
385    }
386
387    fn line_length(&self, position: i32) -> usize {
388        let (_, res) =
389            self.send_message(EM_LINELENGTH, WPARAM(position as usize), LPARAM::default());
390        res
391    }
392
393    fn line_index(&self, line_index: i32) -> i32 {
394        let (_, res) =
395            self.send_message(EM_LINEINDEX, WPARAM(line_index as usize), LPARAM::default());
396        res as i32
397    }
398
399    fn replace_sel(&self, allow_undo: bool, text: &str) {
400        let text = CString::new(text).unwrap();
401        let allow_undo = if allow_undo { WPARAM(1) } else { WPARAM(0) };
402        self.send_message(EM_REPLACESEL, allow_undo, LPARAM(text.as_ptr() as isize));
403    }
404
405    fn set_readonly(&self, enable: bool) -> usize {
406        let enable = if enable { WPARAM(1) } else { WPARAM(0) };
407        let (_, res) = self.send_message(EM_SETREADONLY, enable, LPARAM::default());
408        res
409    }
410
411    fn get_text_range(&self, min: i32, max: i32) -> Option<String> {
412        let len = (max - min).abs();
413        let mem = InProcessMemory::new(self.get_process_handle(), (len * 2 + 1) as usize).unwrap();
414        let range2 = TEXTRANGEW {
415            chrg: CHARRANGE {
416                cpMax: max,
417                cpMin: min,
418            },
419            lpstrText: PWSTR(mem.as_ptr() as *mut u16),
420        };
421        self.send_message(
422            EM_GETTEXTRANGE,
423            WPARAM::default(),
424            LPARAM(&range2 as *const TEXTRANGEW as isize),
425        );
426        mem.read(|buf| (buf as *const u16).to_string_utf16())
427    }
428
429    fn can_undo(&self) -> bool {
430        let (_, res) = self.send_message(EM_CANUNDO, WPARAM::default(), LPARAM::default());
431        res != 0
432    }
433
434    fn empty_undo_buffer(&self) {
435        self.send_message(EM_EMPTYUNDOBUFFER, WPARAM::default(), LPARAM::default());
436    }
437
438    fn get_first_visible_line(&self) -> i32 {
439        let (_, res) =
440            self.send_message(EM_GETFIRSTVISIBLELINE, WPARAM::default(), LPARAM::default());
441        res as i32
442    }
443
444    fn get_line_count(&self) -> usize {
445        let (_, res) = self.send_message(EM_GETLINECOUNT, WPARAM::default(), LPARAM::default());
446        res
447    }
448
449    fn get_modify(&self) -> bool {
450        let (_, res) = self.send_message(EM_GETMODIFY, WPARAM::default(), LPARAM::default());
451        res != 0
452    }
453
454    fn set_modify(&self, is_modified: bool) {
455        let is_modified = if is_modified { WPARAM(1) } else { WPARAM(0) };
456        self.send_message(EM_SETMODIFY, is_modified, LPARAM::default());
457    }
458
459    fn get_rect(&self) -> RECT {
460        let mut rect = unsafe { std::mem::zeroed() };
461        self.send_message(
462            EM_GETRECT,
463            WPARAM::default(),
464            LPARAM(&mut rect as *mut RECT as isize),
465        );
466        rect
467    }
468
469    fn get_sel(&self) -> (i32, i32) {
470        let (mut start, mut end) = unsafe { std::mem::zeroed() };
471        self.send_message(
472            EM_GETSEL,
473            WPARAM(&mut start as *mut i32 as usize),
474            LPARAM(&mut end as *mut i32 as isize),
475        );
476        (start, end)
477    }
478
479    fn get_sel_ex(&self) -> (i32, i32) {
480        let mut cr: CHARRANGE = unsafe { std::mem::zeroed() };
481        self.send_message(
482            EM_EXGETSEL,
483            WPARAM::default(),
484            LPARAM(&mut cr as *mut CHARRANGE as isize),
485        );
486        (cr.cpMin, cr.cpMax)
487    }
488
489    fn set_sel(&self, start: i32, end: i32) {
490        self.send_message(EM_SETSEL, WPARAM(start as usize), LPARAM(end as isize));
491    }
492
493    fn set_sel_ex(&self, min: i32, max: i32) -> usize {
494        let cr = CHARRANGE {
495            cpMin: min,
496            cpMax: max,
497        };
498        let (_, res) = self.send_message(
499            EM_EXSETSEL,
500            WPARAM::default(),
501            LPARAM(&cr as *const CHARRANGE as isize),
502        );
503        res
504    }
505
506    fn get_sel_text(&self, len: usize) -> Option<String> {
507        let mem = InProcessMemory::new(self.get_process_handle(), len * 2 + 1).unwrap();
508        self.send_message(
509            EM_GETSELTEXT,
510            WPARAM::default(),
511            LPARAM(mem.as_ptr() as isize),
512        );
513        mem.read(|buf| (buf as *const u16).to_string_utf16())
514    }
515
516    fn line_from_char(&self, position: i32) -> i32 {
517        let (_, res) = self.send_message(
518            EM_LINEFROMCHAR,
519            WPARAM(position as usize),
520            LPARAM::default(),
521        );
522        res as i32
523    }
524
525    fn line_from_char_ex(&self, position: i32) -> i32 {
526        let (_, res) = self.send_message(
527            EM_EXLINEFROMCHAR,
528            WPARAM::default(),
529            LPARAM(position as isize),
530        );
531        res as i32
532    }
533
534    fn scroll(&self, command: SCROLLBAR_COMMAND) -> isize {
535        let (_, res) = self.send_message(EM_SCROLL, WPARAM(command.0 as usize), LPARAM::default());
536        res as isize
537    }
538
539    fn line_scroll(&self, column: i32, line: i32) -> bool {
540        let (_, res) = self.send_message(
541            EM_LINESCROLL,
542            WPARAM(column as usize),
543            LPARAM(line as isize),
544        );
545        res != 0
546    }
547
548    fn scroll_caret(&self) {
549        self.send_message(EM_SCROLLCARET, WPARAM::default(), LPARAM::default());
550    }
551
552    fn can_paste(&self) -> bool {
553        let (_, res) = self.send_message(EM_CANPASTE, WPARAM::default(), LPARAM::default());
554        res != 0
555    }
556
557    fn char_from_pos(&self, x: i32, y: i32) -> i32 {
558        let point = POINT { x, y };
559        let (_, res) = self.send_message(
560            EM_CHARFROMPOS,
561            WPARAM::default(),
562            LPARAM(&point as *const POINT as isize),
563        );
564        res as i32
565    }
566
567    fn pos_from_char(&self, char_index: i32) -> (i32, i32) {
568        let (_, res) = self.send_message(
569            EM_POSFROMCHAR,
570            WPARAM(char_index as usize),
571            LPARAM::default(),
572        );
573        ((res & 0xffff) as i32, (res >> 16) as i32)
574    }
575
576    fn selection_type(&self) -> RICH_EDIT_GET_CONTEXT_MENU_SEL_TYPE {
577        let (_, res) = self.send_message(EM_SELECTIONTYPE, WPARAM::default(), LPARAM::default());
578        RICH_EDIT_GET_CONTEXT_MENU_SEL_TYPE(res as u16)
579    }
580
581    fn hide_selection(&self, hide: bool) {
582        let hide = if hide { WPARAM(1) } else { WPARAM(0) };
583        self.send_message(EM_HIDESELECTION, hide, LPARAM::default());
584    }
585
586    fn find_text(&self, flags: FINDREPLACE_FLAGS, text: &str, min: i32, max: i32) -> i32 {
587        let find = FINDTEXTW {
588            chrg: CHARRANGE {
589                cpMin: min,
590                cpMax: max,
591            },
592            lpstrText: PCWSTR(HSTRING::from(text).as_ptr()),
593        };
594        let (_, res) = self.send_message(
595            EM_FINDTEXT,
596            WPARAM(flags.0 as usize),
597            LPARAM(&find as *const FINDTEXTW as isize),
598        );
599        res as i32
600    }
601
602    fn find_text_ex(&self, flags: FINDREPLACE_FLAGS, text: &str, min: i32, max: i32) -> (i32, i32) {
603        let mut find = FINDTEXTEXW {
604            chrg: CHARRANGE {
605                cpMin: min,
606                cpMax: max,
607            },
608            lpstrText: PCWSTR(HSTRING::from(text).as_ptr()),
609            chrgText: CHARRANGE::default(),
610        };
611        let (_, _) = self.send_message(
612            EM_FINDTEXT,
613            WPARAM(flags.0 as usize),
614            LPARAM(&mut find as *mut FINDTEXTEXW as isize),
615        );
616        (find.chrgText.cpMin, find.chrgText.cpMax)
617    }
618
619    fn get_margins(&self) -> i32 {
620        let (_, res) = self.send_message(EM_GETMARGINS, WPARAM::default(), LPARAM::default());
621        res as i32
622    }
623
624    fn set_margins(&self, margin: u32, value: i32) {
625        self.send_message(
626            EM_SETMARGINS,
627            WPARAM(margin as usize),
628            LPARAM(value as isize),
629        );
630    }
631}