Solved

How to pass vector in a com method

Posted on 2006-11-29
7
1,123 Views
Last Modified: 2013-12-14
Hi Experts,

             I want to pass STL vector container in one of my com method. I also want to return that vector to my C++ client.

Thanks in advance
0
Comment
Question by:HanuSoftware
7 Comments
 
LVL 8

Expert Comment

by:mrblue
ID: 18036083
You can use:

1. VARIANT type (array of elements) - automation compliant version that can be used from script languages like VB or JS

Funct([out] VARIANT *pArray)

or

2.  If you mark your custom (inheriting from IUnknown) interface as 'local' (marshalling will never be used) you can simply pass pointer to array or pointer to pointer to array

Funct([out] double *pdblArray)

Funct([out] double **pdblArray)
{
  // allocate memory
  *pdblArray = CoTaskMemAlloc(...);
}

In this case it works exactly like regular C/C++ function but cannot be called from script languages and cannot be called from another process or another machine (marshalling).

0
 
LVL 8

Accepted Solution

by:
mrblue earned 500 total points
ID: 18036137
In case 1) you can use SafeArrayCreateVector(), SafeArrayAccessData() & SafeArrayUnaccessData()

for example:

VARIANT vData;
double *pdblArray;

vData.parray = SafeArrayCreateVector(VT_R8,  0,   100);        // 100 element array of doubles

if(vData.parray != NULL) {
  vData.vt = VT_R8 | VT_ARRAY;

  SafeArrayAccessData(vData.parray,   (void **)&pdblArray);
  pdblArray[0] = 1.0;
  // ...
  SafeArrayUnaccessData(vData.parray);
};

0
 

Author Comment

by:HanuSoftware
ID: 18036928
I want to pass a vector that can be used by both vb as well as MFC. The vector passed will return strings.
0
PRTG Network Monitor: Intuitive Network Monitoring

Network Monitoring is essential to ensure that computer systems and network devices are running. Use PRTG to monitor LANs, servers, websites, applications and devices, bandwidth, virtual environments, remote systems, IoT, and many more. PRTG is easy to set up & use.

 
LVL 22

Expert Comment

by:ambience
ID: 18037188
We need more information

- Is your COM object INPROC, i.e. in a dll?

- Are you using a custom interface, i.e. calling through Ixxx (Where Ixxx is not IDispatch)?

- Are you using ATL for the COM dll?

The short answer to your question is that you cannot pass STL vectors and for that matter any STL container in a COM method. The long answer is also a no but there are ways to help do what you intend to do, but that really depends upon the answers to these questions.
0
 
LVL 22

Expert Comment

by:ambience
ID: 18037219
>> I also want to return that vector to my C++ client.
>> I want to pass a vector that can be used by both vb as well as MFC.

Looks like a change of plans to me :)

In that case use SAFEARRAY as explained by mrblue. Ofcourse that means extra work!
0
 
LVL 8

Expert Comment

by:mrblue
ID: 18037493
> I want to pass a vector that can be used by both vb as well as MFC. The vector passed will return strings.

Derive your inteface from IDispatch (automation) & use VARIANT array (possibly array of VARIANTs)

VARIANT vData;
VARIANT *pvArray;

vData.parray = SafeArrayCreateVector(VT_VARIANT,  0,   100);        // 100 element array of VARIANT

if(vData.parray != NULL) {
  vData.vt = VT_VARIANT| VT_ARRAY;

  SafeArrayAccessData(vData.parray,   (void **)&pvArray);
  pvArray[0].vt = VT_R8;          // or type you need (VT_R4, VT_I2, VT_I4, ...)
  pvArray[0].dblVal = 1.0;         // or fltVal, iVal, lVal, ...
  // ...
  SafeArrayUnaccessData(vData.parray);
};
0
 
LVL 2

Expert Comment

by:asmyatt
ID: 18039067
Go to this site and give these steps a try. I did this to return a vector<string> back to my program. I tested it using a C# and C++ client and it worked fine.

http://msdn2.microsoft.com/en-us/library/3stwxh95(VS.80).aspx

After you setup you COM app as above, your client will have to have these things in it:
----------------------------------------------------------------------
#include "YourDllLib_i.c"


#import "YourDllLib.tlb"
using namespace YourDllLibLib;

// Outputs all the items in a collection using the Count and Item properties
template <class T>
HRESULT OutputLoopedItems(T sp)
{
      // Get the count of items
      long lCount = sp->GetCount();
      cout << "Rows Returned: " << lCount << endl << endl;
      // The collection indexes are 1-based
      /*for (long i = 1; i <= lCount; ++i)
      {
            _bstr_t bstrTemp = static_cast<_variant_t>(sp->GetItem(i));
            std::cout << static_cast<const char*>(bstrTemp) << "\n";
      }*/

      return S_OK;
}

// Outputs all the items in a collection using the enumerator
template <class T>
HRESULT OutputEnumeratedItems(T sp)
{
      // Get the VARIANT enumerator from the collection
      IEnumVARIANTPtr spEnum = sp->Get_NewEnum();

      // nBatchSize is the number of items that we request in each call to IEnumVARIANT::Next.
      // The actual number of items returned may not equal nBatchSize.
      const ULONG nBatchSize = 5;

      // nReturned will store the number of items returned by a call to IEnumVARIANT::Next
      ULONG nReturned = 0;

      // arrVariant is the array used to hold the returned items
      VARIANT arrVariant[nBatchSize] = {0};

      HRESULT hr = E_UNEXPECTED;
      do
      {
            hr = spEnum->Next(nBatchSize, &arrVariant[0], &nReturned);
            if (FAILED(hr))
                  return hr;

            for (ULONG i = 0; i < nReturned; ++i)
            {
                  _bstr_t bstrTemp = static_cast<_variant_t>(arrVariant[i]);
                  std::cout << static_cast<const char*>(bstrTemp) << "\n";
                  ::VariantClear(&arrVariant[i]);
            }

      } while (hr != S_FALSE); // S_FALSE indicates end of collection

      return hr;
}

int main(int argc, _TCHAR* argv[])
{
   try
  {
      IYourDllPtr spDLLFunction(__uuidof(YouFunctionName));
      spDLLFunction->YouFunctionName(...what ever parameters you have ...);
       
        //call this function to output the collection that was returned
      OutputLoopedItems(spDLLFunction);      
   }
   catch (const _com_error& Err)
   {
      std::cout << "Error: " << Err.ErrorMessage() << "\n";
   }
   catch (...)
  {
      std::cout << "Unexpected Error\n";
  }
}

Hope this helps.
0

Featured Post

NAS Cloud Backup Strategies

This article explains backup scenarios when using network storage. We review the so-called “3-2-1 strategy” and summarize the methods you can use to send NAS data to the cloud

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Templates For Beginners Or How To Encourage The Compiler To Work For You Introduction This tutorial is targeted at the reader who is, perhaps, familiar with the basics of C++ but would prefer a little slower introduction to the more ad…
A theme is a collection of property settings that allow you to define the look of pages and controls, and then apply the look consistently across pages in an application. Themes can be made up of a set of elements: skins, style sheets, images, and o…
The viewer will learn how to use and create keystrokes in Netbeans IDE 8.0 for Windows.
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

831 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question