Getting an access to member of IDispatch interface
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 membersFrom 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 inte开发者_如何学Pythonrface attached to each other? P.S. sorry for my english, i am not a native speakerDelphi 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.
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(…);
};
};
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?
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.
精彩评论