Fr0sT, сбылась мечта идиотов(то бишь нас) - Инструктор реализовал нативный колбек. Теперь ещё бы сделать нам компилятор ресурсов, и диалоги у нас в кармане
function do_cool_stuff(args)
{
var stuff_callback = function(arg1,arg2,arg3)
{
// do it
}
var func = oSys.RegisterCallback(stuff_callback);
oSys.Call("module::function_with_callback_arg",param, func);
oSys.UnregisterCallkback(func);
}
var func = oSys.RegisterCallback(function(param1,param2){
//stuff in callback
});
oSys.Call("module::function_with_callback_arg",param, func);
oSys.UnregisterCallkback(func);
Posted: Thu Oct 28, 2010 4:54 pm
by Instructor
FeyFre
Чтобы создать обратный вызов с динамическим количеством параметров? Для чего это нужно?
Posted: Thu Oct 28, 2010 7:13 pm
by FeyFre
Нет, количество параметров остается постоянным - таким как задано в объекте функции которую передадут в вызов.
Для того что-бы создавать замыкания. Глобально объявленная функция видит только глобальные переменные. А функция объявленная внутри другой функции, цикла, ветвления видит также объявленные в них переменные, и может их использовать.(Собственно замыкания одно из мощнейших средств ECMA)
var oSys = AkelPad.SystemFunction();
//! Функция возвпащает первое и последнее дочернее окно заданого окна
function GetFirstLastChild(window)
{
// Локальные переменные, будут видны Callback а не глобально, где и могу подпортить.
var first = null, last = null;
// Функция отзыва. Глобально не видна, потому назвать можем как угодно.
// Задекларировання с двумя аргументами.
function Callback(hwnd, lparam)
{
if(first != null)
{
first = hwnd;
}
last = hwnd;
}
var enumerator = oSys.RegisterCallback(Callback);
// Выполняем. Функция будет вызываться определенное количество раз
// и данные будет сохранять в локальных first и last а не в глобальных переменных
// где их тоже могут подпортить.
oSys.Call("user32::EnumWindows",enumerator,0);
oSys.UnregisterCallback(enumerator);
return {"first":first,"last":last};
}
// Тут Callback, first, last уже не существует, можем их имена использовать сколько угодно раз.
Posted: Fri Oct 29, 2010 12:11 pm
by Instructor
FeyFre
Попробовал, но не получилось, чтобы GetIDsOfNames распознал имя функции внутри функции.
Posted: Fri Oct 29, 2010 12:13 pm
by Instructor
Исправлено: true после VariantChangeType превращался в -1.
Признаюсь, пример делал на коленке. Суть такова: переменную objScript вы не ищете сами, а Вам её уже передали аргументом. Вам остается её только посчитать аргументы, сохранить(AddRef-нуть не забыть) в lpCallback. Так только время появится - сам попытаюсь реализовать, в будний день просто некогда.
Posted: Fri Oct 29, 2010 1:56 pm
by Instructor
FeyFre
Я готов подождать, когда появится работающий экземляр И меня интересует вариант, при котором не прийдется указывать количество аргументов при вызове RegisterCallback.
Posted: Fri Oct 29, 2010 4:46 pm
by FeyFre
И меня интересует вариант, при котором не прийдется указывать количество аргументов при вызове RegisterCallback.
на сколько я понял RegisterCallback работает исключительно с __stdcall . А потому не может идти речи об неизвестном количестве аргументов.
Да и не всякий скриптовый движок понимает такие финты. Это мы привыкли к JScript. В VBScript я соовсем не уверен. А если у кого-то ещё какой-нибудь язык подключен к WSH?
Posted: Mon Nov 01, 2010 2:34 pm
by Terrana
А с файлами какого размера этот плагин успешно работает?
Попробовала воспользоваться функцией "Фильтр строк с регулярным выражением", на лог-файле в 80Мб при фильтре:
Строка содержит: "QUEUE"
Учитывать регистр
Оставить строки
меня благополучно выкинуло:
"Всплывающее окно приложения: AkelPad - [c:\tmp\newsmsgw\SystemOut_10.10.23_07.18.34.log]: AkelPad.exe - Ошибка приложения : Инструкция по адресу "0x00429e81" обратилась к памяти по адресу "0x00000000". Память не может быть "read".
С файлом размера 2Мб всё прошло успешно.
У меня, конечно, всего 2,5Гб ОЗУ, но вроде бы должно было хватить.
Posted: Mon Nov 01, 2010 3:31 pm
by Instructor
Terrana
Ограничения не предусмотрены Если используется Scripts v7.3 и ошибка воспроизводится постоянно, то высылайте на почту архив проблемного файла (или на файлообменник).
Posted: Tue Nov 16, 2010 12:08 am
by FeyFre
Хотелка.
(Начну с конца)
В функцию AkelPad.MessageBox добавить 5-ый аргумент.
Этот аргумент функция(остальные типы не валидные).
Назначение:
Если аргумент валидный(функция, не null), то при отображении окна-сообщения добавить к нему птичку где-то снизу или справа от кнопок с надписью "прекратить выполнение скрипта"(если не валидный - птичку не ставим, ничего не меняется).
Если птичка стоит и нажали какую-нибудь кнопку, то плагин выполняет эту функцию а после того как она выполнилась вместо того что-бы вернуть управление скрипту, завершает его. Если птичка не стоит - работает как раньше.
Фича очень полезна при:
1) Отладке скриптов(а) - зачистка выделенной памяти AkelPad.MemAlloc(которая утечет до завершения процесса), Уничтожение системных объектов(окна, контексты, открытые файлы, другие дескрипторы)
2) При выполнении многошаговых контролируемых операций - может быть использована как команда "прервать задачу и откатить назад", вне зависимости от нажатой кнопки(иногда трех кнопок может и не хватить).
3) Ваш вариант.
var buf1,buf2,buf3,res;
function init(){} //! buf1(2,3) = AkelPad.MemAlloc(size);
function doStuff1(choice){} //
function doStuff2(choice){} // use buffers
function doStuff3(choice){} //
function cleanup() // free buffers
{
if(buf1!=0) AkelPad.MemFree(buf1);
if(buf2!=0) AkelPad.MemFree(buf2);
if(buf3!=0) AkelPad.MemFree(buf3);
}
res = AkelPad.MessageBox(hMainWnd,"Question1","Title1",flags1,cleanup);
doStuff1(res);
res = AkelPad.MessageBox(hMainWnd,"Question2","Title2",flags2,cleanup);
doStuff2(res);
res = AkelPad.MessageBox(hMainWnd,"Question3","Title3",flags3,cleanup);
doStuff3(res);
cleanup();
PS: идею птички подсмотрел в alert/prompt/confirm боксах Оперы.
Posted: Mon Nov 22, 2010 5:10 pm
by Infocatcher
Интереса ради попробовал сделать интерфейс для работы с настройками в INI-файлах:
// (c) Infocatcher 2010
// version 0.1.0 - 2010-11-19
var iniFile = WScript.ScriptFullName + ".ini";
var iniParser = INIParser(iniFile);
var test = iniParser.get("qwe", "0");
WScript.Echo(test);
iniParser.set("qwe", ++test);
function INIParser(iniFile) {
var initialized = false;
var saved = true;
var data = {};
var fso;
function getFso() {
return fso || (fso = new ActiveXObject("Scripting.FileSystemObject"));
}
function read() {
if(initialized)
return;
initialized = true;
getFso();
if(!fso.FileExists(iniFile))
return;
var textStream = fso.OpenTextFile(iniFile, 1 /*read*/, false /*create*/, -1 /*unicode*/);
while(!textStream.AtEndOfStream) {
var line = textStream.ReadLine();
var indx = line.indexOf("=");
if(indx == -1)
continue;
var name = line.substr(0, indx);
var val = line.substr(indx + 1);
data[name] = val;
}
textStream.close();
}
function save() {
if(saved)
return;
saved = true;
var textStream = fso.CreateTextFile(iniFile, true /*overwrite*/, true /*unicode*/);
for(var name in data)
textStream.WriteLine(name + "=" + data[name]);
textStream.close();
}
function has(name) {
read();
return name in data;
}
function get(name, defaultValue) {
return has(name)
? data[name]
: String(defaultValue);
}
function set(name, val) {
val = String(val);
if(has(name) && get(name) === val)
return val;
saved = false;
data[name] = val;
return val;
}
function remove(name) {
if(!has(name))
return false;
saved = false;
return delete data[name];
}
function list() {
var r = [];
for(var name in data)
r.push(name);
return r;
}
function reset() {
initialized = true;
saved = true;
data = {};
getFso();
if(fso.FileExists(iniFile))
fso.DeleteFile(iniFile);
}
return {
has: has,
get: get,
set: set,
remove: remove,
save: save,
list: list,
reset: reset
};
}
iniParser.save();
Все бы хорошо, но логичнее, чтобы подобный интерфейс предоставлял сам плагин. Причем тогда можно будет учитывать предпочтения пользователя и хранить настройки или в реестре, или в INI-файле:
HKEY_CURRENT_USER\Software\Akelsoft\AkelPad\Plugs\Scripts\someScript.js\name = val
и
[someScript.js]
name=val
(или отдельными файлами)
FeyFre
У меня есть похожая хотелка: нужна возможность «запланировать» выполнение произвольной функции на момент окончания работы скрипта. Причем хорошо бы, чтобы можно было добавить несколько таких функций – по аналогии с addEventListener("unload", func, false).