【问题标题】:AxAcroPDF swallowing keys, how to get it to stop?AxAcroPDF 吞键,如何让它停止?
【发布时间】:2011-03-05 17:29:39
【问题描述】:

AxAcroPDF 会在获得焦点后立即吞下所有与键相关的事件,包括快捷键、按键等。我添加了一个消息过滤器,它也没有收到任何与键相关的消息。它是一个 COM 组件,这可能是相关的吗?

有什么方法可以在控件开始吞噬它们之前捕获它们?

【问题讨论】:

    标签: c# pdf com axacropdf


    【解决方案1】:

    Hans 是正确的,Acrobat Reader 会生成两个子 AcroRd32 进程,您无法从托管代码中直接访问它们。

    我已经对此进行了实验,您有三个可行的选择:

    1. 您可以创建一个全局系统挂钩,然后查找并过滤/响应发送到您的子 AcroRd32 窗口的 WM_SETFOCUS 消息。您可以使用包装库在 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. 找到一个可接受的 hack。根据您的应用程序需要的健壮程度,以下代码可能是合适的(它适合我的情况):

      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();
      }
      

    【讨论】:

    • +1 用于简洁的回复,尽管特定的可接受的黑客对我不起作用(离开事件 + 文本框而不是列表框的 LostFocus 事件) - 我尝试了其他建议的解决方案,其中很多对 axAcroPDF + 网络焦点问题的回复 - 使用计时器并在调用 AxAcroPDF.LoadFile 后立即激活它,将焦点设置回 Tick 事件处理程序内的表单,然后立即停用计时器
    【解决方案2】:

    我可能终于有一个简单得可笑的答案了。到目前为止,在测试中这是有效的。

    这个问题已经困扰了很长一段时间,并且已经为每个自定义控件构建了一个复杂的系统,记录它们中的最后一个有焦点并使用计时器将焦点翻转回来(当 acropdf 抓住它时)我重新审视了这个问题并阅读了大量答案(寻找最近的解决方案)。收集到的信息帮助我有了这个想法。

    这个想法是在加载时禁用 (acropdf) 控件,如下例所示(为清晰起见,代码已简化)

    AxAcroPDF_this.Enabled = False
    
    AxAcroPDF_this.src = m_src
    

    然后在一个计时器上,比如 1 秒后。

    AxAcroPDF_this.Enabled = True
    

    基本上这个想法是告诉 Windows 在允许之前不要让用户使用 acropdf 控件,因此要求 Windows 阻止它获得焦点(因为那里不允许用户使用)。

    到目前为止,这一直存在,如果有任何变化,我将对其进行编辑。如果它不完全适合你,那么这个想法可能指向一个有用的方向。

    【讨论】:

    【解决方案3】:

    这是一个进程外 COM 组件,这就是问题所在。完全违反了 SetParent() 中规定的 Windows SDK 要求。一旦其窗口获得焦点,acroread.exe 进程中的消息循环将获取所有消息,您的消息过滤器将无法再看到任何消息。

    从技术上讲,它可以通过使用 SetWindowsHookEx() 将 DLL 注入进程并使用 WH_GETMESSAGE 监视消息来修复。但是你不能用 C# 语言编写这样的 DLL。

    很糟糕,我知道。该程序似乎从来没有缺少它。

    【讨论】:

    • Adobe 违反了 SDK 要求?说不是这样!修复听起来比我目前的需求要多一些,但很高兴知道以防将来发生变化。
    【解决方案4】:

    出于某种原因,蒂姆的回答,直接禁用 AxAcroPDF 控件,在我的情况下不起作用。先前选择的文本框上的 Leave 事件也永远不会触发。

    正在工作的是将 AxAcroPDF 控件嵌套在禁用的 GroupBox 内。由于我的应用程序的用户只需要查看 PDF,而不需要与之交互,因此 GroupBox 的 Enabled 属性在设计器中设置为 False。

    【讨论】:

    • 好主意 - 我正在重新审视我的代码/建议(已经工作了多年),因为我怀疑 Acropdf 会导致罕见但麻烦的挂起/崩溃,而我的解决方案中没有错误(根据 Windows 事件)。我喜欢永久禁用容器的想法。我一直讨厌计时器,也没有找到一种可靠的方法来确定阅读器何时完成。因为我已经挂钩了用于导航的 Windows 热键,所以无论如何我都不需要用户输入。
    猜你喜欢
    • 2012-07-14
    • 2013-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多