Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Using TAutoIntfObject to implement dispatch interface?

529 views
Skip to first unread message

Peter Pohmann

unread,
Sep 14, 2001, 10:12:49 AM9/14/01
to
I need to implement a pure dispatch interface in my application and am
wondering what is the best way to do it. My application works with
MSHTML
and needs to intercept some of the DHTML events. Those events are
handled
by passing an IDispatch to MSHTML which in turn then calls the methods
declared in the dispatch interface.

Since my application is not a COM server I don't need to create a COM
object to implement the dispatch interface methods. I just want to have
a internal object that is created via Create and implements IDispatch.

I know I can implement Invoke and GetIDsOfNames etc. within this object
but it seems as if TAutoIntfObject could help me in the task of
dispatching
and unpacking the method parameters. One of my problems is that

type
MyDispatchImpl = class(TAutoIntfObject, HTMLDocumentEvents2)
...
end;

does not compile, because HTMLDocumentEvents is just a dispinterface and
not a dual one.

Another problem is that TAutoIntfObject.Create needs an ITypeInfo
reference and I don't know where to get it.

Can anybody shed some light on this?

Best regards
Peter
--
.....................................................
Peter Pohmann
dataWeb GmbH
poh...@dataweb.de
http://www.dataweb.de
phone +49 8544 971892
fax +49 8544 971899

Ed Hillmann

unread,
Sep 16, 2001, 6:29:32 PM9/16/01
to
>
> type
> MyDispatchImpl = class(TAutoIntfObject, HTMLDocumentEvents2)
> ...
> end;
>
> does not compile, because HTMLDocumentEvents is just a dispinterface and
> not a dual one.
>
> Another problem is that TAutoIntfObject.Create needs an ITypeInfo
> reference and I don't know where to get it.
>
> Can anybody shed some light on this?

Hope so. TAutoIntfObjects are just like TAutoObjects, with the exception of
they don't have Factories managing their construction. I'm sure you know
that already, but I just like stating the obvious. :)

OK, to create an instance of these guys, you need an ITypeInfo reference,
just as you say. That's 100% correct. You can get that from loading up a
Type Library that contains the definition of the Interface you want the
TAutoIntObject to implement. I've used the API function LoadRegTypeLib in
the past, because I can just provide registration details (the GUID of the
Type Library, plus its Major and Minor versions and Locale ID). It's also
useful when you just want to use the registered Type Library and not have to
provide a specific file. If you want to use a specific EXE, DLL or TLB,
then use LoadTypeLib or LoadTypeLibEx. Any of these three API functions
will provide a reference to an ITypeLib interface.

Once you have this, you can call the interface's GetTypeInfoOfGUID method
(API Doco can be found at
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/automat/htm
_hh2/chap9_2xic.asp). You provide the GUID of the class' Interface and it
will provide you with an ITypeInfo reference about the class. It is this
reference which is required when creating an instance of the TAutoIntfObject
class. This is the functionality which an AutoObject Factory provides for
TAutoObject instances.

So, 1) Load the Type Library containing the Object interface definition, and
2) get the ITypeInfo reference for the Class from the Type Library
interface.

Hope this helps!

Ed


Peter Pohmann

unread,
Sep 20, 2001, 9:43:45 AM9/20/01
to
Hi Ed,

thanks a lot. It helps at least for the second part of my problem. But I
am still uncertain about the first part. The dispatch interface I want
to
implement is not a dual one. This means I cannot derive an
implementation
from it and there seems to be no class that supports me in implementing
the GetIDsOfNames, Invoke etc methods.

I also noted that I can declare a parameter of type dispinterface like
that:

type
MyDisp = dispinterface
procedure Foo; dispid 1;
end;

procedure Test(MD: MyDisp);
begin
MD.Foo;
end;

But now: What can I pass to procedure Test? Deriving from MyDisp isn't
possible, IDispatch or OleVariant is rejected by the compiler. Those
dispinterfaces just keep confusing me.

Best regards
Peter
--
.....................................................

Peter Pohmann, dataWeb GmbH
Tools and Components for Delphi and Web Developers
http://www.dataweb.de
mailto: poh...@dataweb.de

Robert Barr

unread,
Sep 22, 2001, 11:13:52 AM9/22/01
to Peter Pohmann
Peter,

