Discussion:
Typelib - not quite knowing how an interface needs to be described.
(too old to reply)
R.Wieser
2019-02-08 18:44:30 UTC
Permalink
Hello all,

I've been writing ActiveX stuff (that is what I think its called) that I
could use with VBScript, and when I began doing so I sought for and found a
description to how to write a typelib, and that was what I've been using for
all this time.

The problem is that I do not really understand what I'm using, and none of
the MSDN pages I found over the time describing the different keywords
helped much either.

For example, this interface definition I'm currently using:
--------------------------------------------
[
uuid (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
,odl, oleautomation, dual, nonextensible
]

interface ITesting : IDispatch {
[id(0x00000001)] HRESULT GetText([out, retval] BSTR* String);
[id(0x00000002)] HRESULT SetText([in] BSTR String);
}
--------------------------------------------
What I currently (don't) know about it:

odl -> current interface description type (no idea what the others look like
though)

oleautomation -> No idea what this is for/aimed at.

dual -> Uses IDispatch to call the methods, but direct calling of those
methods is allowed too (don't they all?) .

nonextensible -> the object can only be used as-is, methods cannot be added
(just added it because I had (and still have) no idea of what run-time added
methods look like or how to deal with them)

[id(0x????)] -> No idea what this is for. Using random numbers does not
seem to change anything. They just cannot be duplicates of each other.

In the last few days I did some more searching, and stumbled over an example
which did not use he above id()s. I tried it, and everything kept running.
I also removed "oleautomation", and it still kept running.

In other words: I'm using a template which seems to contain stuff I do not
actually need. :-(

tl;dr:
I could use a (bare bones) typelib definition example for usage with
VBScript /together with/ some info to what the different items in there
actually do/how they interact with each other.

Other examples accompanied with info about what it contains (and why!) would
be very welcome too ofcourse. :-)

Possibly even better: A website which actually describes (as/like a
tutorial) the different forms (IDL, ODL, COM, ActiveX (more?) ) and their
intended usage.

Regards,
Rudy Wieser
JJ
2019-02-09 12:33:34 UTC
Permalink
Post by R.Wieser
Hello all,
I've been writing ActiveX stuff (that is what I think its called) that I
could use with VBScript, and when I began doing so I sought for and found a
description to how to write a typelib, and that was what I've been using for
all this time.
The problem is that I do not really understand what I'm using, and none of
the MSDN pages I found over the time describing the different keywords
helped much either.
--------------------------------------------
[
uuid (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
,odl, oleautomation, dual, nonextensible
]
interface ITesting : IDispatch {
[id(0x00000001)] HRESULT GetText([out, retval] BSTR* String);
[id(0x00000002)] HRESULT SetText([in] BSTR String);
}
--------------------------------------------
odl -> current interface description type (no idea what the others look like
though)
oleautomation -> No idea what this is for/aimed at.
dual -> Uses IDispatch to call the methods, but direct calling of those
methods is allowed too (don't they all?) .
nonextensible -> the object can only be used as-is, methods cannot be added
(just added it because I had (and still have) no idea of what run-time added
methods look like or how to deal with them)
[id(0x????)] -> No idea what this is for. Using random numbers does not
seem to change anything. They just cannot be duplicates of each other.
In the last few days I did some more searching, and stumbled over an example
which did not use he above id()s. I tried it, and everything kept running.
I also removed "oleautomation", and it still kept running.
In other words: I'm using a template which seems to contain stuff I do not
actually need. :-(
I could use a (bare bones) typelib definition example for usage with
VBScript /together with/ some info to what the different items in there
actually do/how they interact with each other.
Other examples accompanied with info about what it contains (and why!) would
be very welcome too ofcourse. :-)
Possibly even better: A website which actually describes (as/like a
tutorial) the different forms (IDL, ODL, COM, ActiveX (more?) ) and their
intended usage.
Regards,
Rudy Wieser
LOL, this is one of the reasons why I don't use a type library at all. It's
just too much for me. I rely only on IDispatch/IDispatchEx.
R.Wieser
2019-02-09 15:31:39 UTC
Permalink
JJ,
Post by JJ
LOL, this is one of the reasons why I don't use a type library
at all. It's just too much for me. I rely only on IDispatch/IDispatchEx.
:-) I'm afraid I have to, as VBScript won't interface with an object
otherwise.

Luckily a typelib isn't that hard to maintain.

And by the way: the "interface ITesting : IDispatch" line in my example
means that my objects also use the dispatch method of calling the shown
methods. Never tried the IDispatchEx interface though ...

Regards,
Rudy Wieser
René König
2019-02-09 13:52:04 UTC
Permalink
Hi,
Post by R.Wieser
odl -> current interface description type (no idea what the others look like
though)
ODL is not current, MIDL is:
https://docs.microsoft.com/en-us/windows/desktop/Midl/midl-and-odl

But all the ODL is included. ;-)
Post by R.Wieser
oleautomation -> No idea what this is for/aimed at.
That means that the interface uses automation compatible datatypes only.
With having this flag set, there's no need to build custom Proxy/Stub
DLLs, you can use the system provided DLL for marshaling.

After registering the TypeLib, have a look at the registered interface.
You'll find these entries:

[HKEY_CLASSES_ROOT\Interface\{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\ProxyStubClsid32]
@="{00020424-0000-0000-C000-000000000046}"

And when looking up the CLSID, you'll find a class named PSOAInterface
(ProxyStubOleAutomation), implemented in oleaut32.dll
Post by R.Wieser
dual -> Uses IDispatch to call the methods, but direct calling of those
methods is allowed too (don't they all?) .
Yes. You implement your object as usual, but also implement IDispatch.
That allows a client to choose what interface to use. You, probably
having an assembler written client, will certainly not using IDispatch
for calling methods. OTOH, a VBScript client will.

With having a "dual" object, you're open for the rest of the world. This
works pretty well, as long as you're using automation compatible types
only. And you do, says the oleautomation flag.
Post by R.Wieser
nonextensible -> the object can only be used as-is, methods cannot be added
(just added it because I had (and still have) no idea of what run-time added
methods look like or how to deal with them)
Right. I too haven't added methods at runtime so far. But JScript
Arrays, for examples, do.
Post by R.Wieser
[id(0x????)] -> No idea what this is for. Using random numbers does not
seem to change anything. They just cannot be duplicates of each other.
It's all about IDispatch. IDispatch allows calling methods by name. A
client first calls GetIDsOfNames, to translate a name into its
corresponding ID. When having the ID, you're ready to call Invoke.

And before you ask: Right, when having the ID in advance, there's no
need to call GetIDsOfNames. :-)
Post by R.Wieser
In the last few days I did some more searching, and stumbled over an example
which did not use he above id()s. I tried it, and everything kept running.
If you don't implement IDispatch, you don't need IDs in the IDL.
Post by R.Wieser
I also removed "oleautomation", and it still kept running.
No marshaling was involved. If it would, you already knew what
E_NOINTERFACE is. ;-)
Post by R.Wieser
In other words: I'm using a template which seems to contain stuff I do not
actually need. :-(
Everything is needed, believe me. ;-)

Rene
René König
2019-02-09 13:55:21 UTC
Permalink
Post by René König
Post by R.Wieser
I also removed "oleautomation", and it still kept running.
No marshaling was involved. If it would, you already knew what
E_NOINTERFACE is. ;-)
I meant to say REGDB_E_IIDNOTREG!
R.Wieser
2019-02-09 16:48:30 UTC
Permalink
René,
I know, its about as much as I've been able to find. Just not what exactly
the difference is / what either looks like. Most all info I find /says/
its different, but not in which way.

As for MIDL being current, I've got a "rather old" programming language
(Assembly, using Borlands Tasm32 v5) with accompanying tools: I'm still
using MkTypeLib.
Post by René König
Post by R.Wieser
oleautomation -> No idea what this is for/aimed at.
That means that the interface uses automation compatible datatypes only.
With having this flag set, there's no need to build custom Proxy/Stub
DLLs, you can use the system provided DLL for marshaling.
I noticed that a lot of auto-conversion was going on, but I assumed it was
the (VB)Scripting engine which took care of that.
Post by René König
[HKEY_CLASSES_ROOT\Interface\{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\ProxyStubClsid32]
@="{00020424-0000-0000-C000-000000000046}"
And when looking up the CLSID, you'll find a class named PSOAInterface
(ProxyStubOleAutomation), implemented in oleaut32.dll
Yup, its there alright. I'll have to do some more googleing for that
interface (if only to know how that variable marshalling works).
Post by René König
Yes. You implement your object as usual, but also implement
IDispatch.That allows a client to choose what interface to use.
You, probably having an assembler written client, will certainly
not using IDispatch for calling methods. OTOH, a VBScript
client will.
:-) I've experimented a lot with objects (to get to know them) and have
written a number of "direct access" ones. Ony after that I thought of
writing one that would be callable from a scripting engine like VBScript.
Post by René König
With having a "dual" object, you're open for the rest of the world.
This works pretty well, as long as you're using automation compatible
types only.
About that, I seem to have read that marking an interface "dual" has the
same end effect. Ah yes, here: "Specifying dual on an interface implies
that the interface is compatible with Automation, and therefore causes both
the TYPEFLAG_FDUAL and TYPEFLAG_FOLEAUTOMATION flags to be set."
(https://docs.microsoft.com/en-us/previous-versions/windows/desktop/automat/dual)

And while peeking at it and the "oleautomation" docpage it looks like the
"dual" causes the IDispatch interface to be included, and the
"oleautomation" marshals the arguments (and forces the HRESULT syntax(? not
fully sure) ).
Post by René König
And you do, says the oleautomation flag.
Not anymore! , as its already included thru the "dual" setting. :-)
Post by René König
Right. I too haven't added methods at runtime so far. But
JScript Arrays, for examples, do.
What do they do that needs it ? (With a keyword or two I stand more chance
to googeling something about it ... )
Post by René König
And before you ask: Right, when having the ID in advance, there's
no need to call GetIDsOfNames. :-)
Thats the odd thing: I've /always/ seen GetIDsOfNames being called (with
Invoke after it), and I've been using those IDs until this week. No idea
what should do/have done to skip dat method call. :-(

And as mentioned, I have experimented with giving a method a "random" ID
(not matching VTable index) and everything kept working. Even now I've
removed them I cannot see any change in called IDispatch methods. :-\
Post by René König
If you don't implement IDispatch, you don't need IDs in the IDL.
But I do! "interface ITesting : IDispatch". And I do not seem to need
them. What is going On here ? <confused>

Wait: Does it perhaps have something to do with a difference between
IDispatch and its "Ex" version ?
Post by René König
No marshaling was involved. If it would, you already knew
what E_NOINTERFACE is. ;-)
Could you please describe what "marshaling" is in this context ? I've
seen it used before, but always got the idea it had something to do with
transferring data outof / into different processes. I'm not so sure what
oleautomation (variable type conversion as far as I can see) has to do with
it.
Post by René König
Everything is needed, believe me. ;-)
Thas a bit of a problem: a few days ago I removed those IDs as well as the
"oleautomation" keywords, and everything kept working. To me that looks
as if I've got some superfluous stuff in there ...

