C++ Builder
| Главная | Уроки | Статьи | FAQ | Форум | Downloads | Литература | Ссылки | RXLib | Диски |

 
Помогите определить доступность сетевого принтера, узнать, стоит ли на печать док посылать
Deem
Отправлено: 18.12.2003, 15:41


Мастер участка

Группа: Участник
Сообщений: 327



Драйвер сетевого принтера установлен и все настройки верны.
Работает все, когда сетевой (на сервере) принтер доступен.
Вот какая проблема: если принтер вырубить, или сеть вообще отсоединить, при создании объекта QReport , видимо при тесте принтера, программа замирает надолго. Потом, может матюкнуться, а может так и висеть.... Хочу перед динамическим созданием QReport протестировать доступность принтера.
Пробовал по-разному: и через API и VCL... Одним функциям пофиг тот дальний притер и они гонят информацию местного драйвера, другие уходят в сеть и не возвращаются.
Сама винда очень быстро определяет недоступность принтера, когда пытаешься посмотреть свойства принтера в ПРИНТЕРАХ. Значит, есть апишный способ определения доступности принтера. Подскажите, кто знает.
Admin
Отправлено: 18.12.2003, 19:27


Владимир

Группа: Администратор
Сообщений: 1190



EnumPrinters()

http://www.buildercpp.net.ru/articles/prin...nt/print005.htm
Deem
Отправлено: 19.12.2003, 12:01


Мастер участка

Группа: Участник
Сообщений: 327



Не то... Просто получение списка ЗАРЕГИСТРИРОВАННЫХ на локальной машине принтеров с атрибутами. Я даже поигрался с EnumPrinters. Либо она виснет, либо выдает данные о принтерах вне зависимости от того, есть сеть или нету (локальные данные).
pasha
Отправлено: 19.12.2003, 12:53


Дежурный стрелочник

Группа: Участник
Сообщений: 62



QUOTE
Я даже поигрался с EnumPrinters


И Help к этой функции читали ?

PRINTER_ENUM_LOCAL
PRINTER_ENUM_NAME
PRINTER_ENUM_SHARED
PRINTER_ENUM_DEFAULT
PRINTER_ENUM_CONNECTIONS
PRINTER_ENUM_NETWORK
PRINTER_ENUM_REMOTE

и про
DWORD Level, // specifies type of printer info structure
Deem
Отправлено: 19.12.2003, 18:11


Мастер участка

Группа: Участник
Сообщений: 327



Это самое я и имел ввиду под "поигрался". Да, что-то промелькнуло, когда с одной из сетевых констант я получил кол-во аринтеров 3. У меня установлен драйвер для одного, а вобще в сети их 3. Я думал, что получилось, и пошел получать параметры этих трех. Однако получил параметры только одного, который а меня зарегистрирован. А при попытке получить данные других функция повисла (или пошла в сеть на очень долго). А когда я вырубил сеть, то спокойно получил один сетевой принтер и его атрибуты (тот самый, драйвер которого установлен у меня.) Сети нет — а принтер сетевой есть. Класс.
Может Вы вопроса не поняли? Я хочу узнать о готовности сетевого (уже известного ) принтера печатать перед посылкой документа. А та же функция OpenPrinter уходит надолго, если сеть вырубить или отключить от сети компьютер с искомым принтером.

Отредактировано Deem — 23/12/2003, 11:01
pasha
Отправлено: 20.12.2003, 20:17


Дежурный стрелочник

Группа: Участник
Сообщений: 62



Да работы (где есть сеть и сетевые принтеры)
доберусь в понедельник, чтобы что-либо попробовать.

Попробуйте:
http://ixbt.wallst.ru/pspr.html






















Как получить список имен всех доступных принтеров (в т.ч. сетевых) в системе?


Используй флаги
PRINTER_ENUM_LOCAL
PRINTER_ENUM_NETWORK

и т.д.

Вот мучаюсь я с этой EnumPrinters. В 98 надо PPRINTER_INFO_5, а в NT4 надо PPRINTER_INFO_4. Причем выдаются только локальные принтеры. Для сетевых вроде надо только с PPRINTER_INFO_1, а она дает каких-то провайдеров печати вместо принтеров. Короче запутался я уже. Нужен алгоритм как с этим быть. Или может есть уже что-нить готовое?

Я тут у себя в архиве нашел демо-примерчик. На Delphi, но если ты
пишешь на С, С++ — то тоже сгодится (в конце концов API везде одно и
то же)

procedure TMainScreen.BtnEnumClick(Sender: TObject);

