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

Using same interfaces for in-proc vs. out-proc

57 views
Skip to first unread message

Drew

unread,
Nov 4, 2009, 12:08:28 AM11/4/09
to
Is there a way to have both an in-proc (DLL) COM server and an out-of-proc
(EXE) COM server that differ only by LIBID (all interfaces/UDTs have the
same GUID), and if so what would be a good approach (maybe MIDL
preprocessor), and if it's not possible, why not?

Thanks,
Drew


Igor Tandetnik

unread,
Nov 4, 2009, 12:31:47 AM11/4/09
to
Drew wrote:
> Is there a way to have both an in-proc (DLL) COM server and an out-of-proc
> (EXE) COM server that differ only by LIBID (all interfaces/UDTs have the
> same GUID)

You mean CLSID, not LIBID, right? It's a bad idea to have two type libraries describing the same interface, and it's not clear why you would ever want to do that. Build your type library as a separate TLB file, then reuse it from as many servers as you want.
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not necessarily a good idea. It is hard to be sure where they are going to land, and it could be dangerous sitting under them as they fly overhead. -- RFC 1925

Drew

unread,
Nov 4, 2009, 12:35:23 PM11/4/09
to

"Igor Tandetnik" <itand...@mvps.org> wrote in message
news:u26XeARX...@TK2MSFTNGP02.phx.gbl...

Drew wrote:
> Is there a way to have both an in-proc (DLL) COM server and an out-of-proc
> (EXE) COM server that differ only by LIBID (all interfaces/UDTs have the
> same GUID)

>You mean CLSID, not LIBID, right? It's a bad idea to have two type
>libraries describing the same interface, and it's not clear why you would
>ever want to do that. Build >your type library as a separate TLB file, then
>reuse it from as many servers as you want.

But doesn't the LIBID, the one provided to the IDispatchImpl<> have to be
unique to determine whether to invoke the EXE or the DLL version of the
server?

Thanks,
Drew


Igor Tandetnik

unread,
Nov 4, 2009, 12:49:13 PM11/4/09
to
Drew <d...@dam.com> wrote:
> "Igor Tandetnik" <itand...@mvps.org> wrote in message
> news:u26XeARX...@TK2MSFTNGP02.phx.gbl...
> But doesn't the LIBID, the one provided to the IDispatchImpl<> have
> to be unique to determine whether to invoke the EXE or the DLL
> version of the server?

"I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question." - Charles Babbage.

Seriously, with all due respect, I can't imagine what kind of mental picture of COM architecture you have in your mind. Whatever it is, it's incorrect.

Naturally, the client must have already "invoked" (by which I guess you mean "created an instance of") the server (whether EXE or DLL) in order to obtain IDispatch pointer from it in the first place, before a single line in IDispatchImpl implementation is executed. The LIBID is only used to look up the type library in the registry (this type library may be bound as a resource to some DLL or EXE, or be packaged as a standalone TLB file).

Drew

unread,
Nov 4, 2009, 5:55:13 PM11/4/09
to

"Igor Tandetnik" <itand...@mvps.org> wrote in message
news:%23Rn9fcX...@TK2MSFTNGP02.phx.gbl...

Drew <d...@dam.com> wrote:
> "Igor Tandetnik" <itand...@mvps.org> wrote in message
> news:u26XeARX...@TK2MSFTNGP02.phx.gbl...
> But doesn't the LIBID, the one provided to the IDispatchImpl<> have
> to be unique to determine whether to invoke the EXE or the DLL
> version of the server?

"I am not able rightly to apprehend the kind of confusion of ideas that
could provoke such a question." - Charles Babbage.

Seriously, with all due respect, I can't imagine what kind of mental picture
of COM architecture you have in your mind. Whatever it is, it's incorrect.

Naturally, the client must have already "invoked" (by which I guess you mean
"created an instance of") the server (whether EXE or DLL) in order to obtain
IDispatch pointer from it in the first place, before a single line in
IDispatchImpl implementation is executed. The LIBID is only used to look up
the type library in the registry (this type library may be bound as a
resource to some DLL or EXE, or be packaged as a standalone TLB file).


OK, maybe I'm not phrasing this right. By the way, this isn't my idea. "The

LIBID is only used to look up the type library in the registry (this type
library may be bound as a resource to some DLL or EXE, or be packaged as a

standalone TLB file).". I understand this. In this case the typelib is bound
as a resource. Now, we have a ODL for the EXE and an IDL for the DLL that
are maintained seperately and differ only by library name, "MyLibrary"(EXE)
and "MyLibraryX"(DLL). Also LIBID and all UDTs and interface/coclass GUIDs
are different. In the implementation header files we have code like:

namespace SomeColl
{
// We always need to provide the following information
typedef std::map< CAdapt< CComBSTR >, CComVariant > ContainerType;
typedef VARIANT ExposedType;
typedef IEnumVARIANT EnumeratorInterface;
typedef _IDualSomeCollection CollectionInterface;

// Typically the copy policy can be calculated from the typedefs defined
above:
// typedef VCUE::GenericCopy<ExposedType, ContainerType::value_type>
CopyType;
// However, we may want to use a different class, as in this case:
typedef VCUE::MapCopy<ContainerType, ExposedType> CopyType;

// (The advantage of MapCopy is that we don't need to provide
implementations
// of GenericCopy for all the different pairs of key and value types)
// Now we have all the information we need to fill in the template
arguments on the implementation classes
typedef CComEnumOnSTL< EnumeratorInterface,
&__uuidof(EnumeratorInterface), ExposedType,
CopyType, ContainerType > EnumeratorType;
typedef VCUE::ICollectionOnSTLCopyImpl< CollectionInterface,
ContainerType, ExposedType,
CopyType, EnumeratorType > CollectionType;
}; // namespace SomeColl;
using namespace SomeColl;
/////////////////////////////////////////////////////////////////////////////
// CSomeCollection
class ATL_NO_VTABLE CSomeCollection :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CSomeCollection, &CLSID_Somes>,
#ifndef BUILDING_DLL
public IDispatchImpl<SomeColl::CollectionType, &IID__IDualSomeCollection,
&LIBID_MyLibrary, 2, 0>
#else
public IDispatchImpl<SomeColl::CollectionType, &IID__IDualSomeCollection,
&LIBID_MyLibraryX, 2, 0>
#endif
{
// ...
};

What is wanted, by someone who is very well versed in C++ but who I don't
think has much ATL/COM experience, is to use only the ODL or IDL and have
them differ only by LIBID so that we can somehow templatize the creation of
each interface to use the correct LIBID. My personal opinion on this is that
it is not possible but I need to have a good explanation of why.
Unfortunately (for me that is) it has been so long since I even had to touch
this code, and got much of the above code from MSFT examples, that I can't
provide the needed explanation.

Thanks,
Drew


Igor Tandetnik

unread,
Nov 4, 2009, 7:01:50 PM11/4/09
to
Drew <d...@dam.com> wrote:
> In this case the typelib is bound as a resource.

... to which module?

> Now, we have a ODL
> for the EXE and an IDL for the DLL that are maintained seperately and
> differ only by library name, "MyLibrary"(EXE) and "MyLibraryX"(DLL).
> Also LIBID and all UDTs and interface/coclass GUIDs are different.

Your first message stated "all interfaces/UDTs have the same GUID". Which way is it?

