QueryInterface return E_NOINTERFACE when executing in native code and called through managed wrapper  
Author Message
GeminiSaka





PostPosted: Visual C++ General, QueryInterface return E_NOINTERFACE when executing in native code and called through managed wrapper Top

(Environment: WinXP, Visual Studio 2005)

The structure of my sample program is listed as follows:

1. Create a native COM component Fun, with interface IFun;(ATL project)

2. Create a native c++ class using this COM component(Win32 application and build to a dll file)

class CSample{

private:

IFun* m_pFun;

public:

void Initialize(){

... IUnknown* pUnk;
hr = ::CoCreateInstance(
CLSID_Fun,
NULL,
CLSCTX_INPROC_SERVER,
IID_IUnknown,
(LPVOID*)&pUnk);
hr = pUnk->QueryInterface(
IID_IFun,
(LPVOID*)&m_pFun);...}

...};

3. managed Wrapper for native CSample(CLR class libaray)

public ref class MSample
{
private:
CSample *m_sampleWrapper;
public:
...

void Initialize(void){ m_sampleWrapper->Initialize(); }... }

4. C# console application using MSample

MSample mSample = new MSample();
mSample.Initialize();

When debuging, I steped into native code in CSample::Initialize() and found that QueryInterface() return E_NOINTERFACE, why this happend

I've also write a console application of native c++ to test CSample, and QueryInterface() can find the IFun interface and return S_OK.

I'am a new comer for the subject: COM interop between managed and unmanaged code. Thanks for your help!



Visual C++3  
 
 
Mike Danes





PostPosted: Visual C++ General, QueryInterface return E_NOINTERFACE when executing in native code and called through managed wrapper Top

I tried to reproduce this but failed. Are you sure that you have setup everything correctly

And do you really need to wrap the COM component in a native class and then in a managed class to use it in C# Normally you can add a reference to a COM component in C# and just use it without such wrappers.


 
 
GeminiSaka





PostPosted: Visual C++ General, QueryInterface return E_NOINTERFACE when executing in native code and called through managed wrapper Top

I tried to reproduce this but failed. Are you sure that you have setup everything correctly

And do you really need to wrap the COM component in a native class and then in a managed class to use it in C# Normally you can add a reference to a COM component in C# and just use it without such wrappers.

Thanks for your reply first.

I have already tried another way:

use the tlbimp tool to create metadata assembly from the exist COM component and add it directly into the C# project references, then execute the following code:

SampleLib.FunClass func = new SampleLib.FunClass(); // SampleLib.FunClass, I think is the corresponding one to native COM class, right
func.Add(1,1); // Add, I think is the corresponding one to the the method I defined in native COM component, right

and when executing the second statements, there's an error:

Additional information: Unable to cast COM object of type 'SampleLib.FunClass' to interface type 'SampleLib.IFun'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{7BA03ABC-6793-464E-86D6-02A5F2E5A9DA}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).

I'm afraid this is also concerned with QueryInterface() method and is the same problem as before.


 
 
GeminiSaka





PostPosted: Visual C++ General, QueryInterface return E_NOINTERFACE when executing in native code and called through managed wrapper Top

And do you really need to wrap the COM component in a native class and then in a managed class to use it in C# Normally you can add a reference to a COM component in C# and just use it without such wrappers.

My real situation is this:

I've a COM component(maybe "COM component" is not quite accurate since I'm really a new comer, I mean that I can do the operation like creating the COM object through function like CoCreateInstance, getting the interface through QueryInterface and do operations through the interface methods); The former application using the COM component is written in native c++ and now I want the COM component can be used in native code, like C#, VB.NET,etc. So I want to first write a wrapper class using managed c++ and export a dll which can be used in C#, VB.NET, etc.

However, I am not sure how to operate on native COM component directly in managed c++, so I use a class to wrapper the COM component first using native c++ and then wrapped the this class using managed c++.

I have turn to some material about managed c++, COM interop, PInvoke, wrapper, and I've been puzzled by these concepts and do not known which one belongs to which categroy.


 
 
Mike Danes





PostPosted: Visual C++ General, QueryInterface return E_NOINTERFACE when executing in native code and called through managed wrapper Top

"maybe "COM component" is not quite accurate since I'm really a new comer, I mean that I can do the operation like creating the COM object through function like CoCreateInstance, getting the interface through QueryInterface and do operations through the interface methods"

OK, from your description it looks like a COM component.

"So I want to first write a wrapper class using managed c++ and export a dll which can be used in C#, VB.NET, etc. "

