WinAPI - проблема с добавлением текста в поле редактирования

Я создал простое окно с многострочным Edit Control:

Edit = CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("EDIT"), NULL,
                    WS_CHILD | WS_VISIBLE | ES_MULTILINE,
                    20, 200, 200, 200,
                    hWnd, (HMENU)EDIT, GetModuleHandle(NULL), NULL);

Если я устанавливаю текст с помощью сообщения WM_SETTEXT, я не получаю ошибки, но если я использую EM_REPLACESEL, я получаю ошибку 5 (ERROR_ACCESS_DENIED):

SendMessage(GetDlgItem(hWnd, EDIT), EM_REPLACESEL, 0, (LPARAM)TEXT("\r\nSome text"));
if (GetLastError()) {
    /* Error 5 ERROR_ACCESS_DENIED */
}

Та же проблема с EM_SETSEL:

SendMessage(GetDlgItem(hWnd, EDIT), EM_SETSEL, (WPARAM)(0),(LPARAM)(-1));
SendMessage(GetDlgItem(hWnd, EDIT), EM_REPLACESEL, 0, (LPARAM)TEXT("\r\nSome text"));
if (GetLastError()) {
    /* Error 5 ERROR_ACCESS_DENIED */
}

Я заметил, что если я отправлю сообщение WM_SETFOCUS перед EM_REPLACESEL, ошибки не будет:

SendMessage(GetDlgItem(hWnd, EDIT), WM_SETFOCUS, (WPARAM)GetDlgItem(hWnd, EDIT), 0);
SendMessage(GetDlgItem(hWnd, EDIT), EM_REPLACESEL, 0, (LPARAM)TEXT("\r\nSome text"));
if (GetLastError()) {
    /* NO ERRORS */
}

Как я могу решить эту проблему? Должен ли я отправлять сообщение WM_SETFOCUS перед сообщением EM_REPLACESEL каждый раз, когда я хочу добавить какой-либо текст в свое поле редактирования?

Спасибо за помощь!


person Mario    schedule 03.08.2010    source источник
comment
Что, если вы просто SetLastError(0) отправите сообщение EM_REPLACESEL?   -  person Adam Rosenfield    schedule 22.01.2011


Ответы (6)


Вы можете просто использовать сначала EM_SETSEL, а затем EM_REPLACESEL.

Пример:

SendMessage(hwnd, EM_SETSEL, WPARAM(0), LPARAM(-1) );
SendMessage(hwnd, EM_REPLACESEL, WPARAM(TRUE), LPARAM(str) );
person Brian R. Bondy    schedule 03.08.2010
comment
@Марио, если вы получаете ошибку 5 (отказано в доступе), это означает, что у вас нет соответствующих прав. - person Abel; 03.08.2010

Скорее всего, вам отказано в доступе из-за UIPI.

Поле редактирования создано тем же приложением, которое пытается отправлять сообщения? Если нет, приложение, выполняющее SendMessage, вероятно, имеет более низкий уровень UIPI, чем приложение, которому принадлежит Edit.

Если вы действительно являетесь владельцем как приложения, создавшего элемент управления Edit, так и приложения, отправляющего сообщения, вы можете разрешить ввод определенных сообщений с помощью ChangeWindowMessageFilterEx.

ChangeWindowMessageFilterEx(hwndOfWindowReceivingMessage, EM_REPLACESEL, 
    MSGFLT_ALLOW, NULL);
person Collin Dauphinee    schedule 03.08.2010
comment
Да, поле редактирования создается тем же приложением. Я также пробовал ваш код перед EM_REPLACESEL: ChangeWindowMessageFilterEx(GetDlgItem(hWnd, EDIT), EM_REPLACESEL, MSGFLT_ALLOW, NULL); но я получаю ту же ошибку. - person Mario; 03.08.2010
comment
Не могли бы вы проверить, удалось ли выполнить ChangeWindowMessageFilterEx? Если нет, то какой код ошибки? - person Collin Dauphinee; 03.08.2010
comment
ChangeWindowMessageFilterEx удалось, но, поскольку элемент управления Edit создается тем же приложением, должен ли я в любом случае вызывать ChangeWindowMessageFilterEx? - person Mario; 03.08.2010
comment
Вы не должны. Но, насколько мне известно, только проблемы с UIPI могут привести к ошибкам отказа в доступе к SendMessage. Но если все содержится в одном приложении, это не должно быть проблемой. Я не уверен, в чем может быть проблема. - person Collin Dauphinee; 03.08.2010

К сожалению, GetLastError не задокументирован как поддерживаемый для EM_REPLACESEL, что означает, что вам придется разработать альтернативную стратегию для обнаружения сбоев. Возможно, некоторые вычисления длины текста сработают.

Сказав это, мне было любопытно, почему возвращается ошибка отказа в доступе. Я установил точку останова данных по адресу, где SetLastError/GetLastError хранят код ошибки, и обнаружил, что он находится глубоко внутри GDI, а не непосредственно из элемента управления редактированием. Не очень полезно, но, по крайней мере, интересный лакомый кусочек.

person Jerry Joyce    schedule 21.01.2011

Возможно, вам придется использовать SendDlgItemMessage вместо SendMessage.

person Slapout    schedule 21.01.2011

Обратите внимание, что EM_SETSEL, EM_REPLACESEL и т. д. воздействуют на каретку; если фокус находится не на элементе управления, у него нет курсора, и эти сообщения не будут работать. Либо ваш пользователь должен щелкнуть элемент управления, чтобы он получил фокус, либо вы должны сначала выполнить WM_SETFOCUS. К сожалению, именно так работает элемент управления, он не запоминает выделение после того, как теряет фокус (и не может иметь память до того, как получит его).

person Fabio Ceconello    schedule 21.01.2011

Попробуй это

wchar_t buffer[256] = _T("here I am at camp granada \r\n");
int ndx = GetWindowTextLength (hEdit);
SetFocus (hEdit);
SendMessage(hEdit, EM_SETSEL, (WPARAM)ndx, (LPARAM)ndx);
SendMessage(hEdit, EM_REPLACESEL, WPARAM(TRUE), (LPARAM)buffer );
person user2679015    schedule 13.08.2013