2
votes

I am a physicist. I am trying to work on Delphi with an imported activex control (ocx file). Let’s say there are 3 automation interfaces in the library: IGraph, IGraphAxes and IAxis. The structure of the library is such that:

===IGraph’s properties:===
Idispatch* IGraphAxes;
... //other members

===IGraphAxes’ properties:===
Idispatch* XAxis;
Idispatch* YAxis;
Idispatch* ZAxis;
integer Color;
integer Style;
… //other members

===IAxis properties:===
float Min, Max;
Boolean ShowNumbers;
… //other members

From IGraph, I am able to get an access to simple members of IGraphAxes (Color and Style) using GetIDsOfNames() and Invoke() functions. But when I try to get an access to XAxis (or YAxis, Zaxis) it generates an error. First, I use GetIDsOfNames() and it returns the dispid of XAxis without any problem. But when I call Invoke with that dispid there is an error “Access violation at address …”. It seems, the idispatch pointer (**Xaxis)* points to nothing. How can I solve this? How to make
Idispatch* Xaxis
and
IAxis interface attached to each other?
P.S. sorry for my english, i am not a native speaker

4

4 Answers

2
votes

Delphi has built-in support for IDispatch late binding, so you do not need to call Invoke() directly. Just access the members like normal properties, and Delphi will call Invoke() behind the scenes for you.

If you want to call Invoke() directly, then please show your actual code that is failing. An AV is likely due to a bug in your code rather than in the OCX itself.

0
votes

Thanks for your reply. Actually the activex control is a third-party visual component for plotting some 3d graphics. Here is the contents of the activex library:

[
uuid(...),
version(x.x),
helpstring("3-D Graph module"),
control,
custom(..., ...),
custom(..., ...)
]

library GraphLib
{

importlib("stdole2.tlb");

[
uuid(...),
helpstring("Dispatch interface for 3-D Graph Control"),
hidden
]
dispinterface _IGraph
{
properties:
[
id(0x0000006)
]
IDispatch * GraphAxes(...);
methods:
[
id(0x0000001)
]
byte AddScatterGraph(...);
[
id(0x0000002)
]
byte AddVectorFieldGraph(...);
[
id(0x0000003)
]
byte AddParametricSurfaceGraph(...);
[
id(0x0000004)
]
byte AddSurfaceGraph(...);
[
id(0x0000005)
]
byte RemoveGraphs( void );
};
[
uuid(...),
helpstring("3-D Graph Control"),
control
]
coclass cGraph
{
[default] dispinterface _IGraph;
[default, source] dispinterface _IGraphEvents;
};
[
uuid(...)
]
dispinterface IGraphAxis
{
properties:
[
id(0x00000001)
]
byte Numbered;
[
id(0x00000002)
]
double Min;
[
id(0x00000003)
]
double Max;
[
id(0x00000004)
]
short GridNum;
[
id(0x00000005)
]
byte ShowLabel;
methods:
};
[
uuid(...)
]
coclass cGraphAxis
{
[default] dispinterface IGraphAxis;
};
[
uuid(...)
]
dispinterface IGraphAxes
{
properties:
[
id(0x00000001)
]
IDispatch * XAxis;
[
id(0x00000002)
]
IDispatch * YAxis;
[
id(0x00000003)
]
IDispatch * ZAxis;
[
id(0x00000004)
]
integer Color;
[
id(0x00000005)
]
integer Style;
methods:
};
[
uuid(...)
]
coclass cGraphAxes
{
[default] dispinterface IGraphAxes;
};
[
uuid(...),
helpstring("Event interface for 3-D Graph Control")
]
dispinterface _IGraphEvents
{
properties:
methods:
[
id(0xFFFFFDA3)
]
void MouseDown(…);
[
id(0xFFFFFDA8)
]
void Click… );
[
id(0xFFFFFDA7)
]
void DblClick( …);
[
id(0xFFFFFDA6)
]
void KeyDown(… );
[
id(0xFFFFFDA5)
]
void KeyPress(… );
[
id(0xFFFFFDA4)
]
void KeyUp(… );
[
id(0xFFFFFDA2)
]
void MouseMove(…);
[
id(0xFFFFFDA1)
]
void MouseUp(…);
};
};

0
votes

When I import the ocx file into Delphi, it appears on the ActiveX tab of the Component Palette. I just drag it with mouse and put on a form and an object
Graph1: TGraph;
is automatically added to my code. Its properties and events become visible in the Object Inspector window. Now I want to get an access to the control’s axes from my code. As you can see, the property represents coordinate axes. Also I guess that IGraphAxes’ XAxis/YAxis/ZAxis members are idispatch pointers of type IGraphAxis. I wrote the following procedures to access an idispatch interface:

