|
|
|
{*********************************************************}
{* HDTPRTCTL.PAS 1.00 *}
{* Copyright (c) Halkyon Development Team 1999 *}
{* All rights reserved. *}
{*********************************************************}
{Global defines potentially affecting this unit}
{$I HKPRNDEF.INC} // <- click here to open in browser
{Options required for this unit}
{$T-}
unit HdtPrtCtl;
{- Controller component for printer drivers.}
interface
uses
WinTypes,
WinProcs,
Messages,
SysUtils,
Classes,
Graphics,
Controls,
Forms,
Dialogs,
HDTCC; // <- click here to open in browser
type
THdtPrtDriverInterface = class;
{$IFDEF Win32}
{Thread for monitoring messages from the NT driver}
TMonitorThread = class(TThread)
Owner : THdtPrtDriverInterface; {Link to component}
Pipe : THandle; {Connection with driver}
Overlapped : TOverlapped; {Used to control overlapped i/o}
Semaphore : THandle; {Used for sync. with driver}
Events : array[0..1] of THandle;
// Stop & Overlapped finished - array used for WaitForMultiple...
procedure Execute; override;
end;
{$ENDIF Win32}
THdtPrtDriverInterface = class(TComponent)
private
fPaperIEvent,
fFileName,
fDocName : string;
fOnDocStart,
fOnInsertPaper,
fOnPrinterError,
fOnDocEnd : TNotifyEvent;
{$IFDEF Win32}
MonitorThread : TMonitorThread;
SecDesc : TSecurityDescriptor;
SecAttr : TSecurityAttributes;
{$ENDIF Win32}
FWindowHandle : HWND;
protected
procedure WndProc(var Msg: TMessage);
procedure NotifyStartDoc; virtual;
procedure NotifyInsertPaper; virtual;
procedure NotifyPrinterError; virtual;
procedure NotifyEndDoc; virtual;
public
constructor Create(AOwner : TComponent); override;
destructor Destroy; override;
property DocName : string read fDocName;
published
property PaperIEvent : string read fPaperIEvent write fPaperIEvent;
property FileName : string read fFileName write fFileName;
property OnDocStart: TNotifyEvent read fOnDocStart write fOnDocStart;
property OnInsertPaper: TNotifyEvent read fOnInsertPaper write fOnInsertPaper;
property OnPrinterError: TNotifyEvent read fOnPrinterError write fOnPrinterError;
property OnDocEnd: TNotifyEvent read fOnDocEnd write fOnDocEnd;
end;
procedure Register;
implementation
{$IFDEF Win32}
procedure TMonitorThread.Execute;
{- Monitor thread. Looks for "events" coming through the pipe from the driver.}
var
Wait, BytesRead, BytesWritten : DWord;
InBuffer,OutBuffer : TPipeEvent;
Res : Bool;
begin
repeat
fillchar(Overlapped,sizeof(Overlapped),0);
Overlapped.hEvent := Events[1];
ResetEvent(Events[1]);
ConnectNamedPipe(Pipe, @Overlapped); // wait for driver to send something
if GetLastError = ERROR_IO_PENDING then begin
Wait := WaitForMultipleObjects(2, @Events, FALSE, INFINITE);
if Wait <> WAIT_OBJECT_0+1 then // not overlapped i/o event - error occurred,
break; // or stop signaled
end;
fillchar(Overlapped,sizeof(Overlapped),0);
Overlapped.hEvent := Events[1];
ResetEvent(Events[1]);
Res := ReadFile(
Pipe,
InBuffer,
sizeof(InBuffer),
BytesRead,
@Overlapped);
if not Res and (GetLastError = ERROR_IO_PENDING) then
begin
Wait := WaitForMultipleObjects(2, @Events, False, Infinite);
if Wait <> WAIT_OBJECT_0+1 then // not overlapped i/o event - error occurred,
Break; // or stop signaled
GetOverlappedResult(Pipe,Overlapped,BytesRead,False);
end;
if BytesRead > 0 then begin
case InBuffer.Event of
eNull : ;
eStartDoc :
begin
Owner.fDocName := InBuffer.Data;
Synchronize(Owner.NotifyStartDoc);
end;
eEndDoc :
begin
Synchronize(Owner.NotifyEndDoc);
end;
eInsertPaper :
begin
Owner.fPaperIEvent := InBuffer.Data;
Synchronize(Owner.NotifyInsertPaper);
end;
ePrinterErr :
begin
Synchronize(Owner.NotifyPrinterError);
end;
else
raise Exception.CreateFmt('Unknown incoming event encountered:%d',[InBuffer.Event]);
end;
case InBuffer.Event of
eStartDoc, eInsertPaper :
begin
fillchar(Overlapped,sizeof(Overlapped),0);
Overlapped.hEvent := Events[1];
ResetEvent(Events[1]);
OutBuffer.Event := eSetFileName;
if InBuffer.Event = eInsertPaper then
OutBuffer.Data := Owner.PaperIEvent
else
OutBuffer.Data := Owner.FileName;
Res := WriteFile(
Pipe,
OutBuffer,
sizeof(OutBuffer),
BytesWritten,
@Overlapped);
if not Res and (GetLastError() = ERROR_IO_PENDING) then begin
Wait := WaitForMultipleObjects(2, @Events, FALSE, INFINITE);
if Wait <> WAIT_OBJECT_0+1 then // not overlapped i/o event - error occurred,
Break; // or stop signaled
end;
end;
end;
end;
DisconnectNamedPipe(Pipe);
until false;
Suspend;
end;
function IsWinNT : Boolean;
{- Are we running under Windows NT}
var
Osi : TOSVersionInfo;
begin
Osi.dwOSVersionInfoSize := sizeof(Osi);
GetVersionEx(Osi);
Result := (Osi.dwPlatformID = Ver_Platform_Win32_NT);
end;
{$ENDIF Win32}
constructor THdtPrtDriverInterface.Create;
begin
inherited Create(AOwner);
fPaperIEvent := '0';
fFileName := DefFileName;
fDocName := '';
if csDesigning in ComponentState then exit;
{$IFDEF Win32}
if IsWinNT then
begin {32-bit (NT) driver communicates via a named pipe}
MonitorThread := TMonitorThread.Create(True); // Suspended
try
MonitorThread.Owner := Self;
with MonitorThread do begin
{Create security descriptor for pipe}
if not InitializeSecurityDescriptor(@SecDesc, 1) then
raise Exception.Create('Unable to initialize security descriptor');
if not SetSecurityDescriptorDacl(@SecDesc, True, nil, False) then
raise Exception.Create('Unable to set security DACL');
{Create security attributes record for the pipe}
SecAttr.nLength := sizeof(SecAttr);
SecAttr.lpSecurityDescriptor := @SecDesc;
SecAttr.bInheritHandle := True;
{Create pipe that the driver can communicate through}
Pipe := INVALID_HANDLE_VALUE;
Pipe := CreateNamedPipe(
PipeName,
FILE_FLAG_OVERLAPPED or
PIPE_ACCESS_DUPLEX, // pipe open mode
PIPE_TYPE_MESSAGE or
PIPE_READMODE_MESSAGE or
PIPE_WAIT, // pipe IO type
1, // number of instances
sizeof(TPipeEvent), // size of outbuf (0 = allocate as necessary)
sizeof(TPipeEvent), // size of inbuf
PipeTimeout, // default time-out value
@SecAttr); // security attributes
if (Pipe = INVALID_HANDLE_VALUE) or (Pipe = 0) then
raise Exception.CreateFmt('Unable to create named pipe. Error:%d',[GetLastError]);
try
{Create events to signal Overlapped i/o and Stop.}
Events[0] := CreateEvent(nil,true,False,nil);
if Events[0] = 0 then
raise Exception.Create('Unable to create event');
try
Events[1] := CreateEvent(nil,true,False,nil);
if Events[1] = 0 then
raise Exception.Create('Unable to create event');
try
{Start monitor thread}
Resume;
{Check if we were started by driver}
Semaphore := OpenSemaphore(EVENT_ALL_ACCESS, False, SemaphoreName);
if Semaphore <> 0 then
begin
if not ReleaseSemaphore(Semaphore, 1, nil) then //tell driver to continue
raise Exception.Create('Unable to release semaphore');
end
else {No, so...}
{Block driver from auto-starting another instance of us}
Semaphore := CreateSemaphore(nil, 0, 1, SemaphoreName);
except
CloseHandle(Events[1]);
raise;
end;
except
CloseHandle(Events[0]);
raise;
end;
except
CloseHandle(MonitorThread.Pipe);
raise;
end;
end;
except
raise;
end;
end
else
{$ENDIF Win32}
begin {16-bit driver communicates via messages}
FWindowHandle := AllocateHWnd(WndProc);
if FWindowHandle = 0 then
raise Exception.Create('Unable to create "pipe" window');
SetWindowText(FWindowHandle,PipeName);
end;
end;
destructor THdtPrtDriverInterface.Destroy;
begin
fPaperIEvent := '';
fFileName := '';
fDocName := '';
if not (csDesigning in ComponentState) then begin
{$IFDEF Win32}
if IsWinNT then
with MonitorThread do begin
if not Suspended then begin
SetEvent(Events[0]); // tell monitor thread to terminate
while not Suspended do; // wait for it to do so before we pull the carpet
end;
CloseHandle(Events[0]);
CloseHandle(Events[1]);
CloseHandle(MonitorThread.Pipe);
if Semaphore <> 0 then
CloseHandle(Semaphore);
Free;
end
else
{$ENDIF Win32}
DeallocateHWnd(FWindowHandle);
end;
inherited Destroy;
end;
procedure THdtPrtDriverInterface.NotifyStartDoc;
begin
if Assigned(fOnDocStart) then
fOnDocStart(Self);
end;
procedure THdtPrtDriverInterface.NotifyInsertPaper;
begin
if Assigned(fOnInsertPaper) then
fOnInsertPaper(Self);
end;
procedure THdtPrtDriverInterface.NotifyPrinterError;
begin
if Assigned(fOnPrinterError) then
fOnPrinterError(Self);
end;
procedure THdtPrtDriverInterface.NotifyEndDoc;
begin
if Assigned(fOnDocEnd) then
fOnDocEnd(Self);
end;
procedure THdtPrtDriverInterface.WndProc(var Msg: TMessage);
{- Window procedure for the 16-bit driver comm. window}
var
JobNameBuffer : array[0..255] of char;
begin
with Msg do
if Msg = hdt_BeginDoc then
try
GetWindowText(FWindowHandle,JobNameBuffer,sizeof(JobNameBuffer));
fDocName := StrPas(JobNameBuffer);
NotifyStartDoc;
fFileName[length(fFileName)+1] := #0;
SetWindowText(FWindowHandle,@fFileName[1]);
except
Application.HandleException(Self);
end
else
if Msg = hdt_EndDoc then
try
NotifyEndDoc;
except
Application.HandleException(Self);
end
else
if Msg = hdt_InsPaper then
try
fPaperIEvent := '0';
NotifyInsertPaper;
fPaperIEvent[length(fPaperIEvent)+1] := #0;
SetWindowText(FWindowHandle,@fPaperIEvent[1]);
except
Application.HandleException(Self);
end
else
if Msg = hdt_PrtError then
try
NotifyPrinterError;
except
Application.HandleException(Self);
end
else
Result := DefWindowProc(FWindowHandle, Msg, wParam, lParam);
end;
procedure Register;
begin
RegisterComponents('Halkyon', [THdtPrtDriverInterface]);
end;
end.
Back
|
|
About - Business - Experience
- Projects Copyright © 2001 Halkyon Development Team Ltd. |