Я хочу называть Garmin API в проекте VB.Net Compact Framework. API находится на С++, поэтому я делаю проект DLL С# промежуточным способом между API dll и VB.NET. У меня есть некоторые проблемы при выполнении моего кода, потому что он бросает NotSupportedException
(тип плохих аргументов, я думаю) в вызове QueCreatePoint
. Ниже приведен код С++ API и работа с С#.
Протокол С++ и прототип С# P/Invoke Calls:
QueAPIExport QueErrT16 QueCreatePoint( const QuePointType* point, QuePointHandle* handle );
QueAPIExport QueErrT16 QueClosePoint( QuePointHandle point );
[DllImport("QueAPI.dll")]
private static extern QueErrT16 QueCreatePoint(ref QuePointType point, ref uint handle);
[DllImport("QueAPI.dll")]
private static extern QueErrT16 QueRouteToPoint(uint point);
QueErrT16:
typedef uint16 QueErrT16; enum { ... }
public enum QueErrT16 : ushort { ... }
QuePointType:
typedef struct
{
char id[25];
QueSymbolT16 smbl;
QuePositionDataType posn;
} QuePointType;
public struct QuePointType
{
public string id;
public QueSymbolT16 smbl;
public QuePositionDataType posn;
}
QueSymbolT16:
typedef uint16 QueSymbolT16; enum { ... }
public enum QueSymbolT16 : ushort { ... }
QuePositionDataType:
typedef struct
{
sint32 lat;
sint32 lon;
float altMSL;
} QuePositionDataType;
public struct QuePositionDataType
{
public int lat;
public int lon;
public float altMSL;
}
QuePointHandle:
typedef uint32 QuePointHandle;
В С# я управляю им как uint
var.
И это моя текущая функция С#, чтобы вызвать все это:
public static QueErrT16 GarminNavigateToCoordinates(double latitude , double longitude)
{
QueErrT16 err = new QueErrT16();
// Open API
err = QueAPIOpen();
if(err != QueErrT16.queErrNone)
{
return err;
}
// Create position
QuePositionDataType position = new QuePositionDataType();
position.lat = GradosDecimalesASemicirculos(latitude);
position.lon = GradosDecimalesASemicirculos(longitude);
// Create point
QuePointType point = new QuePointType();
point.posn = position;
// Crete point handle
uint hPoint = new uint();
err = QueCreatePoint(ref point, ref hPoint); // HERE i got a NotSupportedException
if (err == QueErrT16.queErrNone)
{
err = QueRouteToPoint(hPoint);
}
// Close API
QueAPIClose();
return err;
}
Вы должны иметь возможность использовать pInvoke непосредственно из VB без оболочки С# (или оболочки С++). Декларации должны быть примерно такими:
'QueAPIExport QueErrT16 QueCreatePoint( const QuePointType* point, QuePointHandle* handle );'
'QueAPIExport QueErrT16 QueClosePoint( QuePointHandle point );'
<DllImport("QueAPI.dll")> _
Private Shared Function QueCreatePoint(ByRef point As QuePointType, ByRef handle As Integer) As QueErrT16
End Function
<DllImport("QueAPI.dll")> _
Private Shared Function QueRouteToPoint(ByVal point As Integer) As QueErrT16
End Function
'-- QueErrT16 ----------'
'typedef uint16 QueErrT16; enum { ... }'
Public Enum QueErrT16 As Short
blah
End Enum
'-- QuePointType ----------'
'typedef struct { char id[25]; QueSymbolT16 smbl; QuePositionDataType posn; } QuePointType;'
'Remeber to initialize the id array.'
Public Structure QuePointType
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=25)> Public id As Byte()
Public smbl As QueSymbolT16
Public posn As QuePositionDataType
End Structure
'-- QueSymbolT16 ----------'
'typedef uint16 QueSymbolT16; enum { ... }'
Public Enum QueSymbolT16 As Short
blahblah
End Enum
'-- QuePositionDataType ----------'
'typedef struct { sint32 lat; sint32 lon; float altMSL; } QuePositionDataType;'
Public Structure QuePositionDataType
Public lat As Integer
Public lon As Integer
Public altMSL As Single
End Structure
'-- QuePointHandle ----------'
'typedef uint32 QuePointHandle;'
'In VB use Integer.'
Я предполагаю, что есть причина, по которой C объявляет в начале QueClosePoint, а pInvoke объявляет QueRouteToPoint. При этом может потребоваться некоторая настройка, в зависимости от проблем с выравниванием/упаковкой и того, как используются различные элементы.
вы всегда можете создать проект CPP/CLI, который будет переносить собственный API с помощью управляемого API. Обычно гораздо проще написать управляемую оболочку, а не использовать DllImprt.