3

The AxAcroPDF swallows all key-related events as soon as it gets focus, including shortcuts, key presses, etc. I added a message filter, and it doesn't get any key-related messages either. It's a COM component, could that be relevant?

Is there any way to catch these before the control starts swallowing them?

Joel Rein
  • 3,608
  • 1
  • 26
  • 32

4 Answers4

4

I might finally have a ridiculously simple answer. So far in testing this is working.

Having suffered from this problem for quite some time and having built a complex system of each custom control recording which of them last had focus and using a timer to flip focus back (when acropdf grabbed it) I revisited this problem and read a great number of answers (looking for recent solutions). The information gleaned helped me with the idea.

The idea is to disable the (acropdf) control whilst it is loading as in the following example (code reduced for clarity)

AxAcroPDF_this.Enabled = False

AxAcroPDF_this.src = m_src

Then on a timer, after say 1 second.

AxAcroPDF_this.Enabled = True

Basically the idea is to tell Windows not to let users use the acropdf control until allowed, so asking Windows to prevent it from getting focus (because users are not allowed in there).

So far this is holding up, I will edit this if anything changes. If it doesn't work completely for you then maybe the idea points into a useful direction.

L_J
  • 2,351
  • 10
  • 23
  • 28
Tim
  • 81
  • 3
  • I created an extension method for this (Windows Forms only): https://gist.github.com/bertvansteen/ec180b645fd6bcfd179e – bvs May 28 '14 at 10:36
4

Hans is correct, the Acrobat Reader spawns two child AcroRd32 processes which you have no direct access to from within your managed code.

I have experimented with this and you have three viable options:

  1. You can create a global system hook, and then look for and filter out / respond to WM_SETFOCUS messages sent to your child AcroRd32 windows. You can accomplish some of this from within C# by using a wrapper library, such as the one here: http://www.codeproject.com/KB/system/WilsonSystemGlobalHooks.aspx

    You also need to identify the correct processes as there may be more than one instance of your application, or other instances of AcroRd32. This is the most deterministic solution, but because your application will now be filtering messages sent to every single window in existence, I generally don't recommend this approach because then your program could negatively affect system stability.

  2. Find an alternate PDF viewing control. See this answer for a few commercial components: .net PDF Viewer control , or roll your own: http://www.codeproject.com/KB/applications/PDFViewerControl.aspx

  3. Find an acceptable hack. Depending on how robust your application needs to be, code such as the following may be suitable (it was suitable for my case):

    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();
    }
    
Community
  • 1
  • 1
Kevin McCormick
  • 2,358
  • 20
  • 20
  • +1 for concise reply, although the particular acceptable hack didn't work for me (Leave event + TextBox instead of LostFocus event of a ListBox) - i tried the other suggested solution that figures a lot in the replies to axAcroPDF + focus questions around the web - using Timer and activating it right after calling AxAcroPDF.LoadFile, setting focus back to the form inside the Tick event handler, and deactivating the timer right afterwards – hello_earth Mar 26 '12 at 09:50
2

For some reason Tim's answer, disabling the AxAcroPDF control directly, didn't work in my case. The Leave event on the previously-selected Textbox would never fire, either.

What is working is nesting the AxAcroPDF control inside of a disabled GroupBox. Since the users of my application need to only see the PDF, not interact with it, the GroupBox's Enabled property is set to False in the designer.

MikeTV
  • 645
  • 6
  • 14
  • Good idea - I am revisiting my code/suggestion (been working for years) because I suspect Acropdf is causing rare but troublesime hangs/crashes with no errors within my solution (according to Windowns events). I like the idea of permanently disabling a container. I always hated the timer and haven't found a relaible way of determining when the Reader has finished. Since I have hooked windows hot keys for navigation I don't need user input in there anyway. – Tim F. Jun 05 '20 at 08:15
2

It is an out-of-process COM component, that's the problem. Completely in violation of Windows SDK requirements as laid out in SetParent(). Once its window gets the focus, the message loop in the acroread.exe process gets all the messages, your message filter cannot see any messages anymore.

Technically it is fixable by using SetWindowsHookEx() to inject a DLL into the process and monitor messages with WH_GETMESSAGE. But you can't write such a DLL in the C# language.

Major suck, I know. There never seems to be any lack of it with that program.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Adobe violating the SDK requirements? Say it ain't so! The fix sounds like a bit more effort than I can justify for my needs at the moment, but good to know in case that changes in the future. – Joel Rein Jun 19 '10 at 10:12