We help IT Professionals succeed at work.

Calling ATL COM method from C# fails with  HRESULT: 0x80004002 (E_NOINTERFACE)

MikeJ2001
MikeJ2001 asked
on
Medium Priority
2,933 Views
Last Modified: 2012-06-27
I am currently trying to port some C++ sample code for an ATL COM Component to C#. The component was developed in C++. It compiles fine with VC6 and VC8 and the console-based sample that calls the COM is also working fine.

The C# code compiles fine, however, when I execute it I get the following runtime error:

System.InvalidCastException was unhandled
Message="Unable to cast COM object of type 'SIMPLE_ATLLib.First_ATLClass' to interface type 'SIMPLE_ATLLib.IFirst_ATL'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{C8F6E230-2672-11D3-A8A8-00105AA943DF}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE))."
  Source="Interop.SIMPLE_ATLLib"
  StackTrace:
       at SIMPLE_ATLLib.First_ATLClass.AddNumbers(Int32 Num1, Int32 Num2)
       at Test_ATL.Program.Main(String[] args) in C:\develop\samples\COM_ATL tutorial\COM_ATL_Tutorial_CS_Source\Test_ATL.cs:line 29
       at System.AppDomain.nExecuteAssembly(Assembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()

here is the source code:
  SIMPLE_ATLLib.First_ATLClass testClass = new SIMPLE_ATLLib.First_ATLClass();
  if (testClass == null)
   {
      Console.WriteLine("ERROR: can't create instance of testClass SIMPLE_ATLLib.First_ATLClass()");
   }
   Console.WriteLine("Getting a long value ..");
   Int32 iValue;
   iValue=testClass.AddNumbers(1, 2); // this is the part that I can't get to work


// ================== WORKING C++ code =====================
/**
 * This test calls the AddNumbers() method. It adds two numbers. The result
 * is returned bu reference.
*/
void test_addNumbers(IFirst_ATL *comClass)
{
  HRESULT hr;
  long ReturnValue;
  hr = comClass->AddNumbers(5, 7, &ReturnValue);
  cout << "================================================================" << endl;
  cout << "calculating 5 + 7 ... ";
  if(SUCCEEDED(hr))
  {
    cout << "result is: " << dec << ReturnValue << endl;
  }
  else
  {
    cout << "ERROR " << hr << endl;
  }
}

NOTE:
the sample code and ATL COM was derived from "A Simple COM tutorial using ATL" by  C. Lung which contains the COM sources and VB and VC sample code. Complete original sources are available at: http://www.codeguru.com/Cpp/COM-Tech/atl/tutorials/article.php/c17
 



Comment
Watch Question

CERTIFIED EXPERT
Most Valuable Expert 2012
Top Expert 2008

Commented:
Is there a definition for SIMPLE_ATLLib.First_ATL also?

Bob

Author

Commented:
Hi Bob,
Thanks for looking into this.
Mike

// ============= from Simple_ATL.h ====================
// excerpt from the Simple_ATL.h file created by the VC compiler.
 
virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE AddNumbers(
            /* [in] */ long Num1,
            /* [in] */ long Num2,
            /* [retval][out] */ long *ReturnVal) = 0;
       
/* [helpstring] */ HRESULT STDMETHODCALLTYPE IFirst_ATL_AddNumbers_Proxy(
    IFirst_ATL * This,
    /* [in] */ long Num1,
    /* [in] */ long Num2,
    /* [retval][out] */ long *ReturnVal);

void __RPC_STUB IFirst_ATL_AddNumbers_Stub(
    IRpcStubBuffer *This,
    IRpcChannelBuffer *_pRpcChannelBuffer,
    PRPC_MESSAGE _pRpcMessage,
    DWORD *_pdwStubPhase);

// ========================== from First_ATL.cpp ==============
// IMPLEMENTATION of the AddNumbers method
STDMETHODIMP CFirst_ATL::AddNumbers(long Num1, long Num2, long *ReturnVal)
{
      *ReturnVal = Num1 + Num2;
      return S_OK;
}

Author

Commented:
// First_ATL.h : Declaration of the CFirst_ATL

#ifndef __FIRST_ATL_H_
#define __FIRST_ATL_H_

#include "resource.h"       // main symbols

/////////////////////////////////////////////////////////////////////////////
// CFirst_ATL
class ATL_NO_VTABLE CFirst_ATL :
      public CComObjectRootEx<CComSingleThreadModel>,
      public CComCoClass<CFirst_ATL, &CLSID_First_ATL>,
      public IFirst_ATL
{
public:
      CFirst_ATL()
      {
      }

DECLARE_REGISTRY_RESOURCEID(IDR_FIRST_ATL)
DECLARE_NOT_AGGREGATABLE(CFirst_ATL)

DECLARE_PROTECT_FINAL_CONSTRUCT()

BEGIN_COM_MAP(CFirst_ATL)
      COM_INTERFACE_ENTRY(IFirst_ATL)
END_COM_MAP()

// IFirst_ATL
public:
      STDMETHOD(getBSTR)(/*[in]*/ BSTR input, /*[in]*/ long offset, /*[out, retval]*/ BSTR *output);
      STDMETHOD(AddNumbers)(/*[in]*/ long Num1, /*[in]*/ long Num2, /*[out, retval]*/ long *ReturnVal);
        STDMETHOD(getByteArray)(/*[in, out]*/long *length, /*[out, retval]*/ unsigned char* byteArray);
      STDMETHOD(getLongValue)(/*[out, retval]*/ long *longValue);
};

#endif //__FIRST_ATL_H_
CERTIFIED EXPERT
Most Valuable Expert 2012
Top Expert 2008

Commented:
I see 'IFirst_ATL' defined.  Did you try that?

Bob

Author

Commented:
Yes, working with IFirst_ATL worked fine C++: an IFirst_ATL *comClass gives me access to all methods within the FirstATl class.
  IFirst_ATL      *IFirstATL;
  hr = CoInitialize(0);
  // Now we will intilize COM
  // Use the SUCCEDED macro and see if we can get a pointer to
  // the interface
  if(SUCCEEDED(hr))
  {
    hr = CoCreateInstance( CLSID_First_ATL, NULL, CLSCTX_INPROC_SERVER,
      IID_IFirst_ATL, (void**) &IFirstATL);
// If we succeeded then call the AddNumbers method, if it failed
      // then display an appropriate message to the user.
      if(SUCCEEDED(hr))
      {
        test_addNumbers(IFirstATL);

I tried that in C#, but there, I can only create an instance of the First_ATL class the following way:
SIMPLE_ATLLib.First_ATLClass testClass = new SIMPLE_ATLLib.First_ATLClass();

changing this to
SIMPLE_ATLLib.IFirst_ATL testClass = new SIMPLE_ATLLib.IFirst_ATL();

leads to the following error message during build:
Cannot create an instance of the abstract class or interface 'SIMPLE_ATLLib.IFirst_ATL'
CERTIFIED EXPERT
Most Valuable Expert 2012
Top Expert 2008

Commented:
I have to say that working with COM/C++ libraries can really be a pain in the ass :(

I have been reading articles like this, that talk about creating a custom wrapper class in managed C++.NET, and calling it from C#.  

Implementing a Custom Runtime Callable Wrapper
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vcmex/html/vcgrfImplementingCustomRuntimeCallableWrapper.asp


I realize, though, that this only adds another layer of complexity.

Bob

Author

Commented:
solved: [STAThread] fixed it
CERTIFIED EXPERT
Most Valuable Expert 2012
Top Expert 2008

Commented:
Sometimes it the easy things.

Bob
Commented:
PAQed with points refunded (400)

DarthMod
Community Support Moderator

Not the solution you were looking for? Getting a personalized solution is easy.

Ask the Experts
Access more of Experts Exchange with a free account
Thanks for using Experts Exchange.

Create a free account to continue.

Limited access with a free account allows you to:

  • View three pieces of content (articles, solutions, posts, and videos)
  • Ask the experts questions (counted toward content limit)
  • Customize your dashboard and profile

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.