Маршалинг массива структур.
От: Defazze  
Дата: 26.07.08 06:47
Оценка:
Добрый день.
Суть проблемы: есть сишная длл-ка без исходников, только заголовочный файл с комментариями. Вот описание интересующей функции, которую я пытаюсь вызвать из с#:


// FullName:  TCL_GetProviderList
// Returns:   DWORD - TCL_ERROR_SUCCESS в случае успешного выполнения. В случае ошибки - см. коды ошибок.
// Parameter: IN_OUT DWORD *pdwListSize - указатель на размер требуемого массива структур TCL_PROV_INFO.
// Parameter: OUT TCL_PROV_INFO **pProvList - указатель на массив структур TCL_PROV_INFO. В случае если массив
//              имеет значение NULL, тогда функция возвращает длину требуетого массива.
//************************************************************************************************************
EXTERN_C ATCL_EXPORT DWORD ATCL_STDCALL TCL_GetProviderList(
    IN_OUT DWORD         *pdwListSize,
    OUT    TCL_PROV_INFO **pProvList = NULL);


Вот таким вот образом я пытаюсь вызвать ее из с#:


[DllImport("atcl.dll")]
        public static extern int TCL_GetProviderList(out int lListSize, out IntPtr ProvList);


с тем, чтобы в дальнейшем при помощи Marshal.PtrToStructure вытащить нужный массив.

Но тут начинаются странности. Функция возвращает ненулевой размер массива, однако возвращаемый указатель всегда IntPtr.Zero. Можно было бы предположить, что проблема в сишной функции, однако код VBA, работающий с этой же функцией, отрабатывает безупречно:


Public Type TCL_PROV_INFO
    ProvName As String
    dwType As Long
End Type

Declare Function LoadLibrary Lib "kernel32.dll" Alias "LoadLibraryA" (ByVal s As String) As Long
Declare Function GetProviderList Lib "aTCL.dll" Alias "#13" (ByRef lListSize As Long, _
                    ByRef ProvList() As TCL_PROV_INFO) As Long
                    
Public Sub test()
Dim ProvList() As TCL_PROV_INFO, lSize As Long, i As Long

LoadLibrary ("atcl.dll")

GetProviderList ProvList, lSize
ReDim ProvList(1 To lSize)
GetProviderList ProvList, lSize
      
For i = 1 To lSize
        Debug.Print ProvList(i).ProvName
Next i

End Sub



Попытка вернуть не указатель, а непосредственно массив структур:

[DllImport("atcl.dll")]
        public static extern int TCL_GetProviderList(out int lListSize, out TCL_PROV_INFO[] ProvList);


так же не приносит успеха: в переменной ProvList содержится NULL.

В обоих вариантах вызова возвращаемый код ошибки — 0, т.е. функция отрабатывает корректно.

Помогите пожалуйста забороть эту проблему.
Re: Маршалинг массива структур.
От: Ovl Россия  
Дата: 26.07.08 11:46
Оценка:
попробуйте

[DllImport("atcl.dll")]
public static extern int TCL_GetProviderList(out int lListSize, ref TCL_PROV_INFO[] ProvList);
Read or Die!
Как правильно задавать вопросы
Как правильно оформить свой вопрос
Автор: anvaka
Дата: 15.05.06
Re[2]: Маршалинг массива структур.
От: Defazze  
Дата: 26.07.08 13:37
Оценка:
Здравствуйте, Ovl, Вы писали:

Ovl>попробуйте


Ovl>
Ovl>[DllImport("atcl.dll")]
Ovl>public static extern int TCL_GetProviderList(out int lListSize, ref TCL_PROV_INFO[] ProvList);
Ovl>


Все возможные сочетания ref, out и даже атрибутов In, Out перепробованы не единожды. Эффект нулевой.
Есть подозрение, что это из-за того, что из сишной функции возвращается двойной указатель вместо простого. Но функцию я изменить не в силах.
Re[3]: Маршалинг массива структур.
От: Аноним  
Дата: 26.07.08 15:24
Оценка:
Здравствуйте, Defazze, Вы писали:

D>Есть подозрение, что это из-за того, что из сишной функции возвращается двойной указатель вместо простого. Но функцию я изменить не в силах.

А какая сторона выделяет память? Сигнатура функции говорит как о том, что память выделяет вызывающая сторона так и о том, что память выделяет вызываемая сторона.
Есть пример вызова на C?
Re[4]: Маршалинг массива структур.
От: TK Лес кывт.рф
Дата: 26.07.08 17:12
Оценка:
Здравствуйте, Аноним, Вы писали:

А>А какая сторона выделяет память? Сигнатура функции говорит как о том, что память выделяет вызывающая сторона так и о том, что память выделяет вызываемая сторона.


Если память выделяет вызываемая сторона то, кто ее тогда освобждает?
Обычно, такие функции используются следующем образом — первый вызов с нулевым указателем для получения размера и второй вызов с уже выделенной памятью нужного размера для получения реальных данных
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re: Маршалинг массива структур.
От: Yozh_Programmer  
Дата: 26.07.08 17:23
Оценка:
Так может легче написать DLL свою которая позволит вызывать

EXTERN_C ATCL_EXPORT DWORD ATCL_STDCALL TCL_GetProviderList(
IN_OUT DWORD *pdwListSize,
OUT TCL_PROV_INFO **pProvList = NULL)

через более дружелюбный .NET совместимый интерфейс?
Re[2]: Маршалинг массива структур.
От: TK Лес кывт.рф
Дата: 26.07.08 17:34
Оценка:
Здравствуйте, Yozh_Programmer, Вы писали:

Y_P>через более дружелюбный .NET совместимый интерфейс?

А зачем тут двойной указатель?
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re[3]: Маршалинг массива структур.
От: Ovl Россия  
Дата: 26.07.08 18:58
Оценка:
не знаю зачем понадобился указатель на массив (то есть двойной указатель) хватило бы и одного. но все же думаю проблема не в этом. как говорил один мой знакомый: машина — дура железная, что ты ей скажешь, то она и делает.

попробуйте так. но назвать это красивым язык не поворачивается
static void Fo()
{
    int size = 0;
    TCL_PROV_INFO[] pProvList = null;

    unsafe {
        fixed (TCL_PROV_INFO* fix = pProvList)
        {
            IntPtr ptr = new IntPtr(fix);
            Debug.Assert(0 != TCL_GetProviderList(ref size, ref ptr));
        }
    }

    pProvList = new TCL_PROV_INFO[size];

    unsafe
    {
        fixed (TCL_PROV_INFO* fix = pProvList)
        {
            IntPtr ptr = new IntPtr(fix);
            Debug.Assert(0 == TCL_GetProviderList(ref size, ref ptr));
        }
    }
}
Read or Die!
Как правильно задавать вопросы
Как правильно оформить свой вопрос
Автор: anvaka
Дата: 15.05.06
Re[4]: Маршалинг массива структур.
От: Ovl Россия  
Дата: 26.07.08 18:59
Оценка:
забыл добавить делегат

[DllImport("...")]
public static extern int TCL_GetProviderList(ref int size, ref IntPtr pProvList);
Read or Die!
Как правильно задавать вопросы
Как правильно оформить свой вопрос
Автор: anvaka
Дата: 15.05.06
Re[5]: Маршалинг массива структур.
От: Аноним  
Дата: 26.07.08 19:09
Оценка:
Здравствуйте, TK, Вы писали:

TK>Если память выделяет вызываемая сторона то, кто ее тогда освобждает?

TK>Обычно, такие функции используются следующем образом — первый вызов с нулевым указателем для получения размера и второй вызов с уже выделенной памятью нужного размера для получения реальных данных
я про что и говорю, что с одной стороны как будто память выделяет вызываемая сторона, но двойной указатель обычно используется когда память выделяет вызывающая сторона
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.