In PDF qua dịch vụ Windows với C #


8

Tôi đang sử dụng mã này để in tệp PDF trên máy in cục bộ có C # trong dịch vụ windows.

Process process = new Process();
PrinterSettings printerSettings = new PrinterSettings();

if (!string.IsNullOrWhiteSpace(basePrint))
   printerSettings.PrinterName = basePrint;

process.StartInfo.FileName = fileName;
process.StartInfo.Verb = "printto";
process.StartInfo.Arguments = "\"" + printerSettings.PrinterName + "\"";
process.Start();
process.WaitForInputIdle();

Mọi thứ hoạt động tốt khi tôi đặt người dùng chạy dịch vụ windows.

Bất cứ khi nào tôi chạy mã này theo thông tin xác thực LocalSystem, tôi gặp lỗi "không có ứng dụng nào liên quan đến thao tác này" thường chỉ ra rằng tôi không có chương trình sẵn sàng xử lý thao tác in của tệp có phần mở rộng .pdf .

Vấn đề của tôi là tôi có chương trình (Foxit Reader) để xử lý thao tác này như được xác nhận bởi thực tế là mã này hoạt động với người dùng cụ thể được đặt trên dịch vụ và tôi có thể gửi tệp đến máy in bằng cách vuốt chúng và chọn tùy chọn in.

Có bất cứ điều gì tôi có thể thay đổi để có thể in trên máy in cục bộ từ trong một dịch vụ mà không cần một người dùng cụ thể không?


Đó là loại máy in nào? Được cài đặt cục bộ hoặc một máy in mạng được chia sẻ thông qua \ computername \ Priinterame?
sa.he

Đó là một Epson EcoTank L375 ( epson.com.jm/Support/Printers/ ALL-In-Ones / L-Series / trộm ) được cài đặt cục bộ.
Caio Sant'Anna

Câu trả lời:


4

Tôi đã kết thúc việc sử dụng pdfium để thực hiện công việc. Với mã đó, tệp PDF được gửi chính xác đến máy in ngay cả khi dịch vụ windows đang chạy dưới người dùng LocalService.

PrinterSettings printerSettings = new PrinterSettings()
{
    PrinterName = printerName,
    Copies = 1
};

PageSettings pageSettings = new PageSettings(printerSettings)
{
    Margins = new Margins(0, 0, 0, 0)
};

foreach (PaperSize paperSize in printerSettings.PaperSizes)
{
    if (paperSize.PaperName == "A4")
    {
        pageSettings.PaperSize = paperSize;
        break;
    }
}

using (PdfDocument pdfDocument = PdfDocument.Load(filePath))
{
    using (PrintDocument printDocument = pdfDocument.CreatePrintDocument())
    {
        printDocument.PrinterSettings = printerSettings;
        printDocument.DefaultPageSettings = pageSettings;
        printDocument.PrintController = (PrintController) new     StandardPrintController();
        printDocument.Print();
    }
}

Cảm ơn các anh vì các câu trả lời.


0

Vấn đề có thể là tài khoản HỆ THỐNG (LocalSystem) bị hạn chế khả năng giao diện người dùng và có thể các tiện ích mở rộng shell hoặc shell bị xóa hoặc vô hiệu hóa. Và động từ là một khả năng của hệ thống con shell, cụ thể là Explorer.

Bạn có thể gọi chương trình theo cách thủ công để xem đó là trường hợp hay đó là vấn đề bảo mật hoặc thiếu chi tiết hồ sơ người dùng.

Để làm điều đó, bạn cần phải đào trong Registry và bạn sẽ thấy rằng nhiều động từ mở rộng thực thi shell có một dòng lệnh.

Ví dụ: Tìm lệnh HKEY_CLASSES_ROOT.pdf \ shell \ printto \ và sử dụng lệnh đó.

Ngoài ra, bạn có thể kiểm tra xem tài khoản HỆ THỐNG có quyền truy cập vào khóa này và khóa cha hay không. (Hiếm khi xảy ra trường hợp nhưng đáng để kiểm tra)


0

Bạn có thể có thể thực thi mã làm việc của mình, nhưng sử dụng mã thông báo người dùng phiên hiện đang hoạt động (nhưng không có phiên hoạt động thì điều này không hoạt động)

Để đơn giản, mã này sẽ không được biên dịch: trước tiên bạn phải điều chỉnh và thêm một số P / Gọi .

