Legalność automatyzacji OLE

0

Mam pytanie odnośnie wyciągania metod z obiektów. Wiem że istnieje coś takiego jak RTTI. Chodzi mi o to że mam zmienną typu OLEVariant, i podstawiam sobie do niej :

V := CreateOLEObject('Excel.Application');

no i teraz mogę się bawić excelem. Pytania mam właściwie dwa :

  1. Jak wyciągnąć dostępne metody dla tej zmiennej (coś jak GetPropList) ?

  2. Jak wywołać jakąś metodę znająć jej nazwę, lub przypisać wartość do jakiejść właściwości, znając nazwę właściwości ?

Właściwie to zapytam od razu odnośnie prawnego aspektu techniki OLE. Jak widać aby przypisać do zmiennej V obiekt Excela nie muszę tego robić z poziomu kodu. Mogę przeciez zrobić

V := CreateOLEObject(Edit1.Text);

Moje pytanie odnoście listy metod i wywoływania metod, wywodzi się właśnie z tąd - czy muszę mieć licencje do programu (tutaj Excel) jeśli korzystam z techniki OLE ? Jeśli istniała by pewna procedura :

WywołajMetodę(V : OLEVariant; NazwaMetody : String;);

która wywołanie postaci

WywołajMetodę(V,'Quit');

zamieniała by na

V.Quit;

to można by zostawić na formie puste kontrolki TEdit, i niech użytkownik sam sobie powpisuje Excel.Application , Quit i inne rzeczy, i używa Excela, jeśli oczywiście ma licencje. Idać dalej można by rozpowszechniać, powiedzmy pliki *.ini zaierające te metody. Użytkowik wczytał by sobie tylko taki plik i miał zaimplementowaną obsługę Excela. No a programista przeciez moze chyba rozpowszechniac zwykle pliki *.ini ?

Mam nadzieje że mnie ktoś zrozumie, a jeszcze większą mam nadzieje że ktoś udzieli mi wyczerpujących odpowiedzi.

Jeśli komuś pomogą szczegóły to chodzi mi o :

Temat : "Prawa autorskie"
Grupa : http://discussion.bentley.com/cgi-bin/dnewsweb.exe?cmd=xover&group=bentley.general.pl&utag=

0

RTTI jak widać daje duże możliwości, związane z dynamiką programu. Co do odpalania metody zapraszam do artykułów, gdzie pokazałem przykład takiego użycia (pod warunkiem znajomości nazwy metody danej klasy). Znalazłem taki przykład programu na wyciąganie listy metod (może się przyda):

unit MainFrm;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ExtCtrls, DBClient, MidasCon, MConnect;

type

  TMainForm = class(TForm)
    lbSampMethods: TListBox;
    lbMethodInfo: TMemo;
    lblBasicMethodInfo: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure lbSampMethodsClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  MainForm: TMainForm;

implementation
uses TypInfo, DBTables, Provider;

{$R *.DFM}

type
  // konieczna jest redefinicja poniższej struktury - jest ona
  // wykomentowana w typinfo.pas

  PParamRecord = ^TParamRecord;
  TParamRecord = record
    Flags:     TParamFlags;
    ParamName: ShortString;
    TypeName:  ShortString;
  end;

procedure GetBaseMethodInfo(ATypeInfo: PTypeInfo; AStrings: TStrings);
{
  Niniejsza metoda pobiera kilka informacji o typie i wpisuje je
  na podaną listę łańcuchów
}
var
  MethodTypeData: PTypeData;
  EnumName: String;
begin
  MethodTypeData := GetTypeData(ATypeInfo);
  with AStrings do
  begin
    Add(Format('Nazwa metody:     %s', [ATypeInfo^.Name]));
    EnumName := GetEnumName(TypeInfo(TTypeKind), Integer(ATypeInfo^.Kind));
    Add(Format('Typ:           %s', [EnumName]));
    Add(Format('Liczba parametrów: %d',[MethodTypeData.ParamCount]));
  end;
end;

procedure GetMethodDefinition(ATypeInfo: PTypeInfo; AStrings: TStrings);
{
  Niniejsza metoda pobiera informację o definicji metody i wpisuje ją
  na podaną listę łańcuchów
}

var
  MethodTypeData: PTypeData;
  MethodDefine:   String;
  ParamRecord:    PParamRecord;
  TypeStr:        ^ShortString;
  ReturnStr:      ^ShortString;
  i: integer;
