Как передать массив из DLL в VB
От: grinia74  
Дата: 05.01.04 07:53
Оценка:
Как передать массив из DLL в VB
Как продекларировать в VB функцию f1
long* f1(long *arr){
return arr;
}
Re: HOWTO: Как передать массив из DLL в VB
От: Vi2 Удмуртия http://www.adem.ru
Дата: 05.01.04 09:27
Оценка: 9 (2)
Здравствуйте, grinia74, Вы писали:

G>Как передать массив из DLL в VB

Существуют два способа сделать это: передать полностью массив или передать только данные массива. При сходстве результата, достигается это разными путями. Но в любом случае это работа с SAFEARRAY, т.к. в VB нет других массивов кроме SAFEARRAY.

Первый способ связан с возвратом SAFEARRAY, а именно с SAFEARRAY(long) в твоем случае. Также можно передать в функцию количество элементов будущего массива или другую подобную информацию.

Private Declare Function f1 Lib "f1.dll" Alias "_f1@0" () As Long()
...два варианта приема массива...
    Dim v As Variant, iArr() As Long
    v = f1()
    iArr = f1()


extern "C" __declspec(dllexport) SAFEARRAY* __stdcall f1()
{
    SAFEARRAYBOUND rgsabound;
    rgsabound.lLbound = 0;   // начиная с 0
    rgsabound.cElements = 3; // всего элементов

    SAFEARRAY * psa = ::SafeArrayCreate( VT_I4, 1, & rgsabound ); 

    long * psadata = NULL; 
    if( SUCCEEDED(::SafeArrayAccessData(psa, (void**)&psadata)) )
    {
        for(long i = 0; i < (long) rgsabound.cElements; i++)
            psadata[i] = i; // заполнение, в данном случае - тривиальное.

        ::SafeArrayUnaccessData(psa);
    }
    return psa;
}


Второй способ связан с изменением массива теми же средствами, с которыми сам VB работает с массивами.
Private Declare Function f1 Lib "f1.dll" Alias "_f1@4" (ByRef arr() As Long) As Long
...два варианта приема массива...
    Dim v As Variant, iArr() As Long, iArr2() As Long
    ReDim iArr2(10)
    v = f1(iArr)
    v = f1(iArr2)


extern "C" __declspec(dllexport) long __stdcall f1(SAFEARRAY* *ppsa)
{
    if( *ppsa == NULL )
    {
        // нужно создать новый
        SAFEARRAYBOUND rgsabound;
        rgsabound.lLbound = 0;   // начиная с 0
        rgsabound.cElements = 3; // всего элементов

        *ppsa = ::SafeArrayCreate( VT_I4, 1, & rgsabound ); 

        long * psadata = NULL; 
        if( SUCCEEDED(::SafeArrayAccessData(*ppsa, (void**)&psadata)) )
        {
            for(long i = 0; i < (long) rgsabound.cElements; i++)
                psadata[i] = i; // заполнение, в данном случае - тривиальное.

            ::SafeArrayUnaccessData(*ppsa);
        }
    }
    else
    {
        // нужно изменить старый (без учета многомерности)
        long lLbound, lUbound;
        SafeArrayGetLBound( *ppsa, 1, & lLbound );
        SafeArrayGetUBound( *ppsa, 1, & lUbound );

        long * psadata = NULL; 
        if( SUCCEEDED(::SafeArrayAccessData(*ppsa, (void**)&psadata)) )
        {
            for(long i = 0; i <= lUbound-lLbound; i++)
                psadata[i] = 2*psadata[i]; // заполнение, в данном случае - тривиальное.

            ::SafeArrayUnaccessData(*ppsa);
        }
    }
    return 0;
}


Третий способ не связан с SAFEARRAY напрямую, а только опосредованно — VB имеет массив, но передает этот массив для заполнения в подпрограмму. С-шная функция уже не может изменить размер этого массива. И чтобы можно было бы работать в С с массивом, нужно передать его количество элементов или использовать подразумеваемое.

Private Declare Function f1 Lib "f1.dll" Alias "_f1@4" (ByRef arr As Long) As Long
...два варианта ихменения массива...
    Dim v As Variant, iArr(10) As Long, iArr2() As Long
    ReDim iArr2(10)
    v = f1(iArr(0))
    v = f1(iArr2(0))


extern "C" __declspec(dllexport) long __stdcall f1(long* arr)
{
    long i;
    for(i = 0; i <= 10; i++)
        arr[i] = 2*arr[i]; // заполнение, в данном случае - тривиальное
    return i;
}
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.