> // CSomeCollection
> class ATL_NO_VTABLE CSomeCollection :
> public CComObjectRootEx<CComSingleThreadModel>,
> public CComCoClass<CSomeCollection, &CLSID_Somes>,
> #ifndef BUILDING_DLL
> public IDispatchImpl<SomeColl::CollectionType,
> &IID__IDualSomeCollection, &LIBID_MyLibrary, 2, 0>
> #else
> public IDispatchImpl<SomeColl::CollectionType,
> &IID__IDualSomeCollection, &LIBID_MyLibraryX, 2, 0>
> #endif
> {
> // ...
> };
>
> What is wanted, by someone who is very well versed in C++ but who I
> don't think has much ATL/COM experience, is to use only the ODL or
> IDL and have them differ only by LIBID so that we can somehow
> templatize the creation of each interface to use the correct LIBID.

I suppose you could do that, with clever use of preprocessor. However, note that:

1) Defining two interfaces that are identical except for their IIDs (whether in the same or different type libraries) is pointless. It's not clear why you would ever want to do that. It'll just make your clients' lives difficult for no good reason.

2) Defining the same interface (with the same IID and everything) in two different type libraries (whether with different LIBIDs, or with the same LIBID but packaged two different ways) is a deployment nightmare. Imagine you install the EXE server and register its type library. This will point the registry entries for the interfaces mentioned in that type library to the EXE (see HKCR\Interface\{Your IID}). Later, you install the DLL, and it overwrites those entries and make them point to itself. Then you uninstall the DLL - it removes those registry entries, and your EXE stops working.

If you want to share the same interface definitions between two modules, build a standalone TLB file and treat it carefully as a shared resource for deployment purposes.

Drew

unread,
Nov 5, 2009, 1:24:34 PM11/5/09
to

"Igor Tandetnik" <itand...@mvps.org> wrote in message
news:%23FH5tsa...@TK2MSFTNGP02.phx.gbl...

Drew <d...@dam.com> wrote:
> In this case the typelib is bound as a resource.

>... to which module?

Both the EXE and DLL have their respective typlib bound as a resource

> Now, we have a ODL
> for the EXE and an IDL for the DLL that are maintained seperately and
> differ only by library name, "MyLibrary"(EXE) and "MyLibraryX"(DLL).
> Also LIBID and all UDTs and interface/coclass GUIDs are different.

Your first message stated "all interfaces/UDTs have the same GUID". Which
way is it?

My fisrt message asked if that was possible. Currently all GUIDs, LIBIDs,
IIDs are differnet between the two servers.

As it works currently, both the EXE and DLL can be registered at the same
time and it's up to the client to reference one or the other and that is
what is instatiated. If the only thing that determines how to reference a
library and hence all the interfaces it exposes is its LIBID then I think
sharing the rest of the contents of the library might work. I'm worried that
the IID assigned to the Application interface, which is the only one
directly creatable by a client would somehow reference the LIBID in such way
that having both EXE and DLL registered at the same time would not be
possible which is what you seem to be describing. Am I on the right track
here?

>If you want to share the same interface definitions between two modules,
>build a standalone TLB file and treat it carefully as a shared resource for
>deployment purposes.

The reason for having these two identical forms of the server is because a
customer requested to have a version with no GUI (even though visibility of
the GUI is optional). My take on all this is that trying to share the
contents of the TLB other than LIBID and clever preprocessor tricks,
notwithstanding, is a Bad Idea. Thanks for your input on this.

Drew


Igor Tandetnik

unread,
Nov 5, 2009, 2:37:20 PM11/5/09
to
Drew <d...@dam.com> wrote:
> I'm worried that the IID assigned to the Application
> interface, which is the only one directly creatable by a client would
> somehow reference the LIBID in such way that having both EXE and DLL
> registered at the same time would not be possible which is what you
> seem to be describing.

An interface can only refer to one LIBID at a time. It doesn't matter how the type library behind that LIBID is physically packaged, as long as it actually exists on the machine. It could be in a separate TLB file, or attached as a resource to the server that implements the interface, or attached as a resource to some unrelated EXE or DLL.

If you have the same type library, with the same LIBID, attached both to the EXE and the DLL, then the registry entries would point to whichever of them was registered last. This is not a problem in itself. There are two issues with this. A minor one - you have a copy of a type library that is not being used, so why have it in the first place? A major one - if you uninstall the module that LIBID registry entries point to, the other module will stop working (or, you will have to take care to re-register it).

> The reason for having these two identical forms of the server is
> because a customer requested to have a version with no GUI (even
> though visibility of the GUI is optional).

I don't quite see how the presence of a GUI is related to whether the server is an EXE or a DLL.

Drew

unread,
Nov 5, 2009, 5:11:56 PM11/5/09
to

"Igor Tandetnik" <itand...@mvps.org> wrote in message

news:uBjIl9kX...@TK2MSFTNGP04.phx.gbl...


Drew <d...@dam.com> wrote:
> I'm worried that the IID assigned to the Application
> interface, which is the only one directly creatable by a client would
> somehow reference the LIBID in such way that having both EXE and DLL
> registered at the same time would not be possible which is what you
> seem to be describing.

An interface can only refer to one LIBID at a time. It doesn't matter how
the type library behind that LIBID is physically packaged, as long as it
actually exists on the machine. It could be in a separate TLB file, or
attached as a resource to the server that implements the interface, or
attached as a resource to some unrelated EXE or DLL.

If you have the same type library, with the same LIBID, attached both to the
EXE and the DLL, then the registry entries would point to whichever of them
was registered last. This is not a problem in itself. There are two issues
with this. A minor one - you have a copy of a type library that is not being
used, so why have it in the first place? A major one - if you uninstall the
module that LIBID registry entries point to, the other module will stop
working (or, you will have to take care to re-register it).

------------
That's my point. The EXE and DLL would have different LIBIDs in their
typelib. One for the EXE one for the DLL. My concern is the interfaces
defined in the typelib and how they reference the LIBID. In this scenario
would I be able to have both EXE and DLL registered at the same time? How
would the non-unique IID interfaces resolve which server they referred to?
------------

> The reason for having these two identical forms of the server is
> because a customer requested to have a version with no GUI (even
> though visibility of the GUI is optional).

I don't quite see how the presence of a GUI is related to whether the server
is an EXE or a DLL.

--------------
Me either but explain that to a (rather important) customer. Maybe the real
issue with them was in-proc vs. out-of-proc.
--------------

Thanks,
Drew


Igor Tandetnik

unread,
Nov 5, 2009, 5:32:27 PM11/5/09
to
Drew <d...@dam.com> wrote:
> That's my point. The EXE and DLL would have different LIBIDs in their
> typelib. One for the EXE one for the DLL.

Why? They describe the same interfaces with the same IIDs, right? Why do you want different LIBIDs?

> My concern is the interfaces
> defined in the typelib and how they reference the LIBID. In this
> scenario would I be able to have both EXE and DLL registered at the
> same time?

Yes. But, again, you'll have a problem if the one that was registered last is uninstalled first, because it'll remove marshalling support for your interfaces from the registry.

> How would the non-unique IID interfaces resolve which
> server they referred to?

IIDs do not refer to a server: after all, thousands of servers implement IUnknown or IDispatch. IIDs (often) refer to a LIBID, with the type library providing marshalling support. Now, you are attempting to tie a LIBID to a server: your problems stem from that.

Drew

unread,
Nov 6, 2009, 10:31:09 AM11/6/09
to

"Igor Tandetnik" <itand...@mvps.org> wrote in message

news:uqWu%23fmXK...@TK2MSFTNGP04.phx.gbl...


Drew <d...@dam.com> wrote:
> That's my point. The EXE and DLL would have different LIBIDs in their
> typelib. One for the EXE one for the DLL.

Why? They describe the same interfaces with the same IIDs, right? Why do you
want different LIBIDs?

---------
So that they can both be registered at the same time. Otherwise, how do you
distinguish between a reference to the EXE and a reference to the DLL?
Suppose one VBA user wants to use the EXE andd one wants to use the DLL. How
do they reference them if their LIBIDs are the same?
---------

