Ghostscript.NET - ไม่มีไฟล์เอาต์พุตเมื่อทำงานเป็นบริการ Windows

ฉันกำลังเขียน Windows Service เพื่อสแกนชุดไดเรกทอรีเพื่อหาไฟล์ PDF ใหม่และแปลงเป็น TIFF ด้วย Ghostscript.NET ตอนที่ฉันคอมไพล์และรันโค้ดเหมือนโปรแกรมปกติ มันทำงานได้อย่างสมบูรณ์ แต่เมื่อฉันใช้โค้ดเดียวกันกับ Service ผลลัพธ์ TIFF จะไม่ปรากฏขึ้นเลย ฉันได้ตั้งค่าไดเรกทอรีปลายทางเพื่อให้สามารถเขียนสำหรับทุกคนได้ และ PDF ต้นฉบับกำลังถูกลบออกตามที่ควรจะเป็น ดังนั้นจึงไม่ควรเป็นปัญหาการอนุญาตสำหรับผู้ใช้ "ระบบท้องถิ่น" การตรวจสอบไดเร็กทอรีสำหรับการเข้าถึงความล้มเหลวและความสำเร็จจะแสดงรายการความสำเร็จเท่านั้น

มีฟังก์ชันที่อ่านประชากรสีของ PDF เพื่อพิจารณาว่าเป็นเอกสารสีหรือสแกนขาวดำเป็นสี ส่วนนั้นใช้งานได้ ดังนั้นจึงไม่มีปัญหาในการเข้าถึงและอ่าน PDF

ฉันได้ลองลบ '-q' ออกจากสวิตช์ Ghostscript และฉันไม่มีรายงานข้อผิดพลาดใด ๆ และ "-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 คลาสยังจัดการการเขียนลงในบันทึกของระบบสำหรับเอาต์พุตหรือไปยังไฟล์ข้อความในเวอร์ชันโปรแกรมปกติ GSTDIO เป็นคลาสสำหรับจัดการอินพุตและเอาต์พุต GS ซึ่งเพียงเปลี่ยนเส้นทางเอาต์พุตทั้งหมดไปยังบันทึกเดียวกันกับ GSVals รหัสเดียวที่เปลี่ยนแปลงระหว่างเวอร์ชันโปรแกรมและเวอร์ชันบริการคือรหัสการจัดการบริการ และเอาต์พุตจะเปลี่ยนจากไฟล์ข้อความเป็นบันทึกของระบบ ไม่มีการเปลี่ยนแปลงใด ๆ เกี่ยวกับการประมวลผล Ghostscript

สิ่งนี้กำลังถูกคอมไพล์เป็น x86 เพื่อการพกพา แต่กำลังรันบน x64 ติดตั้ง GS 9.15 แล้ว ทั้งเวอร์ชัน x86 และ x64 GS.NET เป็นเวอร์ชัน 4.0.30319 ที่ติดตั้งผ่าน NuGet ใน VS 2012 ILMerge 2.13.0307 ถูกใช้เพื่อจัดทำแพ็กเกจ GS.NET dll ลงใน exe เพื่อการพกพาด้วยเช่นกัน สิ่งเหล่านี้ไม่มีการเปลี่ยนแปลงระหว่าง EXE ปกติและเวอร์ชัน Windows Service และอย่างที่บอกไปว่า EXE ปกติทำงานได้โดยไม่มีปัญหาใดๆ


