22 de setembro de 2009

Acrescentando suporte a Scripts em aplicações Delphi - parte 5

Prosseguindo o assunto iniciado no post anterior, vou mostrar aqui o código para fazer funcionar a manupulação de variáveis do meu programa dentro dos scripts.

A primeira providência é criar uma estrutura com as informações que poderão ser manipuladas, isto é, o saldo e a cor do Form. O Form então manterá uma instância dessa estrutura e poderá passá-la para a interface que criei no outro post usando para isso a função InitData:
{ A estrutura ...}
DoublePtr = ^Double;
TWDados = record
Saldo : DoublePtr;
ParentForm : TForm;
end;
TWDadosPtr = ^TWDados;

Veja que criei o Saldo como um ponteiro para Double. A intenção é que esta estrutura sirva de ponte para variáveis reais do meu programa. Assim, quando o script referenciar o Saldo estará referenciando exatamente a mesma variável que existe internamente no programa.

Agora, o Form pode criar uma instância de classe que implementa a nossa interface e transferir para ela a estrutura alimentada. O IDE do Delphi monta automaticamente uma classe (a CoClass) que cria tal instância, ligando a interface a uma classe concreta, que no nosso caso é a TExemplo, cujo esqueleto também foi montado pelo IDE do Delphi.
{ A classe TExemplo }
TExemplo = class(TAutoObject, IExemplo)
private
_Dados : TWDadosPtr;
{ ...}
end;

{ No construtor do Form }
_Saldo := 0;
_Dados.Saldo := @_Saldo;
_Dados.ParentForm := Self;

_VarExemplo := CoExemplo.Create;
_VarExemplo.InitData(@_Dados);
{ ...}

Observe a declaração da classe TExemplo : ela é uma herança do TAutoObject (um objeto COM para automação, definindo o programa como um COM Server) e também implementa a interface IExemplo, com as propriedades e métodos que planejamos permitir interação através de scripts. Como ela é a classe concreta para a interação, inclui nela um membro do tipo TWDadosPtr para receber a estrutura que é mantida pelo Form.

Ao preencher os esqueletos de métodos gerados pelo Delphi para a classe concreta TExemplo, usamos a estrutura informada pelo InitData. Por exemplo:
procedure TExemplo.InitData(AInfo: PChar);
begin
_Dados := TWDadosPtr (AInfo);
end;

function TExemplo.Get_CorForm: Integer;
begin
Result := integer (_Dados.ParentForm.Color);
end;

function TExemplo.Get_Saldo: Double;
begin
Result := _Dados.Saldo^;
end;

O que a função CoExemplo.Create retorna é um ponteiro para a interface e não para a classe concreta. Por isso, _VarExemplo deve ser declarada no Form como sendo do tipo interface.
private
_VarExemplo: IExemplo;

Só falta incluir a variável do programa no engine do Script Control para permitir que ela seja acessada por scripts. Para isso, basta usar o método AddObject.
_ScriptControl.AddObject('Vars', _VarExemplo, true);

O nome Vars passa a representar a instância de nossa interface nos scripts. Então, o código abaixo é reconhecido como válido para um script executado por nosso programa:
Vars.Saldo = Vars.Saldo + 1
Vars.CorForm = RGB (0, 255, 0)

O programa completo com os exemplos incluídos nos posts sobre Script com Delphi (incluindo o executável, os fontes e a type library) pode ser baixado neste link.

4 comentários :

Gustavo Katel disse...

cara pode me mostrar como adicionar um componente com o addobject?

Luís Gustavo Fabbro disse...

Gustavo

Qualquer objeto - incluindo componentes - que implemente a interface IDispatch pode ser adicionado diretamente com o AddObject.

Para os componentes que não fazem essa implementação, você terá que criar uma classe "wrapper" (envólucro) para publicar as propriedades e métodos que desejar. Neste caso, o caminho é exatamente o mesmo usado no exemplo desse post para a propriedade de cor do Form.

Gustavo Katel disse...

obrigado existe a possibilidade de realizar o msm procedimento ou algo parecido em c#?

Luís Gustavo Fabbro disse...

Gustavo
O Script Control é distribuído como um componente COM. Isso significa que pode ser utilizado exatamente do mesmo modo no .NET, bastando incluir em seu projeto uma referência à biblioteca COM.

O.NET, no entanto, possui recursos nativos para permitir scripting dinâmico. Dê uma pesquisada na classe CSharpCodeProvider. Há exemplo do uso dela neste site.

Postar um comentário

OBS: Os comentários enviados a este Blog são submetidos a moderação. Por isso, eles serão publicados somente após aprovação.

Observação: somente um membro deste blog pode postar um comentário.