7 / 7 / 1
Регистрация: 03.04.2012
Сообщений: 25
1

Окно с html страницей в приложении на winapi не копирует текст в буфер по crtl+C

23.04.2020, 16:15. Показов 19709. Ответов 7

Author24 — интернет-сервис помощи студентам
Есть приложение, написанное на winapi, которому нужно в своём окне показывать отрендеренный html. Для этого используется компонент на COM-объекте, внутри которого mshtml. Копирование выделенного текста в буфер через контекстное меню он поддерживает. Но копирование по Ctrl+C - нет. Процедура сабклассинга данного окна показала, что события нажатия клавиш типа WM_KEYDOWN, WM_CHAR съедаются внутри com-объекта и наружу не выходят. А значит отловить сообщение нажатия клавиш или клавиатурных акселераторов на данном этапе в приложении невозможно.
Событие вызова контекстного меню в приложение попадает и работает корректно. А сделано оно на OLE таким образом:

C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class CCustomControlSite : public COleControlSite
{
public:
    CCustomControlSite(COleControlContainer *pCnt):COleControlSite(pCnt){m_pWnd = NULL;}
 
    CWnd* m_pWnd; 
 
protected:
 
  DECLARE_INTERFACE_MAP();
BEGIN_INTERFACE_PART(DocHostUIHandler, IDocHostUIHandler)
  STDMETHOD(ShowContextMenu)(DWORD dwID,
             POINT __RPC_FAR *ppt,
             IUnknown __RPC_FAR *pcmdtReserved,
             IDispatch __RPC_FAR *pdispReserved);
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
HRESULT FAR EXPORT  CCustomControlSite::XDocHostUIHandler::ShowContextMenu(
        DWORD /*dwID*/, 
        POINT* /*pptPosition*/,
        IUnknown* /*pCommandTarget*/,
        IDispatch* /*pDispatchObjectHit*/)
{
  METHOD_PROLOGUE(CCustomControlSite, DocHostUIHandler);
 
    CWnd* pParent = pThis->m_pWnd->GetParent();
 
    NMHDR n;
    memset(&n, 0, sizeof(n));
    n.hwndFrom = pThis->m_pWnd->GetSafeHwnd();
    n.idFrom = pThis->m_pWnd->GetDlgCtrlID();
    n.code = NM_RCLICK;
    if (pParent->SendMessage(WM_NOTIFY, pThis->m_pWnd->GetDlgCtrlID(), (LPARAM) &n))
        return S_OK;
 
    return E_NOTIMPL;
}
Сообщение о клике правой кнопкой мыши отправляется в родительское окно, там ловится процедурой диалогового окна и выполняются все необходимые действия.

Клик левой кнопкой мыши обрабатывается таким образом:
C++ (Qt)
1
2
3
4
5
BEGIN_EVENTSINK_MAP(CHtmlWnd, CWnd)
 
ON_EVENT(CHtmlWnd, AFX_IDW_PANE_FIRST, 259 /* DocumentComplete */, OnDocumentComplete, VTS_DISPATCH VTS_PVARIANT)
 
END_EVENTSINK_MAP()
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void CHtmlWnd::OnDocumentComplete(LPDISPATCH pDisp, VARIANT FAR* URL)
{
    CComQIPtr<IDispatch> pHtml;
    CComQIPtr<IHTMLDocument2> pHtmlDoc;
    pHtml = m_wndBrowser.GetDocument();
    if (pHtml)
    {
        pHtml.QueryInterface(&pHtmlDoc);
    }
 
  if (pHtml && m_sHTML.GetLength() && pHtmlDoc)
  {
    IDispatchPtr mouseclick = EventHandler<CHtmlWnd>::CreateHandler(this, &CHtmlWnd::MouseClick, DISPID_CLICK);
    VARIANT vOnClick;
    V_VT(&vOnClick) = VT_DISPATCH;
    V_DISPATCH(&vOnClick) = mouseclick;
    pHtmlDoc->put_onclick(vOnClick);
 
    IDispatchPtr keyDown = EventHandler<CHtmlWnd>::CreateHandler(this, &CHtmlWnd::KeyDown, DISPID_KEYDOWN);
    VARIANT vKeyDown;
    V_VT(&vKeyDown) = VT_DISPATCH;
    V_DISPATCH(&vKeyDown) = keyDown;
    HRESULT res = pHtmlDoc->put_onkeydown(vKeyDown);
  }
}
Здесь же я попытался через события документа пробросить событие KeyDown, но это ни к чему не привело. В заданный коллбэк исполнение кода не заходит вообще.

Пробовал пробросить события так же таким способом:
C++ (Qt)
1
2
3
4
5
6
7
8
9
BEGIN_MESSAGE_MAP(CHtmlWnd, CWnd)
  ON_WM_CREATE()
  ON_WM_DESTROY()
  ON_WM_SIZE()
  ON_WM_CONTEXTMENU()
  ON_WM_HOTKEY()
  ON_WM_KEYDOWN()
  ON_WM_CHAR()
END_MESSAGE_MAP()
Но в заданные коллбэки WM_CHAR, WM_KEYDOWN, WM_HOTKEY исполнение кода так же не заходит.
Буду признателен за любую помощь.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
23.04.2020, 16:15
Ответы с готовыми решениями:

Почему clipboard.settext(str) копирует текст в буфер обмена без абзацев?
Почему clipboard.settext(str) копирует текст в буфер обмена без абзацев? Например, я скопировал...

Отправить выбранный в стороннем приложении текст в буфер обмена
Как при выделении текста, в стороннем приложении, отправить его в буфер обмена.? Имитировать...

GCC + WinApi. Русский текст в GUI-приложении
Здравствуйте! Как заставить WinApi корректно выводить русский текст в заголовках окна,...

WinAPI: Как нажать кнопку в другом приложении, если в нем открыто модальное окно
В общем есть пару вопросов; 1) Как по заголоку окна узнать имя класса 2) int hwnd...