And that pretty-much sums up the problem : I works, but I have no idea why.
:-(
Post by René König
Post by R.Wieser
No marshaling was involved. If it would, you already knew what
E_NOINTERFACE is. ;-)
I meant to say REGDB_E_IIDNOTREG!
I can't remember ever having encountered that error.

And the same problem here: when I throw that into Google I get multiple
pages with "I've got an REGDB_E_IIDNOTREG error, what do I do now ?" hits,
but no description, let alone what exactly causes it. :-\

Regards,
Rudy Wieser
René König
2019-02-09 18:42:16 UTC
Permalink
Post by R.Wieser
I know, its about as much as I've been able to find. Just not what exactly
the difference is / what either looks like. Most all info I find /says/
its different, but not in which way.
Differences Between MIDL and MkTypLib:
https://docs.microsoft.com/en-us/windows/desktop/midl/differences-between-midl-and-mktyplib
Post by R.Wieser
I noticed that a lot of auto-conversion was going on, but I assumed it was
the (VB)Scripting engine which took care of that.
IDispatch::Invoke operates on VARIANTs and may convert parameters to
what is needed (VariantChangeType/Ex). When speaking about the return
value, it is the scripting engine, indeed.
Post by R.Wieser
About that, I seem to have read that marking an interface "dual" has the
same end effect. Ah yes, here: "Specifying dual on an interface implies
that the interface is compatible with Automation, and therefore causes both
the TYPEFLAG_FDUAL and TYPEFLAG_FOLEAUTOMATION flags to be set."
(https://docs.microsoft.com/en-us/previous-versions/windows/desktop/automat/dual)
Midl.exe gives you a nice warning when accidentally using non compatible
types on an "oleautomation" flagged interface, not with "dual" only, IIRC.
Post by R.Wieser
And while peeking at it and the "oleautomation" docpage it looks like the
"dual" causes the IDispatch interface to be included, and the
"oleautomation" marshals the arguments (and forces the HRESULT syntax(? not
fully sure) ).
I checked it right now: It does *not* include in the resulting TypeLib.
Post by R.Wieser
Post by René König
And you do, says the oleautomation flag.
Not anymore! , as its already included thru the "dual" setting. :-)
Post by René König
Right. I too haven't added methods at runtime so far. But
JScript Arrays, for examples, do.
What do they do that needs it ? (With a keyword or two I stand more chance
to googeling something about it ... )
Example:

