I admit I'm not a Delphi expert, so I need some advice.
I have a pre-built class with this definition
TS7Helper = class
private
function GetInt(pval: pointer): smallint;
procedure SetInt(pval: pointer; const Value: smallint);
function GetWord(pval: pointer): word;
procedure SetWord(pval: pointer; const Value: word);
function GetDInt(pval: pointer): longint;
procedure SetDInt(pval: pointer; const Value: longint);
function GetDWord(pval: pointer): longword;
procedure SetDWord(pval: pointer; const Value: longword);
function GetDateTime(pval: pointer): TDateTime;
procedure SetDateTime(pval: pointer; const Value: TDateTime);
function GetReal(pval: pointer): single;
procedure SetReal(pval: pointer; const Value: single);
function GetBit(pval: pointer; BitIndex: integer): boolean;
procedure SetBit(pval: pointer; BitIndex: integer; const Value: boolean);
public
procedure Reverse(pval : pointer; const S7Type : TS7Type);
property ValBit[pval : pointer; BitIndex : integer] : boolean read GetBit write SetBit;
property ValInt[pval : pointer] : smallint read GetInt write SetInt;
property ValDInt[pval : pointer] : longint read GetDInt write SetDInt;
property ValWord[pval : pointer] : word read GetWord write SetWord;
property ValDWord[pval : pointer] : longword read GetDWord write SetDWord;
property ValReal[pval : pointer] : single read GetReal write SetReal;
property ValDateTime[pval : pointer] : TDateTime read GetDateTime write SetDateTime;
end;
Var
S7 : TS7Helper;
procedure TS7Helper.SetInt(pval: pointer; const Value: smallint);
Var
BW : packed array[0..1] of byte absolute value;
begin
pbyte(NativeInt(pval)+1)^:=BW[0];
pbyte(pval)^:=BW[1];
end;
(I cut some code, so don't look for the implementation clause, etc... the helper class is compiling ok....)
Trivially, I want to invoke the SetInt property (as stated in the class documentation)... but the following code gives me an error "Cannot access private symbol TS7Helper.SetInt".
S7.SetInt(#MySnap7Array[i * 2], gaPlcDataScrittura[i]);
What am I doing wrong ?
SetInt and GetInt is the getter and setter for ValInt property as stated in the definition of ValInt. So you shoud use S7.ValInt like
S7.ValInt[#MySnap7Array[i * 2]] := gaPlcDataScrittura[i];
In Delphi,
A private member is invisible outside of the unit or program where its class is declared.
Note: "program" refers to files starting with program keyword (usually the .dpr file), not to the project as a whole.
So you can only call TS7Helper.SetInt from the same unit where TS7Helper class is declared.
Otherwise, #DmLam answer is the correct way to solve it.
Related
I have to build my program with runtime type information, so compiler option Emit runtime type information is checked.
But with this set the LockBox3 unit uTPLb_codecIntf.pas gives error E2134 Type has no type info on the line containing Implementation (see bottom of source).
The LockBox3\run\ (source) folders are in my library path (as specified by the installation).
LockBox DCU's are in d:\LockBox3\packages\Sydney\Delphi\Win32\Release\ and date from the time of installation.
How can I get rid of the error message yet have RTTI available?
Edit FWIW, these are the contents of uTPLb_codecIntf.pas:
interface
uses SysUtils, Classes, uTPLb_StreamCipher, uTPLb_BlockCipher,
uTPLb_CryptographicLibrary;
type
TCodecMode = (cmUnitialized, cmIdle, cmEncrypting, cmDecrypting);
TOnEncDecProgress = function ( Sender: TObject; CountBytesProcessed: int64): boolean of object;
TGenerateAsymetricKeyPairProgress = procedure (
Sender: TObject; CountPrimalityTests: integer;
var doAbort: boolean) of object;
ICodec = interface
['{48B3116A-5681-4E79-9013-8EC89BAC5B35}']
procedure SetStreamCipher( const Value: IStreamCipher);
procedure SetBlockCipher ( const Value: IBlockCipher);
procedure SetChainMode ( const Value: IBlockChainingModel);
function GetMode: TCodecMode;
function GetStreamCipher: IStreamCipher;
function GetBlockCipher : IBlockCipher;
function GetChainMode : IBlockChainingModel;
function GetOnProgress : TOnEncDecProgress;
procedure SetOnProgress( Value: TOnEncDecProgress);
function GetAsymetricKeySizeInBits: cardinal;
procedure SetAsymetricKeySizeInBits( value: cardinal);
function GetAsymGenProgressEvent: TGenerateAsymetricKeyPairProgress;
procedure SetAsymGenProgressEvent( Value: TGenerateAsymetricKeyPairProgress);
function GetKey: TSymetricKey;
function GetCipherDisplayName( Lib: TCryptographicLibrary): string;
procedure Init(const Key: string; AEncoding: TEncoding);
procedure SaveKeyToStream( Store: TStream);
procedure InitFromStream( Store: TStream);
procedure InitFromKey( Key: TSymetricKey); // Transfers ownership.
procedure Reset;
procedure Burn( doIncludeBurnKey: boolean);
// Asymetric support
function isAsymetric: boolean;
procedure InitFromGeneratedAsymetricKeyPair;
procedure Sign(
Document, Signature: TStream;
ProgressSender: TObject;
ProgressEvent: TOnEncDecProgress;
SigningKeys_PrivatePart: TObject; // Must be uTPLb_Asymetric.TAsymtricKeyPart
var wasAborted: boolean);
function VerifySignature(
Document, Signature: TStream;
ProgressSender: TObject;
ProgressEvent: TOnEncDecProgress;
SigningKeys_PublicPart: TObject; // Must be uTPLb_Asymetric.TAsymtricKeyPart
var wasAborted: boolean): boolean;
procedure Begin_EncryptMemory( CipherText{out}: TStream);
procedure EncryptMemory(const Plaintext: TBytes; PlaintextLen: Integer);
procedure End_EncryptMemory;
procedure Begin_DecryptMemory( PlainText{out}: TStream);
procedure DecryptMemory( const CipherText{in}; CiphertextLen: integer);
procedure End_DecryptMemory;
procedure EncryptStream( Plaintext, CipherText: TStream);
procedure DecryptStream( Plaintext, CipherText: TStream);
procedure EncryptFile( const Plaintext_FileName, CipherText_FileName: string);
procedure DecryptFile( const Plaintext_FileName, CipherText_FileName: string);
procedure EncryptString(const Plaintext: string; var CipherText_Base64: string; AEncoding: TEncoding);
procedure DecryptString(var Plaintext: string; const CipherText_Base64: string; AEncoding: TEncoding);
procedure EncryptAnsiString(const Plaintext: string; var CipherText_Base64: string);
procedure DecryptAnsiString(var Plaintext: string; const CipherText_Base64: string);
function GetAborted: boolean;
procedure SetAborted( Value: boolean);
function GetAdvancedOptions2 : TSymetricEncryptionOptionSet;
procedure SetAdvancedOptions2( Value: TSymetricEncryptionOptionSet);
function GetOnSetIV: TSetMemStreamProc;
procedure SetOnSetIV( Value: TSetMemStreamProc);
property Mode: TCodecMode read GetMode;
property Key: TSymetricKey read GetKey;
property StreamCipher: IStreamCipher read GetStreamCipher write SetStreamCipher;
property BlockCipher : IBlockCipher read GetBlockCipher write SetBlockCipher;
property ChainMode : IBlockChainingModel read GetChainMode write SetChainMode;
property OnProgress : TOnEncDecProgress read GetonProgress write SetOnProgress;
property AsymetricKeySizeInBits: cardinal read GetAsymetricKeySizeInBits
write SetAsymetricKeySizeInBits;
property OnAsymGenProgress: TGenerateAsymetricKeyPairProgress
read GetAsymGenProgressEvent write SetAsymGenProgressEvent;
property isUserAborted: boolean read GetAborted write SetAborted;
end;
implementation
end.
The fact that the LockBox writers suggest to place the source folders in your library path, does not mean you have to. It's handy for tracing into their code, but not required.
Just remove them from that list and add the .dcu directory d:\LockBox3\packages\Sydney\Delphi\Win32\Release\ to it.
This makes the error go away, and I don't need RTTI in the LockBox sources.
You need to rebuild the dcus with run time information. The simplest way to do this (which also only includes the dcu in this project, not all projects) is to include the source file uTPLb_codecIntf.pas in you project and build the project. You may need to repeat the process for other source files depending on what RTTI you need.
I encountered some error for which i just can't find a proper hint on the net. Hopefully one of you can point me to the right direction.
Simple Problem: I've got a class inheriting from TObject. I've got a constructor named Create and i want to call Inherited on the very first line of the very only constructor.
Does not work!
On compile i get a
[dcc32 Fehler] ULSRAware.pas(58): E2008 Inkompatible Typen
If I comment the inherited out it compiles fine but on runtime on creating the object, while I can access methods regulary (like some private _InitAdo method), every access to a property yields an access violation error.
I guess it's coming from calling the inherited nonetheless but without any sufficient success.
This is the declaration at the head of the Unit. Just to mention it, it's just this class in the unit. And of course in the implementation section the implementation.
type TLAConnect = class( TObject )
private
_mailHost : String;
_mailPort : Integer;
_mailUsername : String;
_mailPassword : String;
_mailAddress : String;
_sql_script_sms : String;
_sql_script_mail: String;
_sms_mail_addon : String;
//connection : TADOConnection;
(*
procedure SendMessage( recp:String; subj, body : String );
procedure _InitAdo( config_filename : String; path: String );
function GetMsgId( msg : String ) : Integer;
function GetMsgIdFromByteBit( byte, bit : String ) : Integer;
function ProcessMessage( msgId : Integer ): String;
procedure Trigger( msgId : Integer );
procedure QuittMsg( msgId : Integer );
procedure MakeMessage( _msgid : Integer; _fsms, _fmail : Boolean; _smsgl, _smsgs : String );
function CreateNewByteTrigger( byte, bit : String ) : Integer;
*)
public
Constructor Create( config : String );
Destructor Destroy; override;
//function Call( msg:String ) : Boolean;
end;
And the implementation of the constructor and the desctructor.
Constructor TLAConnect.Create( config : String );
begin
inherited.Create;
//self._InitAdo( config, 'lsraware ado' );
_mailHost := 'blabla';
_mailPort := 587;
_mailUsername := 'blabla_user';
_mailPassword := 'blabla_pass';
_mailAddress := 'blabal';
end;
Destructor TLAConnect.Destroy;
begin
self.connection.Free;
Inherited;
end;
I would like to call SPSS 'backend' from Delphi. There is a DLL that I can use (it seems): SPSSio64.DLL. But I can not find the interface definition.
What I have found is an example in PowerBasic:
Read and write SPSS sav files
DECLARE FUNCTION spssOpenRead LIB "spssio32.dll" ALIAS "spssOpenRead#8" (BYVAL fileName AS STRING, BYREF hHandle AS LONG) AS LONG
DECLARE FUNCTION spssCloseRead LIB "spssio32.dll" ALIAS "spssCloseRead#4" (BYVAL hHandle AS LONG) AS LONG
Since I only need functions to read and write a file (all the processing will be done via a syntax in that file), I thought that this example might be enough to deduce how to call equivalent functions from Delphi.
So the question is: how would these declarations be in Delphi (64-bit)?
Based on the SPSS 14.0 for Windows Developer's Guide, and PowerBasic documentation, try something like this:
32-bit:
// spssio32.dll exports both 'spssOpenRead' and 'spssOpenRead#8', which are the same function...
function spssOpenRead(filename: PAnsiChar; var hHandle: Integer): Integer; stdcall; external 'spssio32.dll' {name 'spssOpenRead#8'};
// spssio32.dll exports both 'spssCloseRead' and 'spssCloseRead#4', which are the same function...
function spssCloseRead(hHandle: Integer): Integer; stdcall; external 'spssio32.dll' {name 'spssCloseRead#4'};
64-bit:
// I can't find a copy of spssio64.dll to download, so I can't verify the exported names. Adjust if needed..
function spssOpenRead(filename: PAnsiChar; var hHandle: Integer): Integer; stdcall; external 'spssio64.dll' {name 'spssOpenRead#16'};
function spssCloseRead(hHandle: Integer): Integer; stdcall; external 'spssio64.dll' {name 'spssCloseRead#8'};
For the record, this works:
function LoadDLL(DLLname : string) : Uint64;
var
em : TArithmeticExceptionMask;
begin
em:=GetExceptionmask;
SetExceptionmask(em+[exInvalidOp,exZeroDivide,exOverflow,exUnderflow]);
result:=LoadLibrary(PwideChar(DLLname));
SetExceptionmask(em);
end;
function RunSPSSio(filename : string; instructions : Tinstructions) : boolean;
// This will only read SAV files, not SPS files !
type
TspssOpenRead = function (filename: PAnsiChar; var hHandle: Uint64): Integer;
TspssCloseRead = function(hHandle: Uint64): Integer;
TspssGetInterfaceEncoding = function(hHandle : Uint64): Integer;
TspssSetInterfaceEncoding = function(encoding : integer; hHandle : Uint64): Integer;
const
SPSS_ENCODING_UTF8 = 1;
var
p : integer;
spssOpenRead : TspssOpenRead;
spssCloseRead : TspssCloseRead;
spssGetIFencoding : TspssGetInterfaceEncoding;
spssSetIFencoding : TspssSetInterfaceEncoding;
DLLhandle : Uint64;
fileref : PANSIchar;
begin
result:=false;
DLLhandle:=LoadDLL('C:\SPSS\spssio64.dll'); // hardcoded
if DLLhandle=0
then begin p:=GetLastError();
report('DLL load error '+IntToStr(p));
exit;
end;
try
#SPSSopenRead:=getProcAddress(DLLhandle,'spssOpenRead');
#SPSScloseRead:=getProcAddress(DLLhandle,'spssCloseRead');
#SPSSsetIFencoding:=getProcAddress(DLLhandle,'spssSetInterfaceEncoding');
SPSSsetIFencoding(SPSS_ENCODING_UTF8,DLLhandle);
fileref:=PANSIchar(ANSIstring(filename));
p:=SPSSopenRead(fileref,DLLhandle);
if p<>0
then report('*** SPSSio error '+IntToStr(p))
else begin // SPSS database interactions here
result:=SPSScloseRead(DLLhandle)=0;
end;
finally
freeLibrary(DLLhandle);
end;
end;
I have a class I want to pass to a datasnap server, but the class contains this field Picture which should be a TPicture but for now I use an integer to avoid getting the marshall error "tkPointer currently not supported" :(
I have tried omitting a field/property "Picture" from getting marshalled by adding [JSONMarshalled(False)] but with no luck.
I have added the units as suggested in the thread here
JSONMarshalled not working in Delphi
unit TestObjU;
interface
uses
Classes, System.Generics.Collections, System.SyncObjs, System.SysUtils,
JSON, DBXJsonReflect, REST.JSON,
Data.FireDACJSONReflect, FireDAC.Comp.Client, vcl.ExtCtrls,
pngimage, graphics, variants,
GlobalFunctionsU, GlobalTypesU;
{$M+}
{$RTTI EXPLICIT FIELDS([vcPrivate])}
type
EPerson = class(Exception);
EPersonsList = class(Exception);
TGender = (Female, Male);
TPerson = class(TObject)
private
FFirstName: string;
FLastName: string;
FId: Integer;
FGender: TGender;
FModified : Boolean;
[JSONMarshalled(False)]
FPicture: Integer;
// [JSONMarshalled(False)] FPicture : TPicture;
function GetName: string;
procedure SetFirstName(const Value: string);
procedure SetLastName(const Value: string);
function GetId: Integer;
procedure SetGender(const Value: TGender);
procedure SetModified(const Value: Boolean);
public
property Id : Integer read GetId;
property Name : string read GetName;
property FirstName : string read FFirstName write SetFirstName;
property LastName : string read FLastName write SetLastName;
property Gender : TGender read FGender write SetGender;
property Modified : Boolean read FModified write SetModified;
// property Picture : TPicture read FPicture write FPicture;
[JSONMarshalled(False)]
property Picture : Integer read FPicture write FPicture;
function Update : Boolean;
function Delete : Boolean;
constructor Create(AId : Integer; AFirstName, ALastName : string; AGender : TGender); overload;
constructor Create(AFirstName, ALastName : string; AGender : TGender); overload;
destructor destroy; override;
function ToJsonString: string;
end;
But clearly it has no effect on the marshalling, Picture is still there - what am I missing?
function TPerson.ToJsonString: string;
begin
result := TJson.ObjectToJsonString(self);
end;
08-03-2016 10:26:24 [NORMAL] AddPerson serialized {"firstName":"Donald","lastName":"Duck","id":24,"gender":"Female","modified":false,"picture":92415648}
You are using TJson.ObjectToJsonString from REST.Json unit and that one needs different attribute to skip fields named JSONMarshalledAttribute
You should change your code to [JSONMarshalledAttribute(False)]
Delphi has a bit of mix up between older Data.DBXJsonReflect and newer REST.Json units and you should not mix them together in same code. Pick only one of them.
REST.Json.TJson.ObjectToJsonString
REST.Json.Types.JSONMarshalledAttribute
Data.DBXJSONReflect.JSONMarshalled
Yes - I found the solution, when using DBX (and not REST) you'll need add this unit "Data.DBXJSON" rather than the "REST.JSON" and change the two "from/to" methods for un/marshaling the object something like this.
NOTE. ToJSONString leaks for some reason, I'll have to investigate that more.
function TPerson.ToJsonString: string;
var
JSONMarshal: TJSONMarshal;
begin
result := '';
JSONMarshal := TJSONMarshal.Create(TJSONConverter.Create);
try
Result := JSONMarshal.Marshal(self).ToString;
finally
JSONMarshal.Free;
end;
end;
class function TPerson.FromJsonString(AJSONString: string): TPerson;
var
JSONUnMarshal: TJSONUnMarshal;
begin
JSONUnMarshal := TJSONUnMarshal.Create;
try
Result := JSONUnMarshal.Unmarshal(TJSONObject.ParseJSONValue(AJSONString)) as TPerson;
finally
JSONUnMarshal.Free;
end;
end;
I'm very new to DLL objects and I search everywhere and can't find the right answer.
I doing little addon to Microsoft RMS, it automatically calls function Process from my dll with IDispach parameter passing current session details.
I'm using interface from QSRules.dll (Components > Import > Component > Typed Library ... Add To Project).
It creates TLB file with all references etc.
procedure TRefreshScreenRefreshScreen.Process(const Session: IDispatch);
begin
CodeSite.Send( csmLevel1, '(Session as SessionClass).Cashier.Name', (Session as SessionClass).Cashier.Name );
CodeSite.Send( csmLevel1, '(Session as SessionClass).Cashier.Number', (Session as SessionClass).Cashier.Number );
end;
That works perfectly with software version 2.01 but when trying to use the same function on version 2.02 it crash with "Interface not supported".
The QSRules.dll has updated version and GUID's for all classes are different.
I tried that with fallowing code:
procedure TRefreshScreenRefreshScreen.Process(const Session: IDispatch);
begin
if Supports(Session, QSRules_TLB_2_0_0_151.SessionClass) then
Begin
CodeSite.Send( csmLevel1, '(Session as SessionClass).Cashier.Name', (Session as QSRules_TLB_2_0_0_151.SessionClass).Cashier.Name );
CodeSite.Send( csmLevel1, '(Session as SessionClass).Cashier.Number', (Session as QSRules_TLB_2_0_0_151.SessionClass).Cashier.Number );
end else
if Supports(Session, QSRules_TLB_2_0_0_105.SessionClass) then
Begin
CodeSite.Send( csmLevel1, '(Session as SessionClass).Cashier.Name', (Session as QSRules_TLB_2_0_0_105.SessionClass).Cashier.Name );
CodeSite.Send( csmLevel1, '(Session as SessionClass).Cashier.Number', (Session as QSRules_TLB_2_0_0_151.SessionClass).Cashier.Number );
end
end;
There is 4 or 5 different versions of dll all with different GUID's bu 98% of code is the same between all of them.
Doing that in this way is unnessesary multiplying the code.
Is there any way that I can shorten it ?
I also tried
procedure TRefreshScreenRefreshScreen.Process(const Session: IDispatch);
var
_Session: SessionClass;
begin
if Supports(Session, QSRules_TLB_2_0_0_151.SessionClass) then
_Session = (Session as QSRules_TLB_2_0_0_151.SessionClass)
else if Supports(Session, QSRules_TLB_2_0_0_105.SessionClass) then
_Session = (Session as QSRules_TLB_2_0_0_105.SessionClass);
with _Session do
Begin
CodeSite.Send( csmLevel1, '_Session.Cashier.Name', Cashier.Name );
CodeSite.Send( csmLevel1, '_Session..Cashier.Number', Cashier.Number );
End;
end;
But this not work because variable type can be assigned only from only unit.
Any help appreciated !
You say that the interfaces have different guids in different versions. That is perfectly fine as long as the newer interfaces derive from the older interfaces. Is that actually the case? If they do, then you can simplify your code by casting your Session object to whatever interface actually defines the Cashier member. You do not need to cast it to each individual interface type unless the interfaces do not derive from each other. Can you show the actual interface declarations?
Cashier declaration from v2.0.0.105
_Cashier = interface(IDispatch)
['{AA84B4FB-AA41-4423-A763-59D0723ED52B}']
function Get_Session: _SessionClass; safecall;
function Get_CashDrawer: _CashDrawer; safecall;
function Get_OverShortLimitType: overshortlimitEnum; safecall;
function Get_MaxOverShortAmount: Currency; safecall;
function Get_MaxOverShortPercent: Double; safecall;
function Get_SecurityLevel: Smallint; safecall;
function Get_HasPrivilege(var CashierPrivilege: cashierprivilegesEnum): WordBool; safecall;
function Get_FailedLogOnAttempts: Integer; safecall;
function Get_EmailAddress: WideString; safecall;
function Get_Messages: _CashierMessages; safecall;
function Get_UnreadMessageCount: Integer; safecall;
function Get_Name: WideString; safecall;
function Get_FirstName: WideString; safecall;
function Get_LastName: WideString; safecall;
function Get_ReturnLimit: Currency; safecall;
function Get_FloorLimit: Currency; safecall;
function Get_ID: Integer; safecall;
function Get_CashDrawerNumber: Smallint; safecall;
function Get_Loaded: WordBool; safecall;
function Get_Number: WideString; safecall;
property Session: _SessionClass read Get_Session;
property CashDrawer: _CashDrawer read Get_CashDrawer;
property OverShortLimitType: overshortlimitEnum read Get_OverShortLimitType;
property MaxOverShortAmount: Currency read Get_MaxOverShortAmount;
property MaxOverShortPercent: Double read Get_MaxOverShortPercent;
property SecurityLevel: Smallint read Get_SecurityLevel;
property HasPrivilege[var CashierPrivilege: cashierprivilegesEnum]: WordBool read Get_HasPrivilege;
property FailedLogOnAttempts: Integer read Get_FailedLogOnAttempts;
property EmailAddress: WideString read Get_EmailAddress;
property Messages: _CashierMessages read Get_Messages;
property UnreadMessageCount: Integer read Get_UnreadMessageCount;
property Name: WideString read Get_Name;
property FirstName: WideString read Get_FirstName;
property LastName: WideString read Get_LastName;
property ReturnLimit: Currency read Get_ReturnLimit;
property FloorLimit: Currency read Get_FloorLimit;
property ID: Integer read Get_ID;
property CashDrawerNumber: Smallint read Get_CashDrawerNumber;
property Loaded: WordBool read Get_Loaded;
property Number: WideString read Get_Number;
end;
Cashier declaration from v2.0.0.151
_Cashier = interface(IDispatch)
['{39B2C128-00F1-4834-B1A4-05197C708BD9}']
function Get_Session: _SessionClass; safecall;
function Get_CashDrawer: _CashDrawer; safecall;
function Get_OverShortLimitType: overshortlimitEnum; safecall;
function Get_MaxOverShortAmount: Currency; safecall;
function Get_MaxOverShortPercent: Double; safecall;
function Get_SecurityLevel: Smallint; safecall;
function Get_HasPrivilege(var CashierPrivilege: cashierprivilegesEnum): WordBool; safecall;
function Get_FailedLogOnAttempts: Integer; safecall;
function Get_EmailAddress: WideString; safecall;
function Get_Messages: _CashierMessages; safecall;
function Get_UnreadMessageCount: Integer; safecall;
function Get_Name: WideString; safecall;
function Get_FirstName: WideString; safecall;
function Get_LastName: WideString; safecall;
function Get_ReturnLimit: Currency; safecall;
function Get_FloorLimit: Currency; safecall;
function Get_ID: Integer; safecall;
function Get_CashDrawerNumber: Smallint; safecall;
function Get_Loaded: WordBool; safecall;
function Get_Number: WideString; safecall;
function Get_PasswordAge: Integer; safecall;
function Get_ReminderPeriod: Integer; safecall;
function Get_PasswordResetFlag: WordBool; safecall;
function Get_IsPasswordChanged: WordBool; safecall;
procedure Set_IsPasswordChanged(var Param1: WordBool); safecall;
function Get_TimecardID: Integer; safecall;
procedure Set_TimecardID(var Param1: Integer); safecall;
function ValidatePassword(var Password: WideString): WordBool; safecall;
function IsPwdDuplicated(var CashierNumber: Integer; var Password: WideString): WordBool; safecall;
property Session: _SessionClass read Get_Session;
property CashDrawer: _CashDrawer read Get_CashDrawer;
property OverShortLimitType: overshortlimitEnum read Get_OverShortLimitType;
property MaxOverShortAmount: Currency read Get_MaxOverShortAmount;
property MaxOverShortPercent: Double read Get_MaxOverShortPercent;
property SecurityLevel: Smallint read Get_SecurityLevel;
property HasPrivilege[var CashierPrivilege: cashierprivilegesEnum]: WordBool read Get_HasPrivilege;
property FailedLogOnAttempts: Integer read Get_FailedLogOnAttempts;
property EmailAddress: WideString read Get_EmailAddress;
property Messages: _CashierMessages read Get_Messages;
property UnreadMessageCount: Integer read Get_UnreadMessageCount;
property Name: WideString read Get_Name;
property FirstName: WideString read Get_FirstName;
property LastName: WideString read Get_LastName;
property ReturnLimit: Currency read Get_ReturnLimit;
property FloorLimit: Currency read Get_FloorLimit;
property ID: Integer read Get_ID;
property CashDrawerNumber: Smallint read Get_CashDrawerNumber;
property Loaded: WordBool read Get_Loaded;
property Number: WideString read Get_Number;
property PasswordAge: Integer read Get_PasswordAge;
property ReminderPeriod: Integer read Get_ReminderPeriod;
property PasswordResetFlag: WordBool read Get_PasswordResetFlag;
property IsPasswordChanged: WordBool read Get_IsPasswordChanged write Set_IsPasswordChanged;
property TimecardID: Integer read Get_TimecardID write Set_TimecardID;
end;
As you can see there is few things added in the later version but there is no doubt that I need to check the software version when calling them functions. Cashier that's only one of 25-30 types there so if I have to write the same basic implementation for all versions .... big task, and horrible code for modifications in later stage.
Finally got it sorted ! Just share the answer in case anyone else looking for it.
The key for success is "late binding", that means you don't use interface.
procedure TRefreshScreenRefreshScreen.Process(const Session: IDispatch);
var
_Session: Variant;
begin
_Session := Session;
CodeSite.Send( csmLevel1, '_Session.Cashier.Name', _Session.Cashier.Name );
CodeSite.Send( csmLevel1, '_Session.Cashier.Number', _Session.Cashier.Number );
end;
With variant variable the functions are not check by compiler but in runtime, so you have to make sure that the spelling is correct because intellisense is not checking it.
Works like a dream !
Thanks all of you anyway !