Маршалинг массива BSTR
От: B_A_D Израиль  
Дата: 26.03.21 08:57
Оценка:
Есть DLL-ка, написанная на С++ Builder.
Из нее экспортируется функция и при вызове из С++ аппликации все работает

typedef BSTR          TStringArray[100];
typedef TStringArray *PStringArray;

typedef Single        TValueArray[100];
typedef TValueArray  *PValueArray;


typedef __stdcall bool GetData(BSTR JN, int &V, PStringArray &JS, PValueArray &JV, BSTR &ErrMsg);


  //вызов
  int                 V;
  PStringArray        JS;
  PValueArray         JV;
  BSTR JN   =SysAllocString(L"ABCD");

  GetData( JN, V,  JS, ОV, ErrMsg);


задача вызвать то же самое из C#, модуль загружается динамически, указатель на функцию получен нормально

     [UnmanagedFunctionPointer(CallingConvention.StdCall)]
        private delegate bool FGetData(string JN, ref int V,
            [In,Out, MarshalAs(UnmanagedType.LPArray, SizeConst = 100,ArraySubType = UnmanagedType.BStr)] ref string[] JS,
            [In, Out, MarshalAs(UnmanagedType.LPArray, SizeConst=100, ArraySubType = UnmanagedType.R4)] ref float[] JV,
             [ MarshalAs(UnmanagedType.BStr)]  ref string ErrMsg);

    //вызов
    string JN = "AA000110";
        string ErrMsg = "";
           
        int Ver = 0;
        string[] JS =  new string[100];
        float[] JN =  new float[100];


        GetData(JN,  ref V,  ref JS,  ref JV, ref ErrMsg);


валится при вызове из C# с ошибкой "AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt."

Доступа к исходникам DLL-ки нет.
В чем ошибка ?
bstr c#
Re: Маршалинг массива BSTR
От: VladD2 Российская Империя www.nemerle.org
Дата: 27.03.21 13:01
Оценка:
Здравствуйте, B_A_D, Вы писали:

B_A>typedef __stdcall bool GetData(BSTR JN, int &V, PStringArray &JS, PValueArray &JV, BSTR &ErrMsg);


Ты не привел описания ни для PStringArray, ни для PValueArray. Вызов тоже описан так, что структуру данных не понять.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Маршалинг массива BSTR
От: _NN_ www.nemerleweb.com
Дата: 29.03.21 14:09
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, B_A_D, Вы писали:


B_A>>typedef __stdcall bool GetData(BSTR JN, int &V, PStringArray &JS, PValueArray &JV, BSTR &ErrMsg);


VD>Ты не привел описания ни для PStringArray, ни для PValueArray. Вызов тоже описан так, что структуру данных не понять.


typedef BSTR          TStringArray[100];
typedef TStringArray *PStringArray;

typedef Single        TValueArray[100];
typedef TValueArray  *PValueArray;


Они выше.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re: Маршалинг массива BSTR
От: _NN_ www.nemerleweb.com
Дата: 29.03.21 14:36
Оценка: 82 (3)
Здравствуйте, B_A_D, Вы писали:

Неясно зачем такой сложный тип.
Ссылка на указатель на массив.

У меня ваш код собирается и работает.
Пропущен у вас в коде: [return: MarshalAs(UnmanagedType.U1)]
Без этого маршаллер думает, что там тип BOOL, который будет 4 байта вместо одного.


#include <windows.h>
#include <combaseapi.h>
#include <cwchar>

typedef BSTR          TStringArray[100];
typedef TStringArray* PStringArray;

typedef float        TValueArray[100];
typedef TValueArray* PValueArray;


extern "C" __declspec(dllexport) bool __stdcall FGetData(BSTR JN, int& V, PStringArray& JS, PValueArray& JV, BSTR& ErrMsg)
{
    wprintf(L"%s\n", JN);

    V = 10;

    (*JS)[0] = SysAllocString(L"1010");

    (*JV)[0] = 10.10f;

    ErrMsg = SysAllocString(L"Err");

    return true;
}


using System;
using System.Runtime.InteropServices;

namespace ConsoleApp30
{
    class Program
    {
        [DllImport("Dll1", CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
        [return: MarshalAs(UnmanagedType.U1)]
        public static extern bool FGetData(
            [MarshalAs(UnmanagedType.BStr)] string JN,
            ref int V,
            [In, Out, MarshalAs(UnmanagedType.LPArray, SizeConst = 100, ArraySubType = UnmanagedType.BStr)] ref string[] JS,
            [In, Out, MarshalAs(UnmanagedType.LPArray, SizeConst = 100, ArraySubType = UnmanagedType.R4)] ref float[] JV,
            [MarshalAs(UnmanagedType.BStr)] ref string ErrMsg);

        static void Main(string[] args)
        {
            int v = 0;
            string[] js = new string[100];
            float[] jv = new float[100];
            string errmsg = null;

            FGetData("abc", ref v, ref js, ref jv, ref errmsg);

            Console.WriteLine(v);
            Console.WriteLine(js[0]);
            Console.WriteLine(jv[1]);
            Console.WriteLine(errmsg);
        }
    }
}


abc
10
1010
0
Err
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[2]: Маршалинг массива BSTR
От: B_A_D Израиль  
Дата: 08.04.21 14:18
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Здравствуйте, B_A_D, Вы писали:


_NN>Неясно зачем такой сложный тип.


Библиотека сторонняя *.bpl, собрана то ли на с++ Builder или на Delfy.


_NN>Ссылка на указатель на массив.


_NN>У меня ваш код собирается и работает.

_NN>Пропущен у вас в коде: [return: MarshalAs(UnmanagedType.U1)]

Да, спасибо, дело было в неправильном маршаллинге BOOL.


_NN>Без этого маршаллер думает, что там тип BOOL, который будет 4 байта вместо одного.


_NN>

_NN>#include <windows.h>
_NN>#include <combaseapi.h>
_NN>#include <cwchar>

_NN>typedef BSTR          TStringArray[100];
_NN>typedef TStringArray* PStringArray;

_NN>typedef float        TValueArray[100];
_NN>typedef TValueArray* PValueArray;


_NN>extern "C" __declspec(dllexport) bool __stdcall FGetData(BSTR JN, int& V, PStringArray& JS, PValueArray& JV, BSTR& ErrMsg)
_NN>{
_NN>    wprintf(L"%s\n", JN);

_NN>    V = 10;

_NN>    (*JS)[0] = SysAllocString(L"1010");

_NN>    (*JV)[0] = 10.10f;

_NN>    ErrMsg = SysAllocString(L"Err");

_NN>    return true;
_NN>}
_NN>


_NN>
_NN>using System;
_NN>using System.Runtime.InteropServices;

_NN>namespace ConsoleApp30
_NN>{
_NN>    class Program
_NN>    {
_NN>        [DllImport("Dll1", CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
_NN>        [return: MarshalAs(UnmanagedType.U1)]
_NN>        public static extern bool FGetData(
_NN>            [MarshalAs(UnmanagedType.BStr)] string JN,
_NN>            ref int V,
_NN>            [In, Out, MarshalAs(UnmanagedType.LPArray, SizeConst = 100, ArraySubType = UnmanagedType.BStr)] ref string[] JS,
_NN>            [In, Out, MarshalAs(UnmanagedType.LPArray, SizeConst = 100, ArraySubType = UnmanagedType.R4)] ref float[] JV,
_NN>            [MarshalAs(UnmanagedType.BStr)] ref string ErrMsg);

_NN>        static void Main(string[] args)
_NN>        {
_NN>            int v = 0;
_NN>            string[] js = new string[100];
_NN>            float[] jv = new float[100];
_NN>            string errmsg = null;

_NN>            FGetData("abc", ref v, ref js, ref jv, ref errmsg);

_NN>            Console.WriteLine(v);
_NN>            Console.WriteLine(js[0]);
_NN>            Console.WriteLine(jv[1]);
_NN>            Console.WriteLine(errmsg);
_NN>        }
_NN>    }
_NN>}
_NN>


_NN>
_NN>abc
_NN>10
_NN>1010
_NN>0
_NN>Err
_NN>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.