Scripts plugin

Discuss and announce AkelPad plugins
  • Author
  • Message
Offline
Site Admin
Posts: 6403
Joined: Thu Jul 06, 2006 7:20 am

Post by Instructor »

Исправлено: необязательный параметр для GetAkelDir().

Fixed: optional parameter for GetAkelDir().


Scripts plugin v7.1

Offline
Posts: 2248
Joined: Tue Aug 07, 2007 2:03 pm
Location: Vinnitsa, Ukraine

Post by FeyFre »

Fr0sT, сбылась мечта идиотов(то бишь нас) - Инструктор реализовал нативный колбек. Теперь ещё бы сделать нам компилятор ресурсов, и диалоги у нас в кармане :)

Offline
Site Admin
Posts: 6403
Joined: Thu Jul 06, 2006 7:20 am

Post by Instructor »

Исправлено: метод ReplaceSel().

Fixed: ReplaceSel() method.


Scripts plugin v7.2

Offline
Posts: 2248
Joined: Tue Aug 07, 2007 2:03 pm
Location: Vinnitsa, Ukraine

Post by FeyFre »

Instructor, а можно так что-бы в RegisterCallback передавалось не имя глобальной функции а сама функция(локальная либо анонимная).

Code: Select all

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);
}
либо так

Code: Select all

var func = oSys.RegisterCallback(function(param1,param2){
  //stuff in callback
});
  oSys.Call("module::function_with_callback_arg",param, func);
  oSys.UnregisterCallkback(func);

Offline
Site Admin
Posts: 6403
Joined: Thu Jul 06, 2006 7:20 am

Post by Instructor »

FeyFre
Чтобы создать обратный вызов с динамическим количеством параметров? Для чего это нужно?

Offline
Posts: 2248
Joined: Tue Aug 07, 2007 2:03 pm
Location: Vinnitsa, Ukraine

Post by FeyFre »

Нет, количество параметров остается постоянным - таким как задано в объекте функции которую передадут в вызов.
Для того что-бы создавать замыкания. Глобально объявленная функция видит только глобальные переменные. А функция объявленная внутри другой функции, цикла, ветвления видит также объявленные в них переменные, и может их использовать.(Собственно замыкания одно из мощнейших средств ECMA)

Code: Select all

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 уже не существует, можем их имена использовать сколько угодно раз.

Offline
Site Admin
Posts: 6403
Joined: Thu Jul 06, 2006 7:20 am

Post by Instructor »

FeyFre
Попробовал, но не получилось, чтобы GetIDsOfNames распознал имя функции внутри функции.

Offline
Site Admin
Posts: 6403
Joined: Thu Jul 06, 2006 7:20 am

Post by Instructor »

Исправлено: true после VariantChangeType превращался в -1.

Fixed: true after VariantChangeType became to -1.


Scripts plugin v7.3

Offline
Posts: 2248
Joined: Tue Aug 07, 2007 2:03 pm
Location: Vinnitsa, Ukraine

Post by FeyFre »

Instructor
Нет, в регистратор передается не строка-имя функции а объект-функция, и с ним уже можно работать непосредственно.

Т.е у Вас есть сейчас так:

Code: Select all

HRESULT STDMETHODCALLTYPE SystemFunction_RegisterCallback(ISystemFunction *this, BSTR wpCallbackName, IDispatch **objFunction)
{
  IDispatch *objScript;
  IDispatch *objCallback=NULL;
  ITypeInfo *pTypeInfo;
  TYPEATTR *pAttr;
  FUNCDESC *pFuncDesc=NULL;
  DISPPARAMS dispp;
  VARIANT vtResult;
  DISPID dispidCallbackName;
  DWORD dwArgCount=0;
  int i;
  HRESULT hr;

  if ((hr=g_objActiveScript->lpVtbl->GetScriptDispatch(g_objActiveScript, 0, &objScript)) == S_OK)
  {
    if ((hr=objScript->lpVtbl->GetIDsOfNames(objScript, &IID_NULL, &wpCallbackName, 1, LOCALE_USER_DEFAULT, &dispidCallbackName)) == S_OK)
    {
      //Get function IDispatch
      dispp.rgvarg=NULL;
      dispp.rgdispidNamedArgs=NULL;
      dispp.cArgs=0;
      dispp.cNamedArgs=0;

      if ((hr=objScript->lpVtbl->Invoke(objScript, dispidCallbackName, &IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &dispp, &vtResult, 0, 0)) == S_OK)
      {
        objCallback=vtResult.pdispVal;

        //Get function arguments count
        if ((hr=objScript->lpVtbl->GetTypeInfo(objScript, 0, LOCALE_USER_DEFAULT, &pTypeInfo)) == S_OK)
        {
А я предлагаю так

Code: Select all

HRESULT STDMETHODCALLTYPE SystemFunction_RegisterCallback(ISystemFunction *this, IDispatch *objScript, IDispatch **objFunction)
{
  IDispatch *objCallback=NULL;
  ITypeInfo *pTypeInfo;
  TYPEATTR *pAttr;
  FUNCDESC *pFuncDesc=NULL;
  DISPPARAMS dispp;
  VARIANT vtResult;
  DISPID dispidCallbackName;
  DWORD dwArgCount=0;
  int i;
  HRESULT hr;
  if ((hr=objScript->lpVtbl->GetIDsOfNames(objScript, &IID_NULL, &wpCallbackName, 1, LOCALE_USER_DEFAULT, &dispidCallbackName)) == S_OK)
  {
    //Get function IDispatch
    dispp.rgvarg=NULL;
    dispp.rgdispidNamedArgs=NULL;
    dispp.cArgs=0;
    dispp.cNamedArgs=0;
  
    if ((hr=objScript->lpVtbl->Invoke(objScript, dispidCallbackName, &IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &dispp, &vtResult, 0, 0)) == S_OK)
    {
      objCallback=vtResult.pdispVal;
  
      //Get function arguments count
      if ((hr=objScript->lpVtbl->GetTypeInfo(objScript, 0, LOCALE_USER_DEFAULT, &pTypeInfo)) == S_OK)
      {
Признаюсь, пример делал на коленке. Суть такова: переменную objScript вы не ищете сами, а Вам её уже передали аргументом. Вам остается её только посчитать аргументы, сохранить(AddRef-нуть не забыть) в lpCallback. Так только время появится - сам попытаюсь реализовать, в будний день просто некогда.

Offline
Site Admin
Posts: 6403
Joined: Thu Jul 06, 2006 7:20 am

Post by Instructor »

FeyFre
Я готов подождать, когда появится работающий экземляр :) И меня интересует вариант, при котором не прийдется указывать количество аргументов при вызове RegisterCallback.

Offline
Posts: 2248
Joined: Tue Aug 07, 2007 2:03 pm
Location: Vinnitsa, Ukraine

Post by FeyFre »

И меня интересует вариант, при котором не прийдется указывать количество аргументов при вызове RegisterCallback.
на сколько я понял RegisterCallback работает исключительно с __stdcall . А потому не может идти речи об неизвестном количестве аргументов.

Да и не всякий скриптовый движок понимает такие финты. Это мы привыкли к JScript. В VBScript я соовсем не уверен. А если у кого-то ещё какой-нибудь язык подключен к WSH?

Offline
Posts: 1
Joined: Mon Nov 01, 2010 2:28 pm

Post by Terrana »

А с файлами какого размера этот плагин успешно работает?
Попробовала воспользоваться функцией "Фильтр строк с регулярным выражением", на лог-файле в 80Мб при фильтре:
Строка содержит: "QUEUE"
Учитывать регистр
Оставить строки
меня благополучно выкинуло:
"Всплывающее окно приложения: AkelPad - [c:\tmp\newsmsgw\SystemOut_10.10.23_07.18.34.log]: AkelPad.exe - Ошибка приложения : Инструкция по адресу "0x00429e81" обратилась к памяти по адресу "0x00000000". Память не может быть "read".

"ОК" -- завершение приложения
"Отмена" -- отладка приложения
"

С файлом размера 2Мб всё прошло успешно.
У меня, конечно, всего 2,5Гб ОЗУ, но вроде бы должно было хватить.

Offline
Site Admin
Posts: 6403
Joined: Thu Jul 06, 2006 7:20 am

Post by Instructor »

Terrana
Ограничения не предусмотрены :) Если используется Scripts v7.3 и ошибка воспроизводится постоянно, то высылайте на почту архив проблемного файла (или на файлообменник).

Offline
Posts: 2248
Joined: Tue Aug 07, 2007 2:03 pm
Location: Vinnitsa, Ukraine

Post by FeyFre »

Хотелка.
(Начну с конца)
В функцию AkelPad.MessageBox добавить 5-ый аргумент.
Этот аргумент функция(остальные типы не валидные).
Назначение:
Если аргумент валидный(функция, не null), то при отображении окна-сообщения добавить к нему птичку где-то снизу или справа от кнопок с надписью "прекратить выполнение скрипта"(если не валидный - птичку не ставим, ничего не меняется).
Если птичка стоит и нажали какую-нибудь кнопку, то плагин выполняет эту функцию а после того как она выполнилась вместо того что-бы вернуть управление скрипту, завершает его. Если птичка не стоит - работает как раньше.
Фича очень полезна при:
1) Отладке скриптов(а) - зачистка выделенной памяти AkelPad.MemAlloc(которая утечет до завершения процесса), Уничтожение системных объектов(окна, контексты, открытые файлы, другие дескрипторы)
2) При выполнении многошаговых контролируемых операций - может быть использована как команда "прервать задачу и откатить назад", вне зависимости от нажатой кнопки(иногда трех кнопок может и не хватить).
3) Ваш вариант.

Code: Select all

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 боксах Оперы.

Offline
Posts: 1873
Joined: Mon Aug 06, 2007 1:07 pm
Contact:

Post by Infocatcher »

Интереса ради попробовал сделать интерфейс для работы с настройками в INI-файлах:

Code: Select all

// (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).
Post Reply