Ru-Board.club
← Вернуться в раздел «Прикладное программирование»

» Нужно написать программу по слежению за принтером

Автор: VovaMozg
Дата сообщения: 04.07.2007 09:59
Люди добрые, помогите пожалуйста в написании программки. В общем нужно программу по учёту печати принтера. Программу пишу на VisualStudio (там уже в принципе без разницы на чём будет)
Нужно:
1) отловить сообщение системы (или что-то другое) что послано задание на принтер
2) тормознуть принтер
3) после чего обработать сообщение (ну это уже менее сложно)
4) и после обработки сообщения продолжить печать либо же остановить печать

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

Помогите хоть чем-нибудь, хоть какими-нибудь мыслями... может кто-то подобными проектамизанимался...
Заранее спасибо...
Автор: VovaMozg
Дата сообщения: 09.07.2007 09:15
Ну что, ни у кого мылей нету чтоли??? хоть какие-нить намётки... помогите пожалуйста...
Автор: SpoinT
Дата сообщения: 09.07.2007 09:27
Для этого есть функции FindFirstPrinterChangeNotification, FindNextPrinterChangeNotification
и т.п.

Компонент TPrinter есть.

Попробуйте, после того как задание отправлено на печать, с определённым интервалом опрашивать принтер посредством таймера, используя функцию EnumJobs,
(модуль WinSpool.pas), по полученному параметру, типа JOB_INFO_1, можно проверить текуший статус принтера (имя документа, пользователь, сколько страниц напечатано, сколько страниц в очереди и др).
Автор: VovaMozg
Дата сообщения: 09.07.2007 09:46
SpoinT по таймеру это конечно же хорошо, но желательно бы отловить мессагу от системы... чтобы таймер уж точно не пропустил

Цитата:
Компонент TPrinter есть
в визуал студии? не мог я чё-то там такой найти (может я туплю?)
Автор: SpoinT
Дата сообщения: 09.07.2007 10:13
VovaMozg
Я же тебе скинул их
Цитата:
FindFirstPrinterChangeNotification, FindNextPrinterChangeNotification

Автор: VovaMozg
Дата сообщения: 09.07.2007 10:16
SpoinT ага, пасиб, теперь хоть понятно куда рыть... а не подскажешь маааааленький примерчик как ими пользоваться???
Автор: SpoinT
Дата сообщения: 09.07.2007 10:40
Получение информации об очереди на принтере
[more=Пример кода намба раз]uses
Winspool, Printers;
Function GetCurrentPrinterHandle: THandle;
var
Device, Driver, Port: array[0..255] of Char;
hDeviceMode: THandle;
Begin
Printer.GetPrinter(Device, Driver, Port, hDeviceMode);
If not OpenPrinter(@Device, Result, nil) Then
RaiseLastWin32Error;
End;
Function SavePChar(p: PChar): PChar;
Const
error: PChar = 'Nil';
Begin
If not Assigned(p) Then
Result := error
Else
Result := p;
End;
Procedure TForm1.Button1Click(SEnder: TObject);
Type
TJobs = array [0..1000] of JOB_INFO_1;
PJobs = ^TJobs;
var
hPrinter: THandle;
bytesNeeded, numJobs, i: Cardinal;
pJ: PJobs;
Begin
hPrinter := GetCurrentPrinterHandle;
Try
EnumJobs(hPrinter, 0, 1000, 1, nil, 0, bytesNeeded,
numJobs);
pJ := AllocMem(bytesNeeded);
If not EnumJobs(hPrinter, 0, 1000, 1, pJ, bytesNeeded,
bytesNeeded, numJobs) Then
RaiseLastWin32Error;
memo1.Clear;
If numJobs = 0 Then
memo1.Lines.Add('No jobs in queue')
Else
For i := 0 to Pred(numJobs) do
memo1.Lines.Add(Format('Printer %s, Job %s, Status (%d): %s',
[SavePChar(pJ^[i].pPrinterName), SavePChar(pJ^[i].pDocument), pJ^[i].Status, SavePChar(pJ^[i].pStatus)]));
finally
ClosePrinter(hPrinter);
End;
End;[/more]

[more=Пример кода намба два ]unit MyHook;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls,WinSpool, DB, DBTables, RxQuery;

