Я работал над C # версией C ++ API, но мне не удалось понять это правильно.
Поскольку первый API был слишком большим, я опубликовал его, и я сократил его до некоторых основных функций, для которых мне действительно нужна помощь в создании управляемой версии.
Итак, по сути, это C ++ dll, содержащий экспортированные функции, которые используются для связи с программным обеспечением для технического анализа.
C ++ функция, которую я хотел бы преобразовать
#define PLUGINAPI extern "C" __declspec(dllexport)
PLUGINAPI int GetFunctionTable( FunctionTag **ppFunctionTable )
{
*ppFunctionTable = gFunctionTable;
// must return the number of functions in the table
return gFunctionTableSize;
}
GetFunctionTable вызывается программным обеспечением, которое предоставляет указатель на массив FunctionTag с именем gFunctionTable:
typedef struct FunctionTag
{
char *Name;
FunDesc Descript;
} FunctionTag;
FunctionTag gFunctionTable[] = {"ExampleA",{ VExampleA, 0, 0, 0, 0, NULL },
"ExampleB",{ VExampleB, 1, 0, 1, 0, NULL }
};
Структура FunctionTag содержит встроенную структуру с именем Fundesc:
// FunDesc structure holds the pointer to actual
// user-defined function that can be called by AmiBroker.
typedef struct FunDesc
{
AmiVar (*Function)( int NumArgs, AmiVar *ArgsTable );
UBYTE ArrayQty; // number of Array arguments required
UBYTE StringQty; // number of String arguments required
SBYTE FloatQty; // number of float args
UBYTE DefaultQty; // number of default float args
float *DefaultValues; // the pointer to defaults table
} FunDesc;
Наконец, Fundesc содержит тип AmiVar:
#pragma pack( push, 2 )
typedef struct AmiVar
{
int type;
union
{
float val;
float *array;
char *string;
void *disp;
};
} AmiVar;
#pragma pack(pop)
C # преобразование до сих пор
Теперь, это то, что я написал до сих пор в попытке заставить мой C # dll "имитировать" оригинальный C ++ API. Экспортируемая функция GetFunctionTable ():
namespace AmiBrokerFrontDll
{
internal static class AmiBrokerFrontDll
{
[DllExport("GetFunctionTable", CallingConvention = CallingConvention.Cdecl)]
public static Int32 GetFunctionTable(ref FunctionTag[] ppFunctionTable)
{
FillFunction();
ppFunctionTable=gFunctionTable;
return gFunctionTableSize;
}
Затем следует определение структуры FunctionTag и gFunctionTableSize:
[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct FunctionTag
{
[MarshalAs(UnmanagedType.LPStr)]
public string Name;
public FunDesc Description;
}
public static FunctionTag[] gFunctionTable=new FunctionTag[1];
public static FunctionTag gfunc;
static Int32 gFunctionTableSize = Marshal.SizeOf(gFunctionTable) / Marshal.SizeOf(gfunc);
public static void FillFunction()
{
gFunctionTable[0].Name = "VExempleA";
gFunctionTable[0].Description.Function += VExempleDeMacd;
//ArrayQty, StringQty, FloatQty, DefaultQty, DefaultTablePtr
gFunctionTable[0].Description.ArrayQty = 0;
gFunctionTable[0].Description.StringQty = 0;
gFunctionTable[0].Description.FloatQty = 2;
gFunctionTable[0].Description.DefaultQty = 0;
gFunctionTable[0].Description.DefaultValues = new IntPtr();
}
Объявление FunDesc включает делегата:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate AmiVar FunctionDelegate(int NumArgs, ref AmiVar ArgsTable);
public struct FunDesc
{
[MarshalAs(UnmanagedType.FunctionPtr)]
public FunctionDelegate Function;
public byte ArrayQty; // The number of Array arguments required
public byte StringQty; // The number of String arguments required
public byte FloatQty; // The number of float args
public byte DefaultQty; // The number of default float args
public IntPtr DefaultValues; // The pointer to defaults table
}
Наконец, у нас есть структура AmiVar:
[StructLayoutAttribute(LayoutKind.Explicit, Size = 8)]
public struct AmiVar
{
[FieldOffset(0)]
public Int32 type;
[FieldOffset(4)]
public Single val;
[FieldOffset(4)]
public IntPtr array;
[FieldOffset(4)]
[MarshalAs(UnmanagedType.LPStr)]
public string name;
[FieldOffset(4)]
public IntPtr disp;
}
Извините, это слишком долго. К сожалению, я не мог сделать небольшой вопрос.
Таким образом, этот код скомпилирован (возможно, больше нет, поскольку это выдержка из общей картины), но при загрузке результирующей библиотеки DLL из программного обеспечения технического анализа я получил ОШИБКУ НАРУШЕНИЯ ДОСТУПА. Я считаю, что это означает, что преобразование C # не отображает размер переменных C ++ правильно. С массивами структур и делегатов этот проект стал слишком сложным для решения в одиночку.
Любая помощь будет высоко ценится!
Спасибо,
Гийом