|
|
{*********************************************************} {* 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. |