zoukankan      html  css  js  c++  java
  • C#调用windows API实现 smallpdf客户端程序进行批量压缩

    一、背景


    Smallpdf 网站针对PDF文件提供了非常齐全的功能:PDF 与 Word、PPT、Excel、JPG 的相互转化、PDF 的压缩、编辑、合并、分割、解密、加密等功能,用户无需注册即可免费使用。

    但是不注册每小时只能处理有限的PDF,对于我们这种有大量PDF需要压缩的人来说就不太合适啦,所以购买了专业版,其在线版本提供了批量压缩的功能,需要上批量上传等待压缩后再下载(存在批量上传后,浏览器卡死或者无法压缩一直等待,以及压缩成功后无法下载,速度只有几十K),而客户端程序版本又没有批量压缩的功能,只能一篇一篇的打开压缩。

    为了解解上述问题,经过考虑,准备利用其客户端的压缩功能来进行批量压缩,虽然时间花得久点,但是在本地不用考虑网络因素这些,至少非常可控,但是是不可能人工一篇一篇来压的,所以这就是这篇文章的由来。

    Smallpdf website provides a very complete function for PDF files: PDF and Word, PPT, Excel, JPG mutual conversion, PDF compression, editing, merging, segmentation, decryption, encryption and other functions, users can use it for free without registration.
    But if you don't register for a limited number of PDFs per hour, it's not suitable for us who have a large number of PDFs to compress, so we bought a professional version. The online version provides batch compression, which requires a batch upload waiting for compression before downloading (there are batch uploads, browsers are stuck or no browsers). The method compression has been waiting, and the compression can not be downloaded after success, the speed is only a few dozen K), and the client version of the program does not have the function of mass compression, can only open and compress one article at a time.
    In order to understand the above problems, after consideration, ready to use its client compression function for batch compression, although it takes a long time, but do not consider the local network factors, at least very controllable, but it is impossible to manually press each article, so this is the origin of this article.


    二、先看实现后的效果(录了gif图,居然显示不了):


    三、实现原理

      主要的原理就是调用WIN API模拟点击,辅助其它的操作完成整个功能,主要的实现就贴主要的代码了,看注释。

           需要的API

          

            [DllImport("User32.dll", EntryPoint = "FindWindow")]
            public extern static IntPtr FindWindow(string lpClassName, string lpWindowName);
    
            [DllImport("User32.dll", EntryPoint = "FindWindowEx")]
            public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpClassName, string lpWindowName);
    
    
            [DllImport("User32.dll", EntryPoint = "SendMessage")]
            public static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, string lParam);
    
            [DllImport("user32.dll")]
            public static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);
    
            [DllImport("user32.dll")]
            [return: MarshalAs(UnmanagedType.Bool)]
            static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);
    
            [StructLayout(LayoutKind.Sequential)]
            public struct RECT
            {
                public int Left;
                public int Top;
                public int Right;
                public int Bottom;
            }
            const int WM_CLOSE = 0x0010;
            const int WM_CLICK = 0x00F5;
    
              enum MouseEventFlag : uint
            {
                Move = 0x0001,
                LeftDown = 0x0002,
                LeftUp = 0x0004,
                RightDown = 0x0008,
                RightUp = 0x0010,
                MiddleDown = 0x0020,
                MiddleUp = 0x0040,
                XDown = 0x0080,
                XUp = 0x0100,
                Wheel = 0x0800,
                VirtualDesk = 0x4000,
                Absolute = 0x8000
            }
    
            [DllImport("user32.dll")]
            static extern void mouse_event(MouseEventFlag flags, int dx, int dy, uint data, UIntPtr extraInfo);
    
            [DllImport("user32.dll")]
            public static extern int SetCursorPos(int x, int y);
    
            public static void MouseLefClickEvent(int dx, int dy, uint data)
            {
                SetCursorPos(dx, dy);
                mouse_event(MouseEventFlag.LeftDown, dx, dy, data, UIntPtr.Zero);
                mouse_event(MouseEventFlag.LeftUp, dx, dy, data, UIntPtr.Zero);
            }

             核心实现:

               var pdfFile = PdfFiles[Index];
                var pdfName = Path.GetFileName(pdfFile);
    
                //用smallpdf打开指定PDF
                System.Diagnostics.Process.Start(SMALLPDFEXE, $""{pdfFile}"");
    
                while (true)
                {
                    //加入等待时间,打开PDF需要一定时间
                    Thread.Sleep(5000);
    
                    //smallpdf窗体句柄
                    IntPtr parentWnd = new IntPtr(0);
                    parentWnd = FindWindow(null, pdfName);
    
                    if (!parentWnd.Equals(IntPtr.Zero))
                    {
                        //保存窗口句柄
                        IntPtr saveWnd = new IntPtr(0);
                        //保存按钮句柄
                        IntPtr btnSave = new IntPtr(0);
    
                        while (true)
                        {
                            //将指定的pdf居最上面显示
                            SwitchToThisWindow(parentWnd, true);
    
                            //获取窗口位置信息,用于计算压缩按钮所在位置
                            RECT rc = new RECT();
                            GetWindowRect(parentWnd, ref rc);
    
                            //点击压缩按钮
                            MouseFlag.MouseLefClickEvent(rc.Right - 50, rc.Top + 100, 0);
    
                            Thread.Sleep(2000);
    
                            saveWnd = FindWindow(null, "Save Document");
                            //当找到保存窗口时点击保存按钮,否则一直循环等待
                            if (!saveWnd.Equals(IntPtr.Zero))
                            {
                                btnSave = FindWindowEx(saveWnd, IntPtr.Zero, "Button", "保存(&S)");
                                if (!btnSave.Equals(IntPtr.Zero))
                                {
                                    break;
                                }
                            }
                        }
                        //点击保存按钮
                        SendMessage(btnSave, WM_CLICK, IntPtr.Zero, "0");
    
                        //保存过程等待
                        bool isCompressed = false;
                        int j = 0, checkCount = 60;
                        while (j < checkCount)
                        {
                            //0001-compressed.pdf
                            string compressPdfName = $"{ Path.GetFileNameWithoutExtension(pdfName)}{COMPRESSED}{Path.GetExtension(pdfFile)}";
                            string compressPdfPath = Path.Combine(PDFDIR, compressPdfName);
                            if (File.Exists(compressPdfPath))
                            {
                                isCompressed = true;
                                break;
                            }
                            Thread.Sleep(1000);
                            j++;
                        }
    
                        //关闭窗体
                        SendMessage(parentWnd, WM_CLOSE, IntPtr.Zero, "0");
    
                        //如果超时都还没有压缩文件生成,认为压缩不成功,记录。
                        if (!isCompressed)
                        {
                           ///记录
                        }
                        break;
                    }
                }
            }
    

            

  • 相关阅读:
    Linux常用命令,touch命令,vi和vim命令,文件查看命令,文本处理命令,备份压缩命令,网络与磁盘命令,软件安装命令
    Linux命令整理,用户管理命令,用户组管理命令,系统管理命令,目录管理常用命令
    单元测试基本步骤?单元测试三个常用注解?日志体系结构和log4j,Log4j三个核心?
    cookies,sessionStorage 和 localStorage 之间有什么区别?
    filter() 、find()、findIndex()
    设置多行文本隐藏显示省略号时样式丢失了
    react 中封装一个简单的滚动条组件
    react-router-cache-router
    浅谈React 中 Component与PureComponent如何使用
    React.Fragment
  • 原文地址:https://www.cnblogs.com/dengxi/p/9564227.html
Copyright © 2011-2022 走看看