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

StackOverflow https://stackoverflow.com/questions/483859

  •  20-08-2019
  •  | 
  •  

Question

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?

Was it helpful?

Solution

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".

OTHER TIPS

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?

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;

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?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top