Click here to Skip to main content
15,885,216 members
Please Sign up or sign in to vote.
3.00/5 (3 votes)
See more:
hi,
I have a native c++ dll and two classes:
classA{
void setNumber(int number);
int getNumber();
}
classB{
void setclassA(classA);
classA getclassA();
}

I have an ATL dll that wraps the native C++ dll and two interfaces: InterfaceForClassA , InterfaceForClassB .

InterfaceForClassA :
STDMETHODIMP CInterfaceForClassA::createClassAObject(void)
{
         ClassA* Aobject = new ClassA();
         return S_OK;
}
STDMETHODIMP CInterfaceForClassA::setNumberInClassA(SHORT pVal)
{
          if(Aobject != NULL)
                Aobject->setNumber(pVal);
         return S_OK;
}

STDMETHODIMP CInterfaceForClassA::getNumberInClassA(SHORT* pVal)
{        
          if(Aobject != NULL)
              *pVal = Aobject->getNumber();
          return S_OK;
}
STDMETHODIMP CInterfaceForClassA::getClassA(VARIANT** pVal)
{
         *pVal = (VARIANT*)Aobject;
          return S_OK;
}
STDMETHODIMP CInterfaceForClassA::putClassA(VARIANT* newVal)
{
         Aobject = (ClassA*)newVal;
         return S_OK;
}

InterfaceForClassB :
STDMETHODIMP CInterfaceForClassB::setClassA(IInterfaceForClassA * val)
{

          ClassB* BObject = new ClassB();
          ClassA* objA = new ClassA();            
         val->getClassA((VARIANT**)&objA);
         BObject->putClassA(objA);
          return S_OK;
}

STDMETHODIMP CInterfaceForClassB::getClassA(IInterfaceForClassA ** returnVal)
{
          ClassA* objA = new ClassA();   
          IInterfaceForClassA *pY;
          objA = BObject->getClassA();        
          pY->putClassA((VARIANT*)&objA);
          *returnVal = pY;
          return S_OK;
}

and finally i have a c# project that includes that ATL dll, in the c# project i call ATL dll classes:
InterfaceForClassAClass classAInt = new InterfaceForClassAClass();
classAInt.createClassAObject();
classAInt.setNumberInClassA(5);
InterfaceForClassBClass classBInt = new InterfaceForClassBClass();
classBInt.setClassA(classAInt);
classBInt.getClassA();

it gives the 'System.ExecutionEngineException' at the line "classBInt.getClassA();" .
Can you help me please?
Posted

An uninitialized pointer pY will be used... :)
class CInterfaceForClassB
{
  IInterfaceForClassA* m_pInterfaceA;
 
public:
  CInterfaceForClassB();
 
  STDMETHODIMP SetInterfaceA(IInterfaceForClassA* val);
  STDMETHODIMP GetInterfaceA(IInterfaceForClassA* val);
};
 
CInterfaceForClassB::CInterfaceForClassB()
  : m_pInterfaceA(NULL)
{
}
 
STDMETHODIMP CInterfaceForClassB::SetInterfaceA(IInterfaceForClassA* val)
{
  m_pInterfaceA = val;
}
 
STDMETHODIMP CInterfaceForClassB::GetInterfaceA(IInterfaceForClassA* val)
{
  val = m_pInterfaceA;
}
 
Share this answer
 
thank you for your answer.
but it gives the following error:

" [out] interface pointers must use double indirection : [ Parameter 'val' of Procedure 'getInterfaceA' ( Interface 'IInterfaceForClassB' ) ] "
 
Share this answer
 
OK :)

Try to change your get function:
STDMETHODIMP CInterfaceForClassB::GetInterfaceA(IInterfaceForClassA** val)
{
  *val = m_pInterfaceA;
}
 
Share this answer
 
