Solved

How to pass vector in a com method

Posted on 2006-11-29
7
1,153 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
Revamp Your Training Process

Drastically shorten your training time with WalkMe's advanced online training solution that Guides your trainees to action.

 
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

Industry Leaders: 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…
Jaspersoft Studio is a plugin for Eclipse that lets you create reports from a datasource.  In this article, we'll go over creating a report from a default template and setting up a datasource that connects to your database.
This tutorial covers a step-by-step guide to install VisualVM launcher in eclipse.
The viewer will learn how to use NetBeans IDE 8.0 for Windows to connect to a MySQL database. Open Services Panel: Create a new connection using New Connection Wizard: Create a test database called eetutorial: Create a new test tabel called ee…

751 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