Link to home
Start Free TrialLog in
Avatar of wayside
wayside

asked on

How do you pass an array to a COM object using interop?

I need to extend an existing COM object to add a function that takes as input an array of bytes, which is readonly. I haven't done COM in a while and I don't remember the gory details so hopefully someone here can help me fill in the blanks.

The interface definition looks something like this:

[object, dual, uuid("12345678-1234-1234-1234-123456789ABC") ]
__interface IMyFoo {
  [id(1), helpstring("method foo1")] HRESULT foo1([in] BSTR str, [out,retval] BSTR* result);
  [id(2), helpstring("method foo2")] HRESULT foo2([in] BYTE buf[], [in] LONG numBytes, [out,retval] BSTR* result);  // <-- #1 below
};

[ coclass, uuid("87654321-4321-4321-4321-CBA987654321"), default(IMyFoo) ]
class CMyFoo : public IMyFoo
{
public:
  CMyFoo(void);
  ~CMyFoo void);
  STDMETHOD(foo1)(BSTR str, LONG* result);
  STDMETHOD(foo2)(BYTE []buf, LONG numBytes, BSTR* result);  // <--#1 below
};

The implementation of foo2 is conceptually something like:

STDMETHODIMP CMyFoo::foo2(BYTE []buf, LONG numBytes, BSTR* result)
{

  int sum = 0;
  for (int i=0; i<numBytes; i++) {
     // process buf here
     sum +=  buf[i]; // <--- #2 below
  }
 
  char outstr[50];
  sprintf(outstr, "answer is %ld", sum);

  *result = ::SysAllocString((OLECHAR *) outstr);

  return S_OK;
}

From the C# side, I want to do something like:

byte[] buf = new byte[1234];
// buf gets data in it, not important how

mycom.CMyFooClass myfoo = new mycomCMyFooClass();
string sum= myfoo.foo2(buf, buf.length);  // <--- #3 below

I've already got everything working to call the foo1() function in C#, but I need help with

#1) setting up the interface to be able to pass an array of bytes in foo2()
#2) accessing that array within the COM object function foo2() - don't need to modify it, just access it
#3) how do I call foo2() from the C# side to pass the array

Thanks!
ASKER CERTIFIED SOLUTION
Avatar of gbzhhu
gbzhhu
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of wayside
wayside

ASKER

gbzhhu,

That article isn't very helpful.

This article is much more helpful, it shows actual sample code:

http://www.codeguru.com/Cpp/COM-Tech/activex/misc/article.php/c2577/

So I set up my code like this, and it works great. If you see any issues please let me know.


[object, dual, uuid("12345678-1234-1234-1234-123456789ABC") ]
__interface IMyFoo {
  [id(1), helpstring("method foo1")] HRESULT foo1([in] BSTR str, [out,retval] BSTR* result);
  [id(2), helpstring("method foo2")] HRESULT foo2([in] VARIANT buf, [in] LONG numBytes, [out,retval] BSTR* result);
};

[ coclass, uuid("87654321-4321-4321-4321-CBA987654321"), default(IMyFoo) ]
class CMyFoo : public IMyFoo
{
public:
  CMyFoo(void);
  ~CMyFoo void);
  STDMETHOD(foo1)(BSTR str, LONG* result);
  STDMETHOD(foo2)(VARIANT buf, LONG numBytes, BSTR* result);
};

STDMETHODIMP CMyFoo::foo2(VARIANT buf, LONG numBytes, BSTR* result)
{
  void *pData;
  if (buf.vt == (VT_ARRAY | VT_UI1)) {
    SafeArrayAccessData(buf.parray, &pData); // Get the data
    SafeArrayUnaccessData(buf.parray);           // Unaccess it.
  }
  else
    return S_FALSE;

  unsigned char pUChar = (unsigned char *)pData;
  int sum = 0;
  for (int i=0; i<numBytes; i++) {
     // process buf here
     sum +=  pUChar [i];
  }
 
  char outstr[50];
  sprintf(outstr, "answer is %ld", sum);

  *result = ::SysAllocString((OLECHAR *) outstr);

  return S_OK;
}

From the C# side:

byte[] buf = new byte[1234];
// buf gets data in it, not important how

mycom.CMyFooClass myfoo = new mycomCMyFooClass();
string sum= myfoo.foo2(buf, buf.Length);

I am glad it is working for you.  The article I pointed out suggested using safesarrays and variants rather than byte array.  The other article does the same but gave example code which I agree is better
Avatar of wayside

ASKER

Sorry, I should have closed this before.