passing c# class as parameter to managed c++ method

L

lolomgwtf

I have a managed C++ method that wraps unmanaged code and creates a
managed object holding data retrieved form an unmanged one. I want
create an instance of this managed class in C#, pass it to this method
and have it set the instance to hold the right data.
From what I've read it seems I should be able to pass C# objects to
managed C++ methods and it should just work; however, when I try it, my
C# instance comes out null. If I step into the C++ method, the
debugger says the parameter is out of scope, but it doesn't throw an
exception when the parameter is referred to in the code -- I assume
this is a debugger problem. But I still don't understand why it
doesn't come out correctly set.

Sorry if this question is unclear. Here's my code, hopefully it will
be more illuminating:

// C# code
public int GetLevel1()
{
// create the managed object in C#
BWCMsgLevel1 msg = null;
// if I instantiate it, then I can set the individual fields
// in the C++ code (see note below)
// BWCMsgLevel1 msg = new BWCMsgLevel1();

// call the managed C++ code, passing the managed object as a
parameter
int result = _DataConnection.GetLevel1(m_Symbol, msg);
return result;
}

// managed C++ code
BOOL Wrapper::GetLevel1(String* sSymbol, BWCMsgLevel1*
pMsgLevel1Managed)
{
// put the String into an LPCTSTR
LPCTSTR lpctSymbol;
const char * c = (const
char*)(System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(sSymbol)).ToPointer();
std::string str = c;

System::Runtime::InteropServices::Marshal::FreeHGlobal(System::IntPtr((void*)c));
lpctSymbol = str.c_str();

// create a local instance of the managed object
BWCMsgLevel1* pTest;

// create a local instance of the unmanaged object
CMsgLevel1* pMsgLevel1 = new CMsgLevel1();

// call unmanaged code to fill msgLevel1 with correct data
int nResult = m_pCStockCache->GetLevel1(lpctSymbol, pMsgLevel1, 0, 0);

if(nResult != 0)
{
// if successful getting data out of cache, put data into a
BWCMsgLevel1 object

// create a managed array of bytes
byte arr __gc[] = new byte __gc[pMsgLevel1->GetSize()];

// copy bytes from unmanaged msgLevel1 to managed arr
Marshal::Copy(msgLevel1, arr, 0, pMsgLevel1->GetSize());

// set pTest to an instance of the managed class
// at this point, I can see pTest and check its members and they are
all set correctly
pTest = new BWCMsgLevel1(arr, true);

// set parameter pMsgLevel1Managed equal to pTest
pMsgLevel1Managed = pTest;

// copy fields from unmanaged c++ level1 object to managed .NET
level1 object.
// This code works if pMsgLevel1Managed isn't null, but I would
prefer
// not to have to write code to copy each field because there are
going to be
// many, many more fields.
// The debugger still says pMsgLevel1Managed is out of scope, but I
can
// step through these lines without an error, and when I inspect the
object
// in C# the fields are set correctly.
//pMsgLevel1Managed->m_bDecimal = pMsgLevel1->m_bDecimal;
//pMsgLevel1Managed->m_cAskMC = pMsgLevel1->m_cAskMC;
//pMsgLevel1Managed->m_cBidMC = pMsgLevel1->m_cBidMC;
}

return nResult;
}

BWCMsgLevel1 is defined in a C# library that both this C# project and
the managed C++ project can see.
I'm not a C++ programmer so maybe I'm missing something. If there is a
better place to post this, please let me know. Thanks for your help.
 
M

Mattias Sjögren

// managed C++ code
BOOL Wrapper::GetLevel1(String* sSymbol, BWCMsgLevel1* >pMsgLevel1Managed)

If you want to return a new BWCMsgLevel1 instance you have to add an
additional level of indirection here (BWCMsgLevel1**), effectively
making it a ref parameter in C#.



Mattias
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top