C#でWindowsサービスを介してPDF印刷


8

このコードを使用して、Windowsサービス内でC#を使用してローカルプリンターでPDFファイルを印刷しています。

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();

ユーザーがWindowsサービスを実行するように設定すると、すべてが正常に機能します。

LocalSystem資格情報の下でこのコードを実行すると、「この操作に関連付けられているアプリケーションはありません」というエラーが表示されますが、これは通常、拡張子が.pdfのファイルの印刷操作を処理するプログラムがないことを示しています。 。

私の問題は、このコードがサービスに設定された特定のユーザーで機能し、ファイルを右クリックすることでプリンターにファイルを送信できるという事実によって確認されるように、この操作を処理するプログラム(Foxit Reader)があることです印刷オプションを選択します。

特定のユーザーなしでサービス内からローカルプリンターで印刷できるように変更できるものはありますか?


どんなプリンターですか?ローカルにインストールされているか、\\ computername \ printername経由の共有ネットワークプリンターですか?
sa.he

これは、ローカルにインストールされたEpson EcoTank L375(epson.com.jm/Support/Printers/All-In-Ones/L-Series/…)です。
Caio Sant'Anna

回答:


4

結局、pdfiumを使用して仕事をしました。そのコードを使用すると、WindowsサービスがLocalServiceユーザーで実行されている場合でも、PDFファイルがプリンターに正しく送信されます。

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();
    }
}

答えてくれてありがとう。


0

問題は、SYSTEM(LocalSystem)アカウントのユーザーインターフェイス機能が制限されており、シェルまたはシェル拡張が削除または無効にされている可能性があります。また、動詞はシェルサブシステム、特にエクスプローラーの機能です。

プログラムを手動で起動して、そうであるか、それともセキュリティの問題であるか、ユーザープロファイルの詳細がないかを確認できます。

これを行うには、レジストリを掘り下げる必要があります。多くのシェル実行拡張機能の動詞にコマンドラインがあることがわかります。

たとえば、HKEY_CLASSES_ROOT.pdf \ shell \ printto \ commandを見つけてそのコマンドを使用します。

また、SYSTEMアカウントがこのキーと親キーにアクセスできることを確認することもできます。(まれなケースですが、確認する価値があります)


0

おそらく作業コードを実行できますが、現在アクティブなセッションユーザートークンを使用します(ただし、アクティブセッションがない場合、これは機能しません)

簡潔にするために、このコードはコンパイルされません。最初にP / Invokeを調整して追加する必要があります。

アクティブなセッションIDを見つける必要があります。ローカルで開かれたセッションの場合、これを使用します:

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

次に、開いているセッションIDを検索します。

        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;
        }

見つからない場合は、次でrdpセッションを検索します。

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

それでトークンを取得

    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);
        }
    }

これにより、開いたユーザーセッションでローカルシステムサービスからexeを実行できます。

    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);
        }
    }

次に、コードを適合できるかどうかを確認します 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);
        }
    }

このコードがあなたや他の誰かに役立つことを願っています!


0

PDFアプリケーションがシステム全体のPATH変数ではなく、特定のユーザーの下にあるのでしょうか?

「ローカルシステム」のユーザーが適切なアプリケーションを見つけられなかったために問題が発生したと思います。そのため、アプリケーションを登録する必要があります。すでに別の回答を受け入れているので、これ以上時間を割くことはしませんが、これについてさらに質問がある場合は、質問してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.