var
Level : Byte;
Buffer, PrinterInfo : PChar;
i : Integer;
Flags, Count, NumInfos : DWORD;
liPrn : TListItem;
begin
// Flush any previous content of the visula printer list
LvPrinters.Items.Clear;
//
// We need different version of PRINTERINFO
// depending of Windows version
if Win32Platform = VER_PLATFORM_WIN32_NT then begin
// Under NT ENUM_CONNECTIONS will work fast, because
// it does not perfrom real RPC calls, but uses internal NT
// "history" instead.
Flags := PRINTER_ENUM_CONNECTIONS or PRINTER_ENUM_LOCAL;
Level := 4;
end
else begin
// Under Win9x ENUM_LOCAL will return even network devices,
// because, in fact, all information will be retrieved from Registry
Flags := PRINTER_ENUM_LOCAL;
Level := 5;
end;
//
// Determine, how much memory do we need for the printer
// list and allocate necessary buffer.
Count := 0;
EnumPrinters( Flags, nil, Level, nil, 0, Count, NumInfos );
if Count = 0 then Exit;
GetMem( Buffer, Count );
//
try
// Retrieve printer list
if not EnumPrinters( Flags, nil, Level, PByte(Buffer), Count, Count, NumInfos ) then
Exit;
PrinterInfo := Buffer;
//
// Walk through the printer list and put an information
// about each printer to our own ListView
for i := 0 to NumInfos — 1 do begin
liPrn := LvPrinters.Items.Add;
//
if Level = 4 then begin
// Process PRINTER_INFO_4 data
liPrn.Caption := PPrinterInfo4(PrinterInfo)^.pPrinterName;
if (PPrinterInfo4(PrinterInfo)^.Attributes and PRINTER_ATTRIBUTE_NETWORK) <> 0
then liPrn.subItems.Add( 'network' )
else liPrn.SubItems.Add( 'local' );
Inc( PrinterInfo, SizeOf(TPrinterInfo4) );
end
else begin
// Process PRINTER_INFO_5 data
liPrn.Caption := PPrinterInfo5(PrinterInfo)^.pPrinterName;
if (PPrinterInfo5(PrinterInfo)^.Attributes and PRINTER_ATTRIBUTE_SHARED) <> 0
then liPrn.subItems.Add( 'shared' )
else liPrn.SubItems.Add( '' );
Inc( PrinterInfo, SizeOf(TPrinterInfo5) );
end;
end;
finally
FreeMem( Buffer, Count );
end;
end;


P.S. Под 9x
INFO_5 не различает локальные и сетевые принтеры


У меня, конечно, на Дельфях (но на Билдере тоже идти должон), так
что не обессудьте (да и с форматированием у меня пока никак)



//Запомнили принтер по умолчанию
GetProfileString ('windows','device',',,,',buffer,256);
OldProfileString:=StrPas(buffer);
FormChangePrinter:=TFormChangePrinter.Create(Application);

// Получаем список всех принтеров системы

FormChangePrinter.ListBoxPrint.Items:=Printer.Printers;
FormChangePrinter.ListBoxPrint.ItemIndex:=0;
if pos(' on ',ListBoxPrint.items[ListBoxPrint.ItemIndex])=0 then
//Windows NT
NewPrn:=ListBoxPrint.items[ListBoxPrint.ItemIndex]
else
//Windows 95/98
NewPrn:=copy(ListBoxPrint.items[ListBoxPrint.ItemIndex],1,
pos(' on ',ListBoxPrint.items[ListBoxPrint.ItemIndex])-1);
// Имя драйвера и порт для выбранного
GetProfileString( 'devices',pchar(NewPrn),',,,',buffer,256);
NewProfileString:=NewPrn+','+buffer;
if (NewProfileString<>OldProfileString) then
//Меняем только если принтер отличен от по умолчанию
begin
WriteProfileString('windows','device',PChar(NewProfileString));
SendMessage(HWND_Broadcast,WM_SETTINGCHANGE,0,0);
end;
...........
//А теперь меняем все назад в системе
WriteProfileString('windows','device',PChar(OldProfileString));
SendMessage(HWND_Broadcast,WM_SETTINGCHANGE,0,0);


ОК!

Добавил PRINTER_ENUM_CONNECTIONS в дополнение к PRINTER_ENUM_LOCAL и в NT4
сетевые стали видны. Вот только имя у них начинается с \\...\"имя принтера".
Вопрос: имя сетевого принтера прямо в таком виде задавать в функцию RawDataToPrinter
(см. MSDN тема "Sending Data Directly to a Printer") или отрезать начало? (
Просто нет сейчас возможности попробовать на сетевом). Ведь в папке "Принтеры" только
имя принтера без сетевого префикса.

Именно в таком виде и задавать.


