1. 程式人生 > >c# 呼叫Microsoft XPS Document Writer印表機,將Pdf檔案轉換成Xps檔案

c# 呼叫Microsoft XPS Document Writer印表機,將Pdf檔案轉換成Xps檔案

最近碰到個專案,其中有個需要將pdf檔案轉換成xps檔案的功能,xps檔案還算是新東西,所以基本沒啥瞭解,通過一段時間的調查,

本人算是找到了2個方法:

  1)通過PDFNet第三發開發元件即可很容易的完成轉換功能,並且還有其他針對pdf檔案操作的功能,還是很強大的。當然啦,這個東

      西是要買的,可以先下一個試用版先體驗體驗。

  2)通過“Microsoft XPS Document Writer”印表機,將pdf列印成本地的xps檔案,以此來完成轉換功能。

      這個印表機的驅動在WIN7的系統上裝Office2007的時候會自動裝上,如果是XP系統的話,可能沒有,可以去微軟官網下載個

     “SaveAsPDFandXPS.exe”,裝上後,就會有這個印表機。

    印表機也有了,那麼接下來的問題就是怎麼呼叫這個印表機了,淡然了,可以通過一系列的API的配合去呼叫這個印表機,但我覺得

      Windows的印表機呼叫起來實在是太麻煩了,通過一番調查,可以直接使用Adobe acro Reader或Foxit Reader這兩個軟體的打

    印功能,將檔案打出,下面的列出了程式碼供參考。

   開發環境:VS2010,.Net FrameWork4.0,C#,WPF

窗體程式碼:

<Window x:Class="TestPdfToXps1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Button Click="Button_Click">PDF TO XPS</Button>
    </Grid>
</Window>
窗體的後臺關鍵程式碼:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using System.ComponentModel;
using System.Runtime.InteropServices;

namespace TestPdfToXps1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        //Win32 Api定義
         [DllImport("user32.dll")]
        static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        [DllImport("user32.dll")]
        static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfeter, string lpszClass, string lpszWindow);

        [DllImport("user32.dll")]
        static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, String lParam);

        [DllImport("user32.dll")]
        static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);


        //Win32訊息定義
         const uint WM_SETTEXT = 0x000c;
        const uint WM_IME_KEYDOWN = 0x0290;
        const uint WM_LBUTTONDOWN = 0x0201;
        const uint WM_LBUTTONUP = 0x0202;


        public MainWindow()
        {
            InitializeComponent();
        }


        private void Button_Click(object sender, RoutedEventArgs e)
        {
            PrintWithFoxitReader();
        }

        void PrintWithFoxitReader()
        {
           string pdf_filepath = @"d:\原檔案.pdf"; // 需要轉換的PDF檔案
             string xps_filepath = @"d:\目標檔案.xps"; // 目標XPS檔案

           /***** 呼叫Foxit Reader.exe的列印功能,並且制定印表機為Microsoft XPS Document Writer *****/
           System.Diagnostics.ProcessStartInfo psInfo = new System.Diagnostics.ProcessStartInfo();
           psInfo.FileName = @"D:\Tools\Reader\Foxit Reader\Foxit Reader.exe"; //Foxit Reader.exe的全路徑
           psInfo.Arguments = String.Format(@" -t {0} ""Microsoft XPS Document Writer""", pdf_filepath);
           psInfo.CreateNoWindow = true; 
           psInfo.UseShellExecute = false; 
           System.Diagnostics.Process ps = new System.Diagnostics.Process();
           ps.StartInfo = psInfo;
           ps.Start();


           // 等待
            System.Threading.Thread.Sleep(5 * 1000);


           /***** 啟動Foxit Reader後,會彈出檔案另存為對話方塊********************************/
           /***** 因此使用Win32Api找到檔案另存為對話方塊中的檔名輸入框,並且通過給輸入******/
           /***** 框發訊息在輸入框中自動填入目標xps檔名,最後通過給儲存按鈕發訊息來*******/
           /***** 最後通過給儲存按鈕發訊息來按下對話方塊中的儲存按鈕**************************/
           // 找到檔案另存為對話方塊的視窗控制代碼
            IntPtr hWnd = FindWindow("#32770", "檔案另存為");    
          IntPtr hChild;
          // 由於輸入框被多個控制元件巢狀,因此需要一級一級的往控制元件內找到輸入框
            hChild = FindWindowEx(hWnd, IntPtr.Zero, "DUIViewWndClassName", String.Empty);
          hChild = FindWindowEx(hChild, IntPtr.Zero, "DirectUIHWND", String.Empty);
          hChild = FindWindowEx(hChild, IntPtr.Zero, "FloatNotifySink", String.Empty);
          hChild = FindWindowEx(hChild, IntPtr.Zero, "ComboBox", String.Empty);
          hChild = FindWindowEx(hChild, IntPtr.Zero, "Edit", String.Empty); // File name edit control
          // 向輸入框傳送訊息,填充目標xps檔名
            SendMessage(hChild, WM_SETTEXT, IntPtr.Zero, xps_filepath);
          // 等待1秒鐘
            System.Threading.Thread.Sleep(1000);
          // 找到對話方塊內的儲存按鈕
            hChild = IntPtr.Zero;
          hChild = FindWindowEx(hWnd, IntPtr.Zero, "Button", "儲存(&S)");
          // 向儲存按鈕傳送2個訊息,以模擬click訊息,藉此來按下儲存按鈕
            PostMessage(hChild, WM_LBUTTONDOWN, IntPtr.Zero, IntPtr.Zero);
          PostMessage(hChild, WM_LBUTTONUP, IntPtr.Zero, IntPtr.Zero);



          /***** 跟蹤印表機佇列中的檔案列印狀況,知道檔案列印完成為止 *****/
          // 呼叫本地印表機佇列
            System.Printing.LocalPrintServer prtSrv = new System.Printing.LocalPrintServer();
          System.Printing.PrintQueue queue = prtSrv.GetPrintQueue("Microsoft XPS Document Writer");


          //一直監視列印佇列,知道列印佇列中沒有列印任務時結束
            do
          {
              // 等待處理  
                System.Threading.Thread.Sleep(1000);
              // 讀取佇列的最新資訊
                queue.Refresh();
          } while (queue.NumberOfJobs > 0);


          MessageBox.Show("完成");
        }
    }
}
*注:如果是使用Adobe Read進行列印,可以參考下列的部分程式碼

使用Adcro Readr的相關程式碼:

//將前面的兩行程式碼換成一下程式碼
psInfo.FileName = @"C:\Program Files\Adobe\Reader 8.0\Reader\AcroRd32.exe";
psInfo.Arguments = String.Format(@" /s /h /t {0} ""Microsoft XPS Document Writer""", pdf_filepath);