C#的Process类调用第三方插件实现PDF文件转SWF文件

 更新时间:2020年6月25日 11:22  点击:2093

在项目开发过程中,有时会需要用到调用第三方程序实现本系统的某一些功能,例如本文中需要使用到的swftools插件,那么如何在程序中使用这个插件,并且该插件是如何将PDF文件转化为SWF文件的呢?接下来就会做一个简单的介绍。

在.NET平台中,对C#提供了一个操作对本地和远程的访问进程,使能够启动和停止系统进程。这个类就是System.Diagnostics.Process,我们首先来了解一下该类。

一.解析System.Diagnostics.Process类

在C#中使用Process类可以提供对本地和远程的访问进程,使能够启动和停止系统进程,并且该类可以对系统进程进行管理。该类中的一些常用方法:Start() ,Kill(),WaitForExit()等方法;StartInfo,FileName,CreateNoWindow等属性。

1.Start()方法:启动(或重用)此 Process 组件的 StartInfo 属性指定的进程资源,并将其与该组件关联。如果启动了进程资源,则为 true;如果没有启动新的进程资源(例如,如果重用了现有进程),则为 false。
具体介绍一下该方法的实现代码:

 /// <devdoc>
    ///  <para> 
    ///  <see cref='System.Diagnostics.Process'/>如果过程资源被重用而不是启动,重用的进程与此相关联<see cref ='System.Diagnostics.Process'/>零件。
    ///  </para>    
    /// </devdoc>
    [ResourceExposure(ResourceScope.None)]
    [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] 
    public bool Start() {
      Close(); 
      ProcessStartInfo startInfo = StartInfo; 
      if (startInfo.FileName.Length == 0)
        throw new InvalidOperationException(SR.GetString(SR.FileNameMissing)); 

      if (startInfo.UseShellExecute) {
#if !FEATURE_PAL
        return StartWithShellExecuteEx(startInfo); 
#else
        throw new InvalidOperationException(SR.GetString(SR.net_perm_invalid_val, "StartInfo.UseShellExecute", true)); 
#endif // !FEATURE_PAL 
      } else {
        return StartWithCreateProcess(startInfo); 
      }
    }

2.Kill()方法:立即停止关联的进程。Kill 强制终止进程,Kill 方法将异步执行。 在调用 Kill 方法后,请调用 WaitForExit 方法等待进程退出,或者检查 HasExited 属性以确定进程是否已经退出。
具体介绍一下该方法的实现代码:

[ResourceExposure(ResourceScope.Machine)] 
    [ResourceConsumption(ResourceScope.Machine)]
    public void Kill() { 
      SafeProcessHandle handle = null;
      try {
        handle = GetProcessHandle(NativeMethods.PROCESS_TERMINATE);
        if (!NativeMethods.TerminateProcess(handle, -1)) 
          throw new Win32Exception();
      } 
      finally { 
        ReleaseProcessHandle(handle);
      } 
    }

SafeProcessHandle GetProcessHandle(int access) {
      return GetProcessHandle(access, true); 
    }

    /// <devdoc>
    /// 获取进程的短期句柄,具有给定的访问权限。
     ///如果句柄存储在当前进程对象中,则使用它。
     ///注意,我们存储在当前进程对象中的句柄将具有我们需要的所有访问权限。
    /// </devdoc> 
    /// <internalonly/> 
    [ResourceExposure(ResourceScope.None)]
    [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] 
    SafeProcessHandle GetProcessHandle(int access, bool throwIfExited) {
      Debug.WriteLineIf(processTracing.TraceVerbose, "GetProcessHandle(access = 0x" + access.ToString("X8", CultureInfo.InvariantCulture) + ", throwIfExited = " + throwIfExited + ")");
#if DEBUG
      if (processTracing.TraceVerbose) { 
        StackFrame calledFrom = new StackTrace(true).GetFrame(0);
        Debug.WriteLine("  called from " + calledFrom.GetFileName() + ", line " + calledFrom.GetFileLineNumber()); 
      } 
#endif
      if (haveProcessHandle) { 
        if (throwIfExited) {
          //因为hasProcessHandle是true,我们知道我们有进程句柄
           //打开时至少要有SYNCHRONIZE访问,所以我们可以等待它
           // zero timeout以查看进程是否已退出。
          ProcessWaitHandle waitHandle = null;
          try { 
            waitHandle = new ProcessWaitHandle(m_processHandle); 
            if (waitHandle.WaitOne(0, false)) {
              if (haveProcessId) 
                throw new InvalidOperationException(SR.GetString(SR.ProcessHasExited, processId.ToString(CultureInfo.CurrentCulture)));
              else
                throw new InvalidOperationException(SR.GetString(SR.ProcessHasExitedNoId));
            } 
          }
          finally { 
            if( waitHandle != null) { 
              waitHandle.Close();
            } 
          }
        }
        return m_processHandle;
      } 
      else {
        EnsureState(State.HaveId | State.IsLocal); 
        SafeProcessHandle handle = SafeProcessHandle.InvalidHandle; 
#if !FEATURE_PAL
        handle = ProcessManager.OpenProcess(processId, access, throwIfExited); 
#else
        IntPtr pseudohandle = NativeMethods.GetCurrentProcess();
        // Get a real handle
        if (!NativeMethods.DuplicateHandle (new HandleRef(this, pseudohandle), 
                          new HandleRef(this, pseudohandle),
                          new HandleRef(this, pseudohandle), 
                          out handle, 
                          0,
                          false, 
                          NativeMethods.DUPLICATE_SAME_ACCESS |
                          NativeMethods.DUPLICATE_CLOSE_SOURCE)) {
          throw new Win32Exception();
        } 
#endif // !FEATURE_PAL
        if (throwIfExited && (access & NativeMethods.PROCESS_QUERY_INFORMATION) != 0) { 
          if (NativeMethods.GetExitCodeProcess(handle, out exitCode) && exitCode != NativeMethods.STILL_ACTIVE) { 
            throw new InvalidOperationException(SR.GetString(SR.ProcessHasExited, processId.ToString(CultureInfo.CurrentCulture)));
          } 
        }
        return handle;
      }
 
    }

