passing a safe Array as an out parameter to a .net component
| I have a .Net component that passes a stringArray to a client program via an out parameter. This works fine from a .net client and I have successfully passed a SafeArray from MFCto a .net component as an [in] parameter. What seems to evade me is returning returning an array of BSTR from a .net component via the CCW as an [out] parameter, back to this MFC client Can anyone help? regards
|
Yeah sure a ref parameter from c# becomes an [out] parameter in the generated TLI and TLH files when u import the type lib into the MFC app.
The thing is the .net procedure that I am calling from MFC is being executed correctly and sucessfully.
It is just that the ref string[] parameter passed back from the c# component does not seem to get marshaled correctly into the safe array in the MFC client.
The SafeArray that is used to recieve the marshaled ref string[] , just contains garbage.
Yes..The safearray has been set up to hold BSTRs
Has any one successfully done this before? If so could you send me a code sample. There doesnt seem to be a lot on the net wrt SafeArray Code samples
Cheers
Rob
Hi,
Here is the TLH file generated from th types lib... The function you are interested in is highlighed with a red background
//
// C++ source equivalent of Win32 type library C:\DEVELOPMENT\ENTERPRISE_5.1\Product Integration\IDTranslation\Translation API\C# Translation API\translation API\bin\Debug\translation API.tlb
// compiler-generated file created 04/27/05 at 11:15:22 - DO NOT EDIT!
#pragma
once #pragma
pack(push, 8) #include
<comdef.h> //
// Forward references and typedefs
//
struct
__declspec(uuid("e6d0059d-00fe-34a0-8f7f-f5c091cfadaa")) /* LIBID */
__translation_API; struct
ID_TRANS_CTX; struct
__declspec(uuid("27aa8457-b0ec-40df-afef-7a868bf8e867")) /* dual interface */
ITranslateID; struct
/* coclass */ CTranslateID; //
// Smart pointer typedef declarations
//
_COM_SMARTPTR_TYPEDEF(ITranslateID,
__uuidof(ITranslateID)); //
// Type library items
//
struct
__declspec(uuid("fbaa356f-dd9c-38b5-a5da-c2453049bdcc")) ID_TRANS_CTX
{
long fromProduct; long toProduct; long elementType; long ProjectNo; long MNC; long MCC; };
struct
__declspec(uuid("27aa8457-b0ec-40df-afef-7a868bf8e867")) ITranslateID : IDispatch
{
// // Wrapper methods for error-handling // long TranslateID ( struct ID_TRANS_CTX xTransCtx, _bstr_t strIdNameToTranslate,
BSTR * rstrTranslatedIdName );
long TranslateID_2 ( struct ID_TRANS_CTX xTransCtx, SAFEARRAY * astrInputIdNames,
SAFEARRAY * * rastrOrigIdNames,
SAFEARRAY * * rastrTranslatedIdNames );
long TranslateToAsset ( struct ID_TRANS_CTX xTransCtx, _bstr_t strIdNameToTranslate,
long * riTranslatedIdKey ); long TranslateToAsset_2 ( struct ID_TRANS_CTX xTransCtx, SAFEARRAY * astrInputIdNames,
SAFEARRAY * * rastrOrigIdNames,
SAFEARRAY * * raiTranslatedIdKeys );
long TranslateFromAsset ( struct ID_TRANS_CTX xTransCtx, long iIdKeyToTranslate, BSTR * rstrTranslatedIdName );
long TranslateFromAsset_2 ( struct ID_TRANS_CTX xTransCtx, SAFEARRAY * aiInputIdKeys,
SAFEARRAY * * riOrigIdKeys,
SAFEARRAY * * rastrTranslatedIdNames );
long TranslateFromSubCell ( struct ID_TRANS_CTX xTransCtx, long iCellKey, long iLayerKey, BSTR * rstrTranslatedIdName );
long TranslateFromSubCell_2 ( struct ID_TRANS_CTX xTransCtx, SAFEARRAY * aiInputCellKeys,
SAFEARRAY * aiInputLayerKeys,
SAFEARRAY * * raiOrigCellKeys,
SAFEARRAY * * raiOrigLayerKeys,
SAFEARRAY * * rastrTranslatedIdNames );
// // Raw methods provided by interface // virtual HRESULT __stdcall raw_TranslateID ( /*[in]*/ struct ID_TRANS_CTX xTransCtx, /*[in]*/ BSTR strIdNameToTranslate, /*[in,out]*/ BSTR * rstrTranslatedIdName, /*[out,retval]*/ long * pRetVal ) = 0; virtual HRESULT __stdcall raw_TranslateID_2 ( /*[in]*/ struct ID_TRANS_CTX xTransCtx, /*[in]*/ SAFEARRAY * astrInputIdNames, /*[in,out]*/ SAFEARRAY * * rastrOrigIdNames, /*[in,out]*/ SAFEARRAY * * rastrTranslatedIdNames, /*[out,retval]*/ long * pRetVal ) = 0; virtual HRESULT __stdcall raw_TranslateToAsset ( /*[in]*/ struct ID_TRANS_CTX xTransCtx, /*[in]*/ BSTR strIdNameToTranslate, /*[in,out]*/ long * riTranslatedIdKey, /*[out,retval]*/ long * pRetVal ) = 0; virtual HRESULT __stdcall raw_TranslateToAsset_2 ( /*[in]*/ struct ID_TRANS_CTX xTransCtx, /*[in]*/ SAFEARRAY * astrInputIdNames, /*[in,out]*/ SAFEARRAY * * rastrOrigIdNames, /*[in,out]*/ SAFEARRAY * * raiTranslatedIdKeys, /*[out,retval]*/ long * pRetVal ) = 0; virtual HRESULT __stdcall raw_TranslateFromAsset ( /*[in]*/ struct ID_TRANS_CTX xTransCtx, /*[in]*/ long iIdKeyToTranslate, /*[in,out]*/ BSTR * rstrTranslatedIdName, /*[out,retval]*/ long * pRetVal ) = 0; virtual HRESULT __stdcall raw_TranslateFromAsset_2 ( /*[in]*/ struct ID_TRANS_CTX xTransCtx, /*[in]*/ SAFEARRAY * aiInputIdKeys, /*[in,out]*/ SAFEARRAY * * riOrigIdKeys, /*[in,out]*/ SAFEARRAY * * rastrTranslatedIdNames, /*[out,retval]*/ long * pRetVal ) = 0; virtual HRESULT __stdcall raw_TranslateFromSubCell ( /*[in]*/ struct ID_TRANS_CTX xTransCtx, /*[in]*/ long iCellKey, /*[in]*/ long iLayerKey, /*[in,out]*/ BSTR * rstrTranslatedIdName, /*[out,retval]*/ long * pRetVal ) = 0; virtual HRESULT __stdcall raw_TranslateFromSubCell_2 ( /*[in]*/ struct ID_TRANS_CTX xTransCtx, /*[in]*/ SAFEARRAY * aiInputCellKeys, /*[in]*/ SAFEARRAY * aiInputLayerKeys, /*[in,out]*/ SAFEARRAY * * raiOrigCellKeys, /*[in,out]*/ SAFEARRAY * * raiOrigLayerKeys, /*[in,out]*/ SAFEARRAY * * rastrTranslatedIdNames, /*[out,retval]*/ long * pRetVal ) = 0; };
struct
__declspec(uuid("30734794-6d17-4983-b864-0e5a6552da4e")) CTranslateID;
// interface _Object // [ default ] interface ITranslateID //
// Named GUID constants initializations
//
extern
"C" const GUID __declspec(selectany) LIBID_translation_API = {0xe6d0059d,0x00fe,0x34a0,{0x8f,0x7f,0xf5,0xc0,0x91,0xcf,0xad,0xaa}};
extern
"C" const GUID __declspec(selectany) IID_ITranslateID = {0x27aa8457,0xb0ec,0x40df,{0xaf,0xef,0x7a,0x86,0x8b,0xf8,0xe8,0x67}};
extern
"C" const GUID __declspec(selectany) CLSID_CTranslateID = {0x30734794,0x6d17,0x4983,{0xb8,0x64,0x0e,0x5a,0x65,0x52,0xda,0x4e}};
//
// Wrapper method implementations
//
#include
"c:\development\enterprise_5.1\product integration\idtranslation\translation api\c# translation api\mfc_translate\debug\translation api.tli" #pragma
pack(pop)
In addition I enclose the MFC procedure that I am using to call this void
CMFC_TRANSLATEDlg:
nBnClickedOk() {
IUnknown* Unk = NULL;
ITranslateID* tt = NULL;
HRESULT hr;
SAFEARRAYBOUND rgsaBound[1];
rgsaBound[0].lLbound = 0;
rgsaBound[0].cElements = 1;
/*SAFEARRAYBOUND rgsaBound2[1];
rgsaBound2[0].lLbound = 0;
rgsaBound2[0].cElements = 4;*/
long bound[] = {0,0,0}; // IListPtr u(__uuidof(IList));
hr = CoInitialize(NULL);
hr = CoCreateInstance( CLSID_CTranslateID , NULL , CLSCTX_INPROC_SERVER , IID_IUnknown ,(
void**) &Unk ); ID_TRANS_CTX z = { 3, 4, 3060 , 0 , 20, 10 };
SAFEARRAY* pSA;
SAFEARRAY* pSB = NULL;;
SAFEARRAY* pSC = NULL;
pSA = SafeArrayCreate( VT_VARIANT , 1 , rgsaBound );
_bstr_t Y = "D_SBA";
_bstr_t X = " ";
BSTR YY = Y.GetBSTR();
BSTR XX = X.GetBSTR();
hr = SafeArrayPutElement( pSA , &bound[0] , YY );
pSB = SafeArrayCreate( VT_BSTR , 1 , rgsaBound);
pSC = SafeArrayCreate( VT_BSTR , 1 , rgsaBound );
hr = Unk->QueryInterface( IID_ITranslateID , (
void**) &tt ); hr = tt->TranslateID_2( z , pSA , &pSB , &pSC );
SafeArrayGetElement( pSC , &bound[2] , XX);
// spTranslate.CoCreateInstance( IID_CTRANSLATEID );
// spTranslate->TranslateID( z , "D_EA" , pX);;
OnOK();
}
Regards
Rob
Hi,
Here is the TLH file generated from th types lib... The function you are interested in is highlighed with a red background
//
// C++ source equivalent of Win32 type library C:\DEVELOPMENT\ENTERPRISE_5.1\Product Integration\IDTranslation\Translation API\C# Translation API\translation API\bin\Debug\translation API.tlb
// compiler-generated file created 04/27/05 at 11:15:22 - DO NOT EDIT!
#pragma
once #pragma
pack(push, 8) #include
<comdef.h> //
// Forward references and typedefs
//
struct
__declspec(uuid("e6d0059d-00fe-34a0-8f7f-f5c091cfadaa")) /* LIBID */
__translation_API; struct
ID_TRANS_CTX; struct
__declspec(uuid("27aa8457-b0ec-40df-afef-7a868bf8e867")) /* dual interface */
ITranslateID; struct
/* coclass */ CTranslateID; //
// Smart pointer typedef declarations
//
_COM_SMARTPTR_TYPEDEF(ITranslateID,
__uuidof(ITranslateID)); //
// Type library items
//
struct
__declspec(uuid("fbaa356f-dd9c-38b5-a5da-c2453049bdcc")) ID_TRANS_CTX
{
long fromProduct; long toProduct; long elementType; long ProjectNo; long MNC; long MCC; };
struct
__declspec(uuid("27aa8457-b0ec-40df-afef-7a868bf8e867")) ITranslateID : IDispatch
{
// // Wrapper methods for error-handling // long TranslateID ( struct ID_TRANS_CTX xTransCtx, _bstr_t strIdNameToTranslate,
BSTR * rstrTranslatedIdName );
long TranslateID_2 ( struct ID_TRANS_CTX xTransCtx, SAFEARRAY * astrInputIdNames,
SAFEARRAY * * rastrOrigIdNames,
SAFEARRAY * * rastrTranslatedIdNames );
long TranslateToAsset ( struct ID_TRANS_CTX xTransCtx, _bstr_t strIdNameToTranslate,
long * riTranslatedIdKey ); long TranslateToAsset_2 ( struct ID_TRANS_CTX xTransCtx, SAFEARRAY * astrInputIdNames,
SAFEARRAY * * rastrOrigIdNames,
SAFEARRAY * * raiTranslatedIdKeys );
long TranslateFromAsset ( struct ID_TRANS_CTX xTransCtx, long iIdKeyToTranslate, BSTR * rstrTranslatedIdName );
long TranslateFromAsset_2 ( struct ID_TRANS_CTX xTransCtx, SAFEARRAY * aiInputIdKeys,
SAFEARRAY * * riOrigIdKeys,
SAFEARRAY * * rastrTranslatedIdNames );
long TranslateFromSubCell ( struct ID_TRANS_CTX xTransCtx, long iCellKey, long iLayerKey, BSTR * rstrTranslatedIdName );
long TranslateFromSubCell_2 ( struct ID_TRANS_CTX xTransCtx, SAFEARRAY * aiInputCellKeys,
SAFEARRAY * aiInputLayerKeys,
SAFEARRAY * * raiOrigCellKeys,
SAFEARRAY * * raiOrigLayerKeys,
SAFEARRAY * * rastrTranslatedIdNames );
// // Raw methods provided by interface // virtual HRESULT __stdcall raw_TranslateID ( /*[in]*/ struct ID_TRANS_CTX xTransCtx, /*[in]*/ BSTR strIdNameToTranslate, /*[in,out]*/ BSTR * rstrTranslatedIdName, /*[out,retval]*/ long * pRetVal ) = 0; virtual HRESULT __stdcall raw_TranslateID_2 ( /*[in]*/ struct ID_TRANS_CTX xTransCtx, /*[in]*/ SAFEARRAY * astrInputIdNames, /*[in,out]*/ SAFEARRAY * * rastrOrigIdNames, /*[in,out]*/ SAFEARRAY * * rastrTranslatedIdNames, /*[out,retval]*/ long * pRetVal ) = 0; virtual HRESULT __stdcall raw_TranslateToAsset ( /*[in]*/ struct ID_TRANS_CTX xTransCtx, /*[in]*/ BSTR strIdNameToTranslate, /*[in,out]*/ long * riTranslatedIdKey, /*[out,retval]*/ long * pRetVal ) = 0; virtual HRESULT __stdcall raw_TranslateToAsset_2 ( /*[in]*/ struct ID_TRANS_CTX xTransCtx, /*[in]*/ SAFEARRAY * astrInputIdNames, /*[in,out]*/ SAFEARRAY * * rastrOrigIdNames, /*[in,out]*/ SAFEARRAY * * raiTranslatedIdKeys, /*[out,retval]*/ long * pRetVal ) = 0; virtual HRESULT __stdcall raw_TranslateFromAsset ( /*[in]*/ struct ID_TRANS_CTX xTransCtx, /*[in]*/ long iIdKeyToTranslate, /*[in,out]*/ BSTR * rstrTranslatedIdName, /*[out,retval]*/ long * pRetVal ) = 0; virtual HRESULT __stdcall raw_TranslateFromAsset_2 ( /*[in]*/ struct ID_TRANS_CTX xTransCtx, /*[in]*/ SAFEARRAY * aiInputIdKeys, /*[in,out]*/ SAFEARRAY * * riOrigIdKeys, /*[in,out]*/ SAFEARRAY * * rastrTranslatedIdNames, /*[out,retval]*/ long * pRetVal ) = 0; virtual HRESULT __stdcall raw_TranslateFromSubCell ( /*[in]*/ struct ID_TRANS_CTX xTransCtx, /*[in]*/ long iCellKey, /*[in]*/ long iLayerKey, /*[in,out]*/ BSTR * rstrTranslatedIdName, /*[out,retval]*/ long * pRetVal ) = 0; virtual HRESULT __stdcall raw_TranslateFromSubCell_2 ( /*[in]*/ struct ID_TRANS_CTX xTransCtx, /*[in]*/ SAFEARRAY * aiInputCellKeys, /*[in]*/ SAFEARRAY * aiInputLayerKeys, /*[in,out]*/ SAFEARRAY * * raiOrigCellKeys, /*[in,out]*/ SAFEARRAY * * raiOrigLayerKeys, /*[in,out]*/ SAFEARRAY * * rastrTranslatedIdNames, /*[out,retval]*/ long * pRetVal ) = 0; };
struct
__declspec(uuid("30734794-6d17-4983-b864-0e5a6552da4e")) CTranslateID;
// interface _Object // [ default ] interface ITranslateID //
// Named GUID constants initializations
//
extern
"C" const GUID __declspec(selectany) LIBID_translation_API = {0xe6d0059d,0x00fe,0x34a0,{0x8f,0x7f,0xf5,0xc0,0x91,0xcf,0xad,0xaa}};
extern
"C" const GUID __declspec(selectany) IID_ITranslateID = {0x27aa8457,0xb0ec,0x40df,{0xaf,0xef,0x7a,0x86,0x8b,0xf8,0xe8,0x67}};
extern
"C" const GUID __declspec(selectany) CLSID_CTranslateID = {0x30734794,0x6d17,0x4983,{0xb8,0x64,0x0e,0x5a,0x65,0x52,0xda,0x4e}};
//
// Wrapper method implementations
//
#include
"c:\development\enterprise_5.1\product integration\idtranslation\translation api\c# translation api\mfc_translate\debug\translation api.tli" #pragma
pack(pop)
In addition I enclose the MFC procedure that I am using to call this void
CMFC_TRANSLATEDlg:
nBnClickedOk() {
IUnknown* Unk = NULL;
ITranslateID* tt = NULL;
HRESULT hr;
SAFEARRAYBOUND rgsaBound[1];
rgsaBound[0].lLbound = 0;
rgsaBound[0].cElements = 1;
/*SAFEARRAYBOUND rgsaBound2[1];
rgsaBound2[0].lLbound = 0;
rgsaBound2[0].cElements = 4;*/
long bound[] = {0,0,0}; // IListPtr u(__uuidof(IList));
hr = CoInitialize(NULL);
hr = CoCreateInstance( CLSID_CTranslateID , NULL , CLSCTX_INPROC_SERVER , IID_IUnknown ,(
void**) &Unk ); ID_TRANS_CTX z = { 3, 4, 3060 , 0 , 20, 10 };
SAFEARRAY* pSA;
SAFEARRAY* pSB = NULL;;
SAFEARRAY* pSC = NULL;
pSA = SafeArrayCreate( VT_VARIANT , 1 , rgsaBound );
_bstr_t Y = "D_SBA";
_bstr_t X = " ";
BSTR YY = Y.GetBSTR();
BSTR XX = X.GetBSTR();
hr = SafeArrayPutElement( pSA , &bound[0] , YY );
pSB = SafeArrayCreate( VT_BSTR , 1 , rgsaBound);
pSC = SafeArrayCreate( VT_BSTR , 1 , rgsaBound );
hr = Unk->QueryInterface( IID_ITranslateID , (
void**) &tt ); hr = tt->TranslateID_2( z , pSA , &pSB , &pSC );
SafeArrayGetElement( pSC , &bound[2] , XX);
// spTranslate.CoCreateInstance( IID_CTRANSLATEID );
// spTranslate->TranslateID( z , "D_EA" , pX);;
OnOK();
}
Regards
Rob
Hi Robert,
This call seems wrong to me:
SafeArrayGetElement( pSC , &bound[2] , XX);
1) you must pass a BSTR reference to be filled:
SafeArrayGetElement( pSC , &bound[2] , (void*)&XX);
2) the third parameter of SafeArrayGetElement is an out param. So you would leak if you passed in a ref which is then overriden by the callee. Use SysFreeString(XX) before the call to SafeArrayGetElement.
3) You are leaking almost everything - might be just for the sample 
- the safearrays are not freed
- Unk and tt are not released
- XX and YY are not freed.
- CoInitialize is called but not CoUninitialize (you should not have to call this anyways in the middle of an MFC app. Normally this is done by the MFC initialization code.)
BUT another problem is: the .Net class interface seems to miss some marshal attributes to set up proper safearray handling: in arrays should be SAFEARRAY not SAFEARRAY* and out should be SAFEARRAY* not SAFEARRAY**. So basically for out arrays you will just write:
SAFEARRAY out1, out2;
tt->Translate2(a, b, &out1, &out2);
See that out1 and out2 are never initialized by the caller. They are out params filled by the callee.
HERE comes the last little caveat: OLE automation does not allow [out] params. You must use [in, out]. Which brings us back to having to initialize the SAFEARRAYs again before passing them as in/out params.
Search the MSDN for this topic "Default Marshaling for Arrays". This gives you the details for how to attribute the .Net class methods which you want to expose for COM clients.
HTH,
SvenC