Solved

How to pass vector in a com method

Posted on 2006-11-29
7
1,133 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
Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

 
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

Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
My project did see openJDK that I installed. What could be the problem 7 151
How can my static class become undefined?? 8 62
Outlook 13 41
SSRS Deployment problem 5 65
Introduction This article is a continuation of the C/C++ Visual Studio Express debugger series. Part 1 provided a quick start guide in using the debugger. Part 2 focused on additional topics in breakpoints. As your assignments become a little more …
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
This tutorial covers a step-by-step guide to install VisualVM launcher in eclipse.
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.

856 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