0

我正在编写一个 Windows 服务来扫描一组目录以查找新的 PDF 文件,并使用 Ghostscript.NET 将它们转换为 TIFF。当我将代码作为普通程序编译并运行时,它运行良好,但是当我将相同的代码用作服务时,输出 TIFF 永远不会出现。我已将目标目录设置为允许为每个人编写,并且原始 PDF 已按预期删除,因此对于“本地系统”用户而言,这不应该是权限问题。审核访问失败和成功的目录仅显示成功列表。

有一个功能可以读取 PDF 的颜色填充,以确定它是彩色文档还是彩色扫描的黑白文档。该部分有效,因此访问和阅读 PDF 没有问题。

我还尝试从 Ghostscript 开关中删除“-q”,但没有报告任何错误,“-dDEBUG”输出了太多垃圾,我不知道它在说什么——但没有任何东西被标记为错误。

public static void ConvertPDF(string file, GSvalues gsVals)
{

    gsProc = new Ghostscript.NET.Processor.GhostscriptProcessor();
    System.Collections.Generic.List<string> switches = new System.Collections.Generic.List<string>();
    switches.Add("-empty"); // GS.NET ignores the first switch
    switches.Add("-r" + gsVals.Resolution); // dpi
    switches.Add("-dDownScaleFactor=" + gsVals.ScaleFactor); // Scale the image back down
    switches.Add("-sCompression=lzw"); // Compression
    switches.Add("-dNumRenderingThreads=" + Environment.ProcessorCount);
    switches.Add("-c \"30000000 setvmthreshold\"");
    switches.Add("-dNOGC");

    string device;
    if (_checkPdf(file, gsVals.InkColorLevels, gsVals))
    {
        gsVals.WriteLog("Color PDF");
        device = "-sDEVICE=tiffscaled24"; // 24bit Color TIFF
    }
    else
    {
        gsVals.WriteLog("Grayscale PDF");
        device = "-sDEVICE=tiffgray"; // grayscale TIFF
    }    
    switches.Add(device);

    // Strip the filename out of the full path to the file
    string filename = System.IO.Path.GetFileNameWithoutExtension(file);
    // Set the output file tag
    string oFileName = _setFileName(oPath + "\\" + filename.Trim(), GSvalues.Extension);
    string oFileTag = "-sOutputFile=" + oFileName;
    switches.Add(oFileTag);
    switches.Add(file);

    // Process the PDF file
    try
    {
        string s = string.Empty;
        foreach (string sw in switches) s += sw + ' ';
            gsVals.DebugLog("Switches:\n\t" + s);

        gsProc.StartProcessing(switches.ToArray(), new GsStdio());
        while (gsProc.IsRunning) System.Threading.Thread.Sleep(1000);
    }
    catch (Exception e)
    {
         gsVals.WriteLog("Exception caught: " + e.Message);
         Console.Read();
    }

    gsVals.DebugLog("Archiving PDF");
    try
    {
        System.IO.File.Move(file, _setFileName(gsVals.ArchiveDir + "\\" + filename, ".pdf"));
    }
    catch (Exception e)
    {
        gsVals.WriteLog("Error moving PDF: " + e.Message);
    }
}


private static string _setFileName(string path, string tifExt)
    {
        if (System.IO.File.Exists(path + tifExt)) return _setFileName(path, 1, tifExt);
        else return path + tifExt;
    }

private static string _setFileName(string path, int ctr, string tifExt)
    {
        // Test the proposed altered filename. It it exists, move to the next iteration
        if(System.IO.File.Exists(path + '(' + ctr.ToString() + ')' + tifExt)) return _setFileName(path, ++ctr, tifExt);
        else return path + '(' + ctr.ToString() + ')' + tifExt;
    }

这是生成的开关的示例输出(从输出日志中提取):

Switches: -empty -r220 -dDownScaleFactor=1 -sCompression=lzw -dNumRenderingThreads=4 -c "30000000 setvmthreshold" -dNOGC -sDEVICE=tiffscaled24 -sOutputFile=\\[servername]\amb_ops_scanning$\Test.tiff \\[servername]\amb_ops_scanning$\Test.pdf 

设置在 XML 文件中读取并存储在 GSVals 类中。该类还处理写入系统日志以进行输出,或写入普通程序版本中的文本文件。GSSTDIO 是一个用于处理 GS 输入和输出的类,它只是将所有输出重定向到与 GSVals 相同的日志。程序版本和服务版本之间的唯一代码更改是服务处理代码,输出从文本文件更改为系统日志。Ghostscript 处理没有任何改变。

为了可移植性,它被编译为 x86,但正在 x64 上运行。已安装 GS 9.15,包括 x86 和 x64 版本。GS.NET 是通过 NuGet 安装到 VS 2012 中的版本 4.0.30319。ILMerge 2.13.0307 用于将 GS.NET dll 打包到 exe 中,也是为了便于移植。这些东西在正常的 EXE 和 Windows 服务版本之间都没有改变,正如我所说的,正常的 EXE 没有任何问题。

4

1 回答 1

1

我通过使用 advapi32.dll 中的 CreateProcessAsUser() 和本文中的代码让它工作了。

我还必须重新调整开关的顺序:

switches.Add("-c 30000000 setvmthreshold -f\"" + file + "\"")

我用来加速转换的原始来源省略了“-f”部分,以及 -f 是标记文件的标签这一事实。我不知道为什么这在 GS.NET 中有效,但是对于正常的 gswin32c.exe,我收到一个错误,说它是一个无效文件,直到我以这种方式设置开关。

奇怪的是,这个方法创建的进程仍然是 Session 0,但它确实有效。我会继续修补,但现在它正在工作。

于 2014-11-18T18:35:06.357 回答