Take these three methods that each build distinct std::list
objects from safe arrays:
void CMSATools::ConvertSAFEARRAY_DISCUSSIONITEMS(SAFEARRAY* psaDiscussionItems, ListDiscussionItems& rListDiscussionItems)
{
MSAToolsLibrary::IDiscussionItemPtr* pVals = nullptr;
HRESULT hr = SafeArrayAccessData(psaDiscussionItems, (void**)&pVals); // direct access to SA memory
if (SUCCEEDED(hr))
{
long lowerBound, upperBound; // get array bounds
hr = SafeArrayGetLBound(psaDiscussionItems, 1, &lowerBound);
if (FAILED(hr))
throw _com_error(hr);
hr = SafeArrayGetUBound(psaDiscussionItems, 1, &upperBound);
if (FAILED(hr))
throw _com_error(hr);
rListDiscussionItems.clear();
long cnt_elements = upperBound - lowerBound + 1;
for (int i = 0; i < cnt_elements; ++i) // iterate through returned values
{
rListDiscussionItems.push_back(pVals[i]);
}
hr = SafeArrayUnaccessData(psaDiscussionItems);
if (FAILED(hr))
throw _com_error(hr);
}
else
{
throw _com_error(hr);
}
hr = SafeArrayDestroy(psaDiscussionItems);
if (FAILED(hr))
throw _com_error(hr);
}
void CMSATools::ConvertSAFEARRAY_STUDENTITEMS(SAFEARRAY* psaStudentItems, ListStudentItems& rListStudentItems)
{
MSAToolsLibrary::IStudentItemPtr *pVals = nullptr;
HRESULT hr = SafeArrayAccessData(psaStudentItems, (void**)&pVals); // direct access to SA memory
if (SUCCEEDED(hr))
{
long lowerBound, upperBound; // get array bounds
hr = SafeArrayGetLBound(psaStudentItems, 1, &lowerBound);
if (FAILED(hr))
throw _com_error(hr);
hr = SafeArrayGetUBound(psaStudentItems, 1, &upperBound);
if (FAILED(hr))
throw _com_error(hr);
rListStudentItems.clear();
long cnt_elements = upperBound - lowerBound + 1;
for (int i = 0; i < cnt_elements; ++i) // iterate through returned values
{
rListStudentItems.push_back(pVals[i]);
}
hr = SafeArrayUnaccessData(psaStudentItems);
if (FAILED(hr))
throw _com_error(hr);
}
else
{
throw _com_error(hr);
}
hr = SafeArrayDestroy(psaStudentItems);
if (FAILED(hr))
throw _com_error(hr);
}
void CMSATools::ConvertSAFEARRAY_DUTYHISTORYITEMS(SAFEARRAY* psaHistoryItems, ListDutyHistoryLookupItems& rListHistoryItems)
{
MSAToolsLibrary::IDutyAssignmentLookupPtr *pVals = nullptr;
HRESULT hr = SafeArrayAccessData(psaHistoryItems, (void**)&pVals); // direct access to SA memory
if (SUCCEEDED(hr))
{
long lowerBound, upperBound; // get array bounds
hr = SafeArrayGetLBound(psaHistoryItems, 1, &lowerBound);
if (FAILED(hr))
throw _com_error(hr);
hr = SafeArrayGetUBound(psaHistoryItems, 1, &upperBound);
if (FAILED(hr))
throw _com_error(hr);
rListHistoryItems.clear();
long cnt_elements = upperBound - lowerBound + 1;
for (int i = 0; i < cnt_elements; ++i) // iterate through returned values
{
rListHistoryItems.push_back(pVals[i]);
}
hr = SafeArrayUnaccessData(psaHistoryItems);
if (FAILED(hr))
throw _com_error(hr);
}
else
{
throw _com_error(hr);
}
hr = SafeArrayDestroy(psaHistoryItems);
if (FAILED(hr))
throw _com_error(hr);
}
They all work and are functional. But they have a lot of common aspects. It is possible to use "templates" here? It is not something I have done before.
I don't mind having three distinct methods but if they could perhaps call one common templated method that converts the safe array it would make the code maintenance easier.
Make sense?
Try this (didn't compile it):
template<typename from, typename to>
void CMSATools::ConvertSAFEARRAY_DUTYHISTORYITEMS(SAFEARRAY* psaItems, to& rItems)
{
from *pVals = nullptr;
HRESULT hr = SafeArrayAccessData(psaItems, (void**)&pVals); // direct access to SA memory
if (SUCCEEDED(hr))
{
long lowerBound, upperBound; // get array bounds
hr = SafeArrayGetLBound(psaItems, 1, &lowerBound);
if (FAILED(hr))
throw _com_error(hr);
hr = SafeArrayGetUBound(psaItems, 1, &upperBound);
if (FAILED(hr))
throw _com_error(hr);
rItems.clear();
long cnt_elements = upperBound - lowerBound + 1;
for (int i = 0; i < cnt_elements; ++i) // iterate through returned values
{
rItems.push_back(pVals[i]);
}
hr = SafeArrayUnaccessData(psaItems);
if (FAILED(hr))
throw _com_error(hr);
}
else
{
throw _com_error(hr);
}
hr = SafeArrayDestroy(psaItems);
if (FAILED(hr))
throw _com_error(hr);
}