const MaxPrinters=10;
NPrinter=1;
MaxJobs=5;
Level=1;
type TJob=TJobInfo1;
PJob=^TJob;
TInfo=TPrinterInfo1;
AInfo=array[1..MaxPrinters]of TInfo;
PInfo=^AInfo;

type
TTestThread=class(TThread)
constructor Create(aNot:THandle);
private
msg:string;
hNot,hWait:THandle;
protected
Procedure SendStatus;
procedure WhenStop(Sender:TObject);
procedure Execute;override;
end;
TPrintThread=class(TThread)
constructor Create(aPrinter:THandle;aNot:THandle);
procedure SendStatus;
private
hPrinter:Thandle;
hNotification:DWORD;
hWait:THandle;
msg:string[30];
protected
procedure WhenStop(Sender:TObject);
procedure Execute;override;
end;
TPrintTestForm = class(TForm)
Status: TMemo;
Header: TPanel;
Start: TButton;
Clear: TButton;
Exits: TButton;
Catch: TButton;
procedure StartClick(Sender: TObject);
procedure ClearClick(Sender: TObject);
procedure ExitsClick(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure CatchClick(Sender: TObject);
private
PT:TPrintThread;
TT:TTestThread;
end;

var
PrintTestForm: TPrintTestForm;
DelayTime:word;
implementation

{$R *.DFM}

Function GetSysError:string;
var Buffer:PChar;
I:DWORD;
begin
GetMem(Buffer,1024);
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,nil,GetLastError,0,Buffer,1024,nil);
I:=0;While(Buffer[I]<>#0)and(I<1024)do Inc(I);Buffer[I-1]:=#0;
Result:='['+inttostr(GetLastError)+']='+Buffer;
SetLastError(0);FreeMem(Buffer,1024);
end;

procedure TPrintTestForm.StartClick(Sender: TObject);
label all;
var I,Count:DWORD;
Info:AInfo;
begin
Screen.Cursor:=crHourglass;DelayTime:=1000;
if Start.Tag=0 then begin
if not EnumPrinters(PRINTER_ENUM_LOCAL,nil,Level,@Info,sizeof(Info),I,Count) then begin
Status.Lines.Add('Can''t enumerate printers!');goto all;end;
if I>sizeof(Info) then begin Status.Lines.Add('Too many printers!');goto all;end;
if Count=0 then begin Status.Lines.Add('No printers in system!');goto all;end;
For I:=1 to Count do Status.Lines.Add(Info[i].pName);
if(not OpenPrinter(Info[1].pName,I,nil))or(I<32)then begin Status.Lines.Add('Error opening printer!');goto all;end;
Count:=FindFirstPrinterChangeNotification(I,PRINTER_CHANGE_SET_JOB,0,nil);
if(Count=INVALID_HANDLE_VALUE)then begin Status.Lines.Add('Failed to notificate printer'+GetSysError);ClosePrinter(I);goto all;end;
try PT:=TPrintThread.Create(I,Count);Start.Tag:=1;Start.Caption:='Stop';PT.Resume;
except Status.Lines.Add('Error during initialization thread!');end;
end else begin
PT.Free;Start.Tag:=0;Start.Caption:='Start';
end;
all:Screen.Cursor:=crDefault;
end;

constructor TPrintThread.Create(aPrinter:THandle;aNot:THandle);
begin
inherited Create(true);
Priority:=tpLowest;OnTerminate:=WhenStop;SetLastError(0);
hPrinter:=aPrinter;hNotification:=aNot;
Msg:='Process executed!';Synchronize(SendStatus);
end;

procedure TPrintThread.Execute;
var Jobs:array[1..MaxJobs]of TJob;
I,Count:DWORD;
begin
while not Terminated do begin
hWait:=WaitForSingleObjectEx(hNotification,10000,true);
if hWait<>WAIT_OBJECT_0 then begin {Msg:=inttostr(hWait);Synchronize(SendStatus);}continue;end;
if not EnumJobs(hPrinter,0,MaxJobs-1,1,@Jobs,sizeof(Jobs),I,Count)then begin
Msg:='Error!';Synchronize(SendStatus);continue;end;
For I:=1 to Count do begin Msg:='Job:'+Jobs[I].pDocument;Synchronize(SendStatus);end;
end;
end;

procedure TPrintThread.SendStatus;
var Buffer:PChar;
I:DWORD;
begin
GetMem(Buffer,1024);
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,nil,GetLastError,0,Buffer,1024,nil);
I:=0;While(Buffer[I]<>#0)and(I<1024)do Inc(I);Buffer[I-1]:=#0;
if GetLastError<>0 then PrintTestForm.Status.Lines.Add(Msg+'. Last error['+inttostr(GetLastError)+']='+Buffer)
else PrintTestForm.Status.Lines.Add(Msg);
SetLastError(0);
FreeMem(Buffer,1024);
end;

procedure TPrintThread.WhenStop(Sender:TObject);
begin
if not FindClosePrinterChangeNotification(hNotification) then begin
Msg:='Can''t close notification';
Synchronize(SendStatus);
end;
ClosePrinter(hPrinter);
Msg:='Process done!';Synchronize(SendStatus);
end;

procedure TPrintTestForm.ClearClick(Sender: TObject);
begin
Status.Lines.Clear;
end;

procedure TPrintTestForm.ExitsClick(Sender: TObject);
begin
Application.Terminate;
end;

procedure TPrintTestForm.FormClose(Sender: TObject;
var Action: TCloseAction);
begin
if Start.Tag<>0 then StartClick(Sender);
end;

constructor TTestThread.Create(aNot:THandle);
begin
Priority:=tpLowest;OnTerminate:=WhenStop;SetLastError(0);hNot:=aNot;
inherited Create(true);
end;

Procedure TTestThread.SendStatus;
begin PrintTestForm.Status.Lines.Add(Msg+GetSysError);end;

procedure TTestThread.WhenStop(Sender:TObject);
begin FindCloseChangeNotification(hNot);hNot:=0;end;

procedure TTestThread.Execute;
begin
while not Terminated do begin
hWait:=WaitForSingleObject(hNot,1000);
if hWait=WAIT_OBJECT_0 then begin
Msg:='Found!';Synchronize(SendStatus);
if not FindNextChangeNotification(hNot)then begin
Msg:='Fuck!';Synchronize(SendStatus);Terminate;
end;
end;
end;
end;

procedure TPrintTestForm.CatchClick(Sender: TObject);
var hNot:THandle;
begin
if Catch.Tag=0 then begin
try
hNot:=FindFirstChangeNotification('C:\EXE',false,FILE_NOTIFY_CHANGE_FILE_NAME);
if hNot=INVALID_HANDLE_VALUE then Exception.Create('Fuflo!');
TT:=TTestThread.Create(hNot);Catch.Tag:=1;Catch.Caption:='Uncatch';TT.Resume;
except Status.Lines.Add('Oblom pri zapuske!');end;
end else begin
TT.Suspend;Catch.Tag:=0;Catch.Caption:='Catch';TT.Free;
end;
end;

end.[/more]
Автор: VovaMozg
Дата сообщения: 09.07.2007 11:07
Ага.. енто на делфи... а на висуал студии нет примера? ужа задолбал да?
попробую в примерах разбраться... пасиба...

Добавлено:
первый пример показывает джоб... а отлавливать как? в таймере?
Автор: SpoinT
Дата сообщения: 09.07.2007 11:22
VovaMozg

Цитата:
а на висуал студии нет примера?

Перепиши

Цитата:
а отлавливать как?

Да как хочешь

Цитата:
в принципе без разницы на чём будет

Я и скинул на делфях, про другое не знаю. если есть код, то его дело времени подправить на нужный тебе. Главное понять суть, что и как, а там до релиза рукой подать
Автор: VovaMozg
Дата сообщения: 09.07.2007 11:27

Цитата:
Главное понять суть, что и как, а там до релиза рукой подать
в принципе-то да... у меня уже готова скуловская абаза, где енто всё будет хораниться... готов локальный портал для просмотра этой базы... оастлось дело за мылы -за прогой, которая будент всё енто складировать... поэтому и хочу на студии... буду пробовать...
Автор: SpoinT
Дата сообщения: 09.07.2007 12:36
VovaMozg
Для чего пишешь? Заказ какой-то или просто для себя?
Автор: VovaMozg
Дата сообщения: 09.07.2007 12:39
Для себя, точнее для организации... покупать начальство не хочет... да и в принципе если можно сделать самим, проще сделать это самим... дело за малым
Автор: VovaMozg
Дата сообщения: 10.07.2007 08:13
SpoinT чё-то я наверное совсем тормоз... RxQuery1 не надо натсраивать? и куда будут выводиться результаты... смотрю пример намбер ту...
Автор: SpoinT
Дата сообщения: 10.07.2007 08:34
Ну ё-моё Ты видишь в примере RxQ...? Нет? Ну так и не нужен тебе. Вывод результатов (мельком глянул) PrintTestForm.Status.Lines.Add(Msg);
Автор: VovaMozg
Дата сообщения: 10.07.2007 09:29
у меня ничего никуда не выводится.. сделал на форме ещё memo1 и везде где
Status.Lines.Add добавил form1.Memo1.Lines.Add и тоже самое... не добавляется ничего... где-то я туплю?
Автор: SpoinT
Дата сообщения: 10.07.2007 09:54
Значит где-то ты накосячил. Там в любом случае, что-то да должно выводиться.

Добавлено:
Эх... Давай разберёмся, как отслеживать задания на принтере программно. Для это существует API функция "EnumJobs", которая позволяет получить давольно много информации о текущем состоянии принтера (Имя задания, Состояние, дату, время и т.д.).

Ниже представлена функция, которая использует EnumJobs и возвращает массив структуры, в котором представлена вся необходимая информация:
uses WinSpool;

type
JOB_INFO_1_ARRAY = array of JOB_INFO_1;

function GetSpoolerJobs(sPrinterName: string): JOB_INFO_1_ARRAY;

var
i: Integer;
hPrinter: THandle;
bResult: Boolean;
cbBuf: DWORD;
pcbNeeded: DWORD;
pcReturned: DWORD;
aJobs: array[0..99] of JOB_INFO_1;
begin
cbBuf := 1000;

bResult := OpenPrinter(PChar(sPrinterName), hPrinter, nil);
if not bResult then
begin
ShowMessage('Error opening the printer');
exit;
end;

bResult := EnumJobs(hPrinter, 0, Length(aJobs), 1, @aJobs, cbBuf, pcbNeeded,
pcReturned);
if not bResult then
begin
ShowMessage('Error Getting Jobs information');
exit;
end;

ClosePrinter(hPrinter);

for i := 0 to pcReturned - 1 do
begin
if aJobs[i].pDocument <> nil then
begin
SetLength(Result, Length(Result) + 1);
Result[Length(Result) - 1] := aJobs[i];
end;
end;
end;



Пример использования:
Создай новый проект со StringGrid и Timer.
В StringGrid установите свойства “ColCount” и “RowCount” в 20.
У таймера (Timer) установите свойство “Interval” в 500.
В обработчик события “OnTime” таймера добавьте следующий код:
procedure TForm1.Timer1Timer(Sender: TObject);
var
i, ii: Integer;
aJobs: JOB_INFO_1_ARRAY;
begin
for i := 0 to StringGrid1.ColCount - 1 do
for ii := 0 to StringGrid1.RowCount - 1 do
StringGrid1.Cells[i, ii] := '';

aJobs := GetSpoolerJobs('HP LaserJet 6L PCL');

for i := 0 to Length(aJobs) - 1 do
begin
StringGrid1.Cells[i, 0] := aJobs[i].pPrinterName;
StringGrid1.Cells[i, 1] := aJobs[i].pMachineName;
StringGrid1.Cells[i, 2] := aJobs[i].pUserName;
StringGrid1.Cells[i, 3] := aJobs[i].pDocument;
StringGrid1.Cells[i, 4] := aJobs[i].pDatatype;
StringGrid1.Cells[i, 5] := aJobs[i].pStatus;
StringGrid1.Cells[i, 6] := IntToStr(aJobs[i].Status);

case aJobs[i].Status of
JOB_STATUS_PAUSED: StringGrid1.Cells[i, 6] := 'JOB_STATUS_PAUSED';
JOB_STATUS_ERROR: StringGrid1.Cells[i, 6] := 'JOB_STATUS_ERROR';
JOB_STATUS_DELETING: StringGrid1.Cells[i, 6] := 'JOB_STATUS_DELETING';
JOB_STATUS_SPOOLING: StringGrid1.Cells[i, 6] := 'JOB_STATUS_SPOOLING';
JOB_STATUS_PRINTING: StringGrid1.Cells[i, 6] := 'JOB_STATUS_PRINTING';
JOB_STATUS_OFFLINE: StringGrid1.Cells[i, 6] := 'JOB_STATUS_OFFLINE';
JOB_STATUS_PAPEROUT: StringGrid1.Cells[i, 6] := 'JOB_STATUS_PAPEROUT';
JOB_STATUS_PRINTED: StringGrid1.Cells[i, 6] := 'JOB_STATUS_PRINTED';
JOB_STATUS_DELETED: StringGrid1.Cells[i, 6] := 'JOB_STATUS_DELETED';
JOB_STATUS_BLOCKED_DEVQ: StringGrid1.Cells[i, 6] :=
'JOB_STATUS_BLOCKED_DEVQ';
JOB_STATUS_USER_INTERVENTION: StringGrid1.Cells[i, 6] :=
'JOB_STATUS_USER_INTERVENTION';
JOB_STATUS_RESTART: StringGrid1.Cells[i, 6] := 'JOB_STATUS_RESTART';
JOB_POSITION_UNSPECIFIED: StringGrid1.Cells[i, 6] :=
'JOB_POSITION_UNSPECIFIED';

else
StringGrid1.Cells[i, 6] := 'Unknown status...';
end;
end;

StringGrid1.Refresh;
end;


Запусти проект и попробуй что-нибудь отправить на печать из MSWord или другого приложения и посмотрите в stringgrid.

Некоторые замечания и дополнения:

Структура JOB_INFO_1 объявлена в юните WinSpool следующим образом:
JOB_INFO_1 = record
JobId: DWORD;
pPrinterName: PAnsiChar;
pMachineName: PAnsiChar;
pUserName: PAnsiChar;
pDocument: PAnsiChar;
pDatatype: PAnsiChar;
pStatus: PAnsiChar;
Status: DWORD;
Priority: DWORD;
Position: DWORD;
TotalPages: DWORD;
PagesPrinted: DWORD;
Submitted: TSystemTime;
end;



И массив так же можно объявить следующим образом:
aJobs: array[0..99] of JOB_INFO_1;

Добавлено:
[more=Ещё один код]BOOL GetJobs(HANDLE hPrinter, /* Дескриптор принтера. */
JOB_INFO_2 **ppJobInfo, /* Указатель который будем заполнять.*/
int *pcJobs, /* Счётчик заданий. */
DWORD *pStatus) /* Состояние очереди печати.*/

{

DWORD cByteNeeded,
nReturned,
cByteUsed;
JOB_INFO_2 *pJobStorage = NULL;
PRINTER_INFO_2 *pPrinterInfo = NULL;

/* Получаем необходимый размер буфера. */
if (!GetPrinter(hPrinter, 2, NULL, 0, &cByteNeeded))
{
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
return FALSE;
}

pPrinterInfo = (PRINTER_INFO_2 *)malloc(cByteNeeded);
if (!(pPrinterInfo))
/* Ошибка выделения памяти. */
return FALSE;

/* Получаем информацию о принтере. */
if (!GetPrinter(hPrinter,
2,
(LPSTR)pPrinterInfo,
cByteNeeded,
&cByteUsed))
{
/* Ошибка доступа к принтеру. */
free(pPrinterInfo);
pPrinterInfo = NULL;
return FALSE;
}

/* Получаем необходимы размер для заданий. */
if (!EnumJobs(hPrinter,
0,
pPrinterInfo->cJobs,
2,
NULL,
0,
(LPDWORD)&cByteNeeded,
(LPDWORD)&nReturned))
{
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
free(pPrinterInfo);
pPrinterInfo = NULL;
return FALSE;
}
}

pJobStorage = (JOB_INFO_2 *)malloc(cByteNeeded);
if (!pJobStorage)
{
/* Ошибка выделения памяти для информации о заданиях. */
free(pPrinterInfo);
pPrinterInfo = NULL;
return FALSE;
}

ZeroMemory(pJobStorage, cByteNeeded);

/* Получаем список заданий. */
if (!EnumJobs(hPrinter,
0,
pPrinterInfo->cJobs,
2,
(LPBYTE)pJobStorage,
cByteNeeded,
(LPDWORD)&cByteUsed,
(LPDWORD)&nReturned))
{
free(pPrinterInfo);
free(pJobStorage);
pJobStorage = NULL;
pPrinterInfo = NULL;
return FALSE;
}

/*
* Возвращаем информацию.
*/
*pcJobs = nReturned;
*pStatus = pPrinterInfo->Status;
*ppJobInfo = pJobStorage;
free(pPrinterInfo);

return TRUE;

}

