Что нового

[Интеракция] Получить массив из функции находящейся в dll

asdf8

Скриптер
Сообщения
564
Репутация
152
Нашел в нете dll позволяющую передавать массив с данными между приложениями, но не могу
разобраться, как вернуть массив.

самодеятельность:
Код:
#Include <Array.au3>

$sName='One'
$dll = DllOpen("GlobalArray.dll")

$dat=StringSplit('2,8,6,9,3,8,5,5',',')
_ArrayDisplay($dat,'Передаваемый массив')

$a=DllStructCreate('double[' & UBound($dat) & ']')
For $i=0 To UBound($dat)-1
	DllStructSetData($a,1,$dat[$i],$i+1)
Next
$result = DllCall($dll,'int','GlobalArraySet','str',$sName,'ptr', DllStructGetPtr($a),'int',UBound($dat))
If @error=0 And $result[0]=0 Then MsgBox(0,'','Создан глобальный массив : ' & $sName)

$result1 = DllCall($dll,'int','GlobalArraySize','str',$sName)
If @error=0 And $result[0]>0 Then MsgBox(0,'','Размер глобального массива : ' & $sName & @LF & $result[0])

$b=DllStructCreate('double['&$result1[0]&']')
$result2 = DllCall($dll,'int','GlobalArrayGet','str',$sName,'ptr', DllStructGetPtr($b),'int',UBound($dat))
Dim $arOUT[$result1[0]]
For $i=1 To UBound($dat)
	$arOUT[$i-1]=DllStructGetData($b,1,$i)
Next
_ArrayDisplay($arOUT,'Полученный массив')

$result3 = DllCall($dll,'int','GlobalArrayDelete','str',$sName)
_ArrayDisplay($result1,'Удаление GlobalArray')

$result1 = DllCall($dll,'int','GlobalArraySize','str',$sName)
_ArrayDisplay($result1,'Размер GlobalArray')


DllClose($dll)


В общем я настолько мало знаком с использованием dll в autoit, что не уверен в правильности
передачи массива в функцию. И тем более не могу получить передаваемый по указателю
массив из функции.
Помогите пожалуйста разобраться.
 
Автор
A

asdf8

Скриптер
Сообщения
564
Репутация
152
amel27 сказал(а):
Если оно не для AutoIT, почему другие параметры передаются?
В общем-то вопрос был о возврате оттуда массива (и еще, возможно, передачи массива туда).
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5 379
Репутация
2 702
Ну, передается туда (от туда) указатель на массив, а не сам массив. Стало быть прикрутить этот Dll к AutoIt очень даже можно. Но вот вопрос: нужно ли это делать? Существует целый вагон и маленькая тележка других способов передачи данных между скриптами...
 

amel27

Продвинутый
Сообщения
146
Репутация
55
Yashied сказал(а):
прикрутить этот Dll к AutoIt очень даже можно
AFAIK AutoIT не позволяет восстановить массив из указателя, т.е. для этого нужно знать бинарное представление массива (для элементов Variant я это себе плохо представляю)... Между тем может же AutoIT принимать/передавать массивы COM-объектов (тот же WSH или WMI)?
 

killbond

Осваивающий
Сообщения
96
Репутация
32
amel27

Тоже мучался? ))) вот и я, пробовал создать нечто наподобие UDF библиотеки и вот что у меня пока получилось:

Код:
$Dll = DllOpen("GlobalArray.dll")
#comments-start
=Описание параметров=
$sName - 	имя массива для объявления
$aArray -	сам массив для объявления
$sType -	тип присваиваемых данных (если не указан, то 'Int')
#comments-end

Func _GlobalArraySet($sName, $aArray, $sType = "int")
	; Проверка, задан ли тип данных, если нет, то присвоить стандартный 'Int'
	
	Local $pArrayPtr, $i, $tArrayStr = DllStructCreate ( $sType & "[" & UBound( $aArray ) & "]" )
	; Т.к. должен быть передан именно указатель на массив, а указатель можно получить только из структуры, то ее и создадим.
	
	For $i = 0 to ( UBound( $aArray ) - 1 ) 
		DllStructSetData ($tArrayStr, 1, $aArray [$i], $i)
	Next
	; В этом цикле массив записывается в созданную ранее структуру такой же размерности...
	
	$pArrayPtr = DllStructGetPtr($tArrayStr, 1) 
	; Получить указатель на структуру с нашим массивом
	
	$result = DllCall($Dll, "int", "GlobalArraySet", "str", $sName, "str", $pArrayPtr, "int", UBound($aArray))
	; Передать данные Dll на обработку...
	
	if  $result [0] = 0 then
		Local $result1 [3] = [$result [1], $result [2], $result [3]]
	Else
		SetError ($result [0])
	EndIf
	; Обработка ошибок - если Dll таковые выдала - то вывести их в Error если таких нет (0) то вывести массив 
	; [0] - Имя
	; [1] - Указатель
	; [2] - Размерность
	
	Return $result1
	; Вывести результат
