Having hard time marshalling parameters from C++ to .Net?
If you are finding it difficult to send parameters from C++ to .Net, try if you can use the following class:
--------------------------------------------------------------------------------------------------------------------------------
#ifndef __PARAMETERS_H_A1B7ECCA_1691_43d0_ACDD_EBE1208005F9
#define __PARAMETERS_H_A1B7ECCA_1691_43d0_ACDD_EBE1208005F9
#include <Comdef.h>
#ifdef _DEBUG
#define NO_ERROR_CHECKING FALSE //Use Error Checking for Debug Versions (throws Exception from Constructor !!)
#else
#define NO_ERROR_CHECKING TRUE //Turn-off Error Checking for Release Versions
#endif
#ifndef _MFC_VER //Check if this is NON-MFC application
typedef const SAFEARRAY* LPCSAFEARRAY;
#endif
class CParameters
{
int m_nParamCount;
int m_nCurParam;
SAFEARRAY* m_pSA;
inline bool IsInvalid()
{
return m_nCurParam >= m_nParamCount || m_pSA == NULL;
}
public:
CParameters(int nCount)
{
m_nCurParam = 0;
m_nParamCount = nCount;
SAFEARRAYBOUND bounds[] = {{nCount,0}}; //Array Contains 'nCount' Elements starting from Index '0'
m_pSA = SafeArrayCreate(VT_VARIANT,1,bounds);
//Create a one-dimensional SafeArray of variants
#if NO_ERROR_CHECKING == FALSE
if(m_pSA == NULL) throw "Exception: Unable to Create Safe Array";
#endif
}
~CParameters(void)
{
if(m_pSA)
{
SafeArrayDestroy(m_pSA);
m_pSA = NULL;
}
}
inline operator LPSAFEARRAY() const { return m_pSA; }
inline operator LPCSAFEARRAY() const { return m_pSA; }
inline int GetCount() const { return m_nParamCount; }
inline HRESULT AddParameter(const bool& bParamVal)
{
#if NO_ERROR_CHECKING == FALSE
if(IsInvalid()) return E_FAIL;
#endif
long lIndex[] = { m_nCurParam++ };
VARIANT var;
var.vt = VT_BOOL;
var.boolVal = bParamVal;
return SafeArrayPutElement(m_pSA, lIndex, &var);
}
inline HRESULT AddParameter(const long& lParamVal)
{
#if NO_ERROR_CHECKING == FALSE
if(IsInvalid()) return E_FAIL;
#endif
long lIndex[] = { m_nCurParam++ };
VARIANT var;
var.vt = VT_I4;
var.lVal= lParamVal;
return SafeArrayPutElement(m_pSA, lIndex, &var);
}
inline HRESULT AddParameter(LPCTSTR lpszParamVal)
{
try
{
#if NO_ERROR_CHECKING == FALSE
if(IsInvalid()) return E_FAIL;
#endif
long lIndex[] = { m_nCurParam++ };
VARIANT var;
var.vt = VT_BSTR;
var.bstrVal = SysAllocString(bstr_t(lpszParamVal));
return SafeArrayPutElement(m_pSA, lIndex, &var);
}
catch(_com_error& e)
{
return e.Error();
}
}
inline HRESULT AddParameter(const LPCTSTR lpszArray[], int nCount)
{
try
{
#if NO_ERROR_CHECKING == FALSE
if(IsInvalid()) return E_FAIL;
#endif
VARIANT var;
SAFEARRAYBOUND bounds[] = {{nCount,0}}; //Array Contains 'nCount' Elements starting from Index '0'
var.vt = VT_ARRAY | VT_BSTR;
var.parray = SafeArrayCreate(VT_BSTR,1,bounds); //Create a one-dimensional SafeArray of variants
if(var.parray == NULL)
return E_OUTOFMEMORY;
for(long i=0; i < nCount; ++i)
{
HRESULT hr = SafeArrayPutElement(var.parray, &i, SysAllocString(bstr_t(lpszArray[i])));
if(FAILED(hr)) return hr;
}
long lIndex[] = { m_nCurParam++ };
return SafeArrayPutElement(m_pSA, lIndex, &var);
}
catch(_com_error& e)
{
return e.Error();
}
}
};
#endif //__PARAMETERS_H_A1B7ECCA_1691_43d0_ACDD_EBE1208005F9
--------------------------------------------------------------------------------------------------------------------------------
Using this class is simple and straight forward. Declare a CParameters variable and call CParameters::AddParameter() once for each argument you want to send to .Net.
For example, to invoke a method in .net that has prototype
void Foo(string strName, int nLen);
use the following from C++:
CParameters param(2); // Two parameters for the method
param.AddParameter("Hello World!!"); // strName
param.AddParameter(13); // nLen = strlen(strName)
spFoo->Invoke_3(..., param); // Invoke the Foo function with the Arguments
You are welcome to add support for CParameters class to accept more types. For similar handy classes, visit https://www.geocities.com/krishnapg/
Comments
- Anonymous
June 18, 2007
PingBack from http://msdnrss.thecoderblogs.com/2007/06/18/having-hard-time-marshalling-parameters-from-c-to-net/