person Scott    schedule 17.11.2014    source แหล่งที่มา
comment
มีโอกาสที่ต้องใช้เซสชัน 0 เพื่อเรนเดอร์ Windows Services บล็อกเซสชัน 0 เพื่อความปลอดภัย   -  person Aron    schedule 17.11.2014
comment
เมื่อพิจารณาแล้ว ขอบคุณ... ghostscript session 0 ใน Google ตอนนี้แสดงหน้านี้ว่าเป็นการเข้าชมครั้งแรก :)   -  person Scott    schedule 17.11.2014
comment
คุณได้ทำเครื่องหมายที่ อนุญาตให้บริการโต้ตอบกับเดสก์ท็อปแล้ว? อาจจะคุ้มค่าที่จะลอง stackoverflow.com/q/4237225/397817 นอกจากนี้ Windows Services ยังบล็อกเซสชัน 0 ใน Google ผลลัพธ์แรก: stackoverflow.com/q/17364932/397817 :)   -  person Stephen Kennedy    schedule 17.11.2014
comment
การโต้ตอบกับเดสก์ท็อปไม่ได้ช่วยอะไร ฉันพบ MS เอกสารไวท์เปเปอร์ ที่แสดงการเปลี่ยนแปลงใน Service 0 ใน Vista+ ดูเหมือนว่าบริการทั้งหมดจะเป็นเซสชัน 0 และเซสชันผู้ใช้คือ 1+ เนื่องจากเซสชัน 0 ไม่ใช่เซสชันผู้ใช้อีกต่อไป บริการที่ทำงานในเซสชัน 0 จึงไม่สามารถเข้าถึงไดรเวอร์วิดีโอได้ ซึ่งหมายความว่าความพยายามใด ๆ ที่บริการทำเพื่อเรนเดอร์กราฟิกจะล้มเหลว   -  person Scott    schedule 17.11.2014
comment
คุณแน่ใจหรือว่าบริการ windows ของคุณสามารถเข้าถึง \[ชื่อเซิร์ฟเวอร์]\? คุณลองตั้งค่าไฟล์อินพุตและเอาท์พุตลงในไดรฟ์ในเครื่องของคุณได้ไหม   -  person HABJAN    schedule 17.11.2014
comment
นอกจากนี้ ให้ลองบันทึกข้อความ Ghostscript stdio ด้วยวิธีนี้: pastebin.com/1F5wCu8M   -  person HABJAN    schedule 17.11.2014
comment
สามารถเปิดไฟล์ PDF ต้นฉบับซึ่งอยู่ในไดเร็กทอรีเดียวกับเส้นทางเอาต์พุตและเก็บถาวร PDF (ลบออก) โดยไม่มีข้อผิดพลาด นั่นควรระบุว่ามีการเข้าถึง R/W สำหรับการแชร์เซิร์ฟเวอร์   -  person Scott    schedule 18.11.2014
comment
ฉันจะต้องแก้ไขด้วยการเปลี่ยนเส้นทางเอาต์พุต GS จาก GS.NET แต่ฉันทำให้มันใช้งานได้โดยการสร้างกระบวนการเพิ่มเติม - ดูคำตอบของฉัน   -  person Scott    schedule 18.11.2014
comment
ฉันไม่สามารถเข้าถึงภาพของคุณได้ เนื่องจากตัวกรองเว็บที่เข้มงวดของบริษัทฉันไม่ชอบประสิทธิภาพการทำงานที่แท้จริง แต่ฉันเปลี่ยนเส้นทางเอาต์พุต Ghostscript.NET โดยใช้คลาส GsStdio ซึ่งเพิ่งพิมพ์เอาต์พุตใด ๆ ไปยังบันทึก ฉันไม่เคยเห็นอะไรเลยนอกจากกดปุ่มใดก็ได้เพื่อดำเนินการต่อประเภทข้อความ ลิงก์ของคุณมีลักษณะคล้าย -sstdout=[ชื่อไฟล์] หรือไม่   -  person Scott    schedule 18.11.2014


คำตอบ (1)


ฉันทำให้มันทำงานได้โดยใช้ CreateProcessAsUser() จาก advapi32.dll โดยใช้โค้ดจาก บทความนี้

ฉันยังต้องปรับโครงสร้างลำดับของสวิตช์ใหม่ด้วย:

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

แหล่งที่มาดั้งเดิมที่ฉันใช้เพื่อเร่งการแปลงนั้นไม่มีส่วน '-f' และความจริงที่ว่า -f คือแท็กที่ทำเครื่องหมายไฟล์ ฉันไม่รู้ว่าทำไมสิ่งนี้ถึงใช้งานได้ใน GS.NET แต่ด้วย gswin32c.exe ปกติ ฉันพบข้อผิดพลาดที่บอกว่ามันเป็นไฟล์ที่ไม่ถูกต้อง จนกว่าฉันจะตั้งค่าสวิตช์ด้วยวิธีนี้

น่าแปลกที่กระบวนการที่วิธีนี้สร้างยังคงเป็นเซสชัน 0 แต่ใช้งานได้จริง ฉันจะซ่อมแซมต่อไป แต่ตอนนี้มันใช้งานได้แล้ว

person Scott    schedule 18.11.2014
comment
-f ไม่ได้ 'ทำเครื่องหมายไฟล์' แต่จะปิดอินพุต PostScript โดยตรงซึ่งขึ้นต้นด้วย '-c' หากคุณไม่ได้ใช้ -c คุณไม่จำเป็นต้อง -f.... - person KenS; 19.11.2014