Что нового

Как прочитать данные из памяти, выделенной функцией _MemGlobalAlloc()

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
Есть структура на C++

Код:
struct CapParams
{
 	/* Target buffer. 
 	 * Must be at least Width * Height * sizeof(int) of size! 
 	 */
 	int * Buffer;
 	/* Buffer width */
 	int Width;
 	/* Buffer height */
 	int Height;
};

Так она заполняется

Код:
 	struct CapParams capture;
 	capture.Width = 320;
 	capture.Height = 240;
 	capture.Buffer = new int[320 * 240];

Далее эта структура передаётся по ссылке в функцию в качестве второго параметра (первый параметр, устройство)

Код:
Capture(0, &capture)

Сама функция
Код:
typedef int (*CaptureProc)(unsigned int deviceno, struct CapParams *aParams);
extern CaptureProc Capture;

Нужно её перевести на AutoIt
Вот как я себе это представляю:

Код:
#Include <Memory.au3>

;~ Создаю структуру
$tSCP = DllStructCreate("ptr Buffer;int Width;int Height;")
If @error Then
    MsgBox(0,"","Error in DllStructCreate " & @error);
    Exit
EndIf

;~ Заполняю структуру
DllStructSetData($tSCP, "Width", 320)
DllStructSetData($tSCP, "Height", 240)
$hBuf = _MemGlobalAlloc(DllStructGetData($tSCP, "Width") * DllStructGetData($tSCP, "Height"), 2)
DllStructSetData($tSCP, "Buffer", _MemGlobalLock($hBuf))

;~ Далее. Функция помещает кадр в "Buffer". Возвращает True
$a_Call = DllCall($h_Dll, "int", "Capture", "int", $nDevice, "int*", DllStructGetPtr($tSCP, "Buffer"))
_MemGlobalUnlock($hBuf)

;~ Смотрим. Всё ок. ( Вроде :) )
ConsoleWrite(DllStructGetData($tSCP, "Width") & @CRLF)
ConsoleWrite(DllStructGetData($tSCP, "Height") & @CRLF)
ConsoleWrite(DllStructGetData($tSCP, "Buffer") & @CRLF)


Вопрос собственно такой. Каким образом теперь считать данные из области, выделенной памяти?
Код:
DllStructGetData($tSCP, "Buffer")
возвращает нам (как я понимаю) указатель на первый адрес выделенной памяти, в которой лежит наш кадр.
Почитал Интернет, просмотрел темы на форуме по работе с _MemGlobalAlloc() (спасибо Yashied`у), вроде все предельно ясно.
Но чего-то я делаю неправильно, так как у меня не получается получить картинку.

В примере на C++ данные из буфера можно считать как из массива.
Код:
printf("%c", capture.Buffer[i])
Но дело в том, что в моём примере буфер, таким образом, не прочитать, ведь у нас на выходе указатель на выделенную память, а не массив.

Буду рад любой помощи.
 
Автор
Garrett

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
OffTopic:
Подниму свою тему, если никто не возражает.
Вопрос остается в силе. Буду рад любой информации.
 

sngr

AutoIT Гуру
Сообщения
1,010
Репутация
408
Для элементов, которые являются массивом этот параметр указывает индекс возвращаемого элемента массива, отсчёт с 1. Если параметр опущен или указано ключевое слово Default, тогда возвращается массив целиком (полезно для быстрого извлечения строк). Это о третьем параметре DllStructGetData в справке.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Здесь не нужна _MemGlobalAlloc(). Эту функцию нужно использовать только там, где это требуется (кстати, я про это ничего не говорил :smile:). В большинстве случаев достаточно выделить память из кучи, т.е. DllStructCreate().

Код:
$Width = 320
$Height = 240
$tBuffer = DllStructCreate('byte[' & ($Width * $Height * 4) & ']')
$tSCP = DllStructCreate('ptr Buffer;int Width;int Height')
DllStructSetData($tSCP, 'Buffer', DllStructGetPtr($tBuffer))
DllStructSetData($tSCP, 'Width', $Width)
DllStructSetData($tSCP, 'Height', $Height)
$a_Call = DllCall($h_Dll, 'int', 'Capture', 'uint', $nDevice, 'ptr', DllStructGetPtr($tSCP))
If Not @error Then
	ConsoleWrite('Result: ' & $a_Call[0] & @CR)
	ConsoleWrite('Buffer: ' & DllStructGetData($tBuffer, 1) & @CR)
EndIf
 
Автор
Garrett

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
Yashied огромное вам спасибо! :thanks:

достаточно выделить память из кучи
Да, сначала, я именно так и подошёл к решению этой задачи, но в какой-то момент (когда не получалось получить данные), предположил, что может быть дело в моём неправильном подходе к выделению памяти. Поэтому стал смотреть в сторону _MemGlobalAlloc().
Однако благодаря вашему примеру выше я увидел свою ошибку, и "пасьянс сошёлся" ;D

(кстати, я про это ничего не говорил
smiley.gif
)
Я наверно не так выразился. Я имел в виду, что просматривал ваши примеры, где вы использовали _MemGlobalAlloc(). :smile:

Кстати, если вас не затруднит, не могли бы вы пояснить, в каких случаях используется _MemGlobalAlloc() и почему. :scratch:
Был бы вам очень признателен.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Garrett сказал(а):
Кстати, если вас не затруднит, не могли бы вы пояснить, в каких случаях используется _MemGlobalAlloc() и почему. :scratch:

Например, если в памяти необходимо разместить исполняемый код с последующим его запуском. В этом случае необходимо выделять виртуальную память с флагом PAGE_EXECUTE, в противном случае возникнит конфликт с DEP (если включен). Или в том случае, когда этого требует та или иная функция, например CreateStreamOnHGlobal(). Кроме того, блоки виртуальной памяти являются перемещаемыми.

Для обычных данных целесообразнее использовать стек. Он статический и работать с ним намного проще. Максимальный размер стека, в любом случае, ограничен 2-мя ГБ (по умолчанию). Правда, как я недавно обнаружил, DllStructCreate() медленнее, чем хотелось бы. Это становится заметно при выделении больших блоков памяти. Все из-за того, что она принудительно заполняет выделенную память нулями. Поэтому, в некоторых функциях из WinAPIEx.au3, я выделяю память из собственного стека библиотеки, вместо использования DllStructCreate(). Например, _WinAPI_CreateString().
 
Автор
Garrett

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
Yashied
Благодарю за исчерпывающий ответ. :thanks:
 

Viktor1703

AutoIT Гуру
Сообщения
1,535
Репутация
413
Garret, я так понял вы реализовывали фызов функций из escapi.dll, хотелось бы тоже работать с этой Dll, только начал писать UDF и сразу же проблема, как Вы реализовали вызов функции getCaptureDeviceName() ?


Добавлено:
Сообщение автоматически объединено:

OffTopic:
Всем наверное известно что WebCam UDF не отображает картинку с Web камеры на форме - то есть не работает в Win7, так вот есть такая dll escapi.dll, вот с помощью неё WebCam работает как на XP так и на Win7, на Vista не тестировал, есть пример к этой Dll, правда он на PureBasic, нужно сделать UDF для AutoIt, так как считаю что эта Dll очень полезная вещь
 
Верх