it builds the dll without error but in the c# side:
InterfaceForClassAClass classAInt = new InterfaceForClassAClass();
classAInt.createClassAObject();
classAInt.setNumberInClassA(5);
InterfaceForClassBClass classBInt = new InterfaceForClassBClass();
classBInt.setClassA(classAInt);

InterfaceForClassAClass classAInt2 = new InterfaceForClassAClass();
classAInt2 = classBInt.getClassA();

it gives following error at the last line:
" Cannot implicitly convert type 'myATLprojectLib.InterfaceForClassA' to 'myATLprojectLib.InterfaceForClassAClass'. An explicit conversion exists (are you missing a cast?) "

then i changed the code to :
InterfaceForClassA classAInt2 = new InterfaceForClassA();
classAInt2 = classBInt.getClassA();
Console.WriteLine("Number "+ classAInt2.getNumberInClassA());

this time it gives the following error at the last line:
"AccessViolationException :Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
 
Share this answer
 
There are some things to improve in your classA... :)

But, firstly, improve and try it, please :) :
{
  InterfaceForClassAClass classAInt = new InterfaceForClassAClass();
  InterfaceForClassBClass classBInt = new InterfaceForClassBClass();
  
  classBInt.SetInterfaceA(classAInt);    // now is the pointer stored by B

  InterfaceForClassAClass classAInt2;    // second empty "pointer"

  classBInt.GetInterfaceA(&classAInt2);  // reference of the "pointer" in C# ??
                                         // classAInt2 = classAInt 

}
 
Share this answer
 
i try it and it gives following errors at line "classBInt.GetInterfaceA(&classAInt2);"

"Cannot take the address of, get the size of, or declare a pointer to a managed type ('myATLprojectLib.InterfaceForClassAClass') "
"No overload for method 'GetInterfaceA' takes '1' arguments "
 
Share this answer
 
OK :)

Could you post your IDL file (of the COM DLL), please,
and the result for:
{
...
  // the same above, and then:
  InterfaceForClassAClass classAInt2 = classBInt.GetInterfaceA();
}
 
Share this answer
 
The result for the above code:
" Cannot implicitly convert type 'myATLprojectLib.InterfaceForClassA' to 'myATLprojectLib.InterfaceForClassAClass'. An explicit conversion exists (are you missing a cast?) ", it gives it at the last line.

my idl:
import "oaidl.idl";
import "ocidl.idl";


[
    object,
    uuid(B825F096-A558-4751-BC3E-13CA91AB08E3),
    dual,
    nonextensible,
    helpstring("IInterfaceForClassA Interface"),
    pointer_default(unique)
]
interface IInterfaceForClassA : IDispatch{
    [id(1), helpstring("method createClassAObject")] HRESULT createClassAObject(void);
    [id(2), helpstring("method setNumberInClassA")] HRESULT setNumberInClassA([in]SHORT pVal);
    [id(3), helpstring("method getNumberInClassA")] HRESULT getNumberInClassA([out,retval]SHORT* pVal);
    [id(4), helpstring("method getClassA")] HRESULT getClassA([out,retval]VARIANT** pVal);
    [id(5), helpstring("method putClassA")] HRESULT putClassA([in]VARIANT* newVal);

};
[
    object,
    uuid(F6D4B1A3-BA23-4499-92B6-8CC815F45107),
    dual,
    nonextensible,
    helpstring("IInterfaceForClassB Interface"),
    pointer_default(unique)
]
interface IInterfaceForClassB : IDispatch{
    [id(1), helpstring("method setClassA")] HRESULT setClassA([in]IInterfaceForClassA * val)
    [id(2), helpstring("method getClassA")] HRESULT getClassA([out,retval]IInterfaceForClassA ** returnVal)

};
[
    uuid(19E570BC-88E1-4EA1-BEBB-55B113C0B71A),
    version(1.0),
    helpstring("myATLproject 1.0 Type Library")
]
library myATLprojectLib
{
    importlib("stdole2.tlb");
    [
        uuid(5A01A221-647A-4FCC-A2AD-2ADF0DA4895B),
        helpstring("InterfaceForClassB Class")
    ]
    coclass InterfaceForClassB
    {
        [default] interface IInterfaceForClassB;
    };
    [
        uuid(D3ACED71-F62A-43FF-AC69-994222D93308),
        helpstring("InterfaceForClassA Class")
    ]
    coclass InterfaceForClassA
    {
        [default] interface IInterfaceForClassA;
    };
);
 