EndFunc

#comments-start
=Описание параметров=
$sName - 	Имя массива, из которого требуется взять значения ранее созданного _GlobalArraySet
$aArray - 	массив, в который требуется занести значения 
$sType -	Тип присваиваемых данных (если не указан, то 'Int')
#comments-end

Func _GlobalArrayGet($sName, $aArray, $sType = "int")
	;GlobalArrayGet(char *ID, double *Array, const int ArraySize)
	Local $result, $ArraySize, $pArrayPtr, $tArray = DllStructCreate ( $sType & "[" & UBound( $aArray ) & "]" )
	; Т.к. должен быть передан именно указатель на массив, а указатель можно получить только из структуры, то ее и создадим.
	
	$ArraySize = UBound($aArray)
	; Размерность массива
	
	For $i = 0 to $ArraySize - 1 
		DllStructSetData ($tArray, 1, $aArray [$i], $i)
	Next
	; В этом цикле массив записывается в созданную ранее структуру такой же размерности...
	
	$pArrayPtr = DllStructGetPtr($tArray, 1)
	; Получить указатель на структуру с нашим массивом
	
	$result = DllCall($Dll,'int','GlobalArrayGet','str',$sName, "str", $pArrayPtr, "int", $ArraySize)
	; В Dll функция ищет массив под приведенным именем $sName если не находит, то возвращает 1
	; Если находит, то присваивает массиву под приведенным указателем значения массива $sName
	
	
	If $result [0] = 1 Then
		SetError ( $result [0] )
		Return ( $result [0] )
	EndIf
	; Нужно проверить, какое значение вернула предыдущая функция если 1, то это ошибка
	
	If $result [0] = 0 Then
		For $i = 0 to $ArraySize - 1
			$aArray [$i] = DllStructGetData ( $tArray, 1, $i )
			Return $aArray
		Next
	EndIf
	Return $result
EndFunc


И вся проблема как раз в том, что
AutoIT не позволяет восстановить массив из указателя
Но в этом коде я пробовал оперировать не именно с массивом, а со структурой, а можно ли восстановить структуру, мне пока неизвестно (((

asdf8

Ошибка в твоем коде в том, что ты передаешь именно массив функции GlobalArraySet а по исходнику Dll'ки требуется указатель... кстати, судя по исходнику, эта Dll может работать только с одномерными массивами.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5 379
Репутация
2 702
killbond сказал(а):
DllCall($Dll, 'int', 'GlobalArrayGet', 'str', $sName, 'str', $pArrayPtr, 'int', $ArraySize)
Если $pArrayPtr у тебя указатель, то почему ты используешь тип "str"? Кроме того, функция GlobalArrayGet() в случае успеха возвращает не 0.
 

killbond

Осваивающий
Сообщения
96
Репутация
32
Если $pArrayPtr у тебя указатель, то почему ты используешь тип "str"?
раз указатель в формате "0х00000000" то для него, наверное, больше подходит тип "str"...

Кроме того, функция GlobalArrayGet() в случае успеха возвращает не 0.
Я то думал, что надо смотреть на метод:
Код:
GlobalArray::RetrieveValues()
раз он выводит 0 в случае успеха, вот я и решил, значит и GlobalArrayGet() выводит 0... на практике оказалось выводится массив, где:
Код:
[0] - код ошибки (0)
[1] - имя массива (при чем именно того, который указан как источник - char *ID)
[2] - указатель на него
[3] - размер


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

Значит все указатели идут под типом "ptr"?
 
Автор
A

asdf8

Скриптер
Сообщения
564
Репутация
152
Да, ребята, вы были правы - фокус с интеракцией не удался. Немного сам поразбирался со структурированием данных. Как только закрываеш dll информация перестает быть видна даже из текущего скрипта, не говоря уже о другом скрипте.
В общем для меня важнее той интеракции было попробывать поработать с dll.

PS:В общем тему считаю решенной. Сейчас обновлю пример в первом посте.
 
Верх