BOOL IsPrinterError(HANDLE hPrinter)
{

JOB_INFO_2 *pJobs;
int cJobs,
i;
DWORD dwPrinterStatus;

/*
* Получаем информацию о состоянии очереди принтера и
* заданиях в очереди принтера.
*/
if (!GetJobs(hPrinter, &pJobs, &cJobs, &dwPrinterStatus))
return FALSE;

/*
* Если на принтере ошибка, то возвращаем ошибку.
*/
if (dwPrinterStatus &
(PRINTER_STATUS_ERROR |
PRINTER_STATUS_PAPER_JAM |
PRINTER_STATUS_PAPER_OUT |
PRINTER_STATUS_PAPER_PROBLEM |
PRINTER_STATUS_OUTPUT_BIN_FULL |
PRINTER_STATUS_NOT_AVAILABLE |
PRINTER_STATUS_NO_TONER |
PRINTER_STATUS_OUT_OF_MEMORY |
PRINTER_STATUS_OFFLINE |
PRINTER_STATUS_DOOR_OPEN))
{
return TRUE;
}

/*
* Находим задание в очереди, которое печатается.
*/
for (i=0; i < cJobs; i++)
{
if (pJobs[i].Status & JOB_STATUS_PRINTING)
{
/*
* Если задание в состоянии ошибки,
* то возвращаем ошибку.
*/
if (pJobs[i].Status &
(JOB_STATUS_ERROR |
JOB_STATUS_OFFLINE |
JOB_STATUS_PAPEROUT |
JOB_STATUS_BLOCKED_DEVQ))
{
return TRUE;
}
}
}

/*
* Ошибок на принтере нет.
*/
return FALSE;

}[/more]