> My concern is the interfaces
> defined in the typelib and how they reference the LIBID. In this
> scenario would I be able to have both EXE and DLL registered at the
> same time?

Yes. But, again, you'll have a problem if the one that was registered last
is uninstalled first, because it'll remove marshalling support for your
interfaces from the registry.

-------------
That's my concern. Having unique LIBIDs isn't enough to support the idea
that's being proposed.
-------------

> How would the non-unique IID interfaces resolve which
> server they referred to?

IIDs do not refer to a server: after all, thousands of servers implement
IUnknown or IDispatch. IIDs (often) refer to a LIBID, with the type library
providing marshalling support. Now, you are attempting to tie a LIBID to a
server: your problems stem from that.

-------------
Maybe when I referred to server I should have said LIBID that referred to
the COM server. Am I mistaken that the LIBID *is* tied to the server? I mean
from a VBA client point of view, they need to add a reference to a server
that is looked up using the LIBID, right?
-------------

Thanks,
Drew


Igor Tandetnik

unread,
Nov 6, 2009, 11:28:18 AM11/6/09
to
Drew <d...@dam.com> wrote:
> "Igor Tandetnik" <itand...@mvps.org> wrote in message
> news:uqWu%23fmXK...@TK2MSFTNGP04.phx.gbl...
> Drew <d...@dam.com> wrote:
>> That's my point. The EXE and DLL would have different LIBIDs in their
>> typelib. One for the EXE one for the DLL.
>
> Why? They describe the same interfaces with the same IIDs, right? Why
> do you want different LIBIDs?
> ---------
> So that they can both be registered at the same time.

They can't anyway, really. Registry entries under HKCR/Interface/{IID} can only point to one LIBID at a time.

> Otherwise, how
> do you distinguish between a reference to the EXE and a reference to
> the DLL?

A reference from _what_ ? This question makes no sense to me.

> Suppose one VBA user wants to use the EXE andd one wants to
> use the DLL. How do they reference them if their LIBIDs are the same?

By CLSID, of course. LIBIDs don't participate in server activation in any way.

> Yes. But, again, you'll have a problem if the one that was registered
> last is uninstalled first, because it'll remove marshalling support
> for your interfaces from the registry.
>
> -------------
> That's my concern. Having unique LIBIDs isn't enough to support the
> idea that's being proposed.

In fact, it's not helpful at all.

>> How would the non-unique IID interfaces resolve which
>> server they referred to?
>
> IIDs do not refer to a server: after all, thousands of servers
> implement IUnknown or IDispatch. IIDs (often) refer to a LIBID, with
> the type library providing marshalling support. Now, you are
> attempting to tie a LIBID to a server: your problems stem from that.
>
> -------------
> Maybe when I referred to server I should have said LIBID that
> referred to the COM server.

LIBIDs don't refer to a COM server. They just refer to a blob of data in a certain format. This data may be stored as a separate file (customarily with .tlb extension), or it may be embedded in some EXE or DLL, which may or may not happen to also house a COM server implementation: whether or not it does is completely irrelevant.

> Am I mistaken that the LIBID *is* tied to
> the server?

Yes, you are mistaken. That's what I'm trying to tell you for days now.

> I mean from a VBA client point of view, they need to add
> a reference to a server that is looked up using the LIBID, right?

No. When you add a reference at compile time, you are just pointing the compiler to a file. The type library doesn't even need to be registered for your code to compile. Once the type information is read and the code is compiled accordingly, the type library is no longer needed at runtime at all. This is similar to the situation with .h header files in C++, say.

At run-time, COM machinery itself uses the type library to allow COM calls to work across apartment (e.g. process) boundaries: this is known as "marshalling". That's why an interface IID needs to point to a LIBID in the registry. Also, ATL's IDispatchImpl happens to use a type library to forward late-bound IDispatch::Invoke calls to appropriate interface methods, and also needs the type library registered so that it can look it up by LIBID. Note that this is an implementation detail of your server, not a requirement imposed by the client.

Now, often but not always, a type library contains one or more "coclass" blocks mentioning specific CLSIDs. This is done mostly for the benefit of clients like VBA that consult type libraries during compilation: these CLSID references are not used at runtime in any way.


In your situation, with two coclasses sharing a set of interfaces, I can suggest two approaches. One is a single type library with two coclass blocks:

library {
[dual]
interface IMySharedInterface : IDispatch {...};

coclass MyInProcServer {
[default] interface IMySharedInterface;
};

coclass MyOutOfProcServer {
[default] interface IMySharedInterface;
};
}

The other involves three IDL files compiled into three type libraries:

// shared.idl
library {
[dual]
interface IMySharedInterface : IDispatch {...};
}

// inproc.idl
library {
importlib("shared.tlb")

coclass MyInProcServer {
[default] interface IMySharedInterface;
};
}

// outpfproc.idl
library {
importlib("shared.tlb")

coclass MyOutOfProcServer {
[default] interface IMySharedInterface;
};
}

The single type library in the first case, and the shared type library in the second, would be packaged as a standalone TLB file and treated as a shared resource for deployment purposes (that is, it should be installed and registered as long as at least one of your servers is still present on the machine). The two coclass-specific type libraries in the second approach could go into their corresponding servers' resources.

Drew

unread,
Nov 6, 2009, 2:47:26 PM11/6/09
to

"Igor Tandetnik" <itand...@mvps.org> wrote in message
news:ubDIn4vX...@TK2MSFTNGP05.phx.gbl...

------------
That sounds like a bit of a contradiction to your statement that a reference
to a server is not looked up using the LIBID. IOW, "...an interface IID

needs to point to a LIBID in the registry. Also, ATL's IDispatchImpl happens
to use a type library to forward late-bound IDispatch::Invoke calls to
appropriate interface methods, and also needs the type library registered so

that it can look it up by LIBID. " When I create a VBA script that wants to
use my COM server, I select from a list of registered servers that are
described using the helpstring (if there is one) that appears at the library
block scope.
------------

---------------
Both of these approaches, I assume, would use a non-unique GUID for LIBID,
and unique GUIDs, at the very least, for each coclass. The IID for each
interface looks like it is the only thing, and possibly GUIDs for UDTs that
can remain non-unique. If that's the case then our present situation where
all GUIDs are different between DLL and EXE isn't much different than what
you are proposing but puts more of an onus on the client in that when they
write code like:

Dim MyApp as MyLibrary.MyInProcServer

currently they can switch to using the DLL version just by changing the
reference to point to the DLL version and doing:

Dim MyApp as MyLibraryX.MyInProcServer

With your solution they would have to do:

Dim MyApp as MyLibrary.MyInProcServer

and to switch to using the DLL they would have to change their code to:

Dim MyApp as MyLibrary.MyOutOfProcServer

Is that correct?
---------------

Thanks,
Drew


Igor Tandetnik

unread,
Nov 6, 2009, 4:38:42 PM11/6/09
to
Drew <d...@dam.com> wrote:
> At run-time, COM machinery itself uses the type library to allow COM
> calls to work across apartment (e.g. process) boundaries: this is
> known as "marshalling". That's why an interface IID needs to point to
> a LIBID in the registry. Also, ATL's IDispatchImpl happens to use a
> type library to forward late-bound IDispatch::Invoke calls to
> appropriate interface methods, and also needs the type library
> registered so that it can look it up by LIBID. Note that this is an
> implementation detail of your server, not a requirement imposed by
> the client.
>
> ------------
> That sounds like a bit of a contradiction to your statement that a
> reference to a server is not looked up using the LIBID. IOW, "...an
> interface IID needs to point to a LIBID in the registry. Also, ATL's
> IDispatchImpl happens to use a type library to forward late-bound
> IDispatch::Invoke calls to appropriate interface methods, and also
> needs the type library registered so that it can look it up by LIBID.

