L505 wrote:
If you choose for a dll system, I would choose Interfaces (and indeed,
don't pass strings, dyn arrays or classes)

Marc



I don't have much experience with interfaces and would like to learn more about
them. Can you import/export one to and from other languages? i.e. c++/c/etc.

Yes, Interfaces are language independent. They only define what functions/procedures are available within an interface (and what calling convention). An Interface itself has no data or code. I' is only a "contract" that those functions are avalable.
The actual code is implemented by a delphi/FPC/C++ class.

As an example lets look at IStream:

Its methods are described at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/stg/stg/istream.asp

and for FPC it is declared in packages\extra\winunits\activex.pp


    IStream = interface(ISequentialStream)
       ['{0000000C-0000-0000-C000-000000000046}']
       function Seek(dlibMove : Large_integer; dwOrigin: Longint;
            out libNewPosition : Large_Integer): HResult; stdcall;
      ...rest skipped...
    end;

This declaration defines only the interface. There is no code involved here. You also see that this interface is derived from ISequentialStream (just like you can have with classes) and this interface is identified by the GUID 0000000C-0000-0000-C000-000000000046
Each interface should have its own GUID.

Now suppose you have some external function in some API/dll/whatever like:

  function GiveMeAStream: IStream; stdcall; external;


then you can use it like:

var
  Stream: IStream;
begin
  Stream := GiveMeAStream;

  if Stream.Seek(....) <> S_OK then ReportSomeError;
end.

You can call interface methods just like you call class methods, independent on how it is implemented. The only thing you have to know is that you can call it.


This is one side of the story. Now suppose you have an external function in some API/dll/whatever like:

  procedure PassMeAStream(aStream: IStream); stdcall; external;

Now are you the one who need to supply an interface. Luckely for us there is a class which implements IStream (in classes.pp, unfortunately comented out):

  TStreamAdapter = class(TInterfacedObject, IStream)
  ....
  end;

This looks like a normal class definition, only we tell now the compiler that we also implement IStream. This means that all methods defined in IStream have to exist in this class (or parent class) (remember "contract")

In this example the TStreamAdapter is a wrapper around a normal FCL stream. So when we need to pass an IStream we can do something like:

var
  FCLStream: TStream;
  InterfaceStream: IStream;
begin
  FCLStream := TMemoryStream.Create(...);
  InterfaceStream := TStreamAdapter.Create(FCLStream);

  PassMeAStream(InterfaceStream);
end.

this is equal to:

var
  FCLStream: TStream;
  Adapter: TStreamAdapter;
begin
  FCLStream := TMemoryStream.Create(...);
  Adapter := TStreamAdapter.Create(FCLStream);

  PassMeAStream(Adapter);
end.


What you see here is that a class which implements an interface can be stored in a variable of the classtype *or* of the interface type. However, you have only access to the methods defined by the class *or* the the interface.


For now I'll leave it here.

Marc

_________________________________________________________________
    To unsubscribe: mail [EMAIL PROTECTED] with
               "unsubscribe" as the Subject
  archives at http://www.lazarus.freepascal.org/mailarchives

Reply via email to