http://delphidabbler.com/articles?article=22&part=1
I am trying to port Article-22 to C++
This line
TMyClass = class(TAutoIntfObject, IMyIntf, IDispatch)
"translates" imho to:
class TMyClass : public TAutoIntfObject, IMyIntf, IDispatch
But it cannot be compiled, since
a) IDispatch is already part of IMyIntf
and
b) some virtual functions will then be missing
Does anyone have an idea?
Related
I am wondering if it is possible to define property of type function/procedure pointer in Delphi 2010 RIDL editor, for an interface definition, such that when I create an instance of its implementor using its CoCreator, I may then assign a function/procedure in my source that uses that interface definition, to that property. Actually I want to know how to fill "???" on the following.
TLB file:
IComIntf = interface(IDispatch)
...
function Get_OnDoSomething : ??? safecall;
procedure Set_OnDoSomething(const New_Event : ???); safecall;
...
property OnDoSomething : ???;
...
implementation
uses ComObj;
class function CoComIntf.Create: IComInt;
...
begin
Result := CreateComObject(CLASS_ComIntf) as IComIntf;
end;
implementation file, ComIntfUnit.pas:
type
TOnDoSomething = function (Info: OleVariant): HResult of object;
TComIntf = class(TAutoObject, IComIntf)
private
fOnDoSomething : TDoSomething;
...
public
property OnDoSomething: TOnDoSomething read fOnDoSomething write fOnDoSomething;
...
Client form:
uses ComIntfUnit;
type
TForm1 = class(TForm)
private
{ Private declarations }
fCom : IComIntf;
function DoSomething(Info: OleVariant): HResult;
public
{ Public declarations }
...
end;
...
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
fCom := CoComIntf.Create;
fCom.OnDoSomething := DoSomething;
...
Thank you in advance.
Raw function pointers are not COM compatible types. You could certainly use a void pointer if you wished but that wouldn't really be in the spirit of COM.
What you are expected to do here is to pass another interface. Then the callee can call a function on that interface and have the caller's code be executed.
You are going about this the wrong way. The correct way to implement this is to define a second interface that the client implements and passes to your COM object. The COM object can then hold on to that interface and call methods on it when needed. This is most commonly implemented using Connection Points for event interfaces.
An easy way to implement this, especially since you are using IDispatch, is to create a new Automation Object using the IDE wizard, and be sure to click on the "Generate Event support code" checkbox in the wizard dialog. The wizard will then generate 2 interfaces, one for the object itself, and one for the object's events, and implement the connection point logic for you. You can then add methods to the 2 interfaces as needed, where the object methods call the event methods when needed.
If you then compile, register, and import the final object into the IDE and generate a VCL wrapper for it, the resulting component will have VCL-style events on it that are internally hooked up to the object's connection point events.
I am trying to use typed interfaces and Spring4D, but have some issues with Resolving. Please review details below.
DB Objects:
unit u_DB;
type
TDBObject = class
public
property ID: TGUID;
end;
TDBCRM = class(TDBObject)
public
property SOME_FIELD: TSomeType;
end;
Declarations:
unit i_BaseDAL;
type
{$M+}
IBaseDAL<T: TDBObject, constructor> = interface
['{56D48844-BD7F-4FF8-A4AE-30DA1A82AD67}']
procedure RefreshData();
....
end;
unit u_BaseDAL;
type
TBaseDAL<T: TDBObject, constructor> = class(TInterfacedObject, IBaseDAL<TDBObject>)
public
procedure RefreshData();
....
end;
After that I was able to register the base IBaseDAL and IBaseDAL
GlobalContainer.RegisterType<IBaseDAL<TDBObject>>;
GlobalContainer.RegisterType<IBaseDAL<TDBCRM>>;
Using in project:
I need to resolve now IBaseDAL, but could not find how do it. Only below ugly approach work
DM := GlobalContainer.Resolve('i_BaseDAL.IBaseDAL<u_DB.TDBObject>#TBaseDAL<u_DBCRM.TDBCRM>').AsInterface as IBaseDAL<TDBObject>;
but I was hoping that below will work :) -
DM := GlobalContainer.Resolve(IBaseDAL<TDBCRM>);
Please advise how could it be resolved correctly?
Edit: I just noticed that somehow the interface table does not contain generic interfaces so you have to explicitly register them as explained below.
First you need to register an implementation and not just an interface.
GlobalContainer.RegisterType<TBaseDAL<TDBObject>>;
GlobalContainer.RegisterType<TBaseDAL<TDBCRM>>;
GlobalContainer.Build;
The container will inspect the class you registered and register all implemented interfaces (except IInterface) so it will know about IBaseDAL<TDBObject> and IBaseDAL<TDBCRM>.
If your class might implement some interfaces you don't want the container to know you have to register explicit:
GlobalContainer.RegisterType<IBaseDAL<TDBObject>, TBaseDAL<TDBObject>>;
GlobalContainer.RegisterType<IBaseDAL<TDBCRM>, TBaseDAL<TDBCRM>>;
GlobalContainer.Build;
Then you can resolve:
GlobalContainer.Resolve<IBaseDAL<TDBCRM>>;
By the way, are you sure your class definition should not be as follows?
type
TBaseDAL<T: TDBObject, constructor> = class(TInterfacedObject, IBaseDAL<T>)
I created a class method in a class that implements an interface, but I can't seem to define it inside of the interface.
IMyClass = interface
procedure someproc();
class function myfunc() : TMyClass; // compiler doesn't like this!
end;
TMyClass = class( TInterfacedObject, IMyClass )
public
procedure someproc();
class function myfunc() : TMyClass;
end;
I want myfunc() to create and return an instance of TMyClass. For example:
somefunc( TMyClass.myfunc(), ... );
creates an instance of TMyClass and passes it into somefunc.
I can define function myfunc() : TMyClass; in the IMyClass interface, but if I put class in front of it, the compiler gives me an error. If I leave it off, it gives me several other errors "E2291 Missing implementation of interface method xyz.myfunc" It just doesn't accept the same signature in the interface as in the class.
I thought I've seen this work before (class methods defined in interfaces) but maybe not.
If this isn't supported directly, how do you do it?
(I'm using Delphi XE5, in case it matters.)
Interfaces are not classes and do not support methods marked as class, they only support non-class methods that are implemented and called on object instances.
What you are looking for will most likely have to be implemented as a class factory instead of using an interface.
What you are trying to achieve is impossible because it violates binary specifications of Delphi interfaces.
Any interface method in Delphi have hidden first parameter - pointer to an instance. Instance methods have the same hidden parameter (Self, the same pointer to an instance) and because of this they are binary compatible with interface methods.
On the other hand the hidden parameter of a class method is a pointer to the class vtable, so Delphi class methods are binary incompartible with Delphi interface methods.
Hypothetically you could think of the following (binary compatible) declarations:
IMyClass = interface
procedure someproc();
function myfunc(): TMyClass;
end;
TMyClass = class( TInterfacedObject, IMyClass )
public
procedure someproc();
class function myfunc(Inst: TMyClass) : TMyClass; static;
end;
Here I use static specifier to remove the hidden parameter (class vtable pointer) we don't need and add the instance pointer parameter explicitely; but the compiler does support such syntax because the above is essentially the same as a simpler
IMyClass = interface
procedure someproc();
function myfunc(): TMyClass;
end;
TMyClass = class( TInterfacedObject, IMyClass )
public
procedure someproc();
function myfunc() : TMyClass;
end;
You can define a class method (class procedure in Delphi) in a class definition (TMyClass) but not in an interface (IMyClass ).
I'm a newbie with Dependency Injection containers, and I am trying to get my head around using them in conjunction with Mocking.
Lets say I have a controller and a list (the model):
IBlahList = interface
property Items[AIndex: integer]: IBlah read GetItem;
end;
IController = interface
property List: IBlahList read GetList;
end;
The implementation of IController would look something like (note, it's in the implementaion section:
implementation
TController = class (TInterfacedObject, IController)
private
FList: IBlahList;
function GetList: IBlahList;
public
constructor Create(const AList: IBlahList);
end;
And then, of course, I would register this class (as well as one for IBlahList) with the GlobalContainer:
GlobalContainer.RegisterType<TController>.Implements<IController>;
I place the TController in the implementation section, as suggested by various sources (well, Nick Hodges anyway!), so that we cannot reference the TController class directly.
Now, just say I want to test my implementation of ICollection in a unit test:
procedure TestSomething
var
LMockList: TMock<IBlahList>;
LController: IController;
begin
LMockList := TMock<IBlahList>.Create;
// Oops, I can't do this, I can't access TController
LController := TController.Create(LMockList);
end;
So, my question is, should I move the TController class into my interface section so I can test it, or is there some other way to pass the mock IBlahList to the controller that I have yet to find?
If you have the concrete class in the implementation section, then you could expose a factory function (i.e. have it in the interface section) that creates an IController with the required parameters.
It makes absolutely no sense to have an implementation that can not be instantiated, IMO.
interface
...
function CreateController(AList: IBlahList): IController;
implementation
function CreateController(AList: IBlahList): IController;
begin
Result := TController.Create(AList);
end;
Well you probably should be using the mock framework in your test projects as well, but in these cases I usually "cheat" and move the implementation to where I need it using a DUNIT conditional variable:
// In the real app, we want the implementation and uses clauses here.
{$IFNDEF DUNIT}
implementation
uses
classes;
{$ENDIF}
type
TClassUnderTest = class(TObject)
// ...
end;
// In test projects it is more convenient to have the implemenation and
// uses clauses down here.
{$IFDEF DUNIT}
implementation
uses
classes;
{$ENDIF}
Then make sure that any test projects define the DUNIT conditional var, and move any units needed by the TClassUnderTest declaration to the interface section. The latter you can do permanently or under control of the DUNIT conditional as well.
I can just say: don't listen to Nick in that case.
Putting a class inside the implementation part of a unit just has disadvantages and you are facing one of them.
The whole point of using dependency injection is to decouple pieces of your code.
Now you removed the static dependency of TController and some class that implements IBlahList but you pulled in another (and much worse imo) dependency: the dependency on the DI container.
Don't put the class inside the implementation part of a unit just to prevent someone from directly creating it in your production code. Also don't put in the dependency on the DI container into that unit.
A much better approach is to have 3 units: interface, class, registration.
Edit:
I suggest reading this article and pay attention to the underlined parts: http://www.loosecouplings.com/2011/01/dependency-injection-using-di-container.html
Edit2 - added some pseudo code to show what I mean.
The unit test code could exactly be as in the question.
unit Interfaces;
interface
type
IBlahList = interface
property Items[AIndex: integer]: IBlah read GetItem;
end;
IController = interface
property List: IBlahList read GetList;
end;
implementation
end.
-
unit Controller;
interface
uses
Classes,
Interfaces;
type
TController = class (TInterfacedObject, IController)
private
FList: IBlahList;
function GetList: IBlahList;
public
constructor Create(const AList: IBlahList);
end;
implementation
...
end.
-
unit Registration;
interface
implementation
uses
Interfaces,
Controller,
Spring.Container;
initialization
GlobalContainer.RegisterType<TController>.Implements<IController>;
end.
How does one go about exposing a class written in Prism via COM Interop? For example, given the following interface:
TYPE
IFoo = public interface
property bar: string; read;
end;
FooImpl = class( IFoo )
private
function GetBar : string;
public
property bar: string; read GetBar;
end;
In this example, assume IFoo was imported via TLBIMP and linked to the project.
use the ComVisible attribute to make the assembly and/or class public. When using tlbexp.exe (part of the .NET SDK) you'll get the interface as a COM interface and the class as a CoClass for IFoo. Optionally you can use the Guid attribute to set a specific guid for your interface and (co) classes.