In both cases, the type library is needed to get the definition of an interface, not a "server" (whatever you mean by that term). Multiple "servers" (coclasses) may implement the same interface.

> " When I create a VBA script that wants to use my COM server, I
> select from a list of registered servers that are described using the
> helpstring (if there is one) that appears at the library block scope.

Yes, that's what the coclass statement is for - basically, just a convenience for certain clients.

I'm not sure I understand this statement. Each of the .idl files shown above would have its own unique LIBID. So you would have one LIBID with the first apporach, and three distinct LIBIDs with the second. And, of course, a unique CLSID for each coclass.

> The IID
> for each interface looks like it is the only thing, and possibly
> GUIDs for UDTs that can remain non-unique.

With both approaches, the interface (and the UDT's, whatever) is defined only once, so naturally there's only one IID for it. That's the whole point of the exercise.

> If that's the case then
> our present situation where all GUIDs are different between DLL and
> EXE isn't much different than what you are proposing but puts more of
> an onus on the client in that when they write code like:
>
> Dim MyApp as MyLibrary.MyInProcServer
>
> currently they can switch to using the DLL version just by changing
> the reference to point to the DLL version and doing:
>
> Dim MyApp as MyLibraryX.MyInProcServer
>
> With your solution they would have to do:
>
> Dim MyApp as MyLibrary.MyInProcServer
>
> and to switch to using the DLL they would have to change their code
> to:
>
> Dim MyApp as MyLibrary.MyOutOfProcServer
>
> Is that correct?

For references to coclasses, yes. However, references to interfaces, UDTs and so on won't require any changes. And, you'll have a sane deployment story.

Drew

unread,
Nov 12, 2009, 11:22:08 AM11/12/09
to
Hi Igor,

First, thank you for your help. More below...

> In your situation, with two coclasses sharing a set of interfaces, I
> can suggest two approaches. One is a single type library with two
> coclass blocks:
>
> library {
> [dual]
> interface IMySharedInterface : IDispatch {...};
>
> coclass MyInProcServer {
> [default] interface IMySharedInterface;
> };
>
> coclass MyOutOfProcServer {
> [default] interface IMySharedInterface;
> };
> }

--------------
It seems that in this case, there can only be one COM server registered at a
time and that neither is prevented from using either of the coclasses
(MyInProcServer, MyOutOfProcServer). So what's the point? I need both
in-proc and out-of-proc to be registered at the same time and be
distinguishable from one another.
--------------

>
> The other involves three IDL files compiled into three type libraries:
>
> // shared.idl
> library {
> [dual]
> interface IMySharedInterface : IDispatch {...};
> }
>
> // inproc.idl
> library {
> importlib("shared.tlb")
>
> coclass MyInProcServer {
> [default] interface IMySharedInterface;
> };
> }
>
> // outpfproc.idl
> library {
> importlib("shared.tlb")
>
> coclass MyOutOfProcServer {
> [default] interface IMySharedInterface;
> };
> }
>
> The single type library in the first case, and the shared type

> library in the second, would be packaged as a standalone TLB file...

-----------------
Could you elaborate on this? I've attempted this approach but end up with
shared.tlb being something like 500k and in-proc/out-of-proc.tlb being about
3k. In the in/out proc typelibs I only included the only createable
coclass/interface, should I have included more? Do I need all coclasses in
the in/out-proc.idl to be included and have unique IDs? Here's my
out-of-proc idl:

[ uuid("SOME-GUID-HERE"), version(1.0),
helpstring("MyApplication 1.0 Object Library") ]
library MyAppLibrary
{
importlib("shared.tlb");

interface _IDualMyApp;

[
uuid("SOME-GUID-HERE"),
version(1.0),
helpstring("Global Application Object"),
appobject
]
coclass Application
{
[default] interface _IDualMyApp;
};
};

for in-proc idl:

[ uuid(SOME-DIFFERENT-GUID-HERE), version(1.0),
helpstring("MyDLL 1.0 Object Library") ]
library MyAppLibraryX
{
importlib("shared.tlb");

interface _IDualMyApp;

[
uuid(SOME-DIFFERENT-GUID-HERE),
version(1.0),
helpstring("Global Application Object"),
appobject
]
coclass Application
{
[default] interface _IDualMyApp;
};

};

All other interfaces (including _IDualMyApp), coclasses, UDTs, enums, etc.
are in the shared.tlb. The .idl files compile fine but when I compile my C++
code, none of them are recognized, giving 3000+ errors. I assume this is
where the "would be packaged as a standalone TLB file" comes in. So how do I
go about doing that? The typelibs I want registered are MyAppLibrary(EXE)
and MyAppLibraryX(DLL). Thanks for all your help.
-----------------

Drew


Igor Tandetnik

unread,
Nov 12, 2009, 11:58:53 AM11/12/09
to

Drew <d...@dam.com> wrote:
>> In your situation, with two coclasses sharing a set of interfaces, I
>> can suggest two approaches. One is a single type library with two
>> coclass blocks:
>>
>> library {
>> [dual]
>> interface IMySharedInterface : IDispatch {...};
>>
>> coclass MyInProcServer {
>> [default] interface IMySharedInterface;
>> };
>>
>> coclass MyOutOfProcServer {
>> [default] interface IMySharedInterface;
>> };
>> }
>
> --------------
> It seems that in this case, there can only be one COM server
> registered at a time

What makes you think so?

> and that neither is prevented from using either
> of the coclasses (MyInProcServer, MyOutOfProcServer).

I don't understand what you mean by "using a coclass".

> So what's the
> point? I need both in-proc and out-of-proc to be registered at the
> same time and be distinguishable from one another.

The example above won't preclude that.

>> The single type library in the first case, and the shared type
>> library in the second, would be packaged as a standalone TLB file...
>
> -----------------
> Could you elaborate on this? I've attempted this approach but end up
> with shared.tlb being something like 500k and in-proc/out-of-proc.tlb
> being about 3k.

Why is that surprising? They only contain the coclass and the reference to the shared TLB.

> Here's my out-of-proc idl:
>
> [ uuid("SOME-GUID-HERE"), version(1.0),
> helpstring("MyApplication 1.0 Object Library") ]
> library MyAppLibrary
> {
> importlib("shared.tlb");
>
> interface _IDualMyApp;

This declaration shouldn't be necessary.

> [
> uuid("SOME-GUID-HERE"),
> version(1.0),
> helpstring("Global Application Object"),
> appobject
> ]
> coclass Application
> {
> [default] interface _IDualMyApp;
> };
> };
>
> for in-proc idl:
>
> [ uuid(SOME-DIFFERENT-GUID-HERE), version(1.0),
> helpstring("MyDLL 1.0 Object Library") ]
> library MyAppLibraryX
> {
> importlib("shared.tlb");
>
> interface _IDualMyApp;
>
> [
> uuid(SOME-DIFFERENT-GUID-HERE),
> version(1.0),
> helpstring("Global Application Object"),
> appobject
> ]
> coclass Application
> {
> [default] interface _IDualMyApp;
> };
>
> };
>
> All other interfaces (including _IDualMyApp), coclasses, UDTs, enums,
> etc. are in the shared.tlb. The .idl files compile fine but when I
> compile my C++ code, none of them are recognized, giving 3000+
> errors.

Are you using #import in your C++ code? Unfortunately, #import doesn't automatically follow references between TLBs. You'll have to #import "shared.tlb" explicitly.

> I assume this is where the "would be packaged as a standalone
> TLB file" comes in. So how do I go about doing that?

When you compile shared.idl, a file named shared.tlb is produced.

Drew

unread,
Nov 12, 2009, 1:29:24 PM11/12/09
to

"Igor Tandetnik" <itand...@mvps.org> wrote in message
news:eGkyrl7Y...@TK2MSFTNGP02.phx.gbl...

Drew <d...@dam.com> wrote:
>> In your situation, with two coclasses sharing a set of interfaces, I
>> can suggest two approaches. One is a single type library with two
>> coclass blocks:
>>
>> library {
>> [dual]
>> interface IMySharedInterface : IDispatch {...};
>>
>> coclass MyInProcServer {
>> [default] interface IMySharedInterface;
>> };
>>
>> coclass MyOutOfProcServer {
>> [default] interface IMySharedInterface;
>> };
>> }
>
> --------------
> It seems that in this case, there can only be one COM server
> registered at a time

What makes you think so?

---------------
One typelib - one registered COM server.
---------------

> and that neither is prevented from using either
> of the coclasses (MyInProcServer, MyOutOfProcServer).

I don't understand what you mean by "using a coclass".

---------------
VBA:

Dim MyInproc as MyLibrary.MyInProcServer
Dim MyOutproc as MyLibrary.MyOutProcServer

Set MyInproc = new MyLibrary.MyInProcServer ' What is invoked in this case,
EXE or DLL? My guess is whichever was registered last.
Set MyOutproc = new MyLibrary.MyOutProcServer ' What is invoked in this
case, EXE or DLL? Same.
---------------

> So what's the
> point? I need both in-proc and out-of-proc to be registered at the
> same time and be distinguishable from one another.

The example above won't preclude that.

>> The single type library in the first case, and the shared type
>> library in the second, would be packaged as a standalone TLB file...
>
> -----------------
> Could you elaborate on this? I've attempted this approach but end up
> with shared.tlb being something like 500k and in-proc/out-of-proc.tlb
> being about 3k.

Why is that surprising? They only contain the coclass and the reference to
the shared TLB.

---------------
I guess I was hoping that importlib acted like including a header. Maybe I
should be using import on the shared.idl? If so, what would that entail?
---------------

---------------
No, I'm not using #import and would prefer not to. I bind the two unique
typelibs shown above as a resource in both EXE and DLL.
---------------

> I assume this is where the "would be packaged as a standalone
> TLB file" comes in. So how do I go about doing that?

When you compile shared.idl, a file named shared.tlb is produced.

---------------
I know this. I don't want to have to distribute this shared.tlb or any .tlb
for that matter. I don't really want anything to change from the end users
perspective. They open up some VBA aware app, add a reference to our product
which is listed as it always has been and code away.

Maybe some background info is required here. The application started out as
an MFC application with no automation. Later, it was decided to add
automation support. Later still, the requirement was added that we should
have a seperate DLL version of our ATL/COM interface. Being somewhat naive,
perhaps, I pretty much just copy/pasted the entire contents of the .odl(EXE
project) to the .idl(DLL project) and changed all the GUIDs in the .idl.
This has been working fine for several years. Now the requirement is that
both the EXE and the DLL share as much of the .idl file as possible. IOW,
have as few unique GUIDs as possible between them and also have them be
registered at the same time so that the end user can choose which COM server
they want to use.
---------------

Thanks again for all your help,
Drew


Igor Tandetnik

unread,
Nov 12, 2009, 2:20:27 PM11/12/09
to
Drew <d...@dam.com> wrote:
> "Igor Tandetnik" <itand...@mvps.org> wrote in message
> news:eGkyrl7Y...@TK2MSFTNGP02.phx.gbl...
>> It seems that in this case, there can only be one COM server
>> registered at a time
>
> What makes you think so?
>
> ---------------
> One typelib - one registered COM server.

What makes you think _that_?

>> and that neither is prevented from using either
>> of the coclasses (MyInProcServer, MyOutOfProcServer).
>
> I don't understand what you mean by "using a coclass".
>
> ---------------
> VBA:
>
> Dim MyInproc as MyLibrary.MyInProcServer
> Dim MyOutproc as MyLibrary.MyOutProcServer
>
> Set MyInproc = new MyLibrary.MyInProcServer ' What is invoked in this
> case, EXE or DLL?

The server whose CLSID is specified in a uuid() attribute on the "coclass MyInProcServer" statement.

> My guess is whichever was registered last.

Your guess is incorrect.

> Set MyOutproc = new MyLibrary.MyOutProcServer ' What is invoked in
> this case, EXE or DLL? Same.

The server whose CLSID is specified in a uuid() attribute on the "coclass MyOutProcServer" statement.

>>> The single type library in the first case, and the shared type
>>> library in the second, would be packaged as a standalone TLB file...
>>
>> -----------------
>> Could you elaborate on this? I've attempted this approach but end up
>> with shared.tlb being something like 500k and in-proc/out-of-proc.tlb
>> being about 3k.
>
> Why is that surprising? They only contain the coclass and the
> reference to the shared TLB.
>

> I guess I was hoping that importlib acted like including a header.

No, it's more like linking to a DLL.

> Maybe I should be using import on the shared.idl?

That would defeat the point of the exercise.

>> All other interfaces (including _IDualMyApp), coclasses, UDTs, enums,
>> etc. are in the shared.tlb. The .idl files compile fine but when I
>> compile my C++ code, none of them are recognized, giving 3000+
>> errors.
>
> Are you using #import in your C++ code? Unfortunately, #import doesn't
> automatically follow references between TLBs. You'll have to #import
> "shared.tlb" explicitly.
>
> ---------------
> No, I'm not using #import and would prefer not to.

Then you are #including MIDL-generated .h file. Simply #include "shared.h".

> I bind the two
> unique typelibs shown above as a resource in both EXE and DLL.

This is unrelated to compiling your source code, of course.

>> I assume this is where the "would be packaged as a standalone
>> TLB file" comes in. So how do I go about doing that?
>
> When you compile shared.idl, a file named shared.tlb is produced.
>
> ---------------
> I know this. I don't want to have to distribute this shared.tlb or
> any .tlb for that matter.

Why not? You are painting yourself into a corner here.

> I don't really want anything to change from
> the end users perspective. They open up some VBA aware app, add a
> reference to our product which is listed as it always has been and
> code away.

That's how it's going to work.

Drew

unread,
Nov 12, 2009, 6:25:45 PM11/12/09
to

"Igor Tandetnik" <itand...@mvps.org> wrote in message
news:uJd0q48Y...@TK2MSFTNGP04.phx.gbl...

Your guess is incorrect.

---------------
OK. I've included the header generated from the cut down IDL and shared.h
and am able to compile/link. Now I'm trying to test a simple COM client
using VB6 and it appears that -all- coclasses must be included in the cut
down version of the IDL because VB does not see any interface other than my
Application interface and the Document interface that is exposed through the
Application interface. So is my observation correct that all coclasses must
be included in the cut down IDL and that their GUIDs must be unique between
EXE and DLL projects?

Thanks,
Drew
---------------

Igor Tandetnik

unread,
Nov 12, 2009, 9:57:34 PM11/12/09
to
Drew wrote:
> OK. I've included the header generated from the cut down IDL and shared.h
> and am able to compile/link. Now I'm trying to test a simple COM client
> using VB6 and it appears that -all- coclasses must be included in the cut
> down version of the IDL because VB does not see any interface other than my
> Application interface and the Document interface that is exposed through the
> Application interface. So is my observation correct that all coclasses must
> be included in the cut down IDL and that their GUIDs must be unique between
> EXE and DLL projects?

This is a bit surprising. I expected VB to follow the link and read shared.tlb. It looks like it does, but only extracts the types that are referenced by those mentioned in the "main" TLB (likely recursively).

You seem to have interfaces that are not reachable from the root application object. I'm curious - how are those supposed to be used from VB? Anyway, you can make them visible by forward-declaring them in "main" TLB:

library MyLibrary {
importlib("shared.tlb")

interface IMyOtherInterface;

coclass MyServer {
[default] interface IMyApplicationInterface;
};
}

This should make IMyOtherInterface, and everything that it references, visible in VB.

Drew

unread,
Nov 13, 2009, 10:58:06 AM11/13/09
to

"Igor Tandetnik" <itand...@mvps.org> wrote in message
news:%23ubnT0A...@TK2MSFTNGP05.phx.gbl...

Drew wrote:
> OK. I've included the header generated from the cut down IDL and shared.h
> and am able to compile/link. Now I'm trying to test a simple COM client
> using VB6 and it appears that -all- coclasses must be included in the cut
> down version of the IDL because VB does not see any interface other than
> my
> Application interface and the Document interface that is exposed through
> the
> Application interface. So is my observation correct that all coclasses
> must
> be included in the cut down IDL and that their GUIDs must be unique
> between
> EXE and DLL projects?

This is a bit surprising. I expected VB to follow the link and read
shared.tlb. It looks like it does, but only extracts the types that are
referenced by those mentioned in the "main" TLB (likely recursively).

You seem to have interfaces that are not reachable from the root application
object. I'm curious - how are those supposed to be used from VB?

------------
The Application interface exposes just some basic things like version, etc.
and a property to get a Document which is then used to open a set of files.
The Document exposes a few other interfaces, one of which exposes dozens of
others.
------------

Anyway, you can make them visible by forward-declaring them in "main" TLB:


library MyLibrary {
importlib("shared.tlb")

interface IMyOtherInterface;

coclass MyServer {
[default] interface IMyApplicationInterface;
};
}

This should make IMyOtherInterface, and everything that it references,
visible in VB.

------------
I tried that and it didn't work. I tried moving the coclass to the other
interface, the one that exposes the dozens of others and now VB6 it
complains about the Document interface not being defined. It looks like I
have to move all coclasses to the in-proc/out-of-proc IDLs. Unless you have
another idea?

Thanks,
Drew
------------

Drew

unread,
Nov 13, 2009, 12:32:17 PM11/13/09
to
More information. When I go to the object browser in VB6 and click on my
Application object it shows its properties/methods. If I click on Document
proerty it shows a little info about Document in a pane at the bottom of the
object browser:

Property Document As Document
read-only
Member of MyLibrary.Application
Returns the document object

The second Document above is a link that when clicked gives me:

"Cannot jump to 'Document; because it is in the library 'Shared' which is
not currently referenced"

I get the same message if I click on any of the interfaces retrieved from
the newly added coclass I referenced in my previous message, the one with
dozens of properties to retrieve interfaces. I was hoping all of this would
be unnecessary by importing the shared.tlb in the in-proc/out-of-proc TLB.
It seems that I would have to register the shared TLB and reference it in my
VB project which is what I want to avoid.

Thanks,
Drew


Igor Tandetnik

unread,
Nov 13, 2009, 12:53:43 PM11/13/09
to

You definitely need to register shared.tlb (search for regtlib tool, or programmatically with LoadTypeLibEx) - have you? I thought it wouldn't be necessary to explicitly reference it in VB. I don't have VB handy at the moment, but I'll test over the weekend.

Drew

unread,
Nov 13, 2009, 1:19:25 PM11/13/09
to

"Igor Tandetnik" <itand...@mvps.org> wrote in message
news:e524%23oIZK...@TK2MSFTNGP02.phx.gbl...

Drew <d...@dam.com> wrote:
> More information. When I go to the object browser in VB6 and click on
> my Application object it shows its properties/methods. If I click on
> Document proerty it shows a little info about Document in a pane at
> the bottom of the object browser:
>
> Property Document As Document
> read-only
> Member of MyLibrary.Application
> Returns the document object
>
> The second Document above is a link that when clicked gives me:
>
> "Cannot jump to 'Document; because it is in the library 'Shared'
> which is not currently referenced"
>
> I get the same message if I click on any of the interfaces retrieved
> from the newly added coclass I referenced in my previous message, the
> one with dozens of properties to retrieve interfaces. I was hoping
> all of this would be unnecessary by importing the shared.tlb in the
> in-proc/out-of-proc TLB. It seems that I would have to register the
> shared TLB and reference it in my VB project which is what I want to
> avoid.

You definitely need to register shared.tlb (search for regtlib tool, or
programmatically with LoadTypeLibEx) - have you? I thought it wouldn't be
necessary to explicitly reference it in VB. I don't have VB handy at the
moment, but I'll test over the weekend.

------------
I registered the shared.tlb but in order to use the interfaces described
there I *do* have to reference it in VB. In addition all objects residing in
that TLB have to be declared in VB like:

Dim MyObject as Shared.SomeObjectInShared

instead of:
Dim MyObject as MyLibrary.SomeObjectInShared ' which is what I want.

I'm trying a minimal test of moving some additional coclasses to my
in-proc/out-of-proc TLBs to see if that fixes it. More and more it seems
that all coclasses will have to be included in their respective IDL files
(with unique IDs between them) in order to acheive what I want.
------------

Thanks,
Drew


Drew

unread,
Nov 13, 2009, 1:37:34 PM11/13/09
to
OK. I've moved a few coclasses out of shared.tlb and now I can get to them.
I've found however that methods that take a UDT as an argument won't work
because the UDT is in the shared TLB and I would be forced to reference
shared.tlb in VB and declare them as Shared.MyUDT. Not what I want. So it
looks like the UDTs and possibly the enums would all have to be moved to
their respective TLBs. I'm not sure about the enums though since they have
no GUIDs. Probably I would have to though in order to get the dropdown in VB
that gives the possible values.

Thanks,
Drew

"Drew" <d...@dam.com> wrote in message
news:OIavi4IZ...@TK2MSFTNGP06.phx.gbl...

Drew

unread,
Nov 13, 2009, 1:53:14 PM11/13/09
to

"I'm not sure about the enums though since they have
> no GUIDs. Probably I would have to though in order to get the dropdown in
> VB that gives the possible values.

Well, I just tried to use a method of one of the coclasses that takes an
enum argument and, although I get the dropdown with acceptable values, VB
gives me a "Variable not defined" error on the enum member. So it looks like
even enums will also have to be included in the in-proc/out-of-proc IDLs.

Drew


Igor Tandetnik

unread,
Nov 13, 2009, 2:31:10 PM11/13/09
to
Drew <d...@dam.com> wrote:
> I registered the shared.tlb but in order to use the interfaces
> described there I *do* have to reference it in VB.

It looks like approach #1 (one IDL file with two coclass statements, one for each server) might work better after all. This way, there's only one TLB (used by both servers), you reference it in VB and gain access to all interfaces, coclasses and types.

Drew

unread,
Nov 16, 2009, 11:59:05 AM11/16/09
to
"Igor Tandetnik" <itand...@mvps.org> wrote in message
news:%23pWIcfJ...@TK2MSFTNGP05.phx.gbl...

Drew <d...@dam.com> wrote:
> I registered the shared.tlb but in order to use the interfaces
> described there I *do* have to reference it in VB.

>It looks like approach #1 (one IDL file with two coclass statements, one
>for each server) might work better after all. This way, there's only one
>TLB (used by both servers), >you reference it in VB and gain access to all
>interfaces, coclasses and types.