I think there's a much easier way to implement this. Download Binh Ly's
ComLib library
(http://www.techvanguards.com/com/resources/downloads.asp). You will
want to use the TEventSinks class to handle events with TAutoIntfObject.

Here's an example of how I've used it.

TIntfMenuItem = class(TAutoIntfObject, IActionMenuItem,
IConnectionPointContainer, IWrappedMenuHelper, IActionUpdateHelper)
private
FEventSinks: TEventSinks;
... // much code removed
protected
... // much code removed
public
constructor Create(const AParent: IDispatch);
destructor Destroy; override;
{ IConnectionPointContainer }
property EventSinks: TEventSinks read FEventSinks
implements IConnectionPointContainer;
end;


constructor TIntfMenuItem.Create(const AParent: IDispatch);
var
TypeLib: ITypeLib;
begin
// Get TypeLib of IActionMenuItem interface
// I'm using a interface in a separate typelib, that's the reason
// for this.
OleCheck(LoadRegTypeLib(LIBID_stdapext, cTypeLibVersion, 0, 0,
TypeLib));

if Assigned(TypeLib) then
begin
// Seems with D4 you have to do this, otherwise an A/V will occur
{$IFDEF REFLOCK}Inc(FRefCount);{$ENDIF} // D4 artificial lock

inherited Create(TypeLib, IActionMenuItem);
FParent := AParent;

{$IFDEF REFLOCK}
FEventSinks := TEventSinks.Create(Self);
// Initialize and hookup supported events
FEventSinks.AddEvent(IActionEvents);
FEventSinks.AddEvent(IActionListenerEvents);
Dec(FRefCount); // D4 artificial lock
{$ENDIF}
end;
end;

HTH,

Robert

Ed Hillmann

unread,
Sep 23, 2001, 6:36:18 PM9/23/01
to
Hi Peter. Sorry for the late reply.

I think (emphasize think) that a dispinterface must be defined within a type
library. Let me just spit out my understanding of Interfaces and
Dispinterfaces and see what sticks.

Interfaces can be defined in units and outside of type libraries. This
allows the Delphi IDE to use the definition for early-binding. It allows
compile-checking of calls to the interface (that they're valid), their use
within the IDE (see them and their members in a Pull-down list, etc).
Interfaces are commonly associated with COM objects, etc, but can be used
completely independant of Automation objects and their constructs. You can
define an interface in a Delphi Unit, and other units can use the definition
and have it all compiled into the one binary.

Dispinterfaces are a bit more MS specific. They are defined for the
Late-binding approach, which offers no compile-time validation, only runtime
usage. The D5 help, "Dispatch Type Information", states that
"Dispinterfaces are only accessible through dynamic binding, while
interfaces can have static binding through a vtable."

When they say dynamic binding, it implies that (at runtime) the interface is
defined in a binary file (a type library, one that is internal to the
EXE/DLL or defined in an external EXE/DLL) and that the interface is
extracted from the library. You're manually using the definitions that get
generated in a Delphi _TLB.pas file. But that's the key point: an _TLB.pas
file is always generated from a Type Library. It's a wrapper around a Type
Library binary file, not the actual definition itself.

It is possible to define a Dispinterface in a type library. It can be
defined in such a way that it's not a Dual interface. But I do think that
it will have to be contained within a Type Library, due to the nature of how
Dispinterfaces are used dynamically. If they are defined in a library, then
you can then follow the previous steps I mentioned.

Dispinterfaces sure are confusing, I agree! :)

Hope this helps,
Ed
"Peter Pohmann" <poh...@dataweb.de> wrote in message
news:3BA9F291...@dataweb.de...

Ed Hillmann

unread,
Sep 23, 2001, 6:41:48 PM9/23/01
to
Sorry for doubling up, but I found some more Delphi help about
Dispinterfaces. The pages is titled "Attribute pages for dispatch". It's
help associated with Delphi's Type library editor...

<doco start>
The following attributes apply to the dispinterface:

Attribute Meaning
Name The name by which the dispinterface is known in the type library. It
must be a unique name within the type library.
GUID The globally unique 128-bit identifier of the dispatch (optional).
Version A particular version of the dispinterface in cases where multiple
versions of the dispinterface exist. The version is either a pair of decimal
integers separated by a period, or a single decimal integer. The first of
the two integers represents the major version number, and the second
represents the minor version number. If a single integer is used, it
represents the major version number. Both major and minor version numbers
are short unsigned integers in the range between 0 and 65535, inclusive.
Help String A short description of the element. Used with Help Context to
provide Help as a Help file.
Help Context The Help context ID of the element, which identifies the Help
topic within the Help file for this element.
Help String Context For help DLLs, the Help context ID of the element, which
identifies the Help topic within the help file for this element. Used with
Help String DLL to provide Help as a separate DLL.
<doco end>

The most revealing part, to me, is the Name. It certainly implies that the
dispinterface will be extracted from a type library. So it's not enough to
define a dispinterface in a unit by hand. It will need to be defined in a
Type Library which is then imported or defined as the type library for the
project (which will generate the _TLB.pas wrapper file containing the
dispinterface definition that can be used by the Delphi compiler).

Ed

"Ed Hillmann" <Edward_...@adc.com> wrote in message
news:3bae63ec_2@dnews...

0 new messages