procedure TForm2.GetProperty(dispobj: IDispatch; PropertyName: WideString;
                                var retvalue: Variant; Sender: TObject);  
var hr: HRESULT;  
    DispId: integer;  
    value: Variant;  
    params: TDispParams;  
begin  
  hr:=dispobj.GetIDsOfNames(GUID_NULL,@PropertyName, 1, LOCALE_SYSTEM_DEFAULT, @DispId);  
  Label1.Caption:=inttostr(DispId);  
  hr:=dispobj.Invoke(DispId,GUID_NULL,LOCALE_SYSTEM_DEFAULT,DISPATCH_PROPERTYGET,
                  Params,@Value,nil,nil);  
  Retvalue:=Value;  
  Label2.Caption:=inttostr(value);  
end;  

procedure TForm2.SetProperty(dispobj: IDispatch; PropertyName: WideString; Value: OLEVariant; Sender: TObject);  
var   
    hr: HRESULT;  
    DispId: integer;  
    params: TDispParams;  
begin  
   hr:=dispobj.GetIDsOfNames(GUID_NULL,@PropertyName,1, LOCALE_SYSTEM_DEFAULT, @DispId);  
  Label1.Caption:=inttostr(DispId);  
  params.rgvarg:=@Value;  
  params.rgdispidNamedArgs:=@DispIDArgs;  
  params.cArgs:=1;  
  params.cNamedArgs:=1;  
  hr:=dispobj.Invoke(DispId,GUID_NULL,LOCALE_SYSTEM_DEFAULT,                  DISPATCH_PROPERTYPUT,Params,nil,nil,nil);  
 end;

They work fine with Color and Style properties of IGraphAxes:

GetProperty(Graph1.GraphAxes, 'Color', retvalue, Sender);

Or

SetProperty(Graph1.GraphAxes, 'Color',value,Sender);

But how to get full access to XAxis/YAxis/ZAxis members of IGraphAxes?

0
votes

And here is the unit file generated from the type library.
unit GraphLib_TLB;

// ************************************************************************  
// The types declared in this file were generated from data read from a       
// Type Library. If this type library is explicitly or indirectly (via        
// another type library referring to this type library) re-imported, or the   
// 'Refresh' command of the Type Library Editor activated while editing the   
// Type Library, the contents of this file will be regenerated and all        
// manual modifications will be lost.                                         
// ************************************************************************ //

// ************************************************************************  //  
// Type Lib: graph3d.ocx (1)  
// LIBID: {...}  
// LCID: 0  
// HelpString: 3-D Graph module  
// DepndLst:   
//   (1) v2.0 stdole, (C:\Windows\system32\stdole2.tlb)  
// ************************************************************************ //  
{$TYPEDADDRESS OFF} // Unit must be compiled without type-checked pointers.   
{$WARN SYMBOL_PLATFORM OFF}  
{$WRITEABLECONST ON}  
{$VARPROPSETTER ON}  
interface  

uses Windows, ActiveX, Classes, Graphics, OleCtrls, OleServer, StdVCL, Variants;  

// *********************************************************************//  
// GUIDS declared in the TypeLibrary. Following prefixes are used:        
//   Type Libraries     : LIBID_xxxx                                      
//   CoClasses          : CLASS_xxxx                                      
//   DISPInterfaces     : DIID_xxxx                                       
//   Non-DISP interfaces: IID_xxxx                                        
// *********************************************************************//  
const  
  // TypeLibrary Major and minor versions  
  GraphLibMajorVersion = x;  
  GraphLibMinorVersion = x;  

  LIBID_GLLib: TGUID = '{...}';  

  DIID__IGraph: TGUID = '{...}';  
  DIID__IGraphEvents: TGUID = '{...}';  
  CLASS_cGraph: TGUID = '{...}';  
  DIID_IGraphAxis: TGUID = '{...}';  
  CLASS_cGraphAxis: TGUID = '{...}';  
  DIID_IGraphAxes: TGUID = '{...}';  
  CLASS_cGraphAxes: TGUID = '{...}';  
type  

// *********************************************************************//  
// Forward declaration of types defined in TypeLibrary                      
// *********************************************************************//  
  _IGraph = dispinterface;  
  _IGraphEvents = dispinterface;  
  IGraphAxis = dispinterface;   
  IGraphAxes = dispinterface;  
