Tuesday, February 05, 2008

Returning a byte array from C++ to Visual Basic 6

I had to figure out how to return a byte array from a C++ DLL to VB6 (using unmanaged C++ in Visual Studio 2005).

This is the general idea:

__declspec(dllexport) int __stdcall modifyArrayTest(SAFEARRAY** fileData)
{
 HRESULT hr;
 SAFEARRAYBOUND bound[1];
 if (*fileData != NULL)
 {
  TCHAR msg[128];
  _stprintf(msg, "Received %lu byte array, destroying it and reallocating", (*fileData)->rgsabound[0].cElements);
  OutputDebugString(msg);
  SafeArrayDestroy(*fileData);
 }
 else
 {
  OutputDebugString("Received null array, reallocating");
 }
 bound[0].cElements = 10; // 10 byte array
 bound[0].lLbound = 0;
 *fileData = SafeArrayCreate(VT_UI1, 1, bound);
 hr = SafeArrayLock(*fileData);
 if (hr)
 {
  OutputDebugString("SafeArrayLock failed");
  return -1;
 }
 unsigned char *data = (unsigned char*)(*fileData)->pvData;
 for (int n = 0; n < 10; n++)
 {
  data[n] = n;
 }
 SafeArrayUnlock(*fileData);
 return 0;
}


Now the function is imported as follows in VB6:

Private Declare Function modifyArrayTest _
Lib "ArrayTest.dll" (ByRef a() As Byte) As Long


And used like this:

Dim data() as Byte
Dim returnedBytes as Long
Call modifyArrayTest(data)
returnedBytes = UBound(data) + 1


Notes:
  • I found it useful to use OutputDebugString to log debug messages in my DLL code and then using DebugView from SysInternals to view the messages.
  • I noticed the DLL has to be compiled using ANSI (i.e. Character Set = Not Set) instead of Unicode (the default) to be able to pass strings back to VB6.
Reference: VB5DLL.TXT
Post a Comment