Hmm... unless you have a very specific need for a wrapper around this component I would advise against doing that. Just add a reference in your C# project to this COM component and use it. As you alreadu discovered you can do new SampleLib.FunClass and call methods on the default interface. If the component has multple interfaces then the equivalent of QueryInterface is simply a cast to that interface. For example if Fun class also implements a IFoo interface then in C# you can just do:

SampleLib.IFoo foo = func as SampleLib.IFoo;

if (foo != null)

{

// object has IFoo interface, do something with it

}

In the documentation look for the COM interop stuff. It's what you need in this case.

And now back to your original problem. How did you create that IFun COM object Are you sure you did correctly I see no reason for QueryInterface to return E_NOINTERFACE from managed code.


 
 
GeminiSaka





PostPosted: Visual C++ General, QueryInterface return E_NOINTERFACE when executing in native code and called through managed wrapper Top

And now back to your original problem. How did you create that IFun COM object Are you sure you did correctly I see no reason for QueryInterface to return E_NOINTERFACE from managed code.

I create the COM component by following steps:

(1) Create an ATL dll project, named Sample;

(2) Add an ATL Simple object, named Fun(CoClass: Fun, Interface IFun, C++ class CFun);

(3) Add a method to IFun: Add(int a1, int a2, int* sum);

Sample.idl file is list as follows:

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

[
object,
uuid(7BA03ABC-6793-464E-86D6-02A5F2E5A9DA),
helpstring("IFun Interface"),
pointer_default(unique)
]
interface IFun : IUnknown{
[, helpstring("method Add")] HRESULT Add([in] int a1, [in] int a2, [out,retval] int* sum);
};
[
uuid(BAAFCFEC-4A5B-4196-A109-970DECF4FFDB),
version(1.0),
helpstring("Sample 1.0 Type Library")
]
library SampleLib
{
importlib("stdole2.tlb");
[
uuid(9FE2F111-C5C6-41F8-A5E6-0D769C217FBF),
helpstring("Fun Class")
]
coclass Fun
{
[default] interface IFun;
};
};

Build this project will generate Sample.dll.

In C# console application project, I add Sample.dll to references selected from the COM references list and this can be seen in window of Object Browser:

Interop.SampleLib

---SampleLib(namespace)

---Fun(interface) // I wonder how a "Fun" interface appears

---FunClass(class)

---IFun(interface)

Then, I write code:

using SampleLib;

// in Main()

SampleLib.FunClass fun = new SampleLib.FunClass();
fun.Add(1, 1); // error arises at this statement


 
 
Mike Danes





PostPosted: Visual C++ General, QueryInterface return E_NOINTERFACE when executing in native code and called through managed wrapper Top

Hmm... that is exactly what I have tried before. The IDL looks fine, what you see in Object Browser is also correct (not sure why Fun interface is autogenerated but I have it too). The only "difference" is that I get no error when calling the Add method.

This is supposed to work and I'm really out of ideas why it fails for you