7
6770 / 4564 / 1843
Регистрация: 07.05.2019
Сообщений: 13,726
23.04.2020, 18:14 2
Цитата Сообщение от Kandelyabr Посмотреть сообщение
Но в заданные коллбэки WM_CHAR, WM_KEYDOWN, WM_HOTKEY исполнение кода так же не заходит.
Посмотри в сторону CDHtmlDialog::TranslateAccelerator
1
7 / 7 / 1
Регистрация: 03.04.2012
Сообщений: 25
24.04.2020, 20:43  [ТС] 3
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Посмотри в сторону CDHtmlDialog::TranslateAccelerator
В коде есть реализация IDocHostUIHandler, которая содержит в том числе TranslateAccelerator, но он не вызывается при нажатии комбинации. Это играет какую-то роль, или нужна реализация именно CDHtmlDialog?
0
6770 / 4564 / 1843
Регистрация: 07.05.2019
Сообщений: 13,726
24.04.2020, 21:12 4
Цитата Сообщение от Kandelyabr Посмотреть сообщение
В коде есть реализация IDocHostUIHandler, которая содержит в том числе TranslateAccelerator, но он не вызывается при нажатии комбинации. Это играет какую-то роль, или нужна реализация именно CDHtmlDialog?
Посмотри реализацию CDHtmlDialog. Это просто обёртка над IWebBrowser2 и в нём всё работает, в том числе ctrl+c.
Переопределил TranslateAccelerator - всё вызывается
C++
1
2
3
4
5
6
7
    STDMETHOD(TranslateAccelerator)(LPMSG lpMsg, const GUID *pguidCmdGroup, DWORD nCmdID) override
    {
        char buf[128];
        sprintf(buf, "key = %d: %c, ctrl = %X", lpMsg->wParam, char(lpMsg->wParam), ::GetAsyncKeyState(VK_CONTROL));
        ::SetWindowTextA(GetSafeHwnd(), buf);
        return S_OK;
    }
1
7 / 7 / 1
Регистрация: 03.04.2012
Сообщений: 25
25.04.2020, 14:04  [ТС] 5
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Посмотри реализацию CDHtmlDialog. Это просто обёртка над IWebBrowser2 и в нём всё работает, в том числе ctrl+c.
Переопределил TranslateAccelerator - всё вызывается
C++
1
2
3
4
5
6
7
    STDMETHOD(TranslateAccelerator)(LPMSG lpMsg, const GUID *pguidCmdGroup, DWORD nCmdID) override
    {
        char buf[128];
        sprintf(buf, "key = %d: %c, ctrl = %X", lpMsg->wParam, char(lpMsg->wParam), ::GetAsyncKeyState(VK_CONTROL));
        ::SetWindowTextA(GetSafeHwnd(), buf);
        return S_OK;
    }