Share this answer
 
v3
Here would be my suggestion :) :

// C++ DLL.h
class A
{
  int m_iNumber;
public:
  A()                               { m_iNumber = 0; };
  void SetNumber(const int& iValue) { m_iNumber = iValue; };
  int  GetNumber()                  { return m_iNumber; };
  const A& operator = (const A& a)  { m_iNumber = a.GetNumber(); return *this; };
};
class B
{
  A m_aProperty;
public:
  B()                                {};
  void SetProperty(const A& a)       { m_aProperty = a; };
  const A& GetProperty()             { return m_aProperty; };
};


// ATL DLL.h
#include "C++ DLL.h"
 
class CInterfaceA
{
  DWORD m_dwID;
  A     m_aProperty;
 
public:
  CInterfaceA();
  ~CInterfaceA();
 
  const A& GetProperty();
 
  STDMETHODIMP SetNumber(SHORT shNumber);
  STDMETHODIMP GetNumber(SHORT* pshNumber);
  STDMETHODIMP GetID(ULONG* pulID);
};
 
class CInterfaceB
{
  B m_bProperty;
 
public:
  CInterfaceB();
 
  STDMETHODIMP SetAByID(ULONG ulID);
};
 
// ATL DLL.cpp
#include "ATL DLL.h"
#include <atlsimpcoll.h>
 
DWORD g_dwAObjectsCount = 0;
CSimpleMap<DWORD, CInterfaceA*> g_AObjectsMap;
 
CInterfaceA::CInterfaceA()
{
  m_dwID = g_dwAObjectsCount++;
  g_AObjectsMap.SetAt(m_dwID, this);
}
 
CInterfaceA::~CInterfaceA()
{
  g_AObjectsMap.RemoveAt(m_dwID);
}
 
const A& CInterfaceA::GetProperty()
{
  return m_aProperty;
}
 
STDMETHODIMP CInterfaceA::SetNumber(SHORT shNumber)
{
  m_aProperty.SetNumber(shNumber);
  return S_OK;
}
  
STDMETHODIMP CInterfaceA::GetNumber(SHORT* pshNumber)
{
  *pshNumber = m_aProperty.GetNumber();
  return S_OK;
}
  
STDMETHODIMP CInterfaceA::GetID(ULONG* pulID)
{
  *pulID = m_dwID;
  return S_OK;
}
  
 
CInterfaceB::CInterfaceB()
{
}
 
STDMETHODIMP CInterfaceB::SetAByID(ULONG ulID)
{
  CInterfaceA* pcInterfaceA = g_AObjectsMap.GetValueAt(ulID);
  if (pcInterfaceA) {
    A a = pcInterfaceA->GetProperty();
    m_bProprerty.SetProperty(a);
  }
  return S_OK;
}


// C# usage
{
...
  InterfaceForClassAClass classAInt = new InterfaceForClassAClass();
  classAInt.SetNumber(5);
  ULONG ulID = 0;
  classAInt.GetID(&ulID);
  
  InterfaceForClassBClass classBInt = new InterfaceForClassBClass();
  classBInt.SetAByID(ulID); // IB::m_bProperty::m_aProperty = IA::m_aProperty :)
...
}
 
Share this answer
 
v2
Eugen thanks for your answer. but i couldn't do it, i can't modify c++ dll and other stuff didn't work. I suppose i should find another way to solve this problem.Thanks again for your all effort
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900