3.WaitForExit()方法:指示<see cref ='System.Diagnostics.Process'/>组件等待指定的毫秒数,以使相关联的进程退出。

具体介绍一下该方法的实现代码:

public bool WaitForExit(int milliseconds) { 
      SafeProcessHandle handle = null; 
     bool exited;
      ProcessWaitHandle processWaitHandle = null; 
      try {
        handle = GetProcessHandle(NativeMethods.SYNCHRONIZE, false);
        if (handle.IsInvalid) {
          exited = true; 
        }
        else { 
          processWaitHandle = new ProcessWaitHandle(handle); 
          if( processWaitHandle.WaitOne(milliseconds, false)) {
            exited = true; 
            signaled = true;
          }
          else {
            exited = false; 
            signaled = false;
          } 
        } 
      }
      finally { 
        if( processWaitHandle != null) {
          processWaitHandle.Close();
        }
 
        // If we have a hard timeout, we cannot wait for the streams
        if( output != null && milliseconds == -1) { 
          output.WaitUtilEOF(); 
        }
 
        if( error != null && milliseconds == -1) {
          error.WaitUtilEOF();
        }
 
        ReleaseProcessHandle(handle);
 
      } 

      if (exited && watchForExit) { 
        RaiseOnExited();
      }
      
      return exited; 
    }

internal ProcessWaitHandle( SafeProcessHandle processHandle): base() {
      SafeWaitHandle waitHandle = null; 
      bool succeeded = NativeMethods.DuplicateHandle(
        new HandleRef(this, NativeMethods.GetCurrentProcess()), 
        processHandle, 
        new HandleRef(this, NativeMethods.GetCurrentProcess()),
        out waitHandle, 
        0,
        false,
        NativeMethods.DUPLICATE_SAME_ACCESS);
 
      if (!succeeded) {
        Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); 
      } 

      this.SafeWaitHandle = waitHandle; 
    }

4.StartInfo属性:获取或设置要传递给 Process 的 Start 方法的属性。StartInfo 表示用于启动进程的一组参数。 调用 Start 时,StartInfo 用于指定要启动的进程。 唯一必须设置的 StartInfo 成员是 FileName 属性。

具体介绍一下该方法的实现代码:
 

 [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), MonitoringDescription(SR.ProcessStartInfo)] 
    public ProcessStartInfo StartInfo {
      get { 
        if (startInfo == null) { 
          startInfo = new ProcessStartInfo(this);
        } 
        return startInfo;
      }
      [ResourceExposure(ResourceScope.Machine)]
      set { 
        if (value == null) {
          throw new ArgumentNullException("value"); 
        } 
        startInfo = value;
      } 
    }

5.CreateNoWindow属性:获取或设置指示是否在新窗口中启动该进程的值。

具体介绍一下该方法的实现代码:

[
    DefaultValue(false),
    MonitoringDescription(SR.ProcessCreateNoWindow),
    NotifyParentProperty(true) 
    ]
    public bool CreateNoWindow { 
      get { return createNoWindow; } 
      set { createNoWindow = value; }
    }

 以上简单介绍了该类的三种常用方法和两种常用属性,在实际的开发项目中无须对每个属性方法和属性的底层实现做全面的了解,但建议在学习该类的时候,适当的了解一下某一些类的方法实现,有助于我们很好的掌握该类。

