2

我正在尝试使用 C# 运行本地进程来调用 Powerpoint 并将 .pdf 转换为 .ppt。

我制作了一个独立的控制台应用程序,希望能够重现和隔离问题。不幸的是,它适用于独立版本,但不适用于集成版本。

当它不起作用时,它不会抛出异常。它只是默默地无法创建 .pdf 文件。

新的:

我在事件日志中收到错误:

Microsoft PowerPoint
PowerPoint can't do this because a dialog box is open. Please close the dialog box to continue.
P1: 400205
P2: 15.0.4420.1017

在我的本地计算机上运行控制台命令、独立控制台应用程序或运行集成 Web 项目时,我看不到任何类型的对话框。

根据官方文档,/pt 命令应该是静默的。

我可以将运行项目的用户设置IdentityApplicationPool我登录的用户,并且在事件日志中不再出现上述错误。但是,我没有从事件日志中得到其他错误(我可以说是相关的)。

但是,它仍然不起作用。Powerpoint 或 PDFCreator 仍然崩溃,并且不创建 .pdf。

我还尝试通过Process从我的集成问题中调用它来运行我的工作控制台应用程序,但这也不起作用。

工作控制台应用程序:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System;
using System.Diagnostics;
using System.Text;

namespace ConsoleApplication3
{
    class Program
    {
        static void Main(string[] args)
        {

        var psi = new ProcessStartInfo();
        psi.FileName = "\"C:\\Program Files\\Microsoft Office\\Office15\\POWERPNT.exe\"";
        psi.Arguments = "/pt \"PDFCreator\" \"\" \"\" dd0e03ff-f386-4e65-b89d-72c7f1ee502d.pptx";
        psi.WorkingDirectory = "C:\\Temp";
        psi.CreateNoWindow = true;
        psi.ErrorDialog = true;
        psi.UseShellExecute = false;
        psi.WindowStyle = ProcessWindowStyle.Hidden;
        psi.RedirectStandardOutput = true;
        psi.RedirectStandardInput = false;
        psi.RedirectStandardError = true;
        try
        {
            using (Process exeProcess = Process.Start(psi))
            {
                exeProcess.PriorityClass = ProcessPriorityClass.High;
                var outString = new StringBuilder(100);
                exeProcess.OutputDataReceived += (s, e) => outString.AppendLine(e.Data);
                exeProcess.BeginOutputReadLine();
                var errString = exeProcess.StandardError.ReadToEnd();

                if (!string.IsNullOrEmpty(errString))
                {
                    Console.WriteLine("errors reported 1");
                }
            }
        }
        catch (Exception ex)
        {
          ex.ToString();
          Console.WriteLine("Errors reported 2 ");
          Console.WriteLine(ex.ToString());
        }

        Console.WriteLine(psi.FileName);
        Console.WriteLine(psi.Arguments);
        Console.WriteLine(psi.WorkingDirectory);
    }
}
}

它打印

"C:\Program Files\Microsoft Office\Office15\POWERPNT.exe"
/pt "PDFCreator" "" "" dd0e03ff-f386-4e65-b89d-72c7f1ee502d.pptx
C:\Temp

不工作的集成应用程序:

using System;
using System.Diagnostics;
using System.Text;

namespace CT.Services.Helper
{
    public static class ExecutableRunner
    {
        public static ExecutableResult RunExeNamed(string exeFilename, string commandLineArgs)
    {
        return RunExeNamed(exeFilename, commandLineArgs, null);
    }

    public static ExecutableResult RunExeNamed(string exeFilename, string commandLineArgs, string workingDirectory)
    {
        var result = new ExecutableResult { WasSuccessful = true };

        var psi = new ProcessStartInfo();
        psi.FileName =  "\""+exeFilename+"\"";
        psi.Arguments = commandLineArgs;
        if(!string.IsNullOrEmpty(workingDirectory))
        {
            psi.WorkingDirectory = workingDirectory;
        }
        psi.CreateNoWindow = false;
        psi.ErrorDialog = true;
        psi.UseShellExecute = false;
        psi.WindowStyle = ProcessWindowStyle.Hidden;
        psi.RedirectStandardOutput = true;
        psi.RedirectStandardInput = false;
        psi.RedirectStandardError = true;
        try
        {
            // Start the process with the info we specified.
            // Call WaitForExit and then the using statement will close.
            using (Process exeProcess = Process.Start(psi))
            {
                exeProcess.PriorityClass = ProcessPriorityClass.High;
                var outString = new StringBuilder(100);
                // use ansynchronous reading for at least one of the streams
                // to avoid deadlock
                exeProcess.OutputDataReceived += (s, e) => outString.AppendLine(e.Data);
                exeProcess.BeginOutputReadLine();
                // now read the StandardError stream to the end
                // this will cause our main thread to wait for the
                // stream to close (which is when ffmpeg quits)
                var errString = exeProcess.StandardError.ReadToEnd();

                if (!string.IsNullOrEmpty(errString))
                {
                    result.WasSuccessful = false;
                    result.ErrorMessage = errString;
                }
            }
        }
        catch (Exception ex)
        {
            result.WasSuccessful = false;
            result.ErrorMessage = ex.ToString();
        }
        Debug.WriteLine(psi.FileName);
        Debug.WriteLine(psi.Arguments);
        Debug.WriteLine(psi.WorkingDirectory);
        return result;
    }
}

public class ExecutableResult
{
    public bool WasSuccessful { get; set; }

