Retreiving string values from a C++ COM

I am writing a COM component in C++ for use with ASP.  
I want to know how to make a COM method that can pass out one or more string values.

For example:
<%MyObject.GetStrings String1Out, String2Out %>

and in C++, the related function might be something like:

STDMETHODIMP CMyObject::GetStrings(BSTR * pbstr1, BSTR * pbstr2)

Is there a way to do this?  I already know about fetching values one by one, using a property.  But is there something that one can specify in the IDL file that will tell ASP to send a variable by reference instead of by value?
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

First, BSTR is a POINTER by definition so BSTR * is a pointer to a pointer.  I.e. it's passed by reference which is what you want.

To return a string reference in pbstr2, do this:

*pbstr2 = ::SysAllocString(L"String to return");

Don't forget to call ::SysFreeString() on the pointer somewhere along the way or you'll leak memory.

If you aren't wanting to return a static string, (L"String to return") then build one.  ::SysAllocString() takes an OLECHAR as input.  If you are using MFC, you may find the A2OLE macro useful (see afxpriv.h) or you may want to use the CString::AllocSysString member function.
mcglincheyAuthor Commented:
The problem is not assigning a value to the BSTR (or to the BSTR *) but rather getting ASP to call the function properly, passing its BSTR by reference.  

If the caller of the COM function is C++, where we can control the type of our parameters, then clearly there's no problem.  But if the caller is ASP, there's no such thing as a pointer, and the default behaviour for BSTRs seems to be to pass them in by value.  

This is maybe best considered an ASP question, and I have cross-posted this to that group too.  But I suspect the answer may lie in the appropriate tags in the C++ IDL file.

Of course the answer is in the IDL.

How do you think ASP knows about the types of parameters passed to and returned from a component?

I assumed you knew what the correct IDL is since you didn't post any.  You cannot, however, pass a BSTR by value, it must be by reference.  The only things that can be passed by value are those data types that fit in the VARIANT struct.  Like I said earlier, a BSTR is a "by ref" by definition.  So your only choices are really "string pointer" by value (BSTR/pointer) or "string pointer" by reference (BSTR */pointer to pointer)

Remember, ASP uses the COM Automation (i.e. IDispatch) to learn about the properties/methods and to call them on the object's interface.  C++ programs have the advantage of the vtbl interface and header file to know about data types at compile time.  ASP must determine these at RUN TIME.

Here's an example of IDL for a COM object method that returns a BSTR to the caller.

[id(7), helpstring("method GetParameterName")] HRESULT GetParameterName([in] long index, [out, retval] BSTR *pbstrParamName);

I have made such COM objects in
MFC and it worked. I had worked with
MFC COM DLL. But you can work both with ATL as well as Win32 COM Dll.

// CapsStr1 is Also a Test Function
// This function takes a BSTR and returns a BSTR
BSTR COne::CapsStr1(LPCSTR str)
      CString strResult1( str );
      cout << "\n From CapsStr1 = " << (LPCSTR) strResult1;
      return strResult1.AllocSysString();
      // TODO: Add your dispatch handler code here

To Call this function from ASP ..
Set x = Server.CreateObject("one.dll")
Set y = x.CapsStr1("Hello")
' Now y will contain the HELLO

For Func which take 2 argument use simply
void f( LPCSTR a , LPCSTR b);

However this method will not work other kind of DLL e.g. ATL and Win32. The argment type is actually modified by MFC.


Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
mcglincheyAuthor Commented:
jhance, thanks for your comments, but the real thrust of my question was to know if I could get out more than one value at a time.  Yes, I know about IDLs, and about the [out, retval] tags.  But you can only have one retval per method, and I want to retrieve multiple strings.

What's more, a BSTR is indeed already a pointer (to an array of shorts) but you can't actually modify it unless your parameter is a pointer to such a pointer: unless you are going to just overwrite the original's memory with a string the same size or less, you've got to have a BSTR * (as you show in your example with a retval).  

I will give the points to basant for being most helpful (although in fact my COM is with ATL rather than MFC, but I didn't mention that anywhere).

For the record, the solution that finally works well is to use a VARIANT *.  ASP is able to convert that to a VARIANT * implicitly.

STDMETHODIMP CMyObject::ReadAttribute(BSTR bstrAttrName, VARIANT *pvarAttrValue)
            // Create a new BSTR to hold the value retrieved from GetAttributeFirstValue
      BSTR BSTRNewValue;

      HRESULT hr;
      hr = pSubObj->GetValue(attrName, &BSTRNewValue);

// Convert the BSTR to a _bstr_t because that's what _variant_t takes in its constructor
  _bstr_t bstrNewValue(BSTRNewValue);

// Now wrap up the BSTR in a variant, so we can pass it out.
  _variant_t varNewValue(bstrNewValue)

// Take the new VARIANT object out of its _variant_t wrapper, set it to the outgoing VARIANT *
      *pvarAttrValue = varNewValue.Detach();

      return S_OK;

It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Microsoft Development

From novice to tech pro — start learning today.