PrintDocument.Print приводит к Win32Exception Операция успешно завершена - PullRequest
10 голосов
/ 09 сентября 2009

Я пытаюсь распечатать приложение C # .NET 3.5 на сетевом принтере и получаю следующее исключение:

Операция успешно завершена

Что является причиной и как ее можно решить?

System.ComponentModel.Win32Exception: The operation completed successfully
   at System.Drawing.Printing.PrinterSettings.GetHdevmodeInternal()
   at System.Drawing.Printing.PrinterSettings.GetHdevmode(PageSettings pageSettings)
   at System.Drawing.Printing.PrintController.OnStartPrint(PrintDocument document, PrintEventArgs e)
   at System.Windows.Forms.PrintControllerWithStatusDialog.OnStartPrint(PrintDocument document, PrintEventArgs e)
   at System.Drawing.Printing.PrintController.Print(PrintDocument document)
   at System.Drawing.Printing.PrintDocument.Print()
  • учетная запись имеет права на печать с использованием сетевого принтера. Для каждого пользователя установлены разрешения на печать.
  • принтер был удален и воссоздан.
  • настройка для буферизации и печати непосредственно на принтер была переключена в обе стороны.
  • другие принтеры на аппарате работают нормально
  • другие клиенты в сети и приложения на этом же компьютере могут печатать на этом принтере без проблем.

Чтобы сузить проблему, я создал простое консольное приложение. Работает как обычный пользователь, приложение печатает. При запуске как учетной записи службы она ошибается для учетной записи службы .

enter image description here

Решением для моей проблемы было удаление драйвера, вызывающего проблему, и установка более старого драйвера.

Ответы [ 4 ]

17 голосов
/ 12 июля 2014

Загадочное сообщение вызвано ошибкой в ​​pinvoke-коде внутри .NET Framework. Основной вызов winapi, который завершается неудачей, является DocumentProperties() функцией . Декларация pinvoke для него выглядит так:

[DllImport("winspool.drv", CharSet=CharSet.Auto, SetLastError=true)]
public static extern int DocumentProperties(...);

Свойство SetLastError неверно. Как вы можете сказать по ссылке MSDN, функция сообщает об ошибке, возвращая отрицательное значение. И не задокументировано для установки кода ошибки, который возвращается GetLastError().

Следствием этой ошибки является то, что фреймворк вызовет Marshal.GetLastWin32Error() для получения кода ошибки и получит случайное значение, поскольку DocumentProperties() не установило его. Значение 0 весьма вероятно, что приводит к сообщению об исключении «Операция успешно завершена».

Так что вам нужно игнорировать сообщение об исключении; это очень бесполезно, конечно. К сожалению, эта функция winapi попадает в категорию функций, как и большинство функций GDI, которые выдают только код возврата «это не сработало». Это не дает подсказки, где искать проблему. Для этой причуды есть полуприличная причина: сама Windows делает очень мало, когда вы звоните DocumentProperties(); большая часть работы выполняется драйвером принтера. Нет набора кодов ошибок, отведенных для печати в winapi. Все возможно: драйверы принтера не являются тонкими частями кода. Задача драйвера принтера - рассказать вам о проблемах. Они должны сделать это, открыв собственное окно. Теоретически они так или иначе; острая конкуренция в этом сегменте рынка не оставляет много денег, чтобы платить хорошую зарплату программиста в наши дни.

Это, конечно, не может работать при печати из службы. Нет такого способа увидеть такое всплывающее окно, что является основной причиной, по которой Microsoft настоятельно не рекомендует печатать из службы. Ни у вас, ни у ИТ-персонала вашего клиента нет возможности диагностировать проблемы. Прочтите это сообщение в блоге для получения дополнительных сведений об использовании PrintDocument из службы.

Никто не любит получать такие советы, но надпись на стене. Не делай этого .

5 голосов
/ 18 июля 2014

Чтобы добавить к ответу @ HansPassant, вот точный код, который вызывает исключение:

Справочный источник Microsoft, PrinterSettings.cs

private IntPtr GetHdevmodeInternal(string printer) {
    // Create DEVMODE
    int modeSize = SafeNativeMethods.DocumentProperties(NativeMethods.NullHandleRef, NativeMethods.NullHandleRef, printer, IntPtr.Zero, NativeMethods.NullHandleRef, 0);
    if (modeSize < 1) {
        throw new InvalidPrinterException(this);
    }
    IntPtr handle = SafeNativeMethods.GlobalAlloc(SafeNativeMethods.GMEM_MOVEABLE, (uint)modeSize); // cannot be <0 anyway
    IntPtr pointer = SafeNativeMethods.GlobalLock(new HandleRef(null, handle));

    //Get the DevMode only if its not cached....
    if (cachedDevmode != null) {
        Marshal.Copy(cachedDevmode, 0, pointer, devmodebytes);
    }
    else  {
        int returnCode = SafeNativeMethods.DocumentProperties(NativeMethods.NullHandleRef, NativeMethods.NullHandleRef, printer, pointer, NativeMethods.NullHandleRef, SafeNativeMethods.DM_OUT_BUFFER);
        if (returnCode < 0) {
            throw new Win32Exception();  // <--------
        }
    }
1 голос
/ 10 сентября 2009

Очень сложно ответить без кода и исключения, которое говорит, что у вас все в порядке. Поэтому я просто дам несколько идей, чтобы отследить проблему

  1. Протестируйте его на локальном принтере, чтобы убедиться, что приложение работает.
  2. Попробуйте выполнить печать на сетевом принтере с помощью блокнота или чего-то подобного
  3. Double nay triple check, чтобы пользователь, у которого запущено приложение, имел права на печать на сетевой принтер.
  4. Проверьте его на другом сетевом принтере (после выполнения 2 и 3 для этого принтера)
0 голосов
/ 07 февраля 2017

У меня тоже была эта проблема. В моем случае я использовал отдельный поток для печати отчета и синхронизировал его с основным потоком через «ManualResetEvent». (Я разработал этот способ, потому что .Net-силы делят логику печати на методы «PrintPage» ...).

Ошибка возникает из-за несовместимости (которую я не могу объяснить источник) между драйвером принтера и этой многопоточной средой.

Я решил проблему, изменив сигнатуру метода логики печати с «void» на «IEnumerable», и пробил доходность - метод, похожий на «CoRoutines» игрового движка Unity3d. Таким образом, нет необходимости создавать более одного потока, и мой код печати организован.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...