1

Тема: AHK: DllCall и правильный вызов функций.

Добрый день, форумчане. Работаю АСУшником. Программирую контроллеры SIEMENS. Наткнулся на библиотеку snap7.dll которая подключается и читает данные в DB контроллера, состояние контроллера и т.д. Только вот как правильно вызывать эту библиотеку через DllCall я так и не понял. Я даже нашел на Гитхабе чью то функцию с примером работы данной дллки. Но все так же не могу понять некоторые моменты данной программы. Как же дописать нужные вызовы DllCall в функции? Помогите хотя бы разобраться в этих скриптах с вызовами.
S7.ahk

+ открыть спойлер

g_lastError := 0

; S7Area
S7AreaPE := 0x81 	;Process Inputs.
S7AreaPA := 0x82 	;Process Outputs.
S7AreaMK := 0x83 	;Merkers.
S7AreaDB := 0x84 	;DB.
S7AreaCT := 0x1C 	;Counters.
S7AreaTM := 0x1D 	;Timers

; S7WordLength
S7WordLengthBit 	:= 0x01
S7WordLengthByte 	:= 0x02
S7WordLengthWord 	:= 0x04
S7WordLengthDword 	:= 0x06
S7WordLengthReal 	:= 0x08
S7WordLengthCounter := 0x1C
S7WordLengthTimer 	:= 0x1D

; Initialisierung
hModule := DllCall("LoadLibrary", Str, PathCombine(A_ScriptDir, "snap7.dll"))
if(hModule == -1 || hModule == 0) {
	MsgBox, 48, Error, Библиотека snap7.dll не найдена
	ExitApp
}

S7_Create_func := DllCall("GetProcAddress", "UInt", hModule, "Str", "Cli_Create")
S7_Create() {
	global S7_Create_func
	return DllCall(S7_Create_func)
}

S7_ConnectTo_func := DllCall("GetProcAddress", "UInt", hModule, "Str", "Cli_ConnectTo")
S7_ConnectTo(obj, ip, rack, slot) {
	global S7_ConnectTo_func
	return execute(DllCall(S7_ConnectTo_func, "uint", obj, "str", ip, "int", rack, "int", slot))
}

S7_ReadArea_func := DllCall("GetProcAddress", "UInt", hModule, "Str", "Cli_ReadArea")
S7_ReadBit(obj, area, db, offset, bitOffset, bit) {
	global S7_ReadArea_func, S7WordLengthBit
	
	buf := bit ;что это такое?
	bufPtr := &buf
	
	MsgBox, %bufPtr%
	return execute(DllCall(S7_ReadArea_func, "UInt", obj, "Int", area, "Int", db, "Int", offset * 8 + bitOffset, "Int", 1, "Int", S7WordLengthBit, "Ptr", &bufPtr))
}
/*
S7_DBRead_func := DllCall("GetProcAddress", "UInt", hModule, "Str", "Cli_DBRead")
S7_DBRead(obj, db, start, size) {
	global S7_DVRead_func, S7WordLengtByte
	
	buf := byte
	bufPtr := &buf
	
	MsgBox %bufPtr%
	return execute(dllcall(S7_DBRead_func, "Uint", obj, "Int", db, "Int", start, "Int", size, "Ptr", &bufPtr))
}
*/
S7_WriteArea_func := DllCall("GetProcAddress", "UInt", hModule, "Str", "Cli_WriteArea")
S7_WriteBit(obj, area, db, offset, bitOffset, bit) {
	global S7_WriteArea_func, S7WordLengthBit
	
	buf := bit
	bufPtr := &buf
	
	MsgBox, %bufPtr%
	return execute(DllCall(S7_WriteArea_func, "UInt", obj, "Int", area, "Int", db, "Int", offset * 8 + bitOffset, "Int", 1, "Int", S7WordLengthBit, "Ptr", &bufPtr))
}
;а эти функции вообще не используются что ли?
PathCombine(abs, rel) {
    VarSetCapacity(dest, (A_IsUnicode ? 2 : 1) * 260, 1) ; MAX_PATH
    DllCall("Shlwapi.dll\PathCombine", "UInt", &dest, "UInt", &abs, "UInt", &rel)
    Return, dest
}
;а эти функции вообще не используются что ли?
BEint(ByRef Var, ByRef BE, Bytes) {
	VarSetCapacity(BE, Bytes, 0)
	
	loop, %Bytes%
	{
		byte := NumGet(Var, Bytes-A_Index, "UChar")
		NumPut(byte, BE, A_Index-1, "UChar")
		
	}
	
	loop, %Bytes% {
		MsgBox, % NumGet(BE, A_index - 1, "UChar")
	}
}

execute(retn) {
	global g_lastError
	if(retn) {
		g_lastError = retn
	}
	
	return (retn == 0)
}

S7_GetLastError() {
	global g_lastError
	err := g_lastError
	g_lastError := 0
	return err
}

example.ahk

+ открыть спойлер

#SingleInstance, Force
#Include S7.ahk

obj := S7_Create()
ret := S7_ConnectTo(obj, "192.168.1.12", 0, 3) ;(Объект соединения,IP адрес, Рэк, Слот)
MsgBox %ret%

ret := S7_ReadBit(obj, 0x83, 0, 0, 1, 1)	;(obj, area, db, offset, bitOffset, bit) 
error := S7_GetLastError()
MsgBox %ret% `n%error%

;~ result := S7_DBRead(obj, 14, 0, 20)
;~ MsgBox %result%
return
Post's attachments

snap7.dll 217 kb, 5 downloads since 2017-08-02 

You don't have the permssions to download the attachments of this post.

2

Re: AHK: DllCall и правильный вызов функций.

Может с документацией кто то сможет помочь?
https://github.com/SCADACS/snap7/blob/m … refman.pdf

3

Re: AHK: DllCall и правильный вызов функций.

Raven, чтобы проверить эту библиотеку нужны эти самые контроллеры, только где их взять? Не думаю, что у кого-то они есть.

4

Re: AHK: DllCall и правильный вызов функций.

Не не не... Мне нужно просто объяснить как правильно вызывать данные функции через DllCall. И чужие примеры я привел исключительно для того что бы мне помогли разобраться хотя бы в них. Все остальное я сам проверю и уведомлю форум о результатах.

5

Re: AHK: DllCall и правильный вызов функций.

Форумчане, ответе на такой вопрос - почему в коде встречается значок & ?

buf := bit
bufPtr := &buf
return execute(DllCall(S7_ReadArea_func, "UInt", obj,
										 "Int", area,
										 "Int", db,
										 "Int", offset * 8 + bitOffset,
										 "Int", 1,
										 "Int", S7WordLengthBit,
										 "Ptr", &bufPtr)) ;Почему  &bufPtr??? 

Это указатель? Или что? Для чего его туда впихнули то? Почему не обычная переменная?

6 (изменено: stealzy, 2017-08-04 17:37:04)

Re: AHK: DllCall и правильный вызов функций.

Ptr - pointer - указатель. Почему не переменная вопрос к авторам библиотеки, почему ф-ия требует указатель параметром.

7

Re: AHK: DllCall и правильный вызов функций.

Ладно, немного разобрался с вызовом функций. Примерно так.

ReadDB(obj, db, start, size){
	VarSetCapacity(data, 10240000, 0)
	DllCall("snap7.dll\Cli_DBRead", "UInt", obj, "Int", db, "int", start, "int", size, "str", data)
	return data
}

Возник другой вопрос, как правильно получать данные? По идее "data" это строка чисел из DB контроллера. А я не получаю ничего из функции если не ставлю "str". Подскажите как мне получить либо массив данных в "data", либо как из строк вида:

B[®дBTУUBeЄСBB)ЋB{ЗЋAшФ
B[®дBTд
B[К«BTНЗBeµ/BB:9B{Т«Aшк9BG)/
B[ЈЗBTНЗBeµ/BB:9B{јrAшк9BG%{
B[ЈЗBTИ9BeЄСBB:9B{¶дAшк9BG)/
B[©UBTУUBe rBB:9B{¶дAшЅЗBG)/
B[ЈЗBTУUBe rBB:9B{¶дAшЅЗBG%{

получить биты данных. То есть преобразовать в другой формат данных.
Да и вообще, чего то я на форуме не нашел преобразования типов данных из оного в другое. Например из string в ineger, из integer в binary, из binary в string ну и так далее. Не подскажите функции преобразования типов?

8 (изменено: stealzy, 2017-08-08 16:28:19)

Re: AHK: DllCall и правильный вызов функций.

Raven пишет:

на форуме не нашел преобразования типов данных из оного в другое

AutoHotkey - язык с динамической неявной слабой типизацией, поэтому внутри самого языка такой задачи быть не может.
Про ф-ии, превращающие юникод/ansi строки в строки вида "011010001001111010", можно не упоминать.

Raven пишет:

"data" это строка чисел из DB контроллера. А я не получаю ничего из функции если не ставлю "str"

DllCall функции возвращают фиксированный тип, права выбирать тип самому вам никто не давал.
В данном случае видимо некая проблема с кодировкой.
В VarSetCapacity ноль не лишний приписан?
Пример строки, которая должна возвращаться, есть?

9 (изменено: MandarinKa02, 2017-08-09 15:36:53)

Re: AHK: DllCall и правильный вызов функций.

stealzy пишет:

Ptr - pointer - указатель. Почему не переменная вопрос к авторам библиотеки, почему ф-ия требует указатель параметром.

Посылать в фунцию указатель на переменную - выгодно. Если посудить самому, когда в функцию посылаешь значительные данные(от 300 мб - к примеру) то в функции выделяется память для этой переменной(т.е. 300 мб). А зачем еще 300 мб выделять? Если можно выделить 8 байт, в которых будет указатель на эти 300 мб.
В итоге: при работе с указателем - 300,8 мб. При работе напрямую - 600 мб

Начинающий скриптер.
По вопросам сюдой: Skype: live:ddeeeennn

10 (изменено: Raven, 2017-08-09 16:12:42)

Re: AHK: DllCall и правильный вызов функций.

Тогда такой вопрос. Вот выдержка из документации по DLL:


int Cli_DBRead(S7Object Client, int DBNumber, int Start, int Size, 
    void *pUsrData); 
 
function Cli_DBRead(Client : S7Object; DBNumber, Start,  
    Size : integer; pUsrData : pointer) : integer; 
+ открыть спойлер
  • Client - Native Integer - The handle as return value of Cli_Create(), passed by value.

  • DBNumber - integer - DB Index (0..0xFFFF).

  • Start - integer - Offset to start

  • Size - integer - Size to read (bytes)

  • pUsrData - Pointer to memory area - Pointer user buffer.

Это мой код:

ret := ReadDB(obj, 110, 8, 4)
Msgbox %ret%
ReadDB(obj, db, start, size){
	;global obj
	VarSetCapacity(data, 10240000, 0)
	DllCall("snap7.dll\Cli_DBRead", "UInt", obj, "Int", db, "int", start, "int", size, "str", data)
	return data
}

Правильно ли я в своем коде использую  "str", data , если в документации сказано "pUsrData - Pointer to memory area - Pointer user buffer" ??? Если нет, то как будет правильно?

11

Re: AHK: DllCall и правильный вызов функций.


"ptr", &data)

"ptr" интерпретируется, как "uint" или "int64" в зависимости от разрядности (32/64) интерпретатора АНК, выполняющего код.

12

Re: AHK: DllCall и правильный вызов функций.

Raven

pUsrData - Pointer to memory area - Pointer user buffer

Pointer - указатель.

Начинающий скриптер.
По вопросам сюдой: Skype: live:ddeeeennn

13

Re: AHK: DllCall и правильный вызов функций.

Охренеть, в документации написан указатель, а вы переменную пихаете.
Вызывайте так тогда, чего уж:

DllCall("snap7.dll\Cli_DBRead", "сделатьмнехорошо", x)

14 (изменено: Raven, 2017-08-09 16:43:41)

Re: AHK: DllCall и правильный вызов функций.

stealzy Ну подскажите как нужно правильно запихнуть туда указатель. То я его как только дуда не пихал... Я так понимаю что нужно сначала объявить переменную а потом уже указатель на нее, поместить в функцию. Только как это сделать то?

15

Re: AHK: DllCall и правильный вызов функций.

YMP вам уже написал. Как вас вообще к контроллерам не боятся пускать ;-)?

16

Re: AHK: DllCall и правильный вызов функций.

В контроллерах проще все. :-) мне вот такой код легче читать чем разбираться в указателях DllCall Autohotkey'я :-)

+ открыть спойлер
 
      L     DB110.DBD  352
      L     9.500000e+001
      >R    
      S     M     90.0

      AN    I     16.0                
      FR    T     58
      L     S5T#5S                     
      SD    T     58

      A     T     58
      S     M     90.0

Туплю я че то с этими dllcall... Вот не получается у меня выковырнуть данные из этих указателей...

17

Re: AHK: DllCall и правильный вызов функций.

А разве строка не передаётся в DllCall указателем и следующие вызовы не делают одно и то же?

DllCall("MyFunc", "Str", "Hello!")

s := "Hello"
DllCall("MyFunc", "Str", s)

DllCall("MyFunc", "Ptr", &s)

DllCall("MyFunc", "Ptr", &(s := "Hello!"))

18

Re: AHK: DllCall и правильный вызов функций.

wisgest
В AHK - нет. По крайне мере у меня так не выходит) А в c++ может быть и работает

Начинающий скриптер.
По вопросам сюдой: Skype: live:ddeeeennn

19 (изменено: teadrinker, 2017-08-10 02:08:27)

Re: AHK: DllCall и правильный вызов функций.

Это легко проверить:

str := "привет"
DllCall("CharUpper", Str, str)
MsgBox, % str

str := "привет"
DllCall("CharUpper", Ptr, &str)
MsgBox, % str
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

20

Re: AHK: DllCall и правильный вызов функций.

teadrinker, у меня оба раза

---------------------------
test.ahk
---------------------------
ПРИВЕТ
---------------------------
ОК   
---------------------------

21

Re: AHK: DllCall и правильный вызов функций.

У меня тоже.
А ещё нагляднее так:

addr := RegisterCallback("MyFunc")
DllCall(addr, Str, "привет")

MyFunc(pStr)  {
   MsgBox, % pStr . "`n" . StrGet(pStr)
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

22

Re: AHK: DllCall и правильный вызов функций.

Передавать буфер, как строку, не стоит по той же причине, по которой не стоит писать "тоже" вместо "то же" и наоборот. Хотя произносится и одинаково, но разное написание облегчает восприятие текста. Мозгу не приходится выводить смысл из контекста.

По той же причине мне не нравятся вещи вроде


, Str, str)

23

Re: AHK: DllCall и правильный вызов функций.

Про «"тоже" вместо "то же"» не понял. Разве у меня неправильно?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

24

Re: AHK: DllCall и правильный вызов функций.

Нет, это я просто как пример привёл.

25

Re: AHK: DllCall и правильный вызов функций.

YMP пишет:

мне не нравятся вещи вроде

, Str, str)

Мне тоже. А вот так нравится

, "Str", str)