Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
?
Solved

Deriving from an interface in another dll

Posted on 2004-10-29
25
Medium Priority
?
1,224 Views
Last Modified: 2013-12-14
Hi,
I have a COM dll named Integrator.dll. It has an interface named IAsync. I have only the dll and not the source code. I create a new ATL COM dll. In that, using Insert->New ATL Object menu, I add a Simple Object named CPlayer. (I am using Visual Studio 6.0). I want CPlayer to be derived from IAsync so that I can implement the exposed functions of IAsync in CPlayer.

What exactly should I write to do this? I tried using
public IAsync

but it did not work.

Any idea?
Thanks
0
Comment
Question by:avinash_sahay
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
25 Comments
 
LVL 86

Expert Comment

by:jkr
ID: 12453176
If you derive from a pure virtual interface, you'll have to provide your own implementation of it's methods.
0
 
LVL 2

Author Comment

by:avinash_sahay
ID: 12455911
The problem is not in implementing. I am ready to implement, but the compiler gives error when I try to derive from that interface.

ATL wizard generates my CPlayer class as

class ATL_NO_VTABLE CPlayer :
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<CPlayer , &CLSID_Player>,
public IDispatchImpl<Player, &IID_IPlayer, &LIBID_EONPLAYERLib>
{
...
...
};

I want CPlayer to be also implement IAsync. I used IAsync as follows:-
(Note 'public IAsync' used)

class ATL_NO_VTABLE CPlayer :
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<CPlayer , &CLSID_Player>,
public IAsync,
public IDispatchImpl<Player, &IID_IPlayer, &LIBID_EONPLAYERLib>
{
...
...
};


Compiler gives error in the line
COM_INTERFACE_ENTRY(IDispatch)

Error is:-
static_cast' : ambiguous conversions from 'class CPlayer *' to 'struct IDispatch *'

But if I do not try to derive from IAsync, then no error comes.
0
 
LVL 19

Expert Comment

by:drichards
ID: 12460777
Do you have the definition of IAsync?  To use a COM interface in C++, you need either to have the header file or you can #import the type library which if it exists will be either embedded in the dll or included as a separate file with a .tlb extension.  If you do a #import, use the no_nameapaces and raw_interfaces_only attributes with the #import statement so the names from the type library will be preserved.  It will look like this:

   #import "<tlb file name>" no_namespace, raw_interfaces_only
0
Free learning courses: Active Directory Deep Dive

Get a firm grasp on your IT environment when you learn Active Directory best practices with Veeam! Watch all, or choose any amount, of this three-part webinar series to improve your skills. From the basics to virtualization and backup, we got you covered.

 
LVL 2

Author Comment

by:avinash_sahay
ID: 12461033
I do not have the tlb. So, I imported the dll. The compiler can recognize IAsync after I import the dll but when I use that as parent interface for CPlayer, then I get compiler error as I mentioned in my previous post.
0
 
LVL 9

Accepted Solution

by:
_ys_ earned 1000 total points
ID: 12461306
Your interface Player inherits from IDispatch. It's also safe to say IAsync does as well.
Hence the reported error - the compiler doesn't know which IDispatch to choose.

Using COM_INTERFACE_ENTRY2 forces it to use whichever IDispatch you choose.

Replace:
COM_INTERFACE_ENTRY(IDispatch)

with:
COM_INTERFACE_ENTRY2(IDispatch, Player)
0
 
LVL 2

Author Comment

by:avinash_sahay
ID: 12461369
I did that. But then I got another error. The error is:-

error C2259: 'CComObject<class CSink>' : cannot instantiate abstract class due to following members:
When I double click on this error, AtlCom.h opens. The error is shown in line
ATLTRY(p = new T1(pv))

I also get some warnings.
I commented out all the lines where I am using any instance of CSink. Even then I get the same error.

Do I need to make some other changes also?
0
 
LVL 9

Expert Comment

by:_ys_
ID: 12461406
And does:
COM_INTERFACE_ENTRY2(IDispatch, IAsync)
give you an error also.

