Excel крадет фокус клавиатуры из VCL Form (в AddIn) - PullRequest
1 голос
/ 09 мая 2019

У меня есть надстройка Excel, написанная на Delphi, в которой есть форма VCL с TMemo. Когда я пытаюсь ввести текст в заметку, вместо этого вводится Excel.

enter image description here

Когда я запускаю модальную форму (ShowModal), все работает нормально, но, очевидно, невозможно одновременно работать с главным окном Excel и окном надстройки.

Кажется, что проблема в точности похожа на этот вопрос: Немодальная форма не может получать ввод с клавиатуры в надстройке Excel, разработанной Delphi

Этот ответ предлагает обработать WM_PARENTNOTIFY, поэтому я попробовал следующее:

TMyForm = class(TForm)
...
 procedure OnParentNotify(var Msg: TMessage); message WM_PARENTNOTIFY;

И в этой процедуре пробовали такие вещи, как SetFocus, WinApi.Windows.SetFocus(self.Handle), SetForeGroundWindows, SetActiveWindow, но, похоже, это не сработало.

Другие предложения, которые я прочитал: запустить пользовательский интерфейс в другом потоке (что, конечно, невозможно с VCL) и установить клавиатуру с SetWindowsHookEx. Очевидно, это даст нам события нажатия клавиш, но не уверен, что с ними делать.

Я не использую сторонние инструменты, такие как Add-In Express, а просто реализую IDTExtensibility2.

РЕДАКТИРОВАТЬ: дополнительные исследования показывают, что Office использует интерфейс под названием IMsoComponent и IMsoComponentManager в качестве способа отслеживания активного компонента в приложении. Visual Studio использует их как IOleComponent и IOleComponentManager .

Эта ссылка и Эта одна предлагает зарегистрировать новый пустой IOleComponent / IMsoComponent.

EDIT : MCVE можно получить здесь , это наименьший возможный код Excel AddIn, который запустит форму VCL с TEdit. Редактирование теряет фокус клавиатуры, как только лист активен.

1 Ответ

2 голосов
/ 26 мая 2019

У меня была такая же проблема.Я также реализую IDTExtensibility2, но, поскольку я делаю это на C ++, мне уже удалось запустить пользовательский интерфейс в другом потоке.Но в любом случае я не был полностью доволен этим решением.У меня все еще была бы эта проблема, если бы я хотел использовать VBA Userform в качестве окна TaskPane.Я пытался, но, поскольку (я думаю, не проверял) пользовательская форма VBA будет работать в нативном потоке Excel, просто вызывая его в другом потоке (для использования в качестве окна панели задач), просто упорядочив его, это не означало, что онбыл создан в другом потоке, так что, как я и пытался, возникла такая проблема.

Я тоже прочитал и попытался обработать сообщения WM_PARENTNOTIFY с SetFocus .. в моем окне, но не работал.

Это оба интерфейса IOleComponent и IOleComponentManager были новыми для меня.Не нашел файлов заголовков, но мог написать и реализовать из описаний по ссылке, которой вы поделились.

Для меня это работало, когда я регистрировал мою реализацию IOleComponent на каждой WM_SETCURSOR и WM_IME_SETCONTEXT в моем окне формы.(Я не уверен, что это точно лучшие сообщения, но у меня сработало) и отменять компонент при каждом щелчке назад в окне EXCEL7.

Параметры MSOCRINFO, которые я использовал для регистрации, были msocrfPreTranslateKey и msocadvfModal.

Надеюсь, что с этим ответом я не получу тонны критики.Я знаю, что это очень специфическая проблема, вопрос был со статусом -1, когда я ее читал, но это было именно то, что мне нужно было закончить с этим пунктом.Поэтому я просто пытаюсь быть честным и делиться чем-то в ответ.

...