// *********************************************************************//  
// Declaration of CoClasses defined in Type Library                         
// (NOTE: Here we map each CoClass to its Default Interface)                
// *********************************************************************//  
  cGraph = _IGraph;  
  cGraphAxis = IGraphAxis;  
  cGraphAxes = IGraphAxes;  

// *********************************************************************//  
// Declaration of structures, unions and aliases.                           
// *********************************************************************//  
  PWideString1 = ^WideString; {*}  
  PShortint1 = ^Shortint; {*}  
  PSmallint1 = ^Smallint; {*}  

// *********************************************************************//  
// DispIntf:  _IGraph  
// Flags:     (4112) Hidden Dispatchable  
// GUID:      {...}  
// *********************************************************************//  
  _IGraph = dispinterface  
    ['{...}']  
    function AddScatterGraph(...): {??Shortint}OleVariant; dispid 1;  
    function AddVectorFieldGraph(...): {??Shortint}OleVariant; dispid 2;  
    function AddParametricSurfaceGraph(...): {??Shortint}OleVariant; dispid 3;  
    function AddSurfaceGraph(...): {??Shortint}OleVariant; dispid 4;  
    function RemoveGraphs: {??Shortint}OleVariant; dispid 5;  
    property GraphAxes: IDispatch dispid 6;  
  end;  

// *********************************************************************//  
// DispIntf:  _IGraphEvents  
// Flags:     (4096) Dispatchable  
// GUID:      {...}  
// *********************************************************************//  
  _IGraphEvents = dispinterface  
    ['{...}']  
    procedure MouseDown(); dispid -605;  
    procedure Click; dispid -600;  
    procedure DblClick; dispid -601;  
    procedure KeyDown(...); dispid -602;  
    procedure KeyPress(...); dispid -603;  
    procedure KeyUp(...); dispid -604;  
    procedure MouseMove(...); dispid -606;  
    procedure MouseUp(...); dispid -607;  
    procedure ReadyStateChange; dispid -609;  
  end;  

// *********************************************************************//  
// DispIntf:  IGraphAxis  
// Flags:     (4096) Dispatchable  
// GUID:      {...}  
// *********************************************************************//  
  IGraphAxis = dispinterface  
    ['{...}']  
    property Numbered: {??Shortint}OleVariant dispid 1;  
    property Min: Double dispid 2;  
    property Max: Double dispid 3;  
    property GridNum: Smallint dispid 4;  
    property ShowLabel: {??Shortint}OleVariant dispid 5;        
  end;  

// *********************************************************************//  
// DispIntf:  IGraphAxes  
// Flags:     (4096) Dispatchable  
// GUID:      {...}  
// *********************************************************************//  
  IGraphAxes = dispinterface  
    ['{...}']  
    property XAxis: IDispatch dispid 1;  
    property YAxis: IDispatch dispid 2;  
    property ZAxis: IDispatch dispid 3;  
    property Color: Integer dispid 4;  
    property Style: Smallint dispid 5;  
  end;  

// *********************************************************************//  
// OLE Control Proxy class declaration  
// Control Name     : TGraph  
// Help String      : 3-D Graph Control  
// Default Interface: _IGraph  
// Def. Intf. DISP? : Yes  
// Event   Interface: _IGraphEvents  
// TypeFlags        : (34) CanCreate Control  
// *********************************************************************//  
  TGraph = class(TOleControl)  
  private  
    FOnError: TGraphError;  
    FOnReadyStateChange: TNotifyEvent;  
    FIntf: _IGraph;  
    function  GetControlInterface: _IGraph;  
  protected  
    procedure CreateControl;  
    procedure InitControlData; override;  
    function Get_GraphAxes: IDispatch;  
    procedure Set_GraphAxes(const Value: IDispatch);  
  public  
    function AddScatterGraph(...): {??Shortint}OleVariant;  
    function AddVectorFieldGraph(...): {??Shortint}OleVariant;  
    function AddParametricSurfaceGraph(...): {??Shortint}OleVariant;  
    function AddSurfaceGraph(...): {??Shortint}OleVariant;  
    function RemoveGraphs: {??Shortint}OleVariant;  
    property ControlInterface: _IGraph read GetControlInterface;  
    property DefaultInterface: _IGraph read GetControlInterface;  
    property GraphAxes: IDispatch index 6 read GetIDispatchProp write SetIDispatchProp;  
  published  
    //properties visible in the Object Inspector go here   
    ...  
    property  OnDragDrop;  
    property  OnDragOver;  
    property  OnEndDrag;  
    property  OnEnter;  
    property  OnExit;  
    property  OnStartDrag;  
    property  OnMouseUp;  
    property  OnMouseMove;  
    property  OnMouseDown;  
    property  OnKeyUp;  
    property  OnKeyPress;  
    property  OnKeyDown;  
    property  OnDblClick;  
    property  OnClick;  
    property OnError: TGraphError read FOnError write FOnError;  
    property OnReadyStateChange: TNotifyEvent read FOnReadyStateChange write FOnReadyStateChange;    
  end;    