二.如何实现PDF文件转化为SWF文件

在项目如果需要将PDF文件转换为SWF文件,可以在项目中引入Swftools插件,该插件的主要功能:PDF到SWF转换器。 每页生成一帧。 使您能够在Flash Movie中拥有完全格式化的文本,包括表格,公式,图形等。 它基于Derek B. Noonburg的xpdf PDF解析器。

简单介绍一下该插件的常用参数:

-h , –help                      Print short help message and exit              打印帮助信息   

-V , –version                Print version info and exit                        打印版本号

-o , –output file.swf         Direct output to file.swf. If file.swf contains ‘13568621′ (file13568630.swf), then each page指定输出的swf文件名

-P , –password password       Use password for deciphering the pdf.指定打开pdf的密码

-z , –zlib                    Use Flash 6 (MX) zlib compression.使用Flash 6的zlib压缩机制

-i , –ignore                  Allows pdf2swf to change the draw order of the pdf. This may make the generated允许程序修改pdf的绘制顺序,可能会导致结果与原来有差异

以上是几种常用的参数,具体擦参数列表详见:http://www.swftools.org/。

对实现本次操作的类和插件做了一个简单的介绍,接下来提供一个具体实现该功能的操作方法:
 

 /// <summary>
    /// PDF格式转为SWF
    /// </summary>
    /// <param name="pdfPathParameter">原视频文件地址,如/a/b/c.pdf</param>
    /// <param name="swfPathParameter">生成后的FLV文件地址,如/a/b/c.swf</param>
    /// <param name="beginpage">转换开始页</param>
    /// <param name="endpage">转换结束页</param>
    /// <param name="photoQuality">照片质量</param>
    /// <returns></returns>
    public static bool PdfConversionSwf(string pdfPathParameter, string swfPathParameter, int beginpage, int endpage, int photoQuality)
    {
      if (string.IsNullOrEmpty(pdfPathParameter))
      {
        throw new ArgumentNullException(pdfPathParameter);
      }
      if (string.IsNullOrEmpty(swfPathParameter))
      {
        throw new ArgumentNullException(swfPathParameter);
      }
      if (endpage < beginpage)
      {
        throw new ArgumentException("起始页数大于结束页数");
      }
      if (photoQuality <= 0)
      {
        throw new ArgumentException("照片质量错误");
      }
      var exe = HttpContext.Current.Server.MapPath("~/tools/swftools-2013-04-09-1007.exe");
      var pdfPath = HttpContext.Current.Server.MapPath(pdfPathParameter);
      var swfPath = HttpContext.Current.Server.MapPath(swfPathParameter);
      Process p = null;
      try
      {
        if (!File.Exists(exe) || !File.Exists(pdfPath))
        {
          return false;
        }
        if (File.Exists(swfPath))
        {
          File.Delete(swfPath);
        }
        var sb = new StringBuilder();
        sb.Append(" \"" + pdfPath + "\"");
        sb.Append(" -o \"" + swfPath + "\"");
        sb.Append(" -s flashversion=9");
        sb.Append(" -s disablelinks");
        if (endpage > GetPageCount(pdfPath))
        {
          endpage = GetPageCount(pdfPath);
        }
        sb.Append(" -p " + "\"" + beginpage + "" + "-" + endpage + "\"");
        //SWF中的图片质量
        sb.Append(" -j " + photoQuality);
        var command = sb.ToString();
        //Process提供对本地和远程的访问进程,使能够启动和停止系统进程。
        p = new Process
        {
          StartInfo =
          {
            FileName = exe,
            Arguments = command,
            WorkingDirectory = HttpContext.Current.Server.MapPath("~/Bin/"),
            UseShellExecute = false,
            RedirectStandardError = true,
            CreateNoWindow = false
          }
        };
        //启动线程
        p.Start();
        //开始异步读取
        p.BeginErrorReadLine();
        //等待完成
        p.WaitForExit();
        //开始同步读取
        //p.StandardError.ReadToEnd();        
        if (!File.Exists(swfPath))
          return false;
        return true;
      }
      catch (IOException ioex)
      {
        throw new IOException(ioex.Message);
      }
      catch (Exception ex)
      {
        throw new Exception(ex.Message);
      }
      finally
      {
        if (p != null)
        {
          //关闭进程
          p.Close();
          //释放资源
          p.Dispose();
        }
      }

    }

三.小结

