通过PHP启动服务器端打印作业

时间:2009-10-30 07:02:12

标签: c# php windows acrobat

这很可能不是一件容易的事,但情况如下:

我编写了一个C#命令行应用程序:

  • 使用ITextSharp
  • 创建PDF
  • 将其写入磁盘
  • 通过Acrord32.exe使用System.Diagnostics.Process(这是Acrobat Reader)以静默打印生成的PDF

如果我构建我的解决方案并双击pdfGen.exe,它会按预期工作。 PDF已创建并打印。

现在,我的应用程序必须部署在运行IIS 7的Windows Vista的内部服务器上。此服务器运行一些PHP webapp。它将通过PHP使用shell_exec()调用,以便生成的PDF将打印在连接到服务器的打印机上。

所以我的PHP页面看起来基本上是这样的:

shell_exec('/path/to/pdfGen.exe');

但这里出了问题。根据任务经理等情况会发生什么:

  • pdfGen.exe开始
  • 创建PDF
  • Acrord32.exe开始
  • pdfGen.exe永远挂起(PHP脚本也是如此)并且没有打印任何内容

我很确定这是与权限相关的问题。我已经IIS_IUSRS访问了默认打印机,并且访问了Acrord32.exe所在的目录。但是,仍然没有打印。但是,如果我手动启动我的pdfGen.exe它可以工作。

知道我错过了什么吗?

编辑:

我不一定要使用Acrobat Reader来打印PDF。如果还有另一种方式静默打印创建的PDF服务器端,我根本不介意。

5 个答案:

答案 0 :(得分:1)

为了检查发生了什么,请尝试运行 process monitor from Sysinternals并将事件过滤到adobe acrobat流程。您将看到acrobat的系统调用,它将让您了解更多或更少的错误。

答案 1 :(得分:1)

我知道您的解决方案有一点改进:SumatraPDF有一个很好的命令行界面,可用于在打印后自动关闭Sumatra。

我使用PHP“system”或“exec”函数执行批处理文件以打开SumatraPDF:

sumatrapdf.exe -print-to-default -exit-on-print <path_to_PDF_file>

(您也可以指定要打印的打印机名称)

答案 2 :(得分:0)

这是一个有趣的节目。

IIS_IUSRS  似乎没有打印权限,请尝试将IIS_IUSRS添加到Print Operators Group /授予用户打印权限。

答案 3 :(得分:0)

Shell_exec()几乎用于shell命令(ls / dir,cp等) 您是否尝试使用exec()而不是shell_exec()?

答案 4 :(得分:0)

感谢大家的评论。不幸的是,这个“php start printjob”的东西是今天取消的一个更大的项目的一部分,因为,好吧......我不知道......政治原因。猜猜这个项目已经死了。

无论如何,我在最后几天尝试了几次,但是无法让它与IIS一起工作。我已经实现并测试过的解决方案:删除IIS,安装带有本地apache的XAMPP或WAMPP包以及使用 admin访问权限运行的PHP。

这就是诀窍。我在PHP中使用了pclose(popen('...command...', 'r'));来启动.exe,因此PHP不会等到PDF完成。一切都很好。

这是我的C#代码,它使用Acrobat Reader

启动打印作业
public void Print(string pathname, string acrobatDirectory)
{
    var proc = new Process
    {
        StartInfo =
        {
            Arguments               = String.Format("/t \"{0}\"", pathname),
            FileName                = acrobatDirectory,
            UseShellExecute         = false,
            CreateNoWindow          = true,
            RedirectStandardOutput  = false,
            RedirectStandardError   = false,
        }
    };

    proc.Start();  
}  

第一个参数是应该打印的PDF的路径,第二个参数是AcroRd32.exe的绝对路径。

唯一的问题是AcroRd32.exe已启动,打印并且再也没有关闭过。所以每个printjob都启动了AcroRd32.exe的新实例(我使用的是Acrobat Reader 9.0)。因此,如果您打印10次,则会创建10个acrobat reader实例。

我所做的是启动打印作业,然后等待X秒,希望打印机完成然后杀死所有AcroRd32.exe个实例:

public void Print(string pathname, string acrobatDirectory)
{
    Debug.WriteLine("Printing...");

    Printer.Print(pathname, acrobatDirectory);

    Thread.Sleep(30000);

    try
    {
        Debug.WriteLine("Trying to kill runnung AcroRd32.exe's ");

        FindAndKillProcess("AcroRd32");
    }
    catch (Exception)
    {
        Debug.WriteLine("AcroRd32.exe could not be killed...");
    }
}

private bool FindAndKillProcess(string name)
{
    foreach (Process clsProcess in Process.GetProcesses())
    {
        if (clsProcess.ProcessName.StartsWith(name))
        {
            clsProcess.Kill();
            return true;
        }
    }

    return false;
}

这很好。


请注意,上述(杀死所有AcroRd32.exe并使用管理员权限运行PHP)仅可行,因为:整个事情一次仅由一个用户使用,并且使用范围非常有限

它应该用于部署在客户端POS的触摸屏应用程序。销售人员将使用PHP应用程序来配置产品,然后PHP将调用我的.exe,它将在后台创建和打印PDF。然后将打印的文件交给客户。 在这种情况下,安全等并不是真正的问题。


如果有人有解决方案以便在IIS中使用它,我仍然愿意接受它作为答案。