AxAcroPDF глотает ключи, как заставить его остановиться?

AxAcroPDF поглощает все связанные с ключами события, как только он получает фокус, включая ярлыки, нажатия клавиш и т. Д. Я добавил фильтр сообщений, и он также не получает никаких сообщений, связанных с ключами. Это COM-компонент, это может быть актуально?

Есть ли способ поймать их до того, как контроль начнет их проглатывать?

4 ответа

Решение

Ганс прав: Acrobat Reader порождает два дочерних процесса AcroRd32, к которым у вас нет прямого доступа из вашего управляемого кода.

Я экспериментировал с этим, и у вас есть три жизнеспособных варианта:

  1. Вы можете создать глобальный системный хук, а затем искать и отфильтровывать / отвечать на сообщения WM_SETFOCUS, отправленные в ваши дочерние окна AcroRd32. Вы можете сделать это из C# с помощью библиотеки-оболочки, например, здесь: http://www.codeproject.com/KB/system/WilsonSystemGlobalHooks.aspx

    Вам также необходимо определить правильные процессы, так как может быть более одного экземпляра вашего приложения или других экземпляров AcroRd32. Это наиболее детерминированное решение, но поскольку ваше приложение теперь будет фильтровать сообщения, отправляемые в каждое существующее окно, я обычно не рекомендую такой подход, потому что тогда ваша программа может негативно повлиять на стабильность системы.

  2. Найти альтернативный контроль просмотра PDF. Посмотрите этот ответ для нескольких коммерческих компонентов: .net PDF Viewer control или сверните свой собственный: http://www.codeproject.com/KB/applications/PDFViewerControl.aspx

  3. Найти приемлемый взломать. В зависимости от того, насколько надежным должно быть ваше приложение, может подойти такой код, как приведенный ниже (он подходит для моего случая):

    DateTime _lastRenav = DateTime.MinValue;
    
    public Form1()
    {
        InitializeComponent();
    
        listBox1.LostFocus += new EventHandler(listBox1_LostFocus);
    }
    
    private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
    {
        axAcroPDF1.src = "sample.pdf";  //this will cause adobe to take away the focus
        _lastRenav = DateTime.Now;
    }
    
    void listBox1_LostFocus(object sender, EventArgs e)
    {
        //restores focus if it were the result of a listbox navigation
        if ((DateTime.Now - _lastRenav).TotalSeconds < 1)
            listBox1.Focus();
    }
    

Я мог бы наконец получить смехотворно простой ответ. Пока в тестировании это работает.

Страдая от этой проблемы в течение достаточно долгого времени и построив сложную систему для каждой записи пользовательского элемента управления, какая из них в последний раз имела фокус, и используя таймер для возврата фокуса назад (когда acropdf схватил ее), я вновь обратился к этой проблеме и прочитал множество ответы (ищу последние решения). Полученная информация помогла мне с идеей.

Идея состоит в том, чтобы отключить элемент управления (acropdf) во время загрузки, как в следующем примере (код для ясности сокращен)

AxAcroPDF_this.Enabled = Ложный AxAcroPDF_this.src = m_src

Затем по таймеру, скажем, через 1 секунду.

AxAcroPDF_this.Enabled = False

По сути, идея состоит в том, чтобы сказать Windows не разрешать пользователям использовать элемент управления acropdf до тех пор, пока он не будет разрешен, поэтому просим Windows не допускать его фокусировки (поскольку пользователи там не допускаются).

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

По какой-то причине ответ Тима, напрямую отключив элемент управления AxAcroPDF, в моем случае не сработал. Событие Leave в ранее выбранном текстовом поле также никогда не будет запущено.

Что работает, так это размещение элемента управления AxAcroPDF внутри отключенного GroupBox. Поскольку пользователям моего приложения нужно только просматривать PDF-файл, а не взаимодействовать с ним, в конструкторе свойство Enabled для GroupBox имеет значение False.

Это внепроцессный COM-компонент, вот в чем проблема. Полностью нарушает требования Windows SDK, изложенные в SetParent(). Как только его окно получает фокус, цикл сообщений в процессе acroread.exe получает все сообщения, ваш фильтр сообщений больше не может видеть никаких сообщений.

Технически это можно исправить с помощью SetWindowsHookEx(), чтобы внедрить DLL в процесс и отслеживать сообщения с помощью WH_GETMESSAGE. Но вы не можете написать такую ​​DLL на языке C#.

Майор сосать, я знаю. Кажется, в этой программе никогда не было недостатка.

Другие вопросы по тегам