begin
  MethodTypeData := GetTypeData(ATypeInfo);

  // Określ typ metody
  case MethodTypeData.MethodKind of
    mkProcedure:      MethodDefine := 'procedure ';
    mkFunction:       MethodDefine := 'function ';
    mkConstructor:    MethodDefine := 'constructor ';
    mkDestructor:     MethodDefine := 'destructor ';
    mkClassProcedure: MethodDefine := 'class procedure ';
    mkClassFunction:  MethodDefine := 'class function ';
  end;

  // wskaźnik do pierwszego parametru
  ParamRecord    := @MethodTypeData.ParamList;
  i := 1; // pierwszy parametr

  // pobieraj kolejno informację o kolejnych parametrach,
  // tworząc deklarację metody


  while i <= MethodTypeData.ParamCount do
  begin
    if i = 1 then
      MethodDefine := MethodDefine+'(';

    if pfVar in ParamRecord.Flags then
      MethodDefine := MethodDefine+('var ');
    if pfconst in ParamRecord.Flags then
      MethodDefine := MethodDefine+('const ');
    if pfArray in ParamRecord.Flags then
      MethodDefine := MethodDefine+('array of ');

// ustawiona flaga pfAddress oznacza NIEJAWNY parametr Self, którego
// nie wykazujemy w informacji o metodzie

{
    if pfAddress in ParamRecord.Flags then
      MethodDefine := MethodDefine+('*address* ');
}
    if pfout in ParamRecord.Flags then
      MethodDefine := MethodDefine+('out ');


    // użyj "arytmetyki na wskaźnikach" do otrzymania nazwy typu parametru:
    TypeStr := Pointer(Integer(@ParamRecord^.ParamName) +
      Length(ParamRecord^.ParamName)+1);

    MethodDefine := Format('%s%s: %s', [MethodDefine, ParamRecord^.ParamName,
      TypeStr^]);

    inc(i); // zwiększ numer parametru

    // przejdź do następnego parametru; zwróć uwagę na "arytmetykę
    // na wskaźnikach"

    ParamRecord := PParamRecord(Integer(ParamRecord) + SizeOf(TParamFlags) +
      (Length(ParamRecord^.ParamName) + 1) + (Length(TypeStr^)+1));

    // jeżeli wyczerpano zestaw parametrów, zamknij nawias
    if i <= MethodTypeData.ParamCount then
    begin
      MethodDefine := MethodDefine + '; ';
    end
    else
      MethodDefine := MethodDefine + ')';
  end;

  // jeżeli metoda jest FUNKCJĄ, RTTI zawiera informację o typie
  // jej wyniku; znajduje się ona bezpośrednio po informacji
  // o ostatnim parametrze

  if MethodTypeData.MethodKind = mkFunction then
  begin
    ReturnStr := Pointer(ParamRecord);
    MethodDefine := Format('%s: %s;', [MethodDefine, ReturnStr^])
  end
  else
    MethodDefine := MethodDefine+';';

  // dodaj kompletny łańcuch do listy
  with AStrings do
  begin
    Add(MethodDefine)
  end;
end;

procedure TMainForm.FormCreate(Sender: TObject);
begin

  // wypełnij listę kilkoma przykładowymi nazwami metod

  with lbSampMethods.Items do
  begin
    AddObject('TNotifyEvent', TypeInfo(TNotifyEvent));
    AddObject('TMouseEvent', TypeInfo(TMouseEvent));
    AddObject('TBDECallBackEvent', TypeInfo(TBDECallBackEvent));
    AddObject('TDataRequestEvent', TypeInfo(TDataRequestEvent));
    AddObject('TGetModuleProc', TypeInfo(TGetModuleProc));
    AddObject('TReaderError', TypeInfo(TReaderError));
  end;
end;

procedure TMainForm.lbSampMethodsClick(Sender: TObject);
begin
  lbMethodInfo.Lines.Clear;
  with lbSampMethods do
  begin
    GetBaseMethodInfo(PTypeInfo(Items.Objects[ItemIndex]), lbMethodInfo.Lines);
    GetMethodDefinition(PTypeInfo(Items.Objects[ItemIndex]), lbMethodInfo.Lines);
  end;
end;

end.

Metody zostaną wyświetlone na ListBoxie, po kliknięciu na metodę do memo załadują się dokładniejsze informacje.

1 użytkowników online, w tym zalogowanych: 0, gości: 1