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

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
 



MikeJ2001Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Bob LearnedCommented:
Is there a definition for SIMPLE_ATLLib.First_ATL also?

Bob
0
MikeJ2001Author 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;
}
0
MikeJ2001Author 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_
0
Cloud Class® Course: C++ 11 Fundamentals

This course will introduce you to C++ 11 and teach you about syntax fundamentals.

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

Bob
0
MikeJ2001Author 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'
0
Bob LearnedCommented:
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
0
MikeJ2001Author Commented:
solved: [STAThread] fixed it
0
Bob LearnedCommented:
Sometimes it the easy things.

Bob
0
DarthModCommented:
PAQed with points refunded (400)

DarthMod
Community Support Moderator
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C#

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.