Is there a way to use visual databindings with my own custom units?
I would like to be able to bind a form property to a property of a class in my own unit.
i.e.:
unit Unit2;
interface
type
TMyClass = class
strict private
fMyTextField : String;
public
property MyTextField : String read fMyTextField write fMyTextField;
published
end;
implementation
end.
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 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 ).
could someone explain to me what is the reason that when creating a generic class I must move my private constans to the interface section? This is killing my design, I don't want others to see something that should be private.
unit Unit38;
interface
uses
Generics.Collections;
type
TSimpleClass<T> = class(TObject)
private
procedure DoSomethingInternal(const SomeString: string);
public
procedure DoSomething;
end;
implementation
const
MyString = 'some string'; //Why this must be public?
{ TSimpleClass<T> }
procedure TSimpleClass<T>.DoSomething;
begin
DoSomethingInternal(MyString); //Compiler error
end;
procedure TSimpleClass<T>.DoSomethingInternal(const SomeString: string);
begin
//-------
end;
end.
Thanks.
Same error in D2010, so the generics fixes of D2010 did not address this. It is a bug: http://qc.embarcadero.com/wc/qcmain.aspx?d=79747
Fixed in build 15.0.3863.33207. Which I think is XE
Another QC on this is: http://qc.embarcadero.com/wc/qcmain.aspx?d=78022 which involves an enum and is still open.
The documentation on the error isn't very clear by the way. See:
E2506 Method of parameterized type declared in interface section must not use local symbol '%s'
It involves a class var in a generic class which cannot be assigned a literal (!) value in the class' constructor, the fix being to parameretrize the constructor... No idea why, but I guess it has to do with a compiler limitation.
It's a consequence of the generics implementation in Delphi. When you instantiate a class by supplying a concrete T in another unit, code for the concrete class is written into that other unit. But that other unit can no longer see your private string constant. It's rather frustrating.
My understanding of the generics implementation suggests that Mikael's workaround will solve the problem because the class const will be visible when you instantiate your concrete type in another unit.
Not an answer but a possible workaround could be to use private const in the class declaration.
TSimpleClass<T> = class(TObject)
private
procedure DoSomethingInternal(const SomeString: string);
const MyString = 'some string'; //Why this must be public?
public
procedure DoSomething;
end;
This works in Delphi 2010, XE and XE2, not in Delphi 2009.
I am constantly getting the: Undeclared identifier for an interface type I have defined in another unit.
Here is what I have:
unit Drawers;
interface
implementation
type
IDrawer = interface
['{070B4742-89C6-4A69-80E2-9441F170F876}']
procedure Draw();
end;
end.
unit Field;
interface
uses
Graphics, Classes, Drawers;
TField = class(TInterfacedObject, IField)
private
FSymbolDrawer: IDrawer;
At FSymbolDrawer I get the complier error.
Of course I have the uses Drawers; in the unit where TField is defined.
What's this about?
Thank you
In the unit Drawers the type declaration of IDrawer has to be in the interface part of the unit. You have inserted it in the implementation part where it is only visible for in-unit declarations.
Here is the code:
unit Drawers;
interface
type
IDrawer = interface
['{070B4742-89C6-4A69-80E2-9441F170F876}']
procedure Draw();
end;
implementation
end.
Which uses clause do you add Drawers to? It has to be in the interface uses clause (above the definition of TField that uses it).
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.