0

Adobe AxAcroPDF 控件没有返回当前页码的功能。我只是在做一个个人实用程序,所以我有幸找到了一种我认为我会分享的黑客方法……它是用网络上的零碎拼凑而成的。它使用来自 User32.dll 的 Windows 本机函数来枚举控件的子项,并在工具栏中找到与页码对应的文本框。然后使用 SendMessage 调用读取其中的文本。

4

1 回答 1

2

此方法枚举 adobe pdf 查看器的子组件并在工具栏中找到文本框。其中一个文本框是页码,一个是当前缩放值。内容中不带“%”的文本框作为页码文本框。使用 SendMessage 函数检索文本框的内容。

您可能需要首先在查看器组件上调用 SetToolbarVisible(true),以确保工具栏(以及文本框)可见。

这是一个可怕而骇人听闻的解决方案,并且随着 Adob​​e 更新查看器时很容易中断。如果 Adob​​e 能添加一个“getCurrentPage”方法,这样就可以避免所有这些,那就太好了。

  //you can get the handle parameter for this method as: yourPDFControl.Handle
  public static string GetPageNumber(IntPtr adobeViewerHandle)
    {
        //get a list of all windows held by parent 
        List<IntPtr> childrenWindows = new List<IntPtr>();
        GCHandle listHandle = GCHandle.Alloc(childrenWindows);
        try
        {
            EnumWindowProc childProc = new EnumWindowProc(EnumWindow);
            EnumChildWindows(adobeViewerHandle, childProc, GCHandle.ToIntPtr(listHandle));
        }
        finally
        {
            if (listHandle.IsAllocated)
                listHandle.Free();
        }

        //now have a list of the children, look for text boxes with class name "Edit"
        for (int i = 0; i < childrenWindows.Count; i++)
        {
            int nRet;
            // Pre-allocate 256 characters, the maximum class name length.
            StringBuilder ClassName = new StringBuilder(256);
            //Get the window class name
            nRet = GetClassName(childrenWindows.ElementAt(i), ClassName, ClassName.Capacity);

            if (ClassName.ToString().CompareTo("Edit") == 0)
            {
                IntPtr resultPointer = Marshal.AllocHGlobal(200);
                StringBuilder text = new StringBuilder(20);
                NativeMethods.SendMessage(childrenWindows.ElementAt(i), 0x000D, text.Capacity, text); //0x000D is WM_GETTEXT message
                if (text.ToString().Contains("%")) //we don't want the text box for the PDF scale (e.g. 66.7% zoomed etc.)
                {
                    continue;
                } else
                {
                    return text.ToString(); // the only other text box is the page number box
                }
            }
        }

        //Note I return as a string because PDF supports page labels, "I", "ii", "iv" etc. or even section labels "A", "B". So you're not guaranteed a numerical page number.
        return "0";

    }

    private static bool EnumWindow(IntPtr handle, IntPtr pointer)
    {
        GCHandle gch = GCHandle.FromIntPtr(pointer);
        List<IntPtr> list = gch.Target as List<IntPtr>;
        if (list == null)
            throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>");

        list.Add(handle);
        return true;
    }


        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal static extern bool EnumChildWindows(IntPtr window,
                                                        EnumWindowProc callback,
                                                        IntPtr i);

        internal delegate bool EnumWindowProc(IntPtr hWnd, IntPtr parameter);

        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        internal static extern int GetWindowTextLength(IntPtr hWnd);

        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        internal static extern int GetWindowText(IntPtr hWnd,
                                                   StringBuilder lpString,
                                                   int nMaxCount);

        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        internal static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);

        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        internal static extern bool SendMessage(IntPtr hWnd, uint Msg, int wParam, StringBuilder lParam);
于 2017-03-24T09:06:14.337 回答