var arr = new Array();
arr["one"] = 1;
arr["two"] = 2;
WScript.Echo(arr["one"]);
WScript.Echo(arr.two); // <--
Post by R.Wieser
Thats the odd thing: I've /always/ seen GetIDsOfNames being called (with
Invoke after it), and I've been using those IDs until this week. No idea
what should do/have done to skip dat method call. :-(
Comparing strings can get time consuming. This why they made is possible
to do string resolution once, cache the returned value(s) and then just
use them. When having a general purpose helper function which wraps
calls to GetIDsOfNames/Invoke, you usually have no cache implemented -
both calls come in tandem then all the time.

If you already *know* the IDs in advance, there's actually no need to
call GetIDsOfNames. But remember, you cannot know all possible IDs in
advance when using an extensible object.
Post by R.Wieser
And as mentioned, I have experimented with giving a method a "random" ID
(not matching VTable index) and everything kept working. Even now I've
removed them I cannot see any change in called IDispatch methods. :-\
This has nothing to do with the VTable. The ID can have all values you
give them, as long as they're unique (yes, I know, they may occur twice
when it comes to properties). And yes, you can remove them entirely. All
it does is specifying what GetIDsOfNames will return when called with a
specific name.

BUT: Don't leave them out! The idl compiler will tell you, when an
identifier is in use. That *is* helpful. Additionally, you're usually
don't implement GetIDsOfNames on your own. You'll probably let the
TypeLib doing the translation, not really possible without IDs.