OK, this part I understand. One IDL, 2 coclasses with unique IDs. My problem
is how this looks in source. I'll try and restate my requirements. First,
both EXE and DLL versions must use the same source code; .cpp and .h files.
They have the same IDL. Use as few preprocessor macros as possible. The EXE
will compile the COM part of the solution as a static LIB and link to that.
The DLL, using the exact same source, will be in a seperate solution
compiled (obviously) as a DLL.

I've set up a minimal example, minus the static LIB for the EXE. IOW, source
for the COM part is in the same project as the rest of the EXE code. The DLL
points to the same source as the EXE project for the COM portion of the
project. I can compile and link both projects but I'm unable to register the
DLL. When I run it through Dependency Walker and profile it with regsvr32 I
get Error 0x80070716 "The specified resource name cannot be found in the
image file". The EXE registers fine and I'm able to use it from a VB
project. Short of posting the code for both solutions I'm unsure how to
proceed. Can you give me any more guidance? I've really appreciated your
help.

Thanks,
Drew

P.S. Here's the header of the shared source file. The DLL has the
preprocessor symbol SERVER_B defined:

// ApplicationA.h : Declaration of the CApplicationA

#pragma once
#include <resource.h> // main symbols

#include <COMServerA_i.h>


#if defined(_WIN32_WCE) && !defined(_CE_DCOM) &&
!defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)
#error "Single-threaded COM objects are not properly supported on Windows CE
platform, such as the Windows Mobile platforms that do not include full DCOM
support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to
support creating single-thread COM object's and allow use of it's
single-threaded COM object implementations. The threading model in your rgs
file was set to 'Free' as that is the only threading model supported in non
DCOM Windows CE platforms."
#endif