// *********************************************************************//  
// The Class CocGraphAxis provides a Create and CreateRemote method to            
// create instances of the default interface IGraphAxis exposed by                
// the CoClass cGraphAxis. The functions are intended to be used by               
// clients wishing to automate the CoClass objects exposed by the           
// server of this typelibrary.                                              
// *********************************************************************//  
  CocGraphAxis = class  
    class function Create: IGraphAxis;  
    class function CreateRemote(const MachineName: string): IGraphAxis;  
  end;  

// *********************************************************************//  
// The Class CocGraphAxes provides a Create and CreateRemote method to            
// create instances of the default interface IGraphAxes exposed by                
// the CoClass cGraphAxes. The functions are intended to be used by               
// clients wishing to automate the CoClass objects exposed by the           
// server of this typelibrary.                                              
// *********************************************************************//  
  CocGraphAxes = class  
    class function Create: IGraphAxes;  
    class function CreateRemote(const MachineName: string): IGraphAxes;  
  end;  

procedure Register;  

resourcestring  
  dtlServerPage = 'ActiveX';  

  dtlOcxPage = 'ActiveX';  

implementation  

uses ComObj;  

procedure TGraph.InitControlData;  
const  
  CEventDispIDs: array [0..1] of DWORD = (...);  
  CLicenseKey: array[0..33] of Word = ($006F, ..., ..., e.g.);  
  CControlData: TControlData2 = (  
    ClassID: '{...}';  
    EventIID: '{...}';  
    EventCount: 2;  
    EventDispIDs: @CEventDispIDs;  
    LicenseKey: @CLicenseKey;  
    Flags: $00000000;  
    Version: 401);  
begin  
  ControlData := @CControlData;  
  TControlData2(CControlData).FirstEventOfs := Cardinal(@@FOnError) - Cardinal(Self);  
end;  

procedure TGraph.CreateControl;  

  procedure DoCreate;  
  begin  
    FIntf := IUnknown(OleObject) as _IGraph;  
  end;  

begin  
  if FIntf = nil then DoCreate;  
end;  

function TGraph.GetControlInterface: _IGraph;  
begin  
  CreateControl;  
  Result := FIntf;  
end;  

function TGraph.Get_GraphAxes: IDispatch;  
begin  
  Result := DefaultInterface.GraphAxes;  
end;  

procedure TGraph.Set_GraphAxes(const Value: IDispatch);  
begin  
  DefaultInterface.GraphAxes := Value;  
end;  

function TGraph.AddScatterGraph(...): {??Shortint}OleVariant;  
begin  
  Result := DefaultInterface.AddScatterGraph(...);  
end;  

function TGraph.AddVectorFieldGraph(...): {??Shortint}OleVariant;  
begin  
  Result := DefaultInterface.AddVectorFieldGraph(...);  
end;  

function TGraph.AddParametricSurfaceGraph(...): {??Shortint}OleVariant;  
begin  
  Result := DefaultInterface.AddParametricSurfaceGraph(...);  
end;  

function TGraph.AddSurfaceGraph(...): {??Shortint}OleVariant;  
begin  
  Result := DefaultInterface.AddSurfaceGraph(...);  
end;  

function TGraph.RemoveGraphs: {??Shortint}OleVariant;  
begin  
  Result := DefaultInterface.RemoveGraphs;  
end;  

class function CocGraphAxis.Create: IGraphAxis;  
begin  
  Result := CreateComObject(CLASS_cGraphAxis) as IGraphAxis;  
end;  

class function CocGraphAxis.CreateRemote(const MachineName: string): IGraphAxis;  
begin  
  Result := CreateRemoteComObject(MachineName, CLASS_cGraphAxis) as IGraphAxis;  
end;  

class function CocGraphAxes.Create: IGraphAxes;  
begin  
  Result := CreateComObject(CLASS_cGraphAxes) as IGraphAxes;  
end;  

class function CocGraphAxes.CreateRemote(const MachineName: string): IGraphAxes;  
begin  
  Result := CreateRemoteComObject(MachineName, CLASS_cGraphAxes) as IGraphAxes;  
end;  

procedure Register;  
begin  
  RegisterComponents(dtlOcxPage, [TGraph]);  
end;  

end.