Then, there are tools like OleView out there. And these display the IDs
as well. So, please, don't remove them.
Post by R.Wieser
Post by René König
If you don't implement IDispatch, you don't need IDs in the IDL.
But I do! "interface ITesting : IDispatch". And I do not seem to need
them. What is going On here ? <confused>
As I can speak for me, the object holds a ITypeInfo* for the interface
description. The entire implementation of GetIDsOfNames looks like this:

IFACEMETHODIMP
MyCoolObject::GetIDsOfNames(REFIID, LPOLESTR* rgszNames, UINT cNames,
LCID, DISPID* rgDispId)
{
return(m_pTypeInfo->GetIDsOfNames(rgszNames, cNames, rgDispId));
}

A one-liner. For this to work, IDs *are* needed.
Post by R.Wieser
Could you please describe what "marshaling" is in this context ? I've
seen it used before, but always got the idea it had something to do with
transferring data outof / into different processes. I'm not so sure what
oleautomation (variable type conversion as far as I can see) has to do with
it.
Marshaling means, that you don't have direct access to the object in
question. This is nothing visible to you, it just happens under special
circumstances. For example: Mark that object as being apartment threaded
and instantiate it from a multi threaded apartment.

To make it all work, the interface needs to be registered, so that the
correct proxy/stub pair can be created. And if this is oleut32.dll, a
message-only window gets created, like it or not. :-)
Post by R.Wieser
Post by René König
Everything is needed, believe me. ;-)
Thas a bit of a problem: a few days ago I removed those IDs as well as the
"oleautomation" keywords, and everything kept working. To me that looks
as if I've got some superfluous stuff in there ...
Being as descriptive as possible is not that superfluous for me...
Post by R.Wieser
And the same problem here: when I throw that into Google I get multiple
pages with "I've got an REGDB_E_IIDNOTREG error, what do I do now ?" hits,
but no description, let alone what exactly causes it. :-\
REGDB_E_IIDNOTREG means that there's no entry below HKCR\Interfaces.
When marshaling has to take place and the object does not implement
IMarshal, no proxy/stub can be created.

