VistA-cprs/CPRS-Chart/uEventHooks.pas

617 lines
16 KiB
Plaintext

unit uEventHooks;
interface
uses SysUtils, Classes, Windows, Dialogs, Forms, ComObj, ActiveX,
CPRSChart_TLB, ORNet, ORFn, uCore;
type
TCPRSExtensionData = record
Data1: string;
Data2: string;
end;
procedure RegisterCPRSTypeLibrary;
procedure ProcessPatientChangeEventHook;
function ProcessOrderAcceptEventHook(OrderID: string; DisplayGroup: integer): boolean;
procedure GetCOMObjectText(COMObject: integer; const Param2, Param3: string;
var Data1, Data2: string);
function COMObjectOK(COMObject: integer): boolean;
function COMObjectActive: boolean;
implementation
uses
Trpcb, rEventHooks, VAUtils;
type
ICPRSBrokerInitializer = interface(ICPRSBroker)
procedure Initialize;
end;
TCPRSBroker = class(TAutoIntfObject, ICPRSBrokerInitializer)
private
FContext: string;
FRPCVersion: string;
FClearParameters: boolean;
FClearResults: boolean;
FResults: string;
FParam: TParams;
FEmptyParams: TParams;
public
constructor Create;
destructor Destroy; override;
procedure Initialize;
function SetContext(const Context: WideString): WordBool; safecall;
function Server: WideString; safecall;
function Port: Integer; safecall;
function DebugMode: WordBool; safecall;
function Get_RPCVersion: WideString; safecall;
procedure Set_RPCVersion(const Value: WideString); safecall;
function Get_ClearParameters: WordBool; safecall;
procedure Set_ClearParameters(Value: WordBool); safecall;
function Get_ClearResults: WordBool; safecall;
procedure Set_ClearResults(Value: WordBool); safecall;
procedure CallRPC(const RPCName: WideString); safecall;
function Get_Results: WideString; safecall;
procedure Set_Results(const Value: WideString); safecall;
function Get_Param(Index: Integer): WideString; safecall;
procedure Set_Param(Index: Integer; const Value: WideString); safecall;
function Get_ParamType(Index: Integer): BrokerParamType; safecall;
procedure Set_ParamType(Index: Integer; Value: BrokerParamType); safecall;
function Get_ParamList(Index: Integer; const Node: WideString): WideString; safecall;
procedure Set_ParamList(Index: Integer; const Node: WideString; const Value: WideString); safecall;
function ParamCount: Integer; safecall;
function ParamListCount(Index: Integer): Integer; safecall;
property RPCVersion: WideString read Get_RPCVersion write Set_RPCVersion;
property ClearParameters: WordBool read Get_ClearParameters write Set_ClearParameters;
property ClearResults: WordBool read Get_ClearResults write Set_ClearResults;
property Results: WideString read Get_Results write Set_Results;
property Param[Index: Integer]: WideString read Get_Param write Set_Param;
property ParamType[Index: Integer]: BrokerParamType read Get_ParamType write Set_ParamType;
property ParamList[Index: Integer; const Node: WideString]: WideString read Get_ParamList write Set_ParamList;
end;
TCPRSState = class(TAutoIntfObject, ICPRSState)
private
FHandle: string;
public
constructor Create;
function Handle: WideString; safecall;
function UserDUZ: WideString; safecall;
function UserName: WideString; safecall;
function PatientDFN: WideString; safecall;
function PatientName: WideString; safecall;
function PatientDOB: WideString; safecall;
function PatientSSN: WideString; safecall;
function LocationIEN: Integer; safecall;
function LocationName: WideString; safecall;
end;
TCPRSEventHookManager = class(TObject)
private
FCPRSBroker: ICPRSBrokerInitializer;
FCPRSState: ICPRSState;
FErrors: TStringList;
FLock: TRTLCriticalSection;
public
constructor Create;
destructor Destroy; override;
function ProcessComObject(const GUIDString: string;
const AParam2, AParam3: string;
var Data1, Data2: WideString): boolean;
procedure EnterCriticalSection;
procedure LeaveCriticalSection;
end;
var
uCPRSEventHookManager: TCPRSEventHookManager = nil;
uCOMObjectActive: boolean = False;
procedure EnsureEventHookObjects;
begin
if not assigned(uCPRSEventHookManager) then
uCPRSEventHookManager := TCPRSEventHookManager.Create;
end;
{ TCPRSBroker }
constructor TCPRSBroker.Create;
var
CPRSLib: ITypeLib;
begin
FParam := TParams.Create(nil);
FEmptyParams := TParams.Create(nil);
OleCheck(LoadRegTypeLib(LIBID_CPRSChart, 1, 0, 0, CPRSLib));
inherited Create(CPRSLib, ICPRSBroker);
EnsureBroker;
end;
procedure TCPRSBroker.CallRPC(const RPCName: WideString);
var
err: boolean;
tmpRPCVersion: string;
tmpClearParameters: boolean;
tmpClearResults: boolean;
tmpResults: string;
tmpParam: TParams;
begin
EnsureEventHookObjects;
uCPRSEventHookManager.EnterCriticalSection;
try
err := (FContext = '');
if(not err) then
err := not UpdateContext(FContext);
if (not err) then
err := IsBaseContext;
if err then
raise EOleException.Create('Invalid Broker Context', OLE_E_FIRST, Application.ExeName ,'', 0)
else
begin
if RPCName <> '' then
begin
tmpRPCVersion := RPCBrokerV.RpcVersion;
tmpClearParameters := RPCBrokerV.ClearParameters;
tmpClearResults := RPCBrokerV.ClearResults;
tmpResults := RPCBrokerV.Results.Text;
tmpParam := TParams.Create(nil);
try
RPCBrokerV.RemoteProcedure := RPCName;
RPCBrokerV.RpcVersion := FRPCVersion;
RPCBrokerV.ClearParameters := FClearParameters;
RPCBrokerV.ClearResults := FClearResults;
RPCBrokerV.Param.Assign(FParam);
CallBrokerInContext;
FParam.Assign(RPCBrokerV.Param);
FResults := RPCBrokerV.Results.Text;
finally
RPCBrokerV.RpcVersion := tmpRPCVersion;
RPCBrokerV.ClearParameters := tmpClearParameters;
RPCBrokerV.ClearResults := tmpClearResults;
RPCBrokerV.Results.Text := tmpResults;
RPCBrokerV.Param.Assign(tmpParam);
tmpParam.Free;
end;
end
else
begin
RPCBrokerV.Results.Clear;
FResults := '';
end;
end;
finally
uCPRSEventHookManager.LeaveCriticalSection;
end;
end;
function TCPRSBroker.DebugMode: WordBool;
begin
Result := RPCBrokerV.DebugMode;
end;
function TCPRSBroker.Get_ClearParameters: WordBool;
begin
Result := FClearParameters;
end;
function TCPRSBroker.Get_ClearResults: WordBool;
begin
Result := FClearResults;
end;
function TCPRSBroker.Get_Param(Index: Integer): WideString;
begin
Result := FParam[Index].Value;
end;
function TCPRSBroker.Get_ParamList(Index: Integer;
const Node: WideString): WideString;
begin
Result := FParam[Index].Mult[Node];
end;
function TCPRSBroker.Get_ParamType(Index: Integer): BrokerParamType;
begin
case FParam[Index].PType of
literal: Result := bptLiteral;
reference: Result := bptReference;
list: Result := bptList;
else Result := bptUndefined;
end;
end;
function TCPRSBroker.Get_Results: WideString;
begin
Result := FResults;
end;
function TCPRSBroker.Get_RPCVersion: WideString;
begin
Result := FRPCVersion;
end;
function TCPRSBroker.ParamCount: Integer;
begin
Result := FParam.Count;
end;
function TCPRSBroker.ParamListCount(Index: Integer): Integer;
begin
Result := FParam[Index].Mult.Count;
end;
function TCPRSBroker.Port: Integer;
begin
Result := RPCBrokerV.ListenerPort;
end;
function TCPRSBroker.Server: WideString;
begin
Result := RPCBrokerV.Server;
end;
procedure TCPRSBroker.Set_ClearParameters(Value: WordBool);
begin
FClearParameters := Value;
end;
procedure TCPRSBroker.Set_ClearResults(Value: WordBool);
begin
FClearResults := Value;
end;
procedure TCPRSBroker.Set_Param(Index: Integer; const Value: WideString);
begin
FParam[Index].Value := Value;
end;
procedure TCPRSBroker.Set_ParamList(Index: Integer; const Node,
Value: WideString);
begin
FParam[Index].Mult[Node] := Value;
end;
procedure TCPRSBroker.Set_ParamType(Index: Integer;
Value: BrokerParamType);
begin
case Value of
bptLiteral: FParam[Index].PType := literal;
bptReference: FParam[Index].PType := reference;
bptList: FParam[Index].PType := list;
else FParam[Index].PType := undefined;
end;
end;
procedure TCPRSBroker.Set_Results(const Value: WideString);
begin
FResults := Value;
end;
procedure TCPRSBroker.Set_RPCVersion(const Value: WideString);
begin
FRPCVersion := Value;
end;
function TCPRSBroker.SetContext(const Context: WideString): WordBool;
begin
FContext := Context;
Result := UpdateContext(FContext);
end;
procedure TCPRSBroker.Initialize;
begin
FContext := '';
FRPCVersion := RPCBrokerV.RpcVersion;
FClearParameters := RPCBrokerV.ClearParameters;
FClearResults := RPCBrokerV.ClearResults;
FResults := '';
FParam.Assign(FEmptyParams);
end;
destructor TCPRSBroker.Destroy;
begin
FParam.Free;
FEmptyParams.Free;
inherited;
end;
{ TCPRSState }
constructor TCPRSState.Create;
var
CPRSLib: ITypeLib;
begin
OleCheck(LoadRegTypeLib(LIBID_CPRSChart, 1, 0, 0, CPRSLib));
inherited Create(CPRSLib, ICPRSState);
FHandle := DottedIPStr + 'x' + IntToHex(Application.Handle,8);
end;
function TCPRSState.Handle: WideString;
begin
Result := FHandle;
end;
function TCPRSState.LocationIEN: Integer;
begin
Result := Encounter.Location;
end;
function TCPRSState.LocationName: WideString;
begin
Result := Encounter.LocationName;
end;
function TCPRSState.PatientDFN: WideString;
begin
Result := Patient.DFN;
end;
function TCPRSState.PatientDOB: WideString;
begin
Result := FormatFMDateTime('mm/dd/yyyy', Patient.DOB);
end;
function TCPRSState.PatientName: WideString;
begin
Result := Patient.Name;
end;
function TCPRSState.PatientSSN: WideString;
begin
Result := Patient.SSN;
end;
function TCPRSState.UserDUZ: WideString;
begin
Result := IntToStr(User.DUZ);
end;
function TCPRSState.UserName: WideString;
begin
Result := User.Name;
end;
{ TCPRSEventHookManager }
constructor TCPRSEventHookManager.Create;
begin
inherited;
FCPRSBroker := TCPRSBroker.Create;
FCPRSState := TCPRSState.Create;
end;
destructor TCPRSEventHookManager.Destroy;
begin
FCPRSState := nil;
FCPRSBroker := nil;
if assigned(FErrors) then
FErrors.Free;
inherited;
end;
procedure TCPRSEventHookManager.EnterCriticalSection;
begin
Windows.EnterCriticalSection(FLock);
end;
procedure TCPRSEventHookManager.LeaveCriticalSection;
begin
Windows.LeaveCriticalSection(FLock);
end;
function TCPRSEventHookManager.ProcessComObject(const GUIDString: string;
const AParam2, AParam3: string;
var Data1, Data2: WideString): boolean;
var
ObjIEN, ObjName, ObjGUIDStr, err, AParam1: string;
ObjGUID: TGUID;
ObjIntf: IUnknown;
Obj: ICPRSExtension;
begin
Result := FALSE;
ObjIEN := Piece(GUIDString,U,1);
if assigned(FErrors) and (FErrors.IndexOf(ObjIEN) >= 0) then exit;
ObjName := Piece(GUIDString,U,2);
ObjGUIDStr := Piece(GUIDString,U,3);
if (ObjGUIDStr <> '') then
begin
try
ObjGUID := StringToGUID(ObjGUIDStr);
try
ObjIntf := CreateComObject(ObjGUID);
if assigned(ObjIntf) then
begin
try
ObjIntf.QueryInterface(IID_ICPRSExtension, Obj);
if assigned(Obj) then
begin
AParam1 := Piece(GUIDString,U,5);
InitializeCriticalSection(FLock);
try
FCPRSBroker.Initialize;
uCOMObjectActive := True;
Result := Obj.Execute(FCPRSBroker, FCPRSState,
AParam1, AParam2, AParam3, Data1, Data2);
finally
DeleteCriticalSection(FLock);
uCOMObjectActive := False;
end;
end
else
err := 'COM Object ' + ObjName + ' does not support ICPRSExtension';
except
err := 'Error executing ' + ObjName;
end;
end;
except
err := 'COM Object ' + ObjName + ' not found on this workstation.';
end;
except
err := 'COM Object ' + ObjName + ' has an invalid GUID' + CRLF + ObjGUIDStr;
end;
if err <> '' then
begin
if not assigned(FErrors) then
FErrors := TStringList.Create;
if FErrors.IndexOf(ObjIEN) < 0 then
FErrors.Add(ObjIEN);
ShowMsg(err);
end;
end;
end;
procedure FreeEventHookObjects;
begin
FreeAndNil(uCPRSEventHookManager);
end;
// External Calls
procedure RegisterCPRSTypeLibrary;
type
TUnregisterProc = function(const GUID: TGUID; VerMajor, VerMinor: Word;
LCID: TLCID; SysKind: TSysKind): HResult stdcall;
var
Unregister: boolean;
CPRSLib: ITypeLib;
DoHalt: boolean;
ModuleName: string;
HelpPath: WideString;
Buffer: array[0..261] of Char;
Handle: THandle;
UnregisterProc: TUnregisterProc;
LibAttr: PTLibAttr;
begin
DoHalt := TRUE;
if FindCmdLineSwitch('UNREGSERVER', ['-', '/'], True) then
Unregister := TRUE
else
begin
Unregister := FALSE;
if not FindCmdLineSwitch('REGSERVER', ['-', '/'], True) then
DoHalt := FALSE;
end;
try
SetString(ModuleName, Buffer, Windows.GetModuleFileName(HInstance, Buffer, SizeOf(Buffer)));
if ModuleName <> '' then
begin
OleCheck(LoadTypeLib(PWideChar(WideString(ModuleName)), CPRSLib)); // will register if needed
if assigned(CPRSLib) then
begin
if Unregister then
begin
Handle := GetModuleHandle('OLEAUT32.DLL');
if Handle <> 0 then
begin
@UnregisterProc := GetProcAddress(Handle, 'UnRegisterTypeLib');
if @UnregisterProc <> nil then
begin
OleCheck(CPRSLib.GetLibAttr(LibAttr));
try
with LibAttr^ do
UnregisterProc(guid, wMajorVerNum, wMinorVerNum, lcid, syskind);
finally
CPRSLib.ReleaseTLibAttr(LibAttr);
end;
end;
end;
end
else
begin
HelpPath := ExtractFilePath(ModuleName);
OleCheck(RegisterTypeLib(CPRSLib, PWideChar(WideString(ModuleName)), PWideChar(HelpPath)));
end;
end;
end;
except
// ignore any errors
end;
if DoHalt then Halt;
end;
procedure ProcessPatientChangeEventHook;
var
d1, d2: WideString;
COMObj: string;
begin
COMObj := GetPatientChangeGUIDs;
if(COMObj <> '') and (COMObj <> '0') then
begin
EnsureEventHookObjects;
d1 := '';
d2 := '';
uCPRSEventHookManager.ProcessComObject(COMObj, 'P=' + Patient.DFN, '', d1, d2);
end;
end;
function ProcessOrderAcceptEventHook(OrderID: string; DisplayGroup: integer): boolean;
var
d1, d2: WideString;
COMObj: string;
begin
Result := False;
COMObj := GetOrderAcceptGUIDs(DisplayGroup);
if(COMObj <> '') and (COMObj <> '0') then
begin
EnsureEventHookObjects;
d1 := '';
d2 := '';
//Result will be set to True by Com object if the order is deleted by LES
Result := uCPRSEventHookManager.ProcessComObject(COMObj, 'O=' + OrderID, '', d1, d2);
end;
end;
procedure GetCOMObjectText(COMObject: integer; const Param2, Param3: string;
var Data1, Data2: string);
var
d1, d2: WideString;
COMObj: string;
begin
if COMObject > 0 then
begin
COMObj := GetCOMObjectDetails(COMObject);
if(COMObj <> '') and (COMObj <> '0') then
begin
EnsureEventHookObjects;
d1 := Data1;
d2 := Data2;
if uCPRSEventHookManager.ProcessComObject(COMObj, Param2, Param3, d1, d2) then
begin
Data1 := d1;
Data2 := d2;
end;
end;
end;
end;
function COMObjectOK(COMObject: integer): boolean;
begin
if assigned(uCPRSEventHookManager) and assigned(uCPRSEventHookManager.FErrors) then
Result := (uCPRSEventHookManager.FErrors.IndexOf(IntToStr(COMObject)) < 0)
else
Result := TRUE;
end;
function COMObjectActive: boolean;
begin
Result := uCOMObjectActive;
end;
initialization
finalization
FreeEventHookObjects;
end.