views:

437

answers:

3

Is there a way to pass a wrap and unwrap a TObject descendent in an OleVariant? I am trying to pass a TObject across automation objects. I know it's not a good idea but I don't have a good alternative.

The object is to be passed between objects from the same automation dll, if that makes any difference.

Something like this:

function GetMyObjAsVariant;
var
  MyObj: TMyObj;
begin
  MyObj := TMyObj.Create;
  result := OleVariant(MyObj);
end;

Which would be used by a client as

var
  MyObj: TMyObj;
begin
  MyObj := GetMyObjAsVariant as TMyObj;
end;

This fails to compile, returning

E2015 Operator not applicable to this operand type.
+3  A: 

You could write and register a custom Variant type; have a look at TSQLTimeStampVariantType for an example.

An alternative would be to write an automation wrapper for your class. The dual dispinterface automatically supports late binding through IDispatch which is supported by OleVariant.

TOndrej
+1 for the automation wrapper
The_Fox
+2  A: 

If you absolutely, really want to, and you know for sure both objects are in the same process, you can cast any TObject to an Integer and then back to an TObject:

function GetMyObjAsVariant;
var
  MyObj: TMyObj;
begin
  MyObj := TMyObj.Create;
  result := OleVariant(Integer(MyObj));
end;

and then:

var
  anInt: Integer;
  MyObj: TMyObj;
begin
  anInt := GetMyObjAsVariant;
  MyObj := TMyObj(anInt);
end;
Cosmin Prund
As said: this only works within the same process. So only in process COM objects (dll)!
Lars Truijens
This is the hack I was looking for! The other answers were good too but this meets my immediate need, thanks.
Alan Clark
If it's an in-process COM DLL then why are you constraining yourself to OLEVariant in the first place? You only have to stick to automation compatible types if providing a dispatch interface (for automation clients). With an in-process COM DLL I think you can simply opt-out of automation type-safety and pass your TObject's directly. But it has been a long time since I did COM at that level so I may be mis-remembering.
Deltics
The dll has wrappers around some existing TObject classes. Some of the wrappers need to share a TObject. Previously, I simply defined a global instance of the TObject and everybody accessed it. However this doesn't work when there are multiple instances of the dll. So I have to pass the objects around properly.The other solution is to recreate the common object itself as an automation object to pass it around but that's a lot of work in this case. I hope I'm explaining the situation clearly.
Alan Clark
+2  A: 

Let your object implement an interface and pass the interface.

function GetMyObjAsVariant: OleVariant;
var
  MyObj: IMyObj;
begin
  MyObj := TMyObj.Create;
  result := MyObj;
end;

var
  MyObj: IMyObj;
begin
  MyObj := GetMyObjAsVariant as IMyObj;
end;

I won't guarantee this works, you should go with TOndrej's suggestion and make an automation wrapper for your class. It shouldn't be to hard if you know your way around.

The_Fox