Rene
R.Wieser
2019-02-10 07:57:50 UTC
Permalink
René,
Post by René König
https://docs.microsoft.com/en-us/windows/desktop/midl/differences-between-midl-and-mktyplib
Yeah, I found that one too. But as nothing in there touched what I'm
currently using (my current template) I've just stored it for later
consideration.
Post by René König
Post by R.Wieser
And while peeking at it and the "oleautomation" docpage it looks like
the "dual" causes the IDispatch interface to be included, and the
"oleautomation" marshals the arguments (and forces the HRESULT syntax
(? not fully sure) ).
I checked it right now: It does *not* include in the resulting TypeLib.
??? /what/ does it not include in the typelib ?
Post by René König
Post by R.Wieser
What do they do that needs it ? (With a keyword or two I stand more
chance to googeling something about it ... )
var arr = new Array();
arr["one"] = 1;
arr["two"] = 2;
WScript.Echo(arr["one"]);
WScript.Echo(arr.two); // <--
Thanks. Yeah, that looks rather interresting (no idea how it works). :-)
Post by René König
Comparing strings can get time consuming. This why they made is
possible to do string resolution once, cache the returned value(s) and
then
just use them.
I always assumed that that caching was a given, performed by whatever calls
my objects GetIdsOfNames method.
Post by René König
When having a general purpose helper function which wraps
calls to GetIDsOfNames/Invoke, you usually have no cache
implemented - both calls come in tandem then all the time.
I don't get it: I could imagine that those IDs could be the indices into the
objects VTable (offsetted from just after the IDispatch methods), which
means there would not be a need for a cache to begin with. But it doesn't
look like they are. So what /are/ they ? Also, which method receives
those IDs - as far as I can tell, not any of the four IDispatch ones.
Post by René König
If you already *know* the IDs in advance, there's actually no need
to call GetIDsOfNames. But remember, you cannot know all possible
IDs in advance when using an extensible object.
:-) Remember I specified "nonextensible" (made a good choice there, even
when not quite knowing why) ? I could imagine that, when using it, the
IDs would switch from being identifiers that would need to be translated (by
GetIdsOf Names ?) into function pointers to indices that only need to be
multiplied by four - which does not need any specific handling or caching.
It does not seem to work that way though ...

Yep. One of those areas which I've not been able to find much (pertinent)
info or examples on, and at some point was just happy I got it to work (and
suspended my efforts to figure it out "until a later time") . :-(
Post by René König
As I can speak for me, the object holds a ITypeInfo* for the interface
...
Post by René König
A one-liner. For this to work, IDs *are* needed.
With all due respect, but I have empirical proof here that they are /not/
needed. As said, I removed them from my TypeLib definition, and all kept
running fine.

Though that seems to mean there is a difference in what you and I are
working with. As for what that difference might be ? At this moment I
have absolutily no idea.

And for reference, this is my code (sans some checking and debugging
output):

- - - - - - - - - - - - - - - -
Dispatch_GetIDsOfNames proc
arg
@@oThis:DWORD,@@RefIID:DWORD,@@rgszNames:DWORD,@@cNames:DWORD,@@lcid:DWORD,@@rgDispID:DWORD

mov ebx,[@@oThis]
mov ebx,[ebx].Dispatch_oTypeInfo

mov eax,[ebx]
call
[eax].ITypeInfo_pGetIDsOfNames,ebx,[@@rgszNames],[@@cNames],[@@rgDispID]

ret
endp
- - - - - - - - - - - - - - - -

I do not see those TypeLib IDs here anywhere ... And for the record: Yes,
when I first started with using TypeLibs I expected to see them somewhere
and did look for them. Never found them though. :-|
Post by René König
For example: Mark that object as being apartment threaded
and instantiate it from a multi threaded apartment
:-) I've never consciously touched the "apartment" subject, so the
comparision doesn't do much for me I'm afraid. Sorry.
Post by René König
Being as descriptive as possible is not that superfluous for me...
Luckily you do not that believe in that when putting a line like the above
down, otherwise that single line would have expanded to a few volumes about
language definition, usage and what not. :-)

And for the record: "superfluous" in this context is ment as stuff which is
not needed, but doesn't do any harm either. Like including "oleautomation"
when a "dual" inclusion already takes care of that (I'll leave those IDs up
for debate).
Post by René König
REGDB_E_IIDNOTREG means that there's no entry below
HKCR\Interfaces. When marshaling has to take place and the
object does not implement IMarshal, no proxy/stub can be created.
Thats sounds rather logical. Thanks.

Regards,
Rudy Wieser
René König
2019-02-10 09:27:17 UTC
Permalink
Post by R.Wieser
Post by René König
I checked it right now: It does *not* include in the resulting TypeLib.
??? /what/ does it not include in the typelib ?
You still need to inherit from IDispatch. Setting "dual" does *not*
magically do that. The object's method count will reduce by 4 when not
doing so.
Post by R.Wieser
I always assumed that that caching was a given, performed by whatever calls
my objects GetIdsOfNames method.
Certainly not. Caching has to be done on a per object basis, as IDs can
be reused by other, unrelated objects.
Post by R.Wieser
I don't get it: I could imagine that those IDs could be the indices into the
objects VTable (offsetted from just after the IDispatch methods), which
means there would not be a need for a cache to begin with. But it doesn't
look like they are. So what /are/ they ? Also, which method receives
those IDs - as far as I can tell, not any of the four IDispatch ones.
They are just Identifiers, assigned by the programmer. Of course, these
can be table indices. But this is an implementation detail. It's up to
you. Everything is fine, but you better do not assign negative numbers,
as these are most commonly used by standard properties.