    public string ErrorMessage { get; set; }
}

}

它打印

"C:\Program Files\Microsoft Office\Office15\POWERPNT.exe"
/pt "PDFCreator" "" "" dd0e03ff-f386-4e65-b89d-72c7f1ee502d.pptx
C:\Temp

我认为我用作文件路径或控制台命令的字符串之一是错误的,所以我将它们打印到控制台,但您可以看到这些不是问题。

4

5 回答 5

1

最后一次尝试 ;-) 您可以使用 Interop,打开文件,然后将其另存为 pdf。

要使这个小示例正常工作,您需要引用 Microsoft.Office.Interop.PowerPoint 程序集和 Microsoft.Office.Core 命名空间(位于 COM 程序集下的“Microsoft Office 14.0 对象库”程序集中)。

小例子:

/// <summary>
/// Converts the specified source file and saves it as pdf with the
/// specified destination filename.
/// </summary>
/// <param name="sourceFilename">The filename of the file to be converted into a pdf.</param>
/// <param name="destinationFilename">The filename of the pdf.</param>
/// <exception cref="System.IO.FileNotFoundException">Is thrown if the specified source file does not exist.</exception>
/// <exception cref="System.Exception">Is thrown if something went wrong during the convertation process.</exception>
public static void SaveAsPDF(string sourceFilename, string destinationFilename)
{
    if (!File.Exists(sourceFilename))
    {
        throw new FileNotFoundException(string.Format("The specified file {0} does not exist.", sourceFilename), sourceFilename);
    }

    try
    {
        Microsoft.Office.Interop.PowerPoint.Application app = new Microsoft.Office.Interop.PowerPoint.Application();

        app.Presentations.Open(sourceFilename).SaveAs(destinationFilename, Microsoft.Office.Interop.PowerPoint.PpSaveAsFileType.ppSaveAsPDF);
        app.Quit();
    }
    catch (Exception e)
    {
        throw new Exception(string.Format("Unable to convert {0} to {1}", sourceFilename, destinationFilename), e);
    }
}
于 2013-10-28T22:18:33.327 回答
1

会不会是应用池的权限有问题?也许它没有执行您想要执行的所有操作的权限 - 您可以通过在与应用程序池正在运行的相同上下文下执行控制台应用程序来检查这一点。

于 2013-10-25T23:46:50.527 回答
1

只是另一个想法(不确定它是否愚蠢)。据我所知,powerpoint(至少从 2010 年开始)能够直接保存为 pdf。对于 2007,您可以使用名为“另存为 PDF”的 microsoft 插件,该插件可在此处找到2007 Microsoft Office 插件:Microsoft Save as PDF or XPS

使用Todd Main 提供的解决方案,您可以(理论上)在启动时执行一个宏,该宏可以将文件直接存储为 PDF(无需打印,希望没有对话框)。

更新:

我现在已经尝试过了 - 问题是你必须将宏存储在演示文稿中,然后你必须使用 pptm 文件格式。接下来,您必须打开文件一次并激活宏执行(显示在编辑屏幕的顶部)。之后,您可以简单地从命令行执行它,例如

POWERPNT.EXE /M Filename.pptm SaveAsPDF

宏如下所示:

Sub SaveAsPDF()
    Dim ap As Presentation: Set ap = ActivePresentation
    ap.SaveAs ap.Path & "\" & ap.Name, ppSaveAsPDF
    PowerPoint.Application.Quit
End Sub
于 2013-10-28T21:25:25.503 回答
0

代码的集成版本是 Web 应用程序的一部分

  1. 提供对正在为应用程序池用户创建此文件的当前工作目录的访问权限,并验证它是否具有读/写功能。
  2. 检查服务器上的 Temp 目录中的 app-pool 进程用户,并验证该进程是否具有对 temp 目录的读/写访问权限。

编辑看到事件日志。

Asp.net 不应使用任何属于用户交互过程的应用程序。您需要找到一个不同的应用程序来创建这些对 asp.net 友好的 powerpoint 幻灯片,或者确定 Powerpoint 在打开对话框时尝试执行的操作。

于 2013-10-28T15:46:32.123 回答
0

很可能您会看到此问题,因为您实际上从未在失败的环境中运行应用程序的用户下打开 Powerpoint。
这将是运行应用程序池的用户,正如我看到您向 OmegaMan 提到的那样,该用户是 LocalSystem。

当 LocalSystem 尝试打开 Powerpoint 时,Powerpoint 将执行所有 Office 应用程序在新用户第一次运行它们时完成安装时所做的事情。
您在控制台应用程序或本地系统中看不到此安装框,因为您是在自己的帐户下运行这些安装框,并且您之前打开过 PowerPoint。

正如 OmegaMan 所说的那样,Powerpoint 是一个交互式过程,因此即使您非常非常小心,它也可能会造成麻烦。您最终会看到 Powerpoint 的实例在它们本应关闭后保持打开状态,并且在

也就是说,如果你真的想让它运行,那么你要么需要以交互方式打开 Powerpoint 的用户身份运行应用程序池,要么更改代码以在需要运行 Powerpoint 然后模拟以交互方式使用它来完成您需要的操作的用户。

于 2013-10-28T17:02:07.393 回答