Dave
Dave

Reputation: 5634

Invalid Variant Operation Exception Trying to Access OleVariant in Delphi - Works in C#

I'm trying to access an OleVariant in a callback that is coming from an ActiveX library.

Here's what the event handler is defined as in the TLB:

procedure(ASender: TObject; var structQSnap: {??structVTIQSnap}OleVariant) of object;

Here's the definition of structVTIQSnap in the TLB:

structVTIQSnap = packed record
  bstrSymbol: WideString;
  bstrListingExch: WideString;
  bstrLastExch: WideString;
  fLastPrice: Double;
  nLastSize: Integer;
  bstrBbo: WideString;
  bstrBidExch: WideString;
  fBidPrice: Double;
  nBidSize: Integer;
  bstrAskExch: WideString;
  fAskPrice: Double;
  nAskSize: Integer;
  fHighPrice: Double;
  fLowPrice: Double;
  fOpenPrice: Double;
  fClosePrice: Double;
  nCumVolume: Integer;
  bstrTradeCondition: WideString;
  nQuoteCondition: Integer;
  bstrCompanyName: WideString;
  f52WeekHigh: Double;
  f52WeekLow: Double;
  fEps: Double;
  nSharesOutstanding: Integer;
  nSpCode: Integer;
  fBeta: Double;
  bstrExDivDate: WideString;
  nDivFreq: Integer;
  fDivAmt: Double;
  nAvgVolume: Integer;
  bstrCusip: WideString;
  fVwap: Double;
  bstrUpdateTime: WideString;
  bstrExch: WideString;
  nSharesPerContract: Integer;
end;

It compiles fine, but everytime I try to access the bstrSymbol, I get an "Invalid Variant Operation":

 procedure TForm1.HandleVTIQuoteSnap(ASender: TObject; var structQSnap: OleVariant);
 var
    symbol: WideString;
 begin
    symbol := structQSnap.bstrSymbol; // this line causes the exception
 end;

How do I access structQSnap and its properties in Delphi?

In C#, this function works fine for the event handler:

    void vtiQ_OnVTIQSnap(ref vtiLib.structVTIQSnap structQSnap)
    {
        MessageBox.Show("Got qsnap for " + structQuoteSnap.bstrSymbol);            
    }

Any ideas?

Upvotes: 0

Views: 5364

Answers (4)

Ondrej Kelle
Ondrej Kelle

Reputation: 37211

I think that Delphi's ActiveX import wizard doesn't know how to handle the structVTIQSnap type (which seems to be a record) properly and just uses the default OleVariant. Is there a type declaration named structVTIQSnap or similar in the generated ..._TLB.pas file? Try using that instead of OleVariant, e.g.

procedure (ASender: TObject; var structQSnap: structVTIQSnap) of object;

The type will probably be declared as a "packed record".

Upvotes: 8

mghie
mghie

Reputation: 32334

You could try to typecast the structQSnap to a pointer to this struct. Something like

PstructVTIQSnap = ^structVTIQSnap;
structVTIQSnap = packed record
   bstrSymbol: WideString;
   // other stuff...
end;

and

procedure TForm1.HandleVTIQuoteSnap(ASender: TObject;
  var structQSnap: OleVariant);
var
  ps: PstructVTIQSnap;
  symbol: WideString;
begi
  ps := PstructVTIQSnap(structQSnap.VPointer^);
  symbol := ps.bstrSymbol;
  ...
end;

What I do not understand however is the following: I take it from the ref in the C# code that the structure should be marshalled twice, once from the library to the callback, second back to the library. This would mean that the varByRef flag ($4000) needs to be set in VType, but the value you gave in your comment (3484) is much too small?

Upvotes: 1

mj2008
mj2008

Reputation: 6747

I'm not sure why you are considering the "structVTIQSnap" to be an "OleVariant". Seems an odd translation to me. Could it be that it has been placed into an OleVariant in some form, either as an array or similar?

Upvotes: 0

Jk.
Jk.

Reputation: 453

try to look what returns in TVarData(structQSnap).VType ?

may be it will work:

 var
   symbol: WideString;
   rec: structVTIQSnap;
 begin
    rec := structVTIQSnap(structQSnap);
    symbol := rec.bstrSymbol; 
 end;

Upvotes: 0

Related Questions