All the outside world needs to know is what method an identifier is used
for. Everything else happens inside the object in question.

And yes, these Identifiers are usually only used by IDispatch/Ex.
Post by R.Wieser
Post by René König
If you already *know* the IDs in advance, there's actually no need
to call GetIDsOfNames. But remember, you cannot know all possible
IDs in advance when using an extensible object.
:-) Remember I specified "nonextensible" (made a good choice there, even
when not quite knowing why) ? I could imagine that, when using it, the
IDs would switch from being identifiers that would need to be translated (by
GetIdsOf Names ?) into function pointers to indices that only need to be
multiplied by four - which does not need any specific handling or caching.
It does not seem to work that way though ...
Just multiplying the IDs by four does not work. Take a property which is
readable as well as modifiable. You'll get two different methods sharing
the *same* ID.

Of course, without using properties, IDs actually *can* be just
table-indices. It depends on how *you* are implementing Invoke. As I can
speak for me, I don't care. I'm just calling ITypeInfo::Invoke. All the
magic happens in there, but this too requires valid IDs.
Post by R.Wieser
Yep. One of those areas which I've not been able to find much (pertinent)
info or examples on, and at some point was just happy I got it to work (and
suspended my efforts to figure it out "until a later time") . :-(
Post by René König
As I can speak for me, the object holds a ITypeInfo* for the interface
...
Post by René König
A one-liner. For this to work, IDs *are* needed.
With all due respect, but I have empirical proof here that they are /not/
needed. As said, I removed them from my TypeLib definition, and all kept
running fine.
Of course, all may work fine. It depends on your implementation.

But why do you choose a interface description language, when you don't
have any intents to describe your interfaces? Don't. It is perfectly
legal to answer IDispatch::GetTypeInfoCount with 0. And you don't really
need IDispatch::GetTypeInfo, just let every index by a bad index.

It reduces the number of possible clients, yes. But hey, *you* do know
what you're doing, so what.

Then, one step further, you can decide to return E_NOTIMPL on
GetIDsOfNames. You, and only you, already know the IDs. Yes, this too
reduces the number of possible client, so what.

Again: When you are calling a method through an automation interface
(IDispatch), it needs a valid Identifier. The ID has no special meaning
- this is up to the object's implementation. Whatever ID scheme you
choose, it is part of the object's specification, which you describe in
the IDL. So it has to be there.

Take your VBScript interpreter, for example. It actually implements
objects at runtime, when it comes to events. It's doing so by reading
your object description. No IDs - no luck. (I know, I know, this will
not be dual interfaces but dispinterfaces...)
Post by R.Wieser
Though that seems to mean there is a difference in what you and I are
working with. As for what that difference might be ? At this moment I
have absolutily no idea.
And for reference, this is my code (sans some checking and debugging
- - - - - - - - - - - - - - - -
Dispatch_GetIDsOfNames proc
arg
@@oThis:DWORD,@@RefIID:DWORD,@@rgszNames:DWORD,@@cNames:DWORD,@@lcid:DWORD,@@rgDispID:DWORD
mov ebx,[ebx].Dispatch_oTypeInfo
mov eax,[ebx]
call
ret
endp
- - - - - - - - - - - - - - - -
I do not see those TypeLib IDs here anywhere ... And for the record: Yes,
when I first started with using TypeLibs I expected to see them somewhere
and did look for them. Never found them though. :-|
The IDs are returned by GetIDsOfNames through the last parameter
(rgDispID). If you can't see them there, the call failed (GetIDsOfNames
did return an error value).
Post by R.Wieser
Post by René König
For example: Mark that object as being apartment threaded
and instantiate it from a multi threaded apartment
:-) I've never consciously touched the "apartment" subject, so the
comparision doesn't do much for me I'm afraid. Sorry.
Post by René König
Being as descriptive as possible is not that superfluous for me...
Luckily you do not that believe in that when putting a line like the above
down, otherwise that single line would have expanded to a few volumes about
language definition, usage and what not. :-)
And for the record: "superfluous" in this context is ment as stuff which is
not needed, but doesn't do any harm either. Like including "oleautomation"
when a "dual" inclusion already takes care of that (I'll leave those IDs up
for debate).
Post by René König
REGDB_E_IIDNOTREG means that there's no entry below
HKCR\Interfaces. When marshaling has to take place and the
object does not implement IMarshal, no proxy/stub can be created.
Thats sounds rather logical. Thanks.
Regards,
Rudy Wieser
R.Wieser
2019-02-11 12:43:32 UTC
Permalink
René,
Post by René König
You still need to inherit from IDispatch. Setting "dual" does
*not* magically do that.
I did not think it would.
Post by René König
Caching has to be done on a per object basis, as IDs can
be reused by other, unrelated objects.
True. But doesn't the calling program/object know which object its calling
? In other words: are the IDs not implicitily bound to it that way ?
Post by René König
They are just Identifiers, assigned by the programmer.
Yeah, I know that. No idea why its "just" identifiers though.
Post by René König
Just multiplying the IDs by four does not work. Take a property which
is readable as well as modifiable. You'll get two different methods
sharing the *same* ID.
Well, so much for identifying a specific method I guess: It also prohibits
using that ID for caching purposes (a single provided ID, two different
methods).

