2012-07-12 11 views
7

Delphi parte:¿Cómo pasar el objeto interconectado a la llamada a la función Pascal Script?

tengo una clase con el evento y de ese evento que tiene que llamar a un procedimiento pasando el objeto de interfaz con él. Funciona bien en Delphi, pero tengo problemas para declararlo en Pascal Script.

Para el fondo - la interfaz IGPGraphics es una parte de la Delphi GDI+ library y sin métodos se define así:

type 
    IGdiplusBase = interface 
    ['{24A5D3F5-4A9B-42A2-9F60-20825E2740F5}'] 
    IGPGraphics = interface(IGdiPlusBase) 
    ['{57F85BA4-CB01-4466-8441-948D03588F54}'] 

El siguiente es sólo un pseudocódigo Delphi simplificada de lo que tengo que hacer en Pascal Script:

type 
    TRenderEvent = procedure(Sender: TObject; const GPGraphics: IGPGraphics) of object; 
    TRenderClass = class(TGraphicControl) 
    private 
    FOnRender: TRenderEvent; 
    public 
    property OnRender: TRenderEvent read FOnRender write FOnRender; 
    end; 

// when the TRenderClass object instance fires its OnRender event I want to call 
// the RenderObject procedure passing the IGPGraphics interfaced object to it; I 
// hope I'm doing it right, I'm just a newbie to this stuff - but it works so far 
// in Delphi (since I didn't get it to work in Pascal Script) 

procedure TForm1.RenderClass1Render(Sender: TObject; const GPGraphics: IGPGraphics); 
begin 
    RenderObject(GPGraphics, 10, 10); 
end; 

// what I need in Pascal Script is between these two lines; just pass the interface 
// object from the event fired by component to the procedure called from inside it 

procedure RenderObject(const GPGraphics: IGPGraphics; X, Y); 
begin 
    // and here to work with the interfaced object somehow 
end; 

Pascal script parte compilación:

Mi objetivo es tener la clase con evento disponible en Pascal Script y necesito pasar ese objeto interconectado a ese procedimiento como el anterior, por lo que el primero que he intentado declarar para el tiempo de compilación esto (pero no estoy seguro si esa es la forma correcta de hacerlo):

// the interface 
PS.AddInterface(Cl.FindInterface('IUnknown'), StringToGuid('{57F85BA4-CB01-4466-8441-948D03588F54}'), 'IGPGraphics'); 
// the type for the event 
PS.AddTypeS('TRenderEvent', 'procedure(Sender: TObject; const GPGraphics: IGPGraphics)'); 
// and the class with the event itself 
with PS.AddClassN(PS.FindClass('TGraphicControl'), 'TRenderClass') do 
begin 
    RegisterProperty('OnRender', 'TRenderEvent', iptrw); 
end; 

Pascal parte de secuencias de comandos en tiempo de ejecución:

Dónde estoy perdido definitivamente es la parte de tiempo de ejecución. No puedo encontrar la manera de obtener el objeto de interfaz de la pila de llamadas y pasarlo a mi procedimiento RenderObject:

function RenderClassProc(Caller: TPSExec; Proc: TPSExternalProcRec; Global, 
    Stack: TPSStack): Boolean; 
var 
    PStart: Cardinal; 
begin 
    PStart := Stack.Count-1; 
    Result := True; 
    if Proc.Name = 'RENDEROBJECT' then 
    begin 
    // how do I get the interfaced object from Stack (or whatever else) and pass 
    // it to the RenderObject proc here ? I can't find anything related about it 
    // except functions that has no parameter index 
    RenderObject(Stack.Get ?, Stack.GetInt(PStart-2), Stack.GetInt(PStart-3)); 
    end; 
end; 

y la pregunta es:

Puede alguien me sugieren cómo ¿Definir correctamente la compilación y la parte del tiempo de ejecución para este caso o corregirme pasando el objeto interconectado de alguna manera?

P.S. perdón por esa etiqueta Inno-Setup, pero tal vez alguien desde allí intentó personalizar InnoSetup de esta manera.

¡Muchas gracias!

Respuesta

1

Si entiendo lo que está preguntando, quiere pasar una interfaz como parámetro a un método. Lamentablemente, no tengo una respuesta exacta para eso, pero sí sé cómo asignar una interfaz a una variable global para PascalScript. Así es como lo hago en Castalia:

En el evento PSScript OnCompile, agregue la interfaz con PS.Comp.AddInterface, y luego agregue cada uno de los métodos necesarios. Después de eso, agregue una variable del tipo de interfaz.Parece que este, por ejemplo:

with PS.Comp.AddInterface(ARunner.Comp.FindInterface('IUnknown'), 
    StringToGUID('{0346F7DF-CA7B-4B15-AEC9-2BDD680EE7AD}'), 
    'ICastaliaMacroClipboardAccess') do 
begin 
    RegisterMethod('function GetText: string', cdRegister); 
    RegisterMethod('procedure SetText(AText: string)', cdRegister); 
end; 
PS.AddRegisteredVariable('Clipboard', 'ICastaliaMacroClipboardAccess'); 

Entonces, en el caso OnExectute, obligar a la variable previamente creada para la instancia:

P := PS.GetVariable('Clipboard'); //P is type PIFVariant 
SetVariantToInterface(P, Implementing object as ICastaliaMacroClipboardAccess);  

Una vez hecho esto, el guión tiene acceso al objeto de interfaz a través de la variable, por lo que en este caso, la secuencia de comandos podría contener una llamada a Clipboard.GetText, y funciona como era de esperar.

Eso está probado y funciona.

Ahora, supongo que es posible que pueda utilizar TPSScript.ExecuteFunction, pasando el PIFVariant desde arriba, para acercarse a lo que desea. Sin embargo, eso no es algo que haya probado.

¡Buena suerte!

1

Es difícil de creer pero he encontrado la manera de hacer que

procedure TApp.CallProcedureWithClassArg(x: TPSExec); 
var 
    o: TSampleObject; 
    argumentList: TPSList; 
    arg1: TPSVariantClass; 
    proc: Integer; 
begin 
    o := TSampleObject.Create; 
    o.X := 1; // do something with the object maybe 
    proc := x.GetProc('TakeThis'); 
    argumentList := TPSList.Create; 
    arg1.VI.FType := x.FindType2(btClass); 
    arg1.Data := o; 
    argumentList.Add(@arg1); 
    x.RunProc(argumentList, proc); 
    argumentList.Free; 
end; 

Esto es básicamente lo que debe hacerse.

  • usuario de la instancia TPSExec, digamos x
  • A continuación, obtener el número de procedimiento utilizando el método x.GetProc
  • luego crear la lista de argumentos de tipo TPSList
  • Crear TPSVariantClass var, asigne la instancia de la clase (que debe ser aprobado) a su campo de datos
  • también asignar x.FindType2 (btClass) a su campo VI.FType (no tienen absolutamente ninguna idea de por qué esto funciona)
  • añadir un puntero a la variable TPSVariantClass a la lista TPSList
  • Y ....... Llame al procedimiento x.RunProc (argList, proc); donde proc es el número del procedimiento obtenido anteriormente

Esto funciona para las clases, pero no debería ser muy diferente para las interfaces, sólo tiene que utilizar el tipo TPSVariantInterface para la variable argumento en lugar de TPSVariantClass; todo lo demás debe ser el mismo.

Espero que esto ayude a alguien tal vez.

Cuestiones relacionadas