If you want you can mail me the binary files that resulted from the above test (the sample.dll, sample.tlb, c# exe, interop.sample.dll files) and I'll see what happens on my machine. My mail address is in my profile.


 
 
GeminiSaka





PostPosted: Visual C++ General, QueryInterface return E_NOINTERFACE when executing in native code and called through managed wrapper Top

 

Hmm... that is exactly what I have tried before. The IDL looks fine, what you see in Object Browser is also correct (not sure why Fun interface is autogenerated but I have it too). The only "difference" is that I get no error when calling the Add method.

This is supposed to work and I'm really out of ideas why it fails for you

If you want you can mail me the binary files that resulted from the above test (the sample.dll, sample.tlb, c# exe, interop.sample.dll files) and I'll see what happens on my machine. My mail address is in my profile.

 

I really appreciate your great help!

I have emailed you the files, but I'm puzzled about your email address in your profile: "onemihaid at (the mail that is hot) com", is ...


 
 
Mike Danes





PostPosted: Visual C++ General, QueryInterface return E_NOINTERFACE when executing in native code and called through managed wrapper Top

Yes, that's the address. I edited your previous post to remove it, it's not a good idea to put email addresses in public pages

I got the sample and indeed it behaves as you say, from .NET the result is E_NOINTERFACE and from C++ it works fine. It'm trying to figure out what is different from my own test.


 
 
GeminiSaka





PostPosted: Visual C++ General, QueryInterface return E_NOINTERFACE when executing in native code and called through managed wrapper Top

Thanks alot!
 
 
Mike Danes





PostPosted: Visual C++ General, QueryInterface return E_NOINTERFACE when executing in native code and called through managed wrapper Top

Try adding the STAThreadAttribute to C# program's Main function:

[STAThread]

static void Main(string[] args)

{...

The IFun interface is definitly there and querying for it should work just fine. The only reason to get E_NOINTERFACE in this case is that the COM call must go through a proxy and there is a problem with the proxy. This happens because when Main does not have STAThread attribute the runtime automatically assumes MTA. However your object is STA and so any call to it must go through a proxy.

Now why doesn't the proxy work Not sure. For one thing your COM object does not have IDispatch. This prevents the runtime for generating a proxy but still it should work because when you create a COM object with the ATL wizard it automatically generates a proxy for you in a project that has the same name as the COM project but with a PS suffix. Do you have this project Did it compile


 
 
GeminiSaka





PostPosted: Visual C++ General, QueryInterface return E_NOINTERFACE when executing in native code and called through managed wrapper Top

 

Try adding the STAThreadAttribute to C# program's Main function:

[STAThread]

static void Main(string[] args)

{...

 

The IFun interface is definitly there and querying for it should work just fine. The only reason to get E_NOINTERFACE in this case is that the COM call must go through a proxy and there is a problem with the proxy. This happens because when Main does not have STAThread attribute the runtime automatically assumes MTA. However your object is STA and so any call to it must go through a proxy.

Now why doesn't the proxy work Not sure. For one thing your COM object does not have IDispatch. This prevents the runtime for generating a proxy but still it should work because when you create a COM object with the ATL wizard it automatically generates a proxy for you in a project that has the same name as the COM project but with a PS suffix. Do you have this project Did it compile

 

Thanks for your help, using the method of adding STAThreadAttribute can solve my problem.

I've found that the SamplePS project can not build correctly and I'm trying to handle this.

Also, I've turn to some materials about some concepts like COM Thread Model, Apartment, etc., the following is what I got:

1. Default situation, ApartmentState of MainThread is MAT;

(1) MainThread Call CoInitializeEx( NULL, COINIT_MULTITHREADED ) to generate a MAT Apartment;

(2) MainThread Call CoCreateInstance() to create the COM object of SAT, so a new SAT Appartment is generated and the COM object is placed in it;(Some doc says a SAT is associated with only one thread, in this case, which thread is associated with the new SAT )

(3) MainThread Call QueryInterface() which is the method of the COM object, due to the difference in appartment state, the call must through a proxy of the COM object, but there's some problem with the proxy in my case, so the call operation fails.

2. Set AppartmentState of MainThread SAT;

(1) MainThread Call CoInitialize() to generate a SAT Appartment;

(2) MainThread Call CoCreateInstance() to create the COM object of SAT, and the COM object is placed in the Appartment in (1);

(3) MainThread Call QueryInterface() which is the method of the COM object, because the thread is just the one associating the appartment which has the COM object, the call is directly pass to the object and do not need the proxy, so it succeeds.

Is the word above right I think there must be something incorrect and I'll try to learn more

 

And another question, back to my real situation, if the COM component is much more complex, for example, the method which need the interface pointer of another COM object, can the method like you say which generate the corresponding COM component in .NET environment automatically always works Or I need to implement a wrapper

Thanks again!


 
 
Mike Danes





PostPosted: Visual C++ General, QueryInterface return E_NOINTERFACE when executing in native code and called through managed wrapper Top

First a small note: It's STA (single threaded apartment) and not SAT, MTA (multithreaded apartent) and not MAT

Yes, it's right.

"which thread is associated with the new SAT )"

The thread that created the component. It's not really a matter of which threads when deciding if the call must go through a proxy, but which apartment. The component is STA, the thread is MTA, you get a proxy.

" for example, the method which need the interface pointer of another COM object, can the method like you say which generate the corresponding COM component in .NET environment automatically always works Or I need to implement a wrapper "

As long as you have a .tlb file for the component you should never need such a wrapper. It just complicates things.


 
 
GeminiSaka





PostPosted: Visual C++ General, QueryInterface return E_NOINTERFACE when executing in native code and called through managed wrapper Top

As long as you have a .tlb file for the component you should never need such a wrapper. It just complicates things.

Is the .tlb file generated when compiling .idl file So, if I've defined the .idl file(also have the .dll file), all the thing about interop can be down by VS2005 automatically


 
 
Mike Danes





PostPosted: Visual C++ General, QueryInterface return E_NOINTERFACE when executing in native code and called through managed wrapper Top

Yes, the tlb is a product of compiling the idl file. The tlb (type library) file contains all the necesary information for VS 2005 to generate an interop assembly from it. It does the same thing as using the tlbimp.exe sdk tool: http://msdn2.microsoft.com/en-us/library/tt0cf3sx(VS.80).aspx