Где мне следует это сделать? Переопределение CDHtmlDialog внутри CCustomControlSite как это сделано для IDocHostUIHandler не помогло

C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class CCustomControlSite:public COleControlSite
{
public:
    CCustomControlSite(COleControlContainer *pCnt):COleControlSite(pCnt){m_pWnd = NULL;}
 
    CWnd* m_pWnd; // Указатель на CHtmlWnd.
 
protected:
 
    DECLARE_INTERFACE_MAP();
BEGIN_INTERFACE_PART(DocHostUIHandler, IDocHostUIHandler)
...
END_INTERFACE_PART(DocHostUIHandler)
 
BEGIN_INTERFACE_PART(HtmlDialog, CDHtmlDialog)
    STDMETHOD(TranslateAccelerator)(LPMSG lpMsg, const GUID *pguidCmdGroup, DWORD nCmdID);
END_INTERFACE_PART(HtmlDialog)
};
0
6770 / 4564 / 1843
Регистрация: 07.05.2019
Сообщений: 13,726
25.04.2020, 16:55 6
Цитата Сообщение от Kandelyabr Посмотреть сообщение
Где мне следует это сделать? Переопределение CDHtmlDialog внутри CCustomControlSite как это сделано для IDocHostUIHandler не помогло
Я вот здесь делал
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// CTestHTMLDlg dialog
class CTestHTMLDlg : public CDHtmlDialog
{
// Construction
public:
    CTestHTMLDlg(CWnd* pParent = nullptr);  // standard constructor
.......................................
    STDMETHOD(TranslateAccelerator)(LPMSG lpMsg, const GUID *pguidCmdGroup, DWORD nCmdID) override
    {
        char buf[128];
        sprintf(buf, "key = %d: %c, ctrl = %X", lpMsg->wParam, char(lpMsg->wParam), ::GetAsyncKeyState(VK_CONTROL));
        ::SetWindowTextA(GetSafeHwnd(), buf);
        return S_OK;
    }
};
0
7 / 7 / 1
Регистрация: 03.04.2012
Сообщений: 25
25.04.2020, 17:17  [ТС] 7
oleg-m1973, А что в данной иерархии является родительским окном, передаваемым аргументом в конструктор? И кто создаёт, держит объект? Просто, похоже, у нас разные способы инициализации, если не вообще всё.
0
6770 / 4564 / 1843
Регистрация: 07.05.2019
Сообщений: 13,726
25.04.2020, 17:24 8
Цитата Сообщение от Kandelyabr Посмотреть сообщение
oleg-m1973, А что в данной иерархии является родительским окном, передаваемым аргументом в конструктор? И кто создаёт, держит объект? Просто, похоже, у нас разные способы инициализации, если не вообще всё.
От этого точно не зависит, окна создаются примерно одинаково.
CDHtmlDialog это просто модальное диалоговое окно
C++
1
2
    CTestHTMLDlg dlg;
    dlg.DoModal();
0
25.04.2020, 17:24
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
25.04.2020, 17:24
Помогаю со студенческими работами здесь

CopyToClipboard не копирует в буфер обмена
Всем привет. У меня такая проблема, я пытаюсь скопировать текст из поля Edit1 в буфер обмена: ...

Кнопка которая копирует содержимое в буфер обмена
Думаю, тут нет ничего тяжелого но никак не могу разобраться сам. Пишу приложение C# Windows Forms....

Очень медленно копирует из буфера в буфер (ОЗУ)
Добрый вечер! Прошу объяснить, в чем причина очень медленного копирования из одного буфера ОЗУ в...

Файлы: программа считывает текст из файла, добавляет в него текст, переименовывает, копирует и удаляет файл
составить программу,которая обеспечивает выполнение след.операций над текстовым файлом:считывает...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
8
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru