Article ID: 171583
Article Last Modified on 1/20/2007
Type Alignment Size Byte 1 byte 1 byte String * n 1 byte 2 bytes per UNICODE character Integer 2 bytes 2 bytes Boolean 2 bytes 2 bytes String 4 bytes 4 byte pointer - UNICODE data not in structure Long 4 bytes 4 bytes Single 4 bytes 4 bytes Double 4 bytes 8 bytes Currency 4 bytes 8 bytes Date 4 bytes 8 bytes Variant 4 bytes 16 bytes - may point to data not in structure Object 4 bytes 4 byte pointer - object not in structureVisual Basic passes arrays as the OLE SAFEARRAY type. This type contains a header structure that contains the following information:
unsigned short cDims; // Count of dimensions unsigned short fFeatures; // Flags unsigned long cbElements; // Size of an element of the array unsigned long cLocks; // Lock count void HUGEP* pvData; // Pointer to the data SAFEARRAYBOUND rgsabound[n]; // One bound for each dimensionThe SAFEARRAYBOUND type contains the following elements:
unsigned long cElements; // Number of elements in this dimension long lLbound; // Lower boundThe Visual C++ code can read the SAFEARRAY structure and get a pointer to the data (pvData), which contains contiguous data items, and read the SAFEARRAYBOUND structure to determine the number of elements passed.
LIBRARY TestType
EXPORTS
FillUDTSafeArray
FillUDTVariable
#include <windows.h>
#include <ole2.h>
#pragma pack(1)
typedef struct
{
short f1;
short filler_1;
long f2;
BYTE f3;
WCHAR f4;
BYTE filler_2;
float f5;
} MyStruct;
void _stdcall FillUDTVariable(MyStruct * ms)
{
ms->f1 = 2001;
ms->f2 = 20012001;
ms->f3 = 255;
ms->f4 = L'A';
ms->f5 = 200.1f;
}
void _stdcall FillUDTSafeArray(LPSAFEARRAY FAR * ppsa)
{
MyStruct * pdata;
unsigned int i;
pdata = (MyStruct*)((*ppsa)->pvData);
for (i=0;i<((*ppsa)->rgsabound->cElements);i++,pdata++)
FillUDTVariable(pdata);
}
Option Explicit
Type My_VarUDT
F1 As Integer
F2 As Long
F3 As Byte
F4(0 To 1) As Byte ' to avoid UNICODE/ANSI conversion
F5 As Single
End Type
Type My_ArrayUDT
F1 As Integer
F2 As Long
F3 As Byte
F4 As String * 1
F5 As Single
End Type
Declare Sub FillUDTVariable Lib "TestType.DLL" (A As My_VarUDT)
Declare Sub FillUDTSafeArray Lib "TestType.DLL" (A() As My_ArrayUDT)
Sub Test()
Dim A As Long, B As My_VarUDT, C As String, D(3) As My_ArrayUDT
Debug.Print "---Variable of My_VarUDT-------"
FillUDTVariable B
With B
C = .F4
Debug.Print .F1, .F2, .F3, C; "("; .F4(0); .F4(1); ")", .F5
End With
Debug.Print "---Safe array of My_ArrayUDT-------"
FillUDTSafeArray D()
For A = 0 To 3
With D(A)
Debug.Print .F1, .F2, .F3, .F4; "("; AscB(MidB(.F4, 1, 1));
Debug.Print AscB(MidB(.F4, 2, 1)); ")", .F5
End With
Next A
End Sub
---Variable of My_VarUDT-------
2001 20012001 255 A( 65 0 ) 200.1
---Safe array of My_ArrayUDT-------
2001 20012001 255 A( 65 0 ) 200.1
2001 20012001 255 A( 65 0 ) 200.1
2001 20012001 255 A( 65 0 ) 200.1
2001 20012001 255 A( 65 0 ) 200.1
NOTE: The My_VarUDT example is included to illustrate avoiding the
normal UNICODE/ANSI conversion that happens when calling a DLL and passing a
single variable. This conversion does not happen when passing the entire array,
so can use STRING * 1 in the My_ArrayUDT as opposed to passing a byte
array.Keywords: kbhowto kbinterop KB171583