在本文中介绍了在C#中如何操作外部程序和线程的类System.Diagnostics.Process,并介绍了该类的一些常用方法的底层实现代码,如果需要对该类进行详细的了解,可以根据MSDN和.NET底层源码的相关注释和文章进行细致的学习。在介绍完实现操作的类的同时,也对Swftools插件做了一个说明,并列举了相关的参数,如果在项目中有较高的要求,可以根据官方提供的API文档进行重构。

在项目开发中,任何一个功能是无法做法完成所有的功能,在编码功能时,只能尽可能的考虑到方法的通用性,在理解了某一个类和某一个插件的基本原理和使用方法后,可以根据对应的API进行添加新功能。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持猪先飞。

[!--infotagslink--]

相关文章

  • C#实现简单的登录界面

    我们在使用C#做项目的时候,基本上都需要制作登录界面,那么今天我们就来一步步看看,如果简单的实现登录界面呢,本文给出2个例子,由简入难,希望大家能够喜欢。...2020-06-25
  • 浅谈C# 字段和属性

    这篇文章主要介绍了C# 字段和属性的的相关资料,文中示例代码非常详细,供大家参考和学习,感兴趣的朋友可以了解下...2020-11-03
  • 解决执行maven命令时提示Process terminated的问题

    这篇文章主要介绍了解决执行maven命令时提示Process terminated的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-09-25
  • C#中截取字符串的的基本方法详解

    这篇文章主要介绍了C#中截取字符串的的基本方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-11-03
  • C#连接SQL数据库和查询数据功能的操作技巧

    本文给大家分享C#连接SQL数据库和查询数据功能的操作技巧,本文通过图文并茂的形式给大家介绍的非常详细,需要的朋友参考下吧...2021-05-17
  • C#实现简单的Http请求实例

    这篇文章主要介绍了C#实现简单的Http请求的方法,以实例形式较为详细的分析了C#实现Http请求的具体方法,需要的朋友可以参考下...2020-06-25
  • C#中new的几种用法详解

    本文主要介绍了C#中new的几种用法,具有很好的参考价值,下面跟着小编一起来看下吧...2020-06-25
  • 使用Visual Studio2019创建C#项目(窗体应用程序、控制台应用程序、Web应用程序)

    这篇文章主要介绍了使用Visual Studio2019创建C#项目(窗体应用程序、控制台应用程序、Web应用程序),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2020-06-25
  • C#开发Windows窗体应用程序的简单操作步骤

    这篇文章主要介绍了C#开发Windows窗体应用程序的简单操作步骤,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-04-12
  • C#从数据库读取图片并保存的两种方法

    这篇文章主要介绍了C#从数据库读取图片并保存的方法,帮助大家更好的理解和使用c#,感兴趣的朋友可以了解下...2021-01-16
  • C#和JavaScript实现交互的方法

    最近做一个小项目不可避免的需要前端脚本与后台进行交互。由于是在asp.net中实现,故问题演化成asp.net中jiavascript与后台c#如何进行交互。...2020-06-25
  • 经典实例讲解C#递归算法

    这篇文章主要用实例讲解C#递归算法的概念以及用法,文中代码非常详细,帮助大家更好的参考和学习,感兴趣的朋友可以了解下...2020-06-25
  • C++调用C#的DLL程序实现方法

    本文通过例子,讲述了C++调用C#的DLL程序的方法,作出了以下总结,下面就让我们一起来学习吧。...2020-06-25
  • 轻松学习C#的基础入门

    轻松学习C#的基础入门,了解C#最基本的知识点,C#是一种简洁的,类型安全的一种完全面向对象的开发语言,是Microsoft专门基于.NET Framework平台开发的而量身定做的高级程序设计语言,需要的朋友可以参考下...2020-06-25
  • C#变量命名规则小结

    本文主要介绍了C#变量命名规则小结,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-09-09
  • c#中(&&,||)与(&,|)的区别详解

    这篇文章主要介绍了c#中(&&,||)与(&,|)的区别详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-06-25
  • C#绘制曲线图的方法

    这篇文章主要介绍了C#绘制曲线图的方法,以完整实例形式较为详细的分析了C#进行曲线绘制的具体步骤与相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下...2020-06-25
  • C# 中如何取绝对值函数

    本文主要介绍了C# 中取绝对值的函数。具有很好的参考价值。下面跟着小编一起来看下吧...2020-06-25
  • c#自带缓存使用方法 c#移除清理缓存

    这篇文章主要介绍了c#自带缓存使用方法,包括获取数据缓存、设置数据缓存、移除指定数据缓存等方法,需要的朋友可以参考下...2020-06-25
  • C#学习笔记- 随机函数Random()的用法详解

    下面小编就为大家带来一篇C#学习笔记- 随机函数Random()的用法详解。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2020-06-25