Solved

How to pass vector in a com method

Posted on 2006-11-29
7
1,173 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
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
[Live Webinar] The Cloud Skills Gap

As Cloud technologies come of age, business leaders grapple with the impact it has on their team's skills and the gap associated with the use of a cloud platform.

Join experts from 451 Research and Concerto Cloud Services on July 27th where we will examine fact and fiction.

 
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

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

Article by: SunnyDark
This article's goal is to present you with an easy to use XML wrapper for C++ and also present some interesting techniques that you might use with MS C++. The reason I built this class is to ease the pain of using XML files with C++, since there is…
With most software applications trying to cater to multiple user needs nowadays, the focus is to make them as configurable as possible. For e.g., when creating Silverlight applications which will connect to WCF services, the service end point usuall…
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.

617 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