Error using array of structs from a COM-Dll

M

Michael

Hi all,

I've written a COM-Dll (with ATL) that holds a database of marathon
runners. I wrote a function that returns the needed information of all
runners and it works fine in VB but not in VB.NET. I'm using an array
of structs as a return value. Here's the code of the function:

*************************************************

const IID ResultUDT_IID = {... };

STDMETHODIMP CDatabase::ResultAll(SAFEARRAY **pResult)
{
t_Result *Results = NULL;
ResultUDT *pData = NULL;

if (!m_bResult)
{
HRESULT hr = Error( _T("No result available!") );
return hr;
}

IRecordInfo *pUdtRecordInfo = NULL;
HRESULT hr = ::GetRecordInfoFromGuids(LIBID_SOFTLib, 1, 0, 0,
ResultUDT_IID, &pUdtRecordInfo );
if (FAILED(hr))
{
HRESULT hr2 = Error( _T("Can not create RecordInfo interface
for ResultUDT") );
return hr;
}

int RecordsCnt = MyDB->Cnt();
Results = My->Result;

SAFEARRAYBOUND rgsabound[1];
rgsabound[0].lLbound = 0;
rgsabound[0].cElements = RecordsCnt ;

*pResult = ::SafeArrayCreateEx( VT_RECORD, 1, rgsabound,
pUdtRecordInfo );
pUdtRecordInfo->Release();
if (*pResult == NULL)
{
HRESULT hr2 = Error( _T("Can not create array of ResultUDT
structures") );
return hr2;
}

hr = ::SafeArrayAccessData(*pResult, (void**)&pData);
if (FAILED(hr))
return( hr );

for (int i=0; i<RecordsCnt; i++, pData++)
{
pData->Pnr = Results.pnr;
pData->Score = Results.Score;
CComBSTR bstrID = MyDB->PersonInfo[Results.tnr].ID;
bstrID.CopyTo(&pData->ID);
CComBSTR bstrFilepath = Results.Filepath;
bstrFilepath.CopyTo(&pData->Filepath);
}

hr = ::SafeArrayUnaccessData(*pResult);
return hr;
}

*************************************************

In the idl.-File I defined my struct as:

*************************************************

typedef
[uuid(...),
helpstring("Result Structure")]
struct ResultUDT
{
int Pnr;
int Score;
BSTR ID;
BSTR Filepath;
} ResultUDT;

*************************************************

and my interface looks like that:

*************************************************

interface INet : IDispatch
{
[id(1), helpstring("Result")]
HRESULT Result([out, retval] SAFEARRAY(struct ResultUDT)
*pResult);
}

*************************************************

In VB I can use that function and it works fine:

*************************************************

Dim res() as ResultUDT

....

res = DB.Result(5)

txtName.text = res(0).ID

*************************************************

In VB.NET I have written the following code (which somehow needs the
lib-name SOFTLib in front of the struct):

*************************************************

Dim res() as SOFTLib.ResultUDT

....

res = DB.Result(5)

txtName.text = res(0).ID

*************************************************

and that always brings up "System.IndexOutOfRangeException" because my
array "res" has the length 0.

Any ideas to this problem?

Thanks
Michael
 
T

Tom Shelton

Hi all,

I've written a COM-Dll (with ATL) that holds a database of marathon
runners. I wrote a function that returns the needed information of all
runners and it works fine in VB but not in VB.NET. I'm using an array
of structs as a return value. Here's the code of the function:

*************************************************

const IID ResultUDT_IID = {... };

STDMETHODIMP CDatabase::ResultAll(SAFEARRAY **pResult)
{
t_Result *Results = NULL;
ResultUDT *pData = NULL;

if (!m_bResult)
{
HRESULT hr = Error( _T("No result available!") );
return hr;
}

IRecordInfo *pUdtRecordInfo = NULL;
HRESULT hr = ::GetRecordInfoFromGuids(LIBID_SOFTLib, 1, 0, 0,
ResultUDT_IID, &pUdtRecordInfo );
if (FAILED(hr))
{
HRESULT hr2 = Error( _T("Can not create RecordInfo interface
for ResultUDT") );
return hr;
}

int RecordsCnt = MyDB->Cnt();
Results = My->Result;

SAFEARRAYBOUND rgsabound[1];
rgsabound[0].lLbound = 0;
rgsabound[0].cElements = RecordsCnt ;

*pResult = ::SafeArrayCreateEx( VT_RECORD, 1, rgsabound,
pUdtRecordInfo );
pUdtRecordInfo->Release();
if (*pResult == NULL)
{
HRESULT hr2 = Error( _T("Can not create array of ResultUDT
structures") );
return hr2;
}

hr = ::SafeArrayAccessData(*pResult, (void**)&pData);
if (FAILED(hr))
return( hr );

for (int i=0; i<RecordsCnt; i++, pData++)
{
pData->Pnr = Results.pnr;
pData->Score = Results.Score;
CComBSTR bstrID = MyDB->PersonInfo[Results.tnr].ID;
bstrID.CopyTo(&pData->ID);
CComBSTR bstrFilepath = Results.Filepath;
bstrFilepath.CopyTo(&pData->Filepath);
}

hr = ::SafeArrayUnaccessData(*pResult);
return hr;
}

*************************************************

In the idl.-File I defined my struct as:

*************************************************

typedef
[uuid(...),
helpstring("Result Structure")]
struct ResultUDT
{
int Pnr;
int Score;
BSTR ID;
BSTR Filepath;
} ResultUDT;

*************************************************

and my interface looks like that:

*************************************************

interface INet : IDispatch
{
[id(1), helpstring("Result")]
HRESULT Result([out, retval] SAFEARRAY(struct ResultUDT)
*pResult);
}

*************************************************

In VB I can use that function and it works fine:

*************************************************

Dim res() as ResultUDT

...

res = DB.Result(5)

txtName.text = res(0).ID

*************************************************

In VB.NET I have written the following code (which somehow needs the
lib-name SOFTLib in front of the struct):

*************************************************

Dim res() as SOFTLib.ResultUDT

...

res = DB.Result(5)

txtName.text = res(0).ID

*************************************************

and that always brings up "System.IndexOutOfRangeException" because my
array "res" has the length 0.

Any ideas to this problem?

Thanks
Michael


You might want to post this to the interop group. You might get a
better answer there.
 

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