VistA-cprs/CPRS-Lib/sqasrvr.pas

1703 lines
68 KiB
Plaintext

{*************************************************************************
*
* Copyright 2000 - 2004 Rational Software Corporation. All Rights Reserved.
* This software contains proprietary and confidential information of Rational
* and its suppliers. Use, disclosure or reproduction is prohibited
* without the prior express written consent of Rational.
*
* Name: sqasrvr.pas
* Description:
*
* Revision History:
* Programmer Date Description
* sraj 05/18/2004 Fixed Delphi 5 compilation issues.
* sraj 07/25/2003 Supported TTreeView items collection in properties.
* sraj 07/25/2003 Supported TStringGrid object data.
* sraj 24/04/2003 RATLC00447073: Included FindControl1() to lookup delphi object
* given a window handle effectively.
* sraj 10/03/2002 RATLC00436896, RATLC00052492 : Included BeautifyApplicationWindow
* sraj 06/23/2003 RATLC00449186 : Exception trace enabled using a Registry key.
* sraj 10/03/2002 RATLC00436896, RATLC00052492 : Included BeautifyApplicationWindow
* to make application object available as a window property.
* Removed the call RegisterAutomationServer() from unit Initialization.
* PBeaulieu 01/08/2002 Changed TPublishedAutoDispatch.NewDispatch to set the found
* flag if found in first case to bypass the second search method.
* PBeaulieu 08/20/2001 Changed TIObjectDispatch.GetProperty inorder to make
* sure that Unassigned Variant or incorrect Variant type
* would not be used in retrieving a property. Changed
* TPublishedAutoDispatch.NewDispatch to search manually the
* inheritance hierarchy if InheritsFrom fails. This allows
* for objects that the InheritsFrom function fails on
* seemingly because it cannot access the information with
* the functions it is using. This seemed to happen with
* MDI app where the MDI children were created from another
* dll that encapsulated the form in another object.
* PBeaulieu 06/26/01 Merged in Pete Ness's changes to fix some warnings and
* to add some logging for exceptions. Also, added the function
* TIObjectDispatch.ParentClassName.
* PMNess 05/16/01 Changed the "Classname" calls in TPublishedAutoDispatch
* to FObject.Classname - as Classname was always
* returning TPublishedAutoDispatch instead of
* the actual invoked class.
* PMNess 05/15/01 Updated and removed hints/warnings under D5
* Added try/excepts around all automated calls
* to trap exceptions that may happen and log to
* file.
* KPATEL 05/25/00 Replaced the function 'VarAsType' with
* 'VarToStr' as Delphi 5 takes only string as
* the third parameter in SetStrProp function.
* SJPak 03/31/98 Modified TIObjectDispatch.GetEnumList to
* return empty variant when the total length of
* the strings for enumerated choices exceed
* 2047. This is to keep Robot from crashing
* Robot cannot handle more 2048 characters total.
* SJPak 04/02/97 Modified TPublishedAutoDispatch.Invoke to
* support TColor type properties.
* SJPak 08/04/96 Added additional interface TIStringGridDispatch
* to support Cols and Rows properties of TStringGrid.
* SJPak 03/06/97 Modified TICollectionDispatch.GetPropNames
* and TICollectionDispatch.GetProperty to support
* Items property.
* SJPak 11/21/96 Replacing calls to OLECheck which
* will raise an exception when return value
* is less than 0. Raising an exception
* will cause a messagebox to pop up when ran
* from Delphi IDE.
* SJPak 11/15/96 Fixed a memory leak in
* TIObjectDispatch.SetProperty
* SJPak 11/11/96 Modified TIStringsDispatch.GetProperty
* to check for empty "Strings" property.
* SJPak 11/07/96 Removed calls to OleError to prevent
* error messages being displayed during
* Rec/Plaback session through IDE.
* SJPak 10/07/96 Modified TIStringsDispatch to support
* Strings property of TStrings object.
* SJPak 09/19/96 Changed CLSID of the server.
* SJPak 08/04/96 Added additional interface TIOleControlDispatch
* to support OCXs.
* SJPak 08/01/96 Modified TPublishedAutoDispatch.Invoke
* to return tkSet type properties as
* a safe array of Variants containing
* names of all possible items in the set
* and booleans representing whether the items
* are in the particular set.
* SJPak 07/31/96 Fixed Borland's bug in
* TPublishedAutoDispatch.Invoke function's
* handling of min and max values of
* tkSet properties.
* SJPak 07/18/96 Changed Unit name to SQASrvr
* SJPak 07/18/96 Added addtional interface TIStringsDispatch
* to support TStrings class.
* SJPak 07/18/96 Added GetPropNames and GetProeprty to
* TICollectionDispatch.
* SJPak 07/18/96 Added GetPropNames method to TIObjectDispatch
* interface.
* SJPak 07/08/96 Added SetProperty method to TIObjectDispatch
* interface.
* SJPak 07/08/96 Additional interface define for
* DatSet Objects.
* SJPak 07/01/96 Fixed a bug in TPublishedAutoDispatch.Invoke
* SJPak 07/01/96 Additional interface defined for
* collections.
* SJPak 07/01/96 Original From Delphi.
*
**************************************************************************}
unit SQASrvr;
interface
uses
Windows,
{$IFDEF VER140}
Variants,
{$ENDIF}
{$IFDEF VER150}
Variants,
{$ELSE} //Added for Delphi 2006
Variants, //Added for Delphi 2006
{$ENDIF}
OleAuto,
OLE2, TypInfo, DB, DBTables, OleCtrls, Grids, Controls, Registry, ComCtrls;
const
AutoClassExistsMsg = 'Automation enabler for class %s is already registered';
{ FirstComponentIndex needs to be high enough so that it doesn't conflict with
the DispIDs of the TAutoObject. The "automated" properties and methods have
DispIDs starting with 1 in the base object and incrementing by one from
there. }
FirstComponentIndex = $000000FF;
LastComponentIndex = $0000FFFE;
FirstPropIndex = $0000FFFF;
LastPropIndex = $7FFFFFFF; { maxint }
// Arbitrary Max for each element of TStrings.Strings property.
MaxStringItem = 32000;
type
{ SJP Todo: This limits the set range from 0 - 15.
According to Doc. Set can have upto 256 elements }
TCardinalSet = set of 0..SizeOf(Cardinal) * 8 - 1;
// TCardinalSet = set of 0..255;
{ TPublishedAutoDispatch }
TPublishedAutoDispatch = class(TAutoDispatch)
private
FObject: TObject;
public
constructor Create(AutoObject: TAutoObject; BoundObj: TObject);
procedure NewDispatch(var V: Variant; Obj: TObject);
function GetIDsOfNames(const iid: TIID; rgszNames: POleStrList;
cNames: Integer; lcid: TLCID; rgdispid: PDispIDList): HResult; override;
function Invoke(dispIDMember: TDispID; const iid: TIID; lcid: TLCID;
flags: Word; var dispParams: TDispParams; varResult: PVariant;
excepInfo: PExcepInfo; argErr: PInteger): HResult; override;
end;
{ TIObjectDispatch }
TIObjectDispatch = class(TAutoObject)
private
procedure GetProps(var v: Variant; TypeKinds: TTypeKinds);
protected
FObject: TObject;
function CreateAutoDispatch: TAutoDispatch; override;
// 5/16/2001 - PMNess - Added new GetExceptionInfo to log any
// exception on the invoke to a log file. This works generically when anything
// is called...
procedure GetExceptionInfo(ExceptObject: TObject;
var ExcepInfo: TExcepInfo); override;
public
constructor Connect(Obj: TObject); virtual;
automated
function ClassName: String;
function GetProperty(PropName: String): Variant;
function GetObject(ObjName: String): Variant;
procedure GetEnumList(PropName: String; var v: Variant);
procedure GetProperties(var v: Variant);
procedure GetObjects(var v: Variant);
function InheritsFrom(AClass: String): WordBool;
// SJP: 07/09/96 Added SetProperty.
function SetProperty(PropName: String; var v: Variant): WordBool;
// SJP: 07/18/96 Added SetProperty.
procedure GetPropNames(var v: Variant);
//PBeaulieu: 05/22/2001 Added ParentClassName
function ParentClassName: String;
end;
{ TIComponentDispatch }
TIComponentDispatch = class(TIObjectDispatch)
private
function GetComponents(Index: Integer): Variant;
function GetComponentCount: Integer;
function GetComponentIndex: Integer;
function GetOwner: Variant;
protected // 5-16-2001 - Added protected to get rid of hint on GetDesignInfo
function GetDesignInfo: LongInt;
automated
property Components[Index: Integer]: Variant read GetComponents;
property ComponentCount: Integer read GetComponentCount;
property ComponentIndex: Integer read GetComponentIndex;
property Owner: Variant read GetOwner;
function FindComponent(AName: String): Variant;
end;
{ TIControlDispatch }
TIControlDispatch = class(TIComponentDispatch)
private
function GetParent: Variant;
automated
property Parent: Variant read GetParent;
end;
{ TIWinControlDispatch }
TIWinControlDispatch = class(TIControlDispatch)
private
function GetHandle: Integer;
function GetControls(Index: Integer): Variant;
function GetControlCount: Integer;
automated
property Handle: Integer read GetHandle;
property Controls[Index: Integer]: Variant read GetControls;
property ControlCount: Integer read GetControlCount;
function ControlAtPos(X, Y: Integer): Variant;
end;
{ TIApplicationDispatch }
TIApplicationDispatch = class(TIComponentDispatch)
private
function GetHandle: Integer;
function GetMainForm: Variant;
function GetExeName: String;
function FindControl1(hWndToFind: HWnd): TWinControl;
public
constructor Create; override;
automated
property Handle: Integer read GetHandle;
property MainForm: Variant read GetMainForm;
property ExeName: String read GetExeName;
function GetDispFromHandle(Handle: Integer): Variant;
end;
// SJP 07/01/96 Additional interface defined for collections
{ TICollectionDispatch }
TICollectionDispatch = class(TIObjectDispatch)
private
function GetItemCount: Integer;
automated
property ItemCount: Integer read GetItemCount;
procedure GetPropNames(var v: Variant);
function GetProperty(PropName: String): Variant;
end;
// SJP 07/08/96 Additional interface defined for 'dataset' objects.
{ TIDataSetDispatch }
TIDataSetDispatch = class(TIObjectDispatch)
private
function GetFieldCount: Integer;
automated
property FieldCount: Integer read GetFieldCount;
function GetData: String;
end;
// SJP 07/18/96 Additional interface defined for TStrings Objects
{ TIStringsDispatch }
TIStringsDispatch = class(TIObjectDispatch)
automated
function GetProperty(PropName: String): Variant;
procedure GetPropNames(var v: Variant);
end;
// SJP 08/03/96 Addition interface defined for TOleControl(OCX) Component
TIOleControlDispatch = class(TIWinControlDispatch)
private
function GetOleObject: Variant;
automated
property OleObject: Variant read GetOleObject;
end;
// SJP 03/10/97 Addition interface defined for TStringGrid Component
TIStringGridDispatch = class(TIWinControlDispatch)
automated
function GetProperty(PropName: String): Variant;
procedure GetPropNames(var v: Variant);
function GetData: String;
end;
// Addition interface defined for TTreeView Component
TITreeViewDispatch = class(TIWinControlDispatch)
automated
function GetProperty(PropName: String): Variant;
procedure GetPropNames(var v: Variant);
end;
{ Support functions}
TIObjectDispatchRef = class of TIObjectDispatch;
PClassMapRecord = ^TClassMapRecord;
TClassMapRecord = record
ObjectClass: TClass;
DispClass: TIObjectDispatchRef;
end;
procedure FreeClassLists;
procedure RegisterAutomationEnabler( ObjectClass: TClass;
DispClass: TIObjectDispatchRef);
implementation
uses Forms, Classes, SysUtils;
var
ClassMap: TList = nil;
// Called when any exception is raised from this COM object. Logs the
// error to a log file.
procedure WriteToLog(ErrorMsg: String);
var
LogFile: TextFile;
LogFileName: String;
begin // AddToErrorLog
try
LogFileName := ExtractFilePath(ParamStr(0))+'\Robot Errors for '+ExtractFileName(ParamStr(0))+'.log';
AssignFile(LogFile, LogFileName);
if (FileExists(LogFileName))
then Append(LogFile)
else Rewrite(LogFile);
try
Writeln(LogFile, DateTimeToStr(Now)+' '+ErrorMsg);
finally
CloseFile(LogFile);
end;
except
// Supress this - as we're likely in some kind of error log already!
end;
end;
function IsExceptionTraceEnabled( ) : Boolean;
var
Reg: TRegistry;
deTrace: string;
begin
Result := False;
Reg := TRegistry.Create;
try
Reg.RootKey := HKEY_CURRENT_USER;
if Reg.OpenKey('Software\Rational Software\Rational Test\8\Robot', False) then
begin
deTrace := Reg.ReadString( 'DelphiExceptionTrace' );
if ( (deTrace = '1') or ( LowerCase(deTrace) = 'true' ) ) then
begin
Result := True;
end;
Reg.CloseKey;
end;
finally
Reg.Free;
end;
end;
{ Exit procedure used to free memory used by the ClassList }
procedure FreeClassLists;
var
I: Integer;
begin
for I := 0 to ClassMap.Count-1 do
Dispose(PClassMapRecord(ClassMap[I]));
ClassMap.Free;
end;
{ This is called in the initialization section of a unit for all new
automation objects. It associates an AutoObject with a VCL class. }
procedure RegisterAutomationEnabler(ObjectClass: TClass;
DispClass: TIObjectDispatchRef);
var
P: PClassMapRecord;
X: Integer;
Found: Boolean;
begin
if not Assigned(ClassMap) then
begin
AddExitProc(FreeClassLists);
ClassMap := TList.Create;
end;
Found := False;
for X := 0 to ClassMap.Count-1 do
begin
P := PClassMapRecord(ClassMap[x]);
if ObjectClass.InheritsFrom(P^.ObjectClass) then
if ObjectClass = P^.ObjectClass then
raise Exception.CreateFmt(AutoClassExistsMsg,[ObjectClass.ClassName])
else
begin
Found := True;
break;
end;
end;
New(P);
P^.ObjectClass := ObjectClass;
P^.DispClass := DispClass;
if Found then
{ ObjectClass is a descendent of P^.ObjectClass, so insert the descendent
into the class list in front of the ancestor. }
ClassMap.Insert(X,P)
else
{ ObjectClass is not related to any classes already in the list, so just add
it to the end of the list. }
ClassMap.Add(P);
end;
{ TPublishedAutoDispatch }
constructor TPublishedAutoDispatch.Create(AutoObject: TAutoObject; BoundObj: TObject);
begin
inherited Create(AutoObject);
FObject := BoundObj;
end;
{ NewDispatch is called to create an AutoObject bound to a VCL object.
Example: when the controller calls Application.MainForm.Button1.Caption,
NewDispatch would be called to return the dispatches for MainForm and
Button1. Not called directly by the controller. }
procedure TPublishedAutoDispatch.NewDispatch(var V: Variant; Obj: TObject);
var
i: Integer;
P: PClassMapRecord;
Found: Boolean;
Cls: TClass;
begin
VarClear(V);
Found := FALSE;
if not (Assigned(Obj) and Assigned(ClassMap)) then Exit;
for i := 0 to ClassMap.Count - 1 do
begin
P := PClassMapRecord(ClassMap[i]);
if Obj.InheritsFrom(P^.ObjectClass) then
begin
V := P^.DispClass.Connect(Obj).OleObject;
{ Do a release here because the Connect does an AddRef and the
OleObject does an AddRef, we only want 1. }
VarToInterface(V).Release;
Found := TRUE;
break;
end;
end;
if Found = FALSE then
begin
for i := 0 to ClassMap.Count - 1 do
begin
P := PClassMapRecord(ClassMap[i]);
if Obj.ClassName = P^.ObjectClass.ClassName then
begin
V := P^.DispClass.Connect(Obj).OleObject;
{ Do a release here because the Connect does an AddRef and the
OleObject does an AddRef, we only want 1. }
VarToInterface(V).Release;
break;
end;
Cls := Obj.ClassParent;
while( Cls <> nil ) do
begin
if Cls.ClassName = P^.ObjectClass.ClassName then
begin
V := P^.DispClass.Connect(Obj).OleObject;
{ Do a release here because the Connect does an AddRef and the
OleObject does an AddRef, we only want 1. }
VarToInterface(V).Release;
Found := TRUE;
break;
end;
Cls := Cls.ClassParent;
end;
if Found = TRUE then
begin
break;
end;
end;
end;
end;
{ Searches through the published properties of the associated object for the
requested name (property). If it is not found it calls the inherited
GetIDsOfNames which will then search through the TAutoObject's "automated"
section for the name. }
function TPublishedAutoDispatch.GetIDsOfNames(const iid: TIID; rgszNames: POleStrList;
cNames: Integer; lcid: TLCID; rgdispid: PDispIDList): HResult;
var
PropName: string;
SubComponent: TComponent;
begin
if cNames <> 1 then
begin
Result := inherited GetIDsOfNames(iid, rgszNames, cNames, lcid, rgdispid);
Exit;
end;
Result := DISP_E_UNKNOWNNAME;
PropName := WideCharToString(rgszNames^[0]);
rgdispid^[0] := TDISPID(GetPropInfo(FObject.ClassInfo, PropName));
if rgdispid^[0] <> 0 then
begin
if PPropInfo(rgdispid^[0])^.PropType^.Kind in [tkInteger, tkEnumeration,
tkString, tkFloat, tkClass, tkSet, tkMethod, tkLString{, tkLWString}] then
Result := S_OK;
end
else if FObject is TComponent then
begin
SubComponent := TComponent(FObject).FindComponent(PropName);
if SubComponent <> nil then
begin
rgdispid^[0] := FirstComponentIndex + TDispID(SubComponent.ComponentIndex);
Result := S_OK;
end;
end;
{ Pass to inherited if nothing resolves the call. }
if Result <> S_OK then
Result := inherited GetIDsOfNames(iid, rgszNames, cNames, lcid, rgdispid);
end;
{ Gets a property or calls a method of the associated object. If the
dispIDMember is less than FirstComponentIndex it should be in the AutoObject,
otherwise it attempts to find the request in the published section of the
associated object. }
function TPublishedAutoDispatch.Invoke(dispIDMember: TDispID; const iid: TIID; lcid: TLCID;
flags: Word; var dispParams: TDispParams; varResult: PVariant;
excepInfo: PExcepInfo; argErr: PInteger): HResult;
var
PropInfo: PPropInfo;
W: Cardinal;
TypeInfo: PTypeInfo;
TypeData: PTypeData;
ErrorMessage: String;
I: Integer;
J: Integer;
// SetItemString: String;
begin
Result := DISP_E_MEMBERNOTFOUND;
PropInfo := NIL;
try
{ If it is a component then call NewDispatch to return the IDispatch to
the controller }
if (dispIDMember >= FirstComponentIndex) and
(dispIDMember <= LastComponentIndex) then
begin
NewDispatch(VarResult^,TComponent(FObject).Components[dispIDMember - FirstComponentIndex]);
Result := S_OK;
end
{ Check to see if it is a property }
else if (dispIDMember >= FirstPropIndex) then
// and (dispIDMember <= LastPropIndex) 5-16-2001 Removed - as this is always true
begin
PropInfo := PPropInfo(dispIDMember);
if Flags and DISPATCH_PROPERTYGET <> 0 then //Only Get Property
begin
VarClear(VarResult^);
Result := S_OK;
case PropInfo^.PropType^.Kind of
tkInteger:
begin
VarResult^ := GetOrdProp(FObject, PropInfo);
// SJP: 04/02/97 Modifying original.
// Set a flag to indicate Color property.
if PropInfo^.PropType^.Name = 'TColor' then
begin
TVariantArg(VarResult^).wReserved1 := 8;
end;
end;
tkEnumeration:
// SJP: 07/10/96 Modifying original.
// Now tkEnumeration properties will
// be returned as VT_I2;
begin
//TVariantArg(VarResult^).vt := VT_BSTR;
//TVariantArg(VarResult^).bstrVal := StringToOleStr(
//GetEnumName(PropInfo^.PropType, GetOrdProp(FObject, PropInfo)));
TVariantArg(VarResult^).vt := VT_I2;
TVariantArg(VarResult^).iVal := GetOrdProp(FObject, PropInfo);
end;
tkFloat:
VarResult^ := GetFloatProp(FObject, PropInfo);
tkString:
VarResult^ := GetStrProp(FObject, PropInfo);
tkSet:
begin
// SJP: 07/31/96 Modifying the original.
// Changing to return a safe array of Variants containing
// Names of all possible items in the set
// and booleans representing whether the items are
// in this particular set.
// SetItemString := '[';
W := GetOrdProp(FObject, PropInfo);
{$IFDEF VER90}
TypeData := GetTypeData(PropInfo^.PropType);
TypeInfo := TypeData^.CompType;
{$ELSE}
TypeData := GetTypeData(PropInfo^.PropType^);
TypeInfo := TypeData^.CompType^;
{$ENDIF}
// SJP: 07/31/96 Modifying the original Borland code.
// Get the TypeData again from the TypeInfo
// TypeInfo represents the OrdType of the set.
// the new TypeData will have correct MinValue and MaxValue.
TypeData := GetTypeData(TypeInfo);
VarResult^ := VarArrayCreate([0, TypeData^.MaxValue - TypeData^.MinValue, 0, 1], varVariant);
J := 0;
for I := TypeData^.MinValue to TypeData^.MaxValue do
begin
VarResult^[J, 0] := GetEnumName(TypeInfo, I);
if I in TCardinalSet(W) then
VarResult^[J, 1] := True
else
VarResult^[J, 1] := False;
J := J + 1;
end;
// begin
// if Length(SetItemString) <> 1 then
// SetItemString := SetItemString + ',';
// SetItemString := SetItemString + GetEnumName(TypeInfo, I);
// end;
// SetItemString := SetItemString + ']';
// TVariantArg(VarResult^).vt := VT_BSTR;
// TVariantArg(VarResult^).bstrVal := StringToOleStr(SetItemString);
end;
tkClass:
NewDispatch(VarResult^, TObject(GetOrdProp(FObject, PropInfo)));
tkLString:
begin
TVariantArg(VarResult^).vt := VT_BSTR;
TVariantArg(VarResult^).bstrVal := StringToOleStr(GetStrProp(FObject, PropInfo));
end;
else
Result := E_NOTIMPL;
end;
end
else if Flags and DISPATCH_PROPERTYPUT <> 0 then
begin
Result := S_OK;
case PropInfo^.PropType^.Kind of
tkInteger:
SetOrdProp(FObject, PropInfo, VarAsType(Variant(dispParams.rgvarg[0]),varInteger));
tkString:
// KPATEL: Replaced the function 'VarAsType' with 'VarToStr' as Delphi 5
// takes only string as the third parameter in SetStrProp function.
// SetStrProp(FObject, PropInfo, VarAsType(Variant(dispParams.rgvarg[0]),varString));
SetStrProp(FObject, PropInfo, VarToStr(Variant(dispParams.rgvarg[0])));
tkLString:
// KPATEL: Replaced the function 'VarAsType' with 'VarToStr' as Delphi 5
// takes only string as the third parameter in SetStrProp function.
// SetStrProp(FObject, PropInfo, VarAsType(Variant(dispParams.rgvarg[0]),varString));
SetStrProp(FObject, PropInfo, VarToStr(Variant(dispParams.rgvarg[0])));
tkEnumeration:
SetOrdProp(FObject, PropInfo, VarAsType(Variant(dispParams.rgvarg[0]),varSmallInt));
tkFloat:
SetFloatProp(FObject, PropInfo, VarAsType(Variant(dispParams.rgvarg[0]),varSingle));
{ tkSet:
begin
SetItemString := '[';
W := GetOrdProp(FObject, PropInfo);
TypeData := GetTypeData(PropInfo^.PropType);
TypeInfo := TypeData^.CompType;
// SJP: Commented out because TypeData^.MinValue/MaxValue is
// bogus.
// ShowMessage(IntToStr(TypeData^.MinValue));
// ShowMessage(IntToStr(TypeData^.MaxValue));
// for I := TypeData^.MinValue to TypeData^.MaxValue do
for I := 0 to 255 do
if I in TCardinalSet(W) then
begin
if Length(SetItemString) <> 1 then
SetItemString := SetItemString + ',';
SetItemString := SetItemString + GetEnumName(TypeInfo, I);
end;
SetItemString := SetItemString + ']';
TVariantArg(VarResult^).vt := VT_BSTR;
TVariantArg(VarResult^).bstrVal := StringToOleStr(SetItemString);
end;}
else
Result := E_NOTIMPL;
end;
end;
end;
{ If not found then pass it to the TAutoDispatch.Invoke method. }
if Result <> S_OK then
begin
Result := inherited Invoke(dispIDMember, iid, lcid, flags, dispParams,
varResult, excepInfo, argErr);
end
except
on E:Exception
do begin
ErrorMessage := FObject.ClassName;
if (Assigned(PropInfo)) then ErrorMessage := ErrorMessage + '.' + PropInfo.Name;
if ExcepInfo <> nil then
begin
FillChar(ExcepInfo^, 0, SizeOf(TExcepInfo));
//Copied this from TAutoObject.GetExceptionInfo
with ExcepInfo^ do
begin
bstrSource := StringToOleStr(FObject.ClassName);
if ExceptObject is Exception then
begin
bstrDescription := StringToOleStr(Exception(ExceptObject).Message);
ErrorMessage := ErrorMessage + ': ' + Exception(ExceptObject).Message;
end
else ErrorMessage := ErrorMessage + ': ' + E.Message;
scode := E_FAIL;
end;
end
else ErrorMessage := ErrorMessage + ': ' + E.Message;
WriteToLog(ErrorMessage);
Result := DISP_E_EXCEPTION;
end;
end;
end;
{ TIObjectDispatch }
{ Obj is the Object that is being "Bound" to here. This AutoObject will then
surface properties for Obj. }
constructor TIObjectDispatch.Connect(Obj: TObject);
begin
FObject := Obj;
inherited Create;
end;
function TIObjectDispatch.CreateAutoDispatch: TAutoDispatch;
begin
Result := TPublishedAutoDispatch.Create(Self, FObject);
end;
// New override to trap exceptions raised in the invoke.
// 5/16/2001 - PMNess
procedure TIObjectDispatch.GetExceptionInfo(ExceptObject: TObject;
var ExcepInfo: TExcepInfo);
begin
try
if (ExceptObject is Exception) then
begin
WriteToLog(PChar(Exception(ExceptObject).Message));
end;
except
// 5/16/2001 - PMNess
// If the exception object has a problem, we don't want to cause another
// exception here, so just mask it.
end;
inherited;
end;
function TIObjectDispatch.ClassName: String;
begin
Result := FObject.ClassName;
end;
function TIObjectDispatch.ParentClassName: String;
var
P: TClass;
ClassNames: String;
begin
P := FObject.ClassParent;
ClassNames := '';
while( P <> nil ) do
begin
if Length(ClassNames) > 0 then
begin
ClassNames := ClassNames + ',';
end;
ClassNames := ClassNames + P.ClassName;
P := P.ClassParent;
end;
Result := ClassNames;
end;
function TIObjectDispatch.InheritsFrom(AClass: String): WordBool;
var
P: TClass;
begin
P := FObject.ClassType;
while (P <> nil) and (CompareText(P.ClassName, AClass) <> 0) do
P := P.ClassParent;
Result := P <> nil;
end;
{ Just a friendly wrapper around GetProperty for ease of use }
function TIObjectDispatch.GetObject(ObjName: String): Variant;
begin
Result := GetProperty(ObjName);
end;
{ GetProperty can take a full path to a property or object
(ie Form1.Button1.Caption) and return the value of the property or object
as a variant. }
function TIObjectDispatch.GetProperty(PropName: String): Variant;
var
Params: TDispParams;
Index: TDISPID;
ExpInfo: TEXCEPINFO;
ArgErr: Integer;
PWStr: PWideChar;
Name: String;
Idx: Integer;
Holder: Variant;
guid: TGUID;
begin
FillChar(Params,SizeOf(Params),0);
FillChar(ExpInfo,SizeOf(ExpInfo),0);
ArgErr := 0;
Idx := Pos('.', PropName);
if Idx > 0 then
begin
Name := Copy(PropName,1,Idx - 1);
Delete(PropName,1,Idx);
end
else
Name := PropName;
PWStr := StringToOleStr(Name);
// 11/21/96 SJPak Replacing calls to OLECheck which will raise an exception
// when return value is less than 0. Raising an exception
// will cause a messagebox to pop up when ran from IDE.
if AutoDispatch.GetIDsOfNames(guid, @PWStr, 1, 0, @Index) >= 0 then
if AutoDispatch.Invoke(Index, guid, 0, Dispatch_PropertyGet or Dispatch_Method,
Params, @Holder, @ExpInfo, @ArgErr) >= 0 then
if VarType(Holder) = varDispatch then
VarToInterface(Holder).AddRef;
SysFreeString(PWStr);
if ( not VarIsEmpty( Holder ) ) and ( VarType( Holder ) = varDispatch ) and ( Idx > 0 ) then
begin
Result := Holder.GetProperty(PropName);
VarToInterface(Holder).Release;
VarClear(Holder);
end
else if ( VarIsEmpty( Holder ) ) then
begin
Holder := NULL;
// VarClear( Holder );
Result := Holder;
end
else
Result := Holder;
end;
procedure TIObjectDispatch.GetProps(var v: Variant; TypeKinds: TTypeKinds);
var
I, J, Count: Integer;
PropInfo: PPropInfo;
TempList: PPropList;
SetItemString: String;
W: Cardinal;
begin
Count := GetPropList(FObject.ClassInfo, TypeKinds, nil);
if Count > 0 then
begin
v := VarArrayCreate([0, Count - 1, 0, 2], varVariant);
GetMem(TempList, Count * SizeOf(Pointer));
try
GetPropList(FObject.ClassInfo, TypeKinds, TempList);
for I := 0 to Count - 1 do
begin
PropInfo := TempList^[I];
v[i,2] := PropInfo^.PropType^.Kind;
case PropInfo^.PropType^.Kind of
tkClass:
begin
v[i,0] := PropInfo^.Name;
v[i,1] := '(' + PropInfo^.PropType^.Name + ')';
end;
tkString,
tkLString:
begin
v[i,0] := PropInfo^.Name;
v[i,1] := GetStrProp(FObject,PropInfo);
end;
tkChar:
begin
v[i,0] := PropInfo^.Name;
v[i,1] := Chr(GetOrdProp(FObject,PropInfo));
if IsCharAlpha(Chr(GetOrdProp(FObject,PropInfo))) then
v[i,1] := Chr(GetOrdProp(FObject,PropInfo))
else
v[i,1] := '#' + IntToStr(GetOrdProp(FObject,PropInfo));
end;
tkInteger:
begin
v[i,0] := PropInfo^.Name;
v[i,1] := IntToStr(GetOrdProp(FObject,PropInfo));
end;
tkFloat:
begin
v[i,0] := PropInfo^.Name;
v[i,1] := FloatToStr(GetFloatProp(FObject,PropInfo));
end;
tkEnumeration:
begin
v[i,0] := PropInfo^.Name;
{$IFDEF VER90}
v[i,1] := GetEnumName(PropInfo^.PropType, GetOrdProp(FObject, PropInfo));
{$ELSE}
v[i,1] := GetEnumName(PropInfo^.PropType^, GetOrdProp(FObject, PropInfo));
{$ENDIF}
end;
tkSet:
begin
v[i,0] := PropInfo^.Name;
SetItemString := '[';
W := GetOrdProp(FObject, PropInfo);
for J := 0 to 15 do
if J in TCardinalSet(W) then
begin
if Length(SetItemString) <> 1 then
SetItemString := SetItemString + ',';
SetItemString := SetItemString +
{$IFDEF VER90}
GetEnumName(GetTypeData(PropInfo^.PropType)^.CompType, J);
{$ELSE}
GetEnumName(GetTypeData(PropInfo^.PropType^)^.CompType^, J);
{$ENDIF}
end;
SetItemString := SetItemString + ']';
v[i,1] := SetItemString;
end;
tkVariant:
try
v[i,0] := PropInfo^.Name;
v[i,1] := VarAsType(GetVariantProp(FObject,PropInfo), varString);
except
v[i,1] := '(Variant)';
end;
//None of these area implemented...
// tkWChar:
// tkLWString:
// tkUnknown:
// tkMethod:
end;
end;
finally
FreeMem(TempList, Count * SizeOf(Pointer));
end;
end;
end;
procedure TIObjectDispatch.GetProperties(var v: Variant);
const
TypeKinds: TTypeKinds = [{tkUnknown,} tkInteger, tkChar, tkEnumeration, tkFloat,
tkString, tkSet, tkClass, {tkMethod, }{tkWChar, }tkLString, {tkLWString,}
tkVariant];
begin
GetProps(v, TypeKinds);
end;
procedure TIObjectDispatch.GetObjects(var v: Variant);
begin
GetProps(v, [tkClass]);
end;
{ Given the property name this will return an array containing the possible
values of an enum. }
procedure TIObjectDispatch.GetEnumList(PropName: String; var v: Variant);
var
Name: String;
Idx: Integer;
Obj: Variant;
I, J: Integer;
TotalLength: Integer;
PropInfo: PPropInfo;
TypeData: PTypeData;
begin
Idx := Length(PropName);
while (Idx > 0) and (PropName[Idx] <> '.') do
Dec(Idx);
if Idx > 0 then
begin
Name := PropName;
Delete(Name,1,Idx);
Obj := GetProperty(Copy(PropName,1,Idx - 1));
try
Obj.GetEnumList(Name,v);
finally
VarToInterface(Obj).Release;
end;
end
else
begin
PropInfo := GetPropInfo(FObject.ClassInfo,PropName);
if PropInfo^.PropType^.Kind <> tkEnumeration then
raise EOleSysError(DISP_E_TYPEMISMATCH);
{$IFDEF VER90}
TypeData := GetTypeData(PropInfo^.PropType);
{$ELSE}
TypeData := GetTypeData(PropInfo^.PropType^);
{$ENDIF}
j := TypeData^.MaxValue - TypeData^.MinValue;
v := VarArrayCreate([0, j], varVariant);
j := 0;
TotalLength := 0;
for i := TypeData^.MinValue to TypeData^.MaxValue do
begin
{$IFDEF VER90}
v[j] := GetEnumName(PropInfo^.PropType,i);
{$ELSE}
v[j] := GetEnumName(PropInfo^.PropType^,i);
{$ENDIF}
TotalLength := TotalLength + Length(v[j]) + 1;
Inc(j);
end;
// SJP 3/31/98 Temporary fix to allow buffer overwrite in 6.1 SQAXDEL.DLL
if TotalLength > 2047 then
begin
v := UnAssigned;
end;
end;
end;
// SJP: 07/09/96 Added SetProperty.
function TIObjectDispatch.SetProperty(PropName: String; var v: Variant): WordBool;
var
Params: TDispParams;
Index: TDISPID;
ExpInfo: TEXCEPINFO;
ArgErr: Integer;
PWStr: PWideChar;
Name: String;
Idx: Integer;
Obj: Variant;
guid: TGUID;
bSuccess: WordBool;
begin
bSuccess := True;
// Separate the last property from the full path name.
Idx := Length(PropName);
while (Idx > 0) and (PropName[Idx] <> '.') do
Dec(Idx);
if Idx > 0 then
begin
Name := PropName;
Delete(Name,1,Idx);
Obj := GetProperty(Copy(PropName,1,Idx - 1));
try
bSuccess := Obj.SetProperty(Name,v);
finally
VarToInterface(Obj).Release;
end;
end
else
begin
FillChar(Params,SizeOf(Params),0);
FillChar(ExpInfo,SizeOf(ExpInfo),0);
ArgErr := 0;
PWStr := StringToOleStr(PropName);
New(Params.rgvarg);
Params.rgvarg[0] := TVariantArg(v);
params.cArgs := 1;
// 11/21/96 SJPak Replacing calls to OLECheck which will raise an exception
// when return value is less than 0. Raising an exception
// will cause a messagebox to pop up when ran from IDE.
if AutoDispatch.GetIDsOfNames(guid, @PWStr, 1, 0, @Index) >= 0 then
begin
if AutoDispatch.Invoke(Index, guid, 0, Dispatch_PropertyPut,
Params, nil, @ExpInfo, @ArgErr) < 0 then
bSuccess := False;
end
else
bSuccess := False;
SysFreeString(PWStr);
Dispose(params.rgvarg);
end;
Result := bSuccess;
end;
// SJP: 07/18/96 Added.
procedure TIObjectDispatch.GetPropNames(var v: Variant);
const
TypeKinds: TTypeKinds = [{tkUnknown,} tkInteger, tkChar, tkEnumeration, tkFloat,
tkString, tkSet, tkClass, {tkMethod, }{tkWChar, }tkLString, {tkLWString,}
tkVariant];
var
I, Count: Integer;
PropInfo: PPropInfo;
TempList: PPropList;
begin
Count := GetPropList(FObject.ClassInfo, TypeKinds, nil);
if Count > 0 then
begin
v := VarArrayCreate([0, Count - 1, 0, 1], varVariant);
GetMem(TempList, Count * SizeOf(Pointer));
try
GetPropList(FObject.ClassInfo, TypeKinds, TempList);
for I := 0 to Count - 1 do
begin
PropInfo := TempList^[I];
v[i,1] := PropInfo^.PropType^.Kind;
case PropInfo^.PropType^.Kind of
tkClass:
v[i,0] := PropInfo^.Name;
tkString,
tkLString:
v[i,0] := PropInfo^.Name;
tkChar:
v[i,0] := PropInfo^.Name;
tkInteger:
v[i,0] := PropInfo^.Name;
tkFloat:
v[i,0] := PropInfo^.Name;
tkEnumeration:
v[i,0] := PropInfo^.Name;
tkSet:
v[i,0] := PropInfo^.Name;
tkVariant:
v[i,0] := PropInfo^.Name;
//None of these area implemented...
// tkWChar:
// tkLWString:
// tkUnknown:
// tkMethod:
end;
end;
finally
FreeMem(TempList, Count * SizeOf(Pointer));
end;
end;
end;
{ TIComponentDispatch }
function TIComponentDispatch.GetComponents(Index: Integer): Variant;
begin
if (Index >= 0) and (Index < TComponent(FObject).ComponentCount) then
TPublishedAutoDispatch(AutoDispatch).NewDispatch(Result, TComponent(FObject).Components[Index])
else
;
// OleError(DISP_E_BADINDEX);
end;
function TIComponentDispatch.GetComponentCount: Integer;
begin
Result := TComponent(FObject).ComponentCount;
end;
function TIComponentDispatch.GetComponentIndex: Integer;
begin
Result := TComponent(FObject).ComponentIndex;
end;
function TIComponentDispatch.GetOwner: Variant;
begin
TPublishedAutoDispatch(AutoDispatch).NewDispatch(Result, TComponent(FObject).Owner)
end;
function TIComponentDispatch.GetDesignInfo: LongInt;
begin
Result := TComponent(FObject).DesignInfo;
end;
function TIComponentDispatch.FindComponent(AName: String): Variant;
var
Obj: TComponent;
begin
Obj := TComponent(FObject).FindComponent(AName);
if Obj <> nil then
TPublishedAutoDispatch(AutoDispatch).NewDispatch(Result, Obj)
else
;
// OleError(DISP_E_UNKNOWNNAME);
end;
{ TICollectionDispatch }
function TICollectionDispatch.GetItemCount: Integer;
begin
Result := TCollection(FObject).Count;
end;
procedure TICollectionDispatch.GetPropNames(var v: Variant);
var
Count, I : Integer;
vTemp : Variant;
begin
inherited GetPropNames(vTemp);
Count := -1;
if VarIsArray(vTemp) then
Count := VarArrayHighBound(vTemp, 1);
v := VarArrayCreate([0, Count + 2, 0, 1], varVariant);
for I := 0 to Count do
begin
v[I, 0] := vTemp[I, 0];
v[I, 1] := vTemp[1, 1];
end;
v[Count + 1, 0] := 'Count';
v[Count + 1, 1] := tkInteger;
v[Count + 2, 0] := 'Items';
v[Count + 2, 1] := tkClass;
VarClear(vTemp);
end;
function TICollectionDispatch.GetProperty(PropName: String): Variant;
var
Count: Integer;
I: Integer;
Item: Variant;
Holder: Variant;
begin
if Propname = 'Count' then
begin
Holder := TCollection(FObject).Count;
Result := Holder;
end
else if Propname = 'Items' then
begin
Count := TCollection(FObject).Count;
Holder := VarArrayCreate([0, Count-1], varDispatch);
for I := 0 to Count-1 do
begin
TPublishedAutoDispatch(AutoDispatch).NewDispatch(Item, TCollection(FObject).Items[I]);
Holder[I] := Item;
end;
Result := Holder;
end
else
Result := inherited GetProperty(PropName);
end;
{ TIDataSetDispatch }
// SJP. 07/08/96 Returns FieldCount for TDataSet Objects.
function TIDataSetDispatch.GetFieldCount: Integer;
begin
Result := TDataSet(FObject).FieldCount;
end;
// SJP. 07/08/96 Returns Tab-delimited/New-line separated
// 'data' for TDataSet Objects.
function TIDataSetDispatch.GetData: String;
var
I: Integer;
Data: String;
InitialBookMark: TBookMark;
begin
InitialBookMark := TDataSet(FObject).GetBookMark;
Data := '';
TDataSet(FObject).First;
while TDataSet(FObject).EOF = False do
begin
for I := 0 to TDataSet(FObject).FieldCount - 1 do
begin
if TDataSet(FObject).Fields[I].InheritsFrom(TMemoField) then
Data := Data + '(Memo)'
else if TDataSet(FObject).Fields[I].InheritsFrom(TGraphicField) then
Data := Data + '(Graphic)'
else if TDataSet(FObject).Fields[I].InheritsFrom(TBlobField) then
Data := Data + '(Blob)'
else if TDataSet(FObject).Fields[I].InheritsFrom(TBytesField) then
Data := Data + '(Bytes)'
else if TDataSet(FObject).Fields[I].InheritsFrom(TVarBytesField) then
Data := Data + '(Var Bytes)'
else
Data := Data + TDataSet(FObject).Fields[I].AsString;
if I < TDataSet(FObject).FieldCount - 1 then
Data := Data + #9;
end;
TDataSet(FObject).Next;
Data := Data + #13;
end;
TDataSet(FObject).GotoBookMark(InitialBookMark);
TDataSet(FObject).FreeBookMark(InitialBookMark);
Result := Data;
end;
{ TIStringDispatch }
procedure TIStringsDispatch.GetPropNames(var v: Variant);
var
Count, I : Integer;
vTemp : Variant;
begin
inherited GetPropNames(vTemp);
Count := -1;
if VarIsArray(vTemp) then
Count := VarArrayHighBound(vTemp, 1);
v := VarArrayCreate([0, Count + 2, 0, 1], varVariant);
for I := 0 to Count do
begin
v[I, 0] := vTemp[I, 0];
v[I, 1] := vTemp[1, 1];
end;
v[Count + 1, 0] := 'Text';
v[Count + 1, 1] := tkString;
v[Count + 2, 0] := 'Strings';
v[Count + 2, 1] := tkString;
VarClear(vTemp);
end;
function TIStringsDispatch.GetProperty(PropName: String): Variant;
var
I: Integer;
Count: Integer;
Holder: Variant;
begin
if Propname = 'Strings' then
begin
Count := TStrings(FObject).Count;
if Count > 0 then
begin
Holder := VarArrayCreate([0, Count-1], varOleStr);
for I := 0 to Count-1 do
begin
// Arbitrary Max len of 32000
Holder[I] := Copy(TStrings(FObject).Strings[I], 0, MaxStringItem);
end;
end;
Result := Holder;
end
else if Propname = 'Text' then
begin
Holder := TStrings(FObject).Text;
Result := Holder;
end
else
Result := inherited GetProperty(PropName);
end;
{ TIOleControlDispatch }
function TIOleControlDispatch.GetOleObject: Variant;
begin
Result := TOleControl(FObject).OleObject;
end;
{ TIStringGridDispatch }
procedure TIStringGridDispatch.GetPropNames(var v: Variant);
var
Count, I : Integer;
vTemp : Variant;
begin
inherited GetPropNames(vTemp);
Count := -1;
if VarIsArray(vTemp) then
Count := VarArrayHighBound(vTemp, 1);
v := VarArrayCreate([0, Count + 2, 0, 1], varVariant);
for I := 0 to Count do
begin
v[I, 0] := vTemp[I, 0];
v[I, 1] := vTemp[1, 1];
end;
v[Count + 1, 0] := 'Cols';
v[Count + 1, 1] := tkClass;
v[Count + 2, 0] := 'Rows';
v[Count + 2, 1] := tkClass;
VarClear(vTemp);
end;
function TIStringGridDispatch.GetProperty(PropName: String): Variant;
var
Count: Integer;
I: Integer;
Item: Variant;
Holder: Variant;
begin
if Propname = 'Cols' then
begin
Count := TStringGrid(FObject).ColCount;
Holder := VarArrayCreate([0, Count-1], varDispatch);
for I := 0 to Count-1 do
begin
TPublishedAutoDispatch(AutoDispatch).NewDispatch(Item, TStringGrid(FObject).Cols[I]);
Holder[I] := Item;
end;
Result := Holder;
end
else if Propname = 'Rows' then
begin
Count := TStringGrid(FObject).RowCount;
Holder := VarArrayCreate([0, Count-1], varDispatch);
for I := 0 to Count-1 do
begin
TPublishedAutoDispatch(AutoDispatch).NewDispatch(Item, TStringGrid(FObject).Rows[I]);
Holder[I] := Item;
end;
Result := Holder;
end
else
Result := inherited GetProperty(PropName);
end;
function TIStringGridDispatch.GetData: String;
var
row, col, RowCount, ColCount: Integer;
DataTemp, Data: String;
begin
//OutputDebugString( PChar( 'TIStringGridDispatch.GetData : ' + #13#10 ) );
Data := '';
RowCount := TStringGrid(FObject).RowCount;
ColCount := TStringGrid(FObject).ColCount;
for row := 0 to RowCount - 1 do
begin
DataTemp := '';
for col := 0 to ColCount - 1 do
begin
DataTemp := DataTemp + TStringGrid(FObject).Cells[ col, row ];
if col < ColCount - 1 then
DataTemp := DataTemp + #9;
end;
Data := Data + DataTemp + #13;
end;
//OutputDebugString( PChar( 'TIStringGridDispatch.GetData Returing: ' + Data + #13#10 ) );
Result := Data;
end;
{ TITreeViewDispatch }
procedure TITreeViewDispatch.GetPropNames(var v: Variant);
begin
inherited GetPropNames(v);
end;
function TITreeViewDispatch.GetProperty(PropName: String): Variant;
var
Count: Integer;
I: Integer;
Holder: Variant;
Nodes: TTreeNodes;
Node, NodeTemp: TTreeNode;
NodePath: string;
begin
//OutputDebugString( PChar( 'TITreeViewDispatch.GetProperty : ' + PropName + #13#10) );
if Propname = 'Items' then
begin
Nodes := TTreeView(FObject).Items;
Count := Nodes.Count;
Holder := VarArrayCreate([0, Count-1], varOleStr);
for I := 0 to Count - 1 do
begin
Node := Nodes.Item[ I ];
NodeTemp := Node.Parent;
NodePath := Node.Text;
while( NodeTemp <> nil ) do
begin
NodePath := NodeTemp.Text + '->' + NodePath;
NodeTemp := NodeTemp.Parent;
end;
Holder[I] := Copy( NodePath, 0, MaxStringItem);
end;
Result := Holder;
end
else
Result := inherited GetProperty(PropName);
end;
{ TIControlDispatch }
function TIControlDispatch.GetParent: Variant;
begin
TPublishedAutoDispatch(AutoDispatch).NewDispatch(Result, TControl(FObject).Parent)
end;
{TIWinControlDispatch}
function TIWinControlDispatch.GetControls(Index: Integer): Variant;
begin
if (Index >= 0) and (Index < TWinControl(FObject).ControlCount) then
TPublishedAutoDispatch(AutoDispatch).NewDispatch(Result, TWinControl(FObject).Controls[Index])
else
;
// OleError(DISP_E_BADINDEX);
end;
function TIWinControlDispatch.GetHandle: Integer;
begin
Result := TWinControl(FObject).Handle;
end;
function TIWinControlDispatch.GetControlCount: Integer;
begin
Result := TWinControl(FObject).ControlCount;
end;
function TIWinControlDispatch.ControlAtPos(X, Y: Integer): Variant;
var
Pt: TPoint;
Control: TControl;
begin
Pt.y := Y;
Pt.x := X;
Control := TWinControl(FObject).ControlAtPos(Pt, True);
if Control <> nil then
TPublishedAutoDispatch(AutoDispatch).NewDispatch(Result, Control)
else
;
// OleError(DISP_E_BADINDEX);
end;
{ TIApplicationDispatch }
constructor TIApplicationDispatch.Create;
begin
FObject := Application;
inherited Create;
end;
function TIApplicationDispatch.GetDispFromHandle(Handle: Integer): Variant;
var
Obj: TObject;
begin
Obj := FindControl(Handle);
if (Obj <> nil) then
TPublishedAutoDispatch(AutoDispatch).NewDispatch(Result, Obj)
else
;
// OleError(DISP_E_PARAMNOTFOUND);
end;
function TIApplicationDispatch.GetHandle: Integer;
begin
Result := TApplication(FObject).Handle;
end;
function TIApplicationDispatch.GetExeName: String;
begin
Result := TApplication(FObject).ExeName;
end;
function TIApplicationDispatch.GetMainForm: Variant;
begin
TPublishedAutoDispatch(AutoDispatch).NewDispatch(Result, TApplication(FObject).MainForm);
end;
procedure RegisterAutomationServer;
const
AutoClassInfo: TAutoClassInfo = (
AutoClass: TIApplicationDispatch;
ProgID: 'SQAServer.Application';
ClassID: '{92E4FBC0-1169-11D0-B5AB-00A02484352C}';
Description: 'SQA Test Automation Server';
Instancing: acMultiInstance);
begin
Automation.RegisterClass(AutoClassInfo);
end;
function GetPropertyName : string;
var
propName : string;
begin
Result := 'SQAApplicationObject';
if ( System.IsLibrary ) then
begin
propName := Format( 'SQAApplicationObject_%x', [ HInstance ] );
Result := propName;
end;
end;
function GetApplicationHandle: THandle;
var
appHandle : THandle;
begin
Result := Application.Handle;
if ( Result = 0 ) then
begin
appHandle := FindWindow( PChar( 'TApplication' ), nil );
Result := appHandle;
end;
end;
procedure BeautifyApplicationWindow;
var
appD : TIApplicationDispatch;
propName : string;
aut : TAutoDispatch;
V : ^Variant;
appHandle : THandle;
begin
propName := GetPropertyName( );
appHandle := GetApplicationHandle( );
//OutputDebugString( PChar( Format( 'DEEnabler: Application handle :<%x>' + #13#10, [ appHandle ] ) ) );
if ( GetProp( appHandle, PChar(propName) ) = 0 ) then
begin
New( V );
VarClear( V^ );
appD := TIApplicationDispatch.Create( );
aut := appD.AutoDispatch;
TVarData(V^).VType := varDispatch;
TVarData(V^).VDispatch := aut;
//VarToInterface(V^).AddRef;
//OutputDebugString( PChar( Format( 'DEEnabler: SetProp <%s> apphandle <%x> object <%x>' + #13#10, [ PChar(propName), appHandle, THandle( V ) ] ) ) );
SetProp( appHandle, PChar(propName), THandle( V ) );
end;
end;
procedure RevertApplicationWindowChanges;
var
th : THandle;
V : PVariant;
propName : PChar;
appHandle : THandle;
begin
propName := 'SQAApplicationObject';
appHandle := GetApplicationHandle();
th := Windows.GetProp( appHandle, propName );
if ( th <> 0 ) then
begin
V := PVariant(th);
Dispose( V );
//VarToInterface(V^).Release;
Windows.RemoveProp( appHandle, propName );
end;
end;
function TIApplicationDispatch.FindControl1(hWndToFind: HWnd): TWinControl;
var
lControlAtom: TAtom;
lControlAtomString: string;
lOwningProcess: Pointer;
lUnknownProcess: DWORD;
lRM_GetObjectInstance: DWORD;
begin
Result := nil;
if (hWndToFind <> 0) then
begin
lControlAtomString := Format('ControlOfs%.8X%.8X', [GetWindowLong( hWndToFind, GWL_HINSTANCE), GetCurrentThreadID]);
lControlAtom := GlobalAddAtom(PChar(lControlAtomString));
if GlobalFindAtom(PChar(lControlAtomString)) = lControlAtom then
begin
Result := Pointer(GetProp(hWndToFind, MakeIntAtom(lControlAtom)))
end
else
begin
lRM_GetObjectInstance := RegisterWindowMessage(PChar(lControlAtomString));
lOwningProcess := nil;
GetWindowThreadProcessID(hWndToFind, lOwningProcess);
lUnknownProcess := GetCurrentProcessID();
if DWORD(lOwningProcess) = lUnknownProcess then
begin
Result := Pointer(SendMessage(hWndToFind, lRM_GetObjectInstance, 0, 0))
end
else
begin
Result := nil;
end;
end;
end;
end;
begin
RegisterAutomationEnabler(TObject, TIObjectDispatch);
RegisterAutomationEnabler(TComponent, TIComponentDispatch);
RegisterAutomationEnabler(TControl, TIControlDispatch);
RegisterAutomationEnabler(TWinControl, TIWinControlDispatch);
// SJP: Added 07/01/96.
RegisterAutomationEnabler(TCollection, TICollectionDispatch);
// SJP: Added 07/08/96.
RegisterAutomationEnabler(TDataSet, TIDataSetDispatch);
// SJP: Added 07/08/96.
RegisterAutomationEnabler(TStrings, TIStringsDispatch);
// SJP: Added 08/04/96.
RegisterAutomationEnabler(TOleControl, TIOleControlDispatch);
// SJP: Added 03/12/97.
RegisterAutomationEnabler(TStringGrid, TIStringGridDispatch);
// TreeView support
RegisterAutomationEnabler(TTreeView, TITreeViewDispatch);
//RegisterAutomationServer;
BeautifyApplicationWindow( );
end.