I have created this unit containing a class derived from TXmlIniFile:
unit PAXMLIniFile;
interface
uses
System.SysUtils,
System.IniFiles,
Xml.XmlDoc,
Xml.XMLIntf,
Xml.XMLIniFile;
type
TMyStandaloneXmlIniFile = class(TXmlIniFile)
strict private
FDocument: IXMLDocument;
FFileName: string;
public
constructor Create(const AFileName: string);
procedure UpdateFile; override;
end;
implementation
constructor TMyStandaloneXmlIniFile.Create(const AFileName: string);
begin
if FileExists(AFileName) then
FDocument := LoadXMLDocument(AFileName)
else
begin
FDocument := NewXMLDocument;
FDocument.Options := FDocument.Options + [doNodeAutoIndent];
end;
if FDocument.DocumentElement = nil then
FDocument.DocumentElement := FDocument.CreateNode('Sections');
TCustomIniFile(Self).Create(AFileName);
FFileName := AFileName;
inherited Create(FDocument.DocumentElement);
end;
procedure TMyStandaloneXmlIniFile.UpdateFile;
begin
FDocument.SaveToFile(FFileName);
end;
end.
Now whenever I call the UpdateFile method I get an error message "Wrong parameter". What is wrong here?
Here is the test program:
program BonkersTest;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, PAXMLIniFile, Winapi.ActiveX;
var
MyStandaloneXmlIniFile: TMyStandaloneXmlIniFile;
MyXmlFile: string;
begin
try
CoInitialize(nil);
MyXmlFile := ChangeFileExt(ParamStr(0), '.xml');
MyStandaloneXmlIniFile := TMyStandaloneXmlIniFile.Create(MyXmlFile);
try
MyStandaloneXmlIniFile.WriteString('Section1', 'Ident1', 'Value1');
MyStandaloneXmlIniFile.UpdateFile;
finally
MyStandaloneXmlIniFile.Free;
end;
CoUninitialize;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Related
I would like to create a Windows Service (with Delphi) that will attempt, every hour, to retrieve a specific file from a specific Amazon S3 Bucket.
I have no problem accessing the Amazon S3 Bucket with my VCL application. However, if I try to run the same function through my Windows Service, it returns absolutely nothing. I believe that it is a permission issue: my Service does not permission to access the outside world.
What should I do to remedy my problem?
I am using Delphi Tokyo Update 3, my Service is built upon a DataSnap Server.
Here is the code for my 'server container' unit:
unit UnitOurDataSnapServerContainer;
interface
uses
System.SysUtils, System.Classes, System.Win.Registry, Vcl.SvcMgr,
Datasnap.DSTCPServerTransport,
Datasnap.DSServer, Datasnap.DSCommonServer,
IPPeerServer, IPPeerAPI, Datasnap.DSAuth;
type
TServerContainer_OurCompany = class(TService)
DSServer_OurCompany: TDSServer;
DSServerClass_OurCompany: TDSServerClass;
DSTCPServerTransport_OurCompany: TDSTCPServerTransport;
procedure DSServerClass_OurCompanyGetClass(DSServerClass: TDSServerClass; var PersistentClass: TPersistentClass);
procedure ServiceStart(Sender: TService; var Started: Boolean);
private
{ Private declarations }
protected
function DoStop: Boolean; override;
function DoPause: Boolean; override;
function DoContinue: Boolean; override;
procedure DoInterrogate; override;
public
function GetServiceController: TServiceController; override;
end;
var
ServerContainer_OurCompany: TServerContainer_OurCompany;
implementation
{$R *.dfm}
uses
Winapi.Windows,
UnitOurDataSnapServerMethods;
procedure TServerContainer_OurCompany.DSServerClass_OurCompanyGetClass(DSServerClass: TDSServerClass; var PersistentClass: TPersistentClass);
begin
PersistentClass := UnitOurDataSnapServerMethods.TOurDataSnapServerMethods;
end;
procedure ServiceController(CtrlCode: DWord); stdcall;
begin
ServerContainer_OurCompany.Controller(CtrlCode);
end;
function TServerContainer_OurCompany.GetServiceController: TServiceController;
begin
Result := ServiceController;
end;
function TServerContainer_OurCompany.DoContinue: Boolean;
begin
Result := inherited;
DSServer_OurCompany.Start;
end;
procedure TServerContainer_OurCompany.DoInterrogate;
begin
inherited;
end;
function TServerContainer_OurCompany.DoPause: Boolean;
begin
DSServer_OurCompany.Stop;
Result := inherited;
end;
function TServerContainer_OurCompany.DoStop: Boolean;
begin
DSServer_OurCompany.Stop;
Result := inherited;
end;
procedure TServerContainer_OurCompany.ServiceStart(Sender: TService; var Started: Boolean);
begin
{$IFDEF RELEASE}
DSServer_OurCompany.HideDSAdmin := True;
{$ENDIF}
DSServer_OurCompany.Start;
end;
end.
Here is the code for my 'servermethods' unit:
unit UnitOurDataSnapServerMethods;
interface
uses
System.SysUtils, System.Classes, Datasnap.DSServer, Datasnap.DSAuth;
type
{$METHODINFO ON}
TOurDataSnapServerMethods = class(TComponent)
private
{ Private declarations }
public
{ Public declarations }
function Get_ListOfFilesInS3Bucket(aS3Path: String; aFileExtension: String) : Integer;
end;
{$METHODINFO OFF}
implementation
uses
Data.Cloud.CloudAPI, Data.Cloud.AmazonAPI;
function TOurDataSnapServerMethods.Get_ListOfFilesInS3Bucket(aS3Path: String; aFileExtension: String) : Integer;
var
iFileList: TStrings;
iFileExtension: String;
iOptionalParams: TStrings;
iResponseInfo: TCloudResponseInfo;
iStorageService: TAmazonStorageService;
iAmazonBucketResult: TAmazonBucketResult;
iAmazonObjectResult: TAmazonObjectResult;
iAmazonConnectionInfo: TAmazonConnectionInfo;
begin
Result := 0;
iFileExtension := aFileExtension;
if Pos('.', iFileExtension) = 0 then
iFileExtension := '.' + iFileExtension;
try
iAmazonConnectionInfo := TAmazonConnectionInfo.Create(nil);
iAmazonConnectionInfo.AccountName := 'AKIA****************';
iAmazonConnectionInfo.AccountKey := 'BzNn************************************';
iOptionalParams := TStringList.Create;
iOptionalParams.Values['prefix'] := aS3Path;
iStorageService := TAmazonStorageService.Create(iAmazonConnectionInfo);
iResponseInfo := TCloudResponseInfo.Create;
iAmazonBucketResult := nil;
iFileList := TStringList.Create;
try
iAmazonBucketResult := iStorageService.GetBucket('our-s3-bucket', iOptionalParams, iResponseInfo);
for iAmazonObjectResult in iAmazonBucketResult.Objects do
begin
if Pos(iFileExtension, iAmazonObjectResult.Name) <> 0 then
iFileList.Add(iAmazonObjectResult.Name);
end;
Result := iFileList.Count;
except
on e: Exception do
;
end;
FreeAndNil(iAmazonBucketResult);
finally
iFileList.Free;
iResponseInfo.Free;
iStorageService.Free;
iOptionalParams.Free;
iAmazonConnectionInfo.Free;
end;
end;
end.
It is the call to 'iStorageService.GetBucket' that returns nothing.
I'd like to create an aspect-aware interfaced dependency-injected object through the means of the Spring/4D framework. My issue is, that I don't know how to combine both parts. The general idea is the following:
Create the aspect layer object and hold two interfaces to it: one to pass as the dependency to the object (IAspect) and one to weave in as aspect into the object (IInterceptor):
Temp := TAspect.Create;
Aspect := Temp as IAspect;
Interceptor := Temp as IInterceptor;
Create the interfaced dependency-injected object:
Instance := TInstance.Create(Aspect) {as IInstance};
Weave in the aspect:
Result := TProxyGenerator.CreateInterfaceProxyWithTarget(Instance, [Interceptor]);
To solve this, I think of registering a factory with a custom constructor along these lines:
Aspect := Resolve<IAspect>;
Interceptor := Aspect as IInterceptor;
Instance := InstanceFactory(Aspect); // InstanceFactory := Resolve<IInstanceFactory>;
Result := TProxyGenerator.CreateInterfaceProxyWithTarget(Instance, [Interceptor]);
My issue is, how would I register this with the Container: TContainer from Spring?
Example: The program below behaves like I want and demonstrates through which aspect layers the GetValue call runs. The custom object creation hapens in the $Region in the main routine. How would I need to refactor this program to use the DI container from the Spring/4D framework, yet keep the custom construction of an aspect-aware object?
program Project1;
{$AppType Console}
{$R *.res}
uses
System.SysUtils,
Spring,
Spring.Interception;
type
IAspect = interface
['{AF8E19F6-176D-490E-A475-4682336CAB89}']
function GetSetting: String;
procedure SetSetting(const Value: String);
property Setting: String read GetSetting write SetSetting;
end;
TAspect = class (TInterfacedObject, IInterceptor, IAspect)
strict private
FSetting: String;
function GetSetting: String;
procedure SetSetting(const Value: String);
procedure Intercept(const Invocation: IInvocation);
public
constructor Create;
end;
IThingy = interface (IInvokable)
function GetAspect: IAspect;
function GetValue: String;
procedure SetValue(const Value: String);
property InstanceAspect: IAspect read GetAspect;
property Value: String read GetValue write SetValue;
end;
TThingy = class (TInterfacedObject, IThingy)
strict private
FInstanceAspect: IAspect;
FClassAspect: IAspect;
FValue: String;
function GetAspect: IAspect;
function GetValue: String;
procedure SetValue(const Value: String);
public
constructor Create(const InstanceAspect, ClassAspect: IAspect);
end;
{ TAspect }
constructor TAspect.Create;
begin
inherited;
FSetting := ' intercepted by class aspect';
end;
function TAspect.GetSetting: String;
begin
Result := FSetting;
end;
procedure TAspect.Intercept(
const Invocation: IInvocation);
begin
Invocation.Proceed;
if Invocation.Method.Name = 'GetValue' then
Invocation.Result := TValue.From<String>(Invocation.Result.AsString + FSetting);
end;
procedure TAspect.SetSetting(
const Value: String);
begin
FSetting := Value;
end;
{ TThingy }
constructor TThingy.Create(const InstanceAspect, ClassAspect: IAspect);
begin
inherited Create;
FInstanceAspect := InstanceAspect;
FClassAspect := ClassAspect;
FValue := 'Value';
end;
function TThingy.GetAspect: IAspect;
begin
Result := FInstanceAspect;
end;
function TThingy.GetValue: String;
begin
Result := FValue;
end;
procedure TThingy.SetValue(const Value: String);
begin
FValue := Value;
end;
{ Main }
procedure Main;
var
Temp: TInterfacedObject;
ClassAspect: IAspect;
ClassInterceptor: IInterceptor;
InstanceAspect: IAspect;
InstanceInterceptor: IInterceptor;
Thingy1: IThingy;
Thingy2: IThingy;
begin
{$Region 'How to do this with the Spring DI container?'}
Temp := TAspect.Create;
ClassAspect := Temp as IAspect;
ClassInterceptor := Temp as IInterceptor;
Temp := TAspect.Create;
InstanceAspect := Temp as IAspect;
InstanceInterceptor := Temp as IInterceptor;
Thingy1 := TThingy.Create(InstanceAspect, ClassAspect);
Thingy1 := TProxyGenerator.CreateInterfaceProxyWithTarget(Thingy1, [ClassInterceptor, InstanceInterceptor]);
Temp := TAspect.Create;
InstanceAspect := Temp as IAspect;
InstanceInterceptor := Temp as IInterceptor;
Thingy2 := TThingy.Create(InstanceAspect, ClassAspect);
Thingy2 := TProxyGenerator.CreateInterfaceProxyWithTarget(Thingy2, [ClassInterceptor, InstanceInterceptor]);
{$EndRegion}
Thingy1.InstanceAspect.Setting := ' intercepted by instance aspect 1';
Thingy2.InstanceAspect.Setting := ' intercepted by instance aspect 2';
Thingy1.Value := 'Value 1';
Thingy2.Value := 'Value 2';
WriteLn(Format('Thingy1.Value: %s', [Thingy1.Value]));
WriteLn(Format('Thingy2.Value: %s', [Thingy2.Value]));
end;
begin
try
Main;
except
on E: Exception do
WriteLn(E.ClassName, ': ', E.Message);
end;
if DebugHook <> 0 then
begin
WriteLn('Press enter...');
ReadLn;
end;
end.
Output:
Thingy1.Value: Value 1 intercepted by instance aspect 1 intercepted by class aspect
Thingy2.Value: Value 2 intercepted by instance aspect 2 intercepted by class aspect
Press enter...
I am not completely sure what exactly you are trying to achieve but here it how to setup the container to get the result you are looking for. What does not work yet is contextual injection (making decisions during the resolve process that are based on the currently built object graph) - this is something we are planning to implement in the future.
program Project1;
{$AppType Console}
{$R *.res}
uses
System.SysUtils,
Spring,
Spring.Container,
Spring.Interception;
type
IThingy = interface (IInvokable)
['{FD337CC6-03EB-4384-A027-E993AB687BF0}']
function GetValue: String;
procedure SetValue(const Value: String);
property Value: String read GetValue write SetValue;
end;
TThingy = class (TInterfacedObject, IThingy)
strict private
FValue: String;
function GetValue: String;
procedure SetValue(const Value: String);
end;
{ TThingy }
function TThingy.GetValue: String;
begin
Result := FValue;
end;
procedure TThingy.SetValue(const Value: String);
begin
FValue := Value;
end;
type
TClassInterceptor = class(TInterfacedObject, IInterceptor)
procedure Intercept(const Invocation: IInvocation);
end;
TInstanceInterceptor = class(TInterfacedObject, IInterceptor)
private
class var InstanceCount: Integer;
var FNo: Integer;
procedure Intercept(const Invocation: IInvocation);
public
constructor Create;
end;
{ Main }
procedure Main;
var
Thingy1: IThingy;
Thingy2: IThingy;
begin
GlobalContainer.RegisterType<TClassInterceptor,TClassInterceptor>.AsSingleton;
GlobalContainer.RegisterType<TInstanceInterceptor>('instance');
GlobalContainer.RegisterType<IThingy, TThingy>.InterceptedBy<TClassInterceptor>.InterceptedBy('instance');
GlobalContainer.Build;
Thingy1 := GlobalContainer.Resolve<IThingy>;
Thingy2 := GlobalContainer.Resolve<IThingy>;
Thingy1.Value := 'Value 1';
Thingy2.Value := 'Value 2';
WriteLn(Format('Thingy1.Value: %s', [Thingy1.Value]));
WriteLn(Format('Thingy2.Value: %s', [Thingy2.Value]));
end;
procedure TClassInterceptor.Intercept(const Invocation: IInvocation);
begin
Invocation.Proceed;
if Invocation.Method.Name = 'GetValue' then
Invocation.Result := TValue.From<String>(Invocation.Result.AsString + ' intercepted by class aspect');
end;
constructor TInstanceInterceptor.Create;
begin
Inc(InstanceCount);
FNo := InstanceCount;
end;
procedure TInstanceInterceptor.Intercept(const Invocation: IInvocation);
begin
Invocation.Proceed;
if Invocation.Method.Name = 'GetValue' then
Invocation.Result := TValue.From<String>(Invocation.Result.AsString + ' intercepted by instance aspect ' + IntToStr(FNo));
end;
begin
try
Main;
except
on E: Exception do
WriteLn(E.ClassName, ': ', E.Message);
end;
if DebugHook <> 0 then
begin
WriteLn('Press enter...');
ReadLn;
end;
end.
Hi I have a problem with the following code:
program test;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, idIRC, idContext, idGlobal;
// procedure TForm1.IdIRC1PrivateMessage(ASender: TIdContext; const ANickname,
// AHost, ATarget, AMessage: string);
// procedure TForm1.IdIRC1Raw(ASender: TIdContext; AIn: Boolean;
// const AMessage: string);
procedure IrcPrivateMessage(ASelf: Pointer; const ANickname, AHost, ATarget,
AMessage: string);
begin
Writeln('[+] Message ' + ANickname + ' > ' + AMessage);
end;
procedure IrcRaw(ASelf: Pointer; ASender: TIdContext; AIn: Boolean;
const AMessage: String);
begin
Writeln(iif(AIn, '[Recv] ', '[Sent] ') + AMessage);
end;
var
irc: TIdIRC;
m1: TMethod;
m2: TMethod;
begin
try
irc := TIdIRC.Create(nil);
try
irc.Host := 'localhost';
irc.Port := 6667;
irc.Nickname := 'tester';
irc.Username := 'tester';
m1.Code := #IrcRaw;
m1.Data := irc;
irc.OnRaw := TIdIRCRawEvent(m1);
m2.Code := #IrcPrivateMessage;
m2.Data := irc;
irc.OnPrivateMessage := TIdIRCPrivMessageEvent(m2);
try
irc.Connect;
except
Writeln('Nay');
Exit;
end;
Writeln('Yeah');
irc.Join('#locos');
while ('1' = '1') do
begin
//
end;
finally
irc.Free;
end;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
The problem is when I receive a private message, the ANickname entry gives me the following error:
Project test.exe raised exeption class #C00000005 with message 'access violation at 0x00404673:read of adress 0x03cf4e58
What am I doing wrong?
TIdIRCPrivMessageEvent is a "procedures of object", which implicitly references the object. You added a Self parameter for that, but you omitted the TIdContext parameter that is also part of the event:
procedure IrcPrivateMessage(ASelf: Pointer; Sender: TIdContext; const ANickname, AHost, ATarget, AMessage: string);
begin
....
end;
Is it possible to inspect the RTTI information for an instance of a generic type with an interface type constraint? The question is probably a little ambiguous so I've created a sample console app to show what I'm trying to do:
program Project3;
{$APPTYPE CONSOLE}
uses
RTTI,
SysUtils,
TypInfo;
type
TMyAttribute = class(TCustomAttribute)
strict private
FName: string;
public
constructor Create(AName: string);
property Name: string read FName;
end;
IMyObjectBase = interface
['{E063AD44-B7F1-443C-B9FE-AEB7395B39DE}']
procedure DoSomething;
end;
TMyObjectBase = class(TInterfacedObject, IMyObjectBase)
public
procedure DoSomething; virtual;
end;
[TMyAttribute('First')]
TMyFirstRealClass = class(TMyObjectBase)
public
procedure DoSomethingDifferent;
end;
[TMyAttribute('Second')]
TMySecondRealClass = class(TMyObjectBase)
public
procedure BeSomethingDifferent;
end;
TGenericClass<I: IMyObjectBase> = class
public
function GetAttributeName(AObject: I): string;
end;
{ TMyAttribute }
constructor TMyAttribute.Create(AName: string);
begin
FName := AName;
end;
{ TMyObjectBase }
procedure TMyObjectBase.DoSomething;
begin
end;
{ TMyFirstRealClass }
procedure TMyFirstRealClass.DoSomethingDifferent;
begin
end;
{ TMySecondRealClass }
procedure TMySecondRealClass.BeSomethingDifferent;
begin
end;
{ TGenericClass<I> }
function TGenericClass<I>.GetAttributeName(AObject: I): string;
var
LContext: TRttiContext;
LProp: TRttiProperty;
LAttr: TCustomAttribute;
begin
Result := '';
LContext := TRttiContext.Create;
try
for LAttr in LContext.GetType(AObject).GetAttributes do
// ----> [DCC Error] E2250 There is no overloaded version of 'GetType' that can be called with these arguments
if LAttr is TMyAttribute then
begin
Result := TMyAttribute(LAttr).Name;
Break;
end;
finally
LContext.Free;
end;
end;
var
LFirstObject: IMyObjectBase;
LSecondObject: IMyObjectBase;
LGeneric: TGenericClass<IMyObjectBase>;
begin
try
LFirstObject := TMyFirstRealClass.Create;
LSecondObject := TMySecondRealClass.Create;
LGeneric := TGenericClass<IMyObjectBase>.Create;
Writeln(LGeneric.GetAttributeName(LFirstObject));
Writeln(LGeneric.GetAttributeName(LSecondObject));
LGeneric.Free;
LFirstObject := nil;
LSecondObject := nil;
Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
I need to inspect the object being passed in (AObject), not the generic interface (I).
(Dephi 2010).
Thanks for any advice.
Two possible solutions for this is as follows:
1) I tested with this and it works (XE4):
for LAttr in LContext.GetType((AObject as TObject).ClassType).GetAttributes do
2) I tested with this and it works (XE4):
for LAttr in LContext.GetType(TMyObjectBase(AObject).ClassType).GetAttributes do
3) Create method on the interface that returns the object and use that to inspect the object:
IMyObjectBase = interface
['{E063AD44-B7F1-443C-B9FE-AEB7395B39DE}']
procedure DoSomething;
function GetObject: TObject;
end;
TMyObjectBase = class(TInterfacedObject, IMyObjectBase)
public
procedure DoSomething; virtual;
function GetObject: TObject;
end;
{ TMyObjectBase }
function TMyObjectBase.GetObject: TObject;
begin
Result := Self;
end;
And then call it like this:
for LAttr in LContext.GetType(AObject.GetObject.ClassType).GetAttributes do
I'm trying to execute this code (this is a minimal sample in order to use CreateOleObject) from inside of a dwscript
function GetFileVersion(const FileName: string): string;
var
V : OleVariant;
begin
V := CreateOleObject('Scripting.FileSystemObject');
Result := V.GetFileVersion(FileName);
end;
So far i tried this
{$APPTYPE CONSOLE}
{$R *.res}
uses
SysUtils,
ComObj,
ActiveX,
dwsComp,
dwsCompiler,
dwsExprs,
dwsCoreExprs;
procedure Execute;
var
LScript: TDelphiWebScript;
LUnit: TdwsUnit;
LProg: IdwsProgram;
LExec: IdwsProgramExecution;
begin
LScript := TDelphiWebScript.Create(NIL);
LUnit := TdwsUnit.Create(NIL);
try
LUnit.UnitName := 'Foo';
LUnit.Script := LScript;
// compile a simple script
LProg := LScript.Compile(
'function GetFileVersion(const FileName: string): string;'+sLineBreak+
'var'+sLineBreak+
' V : Variant;'+sLineBreak+
'begin'+sLineBreak+
' V := CreateOleObject(''Scripting.FileSystemObject'');'+sLineBreak+
' Result := V.GetFileVersion(FileName);'+sLineBreak+
'end;'+sLineBreak+
''+sLineBreak+
'PrintLn(GetFileVersion(''Foo''));'+sLineBreak+
''
);
if LProg.Msgs.HasErrors then begin
Writeln(LProg.Msgs.AsInfo);
Exit;
end;
try
LExec := LProg.Execute;
except
on E: Exception do
WriteLn(E.Message + sLineBreak + LExec.Msgs.AsInfo );
end;
Writeln(LExec.Result.ToString);
finally
LScript.Free;
end;
end;
begin
try
Execute;
Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
But i'm getting this error message
Syntax Error: Unknown name "CreateOleObject" [line: 5, column: 8]
the question is how i can execute the CreateOleObject function using dwscript?
UPDATE
Following the Linas suggestions I could finally resolve the issue.
This is a sample working application
uses
SysUtils,
ComObj,
ActiveX,
dwsComp,
dwsCompiler,
dwsExprs,
dwsComConnector,
dwsCoreExprs;
procedure Execute;
var
LScript: TDelphiWebScript;
LUnit: TdwsUnit;
LProg: IdwsProgram;
LExec: IdwsProgramExecution;
LdwsComConnector : TdwsComConnector;
begin
LScript := TDelphiWebScript.Create(NIL);
LdwsComConnector:=TdwsComConnector.Create(nil);
LdwsComConnector.Script:=LScript;
LUnit := TdwsUnit.Create(NIL);
try
LUnit.UnitName := 'Foo';
LUnit.Script := LScript;
// compile a simple script
LProg := LScript.Compile(
'function GetFileVersion(const FileName: string): string;'+sLineBreak+
'var'+sLineBreak+
' V : OleVariant;'+sLineBreak+
'begin'+sLineBreak+
' V := CreateOleObject(''Scripting.FileSystemObject'');'+sLineBreak+
' Result := VarToStr(V.GetFileVersion(FileName));'+sLineBreak+
'end;'+sLineBreak+
''+sLineBreak+
'PrintLn(GetFileVersion(''C:\Bar\Foo.exe''));'+sLineBreak+
''
);
if LProg.Msgs.HasErrors then begin
Writeln(LProg.Msgs.AsInfo);
Exit;
end;
try
LExec := LProg.Execute;
except
on E: Exception do
WriteLn(E.Message + sLineBreak + LExec.Msgs.AsInfo );
end;
Writeln(LExec.Result.ToString);
finally
LScript.Free;
LdwsComConnector.Free;
end;
end;
begin
try
CoInitialize(nil);
try
Execute;
Readln;
finally
CoUninitialize;
end;
except
on E:Exception do
Writeln(E.Classname, ':', E.Message);
end;
end.
This can be accomplished in two ways.
1 way: You must drop TdwsComConnector (from unit dwsComConnector) to your data module or form (or create it manually) and assign your script instance to it. e.g.:
dwsComConnector1.Script := LScript;
2 way:
interface
uses
dwsFunctions, dwsSymbols, dwsExprs;
type
TCreateOleObjectFunc = class(TInternalFunction)
procedure Execute(info : TProgramInfo); override;
end;
implementation
uses
OleAuto;
{ TCreateOleObjectFunc }
procedure TCreateOleObjectFunc.Execute(info : TProgramInfo);
begin
Info.ResultAsVariant := CreateOleObject(Info.ValueAsString['ClassName']);
end;
initialization
RegisterInternalFunction(TCreateOleObjectFunc, 'CreateOleObject', ['ClassName', cString], cVariant, True);
This will expose CreateOleObject function to DWScript so you could use it.
Also you should declare your V as OleVariant instead of Variant and change the line to Result := VarToStr(V.GetFileVersion(FileName)); to make it work properly.