Search code examples
templatesvisual-c++mfcsafearray

Can these methods that convert safe arrays into std::list objects be turned into a template function?


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?


Solution

  • 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);
    }