Есть 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-ки нет.
В чем ошибка ?
Здравствуйте, 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;
Они выше.
Здравствуйте, 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
Здравствуйте, _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>