I have no idea what should go into a typelib, or why. And by extension I
/also/ have no idea what my implementation should look like (to match the
typelibs contents. Or rather vise-verse).
Post by René König
but you better do not assign negative numbers,
as these are most commonly used by standard properties
I'm only aware if three of them, including DISPID_UNKNOWN (-1) to be used
when a method is not found. I've used DISPID_NEWENUM (-4) a few times
now, but see I still have to take a peek at what DISPID_PROPERTYPUT (-3) is
there for.
Post by René König
Of course, all may work fine. It depends on your implementation.
And that circles us back to my thread-starting post :-((

I have no real idea to what that typelib definition should look like, and as
such also no idea what influence the different definitions might have on the
implementation (or vise-verse).
Post by René König
But why do you choose a interface description language, when you
don't have any intents to describe your interfaces?
I guess you missed the interface description example I included in my inital
message. If you didn't miss that, what the blazes are you talking about ?

Also, I don't think that the VBScript environment will accept an object
without one - at least, none of my information and/or examples in that
regard indicates anything like that. If you have a non-typelib
VBScripting engine object example I would really like to see it though.
Post by René König
It reduces the number of possible clients, yes.
Understood. But as I said in my initial post, my target is the VBScript
engine. Everything else I consider "for later scrutiny".
Post by René König
But hey, *you* do know what you're doing, so what.
Actually, no. Hence this thread. Duh.

But for some odd reason I believe empirical data over a persons word.
Especially when he doesn't even *try* to give an explanation to how the
empirical data (misunderstood or not - yes, I consider that a possibility)
came to be.
Post by René König
Again: When you are calling a method through an automation
interface (IDispatch), it needs a valid Identifier.
Possibly. But definitily not one I had to provide in the typelib
definition.
Post by René König
Whatever ID scheme you choose, it is part of the object's specification,
which
you describe in the IDL. So it has to be there.
No matter what you think you may know about this subject, my empirical data
does not match that. Ignoring it will do neither of us any good I'm afraid.

Besides that, if-and-when its mandatory, why doesn't MkTypeLib throw an
error on them being absent ?
Post by René König
The IDs are returned by GetIDsOfNames through the last parameter
(rgDispID). If you can't see them there, the call failed (GetIDsOfNames
did return an error value).
Although I have /no/ idea what that rgDispID datablock is supposed to look
like (MSDN nor a quick google revealed anything in that regard) I got the
brainfarth to give /one/ of my methods a recognisable ID, and see what the
result would be. It turns out the ID became visible as the first four
bytes of that datablock. I therefore assume (with nothing to back it up,
but for presumed uniformity of that datablock) that the first four bytes in
the other rgDispID datablocks also represent IDs. However, I specified
just a single one. Where the others came from ? I have no idea.

And as it turns out NEITHER DO YOU.

And no, its not /and has never been/ about the GetIDsOfNames method. It
was-and-is all about the TypeLib definition (as in: sourcefile), and what
needs to be in there. Those IDs ? They DO NOT need to be in there.


Having said that, there is a distinct possibility (educated guesswork) that
MkTypeLib (and possible MIDL too for that matter) will make up those IDs
when they are not provided. In other words: While not present in the
/definition/, they might well be (and probably are - have not checked it
though) present in the resulting .TLB.

Nonwithstanding our disagreement here, thank you for trying to help.

Regards
Rudy Wieser
René König
2019-02-12 11:37:31 UTC
Permalink
Post by R.Wieser
Well, so much for identifying a specific method I guess: It also prohibits
using that ID for caching purposes (a single provided ID, two different
methods).
It's one getter, one setter, differentiated by the flags given to Invoke
(parameter 4, wFlags). You're identifying a single property, hence
caching is not a problem at all.
Post by R.Wieser
I'm only aware if three of them, including DISPID_UNKNOWN (-1) to be used
when a method is not found. I've used DISPID_NEWENUM (-4) a few times
now, but see I still have to take a peek at what DISPID_PROPERTYPUT (-3) is
there for.
colldispid.h defines some others, olectl.h defines a ton others. But the
one thing to remember is, that negative numbers are reserved: "The
id-num is a 32-bit positive integral value. Negative IDs are reserved
for use by Automation."
https://docs.microsoft.com/en-us/windows/desktop/Midl/id
Post by R.Wieser
Besides that, if-and-when its mandatory, why doesn't MkTypeLib throw an
error on them being absent ?
OK, tried it right now, and yes, you're right, I was mistaken on this
one. MkTypeLib actually *does* auto-assignment of identifiers. Makes
sense, as there's not a single method without identifier. You'll get
these errors on [dispinterface]-objects though, as expected, but not on
[dual]-objects, for whatever reason.

I also tried different versions of IDL compilers and got different
auto-assignments, BTW. So that's nothing I would rely on.
Post by R.Wieser
Although I have /no/ idea what that rgDispID datablock is supposed to look
like (MSDN nor a quick google revealed anything in that regard) I got the
The documentation is pretty clear on this one:
https://docs.microsoft.com/en-us/windows/desktop/api/oaidl/nf-oaidl-idispatch-getidsofnames
Post by R.Wieser
And no, its not /and has never been/ about the GetIDsOfNames method. It
was-and-is all about the TypeLib definition (as in: sourcefile), and what
needs to be in there. Those IDs ? They DO NOT need to be in there.
You do *not* want predictable results, so please DO NOT specify them!
R.Wieser
2019-02-12 18:55:04 UTC
Permalink
René,
"The id-num is a 32-bit positive integral value. Negative IDs are
reserved for use by Automation."
https://docs.microsoft.com/en-us/windows/desktop/Midl/id
Thanks, stored with the other docs about the subject.
OK, tried it right now, and yes, you're right, I was mistaken on
this one. MkTypeLib actually *does* auto-assignment of identifiers.
Yeah, I also saw (forgot I had a dumper for compiled typelibs).
Makes sense, as there's not a single method without identifier.
Ever thought about the possibility that ITypeLib could have generated them
(read: they did not need to be in the resulting .TLB at all) ?

My first though was that it would possibly a file-wide flag (or all methods
have an ID, or none). Though that got shot down when I did that
"distinctive ID" test (for a single method).

But do me a favour: Next time when someone says he has got empirical data
than do not bluntly ignore it being said because you have some other,
seemingly conflicting idea in your head. You where really testing my
patience there. :-(
You'll get these errors on [dispinterface]-objects though, as expected,
but not on [dual]-objects, for whatever reason.
Did I already say that I do not really have a good idea to what goes into a
typelib desciption file and why ? I still don't. :-( :-) I've never used
a "dispinterface". No idea what it is, how it differes from what I now
use, or what its handy for.
Post by R.Wieser
Although I have /no/ idea what that rgDispID datablock is supposed to look
like (MSDN nor a quick google revealed anything in that regard) I got the
https://docs.microsoft.com/en-us/windows/desktop/api/oaidl/nf-oaidl-idispatch-getidsofnames
Yeah, I also found that page. But really ? All that it says about the
rgDispId argument is:

"Caller-allocated array, each element of which contains an identifier (ID)
corresponding to one of the names passed in the rgszNames array. The first
element represents the member name. The subsequent elements represent each
of the member's parameters."

It does not say anything about data sizes of those "elements", nor about a
parameter count or what the "member's parameters" actually look like. For
all I know that could be anything between a single one upto ... what ever
ammount of bytes. They do not even all need to be of the same size. No,
as documentation to rgDispId its rather worthless. :-(
You do *not* want predictable results, so please DO NOT specify them!
Ehrmm ... That sounds like sarcasm. Why? I though we established that you
do /not need/ to supply them, as in that case MkTypeLib will generate them
for you. So why did you ?

Regards,
Rudy Wieser
R.Wieser
2019-02-15 07:03:54 UTC
Permalink
René,
Post by René König
You do *not* want predictable results, so please DO NOT specify them!
I forgot to ask: What causes those results to become unpredictable when you
do not explicitily specify those IDs yourself ? Do you have an example
of it ?

And pretty much the same counter reasoning here: If that (unpredictable
results) would be the case, why would MkTypeLib allow you to (without as
much as a warning) leave those IDs out ?

Regards,
Rudy Wieser

Loading...