Bạn phải tìm id phiên hoạt động. Đối với phiên mở cục bộ, sử dụng:

    [DllImport("wtsapi32.dll", SetLastError = true)]
    public static extern int WTSEnumerateSessions(
        IntPtr hServer,
        int Reserved,
        int Version,
        ref IntPtr ppSessionInfo,
        ref int pCount);

Sau đó tìm kiếm id phiên mở:

        var typeSessionInfo = typeof(WTSApi32.WTSSessionInfo);
        var sizeSessionInfo = Marshal.SizeOf(typeSessionInfo);
        var current = handleSessionInfo;
        for (var i = 0; i < sessionCount; i++)
        {
            var sessionInfo = (WTSApi32.WTSSessionInfo)Marshal.PtrToStructure(current, typeSessionInfo);
            current += sizeSessionInfo;
            if (sessionInfo.State == WTSApi32.WTSConnectStateClass.WTSActive)
                return sessionInfo.SessionID;
        }

Nếu không tìm thấy, tìm kiếm một phiên thứ bảy với:

    [DllImport("kernel32.dll")]
    public static extern uint WTSGetActiveConsoleSessionId();

Với điều đó nhận được mã thông báo

    private static IntPtr GetUserImpersonatedToken(uint activeSessionId)
    {
        if (!WTSApi32.WTSQueryUserToken(activeSessionId, out var handleImpersonationToken))
            Win32Helper.RaiseInvalidOperation("WTSQueryUserToken");

        try
        {
            return DuplicateToken(handleImpersonationToken, AdvApi32.TokenType.TokenPrimary);
        }
        finally
        {
            Kernel32.CloseHandle(handleImpersonationToken);
        }
    }

Với điều đó, bạn có thể thực thi một exe từ dịch vụ Hệ thống cục bộ, trên phiên người dùng đã mở.

    public static void ExecuteAsUserFromService(string appExeFullPath, uint activeSessionId, bool isVisible = false, string cmdLine = null, string workDir = null)
    {
        var tokenUser = GetUserImpersonatedToken(activeSessionId);
        try
        {
            if (!AdvApi32.SetTokenInformation(tokenUser, AdvApi32.TokenInformationClass.TokenSessionId, ref activeSessionId, sizeof(UInt32)))
                Win32Helper.RaiseInvalidOperation("SetTokenInformation");

            ExecuteAsUser(tokenUser, appExeFullPath, isVisible, cmdLine, workDir);
        }
        finally
        {
            Kernel32.CloseHandle(tokenUser);
        }
    }

Bây giờ hãy xem nếu bạn có thể điều chỉnh mã của mình thành CreateProcessAsUSer(...)

    private static void ExecuteAsUser(IntPtr token, string appExeFullPath, bool isVisible, string cmdLine, string workDir)
    {
        PrepareExecute(appExeFullPath, isVisible, ref workDir, out var creationFlags, out var startInfo, out var procInfo);
        try
        {
            startInfo.lpDesktop = "WinSta0\\Default";
            var processAttributes = new AdvApi32.SecurityAttributes
            {
                lpSecurityDescriptor = IntPtr.Zero
            };
            var threadAttributes = new AdvApi32.SecurityAttributes
            {
                lpSecurityDescriptor = IntPtr.Zero
            };
            if (!AdvApi32.CreateProcessAsUser(token,
                appExeFullPath, // Application Name
                cmdLine, // Command Line
                ref processAttributes,
                ref threadAttributes,
                true,
                creationFlags,
                IntPtr.Zero,
                workDir, // Working directory
                ref startInfo,
                out procInfo))
            {
                throw Win32Helper.RaiseInvalidOperation("CreateProcessAsUser");
            }
        }
        finally
        {
            Kernel32.CloseHandle(procInfo.hThread);
            Kernel32.CloseHandle(procInfo.hProcess);
        }
    }

Hy vọng mã này sẽ phục vụ cho bạn hoặc người khác!


0

Có thể, ứng dụng PDF không nằm trong biến PATH trên toàn hệ thống, mà chỉ dưới người dùng cụ thể của bạn?

Tôi nghĩ vấn đề của bạn xảy ra do người dùng "hệ thống cục bộ" không tìm thấy một ứng dụng phù hợp, vì vậy bạn sẽ phải đăng ký nó cho anh ta. Vì bạn đã chấp nhận câu trả lời khác, tôi sẽ không dành nhiều thời gian hơn cho vấn đề này, nhưng nếu có thêm câu hỏi nào về vấn đề này, vui lòng hỏi.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.