Тема: AHK: COM Port terminal
Программа для работы с COM-портом.
Возможности:
- автоматический поиск порта;
- чтение данных с порта;
- всевозможные типы представления данных (бинарные данные, символ, шестнадцатеричное, десятичное, 1 2 4 8 байта, значение с точкой);
- фильтрация данных (правой кнопкой по таблице);
- построение графика по выбранному типу данных онлайн (правой кнопкой мыши на нужное число в таблице, программа ориентируется по смещению от первого принятого байта пакета, данные не отрисовываются если контрольная сумма не совпадает (если выбрана контрольная сумма));
- сохранение, загрузка собранных данных буфера приема;
- анализ пакетов данных (группировка по одинаковым признакам);
- отправка данных в порт;
- добавление контрольной суммы к данным (1 байт CRC, 2 байта CRC, Modbus RTU);
- настройки параметров CRC-16;
- расшифровка модбас сообщений (при условии что данные приняты корректно);
- построение графиков на основе данных из порта онлайн;
- до 12-ти графиков с возможностью отключать ненужные;
- сохранение графика в файл в виде изображения.
- свободный формат разделителя (например: "123,456,789;" или "123I456I789]" - одна точка трёх графиков);
- настройки нигде не сохраняются;
- программа разделена на два потока: в первом крутится интерфейс и обрабатываются данные, во втором происходит работа с COM портом. Теперь данные практически не дробятся на несколько пакетов и обрабатываются как единый блок;
- добавлена настройка "Пропуск пакетов" - правый клик на информационную строку "В обработке Х". На случай если нужны данные в текущем времени, чтобы не ждать обработку всех накопившихся пакетов, если они поступают быстрее чем обрабатываются;
- добавлена настройка "ReadIntervalTimeout" (Максимальное время, которое может пройти до поступления следующего байта в линию связи, в миллисекундах.) Для более точного разделения данных на пакеты. Настройка определяется автоматически в зависимости от параметров порта, но есть возможность ввести вручную.
- добавлена "Карта регистров Modbus" (возможности: сохранять и загружать сохраненные карты модбас; выбрать приоретный регистр для опроса чаще остальных; изменение значения Holding регистров; изменение адреса устройства для выбранных регистров)
В будущем думаю добавить Modbus TCP. (но это не скоро)
Version:="3.5"
#SingleInstance,off
#NoEnv
;ListLines,Off
#KeyHistory,0
AutoTrim,Off
CoordMode,Mouse,Screen
CoordMode,ToolTip
CoordMode,Pixel
CoordMode,Caret,Screen
DetectHiddenWindows,On
FloatFormat:=3
Menu,Tray,UseErrorLevel
Menu,Tray,NoIcon
SendMode,Input
SetBatchLines,-1
SetControlDelay,-1
SetKeyDelay,-1
SetTitleMatchMode,2
SetWinDelay,-1
SetWorkingDir,%A_ScriptDir%
StringCaseSense,Off
OnExit,EXIT
ComObjError(false)
Gdip_Initialised:=Gdip_Startup()
;Meta:="\.*?+[{|()^$"
global Ptr := A_PtrSize ? "UPtr" : "UInt"
global COMFail
OnMessage(0x8080,"GetPointer")
_Diskonnect:=0 ; UChar 1 +0
_ApplyCOMSettings:=1 ; UChar 1 +1
_COMBusy:=2 ; UChar 1 +2
_COMFail:=3 ; UChar 1 +3
_DataAvailable:=4 ; UChar 1 +4
_SendDataNow:=5 ; UChar 1 +5
_RS232_Baud:=6 ; Int 4 +6
_RS232_Parity:=10 ; Int 4 +10
_RS232_Data:=14 ; Int 4 +14
_RS232_Stop:=26 ; Int 4 +26
_COMPort:=30 ; Str 12 +30
_SendSize:=42 ; Int 4 +42
_DataPos:=46 ; Int 4 +46
_PackagesRecieved:=50 ; Int 4 +50
_ReadIntervalTimeout:=54 ; Int 4 +54
_RS232_Bytes_Reqest:=58 ; Int 4 +58
_MapRun:=62 ; Int 4 +62
_MapSkip:=66 ; Int 4 +66
_RTimeout:=70 ; Int 4 +70
_EmptyPacket:=74 ; Int 4 +74
_SendDataOffset:=100
_RecieveDataOffset:=10000
RTimeout:=100
EmptyPacket:=1
DefaultBReq:=16
DataSize:=1048576
DataPos:=0
ReadPos:=0
2ndThread=%1%
hBufinfo=%2%
hMainWin=%3%
msPointer=%4%
OnMessage(WM_MOVING:=0x0216, "WM_MOVING")
;OnMessage(WM_MOUSEMOVE:=0x200, "WM_MOUSEMOVE")
;IDC_SIZENS := DllCall("User32.dll\LoadCursor", Ptr, NULL, "Int", 32645, "UPtr")
IDC_SIZEWE := DllCall("User32.dll\LoadCursor", Ptr, NULL, "Int", 32644, Ptr)
IDC_SIZEALL:= DllCall("User32.dll\LoadCursor", Ptr, NULL, "Int", 32646, Ptr)
hIDC_ARROW := DllCall("User32.dll\LoadCursor", Ptr, NULL, "Int", 32512, Ptr)
IDC_ARROW := DllCall("CopyImage",Ptr,hIDC_ARROW,"UInt",0x2,"Int",0,"Int",0,"UInt",0)
RS232_Bytes_Reqest:=DefaultBReq
Rownums:=100000
;if (a_osversion~="10")
; add_size=65
;else
; add_size=55
E_Text_h:=510
hGroupBufer_h:=E_Text_h+101
E_Gr_Snd_h:=E_Text_h-72
E_1_ShiftSize:=170
E_1_h:=E_1_ShiftSize+25
E_RTU_Val_y:=E_1_h-E_1_ShiftSize+5
CreateGui_w:=960
CreateGui_h:=E_Text_h+140
ShiftSpaceX:=500
ShiftSpaceY:=950
Packages_Recieved:=0
RS232_Baud:=9600
RS232_Parity:="N"
RS232_Data:=8
RS232_Stop:=1
Timeout:=((RS232_Data+4)/RS232_Baud)*1000
ReadIntervalTimeout:=Floor(Timeout)
if (ReadIntervalTimeout=0)
ReadIntervalTimeout:=1
Gdip_Points_Num:=2000
Gdip_W:=358
Gdip_H:=358
Gdip_M:=Gdip_H//2
Gdip_ZoomX:=1
Gdip_ZoomY:=1
Gdip_X_Offset:=0 ;Gdip_Y_Offset:=Gdip_M
ColourPen1:=0x0000ff
ColourPen2:=0xff0000
ColourPen3:=0x00ff00
ColourPen4:=0x00ffff
ColourPen5:=0xff00ff
ColourPen6:=0xcccc00
ColourPen7:=0x808080
ColourPen8:=0x0000c0
ColourPen9:=0xc00000
ColourPen10:=0x00c000
ColourPen11:=0x0000ff
ColourPen12:=0xff0000
Monitor_value:={}
MaxNumOfGraf:=12
loop,% MaxNumOfGraf
Monitor_value%a_index%:={}
Monitor_value_T:={}
GrafSmooth:=1
AutoMinMax:=1
AutoEnding:=1
HideSamePol:=0xC867
ICON_CRC_ERROR:=132
ICON_EMPTY:=0
ICON_ERROR:=78
ICON_INFO:=222
ICON_REGISTER:=13 ;268
ICON_START:=138
ICON_STOP:=113
ICON_V:=145
ICON_X:=272
ICON_CLEAN:=50
ICON_OPEN:=4
ICON_CLOSE:=132
ICON_SAVE:=259
ICON_EXIT:=28
ICON_CLEAR:=146
ICON_BACK:=147
ICON_FILTER:=56
ICON_SKIP:=25
ICON_ANALYZE:=69
ICON_HIDE_PCKGS:=66
ICON_HELP:=211
ICON_ABOUT:=222
ICON_SHOW:=255
ICON_HIDE:=256
ICON_FAVORITE:=209
ICON_MANUAL:=29
ICON_RESET:=239
ICON_SMOOTH:=131
ICON_STOP_SCROLL:=175
ICON_SIZE:=23
ICON_GRAFDRAW:=217
COLUMN_#:=1
COLUMN_HOOK:=2
COLUMN_INFO:=3
COLUMN_BIN:=4
COLUMN_SYM:=5
COLUMN_HEX:=6
COLUMN_DEC:=7
COLUMN_WORD:=8
COLUMN_INT:=9
COLUMN_DWORD:=10
COLUMN_DINT:=11
COLUMN_FLOAT:=12
COLUMN_DOUBLE:=13
RTUFunc1:="Read Coil Status (Чтение DO) 01"
RTUFunc2:="Read Input Status (Чтение DI) 02"
RTUFunc3:="Read Holding Reg. (Чтение AO) 03"
RTUFunc4:="Read Input Register (Чтение AI) 04"
RTUFunc5:="Force Single Coil (Запись DO) 05"
RTUFunc6:="Preset Single Reg. (Запись AO) 06"
RTUFunc15:="Force Mult. Coils (Запись неск. DO) 0f"
RTUFunc16:="Force Mult. Reg. (Запись неск. AO) 10"
RTU_Command_List:= RTUFunc1 "|" RTUFunc2 "|" RTUFunc3 "|" RTUFunc4 "|" RTUFunc5 "|" RTUFunc6 "|" RTUFunc15 "|" RTUFunc16 ;
RTUF1:="DO"
RTUF2:="DI"
RTUF3:="AO"
RTUF4:="AI"
RTUF5:="1 DO"
RTUF6:="1 AO"
RTUF15:="# DO"
RTUF16:="# AO"
RTUErr1:="У слейва нет такой команды."
RTUErr2:="Регистр недоступен."
RTUErr3:="Недопустимая величина значения."
RTUErr4:="Ошибка во время выполнения действия."
RTUErr5:="Обрабатываю запрос, ждите..."
RTUErr6:="Обрабатываю команду, ждите..."
RTUErr7:="Не могу выполнить программную функцию. Запросите диагностические данные."
RTUErr8:="Ошибка паритета. Повторите запрос или обратитесь в сервис."
RTUErr10:="Шлюз не правильно настроен или перегружен."
RTUErr11:="Слейв устройства нет в сети или от него нет ответа."
MapTypeOfData:={INT:1,WORD:2,DINT:3,DWORD:4,REAL:5}
MapDataOfType:={1:"INT",2:"WORD",3:"DINT",4:"DWORD",5:"REAL"}
RS232_Baud_List:={50:1,75:2,110:3,150:4,300:5,600:6,1200:7,1800:8,2000:9,2400:10,3600:11,4800:12,7200:13,9600:14,14400:15,19200:16,28800:17,38400:18,57600:19,115200:20,250000:21,300000:22,375000:23,500000:24,750000:25,1500000:26,3000000:27}
RS232_Parity_List:={"N":1,"E":2,"O":3,"M":4,"S":5}
RS232_Data_List:={5:1,6:2,7:3,8:4}
if !2ndThread ; Main
{
MenuCreate:
menu,ListRightClick,add,Очистить,Update
menu,ListRightClick,add,Вернуть все,UnUpdate
menu,ListRightClick,add,Очистить безвозвратно,ClUpdate
menu,ListRightClick,add
menu,ListRightClick,add,Фильтровать данные,DataFilter
menu,ListRightClick,add,Анализ пакетов,En_Analyzer
menu,ListRightClick,add
menu,ListRightClick,add,Копировать,ListCopySelected
menu,ListRightClick,add,Отрисовать график,GrafDrawFromSelected
menu,ListRightClick,disable,Отрисовать график ;
Menu,ListRightClick,Icon,Очистить,shell32.dll,% ICON_CLEAR
Menu,ListRightClick,Icon,Вернуть все,shell32.dll,% ICON_BACK
Menu,ListRightClick,Icon,Очистить безвозвратно,shell32.dll,% ICON_X
Menu,ListRightClick,Icon,Фильтровать данные,shell32.dll,% ICON_FILTER
; Menu,ListRightClick,Icon,Анализ пакетов,shell32.dll,% ICON_ANALYZE
Menu,ListRightClick,Icon,Отрисовать график,shell32.dll,% ICON_GRAFDRAW
menu,SecondListRightClick,add,Скрывать одинаковые пакеты,HideSamePackages
menu,SecondListRightClick,add,Копировать,SecondListCopySelected
menu,SecondListRightClick,add,Отрисовать график,GrafDrawFromSelected
menu,SecondListRightClick,disable,Отрисовать график ;
menu,SecondListRightClick,check,Скрывать одинаковые пакеты
; Menu,SecondListRightClick,Icon,Скрывать одинаковые пакеты,shell32.dll,% ICON_HIDE_PCKGS
Menu,SecondListRightClick,Icon,Отрисовать график,shell32.dll,% ICON_GRAFDRAW
HideSamePackages:=1
menu,ListRightClick2,add,Пропуск пакетов,SkeepPack
; Menu,ListRightClick2,Icon,Пропуск пакетов,shell32.dll,% ICON_SKIP
;--------------------------------------------------
menu,FileMenu,Add,Открыть,OpenFile
menu,FileMenu,Add,Сохранить,SaveFile
menu,FileMenu,Add
menu,FileMenu,Add,Открыть карту регистров Modbus,ModbusOpenFromMain
menu,FileMenu,Add
menu,FileMenu,Add,Количество знаков после запятой,ZeroCount
menu,FileMenu,Add
menu,FileMenu,Add,Выход,EXIT
Menu,FileMenu,Icon,Открыть,shell32.dll,% ICON_OPEN
Menu,FileMenu,Icon,Сохранить,shell32.dll,% ICON_SAVE
Menu,FileMenu,Icon,Открыть карту регистров Modbus,shell32.dll,% ICON_OPEN
Menu,FileMenu,Icon,Выход,shell32.dll,% ICON_EXIT
menu,BufferMenu,add,Очистить,Update
menu,BufferMenu,add,Вернуть все,UnUpdate
menu,BufferMenu,add,Очистить безвозвратно,ClUpdate
menu,BufferMenu,add,Фильтровать данные,DataFilter
menu,BufferMenu,add,Пропуск пакетов,SkeepPack
menu,BufferMenu,add
menu,BufferMenu,add,Анализ пакетов,En_Analyzer
menu,BufferMenu,add,Скрывать одинаковые пакеты,HideSamePackages
menu,BufferMenu,check,Скрывать одинаковые пакеты
menu,BufferMenu,disable,Скрывать одинаковые пакеты
Menu,BufferMenu,Icon,Очистить,shell32.dll,% ICON_CLEAR
Menu,BufferMenu,Icon,Вернуть все,shell32.dll,% ICON_BACK
Menu,BufferMenu,Icon,Очистить безвозвратно,shell32.dll,% ICON_X
Menu,BufferMenu,Icon,Фильтровать данные,shell32.dll,% ICON_FILTER
; Menu,BufferMenu,Icon,Пропуск пакетов,shell32.dll,% ICON_SKIP
; Menu,BufferMenu,Icon,Анализ пакетов,shell32.dll,% ICON_ANALYZE
; Menu,BufferMenu,Icon,Скрывать одинаковые пакеты,shell32.dll,% ICON_HIDE_PCKGS
menu,GrafMenu,add,Открыть,GrafOpen
menu,GrafMenu,add,Закрыть,GrafClose
menu,GrafMenu,add
menu,GrafMenu,add,Сохранить текущее изображение графика,GrafSaveImage
menu,GrafMenu,add,Сохранить все данные графика в текстовый документ,GrafSaveData
menu,GrafMenu,add
menu,GrafMenu,add,Автоматическое максимальное значение,GrafAutoMinMax
menu,GrafMenu,add,Задать максимальное значение вручную F2,GrafChangeMinMax
menu,GrafMenu,add
menu,GrafMenu,add,Автоматически определять разделитель графиков,GrafAutoEnding
menu,GrafMenu,add,Сбросить автоопределение разделителя F5,GrafAutoEndingReset
menu,GrafMenu,add,Задать разделитель вручную F3,GrafChangeEnding
menu,GrafMenu,add
menu,GrafMenu,add,Сглаживание "ступенек" F4,GrafSmooth
menu,GrafMenu,add,Остановить прокрутку F1,GrafPause
menu,GrafMenu,add
menu,GrafMenu,add,Очистить график,GrafClear
menu,GrafMenu,add
menu,GrafMenu,add,Увеличить Колесико мыши или Ctrl+,ZoomIn
menu,GrafMenu,add,Уменьшить Колесико мыши или Ctrl-,ZoomOut
gosub,GrafMenuDisable
menu,GrafMenu,Check,Автоматическое максимальное значение ;
menu,GrafMenu,Check,Автоматически определять разделитель графиков ;
menu,GrafMenu,Check,Сглаживание "ступенек" F4 ;
Menu,GrafMenu,Icon,Открыть,shell32.dll,% ICON_SHOW
Menu,GrafMenu,Icon,Закрыть,shell32.dll,% ICON_HIDE
Menu,GrafMenu,Icon,Сохранить текущее изображение графика,shell32.dll,% ICON_SAVE
; Menu,GrafMenu,Icon,Сохранить все данные графика в текстовый документ,shell32.dll,% ICON_SAVE
; Menu,GrafMenu,Icon,Автоматическое максимальное значение,shell32.dll,% ICON_FAVORITE
Menu,GrafMenu,Icon,Задать максимальное значение вручную F2,shell32.dll,% ICON_MANUAL
; Menu,GrafMenu,Icon,Автоматически определять разделитель графиков,shell32.dll,% ICON_FAVORITE
Menu,GrafMenu,Icon,Сбросить автоопределение разделителя F5,shell32.dll,% ICON_RESET
Menu,GrafMenu,Icon,Задать разделитель вручную F3,shell32.dll,% ICON_MANUAL
; Menu,GrafMenu,Icon,Сглаживание "ступенек" F4,shell32.dll,% ICON_SMOOTH
; Menu,GrafMenu,Icon,Остановить прокрутку F1,shell32.dll,% ICON_STOP_SCROLL
Menu,GrafMenu,Icon,Очистить график,shell32.dll,% ICON_CLEAR
Menu,GrafMenu,Icon,Увеличить Колесико мыши или Ctrl+,shell32.dll,% ICON_SIZE
Menu,GrafMenu,Icon,Уменьшить Колесико мыши или Ctrl-,shell32.dll,% ICON_SIZE
menu,HelpMenu,add,О программе,GuiAbout
; Menu,HelpMenu,Icon,Помощь,shell32.dll,% ICON_HELP
Menu,HelpMenu,Icon,О программе,shell32.dll,% ICON_ABOUT
menu,MenuBar,Add,Файл,:FileMenu
menu,MenuBar,Add,Буфер приема,:BufferMenu
menu,MenuBar,Add,График,:GrafMenu
menu,MenuBar,Add,Справка,:HelpMenu
;--------------------------------------------------
GuiCreate:
Gui,1:Menu,MenuBar
Gui,1:+hwndhMainWin ; -DPIScale ; +alwaysontop
Gui,1:+MinimizeBox +maximizebox +Resize ; +E0x80000
Gui,1:Margin,10,10
Gui,1:font,s8,Tahoma
Gui,1:Add,StatusBar,+hwndhStatusBar,Готов
; Настройки COM-порта ;
Gui,1:Add,GroupBox,xm ym w210 h165,Настройки COM-порта ;
Gui,1:Add,Radio,Checked vChoiceCOM xp+10 yp+20 w130,USB-COM устройство ;
Gui,1:Add,Radio,+hwndhCOMNo xp y+10 w106,COM-порт №:
Gui,1:Add,Radio,+hwndhCOMName xp y+3 w106,Искать по имени:
Gui,1:Add,Edit,xp+110 yp-20 w50 vManualCOM gChoseCOMNo Number Limit3,1
Gui,1:Add,UpDown,Range1-30
Gui,1:Add,Edit,xp y+3 w80 vManualCOMByName gChoseCOMName,CH340
Gui,1:add,Button,xp-110 y+5 w90 gAddSettings,Дополнительно ;
Gui,1:add,Button,x+10 yp w90 gAceptSettings,Применить ;
Gui,1:add,text,xp-98 y+6 w187 h40 v_text_ gDiskonnectCOM
; Отправить данные в порт ;
Gui,1:Add,GroupBox,xm y+15 w210 h%E_Gr_Snd_h%,Отправить данные в порт ;
Gui,1:add,text,xp+5 yp+22 +hwndhZeroState,0
Gui,1:Add,Edit,x+1 yp-2 w190 h%E_1_h% vDataToSend gDataToSendCheck +hwndE_1,
Gui,1:add,Button,+hwndhE_RTU_Addres_6 xm+22 yp-4 gFindAdd,Найти
Gui,1:add,text,+hwndhE_RTU_Addres_1 x+3 yp+4,Адрес DEC: ;Адрес DEC:
Gui,1:add,text,+hwndhE_RTU_Addres_2 xp+35 y+7,HEX:
Gui,1:add,Edit,+hwndhE_RTU_Addres_3 xm+130 yp-24 w70 gChangeAddres Number Limit3 vRTU_SlaveAdress,
Gui,1:Add,UpDown,+hwndhE_RTU_Addres_4 Range0-255 Wrap,1
Gui,1:add,Edit,+hwndhE_RTU_Addres_5 xp y+ w70 gChangeAddres vRTU_SlaveAdressHEX,1
GuiControl,hide,% hZeroState
Gui,1:add,text,+hwndhE_RTU_Command_1 xm+10 yp+15,Команда: ;Команда:
Gui,1:add,DropDownList,+hwndhE_RTU_Command_2 xm+10 y+ w190 Choose3 vRTU_Command gSubmitExt AltSubmit,% RTU_Command_List
Gui,1:add,text,+hwndhE_RTU_StartReg_1 xm+19 y+10,Начальный рег. DEC: ;№ регистра DEC:
Gui,1:add,text,+hwndhE_RTU_StartReg_2 xp+85 y+7,HEX:
Gui,1:add,Edit,+hwndhE_RTU_StartReg_3 xm+130 yp-24 w70 gChangeStartReg Number vRTU_StartReg,
Gui,1:Add,UpDown,+hwndhE_RTU_StartReg_4 Range0-65535 Wrap 0x80,0
Gui,1:add,Edit,+hwndhE_RTU_StartReg_5 xp y+ w70 gChangeStartReg vRTU_StartRegHEX,0
Gui,1:add,text,+hwndhE_RTU_RegNum_1 xm+10 y+10,Кол-во регистров DEC: ;Кол-во регистров DEC:
Gui,1:add,text,+hwndhE_RTU_RegNum_2 xp+94 y+7,HEX:
Gui,1:add,Edit,+hwndhE_RTU_RegNum_3 xm+130 yp-24 w70 gChangeRegNum Number vRTU_RegNum,
Gui,1:Add,UpDown,+hwndhE_RTU_RegNum_4 Range1-100 Wrap 0x80,1
Gui,1:add,Edit,+hwndhE_RTU_RegNum_5 xp y+ w70 gChangeRegNum vRTU_RegNumHEX,1
Gui,1:add,text,+hwndhE_RTU_Val_1 xm+10 yp+15,Значение: ;Значение:
Gui,1:add,checkbox,+hwndhE_RTU_Val_2 xm+10 y+%E_RTU_Val_y% vBeliveMe,Данным верить ;Данным верить:
loop,2
GuiControl,hide,% hE_RTU_Command_%a_index%
loop,5
GuiControl,hide,% hE_RTU_StartReg_%a_index%
loop,6
GuiControl,hide,% hE_RTU_Addres_%a_index%
loop,5
GuiControl,hide,% hE_RTU_RegNum_%a_index%
loop,3
GuiControl,hide,% hE_RTU_Val_%a_index%
Gui,1:add,Radio,xm+10 y+5 gConvertToSYM vChoiceFormat,SYM
Gui,1:add,Radio,x+5 yp gConvertToDEC,DEC
Gui,1:add,Radio,x+5 yp gConvertToHEX Checked,HEX
Gui,1:add,Radio,x+5 yp gConvertToBIN,BIN
PreviousConversion:="hex"
Gui,1:Add,GroupBox,+hwndhEDEC1 xm+10 y+2 w190 h55,DEC ;
Gui,1:add,Radio,+hwndhEDEC2 xm+20 yp+15 gChooseDEC vChoiceDEC,Unsigned
Gui,1:add,Radio,+hwndhEDEC3 x+5 yp gChooseDEC,Signed
Gui,1:add,Radio,+hwndhEDEC4 x+5 yp gChooseDEC,Float
Gui,1:add,Radio,+hwndhEDEC5 xm+20 y+5 gChooseDECSize Group vChoiceDECSize,1
Gui,1:add,Radio,+hwndhEDEC6 x+5 yp gChooseDECSize,2
Gui,1:add,Radio,+hwndhEDEC7 x+5 yp gChooseDECSize,4
Gui,1:add,Radio,+hwndhEDEC8 x+5 yp gChooseDECSize,8 Bytes
loop,8
GuiControl,hide,% hEDEC%a_index%
Gui,1:add,text,xm+10 y+10,Добавить контрольную сумму: ; Добавить контрольную сумму ;
Gui,1:add,DropDownList,xp y+5 w190 +hwndhCS vAddCS gSubmitExt Choose1 AltSubmit,Нет|Сумма 8 бит|CRC-16|Modbus RTU|Modbus RTU шаблон ;
Gui,1:add,Radio,+hwndhECSType1 xp y+ gChoiceCSType vChoiceCSType Checked,Сумма
Gui,1:add,Radio,+hwndhECSType2 xp yp+15 gChoiceCSType,Полином=
Gui,1:add,checkbox,+hwndhECSType3 x+ yp-15 Checked gSubmiting vRefIn,RefIn
Gui,1:add,checkbox,+hwndhECSType4 x+ yp Checked gSubmiting vRefOut,RefOut
Gui,1:add,Edit,+hwndhECSType5 xp-47 y+ w46 Limit4 gSubmiting vPolynom,8005
Gui,1:add,text,+hwndhECSType6 x+5 yp+2,init=
Gui,1:add,Edit,+hwndhECSType7 x+ yp-2 w46 Limit4 gSubmiting vInitVal,FFFF
Gui,1:add,text,+hwndhECSType8 xp-115 y+2,XorOut=
Gui,1:add,Edit,+hwndhECSType9 x+ yp-2 w46 Limit4 gSubmiting vXorOut,0000
Gui,1:add,checkbox,+hwndhECSType10 x+ yp+4 gSubmiting vRefPoly,RefPoly
loop,10
GuiControl,hide,% hECSType%a_index%
Gui,1:add,Button,xm+10 y+5 w120 h23 gButtonSendData,Отправить ;
Gui,1:add,Button,x+ yp w69 h23 gSendDataRepitedly +hwndhSendDataRepitedly,Циклично ;
Gui,1:add,Button,xm+10 yp-50 gModbusMapOpen +hwndhModbusMapOpen,Карта регистров ;
GuiControl,hide,% hModbusMapOpen
; Буфер приёма COM-порта ;
Gui,1:Add,GroupBox,xm+220 ym w720 h%hGroupBufer_h% +hwndhGroupBufer,Буфер приёма COM-порта ;
Gui,1:add,text,+hwndhBufinfo xp+10 yp+20 w110 vBufinfo gClearQueue,В обработке 0. ;
SaveBufer:={}
Gui,1:add,text,+hwndhhide1 xp yp w128,Ожидаемое число байт: ;
Gui,1:add,edit,+hwndhhide2 x+5 yp-3 w70 Number Limit3 vRS232_Bytes_Reqest gSubmiting,% RS232_Bytes_Reqest
Gui,1:add,UpDown,+hwndhhide3 Range1-128 gSubmitExt,% RS232_Bytes_Reqest
Gui,1:Add,checkbox,+hwndhAutoByRe x+5 yp+3 checked vAuto_Bytes_Reqest gSubmiting,Автоматически ;
GuiControl,hide,% hAutoByRe
GuiControl,hide,% hhide1
GuiControl,hide,% hhide2
GuiControl,hide,% hhide3
Gui,1:add,checkbox,xp-209 y+9 vFollowSelect gSubmitExt,Сохранять выделение таблицы (мониторить значение) ;
Gui,1:add,ListView,xp y+7 w320 h%E_Text_h% +LV0x10000 v_List_ gListGetSelected AltSubmit grid Count%Rownums% NoSortHdr ReadOnly +hwndE_LV,#|№ байта|№ байта или описание|BIN|SYM|HEX|DEC|WORD|INT|DWORD|DINT|Float|Double
ImageListID:=IL_Create(300)
loop,300
IL_Add(ImageListID,"shell32.dll",a_index)
LV_SetImageList(ImageListID)
; Разделитель 1
Gui,1:Add,Progress,x+0 yp w20 h%E_Text_h% vProgress cNavy backgroundSilver Vertical +hwndhProgress
Gui,1:add,checkbox,x+0 ym+20 +hwndE_111 vEN_Kurvendrucker gKurvendrucker,Включить графопостроитель ;
Gui,1:add,checkbox,xp y+10 +hwndE_112 vAddCRLF gSubmitExt Checked,Добавить перевод строки после каждого сообщения ;
Gui,1:font,s12,Courier New
tmp1:=E_Text_h-36
Gui,1:add,edit,xp y+5 w360 h%tmp1% HScroll VScroll ReadOnly Multi v_InText_ hwndE_Text
Gui,1:font,s8,Tahoma
Gui,1:add,ListView,xp yp w360 h%tmp1% +LV0x10000 v_SecondList_ gSecondListGetSelected AltSubmit grid Count%Rownums% NoSortHdr ReadOnly +hwndE_SLV,#|№ байта|№ байта или описание|BIN|SYM|HEX|DEC|WORD|INT|DWORD|DINT|Float|Double
Gui,1:font,s12,Courier New
LV_SetImageList(ImageListID)
Gui,1:ListView,% E_LV
GuiControl,Hide,% E_SLV
AnBufer:={}
AnCufer:={}
; Разделитель 2
Gui,1:Add,Progress,xp y+0 h20 w360 vProgress2 cSilver backgroundNavy +hwndhProgress2,100
Gui,1:add,edit,% "xp+2 yp+22 w" Gdip_W-4 " h" 12 " +hwndhGrafPos"
;GuiControl,Hide,% hGrafPos
Gui,1:font,s8,Tahoma
Gui,1:add,button,xp-340 y+10 w200 gToTheEnd +hwndhTtEButton,Продолжить прокрутку ;
Gui,1:add,button,% "x+10 yp w490 vUpdateButton gUpdate +hwndhClButton",Обновить ;
Gui,1:add,checkbox,xm+230 yp gSubmiting vGrafPause +hwndhECB0,Остановить прокрутку (F1)
Gui,1:add,text,xm+218 y+1 w1 +hwndhE0, ;
Gui,1:font,s10 w1000,Tahoma
loop,% MaxNumOfGraf
Gui,1:add,checkbox,% "x+5 yp w50 gSubmiting vEnableGraf" a_index " checked c" ColourPen%a_index% " +hwndhECB" a_index,% "[" a_index "]"
loop,% MaxNumOfGraf+1
{
i:=a_index-1
GuiControl,hide,% hECB%i%
}
GuiControl,hide,% hE0
Gui,1:font,s8,Tahoma
Gui,1:Show,w%CreateGui_w% h%CreateGui_h%,COM Terminal v%Version%
Gui,1:+MinSize
E%E_LV%=
( LTrim
)
E%E_LV2%=
( LTrim
Варианты представления выделенных байтов.
)
E%hProgress%=
( LTrim
Шкала заполнения таблицы. При переполнении таблица и текстовое поле очистятся.
)
E%hProgress2%=
( LTrim
Позиция в графике. Правый клик - сменить позицию.
)
E%E_1%=
( LTrim
)
E%E_111%=
( LTrim
Kurvendrucker по немецки.
)
E%hECB12%=
( LTrim
Правый клик - отключить лишние графики. Правый клик на отключенный - включить все.
)
E%hBufinfo%=
( LTrim
Клик чтобы очистить очередь. Правый клик - меню.
)
E%hECSType1%=
( LTrim
Сумма всех байтов данных
)
E%hECSType2%=
( LTrim
Циклический избыточный код
)
E%hECSType3%=
( LTrim
Обратный порядок битов для входных данных
)
E%hECSType4%=
( LTrim
Обратный порядок битов для итога контрольной суммы
)
E%hECSType5%=
( LTrim
Порождающее полиномиальное число в формате HEX
)
E%hECSType6%=
( LTrim
Стартовое значение контрольной суммы (число в формате HEX)
)
E%hECSType7%:=E%hECSType6%
E%hECSType8%=
( LTrim
Применить исключающее-ИЛИ к контрольной сумме с данным числом в формате HEX
)
E%hECSType9%:=E%hECSType8%
E%hECSType10%=
( LTrim
Обратный порядок битов для полиномиального числа
)
E%hECB1%:=E%hECB2%:=E%hECB3%:=E%hECB4%:=E%hECB5%:=E%hECB6%:=E%hECB7%:=E%hECB8%:=E%hECB9%:=E%hECB10%:=E%hECB11%:=E%hECB12%
VarSetCapacity(E_Text_start, 4), VarSetCapacity(E_Text_end, 4)
Gdip_Initialise:
if Gdip_Initialised
{
E%E_LV2%.=" Нажмите на нужный вариант для отрисовки графика."
gui,3:+owner1
Gui,3:+hwndhGraf -Caption +E0x80000 +LastFound +ToolWindow ;+AlwaysOnTop WS_EX_LAYERED := 0x80000
Gui,3:Show,x0 y0 w1 h1
; SetParent(hGraf,hMainWin,,0,0)
Gdip_FontFamilyCreate(Gdip_Font)
Gdip_hbm2 := CreateDIBSection(A_ScreenWidth,A_ScreenHeight)
pMainHolst := CreateCompatibleDC()
Gdip_obm2 := SelectObject(pMainHolst,Gdip_hbm2)
pMainHolst_G := Gdip_GraphicsFromHDC(pMainHolst)
Gdip_SetSmoothingMode(pMainHolst_G,4)
Gdip_Font:="Lucida Console"
Gdip_Font_Size:="s15"
Gdip_Font_W:=10
Gdip_Font_H:=15
Gdip_Font_Selected_Colour:="ff000000"
Gdip_WhiteBrush:= Gdip_BrushCreateSolid(0xffffffff) ; белая кисть для заливки
Gdip_WhiteBrush2:= Gdip_BrushCreateSolid(0xd0ffffff) ; белая кисть для заливки
Gdip_BlackBrush:= Gdip_BrushCreateSolid(0xff000000) ; черная кисть для заливки
Gdip_WhitePen := Gdip_CreatePen(0xffffffff,1) ; карандаш для стирания
Gdip_GrayPen := Gdip_CreatePen(0xff808080,1) ; карандаш для оси
Gdip_GrayPen2 := Gdip_CreatePen(0xffe0e0e0,1) ; карандаш для оси
Gdip_GrayPen3 := Gdip_CreatePen(0x11000000,1) ; карандаш для оси
Gdip_BluePen := Gdip_CreatePen(0xff0000ff,1) ; карандашы для графика
Gdip_BlackPen := Gdip_CreatePen(0xff000000,2) ; карандашы для графика
Line_w:=1
loop,% MaxNumOfGraf
{
Gdip_Pen%a_index%:=Gdip_CreatePen(0xff000000 | ColourPen%a_index%,Line_w)
Gdip_Brush%a_index%:= Gdip_BrushCreateSolid(0x40000000 | ColourPen%a_index%) ; белая кисть для заливки
}
Gdip_FillRectangle(pMainHolst_G,Gdip_WhiteBrush,0,0,Gdip_Points_Num,Gdip_H)
}
Gui,1:ListView,% E_SLV
LV_ModifyCol(COLUMN_#,65)
LV_ModifyCol(COLUMN_HOOK,0)
LV_ModifyCol(COLUMN_INFO,45)
LV_ModifyCol(COLUMN_BIN,60)
LV_ModifyCol(COLUMN_SYM,20)
LV_ModifyCol(COLUMN_HEX,37)
LV_ModifyCol(COLUMN_DEC,32)
LV_ModifyCol(COLUMN_WORD,50)
LV_ModifyCol(COLUMN_INT,50)
LV_ModifyCol(COLUMN_DWORD,20)
LV_ModifyCol(COLUMN_DINT,20)
LV_ModifyCol(COLUMN_FLOAT,80)
LV_ModifyCol(COLUMN_DOUBLE,40)
Gui,1:ListView,% E_LV
LV_ModifyCol(COLUMN_#,65)
LV_ModifyCol(COLUMN_HOOK,0)
LV_ModifyCol(COLUMN_INFO,45)
LV_ModifyCol(COLUMN_BIN,60)
LV_ModifyCol(COLUMN_SYM,20)
LV_ModifyCol(COLUMN_HEX,37)
LV_ModifyCol(COLUMN_DEC,32)
LV_ModifyCol(COLUMN_WORD,50)
LV_ModifyCol(COLUMN_INT,50)
LV_ModifyCol(COLUMN_DWORD,20)
LV_ModifyCol(COLUMN_DINT,20)
LV_ModifyCol(COLUMN_FLOAT,80)
LV_ModifyCol(COLUMN_DOUBLE,40)
Gui,2:-sysmenu +owner1
Gui,2:+hwndhAddWin ; -DPIScale ; +alwaysontop
;Gui,2:Color,dfdfdf
Gui,2:Margin,10,10
Gui,2:font,s8
Gui,2:add,text,xm ym w120,Скорость передачи: ;
Gui,2:Add,DropDownList,+hwndhRS232_Baud_Choice x+3 yp-3 w195 Choose14 vRS232_Baud_Choice gCalcTimeout,50|75|110|150|300|600|1200|1800|2000|2400|3600|4800|7200|9600|14400|19200|28800|38400|57600|115200|250000|300000|375000|500000|750000|1500000|3000000
Gui,2:add,text,xm y+10 w120,Контрольные биты: ;
Gui,2:Add,DropDownList,+hwndhRS232_Parity_Choice x+3 yp-3 w195 Choose1 vRS232_Parity_Choice gCalcTimeout,N (None) - без проверки|E (EVEN) - проверка на четность|O (Odd) - проверка на нечетность|M (MARk) - бит всегда 1|S (SPACE) - бит всегда 0
Gui,2:add,text,xm y+10 w120,Число бит на символ: ;
Gui,2:Add,DropDownList,+hwndhRS232_Data_Choice x+3 yp-3 w195 Choose4 vRS232_Data_Choice gCalcTimeout,5|6|7|8
Gui,2:add,text,xm y+10 w120,Число стоповых бит: ;
Gui,2:Add,DropDownList,+hwndhRS232_Stop_Choice x+3 yp-3 w195 Choose1 vRS232_Stop_Choice gCalcTimeout,1|2
Gui,2:add,text,xm y+10 w120,ReadIntervalTimeout: ;
Gui,2:Add,Edit,+hwndhRITimeout x+3 yp-3 w50 vReadIntervalTimeout,% ReadIntervalTimeout
Gui,2:add,text,x+5 yp+3 w20 ,ms
Gui,2:add,text,+hwndhTimeout x+10 yp w120,Расчетный = %Timeout% ms ;
Gui,2:add,Button,xm y+10 w80 gDefaultSettings default,Поумолчанию ;
Gui,2:add,Button,x+65 yp w80 gEndAddSettings default,Применить ;
Gui,2:add,Button,x+10 yp w80 gCancelAddSettings,Отмена ;
Gui,4:-sysmenu +owner1
Gui,4:+hwndhFilterWin ; -DPIScale ; +alwaysontop
Gui,4:Margin,10,10
Gui,4:font,s8
Gui,4:add,checkbox,xm ym gChangeFilter_Addres vFilter_Addres_EN,Фильтровать пакеты по Byte_№1/"Адресу" ;
Gui,4:add,Edit, xm+255 yp-3 w70 gChangeFilter_Addres Number Limit3 vFilter_Addres,
Gui,4:Add,UpDown, Range1-255 Wrap 0x80,1
Gui,4:add,Edit, xp y+1 w70 gChangeFilter_Addres vFilter_AddresHEX,1
Gui,4:add,checkbox,xm y+20 gChangeFilter_Command vFilter_Command_EN,Фильтровать пакеты по Byte_№2/"Команде" ;
Gui,4:add,Edit,+hwndhFiltE1 xm+255 yp-3 w70 gChangeFilter_Command Number Limit3 vFilter_Command,
Gui,4:Add,UpDown,+hwndhFiltE2 Range1-255 Wrap 0x80,1
Gui,4:add,Edit,+hwndhFiltE3 xp y+1 w70 gChangeFilter_Command vFilter_CommandHEX,1
Gui,4:Add,DropDownList,+hwndhFiltE4 xp-200 yp w195 gChangeFilter_Command vFilter_CommandRTU Choose3 AltSubmit,% RTU_Command_List
Gui,4:add,checkbox,xm y+20 gChangeFilter_Byte vFilter_Byte_EN,Фильтровать по Byte_№3/"Кол-во байт" ;
Gui,4:add,Edit, xm+255 yp-3 w70 gChangeFilter_Byte Number Limit3 vFilter_Byte,
Gui,4:Add,UpDown, Range1-255 Wrap 0x80,1
Gui,4:add,Edit, xp y+1 w70 gChangeFilter_Byte vFilter_ByteHEX,1
Gui,4:Add,Radio,+hwndhFiltE5 xm y+20 Checked gChangeFilter_Addres vFilter_Message_EN,Принимать все ;
Gui,4:Add,Radio,+hwndhFiltE6 xp y+5 gChangeFilter_Addres,Не принимать запросы мастера ;
Gui,4:Add,Radio,+hwndhFiltE7 xp y+5 gChangeFilter_Addres,Не принимать ответы слейва ;
Gui,4:Add,checkbox,+hwndhFiltE8 xp y+15 gChangeFilter_Addres vFilter_CRC_EN,Не принимать ошибки контрольной суммы ;
Gui,4:add,Button,xm+255 y+20 w70 gDataFilterOk,Ok ;
;GuiControl,Show,% hFiltE4
;GuiControl,Show,% hFiltE5
;GuiControl,Show,% hFiltE6
;GuiControl,Show,% hFiltE7
;loop,3
; GuiControl,disable,% hFiltE%a_index%
GuiControl,hide,% hFiltE4
GuiControl,hide,% hFiltE5
GuiControl,hide,% hFiltE6
GuiControl,hide,% hFiltE7
loop,3
GuiControl,enable,% hFiltE%a_index%
GuiControl,hide,% hFiltE8
gosub,6GuiCreate
gosub,7GuiCreate
gosub,8GuiCreate
Gui,1:default
gosub,HotkeysOn
varsetcapacity(Data,DataSize,0xFF)
msPointer:=&Data
MainPID:=DllCall("GetCurrentProcessId")
; run slave
Params:=" " MainPID " " hBufinfo " " hMainWin " " msPointer
if a_iscompiled
run,% a_scriptfullpath . Params,,UseErrorLevel,SlavePID
else
run,% """" a_ahkPath """ """ a_scriptfullpath """" Params,,UseErrorLevel,SlavePID
settimer,WM_MOUSEMOVE,100
; gosub,EndAddSettings
F:=Func("CheckPIDExist").Bind(SlavePID)
settimer,% F,2000
; while(!slPointer)
; {
; sleep,100
; if (a_index>20)
; {
; msgbox,Main`nОшибка получения указателя.
; goto,EXIT
; }
; }
; SLM:=new _ClassMemory("Ahk_PID" SlavePID)
; SLM.write(slPointer+_COMBusy,0,"uChar")
NumPut(0,Data,_COMBusy,"UChar")
NumPut(DefaultBReq,Data,_RS232_Bytes_Reqest,"Int")
loop,300
LV_Add("Icon" a_index,,,a_index)
gosub,AceptSettings
if !FileOpened
gosub,Update
MainLoop:
loop
{
Loop_Time:=oldLoop_Time!="" ? a_tickcount-oldLoop_Time : 0
oldLoop_Time:=a_tickcount
sleep,10
while(FileOpened)
sleep,100
if (NumGet(Data,_Diskonnect,"UChar"))
sleep,100
else if (NumGet(Data,_COMBusy,"UChar"))
{
NumPut(0,Data,_COMBusy,"UChar")
GuiControl,,_text_,% COMPort "`n`nнедоступен"
UnCOMPort:=COMPort
settimer,ResetUnCOMPort,2000
ComPortList:=SearchCOM("",1)
GuiControl,,% E_Text,% COMPort " недоступен.`nВыберите другой порт вручную.`n`nНайденные в системе порты:`n" ComPortList
}
else if (NumGet(Data,_COMFail,"UChar"))
{
NumPut(0,Data,_COMFail,"UChar")
gosub,AceptSettings
}
else
{
; ; отправляем данные в буфер порта
NumPut(MapRun,Data,_MapRun,"Int")
if MapRun
{
ADDCS:=4
AddCSLenght:=2
if SendDataRepitedly
gosub,SendDataRepitedly
if (OldMapNum=MapNum)
MapTimeOut+=Loop_Time
else
MapTimeOut:=0
;tooltip,% MapTimeOut "`n" MapNext
OldMapNum:=MapNum
if (MapTimeOut>MapTOut)
{
MapNext:=1
Gui,6:default
loop,9
LV_GetText(tmp%a_index%,MapNum,a_index)
LV_Modify(MapNum,,tmp1,tmp2,tmp3,tmp4,tmp5,tmp6,tmp7,"",tmp9)
Gui,1:default
}
if MapNext
{
if !MapPriority
MapNum++
else
{
if !MapPrioNext
{
MapPrioNext:=1
SMapNum:=MapNum
MapNum:=MapPriority
}
else
{
MapPrioNext:=0
MapNum:=SMapNum+1
if (MapNum=MapPriority)
MapNum++
}
}
if (MapNum>MapList.MaxIndex())
MapNum:=1
MapTimeOut:=0
MapNext:=0
Gui,6:default
LV_Modify(MapNum,"Focus")
Gui,1:default
gosub,SendData
}
}
if SendDataRepitedly
gosub,SendData
if (!doonce and !NumGet(Data,_Diskonnect,"UChar"))
{
dots:=""
doonce:=1
GuiControl,,_text_,% "Подключен " COMPort ".`n`n`t`tОтключиться"
GuiControl,,% E_Text,% "Подключен " COMPort "`r`n"
}
InWork:=NumGet(Data,_PackagesRecieved,"Int")-ReadPack
if (InWork<0)
{
ReadPack:=NumGet(Data,_PackagesRecieved,"Int")
InWork:=0
}
if (InWork>=10 and !swapcolor)
{
swapcolor:=!swapcolor
GuiControl,+cRed,Bufinfo
}
else if (InWork<10 and swapcolor)
{
swapcolor:=!swapcolor
GuiControl,+cblack,Bufinfo
}
; ; принимаем данные из буфера порта
GuiControl,,Bufinfo,% "В обработке " InWork " пакетов."
if NumGet(Data,_DataAvailable,"UChar")
{
DataFromSlaveSize:=NumGet(Data,_RecieveDataOffset+ReadPos,"Int")
; tooltip,% DataFromSlaveSize "`n" ReadPos
if (DataFromSlaveSize<0 or DataFromSlaveSize>4096) ;DefaultBReq
{
NumPut(0,Data,_DataAvailable,"UChar")
if (DataFromSlaveSize=-2)
ReadPos:=ReadPack:=0
else if (DataFromSlaveSize>DefaultBReq)
gosub,ClearQueue
continue
}
if (DataFromSlaveSize>0)
{
Bufer:={}
NumPut(0xFFFFFFFF,Data,_RecieveDataOffset+ReadPos,"UInt")
loop,% DataFromSlaveSize
{
addr:=_RecieveDataOffset+ReadPos+3+a_index
Bufer[a_index]:=NumGet(Data,addr,"UChar")
NumPut(0xFF,Data,addr,"UChar")
}
SaveBufer.Push(Bufer.Clone())
ReadPos+=DataFromSlaveSize+4
ReadPack++
Packages_Recieved++
if (SkeepPack and InWork>3)
continue
RS232_Bytes_Received:=DataFromSlaveSize
Received_Addres:=Bufer[1]
Received_Command:=Bufer[2]
Received_Byte:=Bufer[3]
; определить корректность контрольной суммы
CheckSummIsCorrect:=0
if (AddCS>=4 and RS232_Bytes_Received>2)
{
tmp1:=(Bufer[RS232_Bytes_Received]<<8)|Bufer[RS232_Bytes_Received-1]
tmp2:=CRC16(Bufer,RS232_Bytes_Received-2)
CheckSummIsCorrect:=(tmp1==tmp2)
}
else if (AddCS=2 or (AddCS=3 and RS232_Bytes_Received>2))
{
tmp0:=CRC16(Bufer,RS232_Bytes_Received-AddCSLenght,(ChoiceCSType=1),Polynom,InitVal,Refin,RefOut,XorOut,RefPoly)
if AddCS=2
tmp1:=Bufer[RS232_Bytes_Received]
else if AddCS=3
tmp1:=(Bufer[RS232_Bytes_Received]<<8)|Bufer[RS232_Bytes_Received-1]
tmp2:=(AddCS=3) ? tmp0 : tmp0&0xff
CheckSummIsCorrect:=(tmp1==tmp2)
}
; определить тип пакета Modbus
Received_Message_Type:=""
if (AddCS>=4)
{
if CheckSummIsCorrect
{
if (Received_Command>0 and Received_Command<5)
{
tmp1:=Bufer[3]
if (RS232_Bytes_Received=tmp1+5)
Received_Message_Type:="Ответ" (tmp1=3?" возможно Запрос":"")
else if (RS232_Bytes_Received=8)
Received_Message_Type:="Запрос"
}
else if (Received_Command>4 and Received_Command<7)
Received_Message_Type:="Запрос/Ответ"
else if (Received_Command=0x0f or Received_Command=0x10)
{
tmp1:=Bufer[7]
if (RS232_Bytes_Received=tmp1+9)
Received_Message_Type:="Запрос"
else
Received_Message_Type:="Ответ"
}
}
}
anindex:=RS232_Bytes_Received "|" Received_Addres "|" Received_Command "|" (Received_Message_Type?0:Received_Byte) "|" Received_Message_Type "|" CheckSummIsCorrect
if !isobject(AnBufer[anindex])
{
AnBufer[anindex]:={}
AnCufer[anindex]:={}
}
AnBufer[anindex].Push(Bufer.Clone())
AnCufer[anindex].Push(Packages_Recieved)
if Analyzer
{
updateOnce:=0
AnalyzerTimer:=0
continue
}
Gosub,ParseBuffer
if (FoundAdd="" and CheckSummIsCorrect)
FoundAdd:=Received_Addres
}
}
else if Analyzer
{
AnalyzerTimer+=Loop_Time
if (AnalyzerTimer>1000 and !updateOnce)
{
Update:=1
updateOnce:=1
gosub,Analyze
}
}
}
gosub,SetFormatFloat
}
}
else ;Slave
{
SysGet,CAPTION,4
SysGet,XBORDER,5
SysGet,YBORDER,6
SysGet,XEDGE,45
SysGet,YEDGE,46
BORDERX:=XBORDER+XEDGE
BORDERY:=YBORDER+YEDGE+CAPTION
F:=Func("CheckPIDExist").Bind(2ndThread)
settimer,% F,2000
; varsetcapacity(Data,DataSize,0xFF)
; slPointer:=&Data
; while(numget(Data,_COMBusy,"uChar"))
; {
; PostMessage,0x8080,0,%slPointer%,,ahk_pid %2ndThread%
; sleep,100
; if (a_index>20)
; {
; msgbox,Slave`nОшибка получения указателя.
; goto,EXIT
; }
; }
Controlgetpos,Bx,By,Bw,Bh,,ahk_id %hBufinfo%
Gui,1:Margin,0,0
Gui,1:font,s8,Tahoma
gui,1:+hwndhSlaveWin -border
Gui,1:+0x40000000 -0x80000000
gui,1:add,text,x0 y0 w200 vBufinfo,Текст
gui,1:show,NA w200
gui,2:add,text,x1000 y1000 w1000 h1000 +hwndhTest,Test
Controlgetpos,Testx,Testy,Testw,Testh,,ahk_id %hTest%
gui,2:Destroy
DPICoef:=Testw/1000
;tooltip,% Bx "`n" By "`n" Bw "`n" Bh "`n`n" Testx-Testw "`n" Testy-Testh "`n`n" BORDERX "`n" BORDERY
SetParent(hSlaveWin,hMainWin,,Bx+Bw-BORDERX*DPICoef,By-25-BORDERY*DPICoef)
settimer,CheckMainExist,1000
Menu,Tray,Icon
SlavePID:=DllCall("GetCurrentProcessId")
varsetcapacity(In_Data,_RecieveDataOffset)
varsetcapacity(tmp_In_Data,_RecieveDataOffset)
MSM:=new _ClassMemory("Ahk_PID" 2ndThread)
varsetcapacity(Send_Data,_RecieveDataOffset-_SendDataOffset)
MSM.write(msPointer+_SendDataNow,0,"UChar")
DllCall("QueryPerformanceCounter", "Int64*", StartTime)
tltp:=[]
SlaveLoop:
loop
{
Loop_Time:=oldLoop_Time!="" ? a_tickcount-oldLoop_Time : 0
oldLoop_Time:=a_tickcount
/*
Array =
Size Int 4 +0
Data byte 0 byte 1 +4
Data byte 1 byte 1
Data byte 2 byte 1
Data byte n byte 1
Size Int 4
Data byte 0 byte 1
Data byte 1 byte 1
Data byte 2 byte 1
Data byte n byte 1
...
if Size == 0xFFFFFFFF
End
*/
if MSM.Read(msPointer+_Diskonnect,"UChar")
{
PackagesRecieved:=0
RS232_Close(RS232_FileHandle)
}
else if (MSM.Read(msPointer+_ApplyCOMSettings,"UChar"))
{
MSM.write(msPointer+_ApplyCOMSettings,0,"UChar")
PackagesRecieved:=0
PackagesSended:=0
RS232_Close(RS232_FileHandle)
varsetcapacity(var,12)
MSM.ReadRaw(msPointer+_COMPort,var,12)
COMPort:=StrGet(&var,6)
RS232_Baud:=MSM.Read(msPointer+_RS232_Baud,"Int")
RS232_Parity:=chr(MSM.Read(msPointer+_RS232_Parity,"Int"))
RS232_Data:=MSM.Read(msPointer+_RS232_Data,"Int")
RS232_Stop:=MSM.Read(msPointer+_RS232_Stop,"Int")
ReadIntervalTimeout:=MSM.Read(msPointer+_ReadIntervalTimeout,"Int")
;tooltip,% COMPort "`n" RS232_Baud "`n" RS232_Parity "`n" RS232_Data "`n" RS232_Stop "`n" ReadIntervalTimeout
RS232_FileHandle:=RS232_Get_FileHandle(COMPort
,RS232_Baud
,RS232_Parity
,RS232_Data
,RS232_Stop
,ReadIntervalTimeout)
if !RS232_FileHandle
MSM.write(msPointer+_COMBusy,1,"UChar")
}
if COMFail
{
RS232_FileHandle:=0
MSM.write(msPointer+_COMFail,1,"UChar")
COMFail:=0
}
if RS232_FileHandle
{
if (MSM.Read(msPointer+_SendDataNow,"UChar")=1)
{
size:=MSM.Read(msPointer+_SendSize,"Int")
if size
{
PackagesSended++
GuiControl,,Bufinfo,% "_______ в буфере " PackagesRecieved ", отправлено " PackagesSended " пакетов."
MSM.ReadRaw(msPointer+_SendDataOffset,Send_Data,size)
RS232_ClearRXBuffer(RS232_FileHandle)
RS232_Write(RS232_FileHandle,&Send_Data,size)
}
MSM.write(msPointer+_SendDataNow,2,"UChar")
DllCall("QueryPerformanceCounter", "Int64*", StartTime)
}
MSM.write(msPointer+_DataPos,DataPos,"Int")
MSM.write(msPointer+_PackagesRecieved,PackagesRecieved,"Int")
RS232_Bytes_Reqest:=MSM.Read(msPointer+_RS232_Bytes_Reqest,"Int")
MapRun:=MSM.Read(msPointer+_MapRun,"Int")
RTimeout:=MSM.Read(msPointer+_RTimeout,"Int")
EmptyPacket:=MSM.Read(msPointer+_EmptyPacket,"Int")
RS232_Read(RS232_FileHandle,1,&In_Data,RS232_Bytes_Received)
if RS232_Bytes_Received
{
Offset:=RS232_Bytes_Received
Packet:=false
EmptyPack:=0
DllCall("QueryPerformanceCounter", "Int64*", StartTime)
loop,% 1000//ReadIntervalTimeout
{
RS232_Read(RS232_FileHandle,4096,&In_Data+Offset,RS232_Bytes_Received)
DllCall("QueryPerformanceFrequency", "Int64*", frequency)
DllCall("QueryPerformanceCounter","Int64*",EndTime)
RTimer:=(EndTime-StartTime)/frequency*1000
if RS232_Bytes_Received
{
EmptyPack:=0
Packet:=true
DllCall("QueryPerformanceCounter", "Int64*", StartTime)
Offset+=RS232_Bytes_Received
}
else if Packet
EmptyPack++
if (RTimer>ReadIntervalTimeout*(EmptyPacket+4) or EmptyPack=EmptyPacket)
{
MSM.write(msPointer+_SendDataNow,0,"UChar")
GuiControl,,Bufinfo,% "_______ в буфере " PackagesRecieved ", отправлено " PackagesSended " пакетов."
break
}
}
RS232_Bytes_Received:=Offset
}
else
{
DllCall("QueryPerformanceFrequency", "Int64*", frequency)
DllCall("QueryPerformanceCounter","Int64*",EndTime)
RTimer:=(EndTime-StartTime)/frequency*1000
if (RTimer>RTimeout)
{
MSM.write(msPointer+_SendDataNow,0,"UChar")
DllCall("QueryPerformanceCounter", "Int64*", StartTime)
}
}
if (MapRun and MSM.Read(msPointer+_MapSkip,"Int")=2)
{
MSM.Write(msPointer+_MapSkip,0,"Int")
RS232_Bytes_Received:=0
}
; }
; else
; sleep,10
if RS232_Bytes_Received
{
PackagesRecieved++
GuiControl,,Bufinfo,% "(чтение) в буфере " PackagesRecieved ", отправлено " PackagesSended " пакетов."
MSM.WriteRaw(msPointer+_RecieveDataOffset+DataPos+4,&In_Data,RS232_Bytes_Received)
MSM.write(msPointer+_RecieveDataOffset+DataPos,RS232_Bytes_Received,"Int")
DataPos+=RS232_Bytes_Received+4
MSM.write(msPointer+_DataAvailable,1,"UChar")
RS232_Bytes_Received:=0
}
if (DataPos>DataSize-_RecieveDataOffset-10240)
{
MSM.write(msPointer+_RecieveDataOffset+DataPos,0xFFFFFFFE,"UInt")
DataPos:=0
PackagesRecieved:=0
}
; GuiControl,,Bufinfo,% "_______ в буфере " PackagesRecieved ", отправлено " PackagesSended " пакетов."
}
else
sleep,100
}
}
return
ZeroCount:
InputBox,tmp1,Количество знаков после запятой,,,240,120,,,,12,3
if !errorlevel
FloatFormat:=tmp1
return
SetFormatFloat:
SetFormat,Float,0.%FloatFormat%
return
6GuiCreate:
MapList:=[]
tmpMap:=[]
MapTOut:=700
menu,MapRmenu,add,Добавить,MapAdd
menu,MapRmenu,add,Редактировать,MapEdit
menu,MapRmenu,add,Изменить адрес выбранных,MapAddresChange
menu,MapRmenu,add
menu,MapRmenu,add,Копировать текст ячейки,MapCopy
menu,MapRmenu,add,Приоритетный опрос первого выделенного,MapPrioritySet
menu,MapRmenu,add
menu,MapRmenu,add,Удалить,MapDelete
menu,MapFileMenu,Add,Открыть,MapOpen
menu,MapFileMenu,Add,Сохранить,MapSave
menu,MapFileMenu,Add
menu,MapFileMenu,Add,Количество знаков после запятой,ZeroCount
menu,MapFileMenu,Add
menu,MapFileMenu,Add,Выход,MapExit
Menu,MapFileMenu,Icon,Открыть,shell32.dll,% ICON_OPEN
Menu,MapFileMenu,Icon,Сохранить,shell32.dll,% ICON_SAVE
Menu,MapFileMenu,Icon,Выход,shell32.dll,% ICON_EXIT
Menu,MapConnection,add,Пуск,MapRun
Menu,MapConnection,add,Стоп,MapStop
Menu,MapConnection,add,Задать таймаут,MapSetTOut
Menu,MapConnection,Icon,Пуск,shell32.dll,% ICON_START
Menu,MapConnection,Icon,Стоп,shell32.dll,% ICON_STOP
menu,MapMenuBar,Add,Файл,:MapFileMenu
menu,MapMenuBar,Add,Регистры,:MapRmenu
menu,MapMenuBar,Add,Связь,:MapConnection
Gui,6:Menu,MapMenuBar
Gui,6:+hwndhMapWin ; -DPIScale ; +alwaysontop
Gui,6:+MinimizeBox +maximizebox +Resize ; +E0x80000
Gui,6:Margin,0,0
Gui,6:font,s8,Tahoma
Gui,6:Add,StatusBar,+hwndhMapStatusBar
Gui,6:add,ListView,xm ym w800 h600 +LV0x10000 v_MapList_ gMapGetSelected AltSubmit grid Count256 NoSortHdr ReadOnly +hwndMap_LV,Адрес|№ регистра|Тип регистра|Тип данных|Значение|Значение HEX|Значение BIN|Актуальность|Коментарий
; Gui,6:add,Button,xp y+5,Пуск
Gui,6:default
LV_ModifyCol(1,50)
LV_ModifyCol(2,60)
LV_ModifyCol(3,20)
LV_ModifyCol(4,50)
LV_ModifyCol(5,70)
LV_ModifyCol(6,70)
LV_ModifyCol(7,130)
LV_ModifyCol(8,20)
LV_ModifyCol(9,300)
Gui,1:default
return
7GuiCreate:
Gui,7:-sysmenu +owner6
Gui,7:+hwndhAddMapWin ; -DPIScale ; +alwaysontop
;Gui,7:Color,dfdfdf
Gui,7:Margin,10,10
Gui,7:font,s8
Gui,7:add,text,xm ym w120,Адрес: ;
Gui,7:Add,Edit,x+3 yp-3 w50 vMapAddres gMapChangeAddres +hwndhMapAddres -Multi,1
Gui,7:add,text,x+5 yp+3,HEX:
Gui,7:Add,Edit,x+3 yp-3 w50 vMapAddresHEX gMapChangeAddres +hwndhMapAddresHEX -Multi,1
Gui,7:add,text,xm y+10 w120,Номер регистра: ;
Gui,7:Add,Edit,x+3 yp-3 w50 vMapRegNum gMapChangeRegNum +hwndhMapRegNum -Multi,0
Gui,7:add,text,x+5 yp+3,HEX:
Gui,7:Add,Edit,x+3 yp-3 w50 vMapRegNumHEX gMapChangeRegNum +hwndhMapRegNumHEX -Multi,0
Gui,7:add,text,xm y+10 w120,Тип данных: ;
Gui,7:Add,DropDownList,x+3 yp-3 w195 Choose1 vMapDataType +hwndhMapDataType,INT|WORD|DINT|DWORD|REAL
Gui,7:add,text,xm y+10 w120,Тип регистра: ;
Gui,7:Add,DropDownList,x+3 yp-3 w195 AltSubmit Choose1 vMapRegType +hwndhMapRegType,% RTUFunc3 "|" RTUFunc4
Gui,7:add,text,xm y+10 w120,Коментарий: ;
Gui,7:Add,Edit,xm y+3 w315 h70 vMapComment +hwndhMapComment Limit120 -WantReturn
Gui,7:add,Button,xm+145 y+10 w80 gMapAddReg default +hwndhMapAddReg,Добавить ;
Gui,7:add,Button,x+10 yp w80 gMapCancelReg,Отмена ;
return
8GuiCreate:
Gui,8:-sysmenu +owner6
Gui,8:+hwndhEditMapWin ; -DPIScale ; +alwaysontop
;Gui,8:Color,dfdfdf
Gui,8:Margin,10,10
Gui,8:font,s8
Gui,8:add,text,xm ym w100,Текущее значение: ;
Gui,8:Add,Edit,x+3 yp-3 w220 +ReadOnly vMapValueNow +hwndhMapValueNow -Multi
Gui,8:add,text,xm y+10 w100,Новое значение: ;
Gui,8:Add,Edit,x+3 yp-3 w220 vMapValueNew +hwndhMapValueNew -Multi
Gui,8:add,Button,xm+145 y+10 w80 gMapEditValue default +hwndhMapEditValue,Применить ;
Gui,8:add,Button,x+10 yp w80 gMapCancelValue,Закрыть ;
return
OpenFile:
if Analyzer
gosub,En_Analyzer
; Thread,NoTimers
FileSelectFile,OpenFileName,3,% OldOpenFileName,Открыть сохраненные данные буфера приема,COM terminal buffer data (*.ctbd)
; Thread,NoTimers,false
if errorlevel
{
tooltip,Отменено
settimer,RemoveTooltip,-2000
return
}
OldOpenFileName:=OpenFileName
OpenFileObj:=FileOpen(OpenFileName,"r","UTF-8-RAW")
if !IsObject(OpenFileObj)
{
MsgBox,% "Не возможно открыть файл " OpenFileName "."
return
}
gosub,DiskonnectCOM
FileLoading:=1
tooltip,Загрузка файла...`nДвойной клик чтобы отменить.
sleep,200
SaveBufer:={}
AnBufer:={}
varsetcapacity(tmpsavedata,4)
OpenFileObj.RawRead(tmpsavedata,4)
LoadSize:=numget(tmpsavedata,0,"Uint")
TotalLoadSize:=4
loop,% LoadSize
{
if StopAnalyze
{
StopAnalyze:=0
tooltip
break
}
if (TotalLoadSize>=OpenFileObj.Length)
break
GuiControl,,Progress,% a_index/LoadSize*100
LoadBlock:=a_index
SaveBufer[LoadBlock]:={}
OpenFileObj.RawRead(tmpsavedata,2)
LoadSizeB:=numget(tmpsavedata,0,"UShort")
TotalLoadSize+=2
ReadPack++
loop,% LoadSizeB
{
OpenFileObj.RawRead(tmpsavedata,1)
SaveBufer[LoadBlock,a_index]:=numget(tmpsavedata,0,"UChar")
TotalLoadSize+=1
}
}
GuiControl,,Progress,0
OpenFileObj.Close()
FileLoading:=0
LoadFile:=1
gosub,UnUpdate
LoadFile:=0
FileOpened:=1
GuiControl,,_text_,% "`n`tФайл открыт"
return
SaveFile:
if !OldSaveFileName
OldSaveFileName:=COMPort " " a_DD "." a_MM "." a_YYYY " " a_hour "." a_min
Thread,NoTimers
FileSelectFile,SaveFileName,S16,% OldSaveFileName,Сохранить данные буфера приема,COM terminal buffer data (*.ctbd)
Thread,NoTimers,false
if errorlevel
{
tooltip,Отменено
settimer,RemoveTooltip,-2000
return
}
if (!instr(SaveFileName,".ctbd") and FileExist(SaveFileName ".ctbd"))
{
msgBox,36,Сохранить данные буфера приема,Файл %SaveFileName%.ctbd существует.`nЗаменить?
IfMsgBox No
return
}
FileSaving:=1
tooltip,Сохранение файла...`nДвойной клик чтобы остановить.
sleep,200
SaveFileName:=instr(SaveFileName,".ctbd")?SaveFileName:SaveFileName . ".ctbd"
OldSaveFileName:=SaveFileName
SaveFileObj:=FileOpen(SaveFileName,"w","UTF-8-RAW")
if !IsObject(SaveFileObj)
{
MsgBox,% "Не возможно создать файл " SaveFileName "."
tooltip
return
}
varsetcapacity(tmpsavedata,4)
SaveSize:=SaveBufer.maxindex()
numput(SaveSize,tmpsavedata,0,"Uint")
SaveFileObj.RawWrite(tmpsavedata,4)
loop,% SaveSize
{
if StopAnalyze
{
StopAnalyze:=0
tooltip
break
}
GuiControl,,Progress,% a_index/SaveSize*100
SaveSizeB:=SaveBufer[a_index].maxindex()
SaveBlock:=a_index
numput(SaveSizeB,tmpsavedata,0,"UShort")
SaveFileObj.RawWrite(tmpsavedata,2)
loop,% SaveSizeB
{
numput(SaveBufer[SaveBlock,a_index],tmpsavedata,0,"UChar")
SaveFileObj.RawWrite(tmpsavedata,1)
}
}
GuiControl,,Progress,0
SaveFileObj.Close()
FileSaving:=0
tooltip
Msgbox,Сохранено.
return
GuiAbout:
gui,5:destroy
Gui,5:+owner1 -MinimizeBox -MaximizeBox
Gui,5:font,s8,Tahoma
gui,5:margin,70,10
gui,5:add,text,xm+25,Free software.
gui,5:add,text,xp-10 y+15,COM Port terminal
gui,5:add,text,xp+13 y+5,Версия: %Version%
gui,5:add,text,xp-13 y+15,Создатель: Alectric.
gui,5:add,Link,xp+13 y+15,<a href="http://forum.script-coding.com/viewtopic.php?id=15215">Серый форум</a>
gui,5:add,Link,xp-20 y+5,<a href="http://forum.script-coding.com/viewtopic.php?id=15216">Тема для обсуждения</a>
gui,5:show,,О программе
return
CheckMainExist:
process,exist,% 2ndThread
if !errorlevel
exitapp
return
ClearQueue:
ReadPos:=NumGet(Data,_DataPos,"Int")
ReadPack:=NumGet(Data,_PackagesRecieved,"Int")
if (ReadPos<0)
ReadPos:=0
if (ReadPack<0)
ReadPack:=0
return
showtext:
if !TurnBack
{
SendMessage, 0xB0, &E_Text_start, &E_Text_end, , ahk_id %E_Text% ; EM_GETSEL
SendMessage, 0x0E, , , , ahk_id %E_Text% ; WM_GETTEXTLENGTH
textlength:=Errorlevel
if !(NumGet(E_Text_start)=textlength)
GuiControl, -Redraw, %E_Text%
SendMessage, 0x00B1, textlength, textlength, , ahk_id %E_Text% ; EM_SETSEL
}
SendMessage, 0x00C2 , TRUE, &InText,, ahk_id %E_Text% ; EM_REPLACESEL
if !TurnBack
{
if !(NumGet(E_Text_start)=textlength)
SendMessage, 0x0B1, NumGet(E_Text_start), NumGet(E_Text_end), , ahk_id %E_Text% ; EM_SETSEL
GuiControl, +Redraw, %E_Text%
}
return
DiskonnectCOM:
GuiControl,,_text_,% COMPort "`n`t`tОтключен"
NumPut(1,Data,_Diskonnect,"UChar")
return
ParseBuffer:
if LoadFile
{
Received_Addres:=Bufer[1]
Received_Command:=Bufer[2]
Received_Byte:=Bufer[3]
; определить корректность контрольной суммы
CheckSummIsCorrect:=0
if (AddCS>=4 and RS232_Bytes_Received>2)
{
tmp1:=(Bufer[RS232_Bytes_Received]<<8)|Bufer[RS232_Bytes_Received-1]
tmp2:=CRC16(Bufer,RS232_Bytes_Received-2)
CheckSummIsCorrect:=(tmp1==tmp2)
}
else if (AddCS=2 or (AddCS=3 and RS232_Bytes_Received>2))
{
tmp0:=CRC16(Bufer,RS232_Bytes_Received-AddCSLenght,(ChoiceCSType=1),Polynom,InitVal,Refin,RefOut,XorOut,RefPoly)
if AddCS=2
tmp1:=Bufer[RS232_Bytes_Received]
else if AddCS=3
tmp1:=(Bufer[RS232_Bytes_Received]<<8)|Bufer[RS232_Bytes_Received-1]
tmp2:=(AddCS=3) ? tmp0 : tmp0&0xff
CheckSummIsCorrect:=(tmp1==tmp2)
}
; определить тип пакета Modbus
Received_Message_Type:=""
if (AddCS>=4)
{
if CheckSummIsCorrect
{
if (Received_Command>0 and Received_Command<5)
{
tmp1:=Bufer[3]
if (RS232_Bytes_Received=tmp1+5)
Received_Message_Type:="Ответ" (tmp1=3?" возможно Запрос":"")
else if (RS232_Bytes_Received=8)
Received_Message_Type:="Запрос"
}
else if (Received_Command>4 and Received_Command<7)
Received_Message_Type:="Запрос/Ответ"
else if (Received_Command=0x0f or Received_Command=0x10)
{
tmp1:=Bufer[7]
if (RS232_Bytes_Received=tmp1+9)
Received_Message_Type:="Запрос"
else
Received_Message_Type:="Ответ"
}
}
}
anindex:=RS232_Bytes_Received "|" Received_Addres "|" Received_Command "|" (Received_Message_Type?0:Received_Byte) "|" Received_Message_Type "|" CheckSummIsCorrect
if !isobject(AnBufer[anindex])
AnBufer[anindex]:={}
AnBufer[anindex].Push(Bufer.Clone())
}
; отфильтровать пакеты
Filtered:=0
if (!Analyzer)
if (Filter_Addres_EN or Filter_Command_EN or Filter_Byte_EN or Filter_Message_EN>1 or Filter_CRC_EN)
{
if (Filter_Addres_EN and Received_Addres!=Filter_Addres)
Filtered:=1
if (Filter_Command_EN and Received_Command!=Filter_Command)
Filtered:=1
if (Filter_Byte_EN and Received_Byte!=Filter_Byte)
Filtered:=1
if (Filter_Message_EN=2 and Received_Message_Type="Запрос")
Filtered:=1
if (Filter_Message_EN=3 and Received_Message_Type="Ответ" or Received_Message_Type="Ответ возможно Запрос")
Filtered:=1
if (AddCS>1 and Filter_CRC_EN and !CheckSummIsCorrect)
Filtered:=1
}
if (!Filtered or Analyzer)
{
if (!Analyzer and !TurnBack)
GuiControl,-Redraw,% E_LV
Add_rn:=0
regcount:=0
; разобраться с принятыми данными
loop,% RS232_Bytes_Received
{
rows++
LV_Icon:=ICON_EMPTY
LV_Hash:=""
LV_DEC:=Bufer[a_index]
LV_NumByte:=a_index-1
LV_HEX:=format("0x{:02x}",LV_DEC)
LV_Sym:=Chr(LV_HEX)
LV_Bin:=DECtoBIN(LV_HEX)
loop,% 8-strlen(LV_Bin)
LV_Bin:="0" . LV_Bin
LV_7Seg:=Arr7SEGtoASCII[(LV_DEC&~(1<<7))] . (LV_DEC&(1<<7)) ? "." : ""
LV_WORD:=LV_INT:=LV_DWORD:=LV_DINT:=LV_Float:=LV_Double:=""
if (MapRun and a_index=4)
{
Gui,6:default
LV_GetText(tmp4,MapNum,4)
Gui,1:default
}
if (RS232_Bytes_Received-a_index+2>2 and RS232_Bytes_Received>1)
{
varsetcapacity(LV_INT_tmp,2)
numput(Bufer[a_index],LV_INT_tmp,1,"uchar")
numput(Bufer[a_index+1],LV_INT_tmp,0,"uchar")
LV_WORD:=numget(LV_INT_tmp,0,"ushort")
LV_INT:=numget(LV_INT_tmp,0,"short")
if (tmp4="INT")
{
tmp5:=LV_INT
tmp6:=DATAtoHEX(&LV_INT_tmp,0,2,1)
tmp7:=DATAtoBIN(&LV_INT_tmp,0,2,1)
}
else if (tmp4="WORD")
{
tmp5:=LV_WORD
tmp6:=DATAtoHEX(&LV_INT_tmp,0,2,1)
tmp7:=DATAtoBIN(&LV_INT_tmp,0,2,1)
}
AddAdd(LV_INT)
}
if (RS232_Bytes_Received-a_index+2>4 and RS232_Bytes_Received>3)
{
varsetcapacity(LV_DINT_tmp,4)
numput(Bufer[a_index],LV_DINT_tmp,3,"uchar")
numput(Bufer[a_index+1],LV_DINT_tmp,2,"uchar")
numput(Bufer[a_index+2],LV_DINT_tmp,1,"uchar")
numput(Bufer[a_index+3],LV_DINT_tmp,0,"uchar")
LV_DWORD:=numget(LV_DINT_tmp,0,"uint")
LV_DINT:=numget(LV_DINT_tmp,0,"int")
LV_Float:=numget(LV_DINT_tmp,0,"float")
if (tmp4="DINT")
{
tmp5:=LV_DINT
tmp6:=DATAtoHEX(&LV_DINT_tmp,0,4,1)
tmp7:=DATAtoBIN(&LV_DINT_tmp,0,4,1)
}
else if (tmp4="DWORD")
{
tmp5:=LV_DWORD
tmp6:=DATAtoHEX(&LV_DINT_tmp,0,4,1)
tmp7:=DATAtoBIN(&LV_DINT_tmp,0,4,1)
}
else if (tmp4="REAL")
{
tmp5:=numget(LV_DINT_tmp,0,"float")
tmp6:=DATAtoHEX(&LV_DINT_tmp,0,4,1)
tmp7:=DATAtoBIN(&LV_DINT_tmp,0,4,1)
}
AddAdd(LV_DINT)
AddAdd(LV_Float)
}
if (RS232_Bytes_Received-a_index+2>8 and RS232_Bytes_Received>7)
{
varsetcapacity(LV_Double_tmp,8)
numput(Bufer[a_index],LV_Double_tmp,7,"uchar")
numput(Bufer[a_index+1],LV_Double_tmp,6,"uchar")
numput(Bufer[a_index+2],LV_Double_tmp,5,"uchar")
numput(Bufer[a_index+3],LV_Double_tmp,4,"uchar")
numput(Bufer[a_index+4],LV_Double_tmp,3,"uchar")
numput(Bufer[a_index+5],LV_Double_tmp,2,"uchar")
numput(Bufer[a_index+6],LV_Double_tmp,1,"uchar")
numput(Bufer[a_index+7],LV_Double_tmp,0,"uchar")
LV_Double:=numget(LV_Double_tmp,0,"Double")
AddAdd(LV_Double)
}
if (MapRun and MapNum and a_index=4)
{
Gui,6:default
LV_GetText(tmp1,MapNum,1)
LV_GetText(tmp2,MapNum,2)
LV_GetText(tmp3,MapNum,3)
LV_GetText(tmp4,MapNum,4)
LV_GetText(tmp8,MapNum,8)
LV_GetText(tmp9,MapNum,9)
if (Bufer[2]&0x80)
{
tmp5:=""
tmp6:=""
tmpt:=Bufer[3]
tmp7:=RTUErr%tmpt%
}
if (CheckSummIsCorrect)
{
tmpMap[MapNum]:=[tmp1,tmp2,tmp3,tmp4,tmp5,tmp6,tmp7,tmp8,tmp9]
LV_Modify(MapNum,,tmp1,tmp2,tmp3,tmp4,tmp5,tmp6,tmp7,tmp8="/"?"\":"/",tmp9)
if (MapChangeVtmp and MapNum=MapEditNum)
{
if (MapChangeVtmp=1)
GuiControl,,% hMapValueNow,% tmp5
else if (MapChangeVtmp=2)
GuiControl,,% hMapValueNow,% tmp6
else if (MapChangeVtmp=3)
GuiControl,,% hMapValueNow,% tmp7
}
}
else
LV_Modify(MapNum,,tmp1,tmp2,tmp3,tmp4,tmpMap[MapNum,5],tmpMap[MapNum,6],tmpMap[MapNum,7],"",tmp9)
LV_Modify(MapNum,"Focus")
MapNext:=1
Gui,1:default
}
if EN_Kurvendrucker
{
Monitorintext.=LV_Sym
DetectAutoEndtext.=LV_Sym
MonLen:=strlen(DetectAutoEndtext)-100
if (strlen(DetectAutoEndtext)>100)
StringTrimLeft,DetectAutoEndtext,DetectAutoEndtext,% MonLen
;tooltip,% DetectAutoEndtext
}
if (a_index=1)
{
LV_Icon:=ICON_START
if !Received_Message_Type
LV_Hash:="Start " Packages_Recieved
else
LV_Hash:=Received_Message_Type " " Packages_Recieved
}
if (AddCS>=4)
{
; работаем с Modbus
; if CheckSummIsCorrect
{
LV_NumByte:=""
if (Received_Message_Type="Ответ" or Received_Message_Type="Ответ возможно Запрос") ; ---------------------------------------------------------
{
if (Received_Command>0 and Received_Command<5)
{
if (a_index=3)
{
if !RTUErrorWasOcured
LV_NumByte:="Кол-во байт далее"
else
LV_NumByte:=RTUErr%LV_DEC%
LV_Icon:=ICON_INFO
}
if (a_index>3 and a_index<RS232_Bytes_Received-1)
{
if ((Received_Command>2 and Received_Command<5) and !(a_index&1))
{
LV_NumByte:="+" regcount " (+0x" format("{:x}",regcount) ")"
regcount++
LV_Icon:=ICON_REGISTER
LV_Hash:="Значения регистров по смещению"
}
if (Received_Command>0 and Received_Command<3)
{
LV_NumByte:=(regcount+1)*8 "-" regcount*8
regcount++
LV_Icon:=ICON_REGISTER
LV_Hash:="Значения битов по смещению"
}
}
}
else if (Received_Command=0xf or Received_Command=0x10)
{
if (a_index=3)
{
LV_NumByte:="Стартовый регистр"
LV_Icon:=ICON_INFO
LV_tmp:=LV_WORD
}
if (a_index=4)
LV_NumByte:=LV_tmp " (" format("0x{:x}",LV_tmp) ")"
if (a_index=5)
{
LV_NumByte:="Кол-во запрашиваемых регистров"
LV_Icon:=ICON_INFO
LV_tmp:=LV_WORD
}
if (a_index=6)
LV_NumByte:=LV_tmp " (" format("0x{:x}",LV_tmp) ")"
}
}
else if (Received_Message_Type="Запрос") ; ---------------------------------------------------------
{
if (Received_Command>0 and Received_Command<5)
{
if (a_index=3)
{
LV_NumByte:="Стартовый регистр"
LV_Icon:=ICON_INFO
LV_tmp:=LV_WORD
}
if (a_index=4)
LV_NumByte:=LV_tmp " (" format("0x{:x}",LV_tmp) ")"
if (a_index=5)
{
if (Received_Command<3)
LV_NumByte:="Кол-во запрашиваемых бит"
if (Received_Command>2)
LV_NumByte:="Кол-во запрашиваемых регистров"
LV_Icon:=ICON_INFO
LV_tmp:=LV_WORD
}
if (a_index=6)
LV_NumByte:=LV_tmp " (" format("0x{:x}",LV_tmp) ")"
}
else if (Received_Command=0xf or Received_Command=0x10)
{
if (a_index=3)
{
LV_NumByte:="Стартовый регистр"
LV_Icon:=ICON_INFO
LV_tmp:=LV_WORD
}
if (a_index=4)
LV_NumByte:=LV_tmp " (" format("0x{:x}",LV_tmp) ")"
if (a_index=5)
{
LV_NumByte:="Кол-во записываемых регистров"
LV_Icon:=ICON_INFO
LV_tmp:=LV_WORD
}
if (a_index=6)
LV_NumByte:=LV_tmp " (" format("0x{:x}",LV_tmp) ")"
if (a_index=7)
{
LV_NumByte:="Кол-во байт далее = " LV_DEC
LV_Icon:=ICON_INFO
LV_tmp:=LV_WORD
}
if (a_index>7 and a_index<RS232_Bytes_Received-1)
{
if (Received_Command=0x10 and !(a_index&1))
{
LV_NumByte:="+" regcount " (+0x" format("{:x}",regcount) ")"
regcount++
LV_Icon:=ICON_REGISTER
LV_Hash:="Значения регистров по смещению"
}
if (Received_Command=0xf)
{
LV_NumByte:=(regcount+1)*8-1 "-" regcount*8
regcount++
LV_Icon:=ICON_REGISTER
LV_Hash:="Значения битов по смещению"
}
}
}
}
else if (Received_Message_Type="Запрос/Ответ") ; ---------------------------------------------------------
{
if (a_index=3)
{
LV_NumByte:="Регистр"
LV_Icon:=ICON_INFO
LV_tmp:=LV_WORD
}
if (a_index=4)
LV_NumByte:=LV_tmp " (" format("0x{:x}",LV_tmp) ")"
if (a_index=5)
{
LV_NumByte:="Значение"
LV_Icon:=ICON_INFO
if (LV_WORD=0xff00)
LV_tmp:="ON (" format("0x{:x}",LV_WORD) ")"
else if (LV_WORD=0x0000)
LV_tmp:="OFF (" format("0x{:x}",LV_WORD) ")"
else
LV_tmp:=LV_WORD " (" format("0x{:x}",LV_WORD) ")"
}
if (a_index=6)
LV_NumByte:=LV_tmp
}
if (a_index=1)
LV_NumByte:="Адрес"
if (a_index=2)
{
RTUErrorWasOcured:=0
if (LV_DEC&0x80)
{
RTUErrorWasOcured:=1
LV_NumByte:="Ошибка"
LV_Icon:=ICON_ERROR
}
else
{
LV_NumByte:=RTUFunc%LV_DEC%
LV_Hash:=RTUF%LV_DEC%
}
}
if (a_index=3 and RTUErrorWasOcured)
{
LV_NumByte:=RTUErr%LV_DEC%
LV_Icon:=ICON_INFO
}
}
; else
; LV_NumByte:=""
if (a_index>RS232_Bytes_Received-2)
LV_NumByte:=""
}
if (a_index>1 and AddCS>1 and !CheckSummIsCorrect)
LV_Icon:=ICON_X
if (AddCS>1)
{
if ((AddCS>2 and a_index=(RS232_Bytes_Received-1)) or (a_index=RS232_Bytes_Received))
{
if CheckSummIsCorrect
{
LV_Icon:=ICON_V
LV_Hash:="CRC" ;"V"
LV_NumByte:="Контрольная сумма верна"
}
else
{
LV_Icon:=ICON_CRC_ERROR
LV_Hash:="CRC" ;"X"
LV_NumByte:="Ошибка контрольной суммы"
}
}
}
; -------------------------------------------------------------------------------------
if !EN_Kurvendrucker
LV_Add("Icon" LV_Icon,LV_Hash,a_index-1,LV_NumByte,LV_Bin,LV_Sym,LV_HEX,LV_DEC,LV_WORD,LV_INT,LV_DWORD,LV_DINT,LV_Float,LV_Double)
; #|№ байта|№ байта или описание|BIN|SYM|HEX|DEC|INT|WORD|DINT|DWORD|Float|Double
; -------------------------------------------------------------------------------------
if !(LV_HEX=0x0a or LV_HEX=0x0d)
tmp_intext.=(LV_HEX ? LV_Sym : " ")
if (LV_HEX=0x0a) ; and LV_HEX_old=0x0d)
{
InText:=tmp_intext . (instr(tmp_intext,"`r`n") ? "" : "`r`n")
tmp_intext=
Add_rn:=1
if (!Analyzer)
gosub,showtext
}
LV_HEX_old:=LV_HEX
}
if !EN_Kurvendrucker
LV_Add("Icon" 0,," ")
if (!Analyzer and !TurnBack)
GuiControl,+Redraw,% E_LV
if (!Analyzer and !TurnBack)
GuiControl,,Progress,% rows/Rownums*100
if (rows>Rownums and !Analyzer and !TurnBack)
gosub,Update
if (tmp_intext)
{
InText:=tmp_intext . (AddCRLF ? "`r`n" : "")
Add_rn:=1
tmp_intext=
if (!Analyzer)
gosub,showtext
}
if (!FollowSelect and !LV_GetCount("S") and !Analyzer and !TurnBack)
{
LV_Modify(LV_GetCount(),"Vis")
sleep,10
}
else if (FollowSelect and CountSelected:=LV_GetCount("S") and !Analyzer and !TurnBack)
{
startpos:=LV_GetCount()-OldGetCount+LV_GetNext()
LV_Modify(0,"-Select")
loop,% CountSelected
LV_Modify(startpos+a_index-1,"Select")
LV_Modify(startpos+CountSelected-1,"Vis Focus")
sleep,10
gosub,ListGetSelected
}
else if (FollowSelect and !LV_GetCount("S") and !Analyzer and !TurnBack)
{
LV_Modify(LV_GetCount(),"Vis")
sleep,10
}
if EN_MonitorVar
{
varsetcapacity(Monitorvalue_tmp,Slave_Len)
loop,% Slave_Len
numput(Bufer[Slave_Start_Byte+a_index],Monitorvalue_tmp,Slave_Len-a_index,"uchar")
;tooltip,% Slave_Data_Type "`n=" Bufer[Slave_Start_Byte+1] "=`nstb=" Slave_Start_Byte "`nsl=" Slave_Len,0,,7
Monitorvalue:=numget(Monitorvalue_tmp,0,Slave_Data_Type)
if GrafPause
Gdip_X_Offset+=1
else
Gdip_Marker_mx-=Gdip_ZoomX
Monitor_value.InsertAt(1,Monitorvalue)
Monitor_value_T.InsertAt(1,a_hour ":" a_min "." a_sec "." a_MSec)
gosub,GrafDraw
}
OldGetCount:=LV_GetCount()
if EN_Kurvendrucker
{
if AutoEnding
{
TryFind++
if (TryFind>10)
{
findMetaSbl(DetectAutoEndtext,SplSymbol,EndSymbol)
TryFind:=0
}
}
;tooltip,% TryFind "`n""" SplSymbol """`n""" EndSymbol """"
if (EndSymbol!="")
while(EndPos:=instr(Monitorintext,EndSymbol))
{
; RS232_Bytes_Reqest:=EndPos*2
; GuiControl,,RS232_Bytes_Reqest,% RS232_Bytes_Reqest
Monitoringtext:=substr(Monitorintext,1,EndPos-1)
StringTrimLeft,Monitorintext,Monitorintext,% EndPos
if (SplSymbol==EndSymbol)
{
loop,parse,Monitoringtext,% EndSymbol
{
if (a_loopfield!="")
{
tmp1:=a_loopfield
if instr(tmp1,"`r")
StringTrimRight,tmp1,tmp1,1
Monitor_value1.InsertAt(1,tmp1)
Monitor_value_T.InsertAt(1,a_hour ":" a_min "." a_sec "." a_MSec)
if GrafPause
Gdip_X_Offset+=1
else
Gdip_Marker_mx-=Gdip_ZoomX
}
}
NumOfGraf:=1
}
else
{
if (Monitoringtext!="")
{
NumOfGraf:=0
loop,parse,Monitoringtext,% SplSymbol
{
if (a_loopfield!="")
{
tmp1:=a_loopfield
if instr(tmp1,"`r")
StringTrimRight,tmp1,tmp1,1
Monitor_value%a_index%.InsertAt(1,tmp1)
NumOfGraf++
}
}
Monitor_value_T.InsertAt(1,a_hour ":" a_min "." a_sec "." a_MSec)
if GrafPause
Gdip_X_Offset+=1
else
Gdip_Marker_mx-=Gdip_ZoomX
}
}
}
gosub,GrafDraw
}
}
return
ClUpdate:
Thread,NoTimers
msgBox,36,Удалить все данные,Вы действительно хотите удалить все данные?
Thread,NoTimers,false
IfMsgBox No
return
ObjClear(Monitor_value)
ObjClear(Monitor_value_T)
loop,% MaxNumOfGraf
ObjClear(Monitor_value%a_index%)
ObjClear(SaveBufer)
ObjClear(AnBufer)
ObjClear(AnCufer)
settimer,Update,-500
return
Update:
Update:=1
If !analyzer
{
Packages_Recieved:=0
rows=
GuiControl,,_InText_
GuiControl,,Progress,0
LV_Delete()
tmp_intext=
}
else
gosub,Analyze
return
UnUpdate:
gosub,Update
TurnBack:=1
tooltip,Загрузка таблицы...`nДвойной клик чтобы отменить.
GuiControl,-Redraw,% E_LV
GuiControl,-Redraw,% E_Text
loop,% SaveBufer.maxindex()
{
if StopAnalyze
{
StopAnalyze:=0
tooltip
break
}
Packages_Recieved++
GuiControl,,Progress,% a_index/SaveBufer.maxindex()*100
Gui,1:ListView,% E_LV
Bufer:=SaveBufer[a_index]
RS232_Bytes_Received:=Bufer.maxindex()
gosub,ParseBuffer
}
LV_Modify(LV_GetCount(),"Vis")
GuiControl,+Redraw,% E_LV
GuiControl,+Redraw,% E_Text
tooltip
GuiControl,,Progress,0
TurnBack:=0
return
SkeepPack:
SkeepPack:=!SkeepPack
if SkeepPack
{
menu,ListRightClick2,Check,Пропуск пакетов ;
menu,BufferMenu,Check,Пропуск пакетов ;
gosub,ClearQueue
}
else
{
menu,ListRightClick2,UnCheck,Пропуск пакетов ;
menu,BufferMenu,UnCheck,Пропуск пакетов ;
}
return
ToTheEnd:
SendMessage, 0x0E, , , , ahk_id %E_Text% ; WM_GETTEXTLENGTH
textlength:=Errorlevel
SendMessage, 0x00B1, textlength, textlength, , ahk_id %E_Text% ; EM_SETSEL
GuiControl, +Redraw, %E_Text%
LV_Modify(0,"-Select")
return
ResetUnCOMPort:
UnCOMPort:=""
return
ComList:
ComPortList:=SearchCOM("",1)
if !FileOpened
GuiControl,,% E_Text,% "`n`nНайденные в системе порты:`n" (ComPortList ? ComPortList : "Портов нет.")
return
AceptSettings:
gosub,submiting
FileOpened:=0
settimer,ComList,1000
COMPort:=""
while(!COMPort)
{
sleep,1000
if FileOpened
return
gosub,submiting
dots.=">"
if (strlen(dots)>20)
dots:=""
if (ChoiceCOM=1)
COMPort:=SearchCOM("USB")
else if (ChoiceCOM=2)
COMPort:="COM" ManualCOM
else if (ChoiceCOM=3)
COMPort:=SearchCOM(ManualCOMByName)
if (!COMPort and ChoiceCOM and !FileOpened)
GuiControl,,_text_,% COMPort "`nCOM-порт не обнаружен`nПоиск " dots
if (COMPort==UnCOMPort)
COMPort:=""
}
settimer,ComList,off
settimer,ResetUnCOMPort,off
GuiControl,,_text_,% COMPort "`n`tподключение"
GuiControl,,% E_Text,% COMPort " подключение"
doonce:=0
StrPut(COMPort,&Data+_COMPort,12)
NumPut(RS232_Baud,Data,_RS232_Baud,"Int")
NumPut(asc(RS232_Parity),Data,_RS232_Parity,"Int")
NumPut(RS232_Data,Data,_RS232_Data,"Int")
NumPut(RS232_Stop,Data,_RS232_Stop,"Int")
NumPut(RTimeout,Data,_RTimeout,"Int")
NumPut(EmptyPacket,Data,_EmptyPacket,"Int")
NumPut(ReadIntervalTimeout,Data,_ReadIntervalTimeout,"Int")
NumPut(0,Data,_Diskonnect,"UChar")
NumPut(1,Data,_ApplyCOMSettings,"UChar")
sleep,300
; gosub,ClearQueue
Gui,6:default
SB_SetText(COMPort)
Gui,1:default
return
ChoiceCSType:
gosub,Submiting
if (ChoiceCSType=1)
{
loop,8
{
a:=a_index+2
GuiControl,hide,% hECSType%a%
}
}
else
{
loop,8
{
a:=a_index+2
GuiControl,show,% hECSType%a%
}
}
return
Submiting:
Gui,1:submit,nohide
AddCSLenght:=(AddCS>2 ? 2:AddCS-1)
Polynom:=instr(Polynom,"0x")?Polynom+0:"0x" Polynom
InitVal:=instr(InitVal,"0x")?InitVal:"0x" InitVal
XorOut:=instr(XorOut,"0x")?XorOut:"0x" XorOut
return
SubmitExt:
gosub,submiting
if (a_GuiControl="AddCS")
{
if (AddCS=5)
{
MoveControl(E_1,,E_1_ShiftSize,,-E_1_ShiftSize)
loop,2
GuiControl,Show,% hE_RTU_Command_%a_index%
loop,5
GuiControl,Show,% hE_RTU_StartReg_%a_index%
loop,6
GuiControl,Show,% hE_RTU_Addres_%a_index%
loop,5
GuiControl,Show,% hE_RTU_RegNum_%a_index%
loop,2
GuiControl,Show,% hE_RTU_Val_%a_index%
}
else
{
GuiControl,enable,% E_1
if (PrevAddCS=5)
MoveControl(E_1,,-E_1_ShiftSize,,E_1_ShiftSize)
loop,2
GuiControl,hide,% hE_RTU_Command_%a_index%
loop,5
GuiControl,hide,% hE_RTU_StartReg_%a_index%
loop,6
GuiControl,hide,% hE_RTU_Addres_%a_index%
loop,5
GuiControl,hide,% hE_RTU_RegNum_%a_index%
loop,2
GuiControl,hide,% hE_RTU_Val_%a_index%
}
if (AddCS>=4)
{
GuiControl,Show,% hFiltE4
GuiControl,Show,% hFiltE5
GuiControl,Show,% hFiltE6
GuiControl,Show,% hFiltE7
; GuiControl,Show,% hAutoByRe
loop,3
GuiControl,disable,% hFiltE%a_index%
Gui,4:submit,nohide
Filter_CommandFlag:=1
if (Filter_CommandRTU>0 and Filter_CommandRTU<7)
Filter_Command:=Filter_CommandRTU
else if (Filter_CommandRTU>6)
Filter_Command:=Filter_CommandRTU+8
GuiControl,,% hFiltE1,% Filter_Command
GuiControl,show,% hModbusMapOpen
}
else
{
GuiControl,hide,% hFiltE4
GuiControl,hide,% hFiltE5
GuiControl,hide,% hFiltE6
GuiControl,hide,% hFiltE7
; GuiControl,hide,% hAutoByRe
loop,3
GuiControl,enable,% hFiltE%a_index%
GuiControl,hide,% hModbusMapOpen
}
if (AddCS>1)
GuiControl,show,% hFiltE8
else
GuiControl,hide,% hFiltE8
if (AddCS=3)
{
loop,10
GuiControl,show,% hECSType%a_index%
gosub,ChoiceCSType
}
else
{
loop,10
GuiControl,hide,% hECSType%a_index%
}
PrevAddCS:=AddCS
}
if (AddCS=5)
{
if (RTU_Command>0 and RTU_Command<5)
{
loop,5
guicontrol,enable,% hE_RTU_RegNum_%a_index%
loop,2
GuiControl,disable,% hE_RTU_Val_%a_index%
GuiControl,disable,% E_1
}
if (RTU_Command=5 or RTU_Command=6)
{
if SendDataRepitedly
gosub,SendDataRepitedly
loop,5
guicontrol,disable,% hE_RTU_RegNum_%a_index%
loop,2
GuiControl,enable,% hE_RTU_Val_%a_index%
GuiControl,enable,% E_1
}
if (RTU_Command=7 or RTU_Command=8)
{
if SendDataRepitedly
gosub,SendDataRepitedly
loop,5
guicontrol,enable,% hE_RTU_RegNum_%a_index%
loop,2
GuiControl,enable,% hE_RTU_Val_%a_index%
GuiControl,enable,% E_1
}
}
if (hi_lim<1)
hi_lim:=1
if ModbusMapOpen
AddCS=4
return
ChangeAddres:
gosub,submiting
if (a_GuiControl="RTU_SlaveAdress")
{
if RTU_SlaveAdressHEXFlag
{
RTU_SlaveAdressHEXFlag:=0
return
}
RTU_SlaveAdressFlag:=1
GuiControl,,RTU_SlaveAdressHEX,% format("{:X}",RTU_SlaveAdress)
}
else if (a_GuiControl="RTU_SlaveAdressHEX")
{
if RTU_SlaveAdressFlag
{
RTU_SlaveAdressFlag:=0
return
}
RTU_SlaveAdressHEXFlag:=1
tmp:="0x" RTU_SlaveAdressHEX
GuiControl,,RTU_SlaveAdress,% tmp+0
}
return
ChangeStartReg:
gosub,submiting
if (a_GuiControl="RTU_StartReg")
{
if RTU_StartRegHEXFlag
{
RTU_StartRegHEXFlag:=0
return
}
RTU_StartRegFlag:=1
GuiControl,,RTU_StartRegHEX,% format("{:X}",RTU_StartReg)
}
else if (a_GuiControl="RTU_StartRegHEX")
{
if RTU_StartRegFlag
{
RTU_StartRegFlag:=0
return
}
RTU_StartRegHEXFlag:=1
tmp:="0x" RTU_StartRegHEX
GuiControl,,RTU_StartReg,% tmp+0
}
return
ChangeRegNum:
gosub,submiting
if (a_GuiControl="RTU_RegNum")
{
if RTU_RegNumHEXFlag
{
RTU_RegNumHEXFlag:=0
return
}
RTU_RegNumFlag:=1
GuiControl,,RTU_RegNumHEX,% format("{:X}",RTU_RegNum)
}
else if (a_GuiControl="RTU_RegNumHEX")
{
if RTU_RegNumFlag
{
RTU_RegNumFlag:=0
return
}
RTU_RegNumHEXFlag:=1
tmp:="0x" RTU_RegNumHEX
GuiControl,,RTU_RegNum,% tmp+0
}
return
ChangeFilter_Addres:
Gui,4:submit,nohide
if (a_GuiControl="Filter_Addres")
{
if Filter_AddresHEXFlag
{
Filter_AddresHEXFlag:=0
return
}
Filter_AddresFlag:=1
GuiControl,,Filter_AddresHEX,% format("{:X}",Filter_Addres)
}
else if (a_GuiControl="Filter_AddresHEX")
{
if Filter_AddresFlag
{
Filter_AddresFlag:=0
return
}
Filter_AddresHEXFlag:=1
tmp:="0x" Filter_AddresHEX
GuiControl,,Filter_Addres,% tmp+0
}
return
ChangeFilter_Command:
Gui,4:submit,nohide
if (a_GuiControl="Filter_Command")
{
if (Filter_CommandHEXFlag)
{
Filter_CommandHEXFlag:=0
return
}
Filter_CommandFlag:=1
GuiControl,,Filter_CommandHEX,% format("{:X}",Filter_Command)
}
else if (a_GuiControl="Filter_CommandHEX")
{
if (Filter_CommandFlag)
{
Filter_CommandFlag:=0
return
}
Filter_CommandHEXFlag:=1
tmp:="0x" Filter_CommandHEX
GuiControl,,Filter_Command,% tmp+0
Filter_Command:=tmp+0
}
else if (a_GuiControl="Filter_CommandRTU")
{
Filter_CommandFlag:=1
if (Filter_CommandRTU>0 and Filter_CommandRTU<7)
Filter_Command:=Filter_CommandRTU
else if (Filter_CommandRTU>6)
Filter_Command:=Filter_CommandRTU+8
GuiControl,,Filter_Command,% Filter_Command
}
return
ChangeFilter_Byte:
Gui,4:submit,nohide
if (a_GuiControl="Filter_Byte")
{
if Filter_ByteHEXFlag
{
Filter_ByteHEXFlag:=0
return
}
Filter_ByteFlag:=1
GuiControl,,Filter_ByteHEX,% format("{:X}",Filter_Byte)
}
else if (a_GuiControl="Filter_ByteHEX")
{
if Filter_ByteFlag
{
Filter_ByteFlag:=0
return
}
Filter_ByteHEXFlag:=1
tmp:="0x" Filter_ByteHEX
GuiControl,,Filter_Byte,% tmp+0
}
return
ChoseCOMNo:
gosub,submiting
if (!noChoseCOMNo)
{
noChoseCOMNo:=1
return
}
GuiControl,,% hCOMNo,1
return
ChoseCOMName:
gosub,submiting
GuiControl,,% hCOMName,1
return
AddSettings:
Gui,2:show
return
CalcTimeout:
Gui,2:submit,nohide
stringleft,RS232_Parity_Choice,RS232_Parity_Choice,1
RS232_Baud:=RS232_Baud_Choice
RS232_Parity:=RS232_Parity_Choice
RS232_Data:=RS232_Data_Choice
RS232_Stop:=RS232_Stop_Choice
Timeout:=((RS232_Data+4)/RS232_Baud)*1000
ReadIntervalTimeout:=Floor(Timeout)
if (ReadIntervalTimeout=0)
ReadIntervalTimeout:=1
GuiControl,,% hTimeout,% "Расчетный = " Timeout " ms"
GuiControl,,% hRITimeout,% ReadIntervalTimeout
return
CancelAddSettings:
Gui,2:hide
Gui,1:show
return
EndAddSettings:
Gui,2:submit
if !ModbusMapOpen
Gui,1:show
stringleft,RS232_Parity_Choice,RS232_Parity_Choice,1
RS232_Baud:=RS232_Baud_Choice
RS232_Parity:=RS232_Parity_Choice
RS232_Data:=RS232_Data_Choice
RS232_Stop:=RS232_Stop_Choice
gosub,AceptSettings
return
DefaultSettings:
GuiControl,Choose,RS232_Baud_Choice,14
GuiControl,Choose,RS232_Parity_Choice,1
GuiControl,Choose,RS232_Data_Choice,4
GuiControl,Choose,RS232_Stop_Choice,1
gosub,CalcTimeout
return
ButtonSendData:
gosub,submiting
SendData:=1
NumPut(2,Data,_MapSkip,"Int")
gosub,SendData
return
SendData:
if (NumGet(Data,_SendDataNow,"UChar"))
return
gosub,submiting
SendData:=0
if MapChangeV
{
; if (MapNum>1)
; MapNum--
AddCS:=5
AddCSLenght:=2
RTU_Command:=6
RTU_SlaveAdress:=MapList[MapEditNum,1]
RTU_StartReg:=MapList[MapEditNum,2]
if (MapList[MapEditNum,3]="INT" or MapList[MapEditNum,3]="WORD")
RTU_RegNum:=1
else
RTU_RegNum:=2
DataToSend:=MapValueNew
ChoiceFormat:=MapChangeV+1
if (MapList[MapEditNum,3]="INT")
ChoiceType:="Short"
else if (MapList[MapEditNum,3]="WORD")
ChoiceType:="UShort"
else if (MapList[MapEditNum,3]="DINT")
ChoiceType:="Int"
else if (MapList[MapEditNum,3]="DWORD")
ChoiceType:="UInt"
else if (MapList[MapEditNum,3]="REAL")
ChoiceType:="Float"
ChoiceSize:=RTU_RegNum*2
;msgbox,% RTU_SlaveAdress "`n" RTU_StartReg "`n" RTU_RegNum "`n" DataToSend "`n" ChoiceFormat "`nm4=" (MapList[MapEditNum,3]) "`n" "`n" "`n"
NumPut(2,Data,_MapSkip,"Int")
}
if (AddCS=5)
{
if (RTU_Command>0 and RTU_Command<5)
{
; if (Auto_Bytes_Reqest and (RTU_Command=1 or RTU_Command=2))
; RS232_Bytes_Reqest:=Ceil(RTU_RegNum/8)+6
; if (Auto_Bytes_Reqest and (RTU_Command=3 or RTU_Command=4))
; RS232_Bytes_Reqest:=RTU_RegNum*2+6
size_to_send:=6
varsetcapacity(VarDataToSend,size_to_send+AddCSLenght)
NumPut(RTU_SlaveAdress,VarDataToSend,0,"uchar")
NumPut(RTU_Command,VarDataToSend,1,"uchar")
NumPut(SwapByte(RTU_StartReg),VarDataToSend,2,"ushort")
NumPut(SwapByte(RTU_RegNum),VarDataToSend,4,"ushort")
NumPut(CRC16(VarDataToSend,size_to_send),VarDataToSend,size_to_send,"ushort")
}
else if (RTU_Command=5 or RTU_Command=6)
{
; if Auto_Bytes_Reqest
; RS232_Bytes_Reqest:=9
size_to_send:=6
varsetcapacity(VarDataToSend,size_to_send+AddCSLenght)
NumPut(RTU_SlaveAdress,VarDataToSend,0,"uchar")
NumPut(RTU_Command,VarDataToSend,1,"uchar")
NumPut(SwapByte(RTU_StartReg),VarDataToSend,2,"ushort")
if (ChoiceFormat=1) ;text
size_to_send_tmp:=STRToDATA(DataToSend,VarDataToSend_tmp)
else if (ChoiceFormat=2) ;DEC
size_to_send_tmp:=DECToDATA(DataToSend,VarDataToSend_tmp,1,ChoiceType,ChoiceSize)
else if (ChoiceFormat=3) ;HEX
size_to_send_tmp:=HEXstrToDATA(DataToSend,VarDataToSend_tmp)
else if (ChoiceFormat=4) ;BIN
size_to_send_tmp:=BINstrToDATA(DataToSend,VarDataToSend_tmp)
NumPut(numget(VarDataToSend_tmp,0,"Uchar"),VarDataToSend,4,"ushort")
NumPut(numget(VarDataToSend_tmp,1,"Uchar"),VarDataToSend,5,"ushort")
NumPut(CRC16(VarDataToSend,size_to_send),VarDataToSend,size_to_send,"ushort")
}
else if (RTU_Command=7 or RTU_Command=8)
{
; if Auto_Bytes_Reqest
; RS232_Bytes_Reqest:=9
if (RTU_Command=7)
{
RTU_Command=15
RTU_ByteNum:=ceil(RTU_RegNum/8)
size_to_send:=7+ceil(RTU_RegNum/8)
}
if (RTU_Command=8)
{
RTU_Command=16
RTU_ByteNum:=RTU_RegNum*2
size_to_send:=7+RTU_ByteNum
}
varsetcapacity(VarDataToSend,size_to_send+AddCSLenght)
NumPut(RTU_SlaveAdress,VarDataToSend,0,"uchar")
NumPut(RTU_Command,VarDataToSend,1,"uchar")
NumPut(SwapByte(RTU_StartReg),VarDataToSend,2,"ushort")
NumPut(SwapByte(RTU_RegNum),VarDataToSend,4,"ushort")
NumPut(RTU_ByteNum,VarDataToSend,6,"uchar")
if (ChoiceFormat=1) ;text
size_to_send_tmp:=STRToDATA(DataToSend,VarDataToSend_tmp)
else if (ChoiceFormat=2) ;DEC
size_to_send_tmp:=DECToDATA(DataToSend,VarDataToSend_tmp,1,ChoiceType,ChoiceSize)
else if (ChoiceFormat=3) ;HEX
size_to_send_tmp:=HEXstrToDATA(DataToSend,VarDataToSend_tmp)
else if (ChoiceFormat=4) ;BIN
size_to_send_tmp:=BINstrToDATA(DataToSend,VarDataToSend_tmp)
loop,% RTU_ByteNum
NumPut(numget(VarDataToSend_tmp,a_index-1,"Uchar"),VarDataToSend,a_index+6,"uchar")
NumPut(CRC16(VarDataToSend,size_to_send),VarDataToSend,size_to_send,"ushort")
}
if Auto_Bytes_Reqest
Reset_Bytes_Reqest:=1
if !MapRun
if (RTU_Command>4 and !BeliveMe)
return
else if (RTU_Command>4 and BeliveMe)
guicontrol,,BeliveMe,0
}
else if (AddCS=4)
{
if (ChoiceFormat=1) ;text
size_to_send:=STRToDATA(DataToSend,VarDataToSend)
else if (ChoiceFormat=2) ;dec
size_to_send:=DECToDATA(DataToSend,VarDataToSend,1,ChoiceType,ChoiceSize)
else if (ChoiceFormat=3) ;HEX
size_to_send:=HEXstrToDATA(DataToSend,VarDataToSend)
else if (ChoiceFormat=4) ;BIN
size_to_send:=BINstrToDATA(DataToSend,VarDataToSend)
NumPut(CRC16(VarDataToSend,size_to_send),VarDataToSend,size_to_send,"ushort")
}
else
{
if (ChoiceFormat=1) ;text
size_to_send:=STRToDATA(DataToSend,VarDataToSend)
else if (ChoiceFormat=2) ;dec
size_to_send:=DECToDATA(DataToSend,VarDataToSend,1,ChoiceType,ChoiceSize)
else if (ChoiceFormat=3) ;HEX
size_to_send:=HEXstrToDATA(DataToSend,VarDataToSend)
else if (ChoiceFormat=4) ;BIN
size_to_send:=BINstrToDATA(DataToSend,VarDataToSend)
if (AddCS>0)
NumPut(CRC16(VarDataToSend,size_to_send,(ChoiceCSType=1),Polynom,InitVal,Refin,RefOut,XorOut,RefPoly),VarDataToSend,size_to_send,AddCS==2?"Uchar":"ushort")
}
if (MapRun and !MapChangeV)
{
AddCSLenght:=2
size_to_send:=6
varsetcapacity(VarDataToSend,size_to_send+AddCSLenght)
NumPut(MapList[MapNum,1],VarDataToSend,0,"uchar")
NumPut((MapList[MapNum,4]+2),VarDataToSend,1,"uchar")
NumPut(SwapByte(MapList[MapNum,2]),VarDataToSend,2,"ushort")
if (MapList[MapNum,3]="INT" or MapList[MapNum,3]="WORD")
NumPut(SwapByte(1),VarDataToSend,4,"ushort")
else
NumPut(SwapByte(2),VarDataToSend,4,"ushort")
NumPut(CRC16(VarDataToSend,size_to_send),VarDataToSend,size_to_send,"ushort")
}
if !size_to_send
return
size:=size_to_send+AddCSLenght
if (size>1024)
{
SB_SetText("Слишком много данных для отправки. " size " byte.")
return
}
sended:="Отправлено: "
loop,% size
{
if (a_index<100)
sended.=format("{:02X}",NumGet(VarDataToSend,a_index-1,"UChar")) " "
NumPut(NumGet(VarDataToSend,a_index-1,"UChar"),Data,_SendDataOffset+a_index-1,"UChar")
}
SB_SetText(sended)
NumPut(size,Data,_SendSize,"Int")
NumPut(1,Data,_SendDataNow,"uChar")
if SearchAdd
{
RTU_SlaveAdress++
if RTU_SlaveAdress=256
{
SearchAdd:=false
NumPut(DefaultBReq,Data,_RS232_Bytes_Reqest,"Int")
if SendDataRepitedly
gosub,SendDataRepitedly
if (FoundAdd!="")
GuiControl,,RTU_SlaveAdress,% FoundAdd
}
else
GuiControl,,RTU_SlaveAdress,% RTU_SlaveAdress
}
if MapChangeV
MapChangeV:=0
return
SendDataRepitedly:
SendDataRepitedly:=!SendDataRepitedly
if SendDataRepitedly
GuiControl,,% hSendDataRepitedly,Стоп ;
else
{
GuiControl,,% hSendDataRepitedly,Циклично ;
GuiControl,,% hE_RTU_Addres_6,Найти ;
SearchAdd:=false
}
return
FindAdd:
gosub,submiting
SearchAdd:=!SearchAdd
if SearchAdd
{
FoundAdd:=""
GuiControl,,% hE_RTU_Addres_6,Стоп ;
NumPut(20,Data,_RS232_Bytes_Reqest,"Int")
if (RTU_SlaveAdress=255)
{
RTU_SlaveAdress:=0
GuiControl,,RTU_SlaveAdress,% RTU_SlaveAdress
}
if !SendDataRepitedly
gosub,SendDataRepitedly
}
else
{
NumPut(DefaultBReq,Data,_RS232_Bytes_Reqest,"Int")
if (FoundAdd!="")
GuiControl,,RTU_SlaveAdress,% FoundAdd
GuiControl,,% hE_RTU_Addres_6,Найти ;
if SendDataRepitedly
gosub,SendDataRepitedly
}
return
DataToSendCheck:
gosub,submiting
tmp1:=DataToSend
if (ChoiceFormat=1)
GuiControl,hide,% hZeroState
else if (ChoiceFormat=2)
{
GuiControl,hide,% hZeroState
RegExMatch(DataToSend,"[0-9 -\.]+",tmp1)
if instr(DataToSend,".")
{
hEDEC4once:=0
GuiControl,,% hEDEC4,1
GuiControl,disable,% hEDEC5
GuiControl,disable,% hEDEC6
; GuiControl,,% hEDEC7,1
}
else if instr(DataToSend,"-")
{
hEDEC4once:=0
GuiControl,,% hEDEC3,1
GuiControl,enable,% hEDEC5
GuiControl,enable,% hEDEC6
}
if (!hEDEC4once and !instr(DataToSend,"-") and !instr(DataToSend,"."))
{
hEDEC4once:=1
GuiControl,,% hEDEC2,1
GuiControl,enable,% hEDEC5
GuiControl,enable,% hEDEC6
}
}
else if (ChoiceFormat=3)
{
RegExMatch(DataToSend,"[A-Fa-f0-9 ]+",tmp1)
StringReplace,tmp2,DataToSend,%A_SPACE%,,All
if (strlen(tmp2)&1)
GuiControl,show,% hZeroState
else
GuiControl,hide,% hZeroState
}
else if (ChoiceFormat=4)
{
RegExMatch(DataToSend,"[0-1 ]+",tmp1)
StringReplace,tmp2,DataToSend,%A_SPACE%,,All
if (Mod(strlen(tmp2),8))
GuiControl,show,% hZeroState
else
GuiControl,hide,% hZeroState
}
if (DataToSend!=tmp1)
{
GuiControl,,DataToSend,% tmp1
PostMessage,0x00B1,1000,1000,,ahk_id %E_1% ; EM_SETSEL
PostMessage,0xB7,,,,ahk_id %E_1% ; EM_SCROLLCARET
}
return
ConvertToSYM: ; to text
gosub,SetFormatFloat
gosub,ResetDECChoise
gosub,submiting
if (PreviousConversion="hex") ; hex to text
{
size:=HEXstrToDATA(DataToSend,tmp0)
tmp_DataToSend:=DATAtoSTR(&tmp0,0,size)
}
else if (PreviousConversion="bin") ; bin to text
{
size:=BINstrToDATA(DataToSend,tmp1)
tmp_DataToSend:=DATAtoSTR(&tmp1,0,size)
}
else if (PreviousConversion="dec") ; dec to text
{
DECToDATA(DataToSend,tmp1,1,ChoiceType,ChoiceSize)
tmp_DataToSend:=DATAtoSTR(&tmp1,0,ChoiceSize)
}
GuiControl,,DataToSend,% tmp_DataToSend
PreviousConversion:="sym"
gosub,DataToSendCheck
return
ConvertToHEX: ; to hex
gosub,SetFormatFloat
gosub,ResetDECChoise
gosub,submiting
if (PreviousConversion="sym") ; text to hex
{
size:=STRToDATA(DataToSend,tmp0)
tmp_DataToSend:=DATAtoHEX(&tmp0,0,size,0,1)
}
else if (PreviousConversion="bin") ; bin to hex
{
size:=BINstrToDATA(DataToSend,tmp0,1)
tmp_DataToSend:=DATAtoHEX(&tmp0,0,size,1)
}
else if (PreviousConversion="dec") ; dec to hex
{
DECToDATA(DataToSend,tmp1,1,ChoiceType,ChoiceSize)
tmp_DataToSend:=DATAtoHEX(&tmp1,0,ChoiceSize)
}
GuiControl,,DataToSend,% tmp_DataToSend
PreviousConversion:="hex"
gosub,DataToSendCheck
return
ConvertToBIN: ; to bin
gosub,SetFormatFloat
gosub,ResetDECChoise
gosub,submiting
if (PreviousConversion="sym") ; text to bin
{
size:=STRToDATA(DataToSend,tmp0)
tmp_DataToSend:=DATAtoBIN(&tmp0,0,size)
}
else if (PreviousConversion="hex") ; hex to bin
{
size:=HEXstrToDATA(DataToSend,tmp0)
tmp_DataToSend:=DATAtoBIN(&tmp0,0,size)
}
else if (PreviousConversion="dec") ; dec to bin
{
DECToDATA(DataToSend,tmp1,1,ChoiceType,ChoiceSize)
tmp_DataToSend:=DATAtoBIN(&tmp1,0,ChoiceSize)
}
GuiControl,,DataToSend,% tmp_DataToSend
PreviousConversion:="bin"
gosub,DataToSendCheck
return
ConvertToDEC: ; to dec
gosub,SetFormatFloat
loop,8
GuiControl,show,% hEDEC%a_index%
gosub,submiting
old_DataToSend:=DataToSend
GuiControl,hide,% hZeroState
return
ConvertToDECRun:
gosub,SetFormatFloat
if !(ChoiceDEC and ChoiceDECSize)
return
ChoicePType:={1:"char",2:"short",3:"int",4:"int64"}
if (ChoiceDEC=1)
ChoiceType:="U" ChoicePType[ChoiceDECSize]
else if (ChoiceDEC=2)
ChoiceType:="" ChoicePType[ChoiceDECSize]
else if (ChoiceDEC=3 and ChoiceDECSize=3)
ChoiceType:="float"
else if (ChoiceDEC=3 and ChoiceDECSize=4)
ChoiceType:="duoble"
if (ChoiceDECSize=3)
ChoiceSize:=4
else if (ChoiceDECSize=4)
ChoiceSize:=8
else
ChoiceSize:=ChoiceDECSize
if (PreviousConversion="sym") ; text to dec
{
STRToDATA(old_DataToSend,tmp0,1)
tmp_DataToSend:=numget(tmp0,0,ChoiceType)
}
else if (PreviousConversion="hex") ; hex to dec
{
ClearVar(old_DataToSend)
HEXstrToDATA(old_DataToSend,tmp0,1)
tmp_DataToSend:=numget(tmp0,0,ChoiceType)
}
else if (PreviousConversion="bin") ; bin to dec
{
BINstrToDATA(old_DataToSend,tmp0,1)
tmp_DataToSend:=numget(tmp0,0,ChoiceType)
}
GuiControl,,DataToSend,% tmp_DataToSend
PreviousConversionWasDEC:=1
return
ChooseDEC:
gosub,submiting
if (ChoiceDEC=3)
{
if (ChoiceDECSize and ChoiceDECSize<3)
{
GuiControl,,% hEDEC5,0
GuiControl,,% hEDEC6,0
GuiControl,,% hEDEC7,1
ChoiceDECSize:=3
}
GuiControl,disable,% hEDEC5
GuiControl,disable,% hEDEC6
}
else
{
GuiControl,enable,% hEDEC5
GuiControl,enable,% hEDEC6
}
gosub,ConvertToDECRun
return
ChooseDECSize:
gosub,submiting
GuiControl,disable,% hEDEC%a_index%
gosub,ConvertToDECRun
return
ResetDECChoise:
loop,8
GuiControl,hide,% hEDEC%a_index%
GuiControl,,% hEDEC2,1
GuiControl,,% hEDEC2,0
GuiControl,,% hEDEC5,1
GuiControl,,% hEDEC5,0
ChoiceDEC:=0
ChoiceDECSize:=0
if PreviousConversionWasDEC
{
PreviousConversion:="dec"
GuiControl,hide,% hZeroState
PreviousConversionWasDEC:=0
}
return
ModbusOpenFromMain:
MapNum:=1
gosub,ModbusMapOpen
gosub,MapOpen
gosub,MapRun
return
ModbusMapOpen:
gui,6:show,,Карта регистров Modbus
Gui,6:default
MapNum:=1
ModbusMapOpen:=1
SB_SetText(COMPort)
Gui,1:default
return
6GuiSize:
Gui,6:default
if (!Old_GuiMapWidth or !Old_GuiMapHeight)
{
Old_GuiMapWidth:=A_GuiWidth
Old_GuiMapHeight:=A_GuiHeight
}
if (A_GuiHeight<50 or A_EventInfo=1)
{
Gui,1:default
return
}
DeltaGuiMapWidth:=A_GuiWidth-Old_GuiMapWidth
DeltaGuiMapHeight:=A_GuiHeight-Old_GuiMapHeight
MoveControl(Map_LV,,,DeltaGuiMapWidth,DeltaGuiMapHeight)
Old_GuiMapWidth:=A_GuiWidth
Old_GuiMapHeight:=A_GuiHeight
Gui,1:default
return
6GuiClose:
6GuiEscape:
MapExit:
ModbusMapOpen:=0
MapRun:=0
gosub,SubmitExt
Gui,6:hide
return
MapOpen:
Gui,6:default
; Thread,NoTimers
FileSelectFile,OpenMapFileName,3,% OldOpenMapFileName,Открыть сохраненную карту регистров,Modbus registers map file (*.mrmf)
; Thread,NoTimers,false
if errorlevel
{
tooltip,Отменено
settimer,RemoveTooltip,-2000
Gui,1:default
return
}
OldOpenMapFileName:=OpenMapFileName
OpenMapFileObj:=FileOpen(OpenMapFileName,"r","UTF-8-RAW")
if !IsObject(OpenMapFileObj)
{
MsgBox,% "Не возможно открыть файл " OpenMapFileName "."
Gui,1:default
return
}
gosub,DiskonnectCOM
FileLoading:=1
tooltip,Загрузка файла...`nДвойной клик чтобы отменить.
sleep,200
TotalLoadSize:=4
varsetcapacity(tmpsavedata,28)
OpenMapFileObj.RawRead(tmpsavedata,28)
LoadSize:=numget(tmpsavedata,0,"Uint")
RS232_Baud:=numget(tmpsavedata,4,"UInt")
RS232_Parity:=chr(numget(tmpsavedata,8,"UInt"))
RS232_Data:=numget(tmpsavedata,12,"UInt")
RS232_Stop:=numget(tmpsavedata,16,"UInt")
ReadIntervalTimeout:=numget(tmpsavedata,20,"UInt")
MapTOut:=numget(tmpsavedata,24,"UInt")
MapList:=[]
LV_Delete()
loop,% LoadSize
{
if StopAnalyze
{
StopAnalyze:=0
msgbox,Отменено
break
}
if (TotalLoadSize>=OpenMapFileObj.Length)
break
TotalLoadSize+=276
varsetcapacity(tmpsavedata,16)
OpenMapFileObj.RawRead(tmpsavedata,16)
MapAddres:=numget(tmpsavedata,0,"UInt")
MapRegNum:=numget(tmpsavedata,4,"UInt")
MapDataType:=MapDataOfType[numget(tmpsavedata,8,"UInt")]
MapRegType:=numget(tmpsavedata,12,"UInt")
varsetcapacity(tmpsavedata,256)
OpenMapFileObj.RawRead(tmpsavedata,240)
MapComment:=uDATAtoSTR(&tmpsavedata,0,120)
MapList.Push([MapAddres,MapRegNum,MapDataType,MapRegType,MapComment])
LV_ADD(,MapAddres " (" format("0x{:02X}",MapAddres) ")",MapRegNum " (" format("0x{:02X}",MapRegNum) ")",(MapRegType=1)?"Holding":"Input",MapDataType,,,,,MapComment)
}
LV_ModifyCol(9,"Auto")
OpenMapFileObj.Close()
Gui,1:default
GuiControl,Choose,% hRS232_Baud_Choice,% RS232_Baud_List[RS232_Baud]
GuiControl,Choose,% hRS232_Parity_Choice,% RS232_Parity_List[RS232_Parity]
GuiControl,Choose,% hRS232_Data_Choice,% RS232_Data_List[RS232_Data]
GuiControl,Choose,% hRS232_Stop_Choice,% RS232_Stop
ReadIntervalTimeout:=ReadIntervalTimeout>255?255:ReadIntervalTimeout
GuiControl,,% hRITimeout,% ReadIntervalTimeout
tooltip,Загружено
settimer,RemoveTooltip,-2000
Gosub,EndAddSettings
gosub,MapRun
return
MapSave:
Gui,6:default
/*
Количество регистров 4 byte
Скорость 4 byte
Четность 4 byte
Бит данных 4 byte
Стоп биты 4 byte
ReadIntervalTimeout 4 byte
MapTOut 4 byte
Адрес 4 byte
№ регистра 4 byte
Тип данных - INT UINT DINT UDINT REAL 4 byte
Тип регистра - holding input 4 byte
Коментарий 240 byte
=280 byte
*/
if !OldSaveMapFileName
OldSaveMapFileName:="ModbusMap " a_DD "." a_MM "." a_YYYY " " a_hour "." a_min
Thread,NoTimers
FileSelectFile,SaveMapFileName,S16,% OldSaveMapFileName,Сохранить карту регистров,Modbus registers map file (*.mrmf)
Thread,NoTimers,false
if errorlevel
{
tooltip,Отменено
settimer,RemoveTooltip,-2000
return
Gui,1:default
}
if (!instr(SaveMapFileName,".mrmf") and FileExist(SaveMapFileName ".mrmf"))
{
msgBox,36,Сохранить карту регистров,Файл %SaveMapFileName%.mrmf существует.`nЗаменить?
IfMsgBox No
{
return
Gui,1:default
}
}
FileSaving:=1
tooltip,Сохранение файла...`nДвойной клик чтобы остановить.
sleep,200
SaveMapFileName:=instr(SaveMapFileName,".mrmf")?SaveMapFileName:SaveMapFileName . ".mrmf"
OldSaveMapFileName:=SaveMapFileName
SaveMapFileObj:=FileOpen(SaveMapFileName,"w","UTF-8-RAW")
if !IsObject(SaveMapFileObj)
{
MsgBox,% "Не возможно создать файл " SaveMapFileName "."
tooltip
return
Gui,1:default
}
varsetcapacity(tmpsavedata,28,0)
SaveSize:=MapList.maxindex()
numput(SaveSize,tmpsavedata,0,"Uint")
numput(RS232_Baud,tmpsavedata,4,"UInt")
numput(asc(RS232_Parity),tmpsavedata,8,"UInt")
numput(RS232_Data,tmpsavedata,12,"UInt")
numput(RS232_Stop,tmpsavedata,16,"UInt")
numput(ReadIntervalTimeout,tmpsavedata,20,"UInt")
numput(MapTOut,tmpsavedata,24,"UInt")
SaveMapFileObj.RawWrite(tmpsavedata,28)
loop,% SaveSize
{
if StopAnalyze
{
StopAnalyze:=0
Msgbox,Отменено
break
}
;msgbox,% MapList[a_index,1] "`n" MapList[a_index,2] "`n" MapList[a_index,3] "`n" MapList[a_index,4] "`n" MapList[a_index,5] "`n"
varsetcapacity(tmpsavedata,16,0)
numput(MapList[a_index,1],tmpsavedata,0,"UInt")
numput(MapList[a_index,2],tmpsavedata,4,"UInt")
numput(MapTypeOfData[MapList[a_index,3]],tmpsavedata,8,"UInt")
numput(MapList[a_index,4],tmpsavedata,12,"UInt")
SaveMapFileObj.RawWrite(tmpsavedata,16)
varsetcapacity(tmpsavedata,240,0)
uSTRToDATA(MapList[a_index,5],tmpsavedata)
SaveMapFileObj.RawWrite(tmpsavedata,240)
}
SaveMapFileObj.Close()
FileSaving:=0
tooltip,Сохранено.
settimer,RemoveTooltip,-2000
Gui,1:default
return
MapGetSelected:
Gui,6:default
LVMap_Column:=LV_SubItemHitTest(Map_LV)
LVMap_Row:=LV_GetNext()
LV_GetText(LVMap_Text,LVMap_Row,LVMap_Column)
;tooltip,% LVMap_Column "`n" LVMap_Row
if (A_GuiEvent="RightClick")
{
if (LVMap_Column=0 and LVMap_Row=0)
{
menu,MapRmenu,disable,Редактировать
menu,MapRmenu,disable,Удалить
}
else
{
menu,MapRmenu,enable,Редактировать
menu,MapRmenu,enable,Удалить
}
menu,MapRmenu,show
}
if (A_GuiEvent="DoubleClick")
{
MapEditNum:=LVMap_Row
GuiControl,,% hMapValueNow,% LVMap_Text
GuiControl,,% hMapValueNew,% LVMap_Text
if (LVMap_Column=5)
gosub,MapChangeDEC
else if (LVMap_Column=6)
gosub,MapChangeHEX
else if (LVMap_Column=7)
gosub,MapChangeBIN
else if LVMap_Column
gosub,MapEdit
}
if (A_GuiEvent="Normal")
{
}
Gui,1:default
return
MapPrioritySet:
MapPriority:=LVMap_Row
return
MapCopy:
clipboard:=LVMap_Text
tooltip,% "Скопированно:`t`t" LVMap_Text
settimer,RemoveTooltip,-2000
return
MapRun:
; Gui,6:default
NumPut(9,Data,_RS232_Bytes_Reqest,"Int")
MapRun:=1
; Gui,1:default
return
MapStop:
; Gui,6:default
NumPut(DefaultBReq,Data,_RS232_Bytes_Reqest,"Int")
MapRun:=0
; Gui,1:default
return
MapSetTOut:
InputBox,tmp1,Задать таймаут ответа,Сколько миллисекунд ждать ответа,,240,160,,,,12,% MapTOut
if !ErrorLevel
MapTOut:=abs(tmp1)
return
MapChangeAddres:
Gui,7:default
Gui,7:submit,nohide
if (a_GuiControl="MapAddres")
{
if MapAddresHEXFlag
{
MapAddresHEXFlag:=0
return
}
MapAddresFlag:=1
GuiControl,,MapAddresHEX,% format("{:X}",MapAddres)
}
else if (a_GuiControl="MapAddresHEX")
{
if MapAddresFlag
{
MapAddresFlag:=0
return
}
MapAddresHEXFlag:=1
tmp:="0x" MapAddresHEX
GuiControl,,MapAddres,% tmp+0
}
Gui,1:default
return
MapChangeRegNum:
Gui,7:default
Gui,7:submit,nohide
if (a_GuiControl="MapRegNum")
{
if MapRegNumHEXFlag
{
MapRegNumHEXFlag:=0
return
}
MapRegNumFlag:=1
GuiControl,,MapRegNumHEX,% format("{:X}",MapRegNum)
}
else if (a_GuiControl="MapRegNumHEX")
{
if MapRegNumFlag
{
MapRegNumFlag:=0
return
}
MapRegNumHEXFlag:=1
tmp:="0x" MapRegNumHEX
GuiControl,,MapRegNum,% tmp+0
}
Gui,1:default
return
MapAddresChange:
InputBox,tmpA,Задать новый адрес,Новый адрес для выделенных строк,,240,160,,,,12,1
if !ErrorLevel
{
if (tmpA>255 or !tmp1)
tmpA:=1
Gui,6:default
LVMap_Row:=0
loop
{
LVMap_Row:=LV_GetNext(LVMap_Row)
if !LVMap_Row
break
loop,9
LV_GetText(tmp%a_index%,LVMap_Row,a_index)
LV_Modify(LVMap_Row,,tmpA,tmp2,tmp3,tmp4,"","","","",tmp9)
MapList[LVMap_Row,1]:=tmpA
}
Gui,1:default
}
return
MapAdd:
Gui,7:show
return
MapAddReg:
gui,7:submit
Gui,6:default
if !MapEdit
{
if !LVMap_Row
LVMap_Row:=MapList.MaxIndex()?(MapList.MaxIndex()+1):1
LV_Insert(LVMap_Row,,MapAddres " (" format("0x{:02X}",MapAddres) ")",MapRegNum " (" format("0x{:02X}",MapRegNum) ")",(MapRegType=1)?"Holding":"Input",MapDataType,,,,,MapComment)
MapList.InsertAt(LVMap_Row,[MapAddres,MapRegNum,MapDataType,MapRegType,MapComment])
}
else
{
MapEdit:=0
GuiControl,,% hMapAddReg,Добавить
LV_Modify(LVMap_Row,,MapAddres " (" format("0x{:02X}",MapAddres) ")",MapRegNum " (" format("0x{:02X}",MapRegNum) ")",(MapRegType=1)?"Holding":"Input",MapDataType,,,,,MapComment)
MapList[LVMap_Row]:=[MapAddres,MapRegNum,MapDataType,MapRegType,MapComment]
}
LV_ModifyCol(9,"Auto")
Gui,1:default
return
MapDelete:
Gui,6:default
loop
{
LVMap_Row:=LV_GetNext()
if !LVMap_Row
break
LV_Delete(LVMap_Row)
MapList.RemoveAt(LVMap_Row)
tmpMap.RemoveAt(LVMap_Row)
}
Gui,1:default
return
MapEdit:
Gui,6:default
MapEdit:=1
GuiControl,,% hMapAddres,% MapList[LVMap_Row,1]
GuiControl,,% hMapRegNum,% MapList[LVMap_Row,2]
GuiControl,Choose,% hMapDataType,% MapList[LVMap_Row,3]
GuiControl,Choose,% hMapRegType,% MapList[LVMap_Row,4]
GuiControl,,% hMapComment,% MapList[LVMap_Row,5]
GuiControl,,% hMapAddReg,Применить
gui,7:show
Gui,1:default
return
MapCancelReg:
gui,7:hide
MapEdit:=0
return
MapChangeDEC:
if (MapList[MapEditNum,4]=2)
{
tooltip,Нельзя изменить Input регистр.
settimer,RemoveTooltip,-2000
return
}
MapChangeVtmp:=1
GuiControl,,% hMapValueNow,% LVMap_Text
GuiControl,,% hMapValueNew,% LVMap_Text
Gui,8:show,,Изменнение значения DEC (функция 0x10)
return
MapChangeHEX:
if (MapList[MapEditNum,4]=2)
{
tooltip,Нельзя изменить Input регистр.
settimer,RemoveTooltip,-2000
return
}
MapChangeVtmp:=2
GuiControl,,% hMapValueNow,% LVMap_Text
GuiControl,,% hMapValueNew,% LVMap_Text
Gui,8:show,,Изменнение значения HEX (функция 0x10)
return
MapChangeBIN:
if (MapList[MapEditNum,4]=2)
{
tooltip,Нельзя изменить Input регистр.
settimer,RemoveTooltip,-2000
return
}
MapChangeVtmp:=3
GuiControl,,% hMapValueNow,% LVMap_Text
GuiControl,,% hMapValueNew,% LVMap_Text
Gui,8:show,,Изменнение значения BIN (функция 0x10)
return
MapEditValue:
Gui,8:submit,nohide
MapChangeV:=MapChangeVtmp
gosub,SendData
return
MapCancelValue:
Gui,8:hide
MapChangeVtmp:=0
GuiControl,,% hMapValueNow,
return
DataFilter:
Gui,4:show,,Фильтровать данные
if (AddCS>=4)
{
Gui,4:submit,nohide
Filter_CommandFlag:=1
if (Filter_CommandRTU>0 and Filter_CommandRTU<7)
Filter_Command:=Filter_CommandRTU
else if (Filter_CommandRTU>6)
Filter_Command:=Filter_CommandRTU+8
GuiControl,,% hFiltE1,% Filter_Command
}
return
DataFilterOk:
Gui,4:submit
return
ListGetSelected:
if (A_GuiEvent="RightClick")
{
LV_Column:=LV_SubItemHitTest(E_LV)
LV_Row:=LV_GetNext(RowNumber)
if (LV_Column>COLUMN_SYM and !EN_Kurvendrucker)
menu,ListRightClick,enable,Отрисовать график ;
else
menu,ListRightClick,disable,Отрисовать график ;
menu,ListRightClick,show
}
if ((A_GuiEvent="DoubleClick" or Update=1) and Analyzer and !AnBusy)
{
tooltip,Загрузка таблицы...`nДвойной клик чтобы отменить.
StopAnalyze:=0
Update:=0
AnBusy:=1
GuiControl,-Redraw,% E_LV
GuiControl,-Redraw,% E_SLV
Gui,1:ListView,% E_LV
LV_GetText(AnSelected,LV_GetNext(),COLUMN_HOOK)
loop,parse,AnSelected,|
{
if A_LoopField
{
if (a_index=1)
RS232_Bytes_Received:=A_LoopField
else if (a_index=2)
Received_Addres:=A_LoopField
else if (a_index=3)
Received_Command:=A_LoopField
else if (a_index=4)
Received_Byte:=A_LoopField
else if (a_index=5)
Received_Message_Type:=A_LoopField
else if (a_index=6)
CheckSummIsCorrect:=A_LoopField
}
}
Gui,1:ListView,% E_SLV
LV_Delete()
CSArr:={}
; skip:=0
For bytenum, val in AnBufer[AnSelected]
{
if StopAnalyze
{
StopAnalyze:=0
tooltip
break
}
skip:=0
GuiControl,,Progress,% a_index/AnBufer[AnSelected].maxindex()*100
if HideSamePackages
{
CS:=CRC16(val,val.maxindex(),,HideSamePol)
if (CS=0)
{
HideSamePol--
CS:=CRC16(val,val.maxindex(),,HideSamePol)
}
loop,% CSArr.maxindex()
{
if (CSArr[a_index]=CS)
{
skip:=1
break
}
}
}
Packages_Recieved:=AnCufer[AnSelected,a_index]
if !skip
{
Bufer:=val
CSArr.Push(CS)
Gui,1:ListView,% E_SLV
gosub,ParseBuffer
}
}
tooltip
Gui,1:ListView,% E_LV
AnBusy:=0
GuiControl,+Redraw,% E_LV
GuiControl,+Redraw,% E_SLV
GuiControl,,Progress,0
}
return
ListCopySelected:
tmp1:=""
S:=LV_GetNext()
if (LV_Column=COLUMN_#)
{
loop,% LV_GetCount("Selected")
{
row:=a_index
loop,13
{
LV_GetText(tmp0,S+row-1,a_index)
tmp1.=tmp0 "`t"
}
tmp1.="`n"
}
tooltip,% "Выделенный текст скопирован."
}
else
{
loop,% LV_GetCount("Selected")
{
LV_GetText(tmp0,S+a_index-1,LV_Column)
tmp1.=tmp0 (tmp0=""?"`n":" ")
}
tooltip,% "Скопирован текст из колонки №" LV_Column
}
clipboard:=tmp1
settimer,RemoveTooltip,-3000
return
SecondListGetSelected:
if UpDown_Label
return
Gui,1:ListView,% E_SLV
if (A_GuiEvent="RightClick")
{
LV_Column:=LV_SubItemHitTest(E_SLV)
LV_Row:=LV_GetNext(RowNumber)
if (LV_Column>COLUMN_SYM and !EN_Kurvendrucker)
menu,SecondListRightClick,enable,Отрисовать график ;
else
menu,SecondListRightClick,disable,Отрисовать график ;
menu,SecondListRightClick,show
}
Gui,1:ListView,% E_LV
return
HideSamePackages:
HideSamePackages:=!HideSamePackages
if HideSamePackages
{
menu,SecondListRightClick,check,Скрывать одинаковые пакеты
menu,BufferMenu,check,Скрывать одинаковые пакеты
}
else
{
menu,SecondListRightClick,uncheck,Скрывать одинаковые пакеты
menu,BufferMenu,uncheck,Скрывать одинаковые пакеты
}
Update:=1
gosub,ListGetSelected
return
SecondListCopySelected:
Gui,1:ListView,% E_SLV
LV_GetText(tmp1,LV_Row,LV_Column)
clipboard:=tmp1
Gui,1:ListView,% E_LV
return
En_Analyzer:
analyzer:=!analyzer
if analyzer
{
menu,ListRightClick,disable,Очистить
menu,ListRightClick,disable,Вернуть все
menu,ListRightClick,disable,Очистить безвозвратно
menu,ListRightClick,disable,Фильтровать данные
menu,ListRightClick,check,Анализ пакетов
menu,BufferMenu,disable,Фильтровать данные
menu,BufferMenu,check,Анализ пакетов
menu,BufferMenu,enable,Скрывать одинаковые пакеты
; menu,ListRightClick,disable,Копировать
menu,ListRightClick,disable,Отрисовать график
GuiControl,show,% E_SLV
GuiControl,Hide,% E_Text
GuiControl,Hide,% E_111
GuiControl,Hide,% E_112
GuiControl,Hide,FollowSelect
GuiControl,Hide,% hTtEButton
GuiControl,,_InText_
GuiControl,,Progress,0
Gui,1:ListView,% E_SLV
LV_Delete()
Gui,1:ListView,% E_LV
LV_Delete()
LV_ModifyCol(COLUMN_#,80)
LV_ModifyCol(COLUMN_HOOK,0)
LV_ModifyCol(COLUMN_INFO,80)
LV_ModifyCol(COLUMN_BIN,80)
LV_ModifyCol(COLUMN_SYM,100)
LV_ModifyCol(COLUMN_HEX,0)
LV_ModifyCol(COLUMN_DEC,0)
LV_ModifyCol(COLUMN_WORD,0)
LV_ModifyCol(COLUMN_INT,0)
LV_ModifyCol(COLUMN_DWORD,0)
LV_ModifyCol(COLUMN_DINT,0)
LV_ModifyCol(COLUMN_FLOAT,0)
LV_ModifyCol(COLUMN_DOUBLE,0)
gosub,Analyze
}
else
{
menu,ListRightClick,enable,Очистить
menu,ListRightClick,enable,Вернуть все
menu,ListRightClick,enable,Очистить безвозвратно
menu,ListRightClick,enable,Фильтровать данные
menu,ListRightClick,uncheck,Анализ пакетов
menu,BufferMenu,enable,Фильтровать данные
menu,BufferMenu,uncheck,Анализ пакетов
menu,BufferMenu,disable,Скрывать одинаковые пакеты
menu,ListRightClick,enable,Копировать
menu,ListRightClick,enable,Отрисовать график
GuiControl,Hide,% E_SLV
GuiControl,show,% E_Text
GuiControl,show,% E_111
GuiControl,show,% E_112
GuiControl,show,FollowSelect
GuiControl,show,% hTtEButton
Gui,1:ListView,% E_SLV
LV_Delete()
Gui,1:ListView,% E_LV
LV_Delete()
LV_ModifyCol(COLUMN_#,65)
LV_ModifyCol(COLUMN_HOOK,0)
LV_ModifyCol(COLUMN_INFO,45)
LV_ModifyCol(COLUMN_BIN,60)
LV_ModifyCol(COLUMN_SYM,20)
LV_ModifyCol(COLUMN_HEX,37)
LV_ModifyCol(COLUMN_DEC,32)
LV_ModifyCol(COLUMN_WORD,50)
LV_ModifyCol(COLUMN_INT,50)
LV_ModifyCol(COLUMN_DWORD,20)
LV_ModifyCol(COLUMN_DINT,20)
LV_ModifyCol(COLUMN_FLOAT,80)
LV_ModifyCol(COLUMN_DOUBLE,40)
gosub,UnUpdate
}
return
Analyze:
gosub,submiting
LV_GetText(AnSelected,LV_GetNext(),COLUMN_HOOK)
Gui,1:ListView,% E_SLV
LV_Delete()
Gui,1:ListView,% E_LV
LV_Delete()
GuiControl,-Redraw,% E_LV
GuiControl,-Redraw,% E_SLV
tooltip,Анализируется...
tmp4:=0
For anindex, AnArray in AnBufer
{
tmp4++
RS232_Bytes_Received:=Received_Addres:=Received_Command:=Received_Byte:=Received_Message_Type:=CheckSummIsCorrect:=""
loop,parse,anindex,|
{
if A_LoopField
{
if (a_index=1)
RS232_Bytes_Received:=A_LoopField
else if (a_index=2)
Received_Addres:=A_LoopField
else if (a_index=3)
Received_Command:=A_LoopField
else if (a_index=4)
Received_Byte:=A_LoopField
else if (a_index=5)
Received_Message_Type:=A_LoopField
else if (a_index=6)
CheckSummIsCorrect:=A_LoopField
}
}
if !CheckSummIsCorrect
continue
LV_Icon:=AddCS>1?(CheckSummIsCorrect?ICON_V:ICON_X):ICON_START
LV_Hash:=AnArray.maxindex() " " Received_Message_Type
LV_NumByte:=AddCS>1?"Адрес " . Received_Addres:"Byte1 = " . Received_Addres
LV_Bin:=(AddCS>1?"Команда ":"Byte2 = ") . (Received_Command?Received_Command:"нет")
LV_Sym:="Кол-во байт " RS232_Bytes_Received
LV_HEX:=
LV_DEC:=
LV_WORD:=
LV_INT:=
LV_DWORD:=
LV_DINT:=
LV_Float:=
LV_Double:=
LV_Add("Icon" LV_Icon,LV_Hash,anindex,LV_NumByte,LV_Bin,LV_Sym,LV_HEX,LV_DEC,LV_WORD,LV_INT,LV_DWORD,LV_DINT,LV_Float,LV_Double)
}
For anindex, AnArray in AnBufer
{
RS232_Bytes_Received:=Received_Addres:=Received_Command:=Received_Byte:=Received_Message_Type:=CheckSummIsCorrect:=""
loop,parse,anindex,|
{
if A_LoopField
{
if (a_index=1)
RS232_Bytes_Received:=A_LoopField
else if (a_index=2)
Received_Addres:=A_LoopField
else if (a_index=3)
Received_Command:=A_LoopField
else if (a_index=4)
Received_Byte:=A_LoopField
else if (a_index=5)
Received_Message_Type:=A_LoopField
else if (a_index=6)
CheckSummIsCorrect:=A_LoopField
}
}
if CheckSummIsCorrect
continue
;msgbox,% AnBufer.maxindex()
GuiControl,,Progress,% a_index/tmp4*100
LV_Icon:=AddCS>1?(CheckSummIsCorrect?ICON_V:ICON_X):ICON_START
LV_Hash:=AnArray.maxindex() " " Received_Message_Type
LV_NumByte:=AddCS>1?"Адрес " . Received_Addres:"Byte1 = " . Received_Addres
LV_Bin:=(AddCS>1?"Команда ":"Byte2 = ") . (Received_Command?Received_Command:"нет")
LV_Sym:="Кол-во байт " RS232_Bytes_Received
LV_HEX:=
LV_DEC:=
LV_WORD:=
LV_INT:=
LV_DWORD:=
LV_DINT:=
LV_Float:=
LV_Double:=
LV_Add("Icon" LV_Icon,LV_Hash,anindex,LV_NumByte,LV_Bin,LV_Sym,LV_HEX,LV_DEC,LV_WORD,LV_INT,LV_DWORD,LV_DINT,LV_Float,LV_Double)
}
Gui,1:ListView,% E_LV
Loop % LV_GetCount()
{
LV_GetText(RetrievedText,A_Index,COLUMN_HOOK)
if (InStr(RetrievedText,AnSelected) or A_Index=1000)
{
LV_Modify(0,"-Select")
LV_Modify(A_Index,"Select")
LV_Modify(A_Index,"Vis Focus")
break
}
}
GuiControl,,Progress,0
tooltip
GuiControl,+Redraw,% E_LV
GuiControl,+Redraw,% E_SLV
return
Kurvendrucker:
if analyzer
gosub,En_Analyzer
if SendDataRepitedly
{
GuiControl,,EN_Kurvendrucker,0
gosub,SendDataRepitedly
return
}
if EN_MonitorVar
gosub,GrafClose
if (!Gdip_Initialised)
{
msgbox,Библиотека GDip++ не поддерживается в системе.
return
}
gosub,submiting
if EN_Kurvendrucker
{
Graf_Start_Time:=a_tickcount
GuiControlGet,SaveT_pos,Pos,% E_Text
GuiControlGet,SavehP2_pos,Pos,% hProgress2
GuiControlGet,SavehG_pos,Pos,% hGrafPos
gosub,GrafOpen
GuiControlGet,E_pos,Pos,% E_LV
GuiControlGet,T_pos,Pos,% E_Text
tmp_Deltamx:=-(E_posw+20)
; MoveControl(hProgress2,tmp_Deltamx,,-tmp_Deltamx,,0)
; MoveControl(E_Text,tmp_Deltamx,,-tmp_Deltamx,,0)
; MoveControl(hGrafPos,tmp_Deltamx,,-tmp_Deltamx,,0)
if (tmp_Deltamx>0)
Gdip_X_Offset-=tmp_Deltamx*2
GuiControl,Hide,% E_LV
GuiControl,Hide,% hProgress
GuiControl,Hide,% hTtEButton
GuiControl,Hide,% hClButton
GuiControl,Hide,FollowSelect
GuiControl,Choose,% hCS,1
loop,10
GuiControl,Hide,% hECSType%a_index%
loop,% MaxNumOfGraf+1
{
i:=a_index-1
GuiControl,Show,% hECB%i%
}
gosub,GrafUpdate
gosub,GrafMenuEnable
gosub,GrafRedraw
}
else
{
GuiControl,show,% E_LV
GuiControl,show,% hProgress
GuiControl,show,% hTtEButton
GuiControl,show,% hClButton
GuiControl,show,FollowSelect
loop,% MaxNumOfGraf+1
{
i:=a_index-1
GuiControl,Hide,% hECB%i%
}
gosub,GrafClose
GuiControlGet,E_pos,Pos,% E_LV
GuiControlGet,T_pos,Pos,% E_Text
tmp_Deltamx:=300
; GuiControl,Move,% E_Text,% " x" SaveT_posX " y" SaveT_posy " w" SaveT_posw " h" SaveT_posh
; GuiControl,Move,% hProgress2,% " x" SavehP2_posX " y" SavehP2_posy " w" SavehP2_posw " h" SavehP2_posh
; GuiControl,Move,% hGrafPos,% " x" SavehG_posX " y" SavehG_posy " w" SavehG_posw " h" SavehG_posh
if (tmp_Deltamx>0)
Gdip_X_Offset-=tmp_Deltamx*2
gosub,GrafUpdate
gosub,GrafMenuDisable
}
gosub,ControlSize
return
GrafCreateMenu:
menu,GrafRightClick,DeleteAll
menu,GrafRightClick,add,Автоматическое максимальное значение,GrafAutoMinMax
menu,GrafRightClick,add,Задать максимальное значение вручную F2,GrafChangeMinMax
menu,GrafRightClick,add
menu,GrafRightClick,add,Сохранить текущее изображение графика,GrafSaveImage
menu,GrafRightClick,add,Сохранить все данные графика в текстовый документ,GrafSaveData
menu,GrafRightClick,add
menu,GrafRightClick,add,Прорисовать старые данные (Вернуть все),UnUpdate
menu,GrafRightClick,add
; Menu,GrafRightClick,Icon,Автоматическое максимальное значение,shell32.dll,% ICON_FAVORITE
Menu,GrafRightClick,Icon,Сохранить текущее изображение графика,shell32.dll,% ICON_SAVE
Menu,GrafRightClick,Icon,Прорисовать старые данные (Вернуть все),shell32.dll,% ICON_BACK
Menu,GrafRightClick,Icon,Задать максимальное значение вручную F2,shell32.dll,% ICON_MANUAL
; Menu,GrafRightClick,Icon,Сохранить все данные графика в текстовый документ,shell32.dll,% ICON_SAVE
if EN_Kurvendrucker
{
menu,GrafRightClick,add,Автоматически определять разделитель графиков,GrafAutoEnding
menu,GrafRightClick,add,Сбросить автоопределение разделителя F5,GrafAutoEndingReset
menu,GrafRightClick,add,Задать разделитель вручную F3,GrafChangeEnding
menu,GrafRightClick,add
; Menu,GrafRightClick,Icon,Автоматически определять разделитель графиков,shell32.dll,% ICON_FAVORITE
Menu,GrafRightClick,Icon,Сбросить автоопределение разделителя F5,shell32.dll,% ICON_RESET
Menu,GrafRightClick,Icon,Задать разделитель вручную F3,shell32.dll,% ICON_MANUAL
if AutoEnding
{
menu,GrafRightClick,Check,Автоматически определять разделитель графиков ;
menu,GrafMenu,Check,Автоматически определять разделитель графиков ;
}
}
menu,GrafRightClick,add,Сглаживание "ступенек" F4,GrafSmooth
menu,GrafRightClick,add,Остановить прокрутку F1,GrafPause
menu,GrafRightClick,add
menu,GrafRightClick,add,Очистить график,GrafClear
menu,GrafRightClick,add
menu,GrafRightClick,add,Увеличить Колесико мыши или Ctrl+,ZoomIn
menu,GrafRightClick,add,Уменьшить Колесико мыши или Ctrl-,ZoomOut
; Menu,GrafRightClick,Icon,Сглаживание "ступенек" F4,shell32.dll,% ICON_SMOOTH
; Menu,GrafRightClick,Icon,Остановить прокрутку F1,shell32.dll,% ICON_STOP_SCROLL
Menu,GrafRightClick,Icon,Очистить график,shell32.dll,% ICON_CLEAR
Menu,GrafRightClick,Icon,Увеличить Колесико мыши или Ctrl+,shell32.dll,% ICON_SIZE
Menu,GrafRightClick,Icon,Уменьшить Колесико мыши или Ctrl-,shell32.dll,% ICON_SIZE
if EN_MonitorVar
{
menu,GrafRightClick,add
menu,GrafRightClick,add,Закрыть,GrafClose
Menu,GrafRightClick,Icon,Закрыть,shell32.dll,% ICON_HIDE
}
if AutoMinMax
{
menu,GrafRightClick,Check,Автоматическое максимальное значение ;
menu,GrafMenu,Check,Автоматическое максимальное значение ;
}
if GrafSmooth
{
menu,GrafRightClick,Check,Сглаживание "ступенек" F4
menu,GrafMenu,Check,Сглаживание "ступенек" F4
}
return
GrafMenuEnable:
if (!GrafDataExist and !EN_Kurvendrucker)
return
if !EN_Kurvendrucker
{
menu,GrafMenu,enable,Открыть
menu,GrafMenu,enable,Закрыть
}
else
{
menu,GrafMenu,disable,Открыть
menu,GrafMenu,disable,Закрыть
}
menu,GrafMenu,enable,Сохранить текущее изображение графика
menu,GrafMenu,enable,Сохранить все данные графика в текстовый документ
menu,GrafMenu,enable,Автоматическое максимальное значение
menu,GrafMenu,enable,Задать максимальное значение вручную F2
if EN_Kurvendrucker
{
menu,GrafMenu,enable,Автоматически определять разделитель графиков
menu,GrafMenu,enable,Сбросить автоопределение разделителя F5
menu,GrafMenu,enable,Задать разделитель вручную F3
}
menu,GrafMenu,enable,Сглаживание "ступенек" F4
menu,GrafMenu,enable,Остановить прокрутку F1
menu,GrafMenu,enable,Очистить график
menu,GrafMenu,enable,Увеличить Колесико мыши или Ctrl+
menu,GrafMenu,enable,Уменьшить Колесико мыши или Ctrl-
return
GrafMenuDisable:
if !GrafDataExist
menu,GrafMenu,disable,Открыть
else
menu,GrafMenu,enable,Открыть
menu,GrafMenu,disable,Закрыть
menu,GrafMenu,disable,Сохранить текущее изображение графика
menu,GrafMenu,disable,Сохранить все данные графика в текстовый документ
menu,GrafMenu,disable,Автоматическое максимальное значение
menu,GrafMenu,disable,Задать максимальное значение вручную F2
if !EN_Kurvendrucker
{
menu,GrafMenu,disable,Автоматически определять разделитель графиков
menu,GrafMenu,disable,Сбросить автоопределение разделителя F5
menu,GrafMenu,disable,Задать разделитель вручную F3
}
menu,GrafMenu,disable,Сглаживание "ступенек" F4
menu,GrafMenu,disable,Остановить прокрутку F1
menu,GrafMenu,disable,Очистить график
menu,GrafMenu,disable,Увеличить Колесико мыши или Ctrl+
menu,GrafMenu,disable,Уменьшить Колесико мыши или Ctrl-
return
GrafSaveImage:
; if !OldGrafSaveFile
OldGrafSaveFile:=COMPort " " a_DD "." a_MM "." a_YYYY " " a_hour "." a_min ".png"
Thread,NoTimers
FileSelectFile,GrafSaveFile,S16,% OldGrafSaveFile,Сохранить текущее изображение графика,Image file (*.BMP, *.DIB, *.RLE, *.JPG, *.JPEG, *.JPE, *.JFIF, *.GIF, *.TIF, *.TIFF, *.PNG)
Thread,NoTimers,false
if errorlevel
{
tooltip,Отменено
settimer,RemoveTooltip,-2000
return
}
gosub,GrafRedraw
pBitmap:=Gdip_CreateBitmapFromHBITMAP(Gdip_hbm2)
pNewBitmap:=Gdip_CreateBitmap(Gdip_W,Gdip_H)
G:=Gdip_GraphicsFromImage(pNewBitmap)
Gdip_DrawImage(G,pBitmap,0,0,Gdip_W,Gdip_H,0,0,Gdip_W,Gdip_H)
Gdip_SaveBitmapToFile(pNewBitmap,GrafSaveFile)
Gdip_DisposeImage(pBitmap)
Gdip_DisposeImage(pNewBitmap)
msgbox,Сохранено.
return
GrafSaveData:
if EN_MonitorVar
{
msgbox,UnderConstruct
}
if EN_Kurvendrucker
{
msgbox,UnderConstruct
}
return
GrafDrawFromSelected:
if (!Gdip_Initialised)
{
msgbox,Библиотека GDip++ не поддерживается в системе.
return
}
if AutoMinMax
hi_lim:=1
EN_MonitorVar:=1
gosub,GrafOpen
if Analyzer
Gui,1:ListView,% E_SLV
else
Gui,1:ListView,% E_LV
Graf_Start_Time:=a_tickcount
LV_GetText(Slave_Start_Byte,LV_Row,COLUMN_HOOK)
LV_GetText(Slave_Addres,LV_Row-Slave_Start_Byte,COLUMN_DEC)
LV_GetText(Slave_Command,LV_Row-Slave_Start_Byte+1,COLUMN_DEC)
LV_GetText(Slave_ByteNum,LV_Row-Slave_Start_Byte+2,COLUMN_DEC)
Slave_ByteNum+=5
if (LV_Column=COLUMN_HEX)
{
Slave_Data_Type:="char"
Slave_Len:=1
}
if (LV_Column=COLUMN_DEC)
{
Slave_Data_Type:="uchar"
Slave_Len:=1
}
if (LV_Column=COLUMN_WORD)
{
Slave_Data_Type:="ushort"
Slave_Len:=2
}
if (LV_Column=COLUMN_INT)
{
Slave_Data_Type:="short"
Slave_Len:=2
}
if (LV_Column=COLUMN_DWORD)
{
Slave_Data_Type:="uint"
Slave_Len:=4
}
if (LV_Column=COLUMN_DINT)
{
Slave_Data_Type:="int"
Slave_Len:=4
}
if (LV_Column=COLUMN_FLOAT)
{
Slave_Data_Type:="float"
Slave_Len:=4
}
if (LV_Column=COLUMN_DOUBLE)
{
Slave_Data_Type:="Double"
Slave_Len:=8
}
if Analyzer
{
Update:=1
gosub,ListGetSelected
}
return
GrafClose:
if EN_MonitorVar
EN_MonitorVar:=0
GuiControlGet,E_pos,Pos,% E_Text
GuiControlGet,T_pos,Pos,% hGrafPos
tmpy:=T_posh-10
; MoveControl(E_Text,,,,tmpy,0)
; MoveControl(E_SLV,,,,tmpy,0)
; MoveControl(hProgress2,,tmpy,,,0)
; MoveControl(hGrafPos,,tmpy,,-tmpy,0)
ShiftSpaceY:=950
gosub,ControlSize
gosub,GrafRedraw
gosub,GrafMenuDisable
return
GrafOpen:
if !EN_Kurvendrucker
{
EN_MonitorVar:=1
GrafDataExist:=1
}
gosub,GrafMenuEnable
GuiControlGet,E_pos,Pos,% E_Text
tmpy:=-E_posh+70
; MoveControl(E_Text,,,,tmpy,0)
; MoveControl(E_SLV,,,,tmpy,0)
; MoveControl(hProgress2,,tmpy,,,0)
; MoveControl(hGrafPos,,tmpy,,-tmpy,0)
ShiftSpaceY:=150
gosub,ControlSize
gosub,GrafCreateMenu
gosub,GrafRedraw
return
GrafClear:
ObjClear(Monitor_value)
ObjClear(Monitor_value_T)
loop,% MaxNumOfGraf
ObjClear(Monitor_value%a_index%)
gosub,GrafRedraw
return
HotkeysOn:
Hotkey,IfWinActive,% "ahk_id " hMainWin
Hotkey,F1,F1_Label
Hotkey,F2,F2_Label
Hotkey,F3,F3_Label
Hotkey,F4,F4_Label
Hotkey,F5,F5_Label
Hotkey,~$LButton,LButton_Label
Hotkey,~$LButton up,LButton_up_Label
Hotkey,~$RButton,RButton_Label
Hotkey,*~$Right,Right_Label
Hotkey,*~$Left,Left_Label
Hotkey,^sc00D,sc00D_Label
Hotkey,~$WheelUp,WheelUp_Label
Hotkey,^sc00C,sc00C_Label
Hotkey,~$WheelDown,WheelDown_Label
Hotkey,^!+#vk4c,vk4c_Label
; Hotkey,Esc,Esc_Label
Hotkey,~$Up,Up_Label
Hotkey,~$Down,Down_Label
Hotkey,IfWinActive,% "ahk_id " hGraf
Hotkey,F1,F1_Label
Hotkey,F2,F2_Label
Hotkey,F3,F3_Label
Hotkey,F4,F4_Label
Hotkey,F5,F5_Label
Hotkey,~$LButton,LButton_Label
Hotkey,~$LButton up,LButton_up_Label
Hotkey,~$RButton,RButton_Label
Hotkey,*~$Right,Right_Label
Hotkey,*~$Left,Left_Label
Hotkey,^sc00D,sc00D_Label
Hotkey,~$WheelUp,WheelUp_Label
Hotkey,^sc00C,sc00C_Label
Hotkey,~$WheelDown,WheelDown_Label
Hotkey,^!+#vk4c,vk4c_Label
Hotkey,Esc,Esc_Label
return
HotkeysOff:
return
F4_Label:
GrafSmooth:
if GrafSmooth:=!GrafSmooth
{
menu,GrafRightClick,Check,Сглаживание "ступенек" F4
menu,GrafMenu,Check,Сглаживание "ступенек" F4
}
else
{
menu,GrafRightClick,UnCheck,Сглаживание "ступенек" F4
menu,GrafMenu,UnCheck,Сглаживание "ступенек" F4
}
if (a_tickcount-StartDrawTime>500)
gosub,GrafRedraw
return
GrafAutoMinMax:
if AutoMinMax:=!AutoMinMax
{
hi_lim:=1
menu,GrafRightClick,Check,Автоматическое максимальное значение ;
menu,GrafMenu,Check,Автоматическое максимальное значение ;
}
else
{
menu,GrafRightClick,UnCheck,Автоматическое максимальное значение ;
menu,GrafMenu,UnCheck,Автоматическое максимальное значение ;
}
if (a_tickcount-StartDrawTime>500)
gosub,GrafRedraw
return
F2_Label:
GrafChangeMinMax:
InputBox,tmp1,Задать максимальное значение вручную F2,Введите положительное число,,240,130,,,,12,% hi_lim
if !ErrorLevel
{
menu,GrafRightClick,UnCheck,Автоматическое максимальное значение ;
menu,GrafMenu,UnCheck,Автоматическое максимальное значение ;
AutoMinMax:=0
hi_lim:=abs(tmp1)
}
if (a_tickcount-StartDrawTime>500)
gosub,GrafRedraw
return
GrafAutoEnding:
AutoEnding:=!AutoEnding
if AutoEnding
{
EndSymbol:=""
TryFind:=0
; Monitorintext:=""
menu,GrafRightClick,Check,Автоматически определять разделитель графиков ;
menu,GrafMenu,Check,Автоматически определять разделитель графиков ;
settimer,GrafAutoEndingReset,1000
}
else
{
menu,GrafRightClick,UnCheck,Автоматически определять разделитель графиков ;
menu,GrafMenu,UnCheck,Автоматически определять разделитель графиков ;
settimer,GrafAutoEndingReset,off
}
return
F5_Label:
if !(EN_Kurvendrucker)
return
GrafAutoEndingReset:
EndSymbol:=""
TryFind:=0
Monitorintext:=""
return
F3_Label:
if !(EN_Kurvendrucker)
return
GrafChangeEnding:
InputBox,tmp1,Задать разделитель вручную,Введите разделительный символ,,240,130,,,,12,% EndSymbol
if !ErrorLevel
{
menu,GrafRightClick,UnCheck,Автоматически определять разделитель графиков ;
menu,GrafMenu,UnCheck,Автоматически определять разделитель графиков ;
AutoEnding:=0
settimer,GrafAutoEndingReset,off
EndSymbol:=tmp1
}
return
F1_Label:
if !(Monitorvalue or EN_Kurvendrucker)
return
GrafPause:
if GrafPause:=!GrafPause
{
GuiControl,,GrafPause,% GrafPause
menu,GrafRightClick,Check,Остановить прокрутку F1 ;
menu,GrafMenu,Check,Остановить прокрутку F1 ;
}
else
{
GuiControl,,GrafPause,% GrafPause
menu,GrafRightClick,UnCheck,Остановить прокрутку F1 ;
menu,GrafMenu,UnCheck,Остановить прокрутку F1 ;
}
return
GrafDraw:
StartDrawTime:=a_tickcount
GrafRedraw:
if (Monitor_value_T.maxindex()<Gdip_W)
Gdip_Points_Num:=Gdip_W
else
Gdip_Points_Num:=Monitor_value_T.maxindex()
tmp0:=((Gdip_H//Gdip_ZoomY)//2)
if (Gdip_Y_Offset<tmp0) ; верхний край
Gdip_Y_Offset:=tmp0
else if (Gdip_Y_Offset>Gdip_H-tmp0) ; нижний край
Gdip_Y_Offset:=Gdip_H-tmp0
if (Gdip_X_Offset>Gdip_Points_Num-Gdip_W/Gdip_ZoomX) ; левый край
Gdip_X_Offset:=Gdip_Points_Num-Gdip_W/Gdip_ZoomX
if (Gdip_X_Offset<0) ; правый край
Gdip_X_Offset:=0
Gdip_X_Offset:=round(Gdip_X_Offset)
if AutoMinMax
{
if EN_Kurvendrucker
{
hi_lim:=0
loop,% NumOfGraf
{
tmp1:=Ceil(ArrGetMax(Monitor_value%a_index%,Gdip_X_Offset,round(Gdip_W/Gdip_ZoomX)))
if (hi_lim<abs(tmp1))
hi_lim:=abs(tmp1)
}
}
else
hi_lim:=abs(Ceil(ArrGetMax(Monitor_value,Gdip_X_Offset,round(Gdip_W/Gdip_ZoomX))))
}
GuiControl,,Progress2,% round(100-Gdip_X_Offset/(Gdip_Points_Num-Gdip_W/Gdip_ZoomX)*100)
; очистить поле
Gdip_FillRectangle(pMainHolst_G,Gdip_WhiteBrush,0,0,Gdip_Points_Num,Gdip_H)
; отрисовать сетку
Gdip_DrawLine(pMainHolst_G,Gdip_GrayPen,0,Gdip_M
,Gdip_Points_Num,Gdip_M)
; Отрисовать горизонтальные линии величин с текстом
Grad:=10**NumOfSymbols:=(strlen(round(hi_lim))-1)
GdipCoordX:=Gdip_Font_W ;Gdip_Points_Num-Gdip_Font_W*(NumOfSymbols+1)-10
Gdip_Text_W:=Gdip_Font_W*NumOfSymbols
loop,% round(hi_lim)//Grad
{
Val:=A_index*Grad
PlussCoordY:=abs(round((Val/hi_lim)*Gdip_M)+Gdip_M-Gdip_H)
MinusCoordY:=abs(round((-Val/hi_lim)*Gdip_M)+Gdip_M-Gdip_H)
Gdip_FillRectangle(pMainHolst_G,Gdip_WhiteBrush2,GdipCoordX,PlussCoordY+1,Gdip_Text_W,Gdip_Font_H)
Gdip_FillRectangle(pMainHolst_G,Gdip_WhiteBrush2,GdipCoordX,MinusCoordY-Gdip_Font_H,Gdip_Text_W,Gdip_Font_H)
Gdip_TextToGraphics(pMainHolst_G,Val,"x" GdipCoordX " y" PlussCoordY+1 " Left cff000000 " Gdip_Font_Size,Gdip_Font)
Gdip_TextToGraphics(pMainHolst_G,-Val,"x" GdipCoordX-10 " y" MinusCoordY-Gdip_Font_H " Left cff000000 " Gdip_Font_Size,Gdip_Font)
Gdip_DrawLine(pMainHolst_G,Gdip_GrayPen2,0,PlussCoordY
,Gdip_Points_Num,PlussCoordY)
Gdip_DrawLine(pMainHolst_G,Gdip_GrayPen2,0,MinusCoordY
,Gdip_Points_Num,MinusCoordY)
}
; линия нуля
Gdip_FillRectangle(pMainHolst_G,Gdip_WhiteBrush2,GdipCoordX,Gdip_M,Gdip_Font_W,Gdip_Font_H)
Gdip_TextToGraphics(pMainHolst_G,0,"x" GdipCoordX " y" Gdip_M " Left cff000000 " Gdip_Font_Size,Gdip_Font)
; отрисовать синий график
if EN_MonitorVar
{
Gdip_Time_Stamp:=0
Old_j:=0
Smooth_GdipCoordX:=0
Old_GdipCoordY:=abs(round((Monitorvalue/hi_lim)*(Gdip_M))+Gdip_M-Gdip_H) ;Gdip_M
Old_Time:=Average_time_summ:=Average_time_Devider:=0
Val_UnderGraf_Drawed:=0
loop,% round(Gdip_W/Gdip_ZoomX)
{
i:=a_index
j:=Monitor_value[i+Gdip_X_Offset]
; out=(inval/max)*(hi_lim-lo_lim)+lo_lim
GdipCoordX:=round(Gdip_W-(i*Gdip_ZoomX))
if (abs(j)<=hi_lim)
GdipCoordY:=abs(round((j/hi_lim)*(Gdip_M))+Gdip_M-Gdip_H)
else if (j>0)
GdipCoordY:=0
else if (j<0)
GdipCoordY:=Gdip_H
if tmp0:=Monitor_value_T[i+Gdip_X_Offset]
{
RegExMatch(tmp0,"([\d]+).([\d]+).([\d]+).([\d]+)",tmp)
Calc_Time:=(tmp1*3600+tmp2*60+tmp3)*1000+tmp4
if Old_Time
{
Delta_Time:=Old_Time-Calc_Time
Average_time_Devider++
Average_time_summ:=Average_time_summ+Delta_Time
; отметить точки с задержкой
; if (Average_time and Delta_Time>Average_time and Old_GdipCoordX!=GdipCoordX)
; Gdip_DrawLine(pMainHolst_G,Gdip_GrayPen3,GdipCoordX+1,0
; ,GdipCoordX+1,Gdip_H)
}
Old_Time:=Calc_Time
}
if (!GrafSmooth or (Old_j!=j))
{
; линия синего графика
Gdip_DrawLine(pMainHolst_G,Gdip_BluePen,round(GdipCoordX+Smooth_GdipCoordX+Gdip_ZoomX),Old_GdipCoordY,GdipCoordX,GdipCoordY)
if (Gdip_ZoomX>7)
Gdip_DrawEllipse(pMainHolst_G,Gdip_BluePen,GdipCoordX-1,GdipCoordY-1,2,2)
if (Gdip_ZoomX<0.5)
Gdip_DrawEllipse(pMainHolst_G,Gdip_BluePen,GdipCoordX-1,GdipCoordY-1,1,1)
Old_GdipCoordY:=GdipCoordY
Old_j:=j
Smooth_GdipCoordX:=0
}
else
Smooth_GdipCoordX+=1*Gdip_ZoomX
Gdip_Time_Stamp+=Gdip_ZoomX
if (Gdip_Time_Stamp>10*Gdip_Font_W)
{
Gdip_Time_Stamp:=0
; линия и текст временой шкалы
Gdip_DrawLine(pMainHolst_G,Gdip_GrayPen2,GdipCoordX+1,0
,GdipCoordX+1,Gdip_H)
tmp0:=Monitor_value_T[i+Gdip_X_Offset]
if tmp0
{
StringTrimRight,tmp0,tmp0,4
Gdip_FillRectangle(pMainHolst_G,Gdip_WhiteBrush2,GdipCoordX+1,Gdip_H-Gdip_Font_H
,Gdip_Font_W*(strlen(tmp0)),Gdip_Font_H)
Gdip_TextToGraphics(pMainHolst_G,tmp0,"x" GdipCoordX+1 " y" Gdip_H-Gdip_Font_H " Left cff000000 " Gdip_Font_Size,Gdip_Font)
}
}
; текст значения под курсором
if (!Val_UnderGraf_Drawed)
if (UnderGraf_mx>=GdipCoordX and UnderGraf_mx<=GdipCoordX+10)
if (UnderGraf_my>GdipCoordY-10 and UnderGraf_my<GdipCoordY+10)
{
Val_UnderGraf_Drawed:=1
tmp1:=(GdipCoordY-Gdip_Font_H)<0?0:(GdipCoordY-Gdip_Font_H)
Gdip_FillRectangle(pMainHolst_G,Gdip_WhiteBrush2,GdipCoordX,tmp1,Gdip_Font_W*(strlen(j)),Gdip_Font_H)
Gdip_TextToGraphics(pMainHolst_G,j,"x" GdipCoordX " y" tmp1 " Left c" Gdip_Font_Selected_Colour " " Gdip_Font_Size,Gdip_Font)
}
Old_GdipCoordX:=GdipCoordX
}
Average_time:=Average_time_summ//Average_time_Devider*2
if (Monitorvalue>=0)
addY:=0
else
addY:=-Gdip_Font_H
Old_GdipCoordY:=abs(round((Monitorvalue/hi_lim)*(Gdip_M))+Gdip_M-Gdip_H) ;Gdip_M
GdipCoordX:=Gdip_W-Gdip_Font_W*(strlen(Monitorvalue))
; текст текущего значения
Gdip_FillRectangle(pMainHolst_G,Gdip_WhiteBrush2,GdipCoordX,Old_GdipCoordY+1+addY,Gdip_Font_W*(strlen(Monitorvalue)),Gdip_Font_H)
Gdip_TextToGraphics(pMainHolst_G,Monitorvalue,"x" GdipCoordX " y" Old_GdipCoordY+1+addY " Left cff000000 " Gdip_Font_Size,Gdip_Font)
if (Gdip_Marker_mx>0 and Gdip_Marker_mx<=Gdip_W and Gdip_Marker_my>0 and Gdip_Marker_my<=Gdip_H)
{
j:=Monitor_value[round((Gdip_W-Gdip_Marker_mx)/Gdip_ZoomX+Gdip_X_Offset)]
if (j>=0)
addY:=0
else
addY:=-Gdip_Font_H
if (abs(j)<=hi_lim)
GdipCoordY:=abs(round((j/hi_lim)*(Gdip_M))+Gdip_M-Gdip_H)
else if (j>0)
GdipCoordY:=0
else if (j<0)
GdipCoordY:=Gdip_H
; время значения выбранного мышкой
t:=Monitor_value_T[round((Gdip_W-Gdip_Marker_mx)/Gdip_ZoomX+Gdip_X_Offset)]
Gdip_FillRectangle(pMainHolst_G,Gdip_WhiteBrush2,Gdip_Marker_mx,1,Gdip_Font_W*(strlen(t)),Gdip_Font_H)
Gdip_TextToGraphics(pMainHolst_G,t,"x" round(Gdip_Marker_mx) " y" 1 " Left c" Gdip_Font_Selected_Colour " " Gdip_Font_Size,Gdip_Font)
; линия и значение выбранное мышкой
Gdip_DrawLine(pMainHolst_G,Gdip_GrayPen,Gdip_Marker_mx,0,Gdip_Marker_mx,Gdip_H)
tmp1:=GdipCoordY+addY<Gdip_Font_H?Gdip_Font_H:GdipCoordY+addY
Gdip_FillRectangle(pMainHolst_G,Gdip_WhiteBrush2,Gdip_Marker_mx,tmp1,Gdip_Font_W*(strlen(j)),Gdip_Font_H)
Gdip_TextToGraphics(pMainHolst_G,j,"x" round(Gdip_Marker_mx) " y" tmp1 " Left c" Gdip_Font_Selected_Colour " " Gdip_Font_Size,Gdip_Font)
}
}
; отрисовать остальные графики
if EN_Kurvendrucker
{
loop,% NumOfGraf
{
CurGN:=a_index
if !EnableGraf%CurGN%
continue
Old_j:=0
Smooth_GdipCoordX:=0
Old_GdipCoordY:=abs(round((Monitorvalue/hi_lim)*(Gdip_M))+Gdip_M-Gdip_H) ;Gdip_M
Val_UnderGraf_Drawed:=0
loop,% round(Gdip_W/Gdip_ZoomX)
{
i:=a_index
j:=Monitor_value%CurGN%[i+Gdip_X_Offset]
; out=(inval/max)*(hi_lim-lo_lim)+lo_lim
GdipCoordX:=round(Gdip_W-(i*Gdip_ZoomX))
if (abs(j)<=hi_lim)
GdipCoordY:=abs(round((j/hi_lim)*(Gdip_M))+Gdip_M-Gdip_H)
else if (j>0)
GdipCoordY:=0
else if (j<0)
GdipCoordY:=Gdip_H
if (!GrafSmooth or (Old_j!=j))
{
; линия остальных графиков
Gdip_DrawLine(pMainHolst_G,Gdip_Pen%CurGN%,round(GdipCoordX+Smooth_GdipCoordX+Gdip_ZoomX),Old_GdipCoordY,GdipCoordX,GdipCoordY)
if (Gdip_ZoomX>7)
Gdip_DrawEllipse(pMainHolst_G,Gdip_Pen%CurGN%,GdipCoordX-2,GdipCoordY-2,4,4)
Old_GdipCoordY:=GdipCoordY
Old_j:=j
Smooth_GdipCoordX:=0
}
else
Smooth_GdipCoordX+=1*Gdip_ZoomX
; текст значения под курсором
if (!Val_UnderGraf_Drawed)
if (UnderGraf_mx>=GdipCoordX and UnderGraf_mx<=GdipCoordX+10)
if (UnderGraf_my>GdipCoordY-10 and UnderGraf_my<GdipCoordY+10)
{
Val_UnderGraf_Drawed:=1
tmp1:=(GdipCoordY-Gdip_Font_H)<0?0:(GdipCoordY-Gdip_Font_H)
Gdip_FillRectangle(pMainHolst_G,Gdip_Brush%CurGN%,GdipCoordX,tmp1,Gdip_Font_W*(strlen(j)),Gdip_Font_H)
Gdip_TextToGraphics(pMainHolst_G,j,"x" GdipCoordX " y" tmp1 " Left c" Gdip_Font_Selected_Colour " " Gdip_Font_Size,Gdip_Font)
}
}
if (Monitorvalue>=0)
addY:=0
else
addY:=-Gdip_Font_H
j:=Monitor_value%CurGN%[Gdip_X_Offset]
Old_GdipCoordY:=abs(round((j/hi_lim)*(Gdip_M))+Gdip_M-Gdip_H) ;Gdip_M
GdipCoordX:=Gdip_W-Gdip_Font_W*(strlen(j))
; текст текущего значения
; Gdip_FillRectangle(pMainHolst_G,Gdip_WhiteBrush2,GdipCoordX,Old_GdipCoordY+1+addY,Gdip_Font_W*(strlen(j)),Gdip_Font_H)
; Gdip_TextToGraphics(pMainHolst_G,j,"x" GdipCoordX " y" Old_GdipCoordY+1+addY " Left cff000000 " Gdip_Font_Size,Gdip_Font)
if (Gdip_Marker_mx>0 and Gdip_Marker_mx<=Gdip_W and Gdip_Marker_my>0 and Gdip_Marker_my<=Gdip_H)
{
j:=Monitor_value%CurGN%[round((Gdip_W-Gdip_Marker_mx)/Gdip_ZoomX+Gdip_X_Offset)]
if (j>=0)
addY:=0
else
addY:=-Gdip_Font_H
if (abs(j)<=hi_lim)
GdipCoordY:=abs(round((j/hi_lim)*(Gdip_M))+Gdip_M-Gdip_H)
else if (j>0)
GdipCoordY:=0
else if (j<0)
GdipCoordY:=Gdip_H
; время значения выбранного мышкой
t:=Monitor_value_T[round((Gdip_W-Gdip_Marker_mx)/Gdip_ZoomX+Gdip_X_Offset)]
Gdip_FillRectangle(pMainHolst_G,Gdip_WhiteBrush2,Gdip_Marker_mx,1,Gdip_Font_W*(strlen(t)),Gdip_Font_H)
Gdip_TextToGraphics(pMainHolst_G,t,"x" round(Gdip_Marker_mx) " y" 1 " Left c" Gdip_Font_Selected_Colour " " Gdip_Font_Size,Gdip_Font)
; линия и значение выбранное мышкой
if (j!="")
tmp1:=CurGN "=" j
else
tmp1:=""
Gdip_DrawLine(pMainHolst_G,Gdip_GrayPen,Gdip_Marker_mx,0,Gdip_Marker_mx,Gdip_H)
Gdip_FillRectangle(pMainHolst_G,Gdip_Brush%CurGN%,Gdip_Marker_mx,Gdip_Font_H*CurGN,Gdip_Font_W*(strlen(tmp1)),Gdip_Font_H)
Gdip_TextToGraphics(pMainHolst_G,tmp1,"x" round(Gdip_Marker_mx) " y" Gdip_Font_H*CurGN " Left c" Gdip_Font_Selected_Colour " " Gdip_Font_Size,Gdip_Font)
}
}
Gdip_Time_Stamp:=0
loop,% round(Gdip_W/Gdip_ZoomX)
{
i:=a_index
Gdip_Time_Stamp+=Gdip_ZoomX
if (Gdip_Time_Stamp>10*Gdip_Font_W)
{
GdipCoordX:=round(Gdip_W-(i*Gdip_ZoomX))
Gdip_Time_Stamp:=0
Gdip_DrawLine(pMainHolst_G,Gdip_GrayPen2,GdipCoordX+1,0
,GdipCoordX+1,Gdip_H)
tmp0:=Monitor_value_T[i+Gdip_X_Offset]
if tmp0
{
; текст временой шкалы
StringTrimRight,tmp0,tmp0,4
Gdip_FillRectangle(pMainHolst_G,Gdip_WhiteBrush2,GdipCoordX+1,Gdip_H-Gdip_Font_H
,Gdip_Font_W*(strlen(tmp0)),Gdip_Font_H)
Gdip_TextToGraphics(pMainHolst_G,tmp0,"x" GdipCoordX+1 " y" Gdip_H-Gdip_Font_H " Left cff000000 " Gdip_Font_Size,Gdip_Font)
}
}
}
}
GrafUpdate:
; Обновить отображение
; Скопировать отрисованный график
; if (a_osversion~="10") ???????????????????try on real system?????????????????????????????????
; GuiControlGet,Gdip_,Pos,% hGrafPos
; else
Gdip_X:=Gdip_Y:=Gdip_W:=Gdip_H:=0
wingetpos,Gdip_X,Gdip_Y,Gdip_W,Gdip_H,% "ahk_id" hGrafPos
if (Gdip_X=0 or Gdip_Y=0 or Gdip_W=0 or Gdip_H=0)
GuiControlGet,Gdip_,Pos,% hGrafPos
Gdip_M:=Gdip_H//2
if (EN_MonitorVar or EN_Kurvendrucker)
UpdateLayeredWindow(hGraf,pMainHolst,Gdip_X,Gdip_Y,Gdip_W,Gdip_H+1)
else
UpdateLayeredWindow(hGraf,pMainHolst,Gdip_X,Gdip_Y,Gdip_W,Gdip_H+1,0)
DrawTime:=a_tickcount-StartDrawTime
;tooltip,% DrawTime "`n" Monitor_value_T.maxindex(),500,0,9
UnderGraf_MouseMove:=0
return
GuiSize:
if 2ndThread
return
if (!Old_GuiWidth or !Old_GuiHeight)
{
Old_GuiWidth:=A_GuiWidth
Old_GuiHeight:=A_GuiHeight
}
if (A_EventInfo=1)
return
DeltaGuiWidth:=A_GuiWidth-Old_GuiWidth
DeltaGuiHeight:=A_GuiHeight-Old_GuiHeight
MoveControl(hGroupBufer,,,DeltaGuiWidth,DeltaGuiHeight)
MoveControl(hClButton,,DeltaGuiHeight,DeltaGuiWidth)
MoveControl(hTtEButton,,DeltaGuiHeight)
loop,% MaxNumOfGraf+1
{
i:=a_index-1
MoveControl(hECB%i%,,DeltaGuiHeight)
}
gosub,ControlSize
if (EN_Kurvendrucker or EN_MonitorVar)
gosub,GrafRedraw
;tooltip,% "dw" DeltaGuiWidth "`ndh" DeltaGuiHeight "`nw" A_GuiWidth "`nh" A_GuiHeight
Old_GuiWidth:=A_GuiWidth
Old_GuiHeight:=A_GuiHeight
return
ControlSize:
GuiControlGet,G_pos,Pos,% hGroupBufer
if (EN_Kurvendrucker)
{
; hGrafPos_over:=MoveControl(hGrafPos,,,DeltaGuiWidth,DeltaGuiHeight)
; E_Text_over:=MoveControl(E_Text,,,DeltaGuiWidth,((hGrafPos_over&2)?DeltaGuiHeight:0))
; MoveControl(E_SLV,,,DeltaGuiWidth,((hGrafPos_over&2)?DeltaGuiHeight:0))
; hProgress2_over:=MoveControl(hProgress2,,((hGrafPos_over&2)?DeltaGuiHeight:0),DeltaGuiWidth)
;
; MoveControl(E_LV,0xffff,0xffff,((E_Text_over&1)?DeltaGuiWidth:0),DeltaGuiHeight)
; MoveControl(hProgress,((E_Text_over&1)?DeltaGuiWidth:0),,,DeltaGuiHeight)
GuiControlGet,P_pos,Pos,% hProgress
tmp0:=(G_posw-20)
tmp1:=P_posy+((P_posh/1000*ShiftSpaceY))
GuiControl,Move,% hProgress2,% " x" (G_posx+10) " y" tmp1 " w" tmp0
GuiControlGet,S_pos,Pos,% hProgress2
GuiControl,Move,% E_Text,% " x" (G_posx+10) " y" P_posy " w" tmp0 " h" (S_posy-P_posy)
GuiControl, Move,% E_SLV,% " x" (G_posx+10) " y" P_posy " w" tmp0 " h" (S_posy-P_posy)
GuiControl,Move,% hGrafPos,% " x" (G_posx+10) " y" (tmp1+20) " w" tmp0 " h" (P_posy+(G_posh-107)-S_posy-S_posh)
gosub,GrafUpdate
}
else
{
GuiControl,Move,% hProgress,% " x" (G_posx+(G_posw/1000*ShiftSpaceX)) " y" (G_posy+65) " h" (G_posh-107)
GuiControlGet,P_pos,Pos,% hProgress
tmp0:=(P_posx+P_posw)
tmp1:=P_posy+((P_posh/1000*ShiftSpaceY))
tmp2:=(G_posx+G_posw-P_posx-30)
GuiControl,Move,% hProgress2,% " x" tmp0 " y" tmp1 " w" tmp2
GuiControlGet,S_pos,Pos,% hProgress2
tmp3:=(S_posy-P_posy)
GuiControl,Move,% E_LV,% " x" (G_posx+10) " y" P_posy " w" (P_posx-G_posx-10) " h" P_posh
GuiControl,Move,% E_Text,% " x" tmp0 " y" P_posy " w" tmp2 " h" tmp3
GuiControl, Move,% E_SLV,% " x" tmp0 " y" P_posy " w" tmp2 " h" tmp3
GuiControl,Move,% hGrafPos,% " x" tmp0 " y" (tmp1+20) " w" tmp2 " h" (P_posy+P_posh-S_posy-S_posh)
if (EN_Kurvendrucker or EN_MonitorVar)
gosub,GrafRedraw
;; E_Text_over:=MoveControl(E_Text,,0xffff,DeltaGuiWidth,DeltaGuiHeight)
;; MoveControl(E_SLV,,0xffff,DeltaGuiWidth,DeltaGuiHeight)
;; hProgress2_over:=MoveControl(hProgress2,,(!(E_Text_over&2)?DeltaGuiHeight:0),DeltaGuiWidth)
;; hGrafPos_over:=MoveControl(hGrafPos,,(!(E_Text_over&2)?DeltaGuiHeight:0),DeltaGuiWidth,((E_Text_over&2)?DeltaGuiHeight:0),0)
;; MoveControl(E_LV,0xffff,0xffff,((E_Text_over&1)?DeltaGuiWidth:0),DeltaGuiHeight)
;; MoveControl(hProgress,((E_Text_over&1)?DeltaGuiWidth:0),,,DeltaGuiHeight)
}
return
RemoveTooltip:
tooltip
return
___________Hotkeys:
return
LButton_Label:
mousegetpos,mx,my,mw,mc
oldmx:=mx
oldmy:=my
oldmc:=mc
oldmw:=mw
if (mw=hGraf)
{
Gdip_Marker_mx:=mx-Gdip_X
Gdip_Marker_my:=my-Gdip_Y
}
if (MouseAbovehMain)
{
ControlGet,hElement,hwnd,,%mc%,ahk_id %mw%
if (hElement=hProgress)
EditResize:=1
if (hElement=hProgress2)
EditResize:=2
if (hElement=E_LV or hElement=E_LV2)
ControlFocus,,ahk_id %hElement%
}
if ((Analyzer and AnBusy) or TurnBack or FileLoading or FileSaving)
if (substr(a_priorhotkey,1,9)=a_thishotkey and a_timesincepriorhotkey<DllCall("GetDoubleClickTime"))
StopAnalyze:=1
return
LButton_up_Label:
EndResizing:
EditResize:=0
if (a_tickcount-StartDrawTime>500)
gosub,GrafRedraw
return
RButton_Label:
mousegetpos,mx,my,mw,mc
ControlGet,hElement,hwnd,,%mc%,ahk_id %mw%
if (mw=hGraf)
menu,GrafRightClick,show
if (hElement=hBufinfo)
menu,ListRightClick2,show
if (hElement=hProgress2)
{
if (a_osversion~="10")
GuiControlGet,E_pos,Pos,% hProgress2
else
wingetpos,E_posX,E_posY,E_posW,E_posH,% "ahk_id" hProgress2
ClickPos:=(E_posw-(mx-E_posx))/E_posw*100
tmp1:=round(Gdip_Points_Num-Gdip_W/Gdip_ZoomX)
Gdip_X_Offset:=ClickPos*tmp1/100
if (a_tickcount-StartDrawTime>500)
gosub,GrafRedraw
}
loop,% MaxNumOfGraf
{
i:=a_index
if (hElement=hECB%i%)
{
if (EnableGraf%i%)
{
loop,% MaxNumOfGraf
if (a_index!=i)
GuiControl,,EnableGraf%a_index%,0
}
else
{
loop,% MaxNumOfGraf
GuiControl,,EnableGraf%a_index%,1
}
gosub,submiting
break
}
}
return
Right_Label:
if WinActive("Ahk_id " hGraf)
{
if getkeystate("Ctrl","P")
Gdip_X_Offset-=20
Gdip_Marker_mx+=20
if (a_tickcount-StartDrawTime>500)
gosub,GrafRedraw
}
return
Left_Label:
if WinActive("Ahk_id " hGraf)
{
if getkeystate("Ctrl","P")
Gdip_X_Offset+=5
Gdip_Marker_mx-=5
if (a_tickcount-StartDrawTime>500)
gosub,GrafRedraw
}
return
ZoomIn:
sc00D_Label:
WheelUp_Label:
if !((MouseAbovehGraf or a_thislabel="ZoomIn") and (EN_MonitorVar or EN_Kurvendrucker))
return
if (Gdip_ZoomX>=1)
Gdip_ZoomX+=1
else
Gdip_ZoomX+=0.1
if (Gdip_ZoomX<0.5)
{
SaveGrafSmooth:=GrafSmooth
GrafSmooth:=false
}
else
GrafSmooth:=SaveGrafSmooth
if (Gdip_ZoomX>10)
Gdip_ZoomX:=10
Gdip_ZoomY+=1
if (Gdip_ZoomY>10)
Gdip_ZoomY:=10
if (a_tickcount-StartDrawTime>500)
gosub,GrafRedraw
return
ZoomOut:
sc00C_Label:
WheelDown_Label:
if !((MouseAbovehGraf or a_thislabel="ZoomOut") and (EN_MonitorVar or EN_Kurvendrucker))
return
if (Gdip_ZoomX>1)
Gdip_ZoomX-=1
else
Gdip_ZoomX-=0.1
if (Gdip_ZoomX<0.1)
Gdip_ZoomX:=0.1
if (Gdip_ZoomX<0.5)
{
SaveGrafSmooth:=GrafSmooth
GrafSmooth:=false
}
else
GrafSmooth:=SaveGrafSmooth
Gdip_ZoomY-=1
if (Gdip_ZoomY<1)
Gdip_ZoomY:=1
if (a_tickcount-StartDrawTime>500)
gosub,GrafRedraw
return
Up_Label:
Down_Label:
if (a_timesincepriorhotkey>100)
{
GuiControlGet,F,FocusV
if (F="_SecondList_" or F="_List_")
{
tmp0:=F="_List_"?E_LV:E_SLV
UpDown_Label:=1
Gui,1:ListView,% tmp0
; GuiControl,-Redraw,% tmp0
SelBlockNow:=LV_GetNext()
loop,30000
{
Gui,1:ListView,% tmp0
tmp1:=(a_thislabel="Up_Label")?SelBlockNow-a_index:SelBlockNow+a_index
if (tmp1>LV_GetCount() or a_timesincepriorhotkey<=100)
break
LV_GetText(SelBlock,tmp1,COLUMN_HOOK)
if (SelBlock=" " or tmp1=1)
{
sleep,10
keywait,% (a_thislabel="Up_Label")?"Up":"Down",L
LV_Modify(0,"-Select")
LV_Modify(tmp1,"Select")
LV_Modify((a_thislabel="Up_Label")?tmp1:tmp1+30,"Vis Focus")
LV_Modify(tmp1+1,"Vis Focus")
;tooltip,% a_timesincepriorhotkey
break
}
}
GuiControl,+Redraw,% tmp0
Gui,1:ListView,% E_LV
UpDown_Label:=0
}
}
return
CheckPIDExist(PID)
{
process,exist,% PID
if !errorlevel
gosub,Exit
}
Esc_Label:
EXIT:
GuiClose:
GuiCancel:
GuiEscape:
DllCall("SystemParametersInfo","UInt",0x57,"UInt",0,Ptr,"","UInt",0)
DC_ARROW := DllCall("CopyImage",Ptr,IDC_ARROW,"UInt",0x2,"Int",0,"Int",0,"UInt",0)
DllCall("SetSystemCursor",Ptr,DC_ARROW,"UInt",32512)
if Gdip_Initialised
{
Gdip_DeletePen(Gdip_WhitePen)
Gdip_DeletePen(Gdip_GrayPen)
Gdip_DeletePen(Gdip_GrayPen2)
Gdip_DeletePen(Gdip_BluePen)
Gdip_DeletePen(Gdip_BlackPen)
loop,% MaxNumOfGraf
Gdip_DeletePen(Gdip_Pen%a_index%)
Gdip_DeleteBrush(Gdip_WhiteBrush)
Gdip_DeleteBrush(Gdip_WhiteBrush2)
Gdip_DeleteBrush(Gdip_BlackBrush)
SelectObject(pMainHolst,Gdip_obm2), DeleteObject(Gdip_hbm2), DeleteDC(pMainHolst), Gdip_DeleteGraphics(pMainHolst_G)
Gdip_Shutdown(Gdip_Initialised)
}
RS232_Close(RS232_FileHandle)
exitapp
; ////////// отработанные линии________ctrl+Shift+win+alt+L ____________________HOTKEYS_________________________
vk4c_Label:
if !((WinActive("ahk_id " hMainWin) or WinActive("ahk_id " hGraf)))
return
ListLines
return
#if
GetPointer(wParam,lParam)
{
global
slPointer:=lParam
}
WM_MOVING()
{
global
if 2ndThread
return
if (EN_MonitorVar or EN_Kurvendrucker)
gosub,GrafUpdate
}
WM_MOUSEMOVE:
if 2ndThread
return
mousegetpos,mx,my,mw,mc
if (mx!=oldmx or my!=oldmy)
{
Deltamx:=mx-oldmx
Deltamy:=my-oldmy
wingetpos,Gdip_X_,Gdip_Y_,Gdip_W_,Gdip_H_,% "ahk_id" hGrafPos
UnderGraf_mx:=mx-Gdip_X_
UnderGraf_my:=my-Gdip_Y_
UnderGraf_MouseMove:=1
MouseAbovehGraf:=(mw=hGraf)
MouseAbovehMain:=(mw=hMainWin)
if (MouseAbovehMain and oldmc!=mc)
{
ControlGet,hElement,hwnd,,%mc%,ahk_id %mw%
if !E%hElement%
SB_SetText(sended)
else
SB_SetText(E%hElement%)
}
if (MouseAbovehMain or MouseAbovehGraf)
{
ControlGet,hElement,hwnd,,%mc%,ahk_id %mw%
if (!ChangeCursorOnce and hElement=hProgress)
{
ChangeCursorOnce=1
DllCall("SystemParametersInfo","UInt",0x57,"UInt",0,"UInt","","UInt",0)
DllCall("SetSystemCursor",Ptr,IDC_SIZEWE,"UInt",32512)
}
if (!ChangeCursorOnce2 and hElement=hProgress2)
{
ChangeCursorOnce2=1
DllCall("SystemParametersInfo","UInt",0x57,"UInt",0,"UInt","","UInt",0)
DllCall("SetSystemCursor",Ptr,IDC_SIZEALL,"UInt",32512)
}
}
if (ChangeCursorOnce or ChangeCursorOnce2) and ((hElement!=hProgress and hElement!=hProgress2) or !MouseAbovehMain)
{
ChangeCursorOnce=0
ChangeCursorOnce2=0
DllCall("SystemParametersInfo","UInt",0x57,"UInt",0,Ptr,"","UInt",0)
DC_ARROW := DllCall("CopyImage",Ptr,IDC_ARROW,"UInt",0x2,"Int",0,"Int",0,"UInt",0)
DllCall("SetSystemCursor",Ptr,DC_ARROW,"UInt",32512)
}
if (EditResize)
{
if EN_Kurvendrucker
Deltamx:=0
GuiControlGet,E_pos,Pos,% E_LV
GuiControlGet,T_pos,Pos,% E_Text
if !((E_posw+Deltamx)<10 or (T_posw-Deltamx)<10)
{
MoveControl(E_LV,,,Deltamx,,0)
MoveControl(hProgress,Deltamx,,,,0)
MoveControl(hProgress2,Deltamx,,-Deltamx,,0)
MoveControl(E_Text,Deltamx,,-Deltamx,,0)
MoveControl(E_SLV,Deltamx,,-Deltamx,,0)
MoveControl(hGrafPos,Deltamx,,-Deltamx,,0)
if (Deltamx>0)
Gdip_X_Offset-=Deltamx*2
; gosub,GrafUpdate
}
if (EditResize=2)
{
GuiControlGet,T_pos,Pos,% hGrafPos
if !((E_posh+Deltamy)<10 or (T_posh-Deltamy)<2)
{
ov:=MoveControl(E_Text,,0xffff,,Deltamy,2)
if !ov
{
MoveControl(E_SLV,,,,Deltamy,0)
MoveControl(hProgress2,,Deltamy,,,0)
MoveControl(hGrafPos,,Deltamy,,-Deltamy,2)
; gosub,GrafUpdate
}
}
}
GuiControlGet,G_pos,Pos,% hGroupBufer
GuiControlGet,P_pos,Pos,% hProgress
GuiControlGet,S_pos,Pos,% hProgress2
ShiftSpaceX:=round((P_posx-G_posx)/(G_posw)*1000)
ShiftSpaceY:=round((S_posy-P_posy)/(P_posh)*1000)
gosub,ControlSize
}
Deltamx:=(mx-oldmx)*((3-Gdip_ZoomX<1) ? 1 : 3-Gdip_ZoomX)
Deltamy:=(my-oldmy)*((3-Gdip_ZoomY<1) ? 1 : 3-Gdip_ZoomY)
if (MouseAbovehGraf and getkeystate("LButton","P"))
{
Gdip_Y_Offset-=Deltamy
Gdip_X_Offset+=Deltamx
Gdip_Marker_mx+=Deltamx
if (a_tickcount-StartDrawTime>500)
gosub,GrafRedraw
}
if (MouseAbovehGraf and (oldmx!=mx or oldmy!=my) and a_tickcount-StartDrawTime>500)
{
SB_SetText("Дополнительное меню правой кнопкой мыши. Масштаб = " round(Gdip_ZoomX,1) ". Максимальное значение = " hi_lim ". Время отрисовки кадра = " DrawTime "ms. Число точек = " Monitor_value_T.maxindex() ".")
gosub,GrafRedraw
}
}
oldmx:=mx
oldmy:=my
oldmc:=mc
oldmw:=mw
if (MouseAbovehGraf and (EN_MonitorVar or EN_Kurvendrucker))
SB_SetText("Дополнительное меню правой кнопкой мыши. Масштаб = " round(Gdip_ZoomX,1) ". Максимальное значение = " hi_lim ". Время отрисовки кадра = " DrawTime "ms. Число точек = " Monitor_value_T.maxindex() ".")
return
GetClientPos(hwnd)
{
VarSetCapacity(pwi, 60, 0), NumPut(60, pwi, 0, "UInt")
DllCall("GetWindowInfo", Ptr, hwnd, "UInt", &pwi)
top := NumGet(pwi, 24, "Int") - NumGet(pwi, 8, "Int")
left := NumGet(pwi, 52, "Int")
w := NumGet(pwi, 28, "Int") - NumGet(pwi, 20, "Int")
h := NumGet(pwi, 32, "Int") - NumGet(pwi, 24, "Int")
return {"top":top,"left":left,"w":w,"h":h}
}
CRC16(byref data,size,summ=0,Polynom=0x8005,Init=0xFFFF,RefIn=1,RefOut=1,XorOut=0,ReversPolynom=0)
{
if !ReversPolynom
Polynom:=ReverseWord(Polynom)
if !summ
{
z:=Init
loop,% size
{
In:=isobject(data)?data[a_index]:numget(data,a_index-1,"uchar")
if !RefIn
In:=ReverseBits(In)
z^=In
loop,8
{
r:=z&1
z>>=1
if r
z^=Polynom
}
}
if !RefOut
z:=ReverseWord(z)
return z^XorOut
}
else
{
loop,% size
sum+=isobject(data)?data[a_index]:numget(data,a_index-1,"uchar")
return sum
}
}
ReverseBits(byte)
{
tmp0:=0
loop,8
{
tmp0<<=1
tmp0|=byte&1
byte>>=1
}
byte:=tmp0
return byte
}
ReverseWord(word)
{
return (ReverseBits(word&0xFF)<<8)|ReverseBits((word&0xFF00)>>8)
}
CRC_RTU(byref data,size)
{
z:=0xFFFF
loop,% size
{
In:=isobject(data)?data[a_index]:numget(data,a_index-1,"uchar")
z^=In
loop,8
{
r:=z&1
z>>=1
if r
z^=0xA001
}
}
a:=z//256
b:=mod(z,256)
return (a<<8)|b
;1) y=65535;
;2) загрузить в переменную x первый байт из потока данных;
;3) вычислить переменную z = ИСКЛЮЧАЮЩЕЕ ИЛИ y c байтом потока данных x.
;4) сдвинуть переменную z на один бит вправо
;5) если сдвинутый бит равен 1 то вычислить переменную z:
;z= ИСКЛЮЧАЮЩЕЕ ИЛИ z с числом 0xA001
;6) повторять шаг 4 и шаг 5 еще 7 раз.
;7) y=z
;8) если все байты из потока данных обработаны перейти на шаг 10
;9) перейти на шаг 2
;10) вычислить первый и второй байты CRC16-кода a и b.
;a=z/256(нацело)
;b= остаток от деления z/256.
}
SwapByte(var)
{
tmp1:=(var<<8)&0xff00
tmp2:=(var>>8)
return (tmp1|tmp2)
}
SearchCOM(name,list=0)
{
Loop,HKLM,HARDWARE\DEVICEMAP\SERIALCOMM\
{
RegRead,COMPort
FriendlyName:=""
Loop,HKLM,SYSTEM\CurrentControlSet\Enum,1,1
{
if (A_LoopRegName="PortName")
{
RegRead,Outputvar
if (Outputvar=COMPort)
{
RegRead,FriendlyName,% A_LoopRegKey,% RegExReplace(A_LoopRegSubKey, "(.*)\\Device Parameters", "$1"),FriendlyName
if (!list and InStr(FriendlyName,name))
return COMPort
}
}
}
if (FriendlyName="")
FriendlyName:=A_LoopRegName
if list
out.=COMPort "`t" FriendlyName "`n"
else if (InStr(A_LoopRegName,name))
return COMPort
}
if list
return out
}
RS232_Get_FileHandle(RS232_Port="COM1",RS232_Baud=9600,RS232_Parity="N",RS232_Data=8,RS232_Stop=1,ReadIntervalTimeout="")
{
; COMx[:][baud=b][parity=p][data=d][stop=s][to={on|off}][xon={on|off}][odsr={on|off}][octs={on|off}][dtr={on|off|hs}][rts={on|off|hs|tg}][idsr={on|off}]
RS232_Settings=%RS232_Port%:baud=%RS232_Baud% parity=%RS232_Parity% data=%RS232_Data% stop=%RS232_Stop% to=off xon=off odsr=off octs=off dtr=Off rts=off idsr=off
;###### Extract/Format the RS232 COM Port Number ######
;7/23/08 Thanks krisky68 for finding/solving the bug in which RS232 COM Ports greater than 9 didn't work.
StringSplit, RS232_Temp, RS232_Settings, `:
RS232_Temp1_Len := StrLen(RS232_Temp1) ;For COM Ports > 9 \\.\ needs to prepended to the COM Port name.
If (RS232_Temp1_Len > 4) ;So the valid names are
RS232_COM = \\.\%RS232_Temp1% ; ... COM8 COM9 \\.\COM10 \\.\COM11 \\.\COM12 and so on...
Else
RS232_COM = %RS232_Temp1%
;8/10/09 A BIG Thanks to trenton_xavier for figuring out how to make COM Ports greater than 9 work for USB-Serial Dongles.
StringTrimLeft, RS232_Settings, RS232_Settings, RS232_Temp1_Len+1 ;Remove the COM number (+1 for the semicolon) for BuildCommDCB.
;MsgBox, RS232_COM=%RS232_COM% `nRS232_Settings=%RS232_Settings%
;###### Build RS232 COM DCB ######
;Creates the structure that contains the RS232 COM Port number, baud rate,...
VarSetCapacity(DCB, 28, 0)
BCD_Result := DllCall("BuildCommDCB"
,"str" , RS232_Settings ;lpDef
,Ptr, &DCB) ;lpDCB
; If (!BCD_Result)
; {
; MsgBox, There is a problem with Serial Port communication. `nFailed Dll BuildCommDCB, BCD_Result=%BCD_Result% `nThe Script Will Now COMFail.`n %DCB%
; COMFail=1
; return
; }
;###### Create RS232 COM File ######
;Creates the RS232 COM Port File Handle
RS232_FileHandle := DllCall("CreateFile"
,"Str" , RS232_COM ;File Name
,"UInt", 0xC0000000 ;Desired Access
,"UInt", 3 ;Safe Mode
,"UInt", 0 ;Security Attributes
,"UInt", 3 ;Creation Disposition
,"UInt", 0 ;Flags And Attributes
,Ptr, 0 ;Template File
,Ptr)
If (!RS232_FileHandle)
{
;; MsgBox, There is a problem with Serial Port communication. `nFailed Dll CreateFile, RS232_FileHandle=%RS232_FileHandle% `nThe Script Will Now COMFail.
COMFail=1
return
}
;###### Set COM State ######
;Sets the RS232 COM Port number, baud rate,...
SCS_Result := DllCall("SetCommState"
,Ptr, RS232_FileHandle ;File Handle
,Ptr, &DCB) ;Pointer to DCB structure
If (!SCS_Result)
{
;; MsgBox, There is a problem with Serial Port communication. `nFailed Dll SetCommState, SCS_Result=%SCS_Result% `nThe Script Will Now COMFail.
RS232_Close(RS232_FileHandle)
COMFail=1
return
}
Timeout:=Floor(((RS232_Data+4)/RS232_Baud)*1000)
if (Timeout=0)
Timeout:=1
;###### Create the SetCommTimeouts Structure ######
if (ReadIntervalTimeout=0)
ReadIntervalTimeout:=1
if (ReadIntervalTimeout="")
ReadIntervalTimeout := Timeout ; ms, max Interval betwen characters
ReadTotalTimeoutMultiplier := 0 ; ms * reqested number of bytes
ReadTotalTimeoutConstant := ReadIntervalTimeout ; ms
WriteTotalTimeoutMultiplier:= 0 ; ms * sended number of bytes
WriteTotalTimeoutConstant := 0 ; ms
;tooltip,% RS232_Baud "`n" ReadIntervalTimeout "`n" (((RS232_Data+4)/RS232_Baud)*1000) "`n" ReadTotalTimeoutConstant,0,500,5
if (ReadTotalTimeoutConstant>500)
ReadTotalTimeoutConstant:=500
VarSetCapacity(Data, 20, 0) ; 5 * sizeof(DWORD)
NumPut(ReadIntervalTimeout, Data, 0, "UInt")
NumPut(ReadTotalTimeoutMultiplier, Data, 4, "UInt")
NumPut(ReadTotalTimeoutConstant, Data, 8, "UInt")
NumPut(WriteTotalTimeoutMultiplier, Data, 12, "UInt")
NumPut(WriteTotalTimeoutConstant, Data, 16, "UInt")
;###### Set the RS232 COM Timeouts ######
SCT_result := DllCall("SetCommTimeouts"
,Ptr, RS232_FileHandle ;File Handle
,Ptr, &Data) ;Pointer to the data structure
If !SCT_result
{
;; MsgBox, There is a problem with Serial Port communication. `nFailed Dll SetCommState, SCT_result=%SCT_result% `nThe Script Will Now COMFail.
RS232_Close(RS232_FileHandle)
COMFail=1
return
}
Return RS232_FileHandle
}
RS232_Close(ByRef RS232_FileHandle)
{
DllCall("CloseHandle",Ptr,RS232_FileHandle)
RS232_FileHandle:=""
return
}
RS232_Write(RS232_FileHandle,Data,Data_Length)
{
if RS232_FileHandle
WF_Result := DllCall("WriteFile"
,Ptr , RS232_FileHandle ;File Handle
,Ptr , Data ;Pointer to string to send
,"UInt", Data_Length ;Data Length
,A_PtrSize ? "UPtr*" : "uint*", Bytes_Sent ;Returns pointer to num bytes sent
,"Int" , "NULL")
; RS232_WaitCommEvent(RS232_FileHandle,0x4)
}
RS232_Read(RS232_FileHandle,Data_Length,Pointer,ByRef RS232_Bytes_Received)
{
if RS232_FileHandle
Read_Result := DllCall("ReadFile"
,Ptr , RS232_FileHandle ; hFile
,Ptr , Pointer ; lpBuffer
,"Int" , Data_Length ; nNumberOfBytesToRead
,A_PtrSize ? "UPtr*" : "uint*", RS232_Bytes_Received ; lpNumberOfBytesReceived
,"Int" , 0) ; lpOverlapped
If (!Read_Result)
{
RS232_Close(RS232_FileHandle)
COMFail=1
return
}
}
RS232_WaitCommEvent(RS232_FileHandle,Event=0x3ff)
{
/*
Events:
EV_BREAK:=0x0040 ;A break was detected on input.
EV_CTS:=0x0008 ;The CTS (clear-to-send) signal changed state.
EV_DSR:=0x0010 ;The DSR (data-set-ready) signal changed state.
EV_ERR:=0x0080 ;A line-status error occurred. Line-status errors are CE_FRAME, CE_OVERRUN, and CE_RXPARITY.
EV_RING:=0x0100 ;A ring indicator was detected.
EV_RLSD:=0x0020 ;The RLSD (receive-line-signal-detect) signal changed state.
EV_RXCHAR:=0x0001 ;A character was received and placed in the input buffer.
EV_RXFLAG:=0x0002 ;The event character was received and placed in the input buffer. The event character is specified in the device's DCB structure, which is applied to a serial port by using the SetCommState function.
EV_TXEMPTY:=0x0004 ;The last character in the output buffer was sent.
*/
MaskSet := DllCall("SetCommMask"
,Ptr , RS232_FileHandle ;File Handle
,"int" , Event) ;Mask
if !MaskSet
{
RS232_Close(RS232_FileHandle)
COMFail=1
return
}
VarSetCapacity(Data,4,0)
if RS232_FileHandle
Success := DllCall("WaitCommEvent"
,Ptr, RS232_FileHandle ;File Handle
,Ptr, &Data ;Pointer to Event
,Ptr, 0)
if !Success
{
RS232_Close(RS232_FileHandle)
COMFail=1
return
}
; tooltip,% Errorlevel "`n" a_lasterror "`n" Success "`nEvent = " format("0x{:04x}",numget(Data,0,"Int64"))
}
RS232_ClearRXBuffer(RS232_FileHandle)
{
Success := DllCall("PurgeComm"
,Ptr, RS232_FileHandle ;File Handle
,"Int", 0x8)
return Success
}
LV_SubitemHitTest(HLV) {
; To run this with AHK_Basic change all DllCall types Ptr to "UInt", please.
; HLV - ListView's HWND
LVM_SUBITEMHITTEST := 0x1039
VarSetCapacity(POINT, 8, 0)
; Get the current cursor position in screen coordinates
DllCall("User32.dll\GetCursorPos", Ptr, &POINT)
; Convert them to client coordinates related to the ListView
DllCall("User32.dll\ScreenToClient", Ptr, HLV, Ptr, &POINT)
; Create a LVHITTESTINFO structure (see below)
VarSetCapacity(LVHITTESTINFO, 24, 0)
; Store the relative mouse coordinates
NumPut(NumGet(POINT, 0, "Int"), LVHITTESTINFO, 0, "Int")
NumPut(NumGet(POINT, 4, "Int"), LVHITTESTINFO, 4, "Int")
; Send a LVM_SUBITEMHITTEST to the ListView
SendMessage, LVM_SUBITEMHITTEST, 0, &LVHITTESTINFO, , ahk_id %HLV%
; If no item was found on this position, the return value is -1
If (ErrorLevel = -1)
Return 0
; Get the corresponding subitem (column)
Subitem := NumGet(LVHITTESTINFO, 16, "Int") + 1
Return Subitem
}
SetParent(hwnd,hNewParent,ClassNN="",x=0,y=0)
{
if ClassNN
ControlGet,hNewParent,Hwnd,,%ClassNN%,ahk_id %hNewParent%
oldParent:=DllCall("SetParent",Ptr,hwnd,Ptr,hNewParent)
WinMove,ahk_id %hwnd%,,%x%,%y%
return oldParent
}
StrCut(byref string,sym)
{
if Pos:=instr(string,sym)
{
stringleft,var,string,Pos-1
stringtrimleft,string,string,Pos
return var
}
}
findMetaSbl(intext,byref Splitter,byref Ending)
{
a:={}
loop,parse,intext
{
if !(a_loopfield+1 or a_loopfield="-" or a_loopfield=".")
{
SmblExist:=0
for i,n in a
{
if (i=a_loopfield)
{
SmblExist:=1
a[i]++
break
}
}
if !SmblExist
a[a_loopfield]:=1
}
}
countS:=0
countE:=32000
for i,n in a
{
if (n>countS)
{
Splitter:=i
countS:=n
}
if (n<countE)
{
Ending:=i
countE:=n
}
}
}
CheckMetaSym(sym)
{
static Meta:="\`n.*?+[{|()^$"
if instr(Meta,sym)
loop,parse,Meta
{
if (a_loopfield="`n" and instr(sym,a_loopfield))
sym:="\n"
else
stringreplace,sym,sym,%a_loopfield%,\%a_loopfield%,all
}
return sym
}
AddAdd(byref var)
{
if (var>=0)
var:="+"var
}
SwapData(var_in,StartByte,NumBytes,byref var_out)
{
varsetcapacity(var_out,NumBytes)
loop,% NumBytes
numput(numget(var_in,StartByte+a_index-1,"uchar"),var_out,NumBytes-a_index,"uchar")
}
CopyData(var_in,StartByte,NumBytes,var_out,out_StartByte)
{
loop,% NumBytes
numput(numget(var_in,StartByte+a_index-1,"uchar"),var_out,out_StartByte+a_index-1,"uchar")
}
ArrGetMax(arr,start=0,weight=1)
{
start:=round(start)
weight:=round(weight)
loop,% weight
{
if (var<abs(arr[a_index+start]))
var:=abs(arr[a_index+start])
}
return var
}
ObjClear(byref obj)
{
obj:=""
obj:={}
}
MoveControl(hwnd,x=0,y=0,w=0,h=0,min=10)
{
overf:=0
GuiControlGet,E_pos,Pos,% hwnd
if (E_posw+w<min)
{
overf|=1
if (x!=0xffff)
x:=w
w:=0
}
if (E_posh+h<min)
{
overf|=2
if (y!=0xffff)
y:=h
h:=0
}
xx:= x=0xffff ? E_posx:E_posx+x
yy:= y=0xffff ? E_posy:E_posy+y
ww:= w=0xffff ? E_posw:E_posw+w
hh:= h=0xffff ? E_posh:E_posh+h
GuiControl,Move,% hwnd,% " x" xx " y" yy " w" ww " h" hh
return overf
}
DECtoBIN(h)
{
stringreplace,h,h,%a_space%,,all
h:=h+0
a:=0
while(h)
{
if (a_index>1 and !a)
r:=" " . r
a++
r:= (h&1) . r
h>>=1
if (a=8)
a:=0
}
if (a!=0)
while(a!=8)
{
r:= 0 . r
a++
}
return r
}
BINtoDEC(b)
{
stringreplace,b,b,%a_space%,,all
r:=0
loop,parse,b
r|=(a_loopfield<<(strlen(b)-a_index))
Ceil(strlen(b)/8)
return r
}
BINtoHEX(b)
{
stringreplace,b,b,%a_space%,,all
r:=0
loop,% strlen(b)
bb.=SubStr(b,strlen(b)-(a_index-1),1)
loop,parse,bb
{
r|=(a_loopfield<<(Mod(a_index-1,8)))
if (a_index!=0 and !Mod(a_index,8))
{
o:=format("{:02X}",r) . o
r:=0
}
d:=a_index
}
if Mod(d,8)
o:=format("{:02X}",r) . o
return o
}
DATAtoSTR(var,st,size,sw=0)
{
loop,% size
str.=chr(numget(var+0,(sw?(size-a_index):(st+a_index-1)),"uchar"))
return str
}
uDATAtoSTR(var,st,size,sw=0)
{
loop,% size
str.=chr(numget(var+0,(sw?(size-a_index*2):(st+(a_index-1)*2)),"ushort"))
return str
}
DATAtoHEX(var,st,size,sw=0,sp=0)
{
loop,% size
hex.=format("{:02X}",numget(var+0,(sw?(size-a_index):(st+a_index-1)),"uchar")) . ((sp and a_index!=size)?" ":"")
return hex
}
DATAtoBIN(var,st,size,sw=0)
{
static bin
bin:=""
loop,% size
{
h:=numget(var+0,(sw?(size-a_index):(st+a_index-1)),"uchar")
r:=(a_index=size)?"":" "
loop,8
{
r:=(h&1) . r
h>>=1
}
bin.= r
}
return bin
}
STRToDATA(str,byref var,swap=0)
{
size:=strlen(str)
varsetcapacity(var,size+2)
loop,parse,str
{
if !swap
NumPut(asc(a_loopfield),var,a_index-1,"Uchar")
else
NumPut(asc(a_loopfield),var,size-a_index,"Uchar")
}
return size
}
uSTRToDATA(str,byref var,swap=0)
{
size:=strlen(str)
varsetcapacity(var,size*2+2)
loop,parse,str
{
if !swap
NumPut(asc(a_loopfield),var,(a_index-1)*2,"ushort")
else
NumPut(asc(a_loopfield),var,size-a_index*2,"ushort")
}
return size
}
DECToDATA(str,byref var,swap=0,dtype="Uint64",size=8)
{
varsetcapacity(var,size+2)
NumPut(str+0,var,0,dtype)
if swap
{
varsetcapacity(tmpvar,size)
loop,% size
numput(numget(var,a_index-1,"uchar"),tmpvar,size-a_index,"uchar")
loop,% size
numput(numget(tmpvar,a_index-1,"uchar"),var,a_index-1,"uchar")
}
return size
}
HEXstrToDATA(str,byref var,swap=0)
{
stringreplace,str,str,%a_space%,,all
size:=ceil(strlen(str)/2)
varsetcapacity(var,size+2)
loop,% size
{
stringright,tmp2,str,2
if !swap
NumPut("0x"tmp2,var,size-a_index,"Uchar")
else
NumPut("0x"tmp2,var,a_index-1,"Uchar")
StringTrimRight,str,str,2
}
return size
}
BINstrToDATA(str,byref var,swap=0)
{
stringreplace,str,str,%a_space%,,all
size:=ceil(strlen(str)/8)
varsetcapacity(var,size+2)
loop,% size
{
stringright,tmp2,str,8
if !swap
NumPut(BINtoDEC(tmp2),var,size-a_index,"Uchar")
else
NumPut(BINtoDEC(tmp2),var,a_index-1,"Uchar")
StringTrimRight,str,str,8
}
return size
}
ClearVar(byref var,symbol=" ")
{
stringreplace,var,var,%symbol%,,all
}
_______________________________:
return
; Gdip standard library v1.45 by tic (Tariq Porter) 07/09/11
; Modifed by Rseding91 using fincs 64 bit compatible Gdip library 5/1/2013
; Supports: Basic, _L ANSi, _L Unicode x86 and _L Unicode x64
;
; Updated 2/20/2014 - fixed Gdip_CreateRegion() and Gdip_GetClipRegion() on AHK Unicode x86
; Updated 5/13/2013 - fixed Gdip_SetBitmapToClipboard() on AHK Unicode x64
;
;#####################################################################################
;#####################################################################################
; STATUS ENUMERATION
; Return values for functions specified to have status enumerated return type
;#####################################################################################
;
; Ok = = 0
; GenericError = 1
; InvalidParameter = 2
; OutOfMemory = 3
; ObjectBusy = 4
; InsufficientBuffer = 5
; NotImplemented = 6
; Win32Error = 7
; WrongState = 8
; Aborted = 9
; FileNotFound = 10
; ValueOverflow = 11
; AccessDenied = 12
; UnknownImageFormat = 13
; FontFamilyNotFound = 14
; FontStyleNotFound = 15
; NotTrueTypeFont = 16
; UnsupportedGdiplusVersion = 17
; GdiplusNotInitialized = 18
; PropertyNotFound = 19
; PropertyNotSupported = 20
; ProfileNotFound = 21
;
;#####################################################################################
;#####################################################################################
; FUNCTIONS
;#####################################################################################
;
; UpdateLayeredWindow(hwnd, hdc, x="", y="", w="", h="", Alpha=255)
; BitBlt(ddc, dx, dy, dw, dh, sdc, sx, sy, Raster="")
; StretchBlt(dDC, dx, dy, dw, dh, sDC, sx, sy, sw, sh, Raster="")
; SetImage(hwnd, hBitmap)
; Gdip_BitmapFromScreen(Screen=0, Raster="")
; CreateRectF(ByRef RectF, x, y, w, h)
; CreateSizeF(ByRef SizeF, w, h)
; CreateDIBSection
;
;#####################################################################################
; Function: UpdateLayeredWindow
; Description: Updates a layered window with the handle to the DC of a gdi bitmap
;
; hwnd Handle of the layered window to update
; hdc Handle to the DC of the GDI bitmap to update the window with
; Layeredx x position to place the window
; Layeredy y position to place the window
; Layeredw Width of the window
; Layeredh Height of the window
; Alpha Default = 255 : The transparency (0-255) to set the window transparency
;
; return If the function succeeds, the return value is nonzero
;
; notes If x or y omitted, then layered window will use its current coordinates
; If w or h omitted then current width and height will be used
UpdateLayeredWindow(hwnd, hdc, x="", y="", w="", h="", Alpha=255)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
if ((x != "") && (y != ""))
VarSetCapacity(pt, 8), NumPut(x, pt, 0, "UInt"), NumPut(y, pt, 4, "UInt")
if (w = "") ||(h = "")
WinGetPos,,, w, h, ahk_id %hwnd%
return DllCall("UpdateLayeredWindow"
, Ptr, hwnd
, Ptr, 0
, Ptr, ((x = "") && (y = "")) ? 0 : &pt
, "int64*", w|h<<32
, Ptr, hdc
, "int64*", 0
, "uint", 0
, "UInt*", Alpha<<16|1<<24
, "uint", 2)
}
;#####################################################################################
; Function BitBlt
; Description The BitBlt function performs a bit-block transfer of the color data corresponding to a rectangle
; of pixels from the specified source device context into a destination device context.
;
; dDC handle to destination DC
; dx x-coord of destination upper-left corner
; dy y-coord of destination upper-left corner
; dw width of the area to copy
; dh height of the area to copy
; sDC handle to source DC
; sx x-coordinate of source upper-left corner
; sy y-coordinate of source upper-left corner
; Raster raster operation code
;
; return If the function succeeds, the return value is nonzero
;
; notes If no raster operation is specified, then SRCCOPY is used, which copies the source directly to the destination rectangle
;
; BLACKNESS = 0x00000042
; NOTSRCERASE = 0x001100A6
; NOTSRCCOPY = 0x00330008
; SRCERASE = 0x00440328
; DSTINVERT = 0x00550009
; PATINVERT = 0x005A0049
; SRCINVERT = 0x00660046
; SRCAND = 0x008800C6
; MERGEPAINT = 0x00BB0226
; MERGECOPY = 0x00C000CA
; SRCCOPY = 0x00CC0020
; SRCPAINT = 0x00EE0086
; PATCOPY = 0x00F00021
; PATPAINT = 0x00FB0A09
; WHITENESS = 0x00FF0062
; CAPTUREBLT = 0x40000000
; NOMIRRORBITMAP = 0x80000000
BitBlt(ddc, dx, dy, dw, dh, sdc, sx, sy, Raster="")
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
return DllCall("gdi32\BitBlt"
, Ptr, dDC
, "int", dx
, "int", dy
, "int", dw
, "int", dh
, Ptr, sDC
, "int", sx
, "int", sy
, "uint", Raster ? Raster : 0x00CC0020)
}
;#####################################################################################
; Function StretchBlt
; Description The StretchBlt function copies a bitmap from a source rectangle into a destination rectangle,
; stretching or compressing the bitmap to fit the dimensions of the destination rectangle, if necessary.
; The system stretches or compresses the bitmap according to the stretching mode currently set in the destination device context.
;
; ddc handle to destination DC
; dx x-coord of destination upper-left corner
; dy y-coord of destination upper-left corner
; dw width of destination rectangle
; dh height of destination rectangle
; sdc handle to source DC
; sx x-coordinate of source upper-left corner
; sy y-coordinate of source upper-left corner
; sw width of source rectangle
; sh height of source rectangle
; Raster raster operation code
;
; return If the function succeeds, the return value is nonzero
;
; notes If no raster operation is specified, then SRCCOPY is used. It uses the same raster operations as BitBlt
StretchBlt(ddc, dx, dy, dw, dh, sdc, sx, sy, sw, sh, Raster="")
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
return DllCall("gdi32\StretchBlt"
, Ptr, ddc
, "int", dx
, "int", dy
, "int", dw
, "int", dh
, Ptr, sdc
, "int", sx
, "int", sy
, "int", sw
, "int", sh
, "uint", Raster ? Raster : 0x00CC0020)
}
;#####################################################################################
; Function SetStretchBltMode
; Description The SetStretchBltMode function sets the bitmap stretching mode in the specified device context
;
; hdc handle to the DC
; iStretchMode The stretching mode, describing how the target will be stretched
;
; return If the function succeeds, the return value is the previous stretching mode. If it fails it will return 0
;
; STRETCH_ANDSCANS = 0x01
; STRETCH_ORSCANS = 0x02
; STRETCH_DELETESCANS = 0x03
; STRETCH_HALFTONE = 0x04
SetStretchBltMode(hdc, iStretchMode=4)
{
return DllCall("gdi32\SetStretchBltMode"
, A_PtrSize ? "UPtr" : "UInt", hdc
, "int", iStretchMode)
}
;#####################################################################################
; Function SetImage
; Description Associates a new image with a static control
;
; hwnd handle of the control to update
; hBitmap a gdi bitmap to associate the static control with
;
; return If the function succeeds, the return value is nonzero
SetImage(hwnd, hBitmap)
{
SendMessage, 0x172, 0x0, hBitmap,, ahk_id %hwnd%
E := ErrorLevel
DeleteObject(E)
return E
}
;#####################################################################################
; Function SetSysColorToControl
; Description Sets a solid colour to a control
;
; hwnd handle of the control to update
; SysColor A system colour to set to the control
;
; return If the function succeeds, the return value is zero
;
; notes A control must have the 0xE style set to it so it is recognised as a bitmap
; By default SysColor=15 is used which is COLOR_3DFACE. This is the standard background for a control
;
; COLOR_3DDKSHADOW = 21
; COLOR_3DFACE = 15
; COLOR_3DHIGHLIGHT = 20
; COLOR_3DHILIGHT = 20
; COLOR_3DLIGHT = 22
; COLOR_3DSHADOW = 16
; COLOR_ACTIVEBORDER = 10
; COLOR_ACTIVECAPTION = 2
; COLOR_APPWORKSPACE = 12
; COLOR_BACKGROUND = 1
; COLOR_BTNFACE = 15
; COLOR_BTNHIGHLIGHT = 20
; COLOR_BTNHILIGHT = 20
; COLOR_BTNSHADOW = 16
; COLOR_BTNTEXT = 18
; COLOR_CAPTIONTEXT = 9
; COLOR_DESKTOP = 1
; COLOR_GRADIENTACTIVECAPTION = 27
; COLOR_GRADIENTINACTIVECAPTION = 28
; COLOR_GRAYTEXT = 17
; COLOR_HIGHLIGHT = 13
; COLOR_HIGHLIGHTTEXT = 14
; COLOR_HOTLIGHT = 26
; COLOR_INACTIVEBORDER = 11
; COLOR_INACTIVECAPTION = 3
; COLOR_INACTIVECAPTIONTEXT = 19
; COLOR_INFOBK = 24
; COLOR_INFOTEXT = 23
; COLOR_MENU = 4
; COLOR_MENUHILIGHT = 29
; COLOR_MENUBAR = 30
; COLOR_MENUTEXT = 7
; COLOR_SCROLLBAR = 0
; COLOR_WINDOW = 5
; COLOR_WINDOWFRAME = 6
; COLOR_WINDOWTEXT = 8
SetSysColorToControl(hwnd, SysColor=15)
{
WinGetPos,,, w, h, ahk_id %hwnd%
bc := DllCall("GetSysColor", "Int", SysColor, "UInt")
pBrushClear := Gdip_BrushCreateSolid(0xff000000 | (bc >> 16 | bc & 0xff00 | (bc & 0xff) << 16))
pBitmap := Gdip_CreateBitmap(w, h), G := Gdip_GraphicsFromImage(pBitmap)
Gdip_FillRectangle(G, pBrushClear, 0, 0, w, h)
hBitmap := Gdip_CreateHBITMAPFromBitmap(pBitmap)
SetImage(hwnd, hBitmap)
Gdip_DeleteBrush(pBrushClear)
Gdip_DeleteGraphics(G), Gdip_DisposeImage(pBitmap), DeleteObject(hBitmap)
return 0
}
;#####################################################################################
; Function Gdip_BitmapFromScreen
; Description Gets a gdi+ bitmap from the screen
;
; Screen 0 = All screens
; Any numerical value = Just that screen
; x|y|w|h = Take specific coordinates with a width and height
; Raster raster operation code
;
; return If the function succeeds, the return value is a pointer to a gdi+ bitmap
; -1: one or more of x,y,w,h not passed properly
;
; notes If no raster operation is specified, then SRCCOPY is used to the returned bitmap
Gdip_BitmapFromScreen(Screen=0, Raster="")
{
if (Screen = 0)
{
Sysget, x, 76
Sysget, y, 77
Sysget, w, 78
Sysget, h, 79
}
else if (SubStr(Screen, 1, 5) = "hwnd:")
{
Screen := SubStr(Screen, 6)
if !WinExist( "ahk_id " Screen)
return -2
WinGetPos,,, w, h, ahk_id %Screen%
x := y := 0
hhdc := GetDCEx(Screen, 3)
}
else if (Screen&1 != "")
{
Sysget, M, Monitor, %Screen%
x := MLeft, y := MTop, w := MRight-MLeft, h := MBottom-MTop
}
else
{
StringSplit, S, Screen, |
x := S1, y := S2, w := S3, h := S4
}
if (x = "") || (y = "") || (w = "") || (h = "")
return -1
chdc := CreateCompatibleDC(), hbm := CreateDIBSection(w, h, chdc), obm := SelectObject(chdc, hbm), hhdc := hhdc ? hhdc : GetDC()
BitBlt(chdc, 0, 0, w, h, hhdc, x, y, Raster)
ReleaseDC(hhdc)
pBitmap := Gdip_CreateBitmapFromHBITMAP(hbm)
SelectObject(chdc, obm), DeleteObject(hbm), DeleteDC(hhdc), DeleteDC(chdc)
return pBitmap
}
;#####################################################################################
; Function Gdip_BitmapFromHWND
; Description Uses PrintWindow to get a handle to the specified window and return a bitmap from it
;
; hwnd handle to the window to get a bitmap from
;
; return If the function succeeds, the return value is a pointer to a gdi+ bitmap
;
; notes Window must not be not minimised in order to get a handle to it's client area
Gdip_BitmapFromHWND(hwnd)
{
WinGetPos,,, Width, Height, ahk_id %hwnd%
hbm := CreateDIBSection(Width, Height), hdc := CreateCompatibleDC(), obm := SelectObject(hdc, hbm)
PrintWindow(hwnd, hdc)
pBitmap := Gdip_CreateBitmapFromHBITMAP(hbm)
SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc)
return pBitmap
}
;#####################################################################################
; Function CreateRectF
; Description Creates a RectF object, containing a the coordinates and dimensions of a rectangle
;
; RectF Name to call the RectF object
; x x-coordinate of the upper left corner of the rectangle
; y y-coordinate of the upper left corner of the rectangle
; w Width of the rectangle
; h Height of the rectangle
;
; return No return value
CreateRectF(ByRef RectF, x, y, w, h)
{
VarSetCapacity(RectF, 16)
NumPut(x, RectF, 0, "float"), NumPut(y, RectF, 4, "float"), NumPut(w, RectF, 8, "float"), NumPut(h, RectF, 12, "float")
}
;#####################################################################################
; Function CreateRect
; Description Creates a Rect object, containing a the coordinates and dimensions of a rectangle
;
; RectF Name to call the RectF object
; x x-coordinate of the upper left corner of the rectangle
; y y-coordinate of the upper left corner of the rectangle
; w Width of the rectangle
; h Height of the rectangle
;
; return No return value
CreateRect(ByRef Rect, x, y, w, h)
{
VarSetCapacity(Rect, 16)
NumPut(x, Rect, 0, "uint"), NumPut(y, Rect, 4, "uint"), NumPut(w, Rect, 8, "uint"), NumPut(h, Rect, 12, "uint")
}
;#####################################################################################
; Function CreateSizeF
; Description Creates a SizeF object, containing an 2 values
;
; SizeF Name to call the SizeF object
; w w-value for the SizeF object
; h h-value for the SizeF object
;
; return No Return value
CreateSizeF(ByRef SizeF, w, h)
{
VarSetCapacity(SizeF, 8)
NumPut(w, SizeF, 0, "float"), NumPut(h, SizeF, 4, "float")
}
;#####################################################################################
; Function CreatePointF
; Description Creates a SizeF object, containing an 2 values
;
; SizeF Name to call the SizeF object
; w w-value for the SizeF object
; h h-value for the SizeF object
;
; return No Return value
CreatePointF(ByRef PointF, x, y)
{
VarSetCapacity(PointF, 8)
NumPut(x, PointF, 0, "float"), NumPut(y, PointF, 4, "float")
}
;#####################################################################################
; Function CreateDIBSection
; Description The CreateDIBSection function creates a DIB (Device Independent Bitmap) that applications can write to directly
;
; w width of the bitmap to create
; h height of the bitmap to create
; hdc a handle to the device context to use the palette from
; bpp bits per pixel (32 = ARGB)
; ppvBits A pointer to a variable that receives a pointer to the location of the DIB bit values
;
; return returns a DIB. A gdi bitmap
;
; notes ppvBits will receive the location of the pixels in the DIB
CreateDIBSection(w, h, hdc="", bpp=32, ByRef ppvBits=0)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
hdc2 := hdc ? hdc : GetDC()
VarSetCapacity(bi, 40, 0)
NumPut(w, bi, 4, "uint")
, NumPut(h, bi, 8, "uint")
, NumPut(40, bi, 0, "uint")
, NumPut(1, bi, 12, "ushort")
, NumPut(0, bi, 16, "uInt")
, NumPut(bpp, bi, 14, "ushort")
hbm := DllCall("CreateDIBSection"
, Ptr, hdc2
, Ptr, &bi
, "uint", 0
, A_PtrSize ? "UPtr*" : "uint*", ppvBits
, Ptr, 0
, "uint", 0, Ptr)
if !hdc
ReleaseDC(hdc2)
return hbm
}
;#####################################################################################
; Function PrintWindow
; Description The PrintWindow function copies a visual window into the specified device context (DC), typically a printer DC
;
; hwnd A handle to the window that will be copied
; hdc A handle to the device context
; Flags Drawing options
;
; return If the function succeeds, it returns a nonzero value
;
; PW_CLIENTONLY = 1
PrintWindow(hwnd, hdc, Flags=0)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
return DllCall("PrintWindow", Ptr, hwnd, Ptr, hdc, "uint", Flags)
}
;#####################################################################################
; Function DestroyIcon
; Description Destroys an icon and frees any memory the icon occupied
;
; hIcon Handle to the icon to be destroyed. The icon must not be in use
;
; return If the function succeeds, the return value is nonzero
DestroyIcon(hIcon)
{
return DllCall("DestroyIcon", A_PtrSize ? "UPtr" : "UInt", hIcon)
}
;#####################################################################################
PaintDesktop(hdc)
{
return DllCall("PaintDesktop", A_PtrSize ? "UPtr" : "UInt", hdc)
}
;#####################################################################################
CreateCompatibleBitmap(hdc, w, h)
{
return DllCall("gdi32\CreateCompatibleBitmap", A_PtrSize ? "UPtr" : "UInt", hdc, "int", w, "int", h)
}
;#####################################################################################
; Function CreateCompatibleDC
; Description This function creates a memory device context (DC) compatible with the specified device
;
; hdc Handle to an existing device context
;
; return returns the handle to a device context or 0 on failure
;
; notes If this handle is 0 (by default), the function creates a memory device context compatible with the application's current screen
CreateCompatibleDC(hdc=0)
{
return DllCall("CreateCompatibleDC", A_PtrSize ? "UPtr" : "UInt", hdc)
}
;#####################################################################################
; Function SelectObject
; Description The SelectObject function selects an object into the specified device context (DC). The new object replaces the previous object of the same type
;
; hdc Handle to a DC
; hgdiobj A handle to the object to be selected into the DC
;
; return If the selected object is not a region and the function succeeds, the return value is a handle to the object being replaced
;
; notes The specified object must have been created by using one of the following functions
; Bitmap - CreateBitmap, CreateBitmapIndirect, CreateCompatibleBitmap, CreateDIBitmap, CreateDIBSection (A single bitmap cannot be selected into more than one DC at the same time)
; Brush - CreateBrushIndirect, CreateDIBPatternBrush, CreateDIBPatternBrushPt, CreateHatchBrush, CreatePatternBrush, CreateSolidBrush
; Font - CreateFont, CreateFontIndirect
; Pen - CreatePen, CreatePenIndirect
; Region - CombineRgn, CreateEllipticRgn, CreateEllipticRgnIndirect, CreatePolygonRgn, CreateRectRgn, CreateRectRgnIndirect
;
; notes If the selected object is a region and the function succeeds, the return value is one of the following value
;
; SIMPLEREGION = 2 Region consists of a single rectangle
; COMPLEXREGION = 3 Region consists of more than one rectangle
; NULLREGION = 1 Region is empty
SelectObject(hdc, hgdiobj)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
return DllCall("SelectObject", Ptr, hdc, Ptr, hgdiobj)
}
;#####################################################################################
; Function DeleteObject
; Description This function deletes a logical pen, brush, font, bitmap, region, or palette, freeing all system resources associated with the object
; After the object is deleted, the specified handle is no longer valid
;
; hObject Handle to a logical pen, brush, font, bitmap, region, or palette to delete
;
; return Nonzero indicates success. Zero indicates that the specified handle is not valid or that the handle is currently selected into a device context
DeleteObject(hObject)
{
return DllCall("DeleteObject", A_PtrSize ? "UPtr" : "UInt", hObject)
}
;#####################################################################################
; Function GetDC
; Description This function retrieves a handle to a display device context (DC) for the client area of the specified window.
; The display device context can be used in subsequent graphics display interface (GDI) functions to draw in the client area of the window.
;
; hwnd Handle to the window whose device context is to be retrieved. If this value is NULL, GetDC retrieves the device context for the entire screen
;
; return The handle the device context for the specified window's client area indicates success. NULL indicates failure
GetDC(hwnd=0)
{
return DllCall("GetDC", A_PtrSize ? "UPtr" : "UInt", hwnd)
}
;#####################################################################################
; DCX_CACHE = 0x2
; DCX_CLIPCHILDREN = 0x8
; DCX_CLIPSIBLINGS = 0x10
; DCX_EXCLUDERGN = 0x40
; DCX_EXCLUDEUPDATE = 0x100
; DCX_INTERSECTRGN = 0x80
; DCX_INTERSECTUPDATE = 0x200
; DCX_LOCKWINDOWUPDATE = 0x400
; DCX_NORECOMPUTE = 0x100000
; DCX_NORESETATTRS = 0x4
; DCX_PARENTCLIP = 0x20
; DCX_VALIDATE = 0x200000
; DCX_WINDOW = 0x1
GetDCEx(hwnd, flags=0, hrgnClip=0)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
return DllCall("GetDCEx", Ptr, hwnd, Ptr, hrgnClip, "int", flags)
}
;#####################################################################################
; Function ReleaseDC
; Description This function releases a device context (DC), freeing it for use by other applications. The effect of ReleaseDC depends on the type of device context
;
; hdc Handle to the device context to be released
; hwnd Handle to the window whose device context is to be released
;
; return 1 = released
; 0 = not released
;
; notes The application must call the ReleaseDC function for each call to the GetWindowDC function and for each call to the GetDC function that retrieves a common device context
; An application cannot use the ReleaseDC function to release a device context that was created by calling the CreateDC function; instead, it must use the DeleteDC function.
ReleaseDC(hdc, hwnd=0)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
return DllCall("ReleaseDC", Ptr, hwnd, Ptr, hdc)
}
;#####################################################################################
; Function DeleteDC
; Description The DeleteDC function deletes the specified device context (DC)
;
; hdc A handle to the device context
;
; return If the function succeeds, the return value is nonzero
;
; notes An application must not delete a DC whose handle was obtained by calling the GetDC function. Instead, it must call the ReleaseDC function to free the DC
DeleteDC(hdc)
{
return DllCall("DeleteDC", A_PtrSize ? "UPtr" : "UInt", hdc)
}
;#####################################################################################
; Function Gdip_LibraryVersion
; Description Get the current library version
;
; return the library version
;
; notes This is useful for non compiled programs to ensure that a person doesn't run an old version when testing your scripts
Gdip_LibraryVersion()
{
return 1.45
}
;#####################################################################################
; Function Gdip_LibrarySubVersion
; Description Get the current library sub version
;
; return the library sub version
;
; notes This is the sub-version currently maintained by Rseding91
Gdip_LibrarySubVersion()
{
return 1.47
}
;#####################################################################################
; Function: Gdip_BitmapFromBRA
; Description: Gets a pointer to a gdi+ bitmap from a BRA file
;
; BRAFromMemIn The variable for a BRA file read to memory
; File The name of the file, or its number that you would like (This depends on alternate parameter)
; Alternate Changes whether the File parameter is the file name or its number
;
; return If the function succeeds, the return value is a pointer to a gdi+ bitmap
; -1 = The BRA variable is empty
; -2 = The BRA has an incorrect header
; -3 = The BRA has information missing
; -4 = Could not find file inside the BRA
Gdip_BitmapFromBRA(ByRef BRAFromMemIn, File, Alternate=0)
{
Static FName = "ObjRelease"
if !BRAFromMemIn
return -1
Loop, Parse, BRAFromMemIn, `n
{
if (A_Index = 1)
{
StringSplit, Header, A_LoopField, |
if (Header0 != 4 || Header2 != "BRA!")
return -2
}
else if (A_Index = 2)
{
StringSplit, Info, A_LoopField, |
if (Info0 != 3)
return -3
}
else
break
}
if !Alternate
StringReplace, File, File, \, \\, All
RegExMatch(BRAFromMemIn, "mi`n)^" (Alternate ? File "\|.+?\|(\d+)\|(\d+)" : "\d+\|" File "\|(\d+)\|(\d+)") "$", FileInfo)
if !FileInfo
return -4
hData := DllCall("GlobalAlloc", "uint", 2, Ptr, FileInfo2, Ptr)
pData := DllCall("GlobalLock", Ptr, hData, Ptr)
DllCall("RtlMoveMemory", Ptr, pData, Ptr, &BRAFromMemIn+Info2+FileInfo1, Ptr, FileInfo2)
DllCall("GlobalUnlock", Ptr, hData)
DllCall("ole32\CreateStreamOnHGlobal", Ptr, hData, "int", 1, A_PtrSize ? "UPtr*" : "UInt*", pStream)
DllCall("gdiplus\GdipCreateBitmapFromStream", Ptr, pStream, A_PtrSize ? "UPtr*" : "UInt*", pBitmap)
If (A_PtrSize)
%FName%(pStream)
Else
DllCall(NumGet(NumGet(1*pStream)+8), "uint", pStream)
return pBitmap
}
;#####################################################################################
; Function Gdip_DrawRectangle
; Description This function uses a pen to draw the outline of a rectangle into the Graphics of a bitmap
;
; pGraphics Pointer to the Graphics of a bitmap
; pPen Pointer to a pen
; x x-coordinate of the top left of the rectangle
; y y-coordinate of the top left of the rectangle
; w width of the rectanlge
; h height of the rectangle
;
; return status enumeration. 0 = success
;
; notes as all coordinates are taken from the top left of each pixel, then the entire width/height should be specified as subtracting the pen width
Gdip_DrawRectangle(pGraphics, pPen, x, y, w, h)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
return DllCall("gdiplus\GdipDrawRectangle", Ptr, pGraphics, Ptr, pPen, "float", x, "float", y, "float", w, "float", h)
}
;#####################################################################################
; Function Gdip_DrawRoundedRectangle
; Description This function uses a pen to draw the outline of a rounded rectangle into the Graphics of a bitmap
;
; pGraphics Pointer to the Graphics of a bitmap
; pPen Pointer to a pen
; x x-coordinate of the top left of the rounded rectangle
; y y-coordinate of the top left of the rounded rectangle
; w width of the rectanlge
; h height of the rectangle
; r radius of the rounded corners
;
; return status enumeration. 0 = success
;
; notes as all coordinates are taken from the top left of each pixel, then the entire width/height should be specified as subtracting the pen width
Gdip_DrawRoundedRectangle(pGraphics, pPen, x, y, w, h, r)
{
Gdip_SetClipRect(pGraphics, x-r, y-r, 2*r, 2*r, 4)
Gdip_SetClipRect(pGraphics, x+w-r, y-r, 2*r, 2*r, 4)
Gdip_SetClipRect(pGraphics, x-r, y+h-r, 2*r, 2*r, 4)
Gdip_SetClipRect(pGraphics, x+w-r, y+h-r, 2*r, 2*r, 4)
E := Gdip_DrawRectangle(pGraphics, pPen, x, y, w, h)
Gdip_ResetClip(pGraphics)
Gdip_SetClipRect(pGraphics, x-(2*r), y+r, w+(4*r), h-(2*r), 4)
Gdip_SetClipRect(pGraphics, x+r, y-(2*r), w-(2*r), h+(4*r), 4)
Gdip_DrawEllipse(pGraphics, pPen, x, y, 2*r, 2*r)
Gdip_DrawEllipse(pGraphics, pPen, x+w-(2*r), y, 2*r, 2*r)
Gdip_DrawEllipse(pGraphics, pPen, x, y+h-(2*r), 2*r, 2*r)
Gdip_DrawEllipse(pGraphics, pPen, x+w-(2*r), y+h-(2*r), 2*r, 2*r)
Gdip_ResetClip(pGraphics)
return E
}
;#####################################################################################
; Function Gdip_DrawEllipse
; Description This function uses a pen to draw the outline of an ellipse into the Graphics of a bitmap
;
; pGraphics Pointer to the Graphics of a bitmap
; pPen Pointer to a pen
; x x-coordinate of the top left of the rectangle the ellipse will be drawn into
; y y-coordinate of the top left of the rectangle the ellipse will be drawn into
; w width of the ellipse
; h height of the ellipse
;
; return status enumeration. 0 = success
;
; notes as all coordinates are taken from the top left of each pixel, then the entire width/height should be specified as subtracting the pen width
Gdip_DrawEllipse(pGraphics, pPen, x, y, w, h)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
return DllCall("gdiplus\GdipDrawEllipse", Ptr, pGraphics, Ptr, pPen, "float", x, "float", y, "float", w, "float", h)
}
;#####################################################################################
; Function Gdip_DrawBezier
; Description This function uses a pen to draw the outline of a bezier (a weighted curve) into the Graphics of a bitmap
;
; pGraphics Pointer to the Graphics of a bitmap
; pPen Pointer to a pen
; x1 x-coordinate of the start of the bezier
; y1 y-coordinate of the start of the bezier
; x2 x-coordinate of the first arc of the bezier
; y2 y-coordinate of the first arc of the bezier
; x3 x-coordinate of the second arc of the bezier
; y3 y-coordinate of the second arc of the bezier
; x4 x-coordinate of the end of the bezier
; y4 y-coordinate of the end of the bezier
;
; return status enumeration. 0 = success
;
; notes as all coordinates are taken from the top left of each pixel, then the entire width/height should be specified as subtracting the pen width
Gdip_DrawBezier(pGraphics, pPen, x1, y1, x2, y2, x3, y3, x4, y4)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
return DllCall("gdiplus\GdipDrawBezier"
, Ptr, pgraphics
, Ptr, pPen
, "float", x1
, "float", y1
, "float", x2
, "float", y2
, "float", x3
, "float", y3
, "float", x4
, "float", y4)
}
;#####################################################################################
; Function Gdip_DrawArc
; Description This function uses a pen to draw the outline of an arc into the Graphics of a bitmap
;
; pGraphics Pointer to the Graphics of a bitmap
; pPen Pointer to a pen
; x x-coordinate of the start of the arc
; y y-coordinate of the start of the arc
; w width of the arc
; h height of the arc
; StartAngle specifies the angle between the x-axis and the starting point of the arc
; SweepAngle specifies the angle between the starting and ending points of the arc
;
; return status enumeration. 0 = success
;
; notes as all coordinates are taken from the top left of each pixel, then the entire width/height should be specified as subtracting the pen width
Gdip_DrawArc(pGraphics, pPen, x, y, w, h, StartAngle, SweepAngle)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
return DllCall("gdiplus\GdipDrawArc"
, Ptr, pGraphics
, Ptr, pPen
, "float", x
, "float", y
, "float", w
, "float", h
, "float", StartAngle
, "float", SweepAngle)
}
;#####################################################################################
; Function Gdip_DrawPie
; Description This function uses a pen to draw the outline of a pie into the Graphics of a bitmap
;
; pGraphics Pointer to the Graphics of a bitmap
; pPen Pointer to a pen
; x x-coordinate of the start of the pie
; y y-coordinate of the start of the pie
; w width of the pie
; h height of the pie
; StartAngle specifies the angle between the x-axis and the starting point of the pie
; SweepAngle specifies the angle between the starting and ending points of the pie
;
; return status enumeration. 0 = success
;
; notes as all coordinates are taken from the top left of each pixel, then the entire width/height should be specified as subtracting the pen width
Gdip_DrawPie(pGraphics, pPen, x, y, w, h, StartAngle, SweepAngle)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
return DllCall("gdiplus\GdipDrawPie", Ptr, pGraphics, Ptr, pPen, "float", x, "float", y, "float", w, "float", h, "float", StartAngle, "float", SweepAngle)
}
;#####################################################################################
; Function Gdip_DrawLine
; Description This function uses a pen to draw a line into the Graphics of a bitmap
;
; pGraphics Pointer to the Graphics of a bitmap
; pPen Pointer to a pen
; x1 x-coordinate of the start of the line
; y1 y-coordinate of the start of the line
; x2 x-coordinate of the end of the line
; y2 y-coordinate of the end of the line
;
; return status enumeration. 0 = success
Gdip_DrawLine(pGraphics, pPen, x1, y1, x2, y2)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
return DllCall("gdiplus\GdipDrawLine"
, Ptr, pGraphics
, Ptr, pPen
, "float", x1
, "float", y1
, "float", x2
, "float", y2)
}
;#####################################################################################
; Function Gdip_DrawLines
; Description This function uses a pen to draw a series of joined lines into the Graphics of a bitmap
;
; pGraphics Pointer to the Graphics of a bitmap
; pPen Pointer to a pen
; Points the coordinates of all the points passed as x1,y1|x2,y2|x3,y3.....
;
; return status enumeration. 0 = success
Gdip_DrawLines(pGraphics, pPen, Points)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
StringSplit, Points, Points, |
VarSetCapacity(PointF, 8*Points0)
Loop, %Points0%
{
StringSplit, Coord, Points%A_Index%, `,
NumPut(Coord1, PointF, 8*(A_Index-1), "float"), NumPut(Coord2, PointF, (8*(A_Index-1))+4, "float")
}
return DllCall("gdiplus\GdipDrawLines", Ptr, pGraphics, Ptr, pPen, Ptr, &PointF, "int", Points0)
}
;#####################################################################################
; Function Gdip_FillRectangle
; Description This function uses a brush to fill a rectangle in the Graphics of a bitmap
;
; pGraphics Pointer to the Graphics of a bitmap
; pBrush Pointer to a brush
; x x-coordinate of the top left of the rectangle
; y y-coordinate of the top left of the rectangle
; w width of the rectanlge
; h height of the rectangle
;
; return status enumeration. 0 = success
Gdip_FillRectangle(pGraphics, pBrush, x, y, w, h)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
return DllCall("gdiplus\GdipFillRectangle"
, Ptr, pGraphics
, Ptr, pBrush
, "float", x
, "float", y
, "float", w
, "float", h)
}
;#####################################################################################
; Function Gdip_FillRoundedRectangle
; Description This function uses a brush to fill a rounded rectangle in the Graphics of a bitmap
;
; pGraphics Pointer to the Graphics of a bitmap
; pBrush Pointer to a brush
; x x-coordinate of the top left of the rounded rectangle
; y y-coordinate of the top left of the rounded rectangle
; w width of the rectanlge
; h height of the rectangle
; r radius of the rounded corners
;
; return status enumeration. 0 = success
Gdip_FillRoundedRectangle(pGraphics, pBrush, x, y, w, h, r)
{
Region := Gdip_GetClipRegion(pGraphics)
Gdip_SetClipRect(pGraphics, x-r, y-r, 2*r, 2*r, 4)
Gdip_SetClipRect(pGraphics, x+w-r, y-r, 2*r, 2*r, 4)
Gdip_SetClipRect(pGraphics, x-r, y+h-r, 2*r, 2*r, 4)
Gdip_SetClipRect(pGraphics, x+w-r, y+h-r, 2*r, 2*r, 4)
E := Gdip_FillRectangle(pGraphics, pBrush, x, y, w, h)
Gdip_SetClipRegion(pGraphics, Region, 0)
Gdip_SetClipRect(pGraphics, x-(2*r), y+r, w+(4*r), h-(2*r), 4)
Gdip_SetClipRect(pGraphics, x+r, y-(2*r), w-(2*r), h+(4*r), 4)
Gdip_FillEllipse(pGraphics, pBrush, x, y, 2*r, 2*r)
Gdip_FillEllipse(pGraphics, pBrush, x+w-(2*r), y, 2*r, 2*r)
Gdip_FillEllipse(pGraphics, pBrush, x, y+h-(2*r), 2*r, 2*r)
Gdip_FillEllipse(pGraphics, pBrush, x+w-(2*r), y+h-(2*r), 2*r, 2*r)
Gdip_SetClipRegion(pGraphics, Region, 0)
Gdip_DeleteRegion(Region)
return E
}
;#####################################################################################
; Function Gdip_FillPolygon
; Description This function uses a brush to fill a polygon in the Graphics of a bitmap
;
; pGraphics Pointer to the Graphics of a bitmap
; pBrush Pointer to a brush
; Points the coordinates of all the points passed as x1,y1|x2,y2|x3,y3.....
;
; return status enumeration. 0 = success
;
; notes Alternate will fill the polygon as a whole, wheras winding will fill each new "segment"
; Alternate = 0
; Winding = 1
Gdip_FillPolygon(pGraphics, pBrush, Points, FillMode=0)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
StringSplit, Points, Points, |
VarSetCapacity(PointF, 8*Points0)
Loop, %Points0%
{
StringSplit, Coord, Points%A_Index%, `,
NumPut(Coord1, PointF, 8*(A_Index-1), "float"), NumPut(Coord2, PointF, (8*(A_Index-1))+4, "float")
}
return DllCall("gdiplus\GdipFillPolygon", Ptr, pGraphics, Ptr, pBrush, Ptr, &PointF, "int", Points0, "int", FillMode)
}
;#####################################################################################
; Function Gdip_FillPie
; Description This function uses a brush to fill a pie in the Graphics of a bitmap
;
; pGraphics Pointer to the Graphics of a bitmap
; pBrush Pointer to a brush
; x x-coordinate of the top left of the pie
; y y-coordinate of the top left of the pie
; w width of the pie
; h height of the pie
; StartAngle specifies the angle between the x-axis and the starting point of the pie
; SweepAngle specifies the angle between the starting and ending points of the pie
;
; return status enumeration. 0 = success
Gdip_FillPie(pGraphics, pBrush, x, y, w, h, StartAngle, SweepAngle)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
return DllCall("gdiplus\GdipFillPie"
, Ptr, pGraphics
, Ptr, pBrush
, "float", x
, "float", y
, "float", w
, "float", h
, "float", StartAngle
, "float", SweepAngle)
}
;#####################################################################################
; Function Gdip_FillEllipse
; Description This function uses a brush to fill an ellipse in the Graphics of a bitmap
;
; pGraphics Pointer to the Graphics of a bitmap
; pBrush Pointer to a brush
; x x-coordinate of the top left of the ellipse
; y y-coordinate of the top left of the ellipse
; w width of the ellipse
; h height of the ellipse
;
; return status enumeration. 0 = success
Gdip_FillEllipse(pGraphics, pBrush, x, y, w, h)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
return DllCall("gdiplus\GdipFillEllipse", Ptr, pGraphics, Ptr, pBrush, "float", x, "float", y, "float", w, "float", h)
}
;#####################################################################################
; Function Gdip_FillRegion
; Description This function uses a brush to fill a region in the Graphics of a bitmap
;
; pGraphics Pointer to the Graphics of a bitmap
; pBrush Pointer to a brush
; Region Pointer to a Region
;
; return status enumeration. 0 = success
;
; notes You can create a region Gdip_CreateRegion() and then add to this
Gdip_FillRegion(pGraphics, pBrush, Region)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
return DllCall("gdiplus\GdipFillRegion", Ptr, pGraphics, Ptr, pBrush, Ptr, Region)
}
;#####################################################################################
; Function Gdip_FillPath
; Description This function uses a brush to fill a path in the Graphics of a bitmap
;
; pGraphics Pointer to the Graphics of a bitmap
; pBrush Pointer to a brush
; Region Pointer to a Path
;
; return status enumeration. 0 = success
Gdip_FillPath(pGraphics, pBrush, Path)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
return DllCall("gdiplus\GdipFillPath", Ptr, pGraphics, Ptr, pBrush, Ptr, Path)
}
;#####################################################################################
; Function Gdip_DrawImagePointsRect
; Description This function draws a bitmap into the Graphics of another bitmap and skews it
;
; pGraphics Pointer to the Graphics of a bitmap
; pBitmap Pointer to a bitmap to be drawn
; Points Points passed as x1,y1|x2,y2|x3,y3 (3 points: top left, top right, bottom left) describing the drawing of the bitmap
; sx x-coordinate of source upper-left corner
; sy y-coordinate of source upper-left corner
; sw width of source rectangle
; sh height of source rectangle
; Matrix a matrix used to alter image attributes when drawing
;
; return status enumeration. 0 = success
;
; notes if sx,sy,sw,sh are missed then the entire source bitmap will be used
; Matrix can be omitted to just draw with no alteration to ARGB
; Matrix may be passed as a digit from 0 - 1 to change just transparency
; Matrix can be passed as a matrix with any delimiter
Gdip_DrawImagePointsRect(pGraphics, pBitmap, Points, sx="", sy="", sw="", sh="", Matrix=1)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
StringSplit, Points, Points, |
VarSetCapacity(PointF, 8*Points0)
Loop, %Points0%
{
StringSplit, Coord, Points%A_Index%, `,
NumPut(Coord1, PointF, 8*(A_Index-1), "float"), NumPut(Coord2, PointF, (8*(A_Index-1))+4, "float")
}
if (Matrix&1 = "")
ImageAttr := Gdip_SetImageAttributesColorMatrix(Matrix)
else if (Matrix != 1)
ImageAttr := Gdip_SetImageAttributesColorMatrix("1|0|0|0|0|0|1|0|0|0|0|0|1|0|0|0|0|0|" Matrix "|0|0|0|0|0|1")
if (sx = "" && sy = "" && sw = "" && sh = "")
{
sx := 0, sy := 0
sw := Gdip_GetImageWidth(pBitmap)
sh := Gdip_GetImageHeight(pBitmap)
}
E := DllCall("gdiplus\GdipDrawImagePointsRect"
, Ptr, pGraphics
, Ptr, pBitmap
, Ptr, &PointF
, "int", Points0
, "float", sx
, "float", sy
, "float", sw
, "float", sh
, "int", 2
, Ptr, ImageAttr
, Ptr, 0
, Ptr, 0)
if ImageAttr
Gdip_DisposeImageAttributes(ImageAttr)
return E
}
;#####################################################################################
; Function Gdip_DrawImage
; Description This function draws a bitmap into the Graphics of another bitmap
;
; pGraphics Pointer to the Graphics of a bitmap
; pBitmap Pointer to a bitmap to be drawn
; dx x-coord of destination upper-left corner
; dy y-coord of destination upper-left corner
; dw width of destination image
; dh height of destination image
; sx x-coordinate of source upper-left corner
; sy y-coordinate of source upper-left corner
; sw width of source image
; sh height of source image
; Matrix a matrix used to alter image attributes when drawing
;
; return status enumeration. 0 = success
;
; notes if sx,sy,sw,sh are missed then the entire source bitmap will be used
; Gdip_DrawImage performs faster
; Matrix can be omitted to just draw with no alteration to ARGB
; Matrix may be passed as a digit from 0 - 1 to change just transparency
; Matrix can be passed as a matrix with any delimiter. For example:
; MatrixBright=
; (
; 1.5 |0 |0 |0 |0
; 0 |1.5 |0 |0 |0
; 0 |0 |1.5 |0 |0
; 0 |0 |0 |1 |0
; 0.05 |0.05 |0.05 |0 |1
; )
;
; notes MatrixBright = 1.5|0|0|0|0|0|1.5|0|0|0|0|0|1.5|0|0|0|0|0|1|0|0.05|0.05|0.05|0|1
; MatrixGreyScale = 0.299|0.299|0.299|0|0|0.587|0.587|0.587|0|0|0.114|0.114|0.114|0|0|0|0|0|1|0|0|0|0|0|1
; MatrixNegative = -1|0|0|0|0|0|-1|0|0|0|0|0|-1|0|0|0|0|0|1|0|0|0|0|0|1
Gdip_DrawImage(pGraphics, pBitmap, dx="", dy="", dw="", dh="", sx="", sy="", sw="", sh="", Matrix=1)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
if (Matrix&1 = "")
ImageAttr := Gdip_SetImageAttributesColorMatrix(Matrix)
else if (Matrix != 1)
ImageAttr := Gdip_SetImageAttributesColorMatrix("1|0|0|0|0|0|1|0|0|0|0|0|1|0|0|0|0|0|" Matrix "|0|0|0|0|0|1")
if (sx = "" && sy = "" && sw = "" && sh = "")
{
if (dx = "" && dy = "" && dw = "" && dh = "")
{
sx := dx := 0, sy := dy := 0
sw := dw := Gdip_GetImageWidth(pBitmap)
sh := dh := Gdip_GetImageHeight(pBitmap)
}
else
{
sx := sy := 0
sw := Gdip_GetImageWidth(pBitmap)
sh := Gdip_GetImageHeight(pBitmap)
}
}
E := DllCall("gdiplus\GdipDrawImageRectRect"
, Ptr, pGraphics
, Ptr, pBitmap
, "float", dx
, "float", dy
, "float", dw
, "float", dh
, "float", sx
, "float", sy
, "float", sw
, "float", sh
, "int", 2
, Ptr, ImageAttr
, Ptr, 0
, Ptr, 0)
if ImageAttr
Gdip_DisposeImageAttributes(ImageAttr)
return E
}
;#####################################################################################
; Function Gdip_SetImageAttributesColorMatrix
; Description This function creates an image matrix ready for drawing
;
; Matrix a matrix used to alter image attributes when drawing
; passed with any delimeter
;
; return returns an image matrix on sucess or 0 if it fails
;
; notes MatrixBright = 1.5|0|0|0|0|0|1.5|0|0|0|0|0|1.5|0|0|0|0|0|1|0|0.05|0.05|0.05|0|1
; MatrixGreyScale = 0.299|0.299|0.299|0|0|0.587|0.587|0.587|0|0|0.114|0.114|0.114|0|0|0|0|0|1|0|0|0|0|0|1
; MatrixNegative = -1|0|0|0|0|0|-1|0|0|0|0|0|-1|0|0|0|0|0|1|0|0|0|0|0|1
Gdip_SetImageAttributesColorMatrix(Matrix)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
VarSetCapacity(ColourMatrix, 100, 0)
Matrix := RegExReplace(RegExReplace(Matrix, "^[^\d-\.]+([\d\.])", "$1", "", 1), "[^\d-\.]+", "|")
StringSplit, Matrix, Matrix, |
Loop, 25
{
Matrix := (Matrix%A_Index% != "") ? Matrix%A_Index% : Mod(A_Index-1, 6) ? 0 : 1
NumPut(Matrix, ColourMatrix, (A_Index-1)*4, "float")
}
DllCall("gdiplus\GdipCreateImageAttributes", A_PtrSize ? "UPtr*" : "uint*", ImageAttr)
DllCall("gdiplus\GdipSetImageAttributesColorMatrix", Ptr, ImageAttr, "int", 1, "int", 1, Ptr, &ColourMatrix, Ptr, 0, "int", 0)
return ImageAttr
}
;#####################################################################################
; Function Gdip_GraphicsFromImage
; Description This function gets the graphics for a bitmap used for drawing functions
;
; pBitmap Pointer to a bitmap to get the pointer to its graphics
;
; return returns a pointer to the graphics of a bitmap
;
; notes a bitmap can be drawn into the graphics of another bitmap
Gdip_GraphicsFromImage(pBitmap)
{
DllCall("gdiplus\GdipGetImageGraphicsContext", A_PtrSize ? "UPtr" : "UInt", pBitmap, A_PtrSize ? "UPtr*" : "UInt*", pGraphics)
return pGraphics
}
;#####################################################################################
; Function Gdip_GraphicsFromHDC
; Description This function gets the graphics from the handle to a device context
;
; hdc This is the handle to the device context
;
; return returns a pointer to the graphics of a bitmap
;
; notes You can draw a bitmap into the graphics of another bitmap
Gdip_GraphicsFromHDC(hdc)
{
DllCall("gdiplus\GdipCreateFromHDC", A_PtrSize ? "UPtr" : "UInt", hdc, A_PtrSize ? "UPtr*" : "UInt*", pGraphics)
return pGraphics
}
;#####################################################################################
; Function Gdip_GetDC
; Description This function gets the device context of the passed Graphics
;
; hdc This is the handle to the device context
;
; return returns the device context for the graphics of a bitmap
Gdip_GetDC(pGraphics)
{
DllCall("gdiplus\GdipGetDC", A_PtrSize ? "UPtr" : "UInt", pGraphics, A_PtrSize ? "UPtr*" : "UInt*", hdc)
return hdc
}
;#####################################################################################
; Function Gdip_ReleaseDC
; Description This function releases a device context from use for further use
;
; pGraphics Pointer to the graphics of a bitmap
; hdc This is the handle to the device context
;
; return status enumeration. 0 = success
Gdip_ReleaseDC(pGraphics, hdc)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
return DllCall("gdiplus\GdipReleaseDC", Ptr, pGraphics, Ptr, hdc)
}
;#####################################################################################
; Function Gdip_GraphicsClear
; Description Clears the graphics of a bitmap ready for further drawing
;
; pGraphics Pointer to the graphics of a bitmap
; ARGB The colour to clear the graphics to
;
; return status enumeration. 0 = success
;
; notes By default this will make the background invisible
; Using clipping regions you can clear a particular area on the graphics rather than clearing the entire graphics
Gdip_GraphicsClear(pGraphics, ARGB=0x00ffffff)
{
return DllCall("gdiplus\GdipGraphicsClear", A_PtrSize ? "UPtr" : "UInt", pGraphics, "int", ARGB)
}
;#####################################################################################
; Function Gdip_BlurBitmap
; Description Gives a pointer to a blurred bitmap from a pointer to a bitmap
;
; pBitmap Pointer to a bitmap to be blurred
; Blur The Amount to blur a bitmap by from 1 (least blur) to 100 (most blur)
;
; return If the function succeeds, the return value is a pointer to the new blurred bitmap
; -1 = The blur parameter is outside the range 1-100
;
; notes This function will not dispose of the original bitmap
Gdip_BlurBitmap(pBitmap, Blur)
{
if (Blur > 100) || (Blur < 1)
return -1
sWidth := Gdip_GetImageWidth(pBitmap), sHeight := Gdip_GetImageHeight(pBitmap)
dWidth := sWidth//Blur, dHeight := sHeight//Blur
pBitmap1 := Gdip_CreateBitmap(dWidth, dHeight)
G1 := Gdip_GraphicsFromImage(pBitmap1)
Gdip_SetInterpolationMode(G1, 7)
Gdip_DrawImage(G1, pBitmap, 0, 0, dWidth, dHeight, 0, 0, sWidth, sHeight)
Gdip_DeleteGraphics(G1)
pBitmap2 := Gdip_CreateBitmap(sWidth, sHeight)
G2 := Gdip_GraphicsFromImage(pBitmap2)
Gdip_SetInterpolationMode(G2, 7)
Gdip_DrawImage(G2, pBitmap1, 0, 0, sWidth, sHeight, 0, 0, dWidth, dHeight)
Gdip_DeleteGraphics(G2)
Gdip_DisposeImage(pBitmap1)
return pBitmap2
}
;#####################################################################################
; Function: Gdip_SaveBitmapToFile
; Description: Saves a bitmap to a file in any supported format onto disk
;
; pBitmap Pointer to a bitmap
; sOutput The name of the file that the bitmap will be saved to. Supported extensions are: .BMP,.DIB,.RLE,.JPG,.JPEG,.JPE,.JFIF,.GIF,.TIF,.TIFF,.PNG
; Quality If saving as jpg (.JPG,.JPEG,.JPE,.JFIF) then quality can be 1-100 with default at maximum quality
;
; return If the function succeeds, the return value is zero, otherwise:
; -1 = Extension supplied is not a supported file format
; -2 = Could not get a list of encoders on system
; -3 = Could not find matching encoder for specified file format
; -4 = Could not get WideChar name of output file
; -5 = Could not save file to disk
;
; notes This function will use the extension supplied from the sOutput parameter to determine the output format
Gdip_SaveBitmapToFile(pBitmap, sOutput, Quality=75)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
SplitPath, sOutput,,, Extension
if Extension not in BMP,DIB,RLE,JPG,JPEG,JPE,JFIF,GIF,TIF,TIFF,PNG
return -1
Extension := "." Extension
DllCall("gdiplus\GdipGetImageEncodersSize", "uint*", nCount, "uint*", nSize)
VarSetCapacity(ci, nSize)
DllCall("gdiplus\GdipGetImageEncoders", "uint", nCount, "uint", nSize, Ptr, &ci)
if !(nCount && nSize)
return -2
If (A_IsUnicode){
StrGet_Name := "StrGet"
Loop, %nCount%
{
sString := %StrGet_Name%(NumGet(ci, (idx := (48+7*A_PtrSize)*(A_Index-1))+32+3*A_PtrSize), "UTF-16")
if !InStr(sString, "*" Extension)
continue
pCodec := &ci+idx
break
}
} else {
Loop, %nCount%
{
Location := NumGet(ci, 76*(A_Index-1)+44)
nSize := DllCall("WideCharToMultiByte", "uint", 0, "uint", 0, "uint", Location, "int", -1, "uint", 0, "int", 0, "uint", 0, "uint", 0)
VarSetCapacity(sString, nSize)
DllCall("WideCharToMultiByte", "uint", 0, "uint", 0, "uint", Location, "int", -1, "str", sString, "int", nSize, "uint", 0, "uint", 0)
if !InStr(sString, "*" Extension)
continue
pCodec := &ci+76*(A_Index-1)
break
}
}
if !pCodec
return -3
if (Quality != 75)
{
Quality := (Quality < 0) ? 0 : (Quality > 100) ? 100 : Quality
if Extension in .JPG,.JPEG,.JPE,.JFIF
{
DllCall("gdiplus\GdipGetEncoderParameterListSize", Ptr, pBitmap, Ptr, pCodec, "uint*", nSize)
VarSetCapacity(EncoderParameters, nSize, 0)
DllCall("gdiplus\GdipGetEncoderParameterList", Ptr, pBitmap, Ptr, pCodec, "uint", nSize, Ptr, &EncoderParameters)
Loop, % NumGet(EncoderParameters, "UInt") ;%
{
elem := (24+(A_PtrSize ? A_PtrSize : 4))*(A_Index-1) + 4 + (pad := A_PtrSize = 8 ? 4 : 0)
if (NumGet(EncoderParameters, elem+16, "UInt") = 1) && (NumGet(EncoderParameters, elem+20, "UInt") = 6)
{
p := elem+&EncoderParameters-pad-4
NumPut(Quality, NumGet(NumPut(4, NumPut(1, p+0)+20, "UInt")), "UInt")
break
}
}
}
}
if (!A_IsUnicode)
{
nSize := DllCall("MultiByteToWideChar", "uint", 0, "uint", 0, Ptr, &sOutput, "int", -1, Ptr, 0, "int", 0)
VarSetCapacity(wOutput, nSize*2)
DllCall("MultiByteToWideChar", "uint", 0, "uint", 0, Ptr, &sOutput, "int", -1, Ptr, &wOutput, "int", nSize)
VarSetCapacity(wOutput, -1)
if !VarSetCapacity(wOutput)
return -4
E := DllCall("gdiplus\GdipSaveImageToFile", Ptr, pBitmap, Ptr, &wOutput, Ptr, pCodec, "uint", p ? p : 0)
}
else
E := DllCall("gdiplus\GdipSaveImageToFile", Ptr, pBitmap, Ptr, &sOutput, Ptr, pCodec, "uint", p ? p : 0)
return E ? -5 : 0
}
;#####################################################################################
; Function Gdip_GetPixel
; Description Gets the ARGB of a pixel in a bitmap
;
; pBitmap Pointer to a bitmap
; x x-coordinate of the pixel
; y y-coordinate of the pixel
;
; return Returns the ARGB value of the pixel
Gdip_GetPixel(pBitmap, x, y)
{
DllCall("gdiplus\GdipBitmapGetPixel", A_PtrSize ? "UPtr" : "UInt", pBitmap, "int", x, "int", y, "uint*", ARGB)
return ARGB
}
;#####################################################################################
; Function Gdip_SetPixel
; Description Sets the ARGB of a pixel in a bitmap
;
; pBitmap Pointer to a bitmap
; x x-coordinate of the pixel
; y y-coordinate of the pixel
;
; return status enumeration. 0 = success
Gdip_SetPixel(pBitmap, x, y, ARGB)
{
return DllCall("gdiplus\GdipBitmapSetPixel", A_PtrSize ? "UPtr" : "UInt", pBitmap, "int", x, "int", y, "int", ARGB)
}
;#####################################################################################
; Function Gdip_GetImageWidth
; Description Gives the width of a bitmap
;
; pBitmap Pointer to a bitmap
;
; return Returns the width in pixels of the supplied bitmap
Gdip_GetImageWidth(pBitmap)
{
DllCall("gdiplus\GdipGetImageWidth", A_PtrSize ? "UPtr" : "UInt", pBitmap, "uint*", Width)
return Width
}
;#####################################################################################
; Function Gdip_GetImageHeight
; Description Gives the height of a bitmap
;
; pBitmap Pointer to a bitmap
;
; return Returns the height in pixels of the supplied bitmap
Gdip_GetImageHeight(pBitmap)
{
DllCall("gdiplus\GdipGetImageHeight", A_PtrSize ? "UPtr" : "UInt", pBitmap, "uint*", Height)
return Height
}
;#####################################################################################
; Function Gdip_GetDimensions
; Description Gives the width and height of a bitmap
;
; pBitmap Pointer to a bitmap
; Width ByRef variable. This variable will be set to the width of the bitmap
; Height ByRef variable. This variable will be set to the height of the bitmap
;
; return No return value
; Gdip_GetDimensions(pBitmap, ThisWidth, ThisHeight) will set ThisWidth to the width and ThisHeight to the height
Gdip_GetImageDimensions(pBitmap, ByRef Width, ByRef Height)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
DllCall("gdiplus\GdipGetImageWidth", Ptr, pBitmap, "uint*", Width)
DllCall("gdiplus\GdipGetImageHeight", Ptr, pBitmap, "uint*", Height)
}
;#####################################################################################
Gdip_GetDimensions(pBitmap, ByRef Width, ByRef Height)
{
Gdip_GetImageDimensions(pBitmap, Width, Height)
}
;#####################################################################################
Gdip_GetImagePixelFormat(pBitmap)
{
DllCall("gdiplus\GdipGetImagePixelFormat", A_PtrSize ? "UPtr" : "UInt", pBitmap, A_PtrSize ? "UPtr*" : "UInt*", Format)
return Format
}
;#####################################################################################
; Function Gdip_GetDpiX
; Description Gives the horizontal dots per inch of the graphics of a bitmap
;
; pBitmap Pointer to a bitmap
; Width ByRef variable. This variable will be set to the width of the bitmap
; Height ByRef variable. This variable will be set to the height of the bitmap
;
; return No return value
; Gdip_GetDimensions(pBitmap, ThisWidth, ThisHeight) will set ThisWidth to the width and ThisHeight to the height
Gdip_GetDpiX(pGraphics)
{
DllCall("gdiplus\GdipGetDpiX", A_PtrSize ? "UPtr" : "uint", pGraphics, "float*", dpix)
return Round(dpix)
}
;#####################################################################################
Gdip_GetDpiY(pGraphics)
{
DllCall("gdiplus\GdipGetDpiY", A_PtrSize ? "UPtr" : "uint", pGraphics, "float*", dpiy)
return Round(dpiy)
}
;#####################################################################################
Gdip_GetImageHorizontalResolution(pBitmap)
{
DllCall("gdiplus\GdipGetImageHorizontalResolution", A_PtrSize ? "UPtr" : "uint", pBitmap, "float*", dpix)
return Round(dpix)
}
;#####################################################################################
Gdip_GetImageVerticalResolution(pBitmap)
{
DllCall("gdiplus\GdipGetImageVerticalResolution", A_PtrSize ? "UPtr" : "uint", pBitmap, "float*", dpiy)
return Round(dpiy)
}
;#####################################################################################
Gdip_BitmapSetResolution(pBitmap, dpix, dpiy)
{
return DllCall("gdiplus\GdipBitmapSetResolution", A_PtrSize ? "UPtr" : "uint", pBitmap, "float", dpix, "float", dpiy)
}
;#####################################################################################
Gdip_CreateBitmapFromFile(sFile, IconNumber=1, IconSize="")
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
, PtrA := A_PtrSize ? "UPtr*" : "UInt*"
SplitPath, sFile,,, ext
if ext in exe,dll
{
Sizes := IconSize ? IconSize : 256 "|" 128 "|" 64 "|" 48 "|" 32 "|" 16
BufSize := 16 + (2*(A_PtrSize ? A_PtrSize : 4))
VarSetCapacity(buf, BufSize, 0)
Loop, Parse, Sizes, |
{
DllCall("PrivateExtractIcons", "str", sFile, "int", IconNumber-1, "int", A_LoopField, "int", A_LoopField, PtrA, hIcon, PtrA, 0, "uint", 1, "uint", 0)
if !hIcon
continue
if !DllCall("GetIconInfo", Ptr, hIcon, Ptr, &buf)
{
DestroyIcon(hIcon)
continue
}
hbmMask := NumGet(buf, 12 + ((A_PtrSize ? A_PtrSize : 4) - 4))
hbmColor := NumGet(buf, 12 + ((A_PtrSize ? A_PtrSize : 4) - 4) + (A_PtrSize ? A_PtrSize : 4))
if !(hbmColor && DllCall("GetObject", Ptr, hbmColor, "int", BufSize, Ptr, &buf))
{
DestroyIcon(hIcon)
continue
}
break
}
if !hIcon
return -1
Width := NumGet(buf, 4, "int"), Height := NumGet(buf, 8, "int")
hbm := CreateDIBSection(Width, -Height), hdc := CreateCompatibleDC(), obm := SelectObject(hdc, hbm)
if !DllCall("DrawIconEx", Ptr, hdc, "int", 0, "int", 0, Ptr, hIcon, "uint", Width, "uint", Height, "uint", 0, Ptr, 0, "uint", 3)
{
DestroyIcon(hIcon)
return -2
}
VarSetCapacity(dib, 104)
DllCall("GetObject", Ptr, hbm, "int", A_PtrSize = 8 ? 104 : 84, Ptr, &dib) ; sizeof(DIBSECTION) = 76+2*(A_PtrSize=8?4:0)+2*A_PtrSize
Stride := NumGet(dib, 12, "Int"), Bits := NumGet(dib, 20 + (A_PtrSize = 8 ? 4 : 0)) ; padding
DllCall("gdiplus\GdipCreateBitmapFromScan0", "int", Width, "int", Height, "int", Stride, "int", 0x26200A, Ptr, Bits, PtrA, pBitmapOld)
pBitmap := Gdip_CreateBitmap(Width, Height)
G := Gdip_GraphicsFromImage(pBitmap)
, Gdip_DrawImage(G, pBitmapOld, 0, 0, Width, Height, 0, 0, Width, Height)
SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc)
Gdip_DeleteGraphics(G), Gdip_DisposeImage(pBitmapOld)
DestroyIcon(hIcon)
}
else
{
if (!A_IsUnicode)
{
VarSetCapacity(wFile, 1024)
DllCall("kernel32\MultiByteToWideChar", "uint", 0, "uint", 0, Ptr, &sFile, "int", -1, Ptr, &wFile, "int", 512)
DllCall("gdiplus\GdipCreateBitmapFromFile", Ptr, &wFile, PtrA, pBitmap)
}
else
DllCall("gdiplus\GdipCreateBitmapFromFile", Ptr, &sFile, PtrA, pBitmap)
}
return pBitmap
}
;#####################################################################################
Gdip_CreateBitmapFromHBITMAP(hBitmap, Palette=0)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", Ptr, hBitmap, Ptr, Palette, A_PtrSize ? "UPtr*" : "uint*", pBitmap)
return pBitmap
}
;#####################################################################################
Gdip_CreateHBITMAPFromBitmap(pBitmap, Background=0xffffffff)
{
DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", A_PtrSize ? "UPtr" : "UInt", pBitmap, A_PtrSize ? "UPtr*" : "uint*", hbm, "int", Background)
return hbm
}
;#####################################################################################
Gdip_CreateBitmapFromHICON(hIcon)
{
DllCall("gdiplus\GdipCreateBitmapFromHICON", A_PtrSize ? "UPtr" : "UInt", hIcon, A_PtrSize ? "UPtr*" : "uint*", pBitmap)
return pBitmap
}
;#####################################################################################
Gdip_CreateHICONFromBitmap(pBitmap)
{
DllCall("gdiplus\GdipCreateHICONFromBitmap", A_PtrSize ? "UPtr" : "UInt", pBitmap, A_PtrSize ? "UPtr*" : "uint*", hIcon)
return hIcon
}
;#####################################################################################
Gdip_CreateBitmap(Width, Height, Format=0x26200A)
{
DllCall("gdiplus\GdipCreateBitmapFromScan0", "int", Width, "int", Height, "int", 0, "int", Format, A_PtrSize ? "UPtr" : "UInt", 0, A_PtrSize ? "UPtr*" : "uint*", pBitmap)
Return pBitmap
}
;#####################################################################################
Gdip_CreateBitmapFromClipboard()
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
if !DllCall("OpenClipboard", Ptr, 0)
return -1
if !DllCall("IsClipboardFormatAvailable", "uint", 8)
return -2
if !hBitmap := DllCall("GetClipboardData", "uint", 2, Ptr)
return -3
if !pBitmap := Gdip_CreateBitmapFromHBITMAP(hBitmap)
return -4
if !DllCall("CloseClipboard")
return -5
DeleteObject(hBitmap)
return pBitmap
}
;#####################################################################################
Gdip_SetBitmapToClipboard(pBitmap)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
off1 := A_PtrSize = 8 ? 52 : 44, off2 := A_PtrSize = 8 ? 32 : 24
hBitmap := Gdip_CreateHBITMAPFromBitmap(pBitmap)
DllCall("GetObject", Ptr, hBitmap, "int", VarSetCapacity(oi, A_PtrSize = 8 ? 104 : 84, 0), Ptr, &oi)
hdib := DllCall("GlobalAlloc", "uint", 2, Ptr, 40+NumGet(oi, off1, "UInt"), Ptr)
pdib := DllCall("GlobalLock", Ptr, hdib, Ptr)
DllCall("RtlMoveMemory", Ptr, pdib, Ptr, &oi+off2, Ptr, 40)
DllCall("RtlMoveMemory", Ptr, pdib+40, Ptr, NumGet(oi, off2 - (A_PtrSize ? A_PtrSize : 4), Ptr), Ptr, NumGet(oi, off1, "UInt"))
DllCall("GlobalUnlock", Ptr, hdib)
DllCall("DeleteObject", Ptr, hBitmap)
DllCall("OpenClipboard", Ptr, 0)
DllCall("EmptyClipboard")
DllCall("SetClipboardData", "uint", 8, Ptr, hdib)
DllCall("CloseClipboard")
}
;#####################################################################################
Gdip_CloneBitmapArea(pBitmap, x, y, w, h, Format=0x26200A)
{
DllCall("gdiplus\GdipCloneBitmapArea"
, "float", x
, "float", y
, "float", w
, "float", h
, "int", Format
, A_PtrSize ? "UPtr" : "UInt", pBitmap
, A_PtrSize ? "UPtr*" : "UInt*", pBitmapDest)
return pBitmapDest
}
;#####################################################################################
; Create resources
;#####################################################################################
Gdip_CreatePen(ARGB, w)
{
DllCall("gdiplus\GdipCreatePen1", "UInt", ARGB, "float", w, "int", 2, A_PtrSize ? "UPtr*" : "UInt*", pPen)
return pPen
}
;#####################################################################################
Gdip_CreatePenFromBrush(pBrush, w)
{
DllCall("gdiplus\GdipCreatePen2", A_PtrSize ? "UPtr" : "UInt", pBrush, "float", w, "int", 2, A_PtrSize ? "UPtr*" : "UInt*", pPen)
return pPen
}
;#####################################################################################
Gdip_BrushCreateSolid(ARGB=0xff000000)
{
DllCall("gdiplus\GdipCreateSolidFill", "UInt", ARGB, A_PtrSize ? "UPtr*" : "UInt*", pBrush)
return pBrush
}
;#####################################################################################
; HatchStyleHorizontal = 0
; HatchStyleVertical = 1
; HatchStyleForwardDiagonal = 2
; HatchStyleBackwardDiagonal = 3
; HatchStyleCross = 4
; HatchStyleDiagonalCross = 5
; HatchStyle05Percent = 6
; HatchStyle10Percent = 7
; HatchStyle20Percent = 8
; HatchStyle25Percent = 9
; HatchStyle30Percent = 10
; HatchStyle40Percent = 11
; HatchStyle50Percent = 12
; HatchStyle60Percent = 13
; HatchStyle70Percent = 14
; HatchStyle75Percent = 15
; HatchStyle80Percent = 16
; HatchStyle90Percent = 17
; HatchStyleLightDownwardDiagonal = 18
; HatchStyleLightUpwardDiagonal = 19
; HatchStyleDarkDownwardDiagonal = 20
; HatchStyleDarkUpwardDiagonal = 21
; HatchStyleWideDownwardDiagonal = 22
; HatchStyleWideUpwardDiagonal = 23
; HatchStyleLightVertical = 24
; HatchStyleLightHorizontal = 25
; HatchStyleNarrowVertical = 26
; HatchStyleNarrowHorizontal = 27
; HatchStyleDarkVertical = 28
; HatchStyleDarkHorizontal = 29
; HatchStyleDashedDownwardDiagonal = 30
; HatchStyleDashedUpwardDiagonal = 31
; HatchStyleDashedHorizontal = 32
; HatchStyleDashedVertical = 33
; HatchStyleSmallConfetti = 34
; HatchStyleLargeConfetti = 35
; HatchStyleZigZag = 36
; HatchStyleWave = 37
; HatchStyleDiagonalBrick = 38
; HatchStyleHorizontalBrick = 39
; HatchStyleWeave = 40
; HatchStylePlaid = 41
; HatchStyleDivot = 42
; HatchStyleDottedGrid = 43
; HatchStyleDottedDiamond = 44
; HatchStyleShingle = 45
; HatchStyleTrellis = 46
; HatchStyleSphere = 47
; HatchStyleSmallGrid = 48
; HatchStyleSmallCheckerBoard = 49
; HatchStyleLargeCheckerBoard = 50
; HatchStyleOutlinedDiamond = 51
; HatchStyleSolidDiamond = 52
; HatchStyleTotal = 53
Gdip_BrushCreateHatch(ARGBfront, ARGBback, HatchStyle=0)
{
DllCall("gdiplus\GdipCreateHatchBrush", "int", HatchStyle, "UInt", ARGBfront, "UInt", ARGBback, A_PtrSize ? "UPtr*" : "UInt*", pBrush)
return pBrush
}
;#####################################################################################
Gdip_CreateTextureBrush(pBitmap, WrapMode=1, x=0, y=0, w="", h="")
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
, PtrA := A_PtrSize ? "UPtr*" : "UInt*"
if !(w && h)
DllCall("gdiplus\GdipCreateTexture", Ptr, pBitmap, "int", WrapMode, PtrA, pBrush)
else
DllCall("gdiplus\GdipCreateTexture2", Ptr, pBitmap, "int", WrapMode, "float", x, "float", y, "float", w, "float", h, PtrA, pBrush)
return pBrush
}
;#####################################################################################
; WrapModeTile = 0
; WrapModeTileFlipX = 1
; WrapModeTileFlipY = 2
; WrapModeTileFlipXY = 3
; WrapModeClamp = 4
Gdip_CreateLineBrush(x1, y1, x2, y2, ARGB1, ARGB2, WrapMode=1)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
CreatePointF(PointF1, x1, y1), CreatePointF(PointF2, x2, y2)
DllCall("gdiplus\GdipCreateLineBrush", Ptr, &PointF1, Ptr, &PointF2, "Uint", ARGB1, "Uint", ARGB2, "int", WrapMode, A_PtrSize ? "UPtr*" : "UInt*", LGpBrush)
return LGpBrush
}
;#####################################################################################
; LinearGradientModeHorizontal = 0
; LinearGradientModeVertical = 1
; LinearGradientModeForwardDiagonal = 2
; LinearGradientModeBackwardDiagonal = 3
Gdip_CreateLineBrushFromRect(x, y, w, h, ARGB1, ARGB2, LinearGradientMode=1, WrapMode=1)
{
CreateRectF(RectF, x, y, w, h)
DllCall("gdiplus\GdipCreateLineBrushFromRect", A_PtrSize ? "UPtr" : "UInt", &RectF, "int", ARGB1, "int", ARGB2, "int", LinearGradientMode, "int", WrapMode, A_PtrSize ? "UPtr*" : "UInt*", LGpBrush)
return LGpBrush
}
;#####################################################################################
Gdip_CloneBrush(pBrush)
{
DllCall("gdiplus\GdipCloneBrush", A_PtrSize ? "UPtr" : "UInt", pBrush, A_PtrSize ? "UPtr*" : "UInt*", pBrushClone)
return pBrushClone
}
;#####################################################################################
; Delete resources
;#####################################################################################
Gdip_DeletePen(pPen)
{
return DllCall("gdiplus\GdipDeletePen", A_PtrSize ? "UPtr" : "UInt", pPen)
}
;#####################################################################################
Gdip_DeleteBrush(pBrush)
{
return DllCall("gdiplus\GdipDeleteBrush", A_PtrSize ? "UPtr" : "UInt", pBrush)
}
;#####################################################################################
Gdip_DisposeImage(pBitmap)
{
return DllCall("gdiplus\GdipDisposeImage", A_PtrSize ? "UPtr" : "UInt", pBitmap)
}
;#####################################################################################
Gdip_DeleteGraphics(pGraphics)
{
return DllCall("gdiplus\GdipDeleteGraphics", A_PtrSize ? "UPtr" : "UInt", pGraphics)
}
;#####################################################################################
Gdip_DisposeImageAttributes(ImageAttr)
{
return DllCall("gdiplus\GdipDisposeImageAttributes", A_PtrSize ? "UPtr" : "UInt", ImageAttr)
}
;#####################################################################################
Gdip_DeleteFont(hFont)
{
return DllCall("gdiplus\GdipDeleteFont", A_PtrSize ? "UPtr" : "UInt", hFont)
}
;#####################################################################################
Gdip_DeleteStringFormat(hFormat)
{
return DllCall("gdiplus\GdipDeleteStringFormat", A_PtrSize ? "UPtr" : "UInt", hFormat)
}
;#####################################################################################
Gdip_DeleteFontFamily(hFamily)
{
return DllCall("gdiplus\GdipDeleteFontFamily", A_PtrSize ? "UPtr" : "UInt", hFamily)
}
;#####################################################################################
Gdip_DeleteMatrix(Matrix)
{
return DllCall("gdiplus\GdipDeleteMatrix", A_PtrSize ? "UPtr" : "UInt", Matrix)
}
;#####################################################################################
; Text functions
;#####################################################################################
Gdip_TextToGraphics(pGraphics, Text, Options, Font="Arial", Width="", Height="", Measure=0)
{
IWidth := Width, IHeight:= Height
RegExMatch(Options, "i)X([\-\d\.]+)(p*)", xpos)
RegExMatch(Options, "i)Y([\-\d\.]+)(p*)", ypos)
RegExMatch(Options, "i)W([\-\d\.]+)(p*)", Width)
RegExMatch(Options, "i)H([\-\d\.]+)(p*)", Height)
RegExMatch(Options, "i)C(?!(entre|enter))([a-f\d]+)", Colour)
RegExMatch(Options, "i)Top|Up|Bottom|Down|vCentre|vCenter", vPos)
RegExMatch(Options, "i)NoWrap", NoWrap)
RegExMatch(Options, "i)R(\d)", Rendering)
RegExMatch(Options, "i)S(\d+)(p*)", Size)
if !Gdip_DeleteBrush(Gdip_CloneBrush(Colour2))
PassBrush := 1, pBrush := Colour2
if !(IWidth && IHeight) && (xpos2 || ypos2 || Width2 || Height2 || Size2)
return -1
Style := 0, Styles := "Regular|Bold|Italic|BoldItalic|Underline|Strikeout"
Loop, Parse, Styles, |
{
if RegExMatch(Options, "\b" A_loopField)
Style |= (A_LoopField != "StrikeOut") ? (A_Index-1) : 8
}
Align := 0, Alignments := "Near|Left|Centre|Center|Far|Right"
Loop, Parse, Alignments, |
{
if RegExMatch(Options, "\b" A_loopField)
Align |= A_Index//2.1 ; 0|0|1|1|2|2
}
xpos := (xpos1 != "") ? xpos2 ? IWidth*(xpos1/100) : xpos1 : 0
ypos := (ypos1 != "") ? ypos2 ? IHeight*(ypos1/100) : ypos1 : 0
Width := Width1 ? Width2 ? IWidth*(Width1/100) : Width1 : IWidth
Height := Height1 ? Height2 ? IHeight*(Height1/100) : Height1 : IHeight
if !PassBrush
Colour := "0x" (Colour2 ? Colour2 : "ff000000")
Rendering := ((Rendering1 >= 0) && (Rendering1 <= 5)) ? Rendering1 : 4
Size := (Size1 > 0) ? Size2 ? IHeight*(Size1/100) : Size1 : 12
hFamily := Gdip_FontFamilyCreate(Font)
hFont := Gdip_FontCreate(hFamily, Size, Style)
FormatStyle := NoWrap ? 0x4000 | 0x1000 : 0x4000
hFormat := Gdip_StringFormatCreate(FormatStyle)
pBrush := PassBrush ? pBrush : Gdip_BrushCreateSolid(Colour)
if !(hFamily && hFont && hFormat && pBrush && pGraphics)
return !pGraphics ? -2 : !hFamily ? -3 : !hFont ? -4 : !hFormat ? -5 : !pBrush ? -6 : 0
CreateRectF(RC, xpos, ypos, Width, Height)
Gdip_SetStringFormatAlign(hFormat, Align)
Gdip_SetTextRenderingHint(pGraphics, Rendering)
ReturnRC := Gdip_MeasureString(pGraphics, Text, hFont, hFormat, RC)
if vPos
{
StringSplit, ReturnRC, ReturnRC, |
if (vPos = "vCentre") || (vPos = "vCenter")
ypos += (Height-ReturnRC4)//2
else if (vPos = "Top") || (vPos = "Up")
ypos := 0
else if (vPos = "Bottom") || (vPos = "Down")
ypos := Height-ReturnRC4
CreateRectF(RC, xpos, ypos, Width, ReturnRC4)
ReturnRC := Gdip_MeasureString(pGraphics, Text, hFont, hFormat, RC)
}
if !Measure
E := Gdip_DrawString(pGraphics, Text, hFont, hFormat, pBrush, RC)
if !PassBrush
Gdip_DeleteBrush(pBrush)
Gdip_DeleteStringFormat(hFormat)
Gdip_DeleteFont(hFont)
Gdip_DeleteFontFamily(hFamily)
return E ? E : ReturnRC
}
;#####################################################################################
Gdip_DrawString(pGraphics, sString, hFont, hFormat, pBrush, ByRef RectF)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
if (!A_IsUnicode)
{
nSize := DllCall("MultiByteToWideChar", "uint", 0, "uint", 0, Ptr, &sString, "int", -1, Ptr, 0, "int", 0)
VarSetCapacity(wString, nSize*2)
DllCall("MultiByteToWideChar", "uint", 0, "uint", 0, Ptr, &sString, "int", -1, Ptr, &wString, "int", nSize)
}
return DllCall("gdiplus\GdipDrawString"
, Ptr, pGraphics
, Ptr, A_IsUnicode ? &sString : &wString
, "int", -1
, Ptr, hFont
, Ptr, &RectF
, Ptr, hFormat
, Ptr, pBrush)
}
;#####################################################################################
Gdip_MeasureString(pGraphics, sString, hFont, hFormat, ByRef RectF)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
VarSetCapacity(RC, 16)
if !A_IsUnicode
{
nSize := DllCall("MultiByteToWideChar", "uint", 0, "uint", 0, Ptr, &sString, "int", -1, "uint", 0, "int", 0)
VarSetCapacity(wString, nSize*2)
DllCall("MultiByteToWideChar", "uint", 0, "uint", 0, Ptr, &sString, "int", -1, Ptr, &wString, "int", nSize)
}
DllCall("gdiplus\GdipMeasureString"
, Ptr, pGraphics
, Ptr, A_IsUnicode ? &sString : &wString
, "int", -1
, Ptr, hFont
, Ptr, &RectF
, Ptr, hFormat
, Ptr, &RC
, "uint*", Chars
, "uint*", Lines)
return &RC ? NumGet(RC, 0, "float") "|" NumGet(RC, 4, "float") "|" NumGet(RC, 8, "float") "|" NumGet(RC, 12, "float") "|" Chars "|" Lines : 0
}
; Near = 0
; Center = 1
; Far = 2
Gdip_SetStringFormatAlign(hFormat, Align)
{
return DllCall("gdiplus\GdipSetStringFormatAlign", A_PtrSize ? "UPtr" : "UInt", hFormat, "int", Align)
}
; StringFormatFlagsDirectionRightToLeft = 0x00000001
; StringFormatFlagsDirectionVertical = 0x00000002
; StringFormatFlagsNoFitBlackBox = 0x00000004
; StringFormatFlagsDisplayFormatControl = 0x00000020
; StringFormatFlagsNoFontFallback = 0x00000400
; StringFormatFlagsMeasureTrailingSpaces = 0x00000800
; StringFormatFlagsNoWrap = 0x00001000
; StringFormatFlagsLineLimit = 0x00002000
; StringFormatFlagsNoClip = 0x00004000
Gdip_StringFormatCreate(Format=0, Lang=0)
{
DllCall("gdiplus\GdipCreateStringFormat", "int", Format, "int", Lang, A_PtrSize ? "UPtr*" : "UInt*", hFormat)
return hFormat
}
; Regular = 0
; Bold = 1
; Italic = 2
; BoldItalic = 3
; Underline = 4
; Strikeout = 8
Gdip_FontCreate(hFamily, Size, Style=0)
{
DllCall("gdiplus\GdipCreateFont", A_PtrSize ? "UPtr" : "UInt", hFamily, "float", Size, "int", Style, "int", 0, A_PtrSize ? "UPtr*" : "UInt*", hFont)
return hFont
}
Gdip_FontFamilyCreate(Font)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
if (!A_IsUnicode)
{
nSize := DllCall("MultiByteToWideChar", "uint", 0, "uint", 0, Ptr, &Font, "int", -1, "uint", 0, "int", 0)
VarSetCapacity(wFont, nSize*2)
DllCall("MultiByteToWideChar", "uint", 0, "uint", 0, Ptr, &Font, "int", -1, Ptr, &wFont, "int", nSize)
}
DllCall("gdiplus\GdipCreateFontFamilyFromName"
, Ptr, A_IsUnicode ? &Font : &wFont
, "uint", 0
, A_PtrSize ? "UPtr*" : "UInt*", hFamily)
return hFamily
}
;#####################################################################################
; Matrix functions
;#####################################################################################
Gdip_CreateAffineMatrix(m11, m12, m21, m22, x, y)
{
DllCall("gdiplus\GdipCreateMatrix2", "float", m11, "float", m12, "float", m21, "float", m22, "float", x, "float", y, A_PtrSize ? "UPtr*" : "UInt*", Matrix)
return Matrix
}
Gdip_CreateMatrix()
{
DllCall("gdiplus\GdipCreateMatrix", A_PtrSize ? "UPtr*" : "UInt*", Matrix)
return Matrix
}
;#####################################################################################
; GraphicsPath functions
;#####################################################################################
; Alternate = 0
; Winding = 1
Gdip_CreatePath(BrushMode=0)
{
DllCall("gdiplus\GdipCreatePath", "int", BrushMode, A_PtrSize ? "UPtr*" : "UInt*", Path)
return Path
}
Gdip_AddPathEllipse(Path, x, y, w, h)
{
return DllCall("gdiplus\GdipAddPathEllipse", A_PtrSize ? "UPtr" : "UInt", Path, "float", x, "float", y, "float", w, "float", h)
}
Gdip_AddPathPolygon(Path, Points)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
StringSplit, Points, Points, |
VarSetCapacity(PointF, 8*Points0)
Loop, %Points0%
{
StringSplit, Coord, Points%A_Index%, `,
NumPut(Coord1, PointF, 8*(A_Index-1), "float"), NumPut(Coord2, PointF, (8*(A_Index-1))+4, "float")
}
return DllCall("gdiplus\GdipAddPathPolygon", Ptr, Path, Ptr, &PointF, "int", Points0)
}
Gdip_DeletePath(Path)
{
return DllCall("gdiplus\GdipDeletePath", A_PtrSize ? "UPtr" : "UInt", Path)
}
;#####################################################################################
; Quality functions
;#####################################################################################
; SystemDefault = 0
; SingleBitPerPixelGridFit = 1
; SingleBitPerPixel = 2
; AntiAliasGridFit = 3
; AntiAlias = 4
Gdip_SetTextRenderingHint(pGraphics, RenderingHint)
{
return DllCall("gdiplus\GdipSetTextRenderingHint", A_PtrSize ? "UPtr" : "UInt", pGraphics, "int", RenderingHint)
}
; Default = 0
; LowQuality = 1
; HighQuality = 2
; Bilinear = 3
; Bicubic = 4
; NearestNeighbor = 5
; HighQualityBilinear = 6
; HighQualityBicubic = 7
Gdip_SetInterpolationMode(pGraphics, InterpolationMode)
{
return DllCall("gdiplus\GdipSetInterpolationMode", A_PtrSize ? "UPtr" : "UInt", pGraphics, "int", InterpolationMode)
}
; Default = 0
; HighSpeed = 1
; HighQuality = 2
; None = 3
; AntiAlias = 4
Gdip_SetSmoothingMode(pGraphics, SmoothingMode)
{
return DllCall("gdiplus\GdipSetSmoothingMode", A_PtrSize ? "UPtr" : "UInt", pGraphics, "int", SmoothingMode)
}
; CompositingModeSourceOver = 0 (blended)
; CompositingModeSourceCopy = 1 (overwrite)
Gdip_SetCompositingMode(pGraphics, CompositingMode=0)
{
return DllCall("gdiplus\GdipSetCompositingMode", A_PtrSize ? "UPtr" : "UInt", pGraphics, "int", CompositingMode)
}
;#####################################################################################
; Extra functions
;#####################################################################################
Gdip_Startup()
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
if !DllCall("GetModuleHandle", "str", "gdiplus", Ptr)
DllCall("LoadLibrary", "str", "gdiplus")
VarSetCapacity(si, A_PtrSize = 8 ? 24 : 16, 0), si := Chr(1)
DllCall("gdiplus\GdiplusStartup", A_PtrSize ? "UPtr*" : "uint*", pToken, Ptr, &si, Ptr, 0)
return pToken
}
Gdip_Shutdown(pToken)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
DllCall("gdiplus\GdiplusShutdown", Ptr, pToken)
if hModule := DllCall("GetModuleHandle", "str", "gdiplus", Ptr)
DllCall("FreeLibrary", Ptr, hModule)
return 0
}
; Prepend = 0; The new operation is applied before the old operation.
; Append = 1; The new operation is applied after the old operation.
Gdip_RotateWorldTransform(pGraphics, Angle, MatrixOrder=0)
{
return DllCall("gdiplus\GdipRotateWorldTransform", A_PtrSize ? "UPtr" : "UInt", pGraphics, "float", Angle, "int", MatrixOrder)
}
Gdip_ScaleWorldTransform(pGraphics, x, y, MatrixOrder=0)
{
return DllCall("gdiplus\GdipScaleWorldTransform", A_PtrSize ? "UPtr" : "UInt", pGraphics, "float", x, "float", y, "int", MatrixOrder)
}
Gdip_TranslateWorldTransform(pGraphics, x, y, MatrixOrder=0)
{
return DllCall("gdiplus\GdipTranslateWorldTransform", A_PtrSize ? "UPtr" : "UInt", pGraphics, "float", x, "float", y, "int", MatrixOrder)
}
Gdip_ResetWorldTransform(pGraphics)
{
return DllCall("gdiplus\GdipResetWorldTransform", A_PtrSize ? "UPtr" : "UInt", pGraphics)
}
Gdip_GetRotatedTranslation(Width, Height, Angle, ByRef xTranslation, ByRef yTranslation)
{
pi := 3.14159, TAngle := Angle*(pi/180)
Bound := (Angle >= 0) ? Mod(Angle, 360) : 360-Mod(-Angle, -360)
if ((Bound >= 0) && (Bound <= 90))
xTranslation := Height*Sin(TAngle), yTranslation := 0
else if ((Bound > 90) && (Bound <= 180))
xTranslation := (Height*Sin(TAngle))-(Width*Cos(TAngle)), yTranslation := -Height*Cos(TAngle)
else if ((Bound > 180) && (Bound <= 270))
xTranslation := -(Width*Cos(TAngle)), yTranslation := -(Height*Cos(TAngle))-(Width*Sin(TAngle))
else if ((Bound > 270) && (Bound <= 360))
xTranslation := 0, yTranslation := -Width*Sin(TAngle)
}
Gdip_GetRotatedDimensions(Width, Height, Angle, ByRef RWidth, ByRef RHeight)
{
pi := 3.14159, TAngle := Angle*(pi/180)
if !(Width && Height)
return -1
RWidth := Ceil(Abs(Width*Cos(TAngle))+Abs(Height*Sin(TAngle)))
RHeight := Ceil(Abs(Width*Sin(TAngle))+Abs(Height*Cos(Tangle)))
}
; RotateNoneFlipNone = 0
; Rotate90FlipNone = 1
; Rotate180FlipNone = 2
; Rotate270FlipNone = 3
; RotateNoneFlipX = 4
; Rotate90FlipX = 5
; Rotate180FlipX = 6
; Rotate270FlipX = 7
; RotateNoneFlipY = Rotate180FlipX
; Rotate90FlipY = Rotate270FlipX
; Rotate180FlipY = RotateNoneFlipX
; Rotate270FlipY = Rotate90FlipX
; RotateNoneFlipXY = Rotate180FlipNone
; Rotate90FlipXY = Rotate270FlipNone
; Rotate180FlipXY = RotateNoneFlipNone
; Rotate270FlipXY = Rotate90FlipNone
Gdip_ImageRotateFlip(pBitmap, RotateFlipType=1)
{
return DllCall("gdiplus\GdipImageRotateFlip", A_PtrSize ? "UPtr" : "UInt", pBitmap, "int", RotateFlipType)
}
; Replace = 0
; Intersect = 1
; Union = 2
; Xor = 3
; Exclude = 4
; Complement = 5
Gdip_SetClipRect(pGraphics, x, y, w, h, CombineMode=0)
{
return DllCall("gdiplus\GdipSetClipRect", A_PtrSize ? "UPtr" : "UInt", pGraphics, "float", x, "float", y, "float", w, "float", h, "int", CombineMode)
}
Gdip_SetClipPath(pGraphics, Path, CombineMode=0)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
return DllCall("gdiplus\GdipSetClipPath", Ptr, pGraphics, Ptr, Path, "int", CombineMode)
}
Gdip_ResetClip(pGraphics)
{
return DllCall("gdiplus\GdipResetClip", A_PtrSize ? "UPtr" : "UInt", pGraphics)
}
Gdip_GetClipRegion(pGraphics)
{
Region := Gdip_CreateRegion()
DllCall("gdiplus\GdipGetClip", A_PtrSize ? "UPtr" : "UInt", pGraphics, "UInt*", Region)
return Region
}
Gdip_SetClipRegion(pGraphics, Region, CombineMode=0)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
return DllCall("gdiplus\GdipSetClipRegion", Ptr, pGraphics, Ptr, Region, "int", CombineMode)
}
Gdip_CreateRegion()
{
DllCall("gdiplus\GdipCreateRegion", "UInt*", Region)
return Region
}
Gdip_DeleteRegion(Region)
{
return DllCall("gdiplus\GdipDeleteRegion", A_PtrSize ? "UPtr" : "UInt", Region)
}
;#####################################################################################
; BitmapLockBits
;#####################################################################################
Gdip_LockBits(pBitmap, x, y, w, h, ByRef Stride, ByRef Scan0, ByRef BitmapData, LockMode = 3, PixelFormat = 0x26200a)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
CreateRect(Rect, x, y, w, h)
VarSetCapacity(BitmapData, 16+2*(A_PtrSize ? A_PtrSize : 4), 0)
E := DllCall("Gdiplus\GdipBitmapLockBits", Ptr, pBitmap, Ptr, &Rect, "uint", LockMode, "int", PixelFormat, Ptr, &BitmapData)
Stride := NumGet(BitmapData, 8, "Int")
Scan0 := NumGet(BitmapData, 16, Ptr)
return E
}
;#####################################################################################
Gdip_UnlockBits(pBitmap, ByRef BitmapData)
{
Ptr := A_PtrSize ? "UPtr" : "UInt"
return DllCall("Gdiplus\GdipBitmapUnlockBits", Ptr, pBitmap, Ptr, &BitmapData)
}
;#####################################################################################
Gdip_SetLockBitPixel(ARGB, Scan0, x, y, Stride)
{
Numput(ARGB, Scan0+0, (x*4)+(y*Stride), "UInt")
}
;#####################################################################################
Gdip_GetLockBitPixel(Scan0, x, y, Stride)
{
return NumGet(Scan0+0, (x*4)+(y*Stride), "UInt")
}
;#####################################################################################
Gdip_PixelateBitmap(pBitmap, ByRef pBitmapOut, BlockSize)
{
static PixelateBitmap
Ptr := A_PtrSize ? "UPtr" : "UInt"
if (!PixelateBitmap)
{
if A_PtrSize != 8 ; x86 machine code
MCode_PixelateBitmap =
(LTrim Join
558BEC83EC3C8B4514538B5D1C99F7FB56578BC88955EC894DD885C90F8E830200008B451099F7FB8365DC008365E000894DC88955F08945E833FF897DD4
397DE80F8E160100008BCB0FAFCB894DCC33C08945F88945FC89451C8945143BD87E608B45088D50028BC82BCA8BF02BF2418945F48B45E02955F4894DC4
8D0CB80FAFCB03CA895DD08BD1895DE40FB64416030145140FB60201451C8B45C40FB604100145FC8B45F40FB604020145F883C204FF4DE475D6034D18FF
4DD075C98B4DCC8B451499F7F98945148B451C99F7F989451C8B45FC99F7F98945FC8B45F899F7F98945F885DB7E648B450C8D50028BC82BCA83C103894D
C48BC82BCA41894DF48B4DD48945E48B45E02955E48D0C880FAFCB03CA895DD08BD18BF38A45148B7DC48804178A451C8B7DF488028A45FC8804178A45F8
8B7DE488043A83C2044E75DA034D18FF4DD075CE8B4DCC8B7DD447897DD43B7DE80F8CF2FEFFFF837DF0000F842C01000033C08945F88945FC89451C8945
148945E43BD87E65837DF0007E578B4DDC034DE48B75E80FAF4D180FAFF38B45088D500203CA8D0CB18BF08BF88945F48B45F02BF22BFA2955F48945CC0F
B6440E030145140FB60101451C0FB6440F010145FC8B45F40FB604010145F883C104FF4DCC75D8FF45E4395DE47C9B8B4DF00FAFCB85C9740B8B451499F7
F9894514EB048365140033F63BCE740B8B451C99F7F989451CEB0389751C3BCE740B8B45FC99F7F98945FCEB038975FC3BCE740B8B45F899F7F98945F8EB
038975F88975E43BDE7E5A837DF0007E4C8B4DDC034DE48B75E80FAF4D180FAFF38B450C8D500203CA8D0CB18BF08BF82BF22BFA2BC28B55F08955CC8A55
1488540E038A551C88118A55FC88540F018A55F888140183C104FF4DCC75DFFF45E4395DE47CA68B45180145E0015DDCFF4DC80F8594FDFFFF8B451099F7
FB8955F08945E885C00F8E450100008B45EC0FAFC38365DC008945D48B45E88945CC33C08945F88945FC89451C8945148945103945EC7E6085DB7E518B4D
D88B45080FAFCB034D108D50020FAF4D18034DDC8BF08BF88945F403CA2BF22BFA2955F4895DC80FB6440E030145140FB60101451C0FB6440F010145FC8B
45F40FB604080145F883C104FF4DC875D8FF45108B45103B45EC7CA08B4DD485C9740B8B451499F7F9894514EB048365140033F63BCE740B8B451C99F7F9
89451CEB0389751C3BCE740B8B45FC99F7F98945FCEB038975FC3BCE740B8B45F899F7F98945F8EB038975F88975103975EC7E5585DB7E468B4DD88B450C
0FAFCB034D108D50020FAF4D18034DDC8BF08BF803CA2BF22BFA2BC2895DC88A551488540E038A551C88118A55FC88540F018A55F888140183C104FF4DC8
75DFFF45108B45103B45EC7CAB8BC3C1E0020145DCFF4DCC0F85CEFEFFFF8B4DEC33C08945F88945FC89451C8945148945103BC87E6C3945F07E5C8B4DD8
8B75E80FAFCB034D100FAFF30FAF4D188B45088D500203CA8D0CB18BF08BF88945F48B45F02BF22BFA2955F48945C80FB6440E030145140FB60101451C0F
B6440F010145FC8B45F40FB604010145F883C104FF4DC875D833C0FF45108B4DEC394D107C940FAF4DF03BC874068B451499F7F933F68945143BCE740B8B
451C99F7F989451CEB0389751C3BCE740B8B45FC99F7F98945FCEB038975FC3BCE740B8B45F899F7F98945F8EB038975F88975083975EC7E63EB0233F639
75F07E4F8B4DD88B75E80FAFCB034D080FAFF30FAF4D188B450C8D500203CA8D0CB18BF08BF82BF22BFA2BC28B55F08955108A551488540E038A551C8811
8A55FC88540F018A55F888140883C104FF4D1075DFFF45088B45083B45EC7C9F5F5E33C05BC9C21800
)
else ; x64 machine code
MCode_PixelateBitmap =
(LTrim Join
4489442418488954241048894C24085355565741544155415641574883EC28418BC1448B8C24980000004C8BDA99488BD941F7F9448BD0448BFA8954240C
448994248800000085C00F8E9D020000418BC04533E4458BF299448924244C8954241041F7F933C9898C24980000008BEA89542404448BE889442408EB05
4C8B5C24784585ED0F8E1A010000458BF1418BFD48897C2418450FAFF14533D233F633ED4533E44533ED4585C97E5B4C63BC2490000000418D040A410FAF
C148984C8D441802498BD9498BD04D8BD90FB642010FB64AFF4403E80FB60203E90FB64AFE4883C2044403E003F149FFCB75DE4D03C748FFCB75D0488B7C
24188B8C24980000004C8B5C2478418BC59941F7FE448BE8418BC49941F7FE448BE08BC59941F7FE8BE88BC69941F7FE8BF04585C97E4048639C24900000
004103CA4D8BC1410FAFC94863C94A8D541902488BCA498BC144886901448821408869FF408871FE4883C10448FFC875E84803D349FFC875DA8B8C249800
0000488B5C24704C8B5C24784183C20448FFCF48897C24180F850AFFFFFF8B6C2404448B2424448B6C24084C8B74241085ED0F840A01000033FF33DB4533
DB4533D24533C04585C97E53488B74247085ED7E42438D0C04418BC50FAF8C2490000000410FAFC18D04814863C8488D5431028BCD0FB642014403D00FB6
024883C2044403D80FB642FB03D80FB642FA03F848FFC975DE41FFC0453BC17CB28BCD410FAFC985C9740A418BC299F7F98BF0EB0233F685C9740B418BC3
99F7F9448BD8EB034533DB85C9740A8BC399F7F9448BD0EB034533D285C9740A8BC799F7F9448BC0EB034533C033D24585C97E4D4C8B74247885ED7E3841
8D0C14418BC50FAF8C2490000000410FAFC18D04814863C84A8D4431028BCD40887001448818448850FF448840FE4883C00448FFC975E8FFC2413BD17CBD
4C8B7424108B8C2498000000038C2490000000488B5C24704503E149FFCE44892424898C24980000004C897424100F859EFDFFFF448B7C240C448B842480
000000418BC09941F7F98BE8448BEA89942498000000896C240C85C00F8E3B010000448BAC2488000000418BCF448BF5410FAFC9898C248000000033FF33
ED33F64533DB4533D24533C04585FF7E524585C97E40418BC5410FAFC14103C00FAF84249000000003C74898488D541802498BD90FB642014403D00FB602
4883C2044403D80FB642FB03F00FB642FA03E848FFCB75DE488B5C247041FFC0453BC77CAE85C9740B418BC299F7F9448BE0EB034533E485C9740A418BC3
99F7F98BD8EB0233DB85C9740A8BC699F7F9448BD8EB034533DB85C9740A8BC599F7F9448BD0EB034533D24533C04585FF7E4E488B4C24784585C97E3541
8BC5410FAFC14103C00FAF84249000000003C74898488D540802498BC144886201881A44885AFF448852FE4883C20448FFC875E941FFC0453BC77CBE8B8C
2480000000488B5C2470418BC1C1E00203F849FFCE0F85ECFEFFFF448BAC24980000008B6C240C448BA4248800000033FF33DB4533DB4533D24533C04585
FF7E5A488B7424704585ED7E48418BCC8BC5410FAFC94103C80FAF8C2490000000410FAFC18D04814863C8488D543102418BCD0FB642014403D00FB60248
83C2044403D80FB642FB03D80FB642FA03F848FFC975DE41FFC0453BC77CAB418BCF410FAFCD85C9740A418BC299F7F98BF0EB0233F685C9740B418BC399
F7F9448BD8EB034533DB85C9740A8BC399F7F9448BD0EB034533D285C9740A8BC799F7F9448BC0EB034533C033D24585FF7E4E4585ED7E42418BCC8BC541
0FAFC903CA0FAF8C2490000000410FAFC18D04814863C8488B442478488D440102418BCD40887001448818448850FF448840FE4883C00448FFC975E8FFC2
413BD77CB233C04883C428415F415E415D415C5F5E5D5BC3
)
VarSetCapacity(PixelateBitmap, StrLen(MCode_PixelateBitmap)//2)
Loop % StrLen(MCode_PixelateBitmap)//2 ;%
NumPut("0x" SubStr(MCode_PixelateBitmap, (2*A_Index)-1, 2), PixelateBitmap, A_Index-1, "UChar")
DllCall("VirtualProtect", Ptr, &PixelateBitmap, Ptr, VarSetCapacity(PixelateBitmap), "uint", 0x40, A_PtrSize ? "UPtr*" : "UInt*", 0)
}
Gdip_GetImageDimensions(pBitmap, Width, Height)
if (Width != Gdip_GetImageWidth(pBitmapOut) || Height != Gdip_GetImageHeight(pBitmapOut))
return -1
if (BlockSize > Width || BlockSize > Height)
return -2
E1 := Gdip_LockBits(pBitmap, 0, 0, Width, Height, Stride1, Scan01, BitmapData1)
E2 := Gdip_LockBits(pBitmapOut, 0, 0, Width, Height, Stride2, Scan02, BitmapData2)
if (E1 || E2)
return -3
E := DllCall(&PixelateBitmap, Ptr, Scan01, Ptr, Scan02, "int", Width, "int", Height, "int", Stride1, "int", BlockSize)
Gdip_UnlockBits(pBitmap, BitmapData1), Gdip_UnlockBits(pBitmapOut, BitmapData2)
return 0
}
;#####################################################################################
Gdip_ToARGB(A, R, G, B)
{
return (A << 24) | (R << 16) | (G << 8) | B
}
;#####################################################################################
Gdip_FromARGB(ARGB, ByRef A, ByRef R, ByRef G, ByRef B)
{
A := (0xff000000 & ARGB) >> 24
R := (0x00ff0000 & ARGB) >> 16
G := (0x0000ff00 & ARGB) >> 8
B := 0x000000ff & ARGB
}
;#####################################################################################
Gdip_AFromARGB(ARGB)
{
return (0xff000000 & ARGB) >> 24
}
;#####################################################################################
Gdip_RFromARGB(ARGB)
{
return (0x00ff0000 & ARGB) >> 16
}
;#####################################################################################
Gdip_GFromARGB(ARGB)
{
return (0x0000ff00 & ARGB) >> 8
}
;#####################################################################################
Gdip_BFromARGB(ARGB)
{
return 0x000000ff & ARGB
}
;#####################################################################################
StrGetB(Address, Length=-1, Encoding=0)
{
; Flexible parameter handling:
if Length is not integer
Encoding := Length, Length := -1
; Check for obvious errors.
if (Address+0 < 1024)
return
; Ensure 'Encoding' contains a numeric identifier.
if Encoding = UTF-16
Encoding = 1200
else if Encoding = UTF-8
Encoding = 65001
else if SubStr(Encoding,1,2)="CP"
Encoding := SubStr(Encoding,3)
if !Encoding ; "" or 0
{
; No conversion necessary, but we might not want the whole string.
if (Length == -1)
Length := DllCall("lstrlen", "uint", Address)
VarSetCapacity(String, Length)
DllCall("lstrcpyn", "str", String, "uint", Address, "int", Length + 1)
}
else if Encoding = 1200 ; UTF-16
{
char_count := DllCall("WideCharToMultiByte", "uint", 0, "uint", 0x400, "uint", Address, "int", Length, "uint", 0, "uint", 0, "uint", 0, "uint", 0)
VarSetCapacity(String, char_count)
DllCall("WideCharToMultiByte", "uint", 0, "uint", 0x400, "uint", Address, "int", Length, "str", String, "int", char_count, "uint", 0, "uint", 0)
}
else if Encoding is integer
{
; Convert from target encoding to UTF-16 then to the active code page.
char_count := DllCall("MultiByteToWideChar", "uint", Encoding, "uint", 0, "uint", Address, "int", Length, "uint", 0, "int", 0)
VarSetCapacity(String, char_count * 2)
char_count := DllCall("MultiByteToWideChar", "uint", Encoding, "uint", 0, "uint", Address, "int", Length, "uint", &String, "int", char_count * 2)
String := StrGetB(&String, char_count, 1200)
}
return String
}
class GlobalContainer {
__New(name) {
for wnd in ComObjCreate("Shell.Application").Windows {
if (wnd.GetProperty("container_name") = name)
this._obj := wnd
}
if !this._obj {
this._obj := ComObjGet("new:{C08AFD90-F2A1-11D1-8455-00A0C91F3880}")
this._obj.PutProperty("container_name", name)
}
}
__Set(prop, value) {
if prop not in _obj,_userFunc
try
Return this._obj.PutProperty(prop, value)
catch{}
}
__Get(prop) {
if (prop != "_obj")
try
Return this._obj.GetProperty(prop)
catch{}
}
Connect(userFunc) {
this._userFunc := userFunc.Bind(this)
ComObjConnect(this._obj, this)
}
PropertyChange(prop, obj) {
this._userFunc.Call(prop)
}
Quit() {
try
this._obj.Quit()
catch{}
}
}
/*
A basic memory class by RHCP:
https://github.com/Kalamity/classMemory
This is a wrapper for commonly used read and write memory functions.
It also contains a variety of pattern scan functions.
This class allows scripts to read/write integers and strings of various types.
Pointer addresses can easily be read/written by passing the base address and offsets to the various read/write functions.
Process handles are kept open between reads. This increases speed.
However, if a program closes/restarts then the process handle will become invalid
and you will need to re-open another handle (blank/destroy the object and recreate it)
isHandleValid() can be used to check if a handle is still active/valid.
read(), readString(), write(), and writeString() can be used to read and write memory addresses respectively.
readRaw() can be used to dump large chunks of memory, this is considerably faster when
reading data from a large structure compared to repeated calls to read().
For example, reading a single UInt takes approximately the same amount of time as reading 1000 bytes via readRaw().
Although, most people wouldn't notice the performance difference. This does however require you
to retrieve the values using AHK's numget()/strGet() from the dumped memory.
In a similar fashion writeRaw() allows a buffer to be be written in a single operation.
When the new operator is used this class returns an object which can be used to read that process's
memory space.To read another process simply create another object.
Process handles are automatically closed when the script exits/restarts or when you free the object.
**Notes:
This was initially written for 32 bit target processes, however the various read/write functions
should now completely support pointers in 64 bit target applications. The only caveat is that the AHK exe must also be 64 bit.
If AHK is 32 bit and the target application is 64 bit you can still read, write, and use pointers, so long as the addresses
fit inside a 4 byte pointer, i.e. The maximum address is limited to the 32 bit range.
The various pattern scan functions are intended to be used on 32 bit target applications, however:
- A 32 bit AHK script can perform pattern scans on a 32 bit target application.
- A 32 bit AHK script may be able to perform pattern scans on a 64 bit process, providing the addresses fall within the 32 bit range.
- A 64 bit AHK script should be able to perform pattern scans on a 32 or 64 bit target application without issue.
If the target process has admin privileges, then the AHK script will also require admin privileges.
AHK doesn't support unsigned 64bit ints, you can however read them as Int64 and interpret negative values as large numbers.
Commonly used methods:
read()
readString()
readRaw()
write()
writeString()
writeBytes()
writeRaw()
isHandleValid()
getModuleBaseAddress()
Less commonly used methods:
getProcessBaseAddress()
hexStringToPattern()
stringToPattern()
modulePatternScan()
processPatternScan()
addressPatternScan()
rawPatternScan()
getModules()
numberOfBytesRead()
numberOfBytesWritten()
suspend()
resume()
Internal methods: (some may be useful when directly called)
getAddressFromOffsets() ; This will return the final memory address of a pointer. This is useful if the pointed address only changes on startup or map/level change and you want to eliminate the overhead associated with pointers.
isTargetProcess64Bit()
pointer()
GetModuleFileNameEx()
EnumProcessModulesEx()
GetModuleInformation()
getNeedleFromAOBPattern()
virtualQueryEx()
patternScan()
bufferScanForMaskedPattern()
openProcess()
closeHandle()
Useful properties: (Do not modify the values of these properties - they are set automatically)
baseAddress ; The base address of the target process
hProcess ; The handle to the target process
PID ; The PID of the target process
currentProgram ; The string the user used to identify the target process e.g. "ahk_exe calc.exe"
isTarget64bit ; True if target process is 64 bit, otherwise false
readStringLastError ; Used to check for success/failure when reading a string
Useful editable properties:
insertNullTerminator ; Determines if a null terminator is inserted when writing strings.
Usage:
; **Note: If you wish to try this calc example, consider using the 32 bit version of calc.exe -
; which is in C:\Windows\SysWOW64\calc.exe on win7 64 bit systems.
; The contents of this file can be copied directly into your script. Alternately, you can copy the classMemory.ahk file into your library folder,
; in which case you will need to use the #include directive in your script i.e.
#Include <classMemory>
; You can use this code to check if you have installed the class correctly.
if (_ClassMemory.__Class != "_ClassMemory")
{
msgbox class memory not correctly installed. Or the (global class) variable "_ClassMemory" has been overwritten
ExitApp
}
; Open a process with sufficient access to read and write memory addresses (this is required before you can use the other functions)
; You only need to do this once. But if the process closes/restarts, then you will need to perform this step again. Refer to the notes section below.
; Also, if the target process is running as admin, then the script will also require admin rights!
; Note: The program identifier can be any AHK windowTitle i.e.ahk_exe, ahk_class, ahk_pid, or simply the window title.
; hProcessCopy is an optional variable in which the opened handled is stored.
calc := new _ClassMemory("ahk_exe calc.exe", "", hProcessCopy)
; Check if the above method was successful.
if !isObject(calc)
{
msgbox failed to open a handle
if (hProcessCopy = 0)
msgbox The program isn't running (not found) or you passed an incorrect program identifier parameter. In some cases _ClassMemory.setSeDebugPrivilege() may be required.
else if (hProcessCopy = "")
msgbox OpenProcess failed. If the target process has admin rights, then the script also needs to be ran as admin. _ClassMemory.setSeDebugPrivilege() may also be required. Consult A_LastError for more information.
ExitApp
}
; Get the process's base address.
; When using the new operator this property is automatically set to the result of getModuleBaseAddress() or getProcessBaseAddress();
; the specific method used depends on the bitness of the target application and AHK.
; If the returned address is incorrect and the target application is 64 bit, but AHK is 32 bit, try using the 64 bit version of AHK.
msgbox % calc.BaseAddress
; Get the base address of a specific module.
msgbox % calc.getModuleBaseAddress("GDI32.dll")
; The rest of these examples are just for illustration (the addresses specified are probably not valid).
; You can use cheat engine to find real addresses to read and write for testing purposes.
; Write 1234 as a UInt at address 0x0016CB60.
calc.write(0x0016CB60, 1234, "UInt")
; Read a UInt.
value := calc.read(0x0016CB60, "UInt")
; Read a pointer with offsets 0x20 and 0x15C which points to a UChar.
value := calc.read(pointerBase, "UChar", 0x20, 0x15C)
; Note: read(), readString(), readRaw(), write(), writeString(), and writeRaw() all support pointers/offsets.
; An array of pointers can be passed directly, i.e.
arrayPointerOffsets := [0x20, 0x15C]
value := calc.read(pointerBase, "UChar", arrayPointerOffsets*)
; Or they can be entered manually.
value := calc.read(pointerBase, "UChar", 0x20, 0x15C)
; You can also pass all the parameters directly, i.e.
aMyPointer := [pointerBase, "UChar", 0x20, 0x15C]
value := calc.read(aMyPointer*)
; Read a utf-16 null terminated string of unknown size at address 0x1234556 - the function will read until the null terminator is found or something goes wrong.
string := calc.readString(0x1234556, length := 0, encoding := "utf-16")
; Read a utf-8 encoded string which is 12 bytes long at address 0x1234556.
string := calc.readString(0x1234556, 12)
; By default a null terminator is included at the end of written strings for writeString().
; The nullterminator property can be used to change this.
_ClassMemory.insertNullTerminator := False ; This will change the property for all processes
calc.insertNullTerminator := False ; Changes the property for just this process
Notes:
If the target process exits and then starts again (or restarts) you will need to free the derived object and then use the new operator to create a new object i.e.
calc := [] ; or calc := "" ; free the object. This is actually optional if using the line below, as the line below would free the previous derived object calc prior to initialising the new copy.
calc := new _ClassMemory("ahk_exe calc.exe") ; Create a new derived object to read calc's memory.
isHandleValid() can be used to check if a target process has closed or restarted.
*/
class _ClassMemory
{
; List of useful accessible values. Some of these inherited values (the non objects) are set when the new operator is used.
static baseAddress, hProcess, PID, currentProgram
, insertNullTerminator := True
, readStringLastError := False
, isTarget64bit := False
, ptrType := "UInt"
, aTypeSize := { "UChar": 1, "Char": 1
, "UShort": 2, "Short": 2
, "UInt": 4, "Int": 4
, "UFloat": 4, "Float": 4
, "Int64": 8, "Double": 8}
, aRights := { "PROCESS_ALL_ACCESS": 0x001F0FFF
, "PROCESS_CREATE_PROCESS": 0x0080
, "PROCESS_CREATE_THREAD": 0x0002
, "PROCESS_DUP_HANDLE": 0x0040
, "PROCESS_QUERY_INFORMATION": 0x0400
, "PROCESS_QUERY_LIMITED_INFORMATION": 0x1000
, "PROCESS_SET_INFORMATION": 0x0200
, "PROCESS_SET_QUOTA": 0x0100
, "PROCESS_SUSPEND_RESUME": 0x0800
, "PROCESS_TERMINATE": 0x0001
, "PROCESS_VM_OPERATION": 0x0008
, "PROCESS_VM_READ": 0x0010
, "PROCESS_VM_WRITE": 0x0020
, "SYNCHRONIZE": 0x00100000}
; Method: __new(program, dwDesiredAccess := "", byRef handle := "", windowMatchMode := 3)
; Example: derivedObject := new _ClassMemory("ahk_exe calc.exe")
; This is the first method which should be called when trying to access a program's memory.
; If the process is successfully opened, an object is returned which can be used to read that processes memory space.
; [derivedObject].hProcess stores the opened handle.
; If the target process closes and re-opens, simply free the derived object and use the new operator again to open a new handle.
; Parameters:
; program The program to be opened. This can be any AHK windowTitle identifier, such as
; ahk_exe, ahk_class, ahk_pid, or simply the window title. e.g. "ahk_exe calc.exe" or "Calculator".
; It's safer not to use the window title, as some things can have the same window title e.g. an open folder called "Starcraft II"
; would have the same window title as the game itself.
; *'DetectHiddenWindows, On' is required for hidden windows*
; dwDesiredAccess The access rights requested when opening the process.
; If this parameter is null the process will be opened with the following rights
; PROCESS_QUERY_INFORMATION, PROCESS_VM_OPERATION, PROCESS_VM_READ, PROCESS_VM_WRITE, & SYNCHRONIZE
; This access level is sufficient to allow all of the methods in this class to work.
; Specific process access rights are listed here http://msdn.microsoft.com/en-us/library/windows/desktop/ms684880(v=vs.85).aspx
; handle (Output) Optional variable in which a copy of the opened processes handle will be stored.
; Values:
; Null OpenProcess failed. The script may need to be run with admin rights admin,
; and/or with the use of _ClassMemory.setSeDebugPrivilege(). Consult A_LastError for more information.
; 0 The program isn't running (not found) or you passed an incorrect program identifier parameter.
; In some cases _ClassMemory.setSeDebugPrivilege() may be required.
; Positive Integer A handle to the process. (Success)
; windowMatchMode - Determines the matching mode used when finding the program (windowTitle).
; The default value is 3 i.e. an exact match. Refer to AHK's setTitleMathMode for more information.
; Return Values:
; Object On success an object is returned which can be used to read the processes memory.
; Null Failure. A_LastError and the optional handle parameter can be consulted for more information.
__new(program, dwDesiredAccess := "", byRef handle := "", windowMatchMode := 3)
{
if this.PID := handle := this.findPID(program, windowMatchMode) ; set handle to 0 if program not found
{
; This default access level is sufficient to read and write memory addresses, and to perform pattern scans.
; if the program is run using admin privileges, then this script will also need admin privileges
if dwDesiredAccess is not integer
dwDesiredAccess := this.aRights.PROCESS_QUERY_INFORMATION | this.aRights.PROCESS_VM_OPERATION | this.aRights.PROCESS_VM_READ | this.aRights.PROCESS_VM_WRITE
dwDesiredAccess |= this.aRights.SYNCHRONIZE ; add SYNCHRONIZE to all handles to allow isHandleValid() to work
if this.hProcess := handle := this.OpenProcess(this.PID, dwDesiredAccess) ; NULL/Blank if failed to open process for some reason
{
this.pNumberOfBytesRead := DllCall("GlobalAlloc", "UInt", 0x0040, "Ptr", A_PtrSize, "Ptr") ; 0x0040 initialise to 0
this.pNumberOfBytesWritten := DllCall("GlobalAlloc", "UInt", 0x0040, "Ptr", A_PtrSize, "Ptr") ; initialise to 0
this.readStringLastError := False
this.currentProgram := program
if this.isTarget64bit := this.isTargetProcess64Bit(this.PID, this.hProcess, dwDesiredAccess)
this.ptrType := "Int64"
else this.ptrType := "UInt" ; If false or Null (fails) assume 32bit
; if script is 64 bit, getModuleBaseAddress() should always work
; if target app is truly 32 bit, then getModuleBaseAddress()
; will work when script is 32 bit
if (A_PtrSize != 4 || !this.isTarget64bit)
this.BaseAddress := this.getModuleBaseAddress()
; If the above failed or wasn't called, fall back to alternate method
if this.BaseAddress < 0 || !this.BaseAddress
this.BaseAddress := this.getProcessBaseAddress(program, windowMatchMode)
return this
}
}
return
}
__delete()
{
this.closeHandle(this.hProcess)
if this.pNumberOfBytesRead
DllCall("GlobalFree", "Ptr", this.pNumberOfBytesRead)
if this.pNumberOfBytesWritten
DllCall("GlobalFree", "Ptr", this.pNumberOfBytesWritten)
return
}
version()
{
return 2.92
}
findPID(program, windowMatchMode := "3")
{
; If user passes an AHK_PID, don't bother searching. There are cases where searching windows for PIDs
; wont work - console apps
if RegExMatch(program, "i)\s*AHK_PID\s+(0x[[:xdigit:]]+|\d+)", pid)
return pid1
if windowMatchMode
{
; This is a string and will not contain the 0x prefix
mode := A_TitleMatchMode
; remove hex prefix as SetTitleMatchMode will throw a run time error. This will occur if integer mode is set to hex and user passed an int (unquoted)
StringReplace, windowMatchMode, windowMatchMode, 0x
SetTitleMatchMode, %windowMatchMode%
}
WinGet, pid, pid, %program%
if windowMatchMode
SetTitleMatchMode, %mode% ; In case executed in autoexec
; If use 'ahk_exe test.exe' and winget fails (which can happen when setSeDebugPrivilege is required),
; try using the process command. When it fails due to setSeDebugPrivilege, setSeDebugPrivilege will still be required to openProcess
; This should also work for apps without windows.
if (!pid && RegExMatch(program, "i)\bAHK_EXE\b\s*(.*)", fileName))
{
; remove any trailing AHK_XXX arguments
filename := RegExReplace(filename1, "i)\bahk_(class|id|pid|group)\b.*", "")
filename := trim(filename) ; extra spaces will make process command fail
; AHK_EXE can be the full path, so just get filename
SplitPath, fileName , fileName
if (fileName) ; if filename blank, scripts own pid is returned
{
process, Exist, %fileName%
pid := ErrorLevel
}
}
return pid ? pid : 0 ; PID is null on fail, return 0
}
; Method: isHandleValid()
; This method provides a means to check if the internal process handle is still valid
; or in other words, the specific target application instance (which you have been reading from)
; has closed or restarted.
; For example, if the target application closes or restarts the handle will become invalid
; and subsequent calls to this method will return false.
;
; Return Values:
; True The handle is valid.
; False The handle is not valid.
;
; Notes:
; This operation requires a handle with SYNCHRONIZE access rights.
; All handles, even user specified ones are opened with the SYNCHRONIZE access right.
isHandleValid()
{
return 0x102 = DllCall("WaitForSingleObject", "Ptr", this.hProcess, "UInt", 0)
; WaitForSingleObject return values
; -1 if called with null hProcess (sets lastError to 6 - invalid handle)
; 258 / 0x102 WAIT_TIMEOUT - if handle is valid (process still running)
; 0 WAIT_OBJECT_0 - if process has terminated
}
; Method: openProcess(PID, dwDesiredAccess)
; ***Note: This is an internal method which shouldn't be called directly unless you absolutely know what you are doing.
; This is because the new operator, in addition to calling this method also sets other values
; which are required for the other methods to work correctly.
; Parameters:
; PID The Process ID of the target process.
; dwDesiredAccess The access rights requested when opening the process.
; Specific process access rights are listed here http://msdn.microsoft.com/en-us/library/windows/desktop/ms684880(v=vs.85).aspx
; Return Values:
; Null/blank OpenProcess failed. If the target process has admin rights, then the script also needs to be ran as admin.
; _ClassMemory.setSeDebugPrivilege() may also be required.
; Positive integer A handle to the process.
openProcess(PID, dwDesiredAccess)
{
r := DllCall("OpenProcess", "UInt", dwDesiredAccess, "Int", False, "UInt", PID, "Ptr")
; if it fails with 0x5 ERROR_ACCESS_DENIED, try enabling privilege ... lots of users never try this.
; there may be other errors which also require DebugPrivilege....
if (!r && A_LastError = 5)
{
this.setSeDebugPrivilege(true) ; no harm in enabling it if it is already enabled by user
if (r2 := DllCall("OpenProcess", "UInt", dwDesiredAccess, "Int", False, "UInt", PID, "Ptr"))
return r2
DllCall("SetLastError", "UInt", 5) ; restore original error if it doesnt work
}
; If fails with 0x5 ERROR_ACCESS_DENIED (when setSeDebugPrivilege() is req.), the func. returns 0 rather than null!! Set it to null.
; If fails for another reason, then it is null.
return r ? r : ""
}
; Method: closeHandle(hProcess)
; Note: This is an internal method which is automatically called when the script exits or the derived object is freed/destroyed.
; There is no need to call this method directly. If you wish to close the handle simply free the derived object.
; i.e. derivedObject := [] ; or derivedObject := ""
; Parameters:
; hProcess The handle to the process, as returned by openProcess().
; Return Values:
; Non-Zero Success
; 0 Failure
closeHandle(hProcess)
{
return DllCall("CloseHandle", "Ptr", hProcess)
}
; Methods: numberOfBytesRead() / numberOfBytesWritten()
; Returns the number of bytes read or written by the last ReadProcessMemory or WriteProcessMemory operation.
;
; Return Values:
; zero or positive value Number of bytes read/written
; -1 Failure. Shouldn't occur
numberOfBytesRead()
{
return !this.pNumberOfBytesRead ? -1 : NumGet(this.pNumberOfBytesRead+0, "Ptr")
}
numberOfBytesWritten()
{
return !this.pNumberOfBytesWritten ? -1 : NumGet(this.pNumberOfBytesWritten+0, "Ptr")
}
; Method: read(address, type := "UInt", aOffsets*)
; Reads various integer type values
; Parameters:
; address - The memory address of the value or if using the offset parameter,
; the base address of the pointer.
; type - The integer type.
; Valid types are UChar, Char, UShort, Short, UInt, Int, Float, Int64 and Double.
; Note: Types must not contain spaces i.e. " UInt" or "UInt " will not work.
; When an invalid type is passed the method returns NULL and sets ErrorLevel to -2
; aOffsets* - A variadic list of offsets. When using offsets the address parameter should equal the base address of the pointer.
; The address (base address) and offsets should point to the memory address which holds the integer.
; Return Values:
; integer - Indicates success.
; Null - Indicates failure. Check ErrorLevel and A_LastError for more information.
; Note: Since the returned integer value may be 0, to check for success/failure compare the result
; against null i.e. if (result = "") then an error has occurred.
; When reading doubles, adjusting "SetFormat, float, totalWidth.DecimalPlaces"
; may be required depending on your requirements.
read(address, type := "UInt", aOffsets*)
{
; If invalid type RPM() returns success (as bytes to read resolves to null in dllCall())
; so set errorlevel to invalid parameter for DLLCall() i.e. -2
if !this.aTypeSize.hasKey(type)
return "", ErrorLevel := -2
if DllCall("ReadProcessMemory", "Ptr", this.hProcess, "Ptr", aOffsets.maxIndex() ? this.getAddressFromOffsets(address, aOffsets*) : address, type "*", result, "Ptr", this.aTypeSize[type], "Ptr", this.pNumberOfBytesRead)
return result
return
}
; Method: readRaw(address, byRef buffer, bytes := 4, aOffsets*)
; Reads an area of the processes memory and stores it in the buffer variable
; Parameters:
; address - The memory address of the area to read or if using the offsets parameter
; the base address of the pointer which points to the memory region.
; buffer - The unquoted variable name for the buffer. This variable will receive the contents from the address space.
; This method calls varsetCapcity() to ensure the variable has an adequate size to perform the operation.
; If the variable already has a larger capacity (from a previous call to varsetcapcity()), then it will not be shrunk.
; Therefore it is the callers responsibility to ensure that any subsequent actions performed on the buffer variable
; do not exceed the bytes which have been read - as these remaining bytes could contain anything.
; bytes - The number of bytes to be read.
; aOffsets* - A variadic list of offsets. When using offsets the address parameter should equal the base address of the pointer.
; The address (base address) and offsets should point to the memory address which is to be read
; Return Values:
; Non Zero - Indicates success.
; Zero - Indicates failure. Check errorLevel and A_LastError for more information
;
; Notes: The contents of the buffer may then be retrieved using AHK's NumGet() and StrGet() functions.
; This method offers significant (~30% and up) performance boost when reading large areas of memory.
; As calling ReadProcessMemory for four bytes takes a similar amount of time as it does for 1,000 bytes.
readRaw(address, byRef buffer, bytes := 4, aOffsets*)
{
VarSetCapacity(buffer, bytes)
return DllCall("ReadProcessMemory", "Ptr", this.hProcess, "Ptr", aOffsets.maxIndex() ? this.getAddressFromOffsets(address, aOffsets*) : address, "Ptr", &buffer, "Ptr", bytes, "Ptr", this.pNumberOfBytesRead)
}
; Method: readString(address, sizeBytes := 0, encoding := "utf-8", aOffsets*)
; Reads string values of various encoding types
; Parameters:
; address - The memory address of the value or if using the offset parameter,
; the base address of the pointer.
; sizeBytes - The size (in bytes) of the string to be read.
; If zero is passed, then the function will read each character until a null terminator is found
; and then returns the entire string.
; encoding - This refers to how the string is stored in the program's memory.
; UTF-8 and UTF-16 are common. Refer to the AHK manual for other encoding types.
; aOffsets* - A variadic list of offsets. When using offsets the address parameter should equal the base address of the pointer.
; The address (base address) and offsets should point to the memory address which holds the string.
;
; Return Values:
; String - On failure an empty (null) string is always returned. Since it's possible for the actual string
; being read to be null (empty), then a null return value should not be used to determine failure of the method.
; Instead the property [derivedObject].ReadStringLastError can be used to check for success/failure.
; This property is set to 0 on success and 1 on failure. On failure ErrorLevel and A_LastError should be consulted
; for more information.
; Notes:
; For best performance use the sizeBytes parameter to specify the exact size of the string.
; If the exact size is not known and the string is null terminated, then specifying the maximum
; possible size of the string will yield the same performance.
; If neither the actual or maximum size is known and the string is null terminated, then specifying
; zero for the sizeBytes parameter is fine. Generally speaking for all intents and purposes the performance difference is
; inconsequential.
readString(address, sizeBytes := 0, encoding := "UTF-8", aOffsets*)
{
bufferSize := VarSetCapacity(buffer, sizeBytes ? sizeBytes : 100, 0)
this.ReadStringLastError := False
if aOffsets.maxIndex()
address := this.getAddressFromOffsets(address, aOffsets*)
if !sizeBytes ; read until null terminator is found or something goes wrong
{
; Even if there are multi-byte-characters (bigger than the encodingSize i.e. surrogates) in the string, when reading in encodingSize byte chunks they will never register as null (as they will have bits set on those bytes)
if (encoding = "utf-16" || encoding = "cp1200")
encodingSize := 2, charType := "UShort", loopCount := 2
else encodingSize := 1, charType := "Char", loopCount := 4
Loop
{ ; Lets save a few reads by reading in 4 byte chunks
if !DllCall("ReadProcessMemory", "Ptr", this.hProcess, "Ptr", address + ((outterIndex := A_index) - 1) * 4, "Ptr", &buffer, "Ptr", 4, "Ptr", this.pNumberOfBytesRead) || ErrorLevel
return "", this.ReadStringLastError := True
else loop, %loopCount%
{
if NumGet(buffer, (A_Index - 1) * encodingSize, charType) = 0 ; NULL terminator
{
if (bufferSize < sizeBytes := outterIndex * 4 - (4 - A_Index * encodingSize))
VarSetCapacity(buffer, sizeBytes)
break, 2
}
}
}
}
if DllCall("ReadProcessMemory", "Ptr", this.hProcess, "Ptr", address, "Ptr", &buffer, "Ptr", sizeBytes, "Ptr", this.pNumberOfBytesRead)
return StrGet(&buffer,, encoding)
return "", this.ReadStringLastError := True
}
; Method: writeString(address, string, encoding := "utf-8", aOffsets*)
; Encodes and then writes a string to the process.
; Parameters:
; address - The memory address to which data will be written or if using the offset parameter,
; the base address of the pointer.
; string - The string to be written.
; encoding - This refers to how the string is to be stored in the program's memory.
; UTF-8 and UTF-16 are common. Refer to the AHK manual for other encoding types.
; aOffsets* - A variadic list of offsets. When using offsets the address parameter should equal the base address of the pointer.
; The address (base address) and offsets should point to the memory address which is to be written to.
; Return Values:
; Non Zero - Indicates success.
; Zero - Indicates failure. Check errorLevel and A_LastError for more information
; Notes:
; By default a null terminator is included at the end of written strings.
; This behaviour is determined by the property [derivedObject].insertNullTerminator
; If this property is true, then a null terminator will be included.
writeString(address, string, encoding := "utf-8", aOffsets*)
{
encodingSize := (encoding = "utf-16" || encoding = "cp1200") ? 2 : 1
requiredSize := StrPut(string, encoding) * encodingSize - (this.insertNullTerminator ? 0 : encodingSize)
VarSetCapacity(buffer, requiredSize)
StrPut(string, &buffer, StrLen(string) + (this.insertNullTerminator ? 1 : 0), encoding)
return DllCall("WriteProcessMemory", "Ptr", this.hProcess, "Ptr", aOffsets.maxIndex() ? this.getAddressFromOffsets(address, aOffsets*) : address, "Ptr", &buffer, "Ptr", requiredSize, "Ptr", this.pNumberOfBytesWritten)
}
; Method: write(address, value, type := "Uint", aOffsets*)
; Writes various integer type values to the process.
; Parameters:
; address - The memory address to which data will be written or if using the offset parameter,
; the base address of the pointer.
; type - The integer type.
; Valid types are UChar, Char, UShort, Short, UInt, Int, Float, Int64 and Double.
; Note: Types must not contain spaces i.e. " UInt" or "UInt " will not work.
; When an invalid type is passed the method returns NULL and sets ErrorLevel to -2
; aOffsets* - A variadic list of offsets. When using offsets the address parameter should equal the base address of the pointer.
; The address (base address) and offsets should point to the memory address which is to be written to.
; Return Values:
; Non Zero - Indicates success.
; Zero - Indicates failure. Check errorLevel and A_LastError for more information
; Null - An invalid type was passed. Errorlevel is set to -2
write(address, value, type := "Uint", aOffsets*)
{
if !this.aTypeSize.hasKey(type)
return "", ErrorLevel := -2
return DllCall("WriteProcessMemory", "Ptr", this.hProcess, "Ptr", aOffsets.maxIndex() ? this.getAddressFromOffsets(address, aOffsets*) : address, type "*", value, "Ptr", this.aTypeSize[type], "Ptr", this.pNumberOfBytesWritten)
}
; Method: writeRaw(address, pBuffer, sizeBytes, aOffsets*)
; Writes a buffer to the process.
; Parameters:
; address - The memory address to which the contents of the buffer will be written
; or if using the offset parameter, the base address of the pointer.
; pBuffer - A pointer to the buffer which is to be written.
; This does not necessarily have to be the beginning of the buffer itself e.g. pBuffer := &buffer + offset
; sizeBytes - The number of bytes which are to be written from the buffer.
; aOffsets* - A variadic list of offsets. When using offsets the address parameter should equal the base address of the pointer.
; The address (base address) and offsets should point to the memory address which is to be written to.
; Return Values:
; Non Zero - Indicates success.
; Zero - Indicates failure. Check errorLevel and A_LastError for more information
writeRaw(address, pBuffer, sizeBytes, aOffsets*)
{
return DllCall("WriteProcessMemory", "Ptr", this.hProcess, "Ptr", aOffsets.maxIndex() ? this.getAddressFromOffsets(address, aOffsets*) : address, "Ptr", pBuffer, "Ptr", sizeBytes, "Ptr", this.pNumberOfBytesWritten)
}
; Method: writeBytes(address, hexStringOrByteArray, aOffsets*)
; Writes a sequence of byte values to the process.
; Parameters:
; address - The memory address to where the bytes will be written
; or if using the offset parameter, the base address of the pointer.
; hexStringOrByteArray - This can either be either a string (A) or an object/array (B) containing the values to be written.
;
; A) HexString - A string of hex bytes. The '0x' hex prefix is optional.
; Bytes can optionally be separated using the space or tab characters.
; Each byte must be two characters in length i.e. '04' or '0x04' (not '4' or '0x4')
; B) Object/Array - An array containing hex or decimal byte values e.g. array := [10, 29, 0xA]
;
; aOffsets* - A variadic list of offsets. When using offsets the address parameter should equal the base address of the pointer.
; The address (base address) and offsets should point to the memory address which is to be written to.
; Return Values:
; -1, -2, -3, -4 - Error with the hexstring. Refer to hexStringToPattern() for details.
; Other Non Zero - Indicates success.
; Zero - Indicates write failure. Check errorLevel and A_LastError for more information
;
; Examples:
; writeBytes(0xAABBCC11, "DEADBEEF") ; Writes the bytes DE AD BE EF starting at address 0xAABBCC11
; writeBytes(0xAABBCC11, [10, 20, 0xA, 2])
writeBytes(address, hexStringOrByteArray, aOffsets*)
{
if !IsObject(hexStringOrByteArray)
{
if !IsObject(hexStringOrByteArray := this.hexStringToPattern(hexStringOrByteArray))
return hexStringOrByteArray
}
sizeBytes := this.getNeedleFromAOBPattern("", buffer, hexStringOrByteArray*)
return this.writeRaw(address, &buffer, sizeBytes, aOffsets*)
}
; Method: pointer(address, finalType := "UInt", offsets*)
; This is an internal method. Since the other various methods all offer this functionality, they should be used instead.
; This will read integer values of both pointers and non-pointers (i.e. a single memory address)
; Parameters:
; address - The base address of the pointer or the memory address for a non-pointer.
; finalType - The type of integer stored at the final address.
; Valid types are UChar, Char, UShort, Short, UInt, Int, Float, Int64 and Double.
; Note: Types must not contain spaces i.e. " UInt" or "UInt " will not work.
; When an invalid type is passed the method returns NULL and sets ErrorLevel to -2
; aOffsets* - A variadic list of offsets used to calculate the pointers final address.
; Return Values: (The same as the read() method)
; integer - Indicates success.
; Null - Indicates failure. Check ErrorLevel and A_LastError for more information.
; Note: Since the returned integer value may be 0, to check for success/failure compare the result
; against null i.e. if (result = "") then an error has occurred.
; If the target application is 64bit the pointers are read as an 8 byte Int64 (this.PtrType)
pointer(address, finalType := "UInt", offsets*)
{
For index, offset in offsets
address := this.Read(address, this.ptrType) + offset
Return this.Read(address, finalType)
}
; Method: getAddressFromOffsets(address, aOffsets*)
; Returns the final address of a pointer.
; This is an internal method used by various methods however, this method may be useful if you are
; looking to eliminate the overhead overhead associated with reading pointers which only change
; on startup or map/level change. In other words you can cache the final address and
; read from this address directly.
; Parameters:
; address The base address of the pointer.
; aOffsets* A variadic list of offsets used to calculate the pointers final address.
; At least one offset must be present.
; Return Values:
; Positive integer The final memory address pointed to by the pointer.
; Negative integer Failure
; Null Failure
; Note: If the target application is 64bit the pointers are read as an 8 byte Int64 (this.PtrType)
getAddressFromOffsets(address, aOffsets*)
{
return aOffsets.Remove() + this.pointer(address, this.ptrType, aOffsets*) ; remove the highest key so can use pointer() to find final memory address (minus the last offset)
}
; Interesting note:
; Although handles are 64-bit pointers, only the less significant 32 bits are employed in them for the purpose
; of better compatibility (for example, to enable 32-bit and 64-bit processes interact with each other)
; Here are examples of such types: HANDLE, HWND, HMENU, HPALETTE, HBITMAP, etc.
; http://www.viva64.com/en/k/0005/
; Method: getProcessBaseAddress(WindowTitle, windowMatchMode := 3)
; Returns the base address of a process. In most cases this will provide the same result as calling getModuleBaseAddress() (when passing
; a null value as the module parameter), however getProcessBaseAddress() will usually work regardless of the bitness
; of both the AHK exe and the target process.
; *This method relies on the target process having a window and will not work for console apps*
; *'DetectHiddenWindows, On' is required for hidden windows*
; ***If this returns an incorrect value, try using (the MORE RELIABLE) getModuleBaseAddress() instead.***
; Parameters:
; windowTitle This can be any AHK windowTitle identifier, such as
; ahk_exe, ahk_class, ahk_pid, or simply the window title. e.g. "ahk_exe calc.exe" or "Calculator".
; It's safer not to use the window title, as some things can have the same window title e.g. an open folder called "Starcraft II"
; would have the same window title as the game itself.
; windowMatchMode Determines the matching mode used when finding the program's window (windowTitle).
; The default value is 3 i.e. an exact match. The current matchmode will be used if the parameter is null or 0.
; Refer to AHK's setTitleMathMode for more information.
; Return Values:
; Positive integer The base address of the process (success).
; Null The process's window couldn't be found.
; 0 The GetWindowLong or GetWindowLongPtr call failed. Try getModuleBaseAddress() instead.
getProcessBaseAddress(windowTitle, windowMatchMode := "3")
{
if (windowMatchMode && A_TitleMatchMode != windowMatchMode)
{
mode := A_TitleMatchMode ; This is a string and will not contain the 0x prefix
StringReplace, windowMatchMode, windowMatchMode, 0x ; remove hex prefix as SetTitleMatchMode will throw a run time error. This will occur if integer mode is set to hex and matchmode param is passed as an number not a string.
SetTitleMatchMode, %windowMatchMode% ;mode 3 is an exact match
}
WinGet, hWnd, ID, %WindowTitle%
if mode
SetTitleMatchMode, %mode% ; In case executed in autoexec
if !hWnd
return ; return blank failed to find window
; GetWindowLong returns a Long (Int) and GetWindowLongPtr return a Long_Ptr
return DllCall(A_PtrSize = 4 ; If DLL call fails, returned value will = 0
? "GetWindowLong"
: "GetWindowLongPtr"
, "Ptr", hWnd, "Int", -6, A_Is64bitOS ? "Int64" : "UInt")
; For the returned value when the OS is 64 bit use Int64 to prevent negative overflow when AHK is 32 bit and target process is 64bit
; however if the OS is 32 bit, must use UInt, otherwise the number will be huge (however it will still work as the lower 4 bytes are correct)
; Note - it's the OS bitness which matters here, not the scripts/AHKs
}
; http://winprogger.com/getmodulefilenameex-enumprocessmodulesex-failures-in-wow64/
; http://stackoverflow.com/questions/3801517/how-to-enum-modules-in-a-64bit-process-from-a-32bit-wow-process
; Method: getModuleBaseAddress(module := "", byRef aModuleInfo := "")
; Parameters:
; moduleName - The file name of the module/dll to find e.g. "calc.exe", "GDI32.dll", "Bass.dll" etc
; If no module (null) is specified, the address of the base module - main()/process will be returned
; e.g. for calc.exe the following two method calls are equivalent getModuleBaseAddress() and getModuleBaseAddress("calc.exe")
; aModuleInfo - (Optional) A module Info object is returned in this variable. If method fails this variable is made blank.
; This object contains the keys: name, fileName, lpBaseOfDll, SizeOfImage, and EntryPoint
; Return Values:
; Positive integer - The module's base/load address (success).
; -1 - Module not found
; -3 - EnumProcessModulesEx failed
; -4 - The AHK script is 32 bit and you are trying to access the modules of a 64 bit target process. Or the target process has been closed.
; Notes: A 64 bit AHK can enumerate the modules of a target 64 or 32 bit process.
; A 32 bit AHK can only enumerate the modules of a 32 bit process
; This method requires PROCESS_QUERY_INFORMATION + PROCESS_VM_READ access rights. These are included by default with this class.
getModuleBaseAddress(moduleName := "", byRef aModuleInfo := "")
{
aModuleInfo := ""
if (moduleName = "")
moduleName := this.GetModuleFileNameEx(0, True) ; main executable module of the process - get just fileName no path
if r := this.getModules(aModules, True) < 0
return r ; -4, -3
return aModules.HasKey(moduleName) ? (aModules[moduleName].lpBaseOfDll, aModuleInfo := aModules[moduleName]) : -1
; no longer returns -5 for failed to get module info
}
; Method: getModuleFromAddress(address, byRef aModuleInfo)
; Finds the module in which the address resides.
; Parameters:
; address The address of interest.
;
; aModuleInfo (Optional) An unquoted variable name. If the module associated with the address is found,
; a moduleInfo object will be stored in this variable. This object has the
; following keys: name, fileName, lpBaseOfDll, SizeOfImage, and EntryPoint.
; If the address is not found to reside inside a module, the passed variable is
; made blank/null.
; offsetFromModuleBase (Optional) Stores the relative offset from the module base address
; to the specified address. If the method fails then the passed variable is set to blank/empty.
; Return Values:
; 1 Success - The address is contained within a module.
; -1 The specified address does not reside within a loaded module.
; -3 EnumProcessModulesEx failed.
; -4 The AHK script is 32 bit and you are trying to access the modules of a 64 bit target process.
getModuleFromAddress(address, byRef aModuleInfo, byRef offsetFromModuleBase := "")
{
aModuleInfo := offsetFromModule := ""
if result := this.getmodules(aModules) < 0
return result ; error -3, -4
for k, module in aModules
{
if (address >= module.lpBaseOfDll && address < module.lpBaseOfDll + module.SizeOfImage)
return 1, aModuleInfo := module, offsetFromModuleBase := address - module.lpBaseOfDll
}
return -1
}
; SeDebugPrivileges is required to read/write memory in some programs.
; This only needs to be called once when the script starts,
; regardless of the number of programs being read (or if the target programs restart)
; Call this before attempting to call any other methods in this class
; i.e. call _ClassMemory.setSeDebugPrivilege() at the very start of the script.
setSeDebugPrivilege(enable := True)
{
h := DllCall("OpenProcess", "UInt", 0x0400, "Int", false, "UInt", DllCall("GetCurrentProcessId"), "Ptr")
; Open an adjustable access token with this process (TOKEN_ADJUST_PRIVILEGES = 32)
DllCall("Advapi32.dll\OpenProcessToken", "Ptr", h, "UInt", 32, "PtrP", t)
VarSetCapacity(ti, 16, 0) ; structure of privileges
NumPut(1, ti, 0, "UInt") ; one entry in the privileges array...
; Retrieves the locally unique identifier of the debug privilege:
DllCall("Advapi32.dll\LookupPrivilegeValue", "Ptr", 0, "Str", "SeDebugPrivilege", "Int64P", luid)
NumPut(luid, ti, 4, "Int64")
if enable
NumPut(2, ti, 12, "UInt") ; enable this privilege: SE_PRIVILEGE_ENABLED = 2
; Update the privileges of this process with the new access token:
r := DllCall("Advapi32.dll\AdjustTokenPrivileges", "Ptr", t, "Int", false, "Ptr", &ti, "UInt", 0, "Ptr", 0, "Ptr", 0)
DllCall("CloseHandle", "Ptr", t) ; close this access token handle to save memory
DllCall("CloseHandle", "Ptr", h) ; close this process handle to save memory
return r
}
; Method: isTargetProcess64Bit(PID, hProcess := "", currentHandleAccess := "")
; Determines if a process is 64 bit.
; Parameters:
; PID The Process ID of the target process. If required this is used to open a temporary process handle.
; hProcess (Optional) A handle to the process, as returned by openProcess() i.e. [derivedObject].hProcess
; currentHandleAccess (Optional) The dwDesiredAccess value used when opening the process handle which has been
; passed as the hProcess parameter. If specifying hProcess, you should also specify this value.
; Return Values:
; True The target application is 64 bit.
; False The target application is 32 bit.
; Null The method failed.
; Notes:
; This is an internal method which is called when the new operator is used. It is used to set the pointer type for 32/64 bit applications so the pointer methods will work.
; This operation requires a handle with PROCESS_QUERY_INFORMATION or PROCESS_QUERY_LIMITED_INFORMATION access rights.
; If the currentHandleAccess parameter does not contain these rights (or not passed) or if the hProcess (process handle) is invalid (or not passed)
; a temporary handle is opened to perform this operation. Otherwise if hProcess and currentHandleAccess appear valid
; the passed hProcess is used to perform the operation.
isTargetProcess64Bit(PID, hProcess := "", currentHandleAccess := "")
{
if !A_Is64bitOS
return False
; If insufficient rights, open a temporary handle
else if !hProcess || !(currentHandleAccess & (this.aRights.PROCESS_QUERY_INFORMATION | this.aRights.PROCESS_QUERY_LIMITED_INFORMATION))
closeHandle := hProcess := this.openProcess(PID, this.aRights.PROCESS_QUERY_INFORMATION)
if (hProcess && DllCall("IsWow64Process", "Ptr", hProcess, "Int*", Wow64Process))
result := !Wow64Process
return result, closeHandle ? this.CloseHandle(hProcess) : ""
}
/*
_Out_ PBOOL Wow64Proces value set to:
True if the process is running under WOW64 - 32bit app on 64bit OS.
False if the process is running under 32-bit Windows!
False if the process is a 64-bit application running under 64-bit Windows.
*/
; Method: suspend() / resume()
; Notes:
; These are undocumented Windows functions which suspend and resume the process. Here be dragons.
; The process handle must have PROCESS_SUSPEND_RESUME access rights.
; That is, you must specify this when using the new operator, as it is not included.
; Some people say it requires more rights and just use PROCESS_ALL_ACCESS, however PROCESS_SUSPEND_RESUME has worked for me.
; Suspending a process manually can be quite helpful when reversing memory addresses and pointers, although it's not at all required.
; As an unorthodox example, memory addresses holding pointers are often stored in a slightly obfuscated manner i.e. they require bit operations to calculate their
; true stored value (address). This obfuscation can prevent Cheat Engine from finding the true origin of a pointer or links to other memory regions. If there
; are no static addresses between the obfuscated address and the final destination address then CE wont find anything (there are ways around this in CE). One way around this is to
; suspend the process, write the true/deobfuscated value to the address and then perform your scans. Afterwards write back the original values and resume the process.
suspend()
{
return DllCall("ntdll\NtSuspendProcess", "Ptr", this.hProcess)
}
resume()
{
return DllCall("ntdll\NtResumeProcess", "Ptr", this.hProcess)
}
; Method: getModules(byRef aModules, useFileNameAsKey := False)
; Stores the process's loaded modules as an array of (object) modules in the aModules parameter.
; Parameters:
; aModules An unquoted variable name. The loaded modules of the process are stored in this variable as an array of objects.
; Each object in this array has the following keys: name, fileName, lpBaseOfDll, SizeOfImage, and EntryPoint.
; useFileNameAsKey When true, the file name e.g. GDI32.dll is used as the lookup key for each module object.
; Return Values:
; Positive integer The size of the aModules array. (Success)
; -3 EnumProcessModulesEx failed.
; -4 The AHK script is 32 bit and you are trying to access the modules of a 64 bit target process.
getModules(byRef aModules, useFileNameAsKey := False)
{
if (A_PtrSize = 4 && this.IsTarget64bit)
return -4 ; AHK is 32bit and target process is 64 bit, this function wont work
aModules := []
if !moduleCount := this.EnumProcessModulesEx(lphModule)
return -3
loop % moduleCount
{
this.GetModuleInformation(hModule := numget(lphModule, (A_index - 1) * A_PtrSize), aModuleInfo)
aModuleInfo.Name := this.GetModuleFileNameEx(hModule)
filePath := aModuleInfo.name
SplitPath, filePath, fileName
aModuleInfo.fileName := fileName
if useFileNameAsKey
aModules[fileName] := aModuleInfo
else aModules.insert(aModuleInfo)
}
return moduleCount
}
getEndAddressOfLastModule(byRef aModuleInfo := "")
{
if !moduleCount := this.EnumProcessModulesEx(lphModule)
return -3
hModule := numget(lphModule, (moduleCount - 1) * A_PtrSize)
if this.GetModuleInformation(hModule, aModuleInfo)
return aModuleInfo.lpBaseOfDll + aModuleInfo.SizeOfImage
return -5
}
; lpFilename [out]
; A pointer to a buffer that receives the fully qualified path to the module.
; If the size of the file name is larger than the value of the nSize parameter, the function succeeds
; but the file name is truncated and null-terminated.
; If the buffer is adequate the string is still null terminated.
GetModuleFileNameEx(hModule := 0, fileNameNoPath := False)
{
; ANSI MAX_PATH = 260 (includes null) - unicode can be ~32K.... but no one would ever have one that size
; So just give it a massive size and don't bother checking. Most coders just give it MAX_PATH size anyway
VarSetCapacity(lpFilename, 2048 * (A_IsUnicode ? 2 : 1))
DllCall("psapi\GetModuleFileNameEx"
, "Ptr", this.hProcess
, "Ptr", hModule
, "Str", lpFilename
, "Uint", 2048 / (A_IsUnicode ? 2 : 1))
if fileNameNoPath
SplitPath, lpFilename, lpFilename ; strips the path so = GDI32.dll
return lpFilename
}
; dwFilterFlag
; LIST_MODULES_DEFAULT 0x0
; LIST_MODULES_32BIT 0x01
; LIST_MODULES_64BIT 0x02
; LIST_MODULES_ALL 0x03
; If the function is called by a 32-bit application running under WOW64, the dwFilterFlag option
; is ignored and the function provides the same results as the EnumProcessModules function.
EnumProcessModulesEx(byRef lphModule, dwFilterFlag := 0x03)
{
lastError := A_LastError
size := VarSetCapacity(lphModule, 4)
loop
{
DllCall("psapi\EnumProcessModulesEx"
, "Ptr", this.hProcess
, "Ptr", &lphModule
, "Uint", size
, "Uint*", reqSize
, "Uint", dwFilterFlag)
if ErrorLevel
return 0
else if (size >= reqSize)
break
else size := VarSetCapacity(lphModule, reqSize)
}
; On first loop it fails with A_lastError = 0x299 as its meant to
; might as well reset it to its previous version
DllCall("SetLastError", "UInt", lastError)
return reqSize // A_PtrSize ; module count ; sizeof(HMODULE) - enumerate the array of HMODULEs
}
GetModuleInformation(hModule, byRef aModuleInfo)
{
VarSetCapacity(MODULEINFO, A_PtrSize * 3), aModuleInfo := []
return DllCall("psapi\GetModuleInformation"
, "Ptr", this.hProcess
, "Ptr", hModule
, "Ptr", &MODULEINFO
, "UInt", A_PtrSize * 3)
, aModuleInfo := { lpBaseOfDll: numget(MODULEINFO, 0, "Ptr")
, SizeOfImage: numget(MODULEINFO, A_PtrSize, "UInt")
, EntryPoint: numget(MODULEINFO, A_PtrSize * 2, "Ptr") }
}
; Method: hexStringToPattern(hexString)
; Converts the hex string parameter into an array of bytes pattern (AOBPattern) that
; can be passed to the various pattern scan methods i.e. modulePatternScan(), addressPatternScan(), rawPatternScan(), and processPatternScan()
;
; Parameters:
; hexString - A string of hex bytes. The '0x' hex prefix is optional.
; Bytes can optionally be separated using the space or tab characters.
; Each byte must be two characters in length i.e. '04' or '0x04' (not '4' or '0x4')
; ** Unlike the other methods, wild card bytes MUST be denoted using '??' (two question marks)**
;
; Return Values:
; Object Success - The returned object contains the AOB pattern.
; -1 An empty string was passed.
; -2 Non hex character present. Acceptable characters are A-F, a-F, 0-9, ?, space, tab, and 0x (hex prefix).
; -3 Non-even wild card character count. One of the wild card bytes is missing a '?' e.g. '?' instead of '??'.
; -4 Non-even character count. One of the hex bytes is probably missing a character e.g. '4' instead of '04'.
;
; Examples:
; pattern := hexStringToPattern("DEADBEEF02")
; pattern := hexStringToPattern("0xDE0xAD0xBE0xEF0x02")
; pattern := hexStringToPattern("DE AD BE EF 02")
; pattern := hexStringToPattern("0xDE 0xAD 0xBE 0xEF 0x02")
;
; This will mark the third byte as wild:
; pattern := hexStringToPattern("DE AD ?? EF 02")
; pattern := hexStringToPattern("0xDE 0xAD ?? 0xEF 0x02")
;
; The returned pattern can then be passed to the various pattern scan methods, for example:
; pattern := hexStringToPattern("DE AD BE EF 02")
; memObject.processPatternScan(,, pattern*) ; Note the '*'
hexStringToPattern(hexString)
{
AOBPattern := []
hexString := RegExReplace(hexString, "(\s|0x)")
StringReplace, hexString, hexString, ?, ?, UseErrorLevel
wildCardCount := ErrorLevel
if !length := StrLen(hexString)
return -1 ; no str
else if RegExMatch(hexString, "[^0-9a-fA-F?]")
return -2 ; non hex character and not a wild card
else if Mod(wildCardCount, 2)
return -3 ; non-even wild card character count
else if Mod(length, 2)
return -4 ; non-even character count
loop, % length/2
{
value := "0x" SubStr(hexString, 1 + 2 * (A_index-1), 2)
AOBPattern.Insert(value + 0 = "" ? "?" : value)
}
return AOBPattern
}
; Method: stringToPattern(string, encoding := "UTF-8", insertNullTerminator := False)
; Converts a text string parameter into an array of bytes pattern (AOBPattern) that
; can be passed to the various pattern scan methods i.e. modulePatternScan(), addressPatternScan(), rawPatternScan(), and processPatternScan()
;
; Parameters:
; string The text string to convert.
; encoding This refers to how the string is stored in the program's memory.
; UTF-8 and UTF-16 are common. Refer to the AHK manual for other encoding types.
; insertNullTerminator Includes the null terminating byte(s) (at the end of the string) in the AOB pattern.
; This should be set to 'false' unless you are certain that the target string is null terminated and you are searching for the entire string or the final part of the string.
;
; Return Values:
; Object Success - The returned object contains the AOB pattern.
; -1 An empty string was passed.
;
; Examples:
; pattern := stringToPattern("This text exists somewhere in the target program!")
; memObject.processPatternScan(,, pattern*) ; Note the '*'
stringToPattern(string, encoding := "UTF-8", insertNullTerminator := False)
{
if !length := StrLen(string)
return -1 ; no str
AOBPattern := []
encodingSize := (encoding = "utf-16" || encoding = "cp1200") ? 2 : 1
requiredSize := StrPut(string, encoding) * encodingSize - (insertNullTerminator ? 0 : encodingSize)
VarSetCapacity(buffer, requiredSize)
StrPut(string, &buffer, length + (insertNullTerminator ? 1 : 0), encoding)
loop, % requiredSize
AOBPattern.Insert(NumGet(buffer, A_Index-1, "UChar"))
return AOBPattern
}
; Method: modulePatternScan(module := "", aAOBPattern*)
; Scans the specified module for the specified array of bytes
; Parameters:
; module - The file name of the module/dll to search e.g. "calc.exe", "GDI32.dll", "Bass.dll" etc
; If no module (null) is specified, the executable file of the process will be used.
; e.g. for calc.exe it would be the same as calling modulePatternScan(, aAOBPattern*) or modulePatternScan("calc.exe", aAOBPattern*)
; aAOBPattern* A variadic list of byte values i.e. the array of bytes to find.
; Wild card bytes should be indicated by passing a non-numeric value eg "?".
; Return Values:
; Positive int Success. The memory address of the found pattern.
; Null Failed to find or retrieve the specified module. ErrorLevel is set to the returned error from getModuleBaseAddress()
; refer to that method for more information.
; 0 The pattern was not found inside the module
; -9 VirtualQueryEx() failed
; -10 The aAOBPattern* is invalid. No bytes were passed
modulePatternScan(module := "", aAOBPattern*)
{
MEM_COMMIT := 0x1000, MEM_MAPPED := 0x40000, MEM_PRIVATE := 0x20000
, PAGE_NOACCESS := 0x01, PAGE_GUARD := 0x100
if (result := this.getModuleBaseAddress(module, aModuleInfo)) <= 0
return "", ErrorLevel := result ; failed
if !patternSize := this.getNeedleFromAOBPattern(patternMask, AOBBuffer, aAOBPattern*)
return -10 ; no pattern
; Try to read the entire module in one RPM()
; If fails with access (-1) iterate the modules memory pages and search the ones which are readable
if (result := this.PatternScan(aModuleInfo.lpBaseOfDll, aModuleInfo.SizeOfImage, patternMask, AOBBuffer)) >= 0
return result ; Found / not found
; else RPM() failed lets iterate the pages
address := aModuleInfo.lpBaseOfDll
endAddress := address + aModuleInfo.SizeOfImage
loop
{
if !this.VirtualQueryEx(address, aRegion)
return -9
if (aRegion.State = MEM_COMMIT
&& !(aRegion.Protect & (PAGE_NOACCESS | PAGE_GUARD)) ; can't read these areas
;&& (aRegion.Type = MEM_MAPPED || aRegion.Type = MEM_PRIVATE) ;Might as well read Image sections as well
&& aRegion.RegionSize >= patternSize
&& (result := this.PatternScan(address, aRegion.RegionSize, patternMask, AOBBuffer)) > 0)
return result
} until (address += aRegion.RegionSize) >= endAddress
return 0
}
; Method: addressPatternScan(startAddress, sizeOfRegionBytes, aAOBPattern*)
; Scans a specified memory region for an array of bytes pattern.
; The entire memory area specified must be readable for this method to work,
; i.e. you must ensure the area is readable before calling this method.
; Parameters:
; startAddress The memory address from which to begin the search.
; sizeOfRegionBytes The numbers of bytes to scan in the memory region.
; aAOBPattern* A variadic list of byte values i.e. the array of bytes to find.
; Wild card bytes should be indicated by passing a non-numeric value eg "?".
; Return Values:
; Positive integer Success. The memory address of the found pattern.
; 0 Pattern not found
; -1 Failed to read the memory region.
; -10 An aAOBPattern pattern. No bytes were passed.
addressPatternScan(startAddress, sizeOfRegionBytes, aAOBPattern*)
{
if !this.getNeedleFromAOBPattern(patternMask, AOBBuffer, aAOBPattern*)
return -10
return this.PatternScan(startAddress, sizeOfRegionBytes, patternMask, AOBBuffer)
}
; Method: processPatternScan(startAddress := 0, endAddress := "", aAOBPattern*)
; Scan the memory space of the current process for an array of bytes pattern.
; To use this in a loop (scanning for multiple occurrences of the same pattern),
; simply call it again passing the last found address + 1 as the startAddress.
; Parameters:
; startAddress - The memory address from which to begin the search.
; endAddress - The memory address at which the search ends.
; Defaults to 0x7FFFFFFF for 32 bit target processes.
; Defaults to 0xFFFFFFFF for 64 bit target processes when the AHK script is 32 bit.
; Defaults to 0x7FFFFFFFFFF for 64 bit target processes when the AHK script is 64 bit.
; 0x7FFFFFFF and 0x7FFFFFFFFFF are the maximum process usable virtual address spaces for 32 and 64 bit applications.
; Anything higher is used by the system (unless /LARGEADDRESSAWARE and 4GT have been modified).
; Note: The entire pattern must be occur inside this range for a match to be found. The range is inclusive.
; aAOBPattern* - A variadic list of byte values i.e. the array of bytes to find.
; Wild card bytes should be indicated by passing a non-numeric value eg "?".
; Return Values:
; Positive integer - Success. The memory address of the found pattern.
; 0 The pattern was not found.
; -1 VirtualQueryEx() failed.
; -2 Failed to read a memory region.
; -10 The aAOBPattern* is invalid. (No bytes were passed)
processPatternScan(startAddress := 0, endAddress := "", aAOBPattern*)
{
address := startAddress
if endAddress is not integer
endAddress := this.isTarget64bit ? (A_PtrSize = 8 ? 0x7FFFFFFFFFF : 0xFFFFFFFF) : 0x7FFFFFFF
MEM_COMMIT := 0x1000, MEM_MAPPED := 0x40000, MEM_PRIVATE := 0x20000
PAGE_NOACCESS := 0x01, PAGE_GUARD := 0x100
if !patternSize := this.getNeedleFromAOBPattern(patternMask, AOBBuffer, aAOBPattern*)
return -10
while address <= endAddress ; > 0x7FFFFFFF - definitely reached the end of the useful area (at least for a 32 target process)
{
if !this.VirtualQueryEx(address, aInfo)
return -1
if A_Index = 1
aInfo.RegionSize -= address - aInfo.BaseAddress
if (aInfo.State = MEM_COMMIT)
&& !(aInfo.Protect & (PAGE_NOACCESS | PAGE_GUARD)) ; can't read these areas
;&& (aInfo.Type = MEM_MAPPED || aInfo.Type = MEM_PRIVATE) ;Might as well read Image sections as well
&& aInfo.RegionSize >= patternSize
&& (result := this.PatternScan(address, aInfo.RegionSize, patternMask, AOBBuffer))
{
if result < 0
return -2
else if (result + patternSize - 1 <= endAddress)
return result
else return 0
}
address += aInfo.RegionSize
}
return 0
}
; Method: rawPatternScan(byRef buffer, sizeOfBufferBytes := "", aAOBPattern*)
; Scans a binary buffer for an array of bytes pattern.
; This is useful if you have already dumped a region of memory via readRaw()
; Parameters:
; buffer The binary buffer to be searched.
; sizeOfBufferBytes The size of the binary buffer. If null or 0 the size is automatically retrieved.
; startOffset The offset from the start of the buffer from which to begin the search. This must be >= 0.
; aAOBPattern* A variadic list of byte values i.e. the array of bytes to find.
; Wild card bytes should be indicated by passing a non-numeric value eg "?".
; Return Values:
; >= 0 The offset of the pattern relative to the start of the haystack.
; -1 Not found.
; -2 Parameter incorrect.
rawPatternScan(byRef buffer, sizeOfBufferBytes := "", startOffset := 0, aAOBPattern*)
{
if !this.getNeedleFromAOBPattern(patternMask, AOBBuffer, aAOBPattern*)
return -10
if (sizeOfBufferBytes + 0 = "" || sizeOfBufferBytes <= 0)
sizeOfBufferBytes := VarSetCapacity(buffer)
if (startOffset + 0 = "" || startOffset < 0)
startOffset := 0
return this.bufferScanForMaskedPattern(&buffer, sizeOfBufferBytes, patternMask, &AOBBuffer, startOffset)
}
; Method: getNeedleFromAOBPattern(byRef patternMask, byRef needleBuffer, aAOBPattern*)
; Converts an array of bytes pattern (aAOBPattern*) into a binary needle and pattern mask string
; which are compatible with patternScan() and bufferScanForMaskedPattern().
; The modulePatternScan(), addressPatternScan(), rawPatternScan(), and processPatternScan() methods
; allow you to directly search for an array of bytes pattern in a single method call.
; Parameters:
; patternMask - (output) A string which indicates which bytes are wild/non-wild.
; needleBuffer - (output) The array of bytes passed via aAOBPattern* is converted to a binary needle and stored inside this variable.
; aAOBPattern* - (input) A variadic list of byte values i.e. the array of bytes from which to create the patternMask and needleBuffer.
; Wild card bytes should be indicated by passing a non-numeric value eg "?".
; Return Values:
; The number of bytes in the binary needle and hence the number of characters in the patternMask string.
getNeedleFromAOBPattern(byRef patternMask, byRef needleBuffer, aAOBPattern*)
{
patternMask := "", VarSetCapacity(needleBuffer, aAOBPattern.MaxIndex())
for i, v in aAOBPattern
patternMask .= (v + 0 = "" ? "?" : "x"), NumPut(round(v), needleBuffer, A_Index - 1, "UChar")
return round(aAOBPattern.MaxIndex())
}
; The handle must have been opened with the PROCESS_QUERY_INFORMATION access right
VirtualQueryEx(address, byRef aInfo)
{
if (aInfo.__Class != "_ClassMemory._MEMORY_BASIC_INFORMATION")
aInfo := new this._MEMORY_BASIC_INFORMATION()
return aInfo.SizeOfStructure = DLLCall("VirtualQueryEx"
, "Ptr", this.hProcess
, "Ptr", address
, "Ptr", aInfo.pStructure
, "Ptr", aInfo.SizeOfStructure
, "Ptr")
}
/*
// The c++ function used to generate the machine code
int scan(unsigned char* haystack, unsigned int haystackSize, unsigned char* needle, unsigned int needleSize, char* patternMask, unsigned int startOffset)
{
for (unsigned int i = startOffset; i <= haystackSize - needleSize; i++)
{
for (unsigned int j = 0; needle[j] == haystack[i + j] || patternMask[j] == '?'; j++)
{
if (j + 1 == needleSize)
return i;
}
}
return -1;
}
*/
; Method: PatternScan(startAddress, sizeOfRegionBytes, patternMask, byRef needleBuffer)
; Scans a specified memory region for a binary needle pattern using a machine code function
; If found it returns the memory address of the needle in the processes memory.
; Parameters:
; startAddress - The memory address from which to begin the search.
; sizeOfRegionBytes - The numbers of bytes to scan in the memory region.
; patternMask - This string indicates which bytes must match and which bytes are wild. Each wildcard byte must be denoted by a single '?'.
; Non wildcards can use any other single character e.g 'x'. There should be no spaces.
; With the patternMask 'xx??x', the first, second, and fifth bytes must match. The third and fourth bytes are wild.
; needleBuffer - The variable which contains the binary needle. This needle should consist of UChar bytes.
; Return Values:
; Positive integer The address of the pattern.
; 0 Pattern not found.
; -1 Failed to read the region.
patternScan(startAddress, sizeOfRegionBytes, byRef patternMask, byRef needleBuffer)
{
if !this.readRaw(startAddress, buffer, sizeOfRegionBytes)
return -1
if (offset := this.bufferScanForMaskedPattern(&buffer, sizeOfRegionBytes, patternMask, &needleBuffer)) >= 0
return startAddress + offset
else return 0
}
; Method: bufferScanForMaskedPattern(byRef hayStack, sizeOfHayStackBytes, byRef patternMask, byRef needle)
; Scans a binary haystack for binary needle against a pattern mask string using a machine code function.
; Parameters:
; hayStackAddress - The address of the binary haystack which is to be searched.
; sizeOfHayStackBytes The total size of the haystack in bytes.
; patternMask - A string which indicates which bytes must match and which bytes are wild. Each wildcard byte must be denoted by a single '?'.
; Non wildcards can use any other single character e.g 'x'. There should be no spaces.
; With the patternMask 'xx??x', the first, second, and fifth bytes must match. The third and fourth bytes are wild.
; needleAddress - The address of the binary needle to find. This needle should consist of UChar bytes.
; startOffset - The offset from the start of the haystack from which to begin the search. This must be >= 0.
; Return Values:
; >= 0 Found. The pattern begins at this offset - relative to the start of the haystack.
; -1 Not found.
; -2 Invalid sizeOfHayStackBytes parameter - Must be > 0.
; Notes:
; This is a basic function with few safeguards. Incorrect parameters may crash the script.
bufferScanForMaskedPattern(hayStackAddress, sizeOfHayStackBytes, byRef patternMask, needleAddress, startOffset := 0)
{
static p
if !p
{
if A_PtrSize = 4
p := this.MCode("1,x86:8B44240853558B6C24182BC5568B74242489442414573BF0773E8B7C241CBB010000008B4424242BF82BD8EB038D49008B54241403D68A0C073A0A740580383F750B8D0C033BCD74174240EBE98B442424463B74241876D85F5E5D83C8FF5BC35F8BC65E5D5BC3")
else
p := this.MCode("1,x64:48895C2408488974241048897C2418448B5424308BF2498BD8412BF1488BF9443BD6774A4C8B5C24280F1F800000000033C90F1F400066660F1F840000000000448BC18D4101418D4AFF03C80FB60C3941380C18740743803C183F7509413BC1741F8BC8EBDA41FFC2443BD676C283C8FF488B5C2408488B742410488B7C2418C3488B5C2408488B742410488B7C2418418BC2C3")
}
if (needleSize := StrLen(patternMask)) + startOffset > sizeOfHayStackBytes
return -1 ; needle can't exist inside this region. And basic check to prevent wrap around error of the UInts in the machine function
if (sizeOfHayStackBytes > 0)
return DllCall(p, "Ptr", hayStackAddress, "UInt", sizeOfHayStackBytes, "Ptr", needleAddress, "UInt", needleSize, "AStr", patternMask, "UInt", startOffset, "cdecl int")
return -2
}
; Notes:
; Other alternatives for non-wildcard buffer comparison.
; Use memchr to find the first byte, then memcmp to compare the remainder of the buffer against the needle and loop if it doesn't match
; The function FindMagic() by Lexikos uses this method.
; Use scanInBuf() machine code function - but this only supports 32 bit ahk. I could check if needle contains wild card and AHK is 32bit,
; then call this function. But need to do a speed comparison to see the benefits, but this should be faster. Although the benefits for
; the size of the memory regions be dumped would most likely be inconsequential as it's already extremely fast.
MCode(mcode)
{
static e := {1:4, 2:1}, c := (A_PtrSize=8) ? "x64" : "x86"
if !regexmatch(mcode, "^([0-9]+),(" c ":|.*?," c ":)([^,]+)", m)
return
if !DllCall("crypt32\CryptStringToBinary", "str", m3, "uint", 0, "uint", e[m1], "ptr", 0, "uint*", s, "ptr", 0, "ptr", 0)
return
p := DllCall("GlobalAlloc", "uint", 0, "ptr", s, "ptr")
; if (c="x64") ; Virtual protect must always be enabled for both 32 and 64 bit. If DEP is set to all applications (not just systems), then this is required
DllCall("VirtualProtect", "ptr", p, "ptr", s, "uint", 0x40, "uint*", op)
if DllCall("crypt32\CryptStringToBinary", "str", m3, "uint", 0, "uint", e[m1], "ptr", p, "uint*", s, "ptr", 0, "ptr", 0)
return p
DllCall("GlobalFree", "ptr", p)
return
}
; This link indicates that the _MEMORY_BASIC_INFORMATION32/64 should be based on the target process
; http://stackoverflow.com/questions/20068219/readprocessmemory-on-a-64-bit-proces-always-returns-error-299
; The msdn documentation is unclear, and suggests that a debugger can pass either structure - perhaps there is some other step involved.
; My tests seem to indicate that you must pass _MEMORY_BASIC_INFORMATION i.e. structure is relative to the AHK script bitness.
; Another post on the net also agrees with my results.
; Notes:
; A 64 bit AHK script can call this on a target 64 bit process. Issues may arise at extremely high memory addresses as AHK does not support UInt64 (but these addresses should never be used anyway).
; A 64 bit AHK can call this on a 32 bit target and it should work.
; A 32 bit AHk script can call this on a 64 bit target and it should work providing the addresses fall inside the 32 bit range.
class _MEMORY_BASIC_INFORMATION
{
__new()
{
if !this.pStructure := DllCall("GlobalAlloc", "UInt", 0, "Ptr", this.SizeOfStructure := A_PtrSize = 8 ? 48 : 28, "Ptr")
return ""
return this
}
__Delete()
{
DllCall("GlobalFree", "Ptr", this.pStructure)
}
; For 64bit the int64 should really be unsigned. But AHK doesn't support these
; so this won't work correctly for higher memory address areas
__get(key)
{
static aLookUp := A_PtrSize = 8
? { "BaseAddress": {"Offset": 0, "Type": "Int64"}
, "AllocationBase": {"Offset": 8, "Type": "Int64"}
, "AllocationProtect": {"Offset": 16, "Type": "UInt"}
, "RegionSize": {"Offset": 24, "Type": "Int64"}
, "State": {"Offset": 32, "Type": "UInt"}
, "Protect": {"Offset": 36, "Type": "UInt"}
, "Type": {"Offset": 40, "Type": "UInt"} }
: { "BaseAddress": {"Offset": 0, "Type": "UInt"}
, "AllocationBase": {"Offset": 4, "Type": "UInt"}
, "AllocationProtect": {"Offset": 8, "Type": "UInt"}
, "RegionSize": {"Offset": 12, "Type": "UInt"}
, "State": {"Offset": 16, "Type": "UInt"}
, "Protect": {"Offset": 20, "Type": "UInt"}
, "Type": {"Offset": 24, "Type": "UInt"} }
if aLookUp.HasKey(key)
return numget(this.pStructure+0, aLookUp[key].Offset, aLookUp[key].Type)
}
__set(key, value)
{
static aLookUp := A_PtrSize = 8
? { "BaseAddress": {"Offset": 0, "Type": "Int64"}
, "AllocationBase": {"Offset": 8, "Type": "Int64"}
, "AllocationProtect": {"Offset": 16, "Type": "UInt"}
, "RegionSize": {"Offset": 24, "Type": "Int64"}
, "State": {"Offset": 32, "Type": "UInt"}
, "Protect": {"Offset": 36, "Type": "UInt"}
, "Type": {"Offset": 40, "Type": "UInt"} }
: { "BaseAddress": {"Offset": 0, "Type": "UInt"}
, "AllocationBase": {"Offset": 4, "Type": "UInt"}
, "AllocationProtect": {"Offset": 8, "Type": "UInt"}
, "RegionSize": {"Offset": 12, "Type": "UInt"}
, "State": {"Offset": 16, "Type": "UInt"}
, "Protect": {"Offset": 20, "Type": "UInt"}
, "Type": {"Offset": 24, "Type": "UInt"} }
if aLookUp.HasKey(key)
{
NumPut(value, this.pStructure+0, aLookUp[key].Offset, aLookUp[key].Type)
return value
}
}
Ptr()
{
return this.pStructure
}
sizeOf()
{
return this.SizeOfStructure
}
}
}
В архиве исходник и скомпилированный вариант.