Такая программа, как AkelPad существует уже давно, и также давно существуют скрипты под нее. Тем не менее, прога живет, периодически что-то не спеша дополняется, улучшается. Что меня в первую очередь в AP заинтересовало, это сама прога легкая, написаная на C имеющая, простой понятный мне интерфейс, плюс также, то, что скрипты там базируются на движке WSH который мне более-мнее знаком. Да сейчас можно сказать, что он во многом, как бы устаревший (хотя в Win11 уже обновили движек JScript), тем не менее, у него очень не плохие возможности. Что-то я узнал даже нового, например, то, что в VBS можно сделать дефолтное свойство у класса, я вообще не знал, что там есть такое ключевое свойство Defaullt, что в VBS можно функции передвать в переменные с помощью GetRef(). В JScript конечно это есть по умолчанию функции как переменные, но также там есть возможность приделывать свои "ручки" к чему угодно и также, там есть замыкания, так что все довольно не плохо, есть свобода действия. То что я там сразу заметил в скриптах - это довольно частое использование внутреннего сишного апи проги в скриптах, и ActiveX-ное апи там, тоже немного, такое, как бы, си-подобное, и вот, выглядеть это может не всегда эстетично, в частности, особенно, когда дело касается работы со сложными структурами.. Может быть в обиходе это не так и часто можно там найти, но вот мне как раз это понадобилось, поэтому повился интерес сделать какой-то более удобный интерфейс для работы со структурами, посему я создал следующий модуль, предоставляющий относительно удобную возможность создания объектов-оберток для раоты со структурами в памяти. Может быть это не модуль, а просто файл, но мне почему-то хочется всегда называть это модули, поскольку в VBxx это называется модули.
| JavaScript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
| // Модуль MemHelp.js (AkelPad-WSH-JScript) для секции "Include"
// (c) testuser2 2026
// Версия: 1 - 04/2026
// Описание: различные функции и объекты, урощающими работу с памятью и структурами в JScript
// https://github.com/LAcoder2/AkelPadScripts/blob/main/Include/MemHelp.js
// Функция создания объекта-враппера структуры, упрощающего работу со структурами данных
// pStruct - указатель структуры
// oStruct - объект-враппер структуры, если нужно использовать уже существующий объект/функцию
// nSize - размер структуры
// fullInit - флаг инициализации всех свойств объекта, соответствующих полям основной структуры, являющимися (суб-)структурами
// если fullInit === 1, - все свойства, соответствующие дочерним структурам, и их свойства, соотв. их дочерним структурам любой вложенности будут инициализированы
// если fullInit > 1, - дополнительно будут инициализированы все референсные структуры первого уровня вложенности равного fullInit
// если !fullInit, - ни чего не будет инициализировано заранее, а только при первом обращении.
function makeStructWrapper(pStruct, oStruct, nSize, fullInit){
if (!oStruct) oStruct = {}
if (!fullInit) fullInit = 0
var nCountSubStructs = 0
var nCountInit = 0
var nMaxCount = 0
var arSubStructs = [] // массив для хранения данных (и контроля) полей проинициализированных дочерних структур
//var dictRefs = {}
var fnGetWrp
//--Инициализация свойств, отвечающих за поля структуры--//
for (var i = 6; i < arguments.length; i += 3){
var fieldName = arguments[i-2]
var nOffset = arguments[i-1]
var nType = arguments[i]
if (nType === 6){ // структура, вложенная в основную структуру
nCountSubStructs += 2
if (nMaxCount < nCountSubStructs) {
nMaxCount += 10
arSubStructs.realloc(nMaxCount)
}
fnGetWrp = arguments[++i]
var fnSubStructInit = fieldSubStruct(nOffset, fnGetWrp, fieldName)
oStruct[fieldName] = !fullInit ? fnSubStructInit : fnSubStructInit()
} else if (nType === 9){ // указатель на структуру
oStruct[fieldName] = fieldRead(nOffset, 2, nLength)
oStruct[fieldName + "Set"] = fieldWrite(nOffset, 2, nLength)
fnGetWrp = arguments[++i]
var fldNmRef = fieldName + "Ref"
//oStruct[fldNmRef] = fieldRefStruct(nOffset, fnGetWrp, fldNmRef) // v1 объекты референсных структур всегда инициализируются отложенно
var fnRefStructInit = fieldRefStruct(nOffset, fnGetWrp, fldNmRef) // v2 реф-структуры также инициализируются, до уровня вложенности, соответствующего параметру fullInit
oStruct[fldNmRef] = (fullInit < 2 || !pStruct) ? fnRefStructInit : fnRefStructInit()
} else {
var nLength = (nType === 1 || nType === 0) ? arguments[++i] : -1 // Строки Unicode и Ansi, включенные в структуру
if (nType === 7 || nType === 8){ // указатель строки char*/wchar_t
oStruct[fieldName + "Ref"] = fieldReadRef(nOffset, nType - 7, nLength) // прочитать значение по ссылке (DT_ANSI 1/DT_UNICODE)
nType = 2
}
oStruct[fieldName] = fieldRead(nOffset, nType, nLength) // прочитать значение поля
oStruct[fieldName + "Set"] = fieldWrite(nOffset, nType, nLength) // записать значение
}
oStruct[fieldName + "Ptr"] = fieldPtr(nOffset) // получить указатель поля
}
if (nCountSubStructs) arSubStructs.realloc(nCountSubStructs)
//--Инициализация дефолтных свойств--//
oStruct.pStruct = function(){return pStruct}
oStruct.pStructSet = function(pNewStruct){
//if (isInteger(pNewStruct) && pNewStruct > 0){} else errorNoPointer()
pStruct = pNewStruct //меняем указатель основной структуры
var fn_pSubStructSet, nOffset
if (pStruct){
for(var i = 0; i < nCountInit;){ //меняем указатели в каждом проинициализированном объекте дочерней структуры
fn_pSubStructSet = arSubStructs[i++]
nOffset = arSubStructs[i++]
fn_pSubStructSet(pStruct + nOffset)
}
} else {
for(var i = 0; i < nCountInit; i += 2){
fn_pSubStructSet = arSubStructs[i]
fn_pSubStructSet(0) //обнуляем указатели в объектах дочерних структур
}
}
return pStruct
}
oStruct.size = function(){return nSize}
return oStruct
//--Функции для инициализации полей - структур--//
function fieldSubStruct(nOffset, fnGetWrp, fieldName){ // "ленивая" инициализация объекта вложенной структуры
return function (){
if(pStruct || fullInit){
var oSubStruct = oStruct[fieldName] = function (){
if (pStruct) return oSubStruct
errorNullPointer()
}
fnGetWrp((pStruct ? pStruct + nOffset : 0), oSubStruct, fullInit)
arSubStructs[nCountInit++] = oSubStruct.pStructSet // забираем у объекта вложенной структуры ручку pStructSet()
arSubStructs[nCountInit++] = nOffset
oSubStruct.pStructSet = function (){ // бьем по рукам, чтобы не пытались..
throw new Error("Нельзя изменить указатель дочерней структуры!")
}
return oSubStruct
}
//errorNullPointer()
}
}
function fieldRefStruct(nOffset, fnGetWrp, fieldName){ // "ленивая" инициализация ссылочной структуры
return function fnRefStructInit(){
//PrintLog('Попытка инициализации ' + pStruct)
if (pStruct){
var fn_pStructSet
var pSubStruct = AkelPad.MemRead(pStruct + nOffset, 2)
if (pSubStruct){
//PrintLog('Инициализация ссылочной структуры')
var oRefStruct = oStruct[fieldName] = function (){
if (pStruct){
if (pSubStruct = AkelPad.MemRead(pStruct + nOffset, 2)) {
// Возвращает объект референсной структуры, только если указатель не равен нулю
fn_pStructSet(pSubStruct)
return oRefStruct
}
}
errorNullPointer()
}
fnGetWrp(pSubStruct, oRefStruct, fullInit - 1)
fn_pStructSet = oRefStruct.pStructSet // забираем у ссылочной структуры метод pStructSet()
oRefStruct.pStructSet = function (){
throw new Error("Нельзя изменить указатель референсной структуры!")
}
return oRefStruct
}
return fnRefStructInit
}//; errorNullPointer()
}
}
//--Функции для инициализации полей базовых типов (числа, строки)--//
function fieldRead(nOffset, nType, nLength){ // чтение из поля структуры базового типа
return function(nType2, nLength2){
if (pStruct)
return AkelPad.MemRead(_PtrAdd(pStruct, nOffset),
nType2 === undefined ? nType : nType2,
!nLength2 ? nLength : nLength2)
errorNullPointer()
}
}
function fieldWrite(nOffset, nType, nLength){ // запись в поле структуры базовых типов
return function(vData, nType2, nLength2){
if (pStruct){
AkelPad.MemCopy(_PtrAdd(pStruct, nOffset), vData,
nType2 === undefined ? nType : nType2,
!nLength2 ? nLength : nLength2)
return vData
}
errorNullPointer()
}
}
function fieldReadRef(nOffset, nType, nLength){ // разименование строк и др. базовых типов
return function(nType2, nLength2){
if (pStruct)
var pValue = AkelPad.MemRead(pStruct + nOffset, 2)
if (pValue){
return AkelPad.MemRead(pValue,
(!isInteger(nType2) || nType2 < 0) ? nType : nType2,
(!isInteger(nLength2) || nLength2 < 0) ? nLength : nLength2)
} // при pValue = 0 вернет undefined
errorNullPointer()
}
}
function fieldPtr(nOffset){ // получение указателя поля структуры
return function(){
if (pStruct) return pStruct + nOffset
errorNullPointer()
}
}
function errorNullPointer(){ // ошибка при pStruct = 0
throw new Error("Указатель основной структуры равен нулю!")
}
function errorNoPointer(){
throw new Error("Значение не соответствует типу указателя!")
}
}
// аналоги SysAllocString/Len/ByteLen
function AllocString(pwStr, nLength){
if(!nLength) nLength = -1
return AkelPad.MemRead(pwStr, 1/*DT_UNICODE*/, nLength)
}
var AllocStringW = AllocString
function AllocStringA(paStr, nLength){
if(!nLength) nLength = -1
return AkelPad.MemRead(paStr, 0/*DT_ANSI*/, nLength)
}
// Создание строки, заполненной нулями заданного размера (nLen)
// предназначено для безопасного выделения памяти
var makeStrBuff = (function() {
var StrBuf = ""
return function(nLen) {
if (StrBuf.length < nLen) {
StrBuf = Array(nLen + 1).join("\0")
}
return StrBuf.substr(0, nLen);
}
})()
// Создание строки, заполненной пробелами
// Аналог Space() в VB
var Space = (function() {
var StrBuf = ""
return function(nLen) {
if (StrBuf.length < nLen) {
StrBuf = Array(nLen + 1).join(" ")
}
return StrBuf.substr(0, nLen);
}
})()
//Поверхностное копирование объекта
function shallowCopyObject(objInp, objOut){
if (!objOut) objOut = new Object()
for(var key in objInp){
objOut[key] = objInp[key]
}
return objOut
}
function StrPtr(sVar){return AkelPad.MemStrPtr(sVar)}
String.prototype.StrPtr = function(){
return AkelPad.MemStrPtr(this.toString())
}
Array.prototype.realloc = function(newlen) {
if (newlen < this.length)
this.splice(newlen, this.length - newlen) // Укорачиваем: удаляем лишние элементы
else if (newlen > this.length) // Удлиняем: добавляем undefined элементы
this[newlen - 1] = undefined // автоматически расширит массив
return this
}
Array.prototype.padEnd = function(lenadd, value){ // добавить lenadd элементов в конец
if(lenadd > 0)
this[this.length + lenadd - 1] = value
return this
}
Array.prototype.rightDelete = function(lendel){
this.splice(-lendel, lendel)
return this
}
Array.prototype.leftDelete = function(lendel){
this.splice(0, lendel)
return this
}
// проверка любого значения (строка, объект, булево и т.д.) на соответствие целому числу
function isInteger(vData){
return Math.floor(vData) === vData
} |
|
Пример использования в функции регистрации клавиатурных сочетаний в AkelPad.
| JavaScript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
| AkelPad.Include("log.js")
AkelPad.Include("MemHelp.js")
var hMainWnd=AkelPad.GetMainWnd()
//testRegisterHotkey()
function testRegisterHotkey(){
//RegisterHotkey("TabSwitch.js", GetHotkeyCode(9, true)) // регистрация обработчика Ctrl+Tab
//RegisterHotkey("TabSwitch.js", 0) // удаление обработчика
//PrintLog(RegisterHotkey("Test3.js", 0))
PrintLog(RegisterHotkey("Test3.js", 593))
}
// Получить код клавиатурного сочетания. Пример:
// WScript.Echo(GetHotkeyCode(9, true)) //получение кода сочетания Ctrl + Tab
function GetHotkeyCode(keyCode, ctrl, shift, alt) {
if (shift) keyCode |= 0x100
if (ctrl) keyCode |= 0x200
if (alt) keyCode |= 0x400
return keyCode;
}
// Регистрация клавиатурного сочетания. Пример (назначение сочетания Ctrl + Q для скрипта TestHotkey.js):
// RegisterHotkey("TestHotKey.js", GetHotkeyCode("Q".charCodeAt(0), true)) //
// Является портом одноименной функции из исходных файлов плагина Scripts (Scripts.c)
function RegisterHotkey(wszScriptName, wHotkey){
var pfElement // Указатель на структуру функции плагина
var wszHotkeyOwner = makeStrBuff(260) // Имя владельца, если клавиша занята
// Формируем полное имя функции для регистрации: "Scripts::Main::имя_скрипта"
var wszPrefix = "Scripts::Main::"
var wszFunction = wszPrefix + wszScriptName
//Проверяем, не занята ли уже эта комбинация клавиш
var nOwner = AkelPad.SendMessage(hMainWnd, 1338/*AKD_CHECKHOTKEY*/, wHotkey, wszHotkeyOwner.StrPtr())
if (!nOwner){ //Пытаемся найти уже зарегистрированную функцию с таким именем
if (pfElement = AkelPad.SendMessage(hMainWnd, 1331/*AKD_DLLFINDW*/, wszFunction.StrPtr(), 0)) {
// Функция уже существует - просто обновляем её горячую клавишу
var opf = makePLUGINFUNCTIONwrp(pfElement) // Создаем объект-враппер структуры PLUGINFUNCTION
// Если клавиша сброшена (0) и функция не активна и не в автозагрузке то удаляем её из системы
if(!wHotkey && !opf.bRunning() && !opf.bAutoLoad()){
AkelPad.SendMessage(hMainWnd, 1335/*AKD_DLLDELETE*/, 0, pfElement)
} else opf.wHotkeySet(wHotkey)
} else { // Функция не найдена - создаем новую, если есть клавиша для назначения
if (wHotkey) {
var spa = makeStrBuff(16) // выделяем память под структуру PLUGINADDW, 32/2 - размер структуры (в x64)
var ppa = spa.StrPtr()
var opa = makePLUGINADDWwrp(ppa) // Создаем объект-враппер структуры PLUGINADDW
opa.pFunctionSet(wszFunction.StrPtr()) // Имя функции
opa.wHotkeySet(wHotkey)
var HotkeyProc = GetHotkeyProc() // callback-Функция-обработчик
if (!HotkeyProc){
WScript.Echo("Не получен адрес HotkeyProc (внутреняя процедура обработки хоткеев плагина Scripts), \n" +
"необходимой для регистарции клав. сочетаний!")
return false
}
opa.PluginProcSet(HotkeyProc)
// Регистрируем новую функцию в ядре AkelPad
if (pfElement = AkelPad.SendMessage(hMainWnd, 1334/*AKD_DLLADDW*/, 0, ppa)){
//PrintLog("Успешная регистрация новой функции в ядро AkelPad!")
// Устанавливаем параметр для обработчика - указатель на имя скрипта
opf = makePLUGINFUNCTIONwrp(pfElement)
opf.lpParameterSet(opf.wszFunctionPtr() + wszPrefix.length * 2)
}
}
}
return true
} else {
var nLen = wszHotkeyOwner.indexOf("\0", 0)
var sHotkeyOwner = wszHotkeyOwner.substr(0, nLen)
if (wszFunction !== sHotkeyOwner) {
WScript.Echo("Комбинация уже занята действием:\n" + sHotkeyOwner)
return false
} else
return true
}
}
// Получение указателя внутренней функции обработчика хоткеев в Акелпаде
function GetHotkeyProc(wHotkey){
if(!wHotkey) wHotkey = 265 // Shift + Tab
var wszHotkeyOwner = makeStrBuff(260) // Имя процедуры, назначенной на клавишу
var pwszHotkeyOwner = StrPtr(wszHotkeyOwner)
if (AkelPad.SendMessage(hMainWnd, 1338/*AKD_CHECKHOTKEY*/, wHotkey, pwszHotkeyOwner)){
var pfElement = AkelPad.SendMessage(hMainWnd, 1331/*AKD_DLLFINDW*/, pwszHotkeyOwner, 0)
if (pfElement) return makePLUGINFUNCTIONwrp(pfElement).PluginProc()
}
}
/*typedef struct { // смещения (x64/x86)
const wchar_t *pFunction; // 0/0 Function name, format "Plugin::Function".
WORD wHotkey; // 8/4 Function hotkey. See HKM_GETHOTKEY message return value (MSDN).
BOOL bAutoLoad; // 12/8 TRUE if function has autoload flag.
// FALSE if function has no autoload flag.
PLUGINPROC PluginProc; // 16/12 Function procedure.
void *lpParameter; // 24/16 Procedure parameter.
} PLUGINADDW; // 32/20 Общий размер*/
// Создание объекта-враппера структуры PLUGINADDW
function makePLUGINADDWwrp(pStruct, oStruct){
return oStruct = makeStructWrapper(pStruct, oStruct, (_X64 ? 32 : 20), 0,
"pFunction", 0, 2,
"wHotkey", (_X64 ? 8 : 4), 4,
"bAutoLoad", (_X64 ? 12 : 8), 3,
"PluginProc", (_X64 ? 16 : 12), 2,
"lpParameter", (_X64 ? 24 : 16), 2)
}
/*typedef struct {
struct _PLUGINFUNCTION *next; // 0x00 : 0x00 - указатель на следующий элемент в списке
struct _PLUGINFUNCTION *prev; // 0x08 : 0x04 - указатель на предыдущий элемент в списке
const BYTE *pFunction; // 0x10 : 0x08 - указатель на имя функции
// Формат: "Plugin::Function"
// const char *pFunction если bOldWindows == TRUE
// const wchar_t *pFunction если bOldWindows == FALSE
char szFunction[MAX_PATH]; // 0x18 : 0x0C - имя функции в ANSI кодировке (260 байт)
wchar_t wszFunction[MAX_PATH]; // 0x11C : 0x110 - имя функции в Unicode кодировке (520 байт)
// Максимум MAX_PATH символов (обычно 260)
int nFunctionLen; // 0x324 : 0x318 - длина имени функции в символах
WORD wHotkey; // 0x328 : 0x31C - горячая клавиша функции
// Формат: старший байт = флаги модификаторов (HOTKEYF_*)
// младший байт = виртуальный код клавиши (VK_*)
// См. документацию по HKM_GETHOTKEY в MSDN
BOOL bAutoLoad; // 0x32C : 0x320 - флаг автозагрузки функции
// TRUE - функция загружается автоматически при старте
// FALSE - функция не загружается автоматически
BOOL bRunning; // 0x330 : 0x324 - флаг выполнения функции
// TRUE - функция выполняется в данный момент
// FALSE - функция не выполняется
PLUGINPROC PluginProc; // 0x338 : 0x328 - указатель на функцию-обработчик
// Прототип: BOOL CALLBACK PluginProc(void *lpParameter, LPARAM lParam, DWORD dwSupport)
void *lpParameter; // 0x340 : 0x32C - пользовательские данные для обработчика
// В случае Scripts плагина: указатель на имя скрипта
int nRefCount; // 0x348 : 0x330 - счётчик ссылок (внутреннее использование)
// Используется для управления временем жизни структуры
} PLUGINFUNCTION; // 0x350 : 0x334 - размер структуры (820/848 байт)*/
// Создание объекта-враппера структуры PLUGINFUNCTION
function makePLUGINFUNCTIONwrp(pStruct, oStruct){
return oStruct = makeStructWrapper(pStruct, oStruct, (_X64 ? 0x350 : 0x334), 0,
/*"next", 0, 2,
"prev", (_X64 ? 8 : 4), 2,*/
"wszFunction", (_X64 ? 0x11C : 0x110), 1, -1,
"wHotkey", (_X64 ? 0x328 : 0x31C), 4,
"bAutoLoad", (_X64 ? 0x32C : 0x320), 3,
"bRunning", (_X64 ? 0x330 : 0x324), 3,
"PluginProc", (_X64 ? 0x338 : 0x328), 2,
"lpParameter", (_X64 ? 0x340 : 0x32C), 2)
} |
|
Можно сравнить с оригинальной реализацией функции на C
| C++ | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
| BOOL RegisterHotkey(wchar_t *wszScriptName, WORD wHotkey) {
PLUGINFUNCTION *pfElement; // Указатель на структуру функции плагина
wchar_t wszPrefix[MAX_PATH]; // Префикс для имени функции
wchar_t wszFunction[MAX_PATH]; // Полное имя функции "Scripts::Main::script.js"
wchar_t wszHotkeyOwner[MAX_PATH]; // Имя владельца, если клавиша занята
int nOwner; // Результат проверки (0 - свободно, иначе занято)
xstrcpyW(wszPrefix, L"Scripts::Main::"); // Формируем полное имя функции для регистрации
xprintfW(wszFunction, L"%s%s", wszPrefix, wszScriptName); // Формат: "Scripts::Main::имя_скрипта"
// Проверяем, не занята ли уже эта комбинация клавиш
// AKD_CHECKHOTKEY - сообщение ядру AkelPad
// wHotkey - код клавиши (виртуальный код + модификаторы)
// wszHotkeyOwner - буфер, куда запишется имя текущего владельца
nOwner = (int)SendMessage(hMainWnd, AKD_CHECKHOTKEY, wHotkey, (LPARAM)wszHotkeyOwner);
if (!nOwner) { // Если комбинация свободна
// Пытаемся найти уже зарегистрированную функцию с таким именем
// AKD_DLLFINDW - поиск функции плагина по имени
if (pfElement = (PLUGINFUNCTION *)SendMessage(hMainWnd, AKD_DLLFINDW, (WPARAM)wszFunction, 0)) {
pfElement->wHotkey = wHotkey; // Функция уже существует - просто обновляем её горячую клавишу
// Если клавиша сброшена (0) и функция не активна и не в автозагрузке то удаляем её из системы
if (!pfElement->wHotkey && !pfElement->bRunning && !pfElement->bAutoLoad)
SendMessage(hMainWnd, AKD_DLLDELETE, 0, (LPARAM)pfElement);
} else {
// Функция не найдена - создаем новую, если есть клавиша для назначения
if (wHotkey) {
PLUGINADDW pa = { 0 }; // Структура для добавления функции
pa.pFunction = wszFunction; // Имя функции
pa.wHotkey = wHotkey; // Горячая клавиша
pa.PluginProc = HotkeyProc; // Функция-обработчик (callback)
// Регистрируем новую функцию в ядре AkelPad
if (pfElement = (PLUGINFUNCTION *)SendMessage(hMainWnd, AKD_DLLADDW, 0, (LPARAM)&pa)) {
// Устанавливаем параметр для обработчика - указатель на имя скрипта
// lpParameter будет передан в HotkeyProc при нажатии
pfElement->lpParameter = pfElement->wszFunction + xstrlenW(wszPrefix);
}
}
}
return TRUE; // Успешная регистрация
} else { // Комбинация уже занята - показываем сообщение об ошибке
xprintfW(wszBuffer, GetLangStringW(wLangModule, STRID_HOTKEY_EXISTS),
wszFunction, wszHotkeyOwner);
MessageBoxW(hWndMainDlg, wszBuffer, wszPluginTitle, MB_OK | MB_ICONEXCLAMATION);
return FALSE; // Регистрация не удалась
}
} |
|
Пример (не практический) работы со сложной структурой, имеющей ссылочные значения (указатели)
| JavaScript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
| // Модуль StructTest.js (AkelPad-WSH-JScript)
// (c) testuser2 2026
// Описание: пример работы со C-структурами в AkelPad-JScript, используя объектные оболочки структур
// https://github.com/LAcoder2/AkelPadScripts/blob/main/StructTest.js
AkelPad.Include("log.js")
AkelPad.Include("MemHelp.js")
try{
var nstp = -1
var sTCBuf = Space(/*oTC.size()*/128 / 2) // выделяем память для основной структуры AENTEXTCHANGE
var sLDTBuf = Space(/*oLDt.size()*/48 / 2) // выделяем память для ссылочной структуры AELINEDATA,
// заполненную символом пробела, чтобы имитировать заполненность
var oTC = makeAENTEXTCHANGEwrp(StrPtr(sTCBuf), 0, 2)
nstp = 1
PrintLog(oTC.crRichSel().cpMaxPtr() - oTC.pStruct()) // получаем смещение последнего элемента структуры
oTC.crSel().ciMax().nCharInLineSet(752) // пишем простое значение в поле структуры
PrintLog(oTC.crSel.ciMax.nCharInLine()) // читаем это значение
var s = "Привет Ворлд!"
oTC.crSel.ciMax.lpLineSet(StrPtr(sLDTBuf))
oTC.crSel.ciMax.lpLineRef().wpLineSet(StrPtr(s)) // пишем значение (указатель) в ссылочную структуру
// имитируя доступ к заполненной структуре
PrintLog(oTC.crSel.ciMax.lpLineRef.wpLineRef()) // считываем ссылочное значение (строку wchar_t) из ссылочной структуры
}catch(e){
PrintLog(e.message + " " + nstp)
}
/*typedef struct { // смещения (x64/x86)
struct _AELINEDATA *next; // 0/0 Указатель на следующую структуру AELINEDATA.
struct _AELINEDATA *prev; // 8/4 Указатель на предыдущую структуру AELINEDATA.
wchar_t *wpLine; // 16/8 Текст строки, заканчивающийся NULL‑символом.
int nLineLen; // 24/12 Длина wpLine, не включая завершающий NULL‑символ.
BYTE nLineBreak; // 28/16 Новая строка: AELB_EOF, AELB_R, AELB_N, AELB_RN, AELB_RRN или AELB_WRAP.
BYTE nLineFlags; // 29/17 Зарезервировано.
WORD nReserved; // 30/18 Зарезервировано.
int nLineWidth; // 32/20 Ширина строки в пикселях.
int nSelStart; // 36/24 Начальная позиция символа выделения в строке.
int nSelEnd; // 40/28 Конечная позиция символа выделения в строке.
} AELINEDATA; // 48/32 Общий размер.*/
function makeAELINEDATAwrp(pStruct, oStruct, fullInit){
return oStruct = makeStructWrapper(pStruct, oStruct, (_X64 ? 48 : 32), fullInit,
"next", 0, 9, makeAELINEDATAwrp,
"prev", (_X64 ? 8 : 4), 9, makeAELINEDATAwrp,
"wpLine", (_X64 ? 16 : 8), 8,
"nLineLen", (_X64 ? 24 : 12), 3,
"nLineBreak", (_X64 ? 28 : 16), 5,
"nLineFlags", (_X64 ? 29 : 17), 5,
"nReserved", (_X64 ? 30 : 18), 4,
"nLineWidth", (_X64 ? 32 : 20), 3,
"nSelStart", (_X64 ? 36 : 24), 3,
"nSelEnd", (_X64 ? 40 : 28), 3
)
}
/*typedef struct { // смещения (x64/x86)
int nLine; // 0/0 Номер строки в документе, начиная с нуля.
AELINEDATA *lpLine; // 8/4 Указатель на структуру AELINEDATA.
int nCharInLine; // 16/8 Позиция символа в строке.
} AECHARINDEX; // 24/12 Общий размер.*/
function makeAECHARINDEXwrp(pStruct, oStruct, fullInit){
return oStruct = makeStructWrapper(pStruct, oStruct, (_X64 ? 24 : 12), fullInit,
"nLine", 0, 3,
"lpLine", (_X64 ? 8 : 4), 9, makeAELINEDATAwrp,
"nCharInLine", (_X64 ? 16 : 8), 3
)
}
/*typedef struct { // смещения (x64/x86)
AECHARINDEX ciMin; // 0/0 Индекс первого символа в диапазоне.
AECHARINDEX ciMax; // 24/12 Индекс последнего символа в диапазоне.
} AECHARRANGE; // 48/24 Общий размер.*/
function makeAECHARRANGEwrp(pStruct, oStruct, fullInit){
return oStruct = makeStructWrapper(pStruct, oStruct, (_X64 ? 48 : 24), fullInit,
"ciMin", 0, 6, makeAECHARINDEXwrp,
"ciMax", (_X64 ? 24 : 12), 6, makeAECHARINDEXwrp
)
}
/*typedef struct { // смещения (x64/x86)
HWND hwndFrom; // 0/0 Дескриптор окна‑источника.
UINT_PTR idFrom; // 8/4 Идентификатор источника.
UINT code; // 16/8 Код уведомления.
AEHDOC docFrom; // 20/12 Дескриптор документа. См. сообщение AEM_CREATEDOCUMENT.
} AENMHDR; // 28/16 Общий размер.*/
function makeAENMHDRwrp(pStruct, oStruct){
return oStruct = makeStructWrapper(pStruct, oStruct, (_X64 ? 28 : 16), undefined,
"hwndFrom", 0, 2,
"idFrom", (_X64 ? 8 : 4), 2,
"code", (_X64 ? 16 : 8), 3,
"docFrom", (_X64 ? 20 : 12), 2
)
}
/*typedef struct { // смещения (x64/x86)
INT_PTR cpMin; // 0/0 Минимальное смещение.
INT_PTR cpMax; // 8/4 Максимальное смещение.
} CHARRANGE64; // 16/8 Общий размер.*/
function makeCHARRANGE64wrp(pStruct, oStruct){
return oStruct = makeStructWrapper(pStruct, oStruct, (_X64 ? 16 : 8)/*size*/, undefined,
"cpMin", 0, 2,
"cpMax", (_X64 ? 8 : 4), 2
)
}
/*typedef struct { // смещения (x64/x86)
AENMHDR hdr; // 0/0 Стандартный NMHDR.
AECHARRANGE crSel; // 28/16 Текущее выделение.
AECHARINDEX ciCaret; // 76/40 Позиция индекса символа курсора.
DWORD dwType; // 100/52 См. определения AETCT_*.
BOOL bColumnSel; // 104/56 Колоночное выделение.
CHARRANGE64 crRichSel; // 112/60 Текущее выделение (смещение RichEdit).
} AENTEXTCHANGE; // 128/68 Общий размер.
*/
function makeAENTEXTCHANGEwrp(pStruct, oStruct, fullInit){
return oStruct = makeStructWrapper(pStruct, oStruct, (_X64 ? 128 : 68)/*size*/, fullInit,
"hdr", 0, 6, makeAENMHDRwrp,
"crSel", (_X64 ? 28 : 16), 6, makeAECHARRANGEwrp,
"ciCaret", (_X64 ? 76 : 40), 6, makeAECHARRANGEwrp,
"dwType", (_X64 ? 100 : 52), 3,
"bColumnSel", (_X64 ? 104 : 56), 3,
"crRichSel", (_X64 ? 112 : 60), 6, makeCHARRANGE64wrp
)
} |
|
|