Добавлено:
Мониторинг принтера
Автор: VovaMozg
Дата сообщения: 10.07.2007 14:41

Цитата:
Мониторинг принтера
находит принтер, токльо почему-то говрит, что мол имя принтера определено не верно... и при печати не показывает...
И в этом примере где StringGrid, тоже говорит Error opening the printer...
А ещё я так понял определяет только физически подключённые принтеры (т.е. не сетевые принтеры)

Чё-то видимо надо делать с руками...
Попробую ещё раз примеры перелопатить...
Автор: SpoinT
Дата сообщения: 10.07.2007 16:03
Не знаю что с тобою делать

http://www.codeproject.com/useritems/wpa.asp
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/prntspol_7mgj.asp

--
Это задача нетривиальная! Достаточно все сложно.
Мой совет, пока с обычным принтером постарайся "подружиться", а потом лезь в сеть.
Автор: VovaMozg
Дата сообщения: 11.07.2007 09:55
Да уж... действительно не тривиальная... к сетевому принтеру я ещё могу подключиться по IP пртоколу... но енто дальше... не могу разобраться почему у меня не отслеживается на той машине, куда физически подключен принтер... Наверное дело ламера боится... исходники целиком как есть вставляю
Автор: SpoinT
Дата сообщения: 11.07.2007 10:08

Цитата:
исходники целиком как есть вставляю

А это зря. Нужно разобраться. Что-то дописать свое, что-то. Ведь у каждого свои нужды, а исходник - это всего лишь пример.
Автор: VovaMozg
Дата сообщения: 11.07.2007 10:19
не, не целиком конечно же, а добавляю необходимые куски и элементы на форму кидаю.... я так понимаю они у меня матерятся что принтер определяется неправильно (т.к. два исхродника на это матерятся)

Добавлено:
SpoinT код намбер два, что ты кидал в начале я уц себя завёл теперь он показыват с принтер (если он физиески подключён) и когда печатаю что-нить показывает приложени, переписывает его кучу раз... ща буду рыть чё да как... но уже что-то сдвинулось с места...
Автор: SpoinT
Дата сообщения: 01.08.2007 13:48
Все получается? В коде, конечно могут быть косяки, я не проверял особо, но думаю разберешься.

Страницы: 1

Предыдущая тема: Альтернатива Internet Explorer object model


Форум Ru-Board.club — поднят 15-09-2016 числа. Цель - сохранить наследие старого Ru-Board, истории становления российского интернета. Сделано для людей.