Отредактировано pasha — 20/12/2003, 22:29
Deem
Отправлено: 23.12.2003, 16:51


Мастер участка

Группа: Участник
Сообщений: 327



Все эти примеры посмотрел, запустил... Перебирал свои варианты. При использовании НТ-шных опций видны принтеры, доступные при загрузке винды. При изменении ситуации по сети рассмотренные функции не видят изменений. При использовании 9х-опций видны принтеры, уже удаленные из сети и даже удаленные с локальной машины.

Короче, у меня ругался QReport при создании объекта. Он как-то тестит принтер, установленный по умолчанию. Может, он просто проверяет комп в сети, на котором принтер висит, не знаю.
Короче, я создаю объект QReport в рантайме в try{} и выдаю пользователю свою интерпретацию ошибки.
Хотел кнопку ПРИНТ заранее прятать, ну не вышло.
Исходников QReport у меня нет.
Может кто знает, как он принтер тестит ?
Asher
Отправлено: 23.12.2003, 17:52


Мастер участка

Группа: Модератор
Сообщений: 550



QUOTE
Все эти примеры посмотрел, запустил... Перебирал свои варианты.

а EnumPrinters с Level = 2 (PRINTER_INFO_2)пробовал?
В MSDN'е пример написан с использованием PRINTER_INFO_2. В нем есть атрибуты PRINTER_ATTRIBUTE_WORK_OFFLINE и PRINTER_ATTRIBUTE_NETWORK, а также уйма статусов, среди которых PRINTER_STATUS_OFFLINE, PRINTER_STATUS_ERROR и конечно PRINTER_STATUS_SERVER_UNKNOWN biggrin.gif

P.S. Сам я пример не пробовал, жестокая горячка по поводу конца года.
Если MSDN'а нет, то пример могу выковырять и прислать по e-mail.

P.P.S. ты мой PersonalMessages получил?
Deem
Отправлено: 24.12.2003, 14:32


Мастер участка

Группа: Участник
Сообщений: 327



Да, пробовал. По первой ссылке народ его использует. Но там ограничено. А последние опции интересные... Позырю. Хотя, я уже слегка успокоился. Тоже запарка. Дырку с принтерами я кое-как заткнул. Но разобраться надо.


А перссообч я получил. Руки пока не дошли. А на носу — Новый Год. У нас только сегодня снег выпал smile.gif.


мздн-а, таки да, нету. Зато направление уже есть.

Отредактировано Deem — 24/12/2003, 15:39
Deem
Отправлено: 24.12.2003, 15:42


Мастер участка

Группа: Участник
Сообщений: 327



Пробовал я все эти страшные опции, однако получаю один результат как при включеной сети, та и при выключеной. Кроме того, 2 уровень возвращает принтер, который был на моей машине раньше, а теперь его нет. Короче, не могу понять эту технологию. Может есть какя-то фишка, я ее не нашел.

Ну, а если так: кто-нить пробовал получить (прочитать) с известного принтера (а не местного драйвера-спулера) какие-нить данные?
Есть такая ReadPrinter. Ей, правда, тоже пофиг, включена ли сеть. А результат она возвращает true раз в 4-5 вызовов.
Или уже так: может стоит просто определить сервер принтера (комп), а пототм проверить доступность его по сетке? Если доступен, то посылать на принтер документ, а сервер уже сам пусть разбирается, можно ли на своем принтре печатать.
Doga
Отправлено: 29.06.2006, 14:10


Мастер участка

Группа: Участник
Сообщений: 575



Так кто нибудь разобрался с проверкой работоспособности принтера?

А то ведь и мне знать надо...
*avc
Отправлено: 29.06.2006, 15:27


Не зарегистрирован







Разобрался.
EnumPrinters (с уровнем 2)
Винда считает его всегда готовым, и другого способа проверки найти не удалось. Вернее удалось, но это уже зависит от самого принтера и его возможностей (напимер критичный для нас принтер умеет отвечать по SNMP протоколу).
Кстати, cJobs иногда бессовестно врет (cJobs==0 еще не означает отсутствия заданий в очереди).
Doga
Отправлено: 29.06.2006, 18:01


Мастер участка

Группа: Участник
Сообщений: 575



THX!

P.S. Вспомнилась вдруг такая фраза: "После сборки обработать напильником...."

Ну ка, где тут мой напильник? biggrin.gif
klen
Отправлено: 01.07.2006, 11:27


Машинист паровоза

Группа: Участник
Сообщений: 239



Проблема таже что и у Вас.
Ну че? так мы и не узнаем включен в розетку принтер или нет....
Билли урод.

Отредактировано klen — 01/07/2006, 11:31

Вернуться в Вопросы программирования в C++Builder