Добрый день.
Суть проблемы: есть сишная длл-ка без исходников, только заголовочный файл с комментариями. Вот описание интересующей функции, которую я пытаюсь вызвать из с#:
// 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, т.е. функция отрабатывает корректно.
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?
Здравствуйте, Аноним, Вы писали:
А>А какая сторона выделяет память? Сигнатура функции говорит как о том, что память выделяет вызывающая сторона так и о том, что память выделяет вызываемая сторона.
Если память выделяет вызываемая сторона то, кто ее тогда освобждает?
Обычно, такие функции используются следующем образом — первый вызов с нулевым указателем для получения размера и второй вызов с уже выделенной памятью нужного размера для получения реальных данных
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
не знаю зачем понадобился указатель на массив (то есть двойной указатель) хватило бы и одного. но все же думаю проблема не в этом. как говорил один мой знакомый: машина — дура железная, что ты ей скажешь, то она и делает.
попробуйте так. но назвать это красивым язык не поворачивается
Здравствуйте, TK, Вы писали:
TK>Если память выделяет вызываемая сторона то, кто ее тогда освобждает? TK>Обычно, такие функции используются следующем образом — первый вызов с нулевым указателем для получения размера и второй вызов с уже выделенной памятью нужного размера для получения реальных данных
я про что и говорю, что с одной стороны как будто память выделяет вызываемая сторона, но двойной указатель обычно используется когда память выделяет вызывающая сторона