DllImport как получить отдельные значения по ссылке

Какой подходящий атрибут подписи/marshall для получения выходных параметров с использованием параметров указателей? До сих пор я пробовал это:

// Function to calculate the norm of vector. !0 on error.
// int err_NormVec(int size, double * vector, double * norm)
[DllImport("vectors.dll")]
int err_NormVec(int size, double[] vector, ref double norm)

Предыдущий подход не возвращает значение в .NET из C. Я также пытался использовать закрепленный GCHandle с подписью IntPtr.

[DllImport("vectors.dll")]
int err_NormVec(int size, double[] vector, IntPtr norm)

public void doSomething()
{
   double norm = 0;
   // ...
   GCHandle handle = GCHandle.Alloc(norm, GCHandleType.Pinned);
   int status = err_NormVec(vector.Lenght, vector, handle.AddrOfPinnedObject());
   // ... clean gchandle, check status and so on
}

В этом случае я получил значение обратно, но в GCHandle.Target, а не в исходной норме. Что раздражает. Я хотел бы иметь возможность закрепить intptr самой нормы, а не просто копию.

Какова подходящая подпись для возврата значения с использованием указателя? Есть ли поддерживаемый способ получить IntPtr значение int?


person fprades    schedule 11.04.2012    source источник
comment
Я забыл упомянуть, что я использую win64. Который раскрыл некоторые плохие практики, которые, к счастью, работают в приложениях win32.   -  person fprades    schedule 11.04.2012
comment
Покажите нам реализацию (или хотя бы подпись) err_NormVec. Вам не нужно прикреплять двойник, чтобы использовать его в качестве выходного параметра, ref будет достаточно.   -  person Ed S.    schedule 11.04.2012
comment
@leppie: Нет, не я, а ты? Я вижу взаимодействие подписи C#, я не вижу здесь нативного кода. Вы бы просто предположили, что это правильно тогда?   -  person Ed S.    schedule 11.04.2012
comment
@EdS.: В комментарии выше первый фрагмент кода C#. Нет?   -  person leppie    schedule 11.04.2012
comment
@leppie: .... так оно и есть, извините (хотя вам не нужно быть придурком). Однако реализация была бы хорошей, если бы это было возможно.   -  person Ed S.    schedule 11.04.2012
comment
Что касается проблем с IntPtr, я думаю, что они вызваны автоупаковкой, как ожидает и возражает GCHandle. Следовательно, двойник преобразуется в новый двойник. Должна быть возможность подтвердить позже.   -  person fprades    schedule 11.04.2012


Ответы (1)


Это работает для меня (как и должно):

//C++ DLL (__stdcall calling convention)
extern "C" __declspec(dllexport) void Foo(double *result) {
    *result = 1.2;
}

//C#    
class Program
{
    [DllImport( "Snadbox.dll", CallingConvention=CallingConvention.StdCall )]
    static extern void Foo( ref double output );

    static void Main( string[] args )
    {
        double d = 0;           
        Foo( ref d );

        Console.WriteLine( d ); // prints "1.2"         
    }
}

Достаточно передать double с помощью ключевого слова ref. Итак, меня заставили поверить, что в реализации что-то не так (или неправильно понято). Можете ли вы опубликовать реализацию для нас?

Кроме того, возможно, вы создаете версию C++, используя соглашение о вызовах по умолчанию (cdecl), но .NET использует StdCall. Вы убедились, что они совпадают? Вы можете разбиться, если они смешаны, но нет никакой гарантии. Например, в моем примере, если я изменю сторону C++ на cdecl, тогда параметр out будет считан как 0.

person Ed S.    schedule 11.04.2012
comment
Реализация незначительна, это просто пример, так как на самом деле это очень сложная библиотека. Если вы хотите, реализация будет следующей: int err_NormVec(int size, double[] vector, double * norm)(*norm=0;for(int i=0;i‹size;++i){norm+=vector[ i]*vector[i];}*norm=sqrt(*norm);возврат 0;) - person fprades; 11.04.2012
comment
@fprades.bbva: Ну, и я не хочу показаться грубым, но ваше мнение не имеет большого значения, поскольку вы не знаете, почему это не работает. Я показал вам, что упрощенный пример работает, значит, что-то еще не так, и вы не дали нам достаточно информации, чтобы понять, что это такое. Кроме того, фрагмент, который вы мне дали, неверен, поскольку вы добавляете к самому указателю, не разыменовывая его. - person Ed S.; 11.04.2012
comment
Это то, что также должно работать. Однако по какой-то причине это не работает во время выполнения x64. Странный. Может быть, я что-то пропустил со всеми пробами и ошибками. - person fprades; 11.04.2012
comment
@fprades.bbva: Я также создаю все для x64 (должен был это отметить). Двойной тип имеет одинаковый размер между языками. - person Ed S.; 11.04.2012
comment
Эд С. Это сработало. Я столкнулся с аналогичной проблемой с массивами ссылок, которые приводят к сбою моего приложения. Те, с которыми я могу безопасно справиться с GCHandle. Спасибо за помощь, и терпение. - person fprades; 12.04.2012