// CApplicationA

class ATL_NO_VTABLE CApplicationA :
public CComObjectRootEx<CComSingleThreadModel>,
#ifdef SERVER_B
public CComCoClass<CApplicationA, &CLSID_ApplicationX>,
#else
public CComCoClass<CApplicationA, &CLSID_Application>,
#endif
public IDispatchImpl<IApplicationA, &IID_IApplicationA,
&LIBID_COMServerALib, /*wMajor =*/ 1, /*wMinor =*/ 0>

{
public:
CApplicationA()
{
}

DECLARE_REGISTRY_RESOURCEID(IDR_APPLICATIONA)


BEGIN_COM_MAP(CApplicationA)
COM_INTERFACE_ENTRY(IApplicationA)
COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()

STDMETHOD (get_Application)
(/*[out, retval]*/ IApplicationA** Application);
STDMETHOD (get_ApplicationX)
(/*[out, retval]*/ IApplicationA** Application);
STDMETHOD (get_Name)
(/*[out, retval]*/ BSTR* name);


DECLARE_PROTECT_FINAL_CONSTRUCT()

HRESULT FinalConstruct()
{
return S_OK;
}

void FinalRelease()
{
}

public:

};

#ifdef SERVER_B
OBJECT_ENTRY_AUTO(__uuidof(ApplicationX), CApplicationA)
#else
OBJECT_ENTRY_AUTO(__uuidof(Application), CApplicationA)
#endif


Igor Tandetnik

unread,
Nov 16, 2009, 2:30:20 PM11/16/09
to
Drew wrote:
> I've set up a minimal example, minus the static LIB for the EXE. IOW, source
> for the COM part is in the same project as the rest of the EXE code. The DLL
> points to the same source as the EXE project for the COM portion of the
> project. I can compile and link both projects but I'm unable to register the
> DLL. When I run it through Dependency Walker and profile it with regsvr32 I
> get Error 0x80070716 "The specified resource name cannot be found in the
> image file".

Find CAtlComModule::RegisterServer call (in a DLL project it's in DllRegisterServer; in EXE, I don't remember off the top of my head). Pass FALSE for the first parameter (the wizard-generated code passes TRUE). Since you no longer bind a TLB as a resource, you can't register it this way.

> The EXE registers fine and I'm able to use it from a VB
> project.

Apparently, you still bind the TLB (which is now supposed to be standalone) as a resource to your EXE. Check your .rc file.

Drew

unread,
Nov 16, 2009, 2:57:16 PM11/16/09
to

"Igor Tandetnik" <itand...@mvps.org> wrote in message
news:OOY9ENvZ...@TK2MSFTNGP04.phx.gbl...

Drew wrote:
> I've set up a minimal example, minus the static LIB for the EXE. IOW,
> source
> for the COM part is in the same project as the rest of the EXE code. The
> DLL
> points to the same source as the EXE project for the COM portion of the
> project. I can compile and link both projects but I'm unable to register
> the
> DLL. When I run it through Dependency Walker and profile it with regsvr32
> I
> get Error 0x80070716 "The specified resource name cannot be found in the
> image file".

Find CAtlComModule::RegisterServer call (in a DLL project it's in
DllRegisterServer; in EXE, I don't remember off the top of my head). Pass
FALSE for the first parameter (the wizard-generated code passes TRUE). Since
you no longer bind a TLB as a resource, you can't register it this way.

> The EXE registers fine and I'm able to use it from a VB
> project.

>Apparently, you still bind the TLB (which is now supposed to be standalone)
>as a resource to your EXE. Check your .rc file.

Yes, that's true. I've removed the TYPELIB statement from both EXE and DLL
projects and registered the TLB using regtlib. I also removed the REGISTRY
statements from the RC files. Should I have? Anyway, I still have the same
problem. This works:

Dim myapp As COMServerALib.Application

Set myapp = New COMServerALib.Application

Dim name As String
name = myapp.name

This doesn't:

Dim myapp As COMServerALib.ApplicationX

Set myapp = New COMServerALib.ApplicationX ' ActiveX component can't
create object

Dim name As String
name = myapp.name

Any ideas?

Thanks again,
Drew


Drew

unread,
Nov 16, 2009, 3:08:34 PM11/16/09
to
I forgot to mention that when I compile the DLL after removing the TYPELIB
and REGISTRY entries in the RC file I still get this message:

"Project : error PRJ0050: Failed to register output. Please ensure you have
the appropriate permissions to modify the registry."

Drew

"Igor Tandetnik" <itand...@mvps.org> wrote in message

news:OOY9ENvZ...@TK2MSFTNGP04.phx.gbl...

Igor Tandetnik

unread,
Nov 16, 2009, 4:45:00 PM11/16/09
to

Drew wrote:
> Yes, that's true. I've removed the TYPELIB statement from both EXE and DLL
> projects and registered the TLB using regtlib. I also removed the REGISTRY
> statements from the RC files. Should I have?

No, you shouldn't have. You still need your .rgs files, those are the ones that register CLSIDs and point them to the correct executable.

> This doesn't:
>
> Dim myapp As COMServerALib.ApplicationX
>
> Set myapp = New COMServerALib.ApplicationX ' ActiveX component can't
> create object

Your DLL's CLSID isn't registered. Double-check in the registry under HKCR\CLSID\{Your CLSID}.

Drew

unread,
Nov 16, 2009, 5:26:59 PM11/16/09
to

"Igor Tandetnik" <itand...@mvps.org> wrote in message
news:ODCzUYw...@TK2MSFTNGP04.phx.gbl...

Drew wrote:
> Yes, that's true. I've removed the TYPELIB statement from both EXE and DLL
> projects and registered the TLB using regtlib. I also removed the REGISTRY
> statements from the RC files. Should I have?

No, you shouldn't have. You still need your .rgs files, those are the ones
that register CLSIDs and point them to the correct executable.

> This doesn't:
>
> Dim myapp As COMServerALib.ApplicationX
>
> Set myapp = New COMServerALib.ApplicationX ' ActiveX component can't
> create object

>Your DLL's CLSID isn't registered. Double-check in the registry under
>HKCR\CLSID\{Your CLSID}.

OK. I added back the REGISTRY entries in the RC files and did the regtlib on
the TLB file again but the CLSID for my DLL still does not show up in the
registry. Are there any other steps I'm missing? Also, I'm still getting the
same error when I compile the DLL:

"Project : error PRJ0050: Failed to register output. Please ensure you have
the appropriate permissions to modify the registry."

If it helps I'm using VS2008 SP1 on WinXP x64.

Thanks for your continued assistance,
Drew


Igor Tandetnik

unread,
Nov 16, 2009, 5:48:44 PM11/16/09
to
Drew wrote:
> "Igor Tandetnik" <itand...@mvps.org> wrote in message
> news:ODCzUYw...@TK2MSFTNGP04.phx.gbl...
>> Your DLL's CLSID isn't registered. Double-check in the registry under
>> HKCR\CLSID\{Your CLSID}.
>
> OK. I added back the REGISTRY entries in the RC files and did the regtlib on
> the TLB file again but the CLSID for my DLL still does not show up in the
> registry.

There's something wrong with your .RGS file, or with your .RC file, or with your code. You are calling RegisterServer(FALSE) now, right? Perhaps your macros are misconfigured so that a wrong OBJECT_ENTRY[_AUTO] directive is being seen by the compiler, or none at all.

You can make regsvr32 your debug executable (Project | Properties | Debugging | Command), step through the registration code under debugger, and see where it fails.

Drew

unread,
Nov 16, 2009, 6:04:42 PM11/16/09
to

"Igor Tandetnik" <itand...@mvps.org> wrote in message
news:eq%23S87wZ...@TK2MSFTNGP05.phx.gbl...

Drew wrote:
> "Igor Tandetnik" <itand...@mvps.org> wrote in message
> news:ODCzUYw...@TK2MSFTNGP04.phx.gbl...
>> Your DLL's CLSID isn't registered. Double-check in the registry under
>> HKCR\CLSID\{Your CLSID}.
>
> OK. I added back the REGISTRY entries in the RC files and did the regtlib
> on
> the TLB file again but the CLSID for my DLL still does not show up in the
> registry.

>There's something wrong with your .RGS file, or with your .RC file, or with
>your code. You are calling RegisterServer(FALSE) now, right? Perhaps your
>macros are >misconfigured so that a wrong OBJECT_ENTRY[_AUTO] directive is
>being seen by the compiler, or none at all.

>You can make regsvr32 your debug executable (Project | Properties |
>Debugging | Command), step through the registration code under debugger,
>and see where it fails.

Yes, I am calling RegisterServer(FALSE). I did the above and got the same
error that I got when I profiled the DLL in DW:

0x80070716 "The specified resource name cannot be found in the image file".

I showed the code of my common header in a previous message where the DLL
defines the SERVER_B preprocessor symbol and syntax highlighting shows the
line:

OBJECT_ENTRY_AUTO(__uuidof(ApplicationX), CApplicationA)

as being the active one.

Thanks,
Drew


Drew

unread,
Nov 17, 2009, 10:54:18 AM11/17/09
to
OK. Since this seemed to be a resource problem I made sure all the DLL files
that were #include "resource.h" now #include <resource.h> to pick up the EXE
resource.h file. The only place I didn't change the #include was in the RC
file for the DLL. I still have the same problem. I suspect you are right
that it's probably my RGS files and/or a combination of code. Here are the
RGS files and the shared IDL I use for the DLL:

// COMServerB.rgs

HKCR
{
NoRemove AppID
{
'%APPID%' = s 'COMServerB'
'COMServerB.DLL'
{
val AppID = s '%APPID%'
}
}
}

// ApplicationB.rgs - I just copied ApplicationA.rgs and modified it as I
thought appropriate

HKCR
{
COMServerB.ApplicationX.1 = s 'ApplicationX Class'
{
CLSID = s '{72274097-64D1-47e2-A029-55B3CB9FF7C2}'
}
COMServerB.ApplicationX = s 'ApplicationX Class'
{
CLSID = s '{72274097-64D1-47e2-A029-55B3CB9FF7C2}'
CurVer = s 'COMServerB.ApplicationX.1'
}
NoRemove CLSID
{
ForceRemove {72274097-64D1-47e2-A029-55B3CB9FF7C2} = s 'ApplicationX
Class'
{
ProgID = s 'COMServerB.ApplicationX.1'
VersionIndependentProgID = s 'COMServerB.ApplicationX'
ForceRemove 'Programmable'
LocalServer32 = s '%MODULE%'
'TypeLib' = s '{5243544C-E40C-45A7-A882-1780F85FF1BE}'
}
}
}

// COMServerA.idl : IDL source for COMServerA
//

// This file will be processed by the MIDL tool to
// produce the type library (COMServerA.tlb) and marshalling code.

import "oaidl.idl";
import "ocidl.idl";

[
object,
uuid(417B7699-51DE-48D8-BA88-FF849489B201),
dual,
nonextensible,
helpstring("IApplicationA Interface"),
pointer_default(unique)
]
interface IApplicationA : IDispatch{
[propget, id(1), helpstring("Returns the application name")]
HRESULT Name([out,retval] BSTR* pVal);
};

[
uuid(5243544C-E40C-45A7-A882-1780F85FF1BE),
version(1.0),
helpstring("COMServerA 1.0 Type Library")
]
library COMServerALib
{
importlib("stdole2.tlb");
[
uuid(A86C8ABD-184A-4D9E-B723-BB722F780D2E),
helpstring("Application Class"),
appobject
]
coclass Application
{
[default] interface IApplicationA;
};

[
uuid(72274097-64D1-47e2-A029-55B3CB9FF7C2),
helpstring("Application Class"),
appobject
]
coclass ApplicationX
{
[default] interface IApplicationA;
};
};

See anything wrong with the above?

Thanks,
Drew


Drew

unread,
Nov 17, 2009, 12:35:21 PM11/17/09
to
I've gotten farther on this now. There was a problem with my dllmain.h file.
It was:

// dllmain.h : Declaration of module class.
#include "COMServerA_i.h"

class CCOMServerBModule : public CAtlDllModuleT< CCOMServerBModule >
{
public :
DECLARE_LIBID(LIBID_COMServerALib)
DECLARE_REGISTRY_APPID_RESOURCEID(IDR_COMSERVERA,
"{88EBE100-756C-4B70-BF65-68925B30810B}")
};

extern class CCOMServerBModule _AtlModule;

I changed it to be:

// dllmain.h : Declaration of module class.
#include "COMServerA_i.h"
#include "resource.h" // Need definition of IDR_COMSERVERB

class CCOMServerBModule : public CAtlDllModuleT< CCOMServerBModule >
{
public :
DECLARE_LIBID(LIBID_COMServerALib)
DECLARE_REGISTRY_APPID_RESOURCEID(IDR_COMSERVERB,
"{88EBE100-756C-4B70-BF65-68925B30810B}") // Now IDR_COMSERVERB
};

extern class CCOMServerBModule _AtlModule;

The DLL now registers and its CLSID shows up in the registry. But when I try
to run my VB script I now get:

Run-time error '-2147024703 (800700c1)':

Automation error
%1 is not a valid Win32 application.

The VB again is:

Dim myapp As COMServerALib.ApplicationX

Set myapp = New COMServerALib.ApplicationX ' ERROR HERE

Dim name As String
name = myapp.name

Any ideas?

Thanks,
Drew

"Igor Tandetnik" <itand...@mvps.org> wrote in message

news:eq%23S87wZ...@TK2MSFTNGP05.phx.gbl...

Drew

unread,
Nov 17, 2009, 12:57:54 PM11/17/09
to
OK. I GOT IT! I had to change one line of ApplicationB.rgs file from:

LocalServer32 = s '%MODULE%'

to:

InprocServer32 = s '%MODULE%'
{
val ThreadingModel = s 'Apartment'
}

Thanks for all your help Igor!

Drew

"Drew" <d...@dam.com> wrote in message

news:%23liSly6...@TK2MSFTNGP06.phx.gbl...

0 new messages