Как вернуть двойной указатель из C++ DLL на C#?

Я пытаюсь вернуть указатель из моей C++ DLL на C#. Я перепробовал все, но мой указатель типа double не имеет значения.

Ниже мой импорт DLL C++:

[DllImport("/Resources/libfli.dll", EntryPoint = "FLIGetTemperature")]
public static extern unsafe int FLIGetTemperature(long dev, double* temperature);
// Get the temperature of a given camera. This function places the temperature of the CCD camera 
// cold finger of device dev in the location pointed to by temperature.
// Return Value: Zero on success. Non-zero on failure.
// Parameters: dev Camera device to get the temperature of.
// temperature Pointer to where the temperature will be placed.
// See Also: FLISetTemperature

определение FliGetTemperatre из FLI_SDK_Documentation

LIBFLIAPI FLIGetTemperature (flidev_t dev, double* temperature)
Get the temperature of a given camera.

Ниже показано, как я объявляю свой вызов.Dll в C#:

unsafe public void GetTheTemperatureOfTheCamera()
{
    int success=0;
    long ldev = 0;
    long* dev = &ldev;
    double lTemperature = 0;
    double* temperature = &lTemperature;
    success = FLIGetTemperature(ldev, temperature);
}

Когда я запускаю свой код, я получаю следующую ошибку ниже:

Произошло необработанное исключение типа "System.AccessViolationException" в myApplication.exe

Дополнительная информация: Попытка чтения или записи в защищенную память. Это часто указывает на то, что другая память повреждена.

Я также пытался маршалинг и IntPtr, но это тоже не работает.

Я пытался Флиопен, что функция работает. Это успех. Ниже приведен код для FliOpen.

    [DllImport("/Resources/libfli.dll", EntryPoint = "FLIOpen")]
    public static extern unsafe int FLIOpen(long* dev, string name, long domain);

    unsafe public int InitDevice()
    {
        long ldev = 0;
        long* dev = &ldev;
        int success;
        string deviceName = "flipro0";// this is default name for device
        long domainName = 258; //this is default domain name

        success = FLIOpen(dev, deviceName, domainName);
        return success;
    }

Хотя метод FLIOpen является успешным

2 ответа

Существует несоответствие между вашим C# long параметр и неуправляемый тип flidev_t, Ключевым моментом является то, что long это 64-битный тип. Если ваш код работает в Windows, то flidev_t, который является псевдонимом C++ long, имеет ширину 32 бита.

Вам также не нужен небезопасный код здесь. Вы можете объявить функцию следующим образом:

[DllImport("/Resources/libfli.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int FLIGetTemperature(int dev, out double temperature);

Я также предполагаю, что соглашение о вызовах cdecl, но вам, вероятно, нужно проверить файл заголовка C++, чтобы быть уверенным в этом.

Вам нужно будет внести другие изменения в другие объявления p/invoke. По сути везде, где вы перевели flidev_t в C# long вы должны изменить его на int, Или, может быть, даже IntPtr, Тогда вы будете на шаг впереди неуправляемого кода, который в настоящее время не подходит для 64-битного порта, я подозреваю!

Начиная с FLIOpen это будет:

[DllImport("/Resources/libfli.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int FLIOpen(out int dev, string name, int domain);

Ну, параметр домена может быть лучше переведен как перечисление C# с int базовый тип.

Читая документацию, я написал бы что-то вроде этого:

unsafe public void GetTheTemperatureOfTheCamera()
{
     int success=0;
     long dev = 0;
     long* ldev  = &dev;
     success = FLIOpen(ldev, deviceName, domainName); //Get the device handle.

     if (success != 0)
        throw new Exception("Cannot open device");

     double lTemperature = 0;
     double* temperature = &lTemperature;
     success = FLIGetTemperature(dev, temperature);
}
Другие вопросы по тегам