Do you really need to expose IDispatch ? Can you provide a *good* reason why you need to ?
If you don't need it simply comment out the offending COM_INTERFACE_ENTRY. All you're saying by using COM_INTERFACE_ENTRY is that clients are allowed to QI for the listed interfaces.
0
 
LVL 2

Author Comment

by:avinash_sahay
ID: 12461446
COM_INTERFACE_ENTRY2(IDispatch, IAsync)
does not give error.

I need to expose IDispatch because a pointer to IPlayer may need to be passed to a VB client. But, just to check, I commented out the COM_INTERFACE_ENTRY entry. I got the same error in AtlCom.h. Do I need to make some change in the line
public IDispatchImpl<Player, &IID_IPlayer, &LIBID_EONPLAYERLib>

also?

In any case, it will be better if I could support IDispatch.
0
 
LVL 2

Author Comment

by:avinash_sahay
ID: 12461525
If I replace
COM_INTERFACE_ENTRY(IDispatch)
by
COM_INTERFACE_ENTRY2(IDispatch, IAsync)

and I do not use public IAsync to declare IAsync as a parent interface for CPlayer, then I do not get any error. But I do want CPlayer to support IAsync. Moreover, when I do not use public IAsync, even COM_INTERFACE_ENTRY(IDispatch) does not give error.
0
 
LVL 2

Author Comment

by:avinash_sahay
ID: 12461565
The members that the error says are not defined are:-

GetTypeInfoCount
GetTypeInfo
GetIDsOfNames
Invoke
0
 
LVL 2

Author Comment

by:avinash_sahay
ID: 12461688
I tried one more thing. I replaced
COM_INTERFACE_ENTRY
by
COM_INTERFACE_ENTRY2

and also
public IAsync by

public IDispatchImpl<IAsync, &__uuidof(IAsync), &LIBID_EONPLAYERLib>

I am creating an instance of CPlayer as follows:-
CComObject<CSink> *pPlayer = NULL;
CComObject<CPlayer>::CreateInstance(&pPlayer);

There is another module that exposes a function to which LPDISPATCH has to be passed. That function converts that LPDISPATCH to IAsync* using QueryInterface. From my dll (the one of which we are discussing here), I pass pPlayer to that function.

But I get an error in the line in which I try to pass pPlayer to that function. The error is
error C2594: 'argument' : ambiguous conversions from 'class ATL::CComObject<class CPlayer> *' to 'struct IDispatch *'

To correct the error I did QueryInterface from pPlayer to get IDispatch* and I passed this pointer to the function.

Now, I do not get any compile time error. But do you think it is fine or will it result in some other problem?
Thanks
0
 
LVL 9

Expert Comment

by:_ys_
ID: 12461794
So long as you never create a proxy/stub pair to your pPlayer instance, all should be well. If you ever do then multiple IDispatch implementations doesn't work. But since you're using COM_INTERFACE_ENTRY2 this should not be a problem - you only expose a single IDispatch implementation.

I trust you are aware that VB does support early binding, and hence support for IDispatch is irrelevant.

When you QI for IDispatch from pPlayer, it gives you the implementation defined within COM_INTERFACE_ENTRY2. What if you ever wanted access to the *other* IDispatch implementation? Do you ever require this?
0
 
LVL 2

Author Comment

by:avinash_sahay
ID: 12461872
A VB module is one of the clients. In fact, depending on some other settings there can be different kinds of clients. One of them is an exe written in MFC. It was written long back. I have not been given the authority to make changes in it unless it becomes necessary. It takes pointer to IDispatch through one of its functions. Through this pointer (after doing other needed conversions) it calls certain functions. These functions are to be implemented in my CPlayer. I think this is one of the reasons I need to support IDispatch.
Here is the actual scenario.

There is a dll named Integrator.dll. It has an interface named IAsync. Inside IAsync there are various functions. Just for example, consider one of its functions named PausedByUser. There is an exe that exposes a class with a function NotifyMe. This function takes dispClient as a parameter. dispClient is a pointer to IDispatch. Inside eonPlayer, there are some classes, one of which is CPlayer. I need to pass an instance of CPlayer to NotifyMe. NotifyMe converts dispClient to IAsync*. The method of conversion depends on the type of exe that contains NotifyMe. As I said there are various kinds of such exes. If it is MFC, then Integrator.dll has been added through class wizard and conversion is not really to IAsync* but to a class derived from COleDispatchDriver and I attach dispClient to an instance of this class using AttachDispatch. Through this instance, NotifyMe calls PausedByUser which is implemented in CPlayer. At this stage, the implementation inside CPlayer should get executed.

Do you think what I have done will help me achieve the above?
0
 
LVL 2

Author Comment

by:avinash_sahay
ID: 12461894
>>When you QI for IDispatch from pPlayer, it gives you the implementation defined within COM_INTERFACE_ENTRY2. What if you ever wanted access to the *other* IDispatch implementation? Do you ever require this?<<

Yes, I do because not all the exposed functions of CPlayer are those of IAsync. There are some other functions as well. So, if I can get the IDispatch implementation that I want, then it will be good.
But, even if I cannot do that, it is fine with me. In that case, I will break CPlayer into two classes. One will be used only for implementing the functions of IAsync and the other will do the rest. Will this be fine?
0
 
LVL 9

Expert Comment

by:_ys_
ID: 12461987
Whilst it is possible to support multiple IDispatch implementations and enable QI support for them, it's not trivial. Furthermore it won't work around the proxy/stub issue I mentioned, unless you're going to write your own - and you don't want to go there.

There are two easy solutions:

1. Break it into 2 classes, providing disparate support for the 2 IDispatch implementations.
2. Create a single huge IDispatch implementation that supports all functions from the other 2 IDispatch implementations.

Solution 1 is easier, and future proof. If you add another function at a later date, minimal (if any) code chages would be necessary to expose it.
0
 
LVL 2

Author Comment

by:avinash_sahay
ID: 12470180
Thankyou. I will use the first approach. Meanwhile, I would like to ask one more question related to this. I will break the class into two classes. One of them will implement only IAsync functions. Let us call that class as CAsyncImpl. This will be derived from both IAsync and IAsyncImpl. But IAsyncImpl does not contain any functions of its own. So, does it make sense not to make IAsyncImpl as a parent interface of CAsyncImpl? If yes, how to remove this? By default, ATL wizard will add code to make IAsyncImpl as a parent interface. How to remove that?
0
 
LVL 9

Expert Comment

by:_ys_
ID: 12471068
I'm not familiar with ATL ... I prefer to do COM raw ...

But, anyhow, borrowing from code samples you've already posted, let's say CAsyncImpl looks like this:

class ATL_NO_VTABLE CAsyncImpl :
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<CAsyncImpl , &CLSID_AsyncImpl>,
public IAsync,
public IDispatchImpl<IAsyncImpl, &IID_IAsyncImpl, &LIBID_EONPLAYERLib>
{
...
...
};

Simply merging the last two lines should do the trick:

class ATL_NO_VTABLE CAsyncImpl :
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<CAsyncImpl , &CLSID_AsyncImpl>,
public IDispatchImpl<IAsync, &IID_IAsync, &LIBID_XxxxLib, majorXxxx, minorXxxx>
{
...
...
};

The last three arguments are the LIBId for the source of IAsync, as well as it's major and minor version numbers (version of the typelib, bot the DLL); you did mention it was imported from another DLL, so it's not going to be the local library.

Also, remove COM_INTERFACE_ENTRY(IAsyncImpl).
0
 
LVL 2

Author Comment

by:avinash_sahay
ID: 12471877
I am still getting problem. I broke CPlayer into two classes. One of them is CAsyncImpl. This class implements the exposed methods of IAsync.

I create a new instance of CAsyncImpl. Using QI, I get a pointer to IDispatch. QI works properly and I get the LPDISPATCH. I pass this to a function in an MFC exe that takes an LPDISPATCH parameter. MFC exe has added Integrator.dll (the dll that contains IAsync) using class wizard. Classwizard adds wrappers for all the exposed functions of IAsync. Consider one exposed function of IAsync. It is PausedByUser. MFC exe calls this method. Inside the wrapper of PausedByUser, there is call to InvokeHelper. I expect this to call PausedByUser of CAsyncImpl. But it does not. In fact, InvokeHelper hangs. I put one message box  before calling InvokeHelper and another after. The first one if displayed but the second is not.

I put the library that defines IAsync in the library section of the idl of my ATL COM project using importlib. Inside the coclass section for AsyncImpl, I have added IAsync. I have also done all that you have suggested.

To find out where the error is, I made one change in the MFC exe. As I said the MFC exe exposes one function to which my ATL COM module passes an LPDISPATCH parameter (which is actually CAsyncImpl). When I have to call PausedByUser, earlier it was going through the wrapper. I made a change. Now, I directly call Invoke of LPDISPATCH. To do that I have to get disp id PausedByUser. I get that using GetIDsOfNames. The return value of GetIDsOfNames is not S_OK. This means that Invoke is not able to find PausedByUser method.
0
 
LVL 9

Expert Comment

by:_ys_
ID: 12472103
> QI works properly and I get the LPDISPATCH
Can you confirm this? Try to invoke PausedByUser immediately after obtaining this pointer - before passing it to the MFC exe.

Let me know the result.
0
 
LVL 2

Author Comment

by:avinash_sahay
ID: 12472246
I did that. This time also, the value of hr is not S_OK. I checked the meaning of the value in Tools->Error Lookup menu. The error is "Library Not Registered". I even tried to get the disp id of AddRef. Even this fails and I get the same error. Just to check, instead of creating an instance of CAsyncImpl, I create an instance of some other COM class (which does not support IAsync). Using QI, I get LPDISPATCH. From LPDISPATCH, I get the disp id of an exposed method in that class. This time disp id is proper.
0
 
LVL 9

Expert Comment

by:_ys_
ID: 12472823
I'll assume that the values for LIBID_XxxxLib, majorXxxx and minorXxxx are correct.

You use importlib of the type library for IAsync. So, try registering this type library as the error suggests. There should be a utility called RegTLib.exe on your local machine. Use this.
0
 
LVL 2

Author Comment

by:avinash_sahay
ID: 12479910
The dll is already registered. I tried registering once more. Note: I do not have the tlb file, I have only the dll. I have imported that. The dll  has been registered using regsvr32.exe.
0
 
LVL 9

Expert Comment

by:_ys_
ID: 12481511
Can you take the value of LIBID_XxxxLib in the format {00000000-0000-0000-0000-000000000000} (if you can't find this, the function StringFromCLSID should give you it.) and search the registry for it.

It should reside under the HKEY_CLASS_ROOT/TypeLib key. It's sub-key states the registered version and should again match your majorXxxx and minorXxxx.

Let me know what you find.
0
 
LVL 2

Author Comment

by:avinash_sahay
ID: 12490005
Yes, now it works. Thanks. But I do not understand why these were required when I have just one copy of that dll in my system.
Thanks a lot
0
 
LVL 9

Expert Comment

by:_ys_
ID: 12491610
When the DLL registerd itself with the system, it did enough for itself to work. What it didn't count on was what you were doing - reusing its interfaces.

So it didn't register the embedded typelib properly. But you need it, so these entries make it work for you as well.

At least it's now sorted.
0

Featured Post

What is SQL Server and how does it work?

The purpose of this paper is to provide you background on SQL Server. It’s your self-study guide for learning fundamentals. It includes both the history of SQL and its technical basics. Concepts and definitions will form the solid foundation of your future DBA expertise.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article shows you how to optimize memory allocations in C++ using placement new. Applicable especially to usecases dealing with creation of large number of objects. A brief on problem: Lets take example problem for simplicity: - I have a G…
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
This tutorial covers a step-by-step guide to install VisualVM launcher in eclipse.
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…

636 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question