Что нового

Как определить размер возвращаемой структуры char*

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
Всегда мучил вопрос, как определить размер возвращаемой структуры char*.
Код:
typedef struct time_info_t {
   char const * time;
}

Выходил из положения следующим образом:
Код:
$a_Ret = DllCall($hDll, 'ptr', 'time_info') ; некая функция возвращает char* (ptr)
$sTime = DllStructGetData(DllStructCreate('char[64]', $a_Ret[0]), 'time') ; оформляю структуру с запасом
ConsoleWrite($sTime & @CR)
; Результат "Jan  7 2014 03:31:50"


Однако, с запасом как-то не по "взрослому" :smile:
Читал литературу по Си, мучил google, однако как это сделать более грамотно так и не нашёл. :(
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Обычно это известно заранее (тип данных, их содержание).
А вообще есть DllStructGetSize, не знаю насколько она поможет здесь.
Есть рабочий пример с которым можно поиграться?
 

Viktor1703

AutoIT Гуру
Сообщения
1,535
Репутация
413
Garrett

Я так понял в скрипт поступает указатель на область памяти, в таком случае в dll написать функцию которая будет возвращать этот размер, либо если я не ошибаюсь, задействовать функцию из Memory.au3

Код:
#include <Memory.au3>

$a_Ret = DllCall($hDll, 'ptr', 'time_info') ; некая функция возвращает char* (ptr)
$sTime = DllStructGetData(DllStructCreate('char[' & _MemGlobalSize($a_Ret[0]) & ']', $a_Ret[0]), 'time') ; оформляю структуру с запасом
ConsoleWrite($sTime & @CR)


Пример:

Код:
#include <Memory.au3>

$tBuffer = DllStructCreate('byte[112]')
$pBuffer = DllStructGetPtr($tBuffer)

MsgBox(0, '', _MemGlobalSize($pBuffer))
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Код:
$a_Ret = DllCall($hDll, 'ptr', 'time_info')
$sTime = DllStructGetData(DllStructCreate('char[' & (_WinAPI_StrLen($a_Ret[0], 0) + 1) & ']', $a_Ret[0]), 1)


Или так:

Код:
$a_Ret = DllCall($hDll, 'ptr', 'time_info')
$sTime = _WinAPI_GetString($a_Ret[0], 0)
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
Garrett,
А если сделать примерно так?
Код:
#include <WinAPIEx.au3>;3.3.8.1
;~ #include <WinAPISys.au3>;3.3.12.0+

Local $tBuffer, $pBuffer, $iSize, $tRes

ConsoleWrite('char:' & @LF)
$tBuffer = DllStructCreate('char[' & Random(512, 1024, 1) & ']')
DllStructSetData($tBuffer, 1, 'Garrett')
ConsoleWrite('Ptr 1: ' & DllStructGetPtr($tBuffer) & @LF)

$pBuffer = _WinAPI_CreateBufferFromStruct($tBuffer)
ConsoleWrite('Ptr 2: ' & $pBuffer & @LF)
$iSize =  _WinAPI_StringLenA($pBuffer)
ConsoleWrite('StringLenA: ' & $iSize & @LF)
$tRes = DllStructCreate('char[' & $iSize + 1 & ']', $pBuffer)
ConsoleWrite('Result: ' & DllStructGetData($tRes, 1) & @LF & @LF)
_WinAPI_FreeMemory($pBuffer)
;~ ---------------

ConsoleWrite('wchar:' & @LF)
$tBuffer = DllStructCreate('wchar[' & Random(512, 1024, 1) & ']')
DllStructSetData($tBuffer, 1, 'определить размер возвращаемой строки')
ConsoleWrite('Ptr 1: ' & DllStructGetPtr($tBuffer) & @LF)

$pBuffer = _WinAPI_CreateBufferFromStruct($tBuffer)
ConsoleWrite('Ptr 2: ' & $pBuffer & @LF)
$iSize =  _WinAPI_StringLenW($pBuffer)
ConsoleWrite('StringLenW: ' & $iSize & @LF)
$tRes = DllStructCreate('wchar[' & $iSize + 1 & ']', $pBuffer)
ConsoleWrite('Result: ' & DllStructGetData($tRes, 1) & @LF)
_WinAPI_FreeMemory($pBuffer)

PS
Yashied ответил раньше, у меня с примером. :smile:
 
Автор
Garrett

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
CreatoR [?]
Есть рабочий пример с которым можно поиграться?

Код:
#include <WinAPIEx.au3>

; Вот к примеру данные которые формирует функция на C++ и после того как мы её вызываем,
; отдаёт нам указатель на структуру.

#Region Function C++

; Си функция формирует структуру.
$sStr1 = 'Всем'
$sStr2 = 'спасибо'
$sStr3 = 'за помощь!'
$sStr4 = 'С уважением'
$sStr5 = 'Garrett!'

; Си функция создает строки 'char[n]'.
$tStr1 = DllStructCreate('char['& StringLen($sStr1)+1 &']')
DllStructSetData($tStr1, 1, $sStr1)
$pStr1 = DllStructGetPtr($tStr1)

$tStr2 = DllStructCreate('char['& StringLen($sStr2)+1 &']')
DllStructSetData($tStr2, 1, $sStr2)
$pStr2 = DllStructGetPtr($tStr2)

$tStr3 = DllStructCreate('char['& StringLen($sStr3)+1 &']')
DllStructSetData($tStr3, 1, $sStr3)
$pStr3 = DllStructGetPtr($tStr3)

$tStr4 = DllStructCreate('char['& StringLen($sStr4)+1 &']')
DllStructSetData($tStr4, 1, $sStr4)
$pStr4 = DllStructGetPtr($tStr4)

$tStr5 = DllStructCreate('char['& StringLen($sStr5)+1 &']')
DllStructSetData($tStr5, 1, $sStr5)
$pStr5 = DllStructGetPtr($tStr5)

; Си функция создает массив указателей 'char *'.
$tPtrArr = DllStructCreate('ptr[5]')
DllStructSetData($tPtrArr, 1, $pStr1, 1)
DllStructSetData($tPtrArr, 1, $pStr2, 2)
DllStructSetData($tPtrArr, 1, $pStr3, 3)
DllStructSetData($tPtrArr, 1, $pStr4, 4)
DllStructSetData($tPtrArr, 1, $pStr5, 5)

$pPtrArr = DllStructGetPtr($tPtrArr)

; Си функция возвращает указатель 'char **'.
; Return $pPtr
$tPtr = DllStructCreate('ptr')
DllStructSetData($tPtr, 1, $pPtrArr)
$pPtr = DllStructGetPtr($tPtr)

#EndRegion Function C++

#Region Function Autoit

; Итак, мы получили указатель Ptr (char **).
Local $aRet[1] = [$pPtr] ; DllCall(...)

; Формируем структуру в Autoit
$tRetPtr = DllStructCreate('ptr', $aRet[0])

; Получаем указатель на массив строк.
; Тут нужно как-то по "взрослому" получить размер массива указателей,
; однако, это уже отдельная тема :)
$tRetArr = DllStructCreate('ptr[5]', DllStructGetData($tRetPtr, 1))

; Получаем строки.
; Тут возник вопрос заданный в теме.
; http://autoit-script.ru/index.php?topic=18576.msg112153;topicseen
; Большое спасибо всем, кто отозвался: CreatoR, Viktor1703, Yashied, madmasles!
; Yashied, madmasles +1 ваши варианты то, что надо.
$pRetStr1 = DllStructGetData($tRetArr, 1, 1)
$tRetStr1 = DllStructCreate('char['& _WinAPI_StrLen($pRetStr1, 0) &']', $pRetStr1)
$sRetStr1 = DllStructGetData($tRetStr1, 1)

$pRetStr2 = DllStructGetData($tRetArr, 1, 2)
$tRetStr2 = DllStructCreate('char['& _WinAPI_StrLen($pRetStr2, 0) &']', $pRetStr2)
$sRetStr2 = DllStructGetData($tRetStr2, 1)

$pRetStr3 = DllStructGetData($tRetArr, 1, 3)
$tRetStr3 = DllStructCreate('char['& _WinAPI_StrLen($pRetStr3, 0) &']', $pRetStr3)
$sRetStr3 = DllStructGetData($tRetStr3, 1)

$pRetStr4 = DllStructGetData($tRetArr, 1, 4)
$tRetStr4 = DllStructCreate('char['& _WinAPI_StrLen($pRetStr4, 0) &']', $pRetStr4)
$sRetStr4 = DllStructGetData($tRetStr4, 1)

$pRetStr5 = DllStructGetData($tRetArr, 1, 5)
$tRetStr5 = DllStructCreate('char['& _WinAPI_StrLen($pRetStr5, 0) &']', $pRetStr5)
$sRetStr5 = DllStructGetData($tRetStr5, 1)

ConsoleWrite(StringFormat('=================================\r\n'))
ConsoleWrite(StringFormat('%7s %s %s\r\n\t%s %s\r\n', $sRetStr1, $sRetStr2, $sRetStr3, $sRetStr4, $sRetStr5))
ConsoleWrite(StringFormat('=================================\r\n'))

#EndRegion Function Autoit

Большое спасибо всем, кто отозвался: CreatoR, Viktor1703, Yashied, madmasles!
Yashied, madmasles ваши варианты то, что надо. :thanks:
 
Верх