Что нового

Как передать , получить и сохранить данные из DLL

StarEdik

Новичок
Сообщения
365
Репутация
4
Привет всем !!!
Я мало знаком с dll и не уверен в правильности с использованием dll в autoit.Написал скрипт, но не могу получать данные .
Код:
Global Const $SEFLG_SWIEPH  = 2   
Global Const $SEFLG_MOSEPH  = 4  
Global Const $SEFLG_SPEED   = 256 
Global Const $SEFLG_TRUEPOS = 16 
Global $JD ,$pl , $iflag , $serr  ,$Plcc , $result , $x[6]

$JD=2456050.74931
$pl=0 ;(0,1,2,3,4,5,6,7,8,9)
;$iflag = $SEFLG_TRUEPOS + $SEFLG_SWIEPH 
$iflag = $SEFLG_SPEED + $SEFLG_MOSEPH  
$Plcc =$x[0]
$serr =String(255)

_PLC()
Func _PLC()
 $Dll2 = DllOpen(@ScriptDir & "\swedll32.dll")
  $Asp2 ='_swe_calc_ut@24'
   $result2 = DllCall($dll2, "long", $Asp2,"double",$JD,"int",$pl,"int",$iflag,"double",$Plcc,"str",$serr)
  
 ConsoleWrite(' 1 $Asp2- ' & VarGetType($Asp2) & @CRLF &  " 2 $JD- " & VarGetType($JD) & @CRLF & " 3 $pl- " & VarGetType($pl) & @CRLF )
 ConsoleWrite( " 4 $iflag- " & VarGetType($iflag) & @CRLF & " 5 $Plcc- " & VarGetType($Plcc) & @CRLF  & " 6 $serr- " & VarGetType($serr) & @CRLF )

 If @error or Not($result2) Then MsgBox(4096, "Error", "Error = " & @error)
 	 ConsoleWrite('OK: ' & $x[0] & @CRLF  & $result2[0] &@CR) ;
 DllClose($Dll2)

EndFunc
Данные из DLL получаю с помощью VB6 и через макроса Excel.
Используется это функция так
Код:
Private Declare Function swe_calc_ut Lib "swedll32.dll" _
        Alias "_swe_calc_ut@24" ( _
          ByVal tjd_ut As Double, _
          ByVal ipl As Long, _
          ByVal iflag As Long, _
          ByRef x As Double, _
          ByVal serr As String _
        ) As Long   ' x must be first of six array elements
                    ' serr must be able to hold 256 bytes

Информация извлекается так (простой пример)

Private Sub Plc_Click()
 Dim x(6) As Double
   JD = 2456051.71277778
   pl = 0
   iflag = 260
   serr$ =  String(255, 0)
Call swe_calc_ut(JD, pl, iflag, x(0), serr$)
Label1.Caption = x(0)
For i =0 to 5
  List1.Additem x(i)
Next i
DoEvents

End Sub

Про DLL
Код:
Имя функции  в dll  « _swe_calc_ut@24 » ( DLL Export Viewer )
The call parameters
int swe_calc_ut ( double tjd_ut, int ipl, int iflag, double* xx, char* serr),
where
tjd_ut     =Julian day, Universal Time
ipl       =body number
iflag    =a 32 bit integer containing bit flags that indicate what kind of computation is wanted
xx       =array of 6 doubles for longitude, latitude, distance, speed in long., speed in lat., and speed in dist.
serr[256] =character string to return error messages in case of error.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
1. Нет в AutoIt такого типа "int32", есть "int".
2. DllCall() возвращает массив (см. справку), значение, возвращаемое функцией, находится в первом элементе массива - $result2[0].
3. После вызова DllCall() нужно всегда проверять флаг @error на наличие ошибки.
 
Автор
StarEdik

StarEdik

Новичок
Сообщения
365
Репутация
4
Yashied
Спасибо.Пробовал .Но ничего не получается .Вы дается "Ошибка Приложения" .память не может быть "Written"
А вот другая функция у меня работает.
Код:
$Asp ='_swe_difdeg2n@16'
$result = DllCall($dll, "double", $Asp,"double",$x,"double",$y)
;$result = DllCall($dll, "double", "_swe_difdeg2n@16",'double',$x,'double',$y)
If @error Then
    MsgBox(4096, "Error", "Error = " & @error)
Else
	  MsgBox(4096, "Result", "Result = " & Abs($result[0]),2)
	  ConsoleWrite('OK: ' & $result[0] & @CR) ;100,642184

EndIf
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Первое, что нужно сделать перед использованием dll - ОЧЕНЬ внимательно прочитать, перечитать, а затем еще раз перечитать описание функции, особенно, если она не совсем тривиальная.

StarEdik сказал(а):
...xx = array of 6 doubles for longitude, latitude, distance, speed in long., speed in lat., and speed in dist...

Код:
Global Const $SEFLG_MOSEPH = 4
Global Const $SEFLG_SPEED = 256

$tPlanet = DllStructCreate('double[6]')
$Ret = DllCall('swedll32.dll', 'int', '_swe_calc_ut@24', 'double', 2456050.74931, 'int', 0, 'int', BitOR($SEFLG_SPEED, $SEFLG_MOSEPH), 'ptr', DllStructGetPtr($tPlanet), 'str', '')
If @error Then
	MsgBox(16, '', 'DllCall() error: ' & @error)
Else
	If $Ret[0] < 0 Then
		MsgBox(16, '', 'swe_calc_ut() error: ' & $Ret[5])
	Else
		ConsoleWrite('Longitude:      ' & DllStructGetData($tPlanet, 1, 1) & @CR)
		ConsoleWrite('Latitude:       ' & DllStructGetData($tPlanet, 1, 2) & @CR)
		ConsoleWrite('Distance:       ' & DllStructGetData($tPlanet, 1, 3) & @CR)
		ConsoleWrite('Speed in long.: ' & DllStructGetData($tPlanet, 1, 4) & @CR)
		ConsoleWrite('Speed in lat.:  ' & DllStructGetData($tPlanet, 1, 5) & @CR)
		ConsoleWrite('Speed in dist.: ' & DllStructGetData($tPlanet, 1, 6) & @CR)
	EndIf
EndIf
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
Yashied
Я сейчас тоже писал пример на эту функцию, и хотел бы уточнить у Вас, а char* не нужно в Autoit представлять как str*
Код:
$pSerr = DllStructCreate("char[256]")
DllStructSetData($pSerr, 1, "текст")
;...
$a_Ret = DllCall($Dll, "long", "_swe_calc_ut@24", "double", $JD, "int", $pl, "int", $iflag, "ptr", DllStructGetPtr($Plcc), "str*", DllStructGetPtr($serr))
 
Автор
StarEdik

StarEdik

Новичок
Сообщения
365
Репутация
4
Yashied
Просто нет слов.Спасибо за удовлетворительный ответ.БЛАГОДАРЮ
Garrett
Вам тоже большое спасибо
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Garrett

Можно и так, но это лишнее:

Код:
DllStructSetData($pSerr, 1, "текст")


т.к. функция не использует эти данные, а возврашает в этом параметре строку с описанием ошибки в случае таковой. А еще, в этом случае нужно использовать адрес структуры, а не "str*":

Код:
$tErr = DllStructCreate("char[256]")
$Ret = DllCall($Dll, "int", "_swe_calc_ut@24", "double", $JD, "int", $pl, "int", $iflag, "ptr", DllStructGetPtr($Plcc), "ptr", DllStructGetPtr($tErr))


А вообще, что происходит, когда вы пишите "str" или "wstr" в функции DllCall()? Все очень просто. DllCall() автоматически выделяет память под строку (не менее 64 КБ) и освобождает ее по завершению, возвращая в массиве саму строку. Таким образом, это избавляет вас от лишнего кода + выигрыш в скорости.

P.S

"str" эквивалентна следующей конструкции:

Код:
$tStr = DllStructCreate('char[65536]')
DllStructSetData($tStr, 1, ...)
DllCall(..., 'ptr', DllStructGetPtr($tStr))


"str*" представляется так:

Код:
$tStr = DllStructCreate('char[65536]')
DllStructSetData($tStr, 1, ...)
$tPtr = DllStructCreate('ptr')
DllStructSetData($tPtr, 1, DllStructGetPtr($tStr))
DllCall(..., 'ptr', DllStructGetPtr($tPtr))
 
Автор
StarEdik

StarEdik

Новичок
Сообщения
365
Репутация
4
Yashied
Так мне еще понятнее стало.СПАСИБО
Тему пока не закрываю, потому что есть еще несколько недоработанных функции. Если что буду очень благодарен за вашу помощь.
 

Garrett

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

StarEdik

Новичок
Сообщения
365
Репутация
4
Yashied
В этой функции объявляется местонахождение файлов. Ну не получается у меня. Прошу вашей помощи. Исправьте мои ошибки, пожалуйста
Код:
Func _PathEfem()
Local $Res ,$tPathEf ,$tPathStr ,$pSerr

$tPathStr = DllStructCreate('Char[256]',@ScriptDir & "\ephe")
;$pSerr = DllStructCreate("char[256]")
;DllStructSetData($pSerr, 1, @ScriptDir & "\ephe")

;$Res = DllCall(@ScriptDir & "\swedll32.dll",'int',"_swe_set_ephe_path@4","str*",DllStructGetPtr($pSerr))
$Res = DllCall(@ScriptDir & "\swedll32.dll",'int',"_swe_set_ephe_path@4","prt",DllStructGetPtr($tPathStr))

If @error Then MsgBox(16, '', 'DllCall() error: ' & @error)
;ConsoleWrite('DirEpheFile : ' & DllStructGetData($pSerr,1) & $Res[0] & @CR)
EndFunc

Про DLL
Код:
swe_set_ephe_path()
If the environment variable SE_EPHE_PATH  exists in the environment where Swiss Ephemeris is used, its content is used to find the ephemeris files. The variable can contain a directory name, or a list of directory names separated by ; (semicolon) on Windows or : (colon) on Unix. 
int swe_set_ephe_path(char *path);
 
Usually an application will want to set its own ephemeris path by calling swe_ephe_path(), e.g.
swe_set_ephe_path(”C:\\SWEPH\\EPHE”);
 
The argument can be a single directory name or a list of directories, which are then searched in sequence. The argument of this call is ignored if the environment variable SE_EPHE_PATH exists and is not empty.
If you want to make sure that your program overrides any environment variable setting, you can use putenv() to set it to an empty string. 
 If the path is longer than 256 bytes, swe_set_ephe_path() sets the path \SWEPH\EPHE instead.
If no environment variable exists and swe_set_ephe_path() is never called, the built-in ephemeris path is used. On Windows it is ”\sweph\ephe” relative to the current working drive, on Unix it is "/users/ephe".
Set directory path of ephemeris files
int swe_set_ephe_path(char *path);
 
/* set name of JPL ephemeris file */
int swe_set_jpl_file(char *fname);
 
/* close Swiss Ephemeris */
void swe_close(void);
 

Garrett

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

StarEdik

Новичок
Сообщения
365
Репутация
4
Эта функция должен запускается из предыдущего скрипта (которую написал Yashied ) для точного вычисления .Я по рекомендациям все пробовал. Но безуспешно. Может кто нить поможет.
Код:
$tPathStr = DllStructCreate('char[65536]')
DllStructSetData($tPathStr, 1, @ScriptDir & "\ephe\")
$Ret = DllCall(@ScriptDir & "\swedll32.dll", 'int',"_swe_set_ephe_path@4",'ptr',DllStructGetPtr($tPathStr))
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
Вы явно не хотите слышать, о чём вам говорят
Код:
$aRet = DllCall("swedll32.dll", "int", "_swe_set_ephe_path@4", "str", @ScriptDir & "\ephe")
 
Автор
StarEdik

StarEdik

Новичок
Сообщения
365
Репутация
4
Жаль, но это тоже не помогло. Хотя я так уже пробовал.
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
StarEdik [?]
это тоже не помогло
Что значит, не помогло! Вы сами с собой разговариваете? :smile:
Где данные, ошибки и т.д.

Лично у меня ваша функция отдаёт "int" = 64
 
Автор
StarEdik

StarEdik

Новичок
Сообщения
365
Репутация
4
Garrett
Спасибо вам.
Лично у меня ваша функция отдаёт "int" = 64
Я получал с разными вызовами разные показания – 10 , 13 , 34 ,64
Как уже вы знаете, запускается из вызывавшей функции каждый раз при вызове и указывает ему путь к файлу «C:\sweph\ephe\sepl_18.se1». В саму библиотеку встроены данные, но не точные. А в файле sepl_18.se1 данные точные. Если не использовать этот файл то в расчетах будут отклонении .Например.
Без использования файла sepl_18.se1 - 46.1128480023918
С файлом sepl_18.se1 - 46.11285642
Как видно хоть малость, но есть разница.Дело в том что этот вызов нужен и другим функциям.Запустите пожалуйста скрипт с и без указания пути к файлу sepl_18.se1 ( 473 кб ). ftp://ftp.astro.com/pub/swisseph/ephe/sepl_18.se1
Код:
Global $JD ,$pl ,$Plcc
$JD = 2456053.74068287
$pl = 0
_PLC($JD,$pl)
ConsoleWrite('Longitude Plcc                            :      ' & $Plcc & @CR) ;46.1128480023918
ConsoleWrite('Longitude Plcc with sepl_18.se1 :      ' & '46.11285642 ' & @CR) ;46.11285642

Func _PLC($JuDy,$plnt)

Local $tPlanet , $iflag , $Ret ,$tPath ,$tPathStr
Const $SEFLG_SWIEPH  = 2
Const $SEFLG_MOSEPH  = 4
Const $SEFLG_SPEED   = 256
Const $SEFLG_TRUEPOS = 16
_PathEfem()
$iflag = $SEFLG_TRUEPOS + $SEFLG_SWIEPH
;$iflag = $SEFLG_SPEED + $SEFLG_MOSEPH
$tPlanet = DllStructCreate('double[6]')
$Ret = DllCall(@ScriptDir & "\swedll32.dll", 'int', '_swe_calc_ut@24', 'double', $JuDy, 'int', $plnt, 'int', $iflag, 'ptr', DllStructGetPtr($tPlanet), 'str', '')
If @error Then
    MsgBox(16, '', 'DllCall() error: ' & @error)
Else
    If $Ret[0] < 0 Then
        MsgBox(16, '', 'swe_calc_ut() error: ' & $Ret[5])
    Else
        $Plcc = DllStructGetData($tPlanet, 1, 1)
    EndIf
EndIf
Return $Plcc
EndFunc

Func _PathEfem()
Local $Ret ,$tPathEf ,$tPathStr ,$tErr

$aRet = DllCall("swedll32.dll", "int", "_swe_set_ephe_path@4", "str", @ScriptDir & "\ephe")
ConsoleWrite('ScriptDir: ' & $Ret & @CR )
If @error Then MsgBox(16, '', 'DllCall() error: ' & @error)

EndFunc

Декларируется как Sub
Код:
Private Declare Sub swe_set_ephe_path Lib "swedll32.dll" _
        Alias "_swe_set_ephe_path@4" ( _
          ByVal path As String _
        )

Вызывается так
Call swe_set_ephe_path("c:\sweph\ephe")
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
StarEdik
Я советую вам уделить больше внимания на изучение документации к модулю "Швейцарских эфемерид". Так же почитайте AutoIt3.chm (раздел "Process Management"), в частности про работу с DLL.

Код:
Global Const $SE_GREG_CAL = 1
Global Const $SE_SUN = 0
Global Const $SE_VESTA = 20
Global Const $SE_EARTH = 14
Global Const $SEFLG_SPEED = 256

Global $h_Dll = DllOpen("swedll32.dll")
If $h_Dll = -1 Then
	MsgBox(16, @ScriptName, "Dll not found!")
	Exit
EndIf

_SWE_SetEphePath(@ScriptDir & "\ephe") ; нужен файл seas_18.se1 (220Kb) но форум не позволяет загрузить более 200 Kb 
$iJDUT = _SWE_JulDay(@YEAR, @MON, @MDAY, (@HOUR + @MIN / 60 + @SEC / 3600), $SE_GREG_CAL)

; ConsoleWrite
ConsoleWrite('>------------------------------------------------------' & @CR )
ConsoleWrite('! Date: ' & @YEAR&'-'&@MON&'-'&@MDAY &' '& @HOUR&':'&@MIN&':'&@SEC & @CR )
ConsoleWrite('! Julian Date: ' & $iJDUT & @CR )
ConsoleWrite('>------------------------------------------------------' & @CR )

For $i = $SE_SUN To $SE_VESTA
	If ($i == $SE_EARTH) Then ContinueLoop
	ConsoleWrite('! Planet Name: ' & _SWE_GetPlanetName($i) & @CR )
	$pXX = _SWE_CalcUT($iJDUT, $i, $SEFLG_SPEED)
	If Not @error Then
		ConsoleWrite('Longitude:      ' & DllStructGetData($pXX, 1, 1) & @CR)
		ConsoleWrite('Latitude:       ' & DllStructGetData($pXX, 1, 2) & @CR)
		ConsoleWrite('Distance:       ' & DllStructGetData($pXX, 1, 3) & @CR)
		ConsoleWrite('Speed in long.: ' & DllStructGetData($pXX, 1, 4) & @CR)
		ConsoleWrite('Speed in lat.:  ' & DllStructGetData($pXX, 1, 5) & @CR)
		ConsoleWrite('Speed in dist.: ' & DllStructGetData($pXX, 1, 6) & @CR)
	EndIf
	ConsoleWrite('>------------------------------------------------------' & @CR )
Next
; End ConsoleWrite

DllClose($h_Dll)

Func _SWE_JulDay($i_Year, $i_Month, $i_Day, $d_Hour, $i_Flag) ; double
	
	$a_Ret = DllCall($h_Dll, "double", "_swe_julday@24", "int", $i_Year, "int", $i_Month, "int", $i_Day, "double", $d_Hour, "int", $i_Flag)
	If @error Then
		MsgBox(16, '_SWE_JulDay()', 'DllCall error: ' & @error)
	EndIf
	
	Return $a_Ret[0]
EndFunc	;==>_SWE_JulDay

Func _SWE_SetEphePath($s_Path) ; void
	
	$a_Ret = DllCall($h_Dll, "int", "_swe_set_ephe_path@4", "str", $s_Path)
	If @error Then
		MsgBox(16, '_SWE_SetEphePath()', 'DllCall error: ' & @error)
	EndIf
EndFunc	;==>_SWE_SetEphePath

Func _SWE_CalcUT($i_JDUT, $i_Pl, $i_Flag) ; ptr
	
	Local $p_XX = DllStructCreate('double[6]')
	
	$a_Ret = DllCall($h_Dll, "int", "_swe_calc_ut@24", "double", $i_JDUT, "int", $i_Pl, "int", $i_Flag, "ptr", DllStructGetPtr($p_XX), "str", "")
	If @error Then
		MsgBox(16, '_SWE_CalcUT()', 'DllCall error: ' & @error)
	Else
		If $a_Ret[0] < 0 Then
			MsgBox(16, '', '_SWE_CalcUT() error: ' & $a_Ret[5])
			Return SetError(1, 0, 0)
		Else
			Return SetError(0, 0, $p_XX)
		EndIf
	EndIf
EndFunc	;==>_SWE_CalcUT

Func _SWE_GetPlanetName($i_Pl) ; string
	
	$a_Ret = DllCall($h_Dll, "str", "_swe_get_planet_name@8", "int", $i_Pl, "str", "")
	If @error Then
		MsgBox(16, '_SWE_GetPlanetName()', 'DllCall error: ' & @error)
	EndIf
	
	Return $a_Ret[2]
EndFunc	;==>_SWE_GetPlanetName
 
Автор
StarEdik

StarEdik

Новичок
Сообщения
365
Репутация
4
Garrett
Большое человеческое вам спасибо. :smile:
Я советую вам уделить больше внимания на изучение документации к модулю "Швейцарских эфемерид". Так же почитайте AutoIt3.chm (раздел "Process Management"), в частности про работу с DLL.
Совет принял :-[.Буду изучать дальше.Проста интересно
sepl_18.se1 - для планет а seas_18.se1 - для астероид??? :scratch:
http://www.saravali.de/articles/calc_ephemfiles.html
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
StarEdik [?]
sepl_18.se1 - для планет а seas_18.se1 - для астероид???
Я сильно не вникал, но в примере выше, как я понял c $i = 15 по 20 выводятся основные астероиды (Хирон, Фол, Церара, Плалада, Юнона, Веста)
 
Верх