Управление C ++ Garmin API в C #

2

Я хочу называть 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
marshalling
garmin

2 ответа

1

Вы должны иметь возможность использовать 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. При этом может потребоваться некоторая настройка, в зависимости от проблем с выравниванием/упаковкой и того, как используются различные элементы.

0

вы всегда можете создать проект CPP/CLI, который будет переносить собственный API с помощью управляемого API. Обычно гораздо проще написать управляемую оболочку, а не использовать DllImprt.

  • 0
    Вау, это выглядит сложно. Есть какой-нибудь инструмент, чтобы сделать обертку? Мои знания C низки, и я не знаю, как обернуть нативный API. Я вижу, что другой человек делает Wrapper ( christian-helle.blogspot.com/2008/02/… ), но я не могу использовать его в .NET 1.1. Это причина, по которой я использую P / Invoke. Благодарю.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню