101 (изменено: maksim32, 2018-03-29 16:52:25)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Parazit, пожалуйста.
Нет, не из-за выравнивания, BOOL в windows это int. Но есть и тип BOOLEAN: sizeof(BOOLEAN) = 1 байту. Размер структур, её членов и смещения лучше уточнять, например, я с помощью элементарной программки на C в VisualStudio проверяю.

typedef int BOOL;

https://msdn.microsoft.com/en-us/librar … s.85).aspx

102 (изменено: Parazit, 2018-03-29 18:15:53)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

maksim32, а для чего вообще делается выравнивание?
Размер структуры должен быть чему-то кратен?

Т.е, если у меня есть член размером 8 байт,
то я должен все другие члены выравнивать под этот размер?

103 (изменено: maksim32, 2018-03-29 17:16:42)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Parazit, в языках C/C++ (на чём написаны функции WinApi) члены структур выравниваются для наиболее быстрого доступа к ним - если число в памяти попадает на границу, например 32-битного числа у 32-битного процессора, то загрузка числа в регистр процессора будет выполняться дольше.
https://ru.wikipedia.org/wiki/%D0%92%D1 … 1%8B%D1%85

Некоторые структуры в windows.h описаны с явно указанным выравниванием (#pragma pack), а в остальных случаях выравнивание равно размеру самого большого члена в структуре (кратного степени двойки).
https://msdn.microsoft.com/en-us/librar … s.60).aspx

Да, поэтому, структура SECURITY_ATTRIBUTES имела размер 12 на x32, т.к. выравнивание было 4 байта (размер каждого из членов по 4 байта), а на x64 24 байта, т.к. указатель PVOID занимает уже 8 байт и выравнивание членов структуры будет кратным 8-ми байтам.
Размер структуры также кратен выравниванию.

104

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

maksim32, спасибо, за информацию.

105

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Что-то у меня выдаёт ошибку, что неподдерживаемый тип параметра.
Ни post, ни send  не могу послать.

Const WM_GETTEXT = &HD
Set Wrap = CreateObject("DynamicWrapperX")
Wrap.Register "USER32.DLL", "GetForegroundWindow", "f=s", "r=l"
Wrap.Register "USER32.DLL", "SendMessage", "i=lllr", "f=s", "r=l"
Title = Space(100)
res = Wrap.SendMessage(Wrap.GetForegroundWindow(), WM_GETTEXT , 100, Title)
MsgBox Title

106 (изменено: maksim32, 2018-04-14 23:32:17)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Потому что типа "r" не существует, в документации отсутствует: http://dynwrapx.script-coding.com/dwx/pages/types.php. Вот рабочие параметры для регистрации этих функций:

DWX.Register("user32","PostMessage","i=huhp","r=l"); // HWND,UINT,WPARAM,LPARAM; BOOL
DWX.Register("user32","SendMessage","i=huhp","r=p"); // HWND,UINT,WPARAM,LPARAM; LRESULT
DWX.Register("user32","GetForegroundWindow","r=h"); // void; HWND

107 (изменено: maksim32, 2018-04-14 23:35:12)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Обращайте внимание, что указатели имеют непостоянный размер в ОС различных разрядностей, поэтому возвращаемое значение GetForegroundWindow типа "l" будет работать только в 32-битных (x86) системах. Корректнее дескрипторам давать тип "h".
Также флага "s" не существует, поэтому "f=s" - это лишнее. Про флаги подробнее тут: http://dynwrapx.script-coding.com/dwx/p … gister.php

108 (изменено: Parazit, 2018-04-14 23:46:28)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

maksim32, ну вот смотрите, я хочу послать сообщение.

var DWX = new ActiveXObject("DynamicWrapperX.2"), a = new ActiveXObject("AutoItX3.Control"), s;
s = a.WinGetHandle("[CLASS:TTOTAL_CMD]", "");
// echo(s);

DWX.Register("user32.dll", "PostMessage", "i=hull");
DWX.PostMessage(s, 1075, 501, 0);

И у меня выдаёт ошибку, что тип аргумента непреводим к типу параметра.

109

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

new ActiveXObject("AutoItX3.Control").WinGetHandle вроде бы возвращает строку, а вы её как дескриптор ("h") передаёте первым параметром. Преобразовать надо строку к дескриптору, судя по описанию ошибки. И вы снова путаете типы: размер WPARAM и LPARAM у функции PostMessage зависит от разрядности ОС.

110

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Первый код работает с такими переделками:


Const WM_GETTEXT = &HD
Set Wrap = CreateObject("DynamicWrapperX")
Wrap.Register "USER32.DLL", "GetForegroundWindow", "r=h"
Wrap.Register "USER32.DLL", "SendMessageW", "i=huhW", "r=h"
Title = Space(100)
res = Wrap.SendMessageW(Wrap.GetForegroundWindow(), WM_GETTEXT , 100, Title)
MsgBox Title

111

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Чё-то не работает в PSPad-скриптах.
Jscript срабатывает редко, а VBScript вообще никах. Возращает 0.

Наверное, в этом редакторе какая-то защищённая оболочка.

112

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Не понимаю, о чём речь. Не пользуюсь этим редактором. Что это за скрипты?

113

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Ну скрипты для работы с текстом.
Там он предоставляет WSH, и можно создавать Jscript и VBScript скрипты.
При вызове функции обратного вызова, вообще ошибку выдаёт.

114 (изменено: alexii, 2018-09-30 23:42:31)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

YMP, после установки приложения в каталоге установки создаётся каталог Script с подкаталогами:

JScript
JScript.Compact
VBScript
XML

Внутри каталога VBScript лежат три примера/образца скриптов:

ListTransform.vbs
PrinAll.vbs
VBIndent.vbs

После активации в настройках \Settings\Program Settings…, вкладка System integration, пункта «Integrated scripting support (WSH)» (никаким WSH на самом деле там, как я понимаю, даже и близко не пахнет, гольный VBScript/JScript & etc):

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

https://i.imgur.com/ber0amI.png

в меню появляется новый пункт Scripts. Ссылка на экземпляр объекта редактора создаётся как вызов функции:

Set editor = newEditor()

.

В документации скриптам посвящены разделы Script User's Guide, Script Language Reference и PSPad Actions.

115

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Parazit, теперь Вы можете излагать Ваш код и описывать, что он должен был делать.

116

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Спасибо, alexii, разобрался. Сначала смотрел портабельную версию, там нет этих папок.

С callback какие-то проблемы только в VBS. Пока не ясно, в чём дело. В остальном вроде всё нормально работает.

117

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Это я немного натупил, вроде всё работает.

118 (изменено: Parazit, 2018-10-01 18:58:44)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Del

119

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Вы, видимо, не в курсе, что переменные, объявленные через var внутри функции, являются локальными? Из другой-то функции их не видно.

120

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Проблемы с callback в VBS оказались тоже из-за области видимости переменных. В JS и VBS разные умолчания насчёт переменных внутри функций. Так что в VBS нужно объявлять глобально те переменные, которые используются в нескольких функциях.

121 (изменено: maksim32, 2019-03-21 05:37:14)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

YMP, здравствуйте!
Было бы очень удобно иметь возможность регистрации функций при первой необходимости (а не только перед использованием).
К примеру, иметь коллбэк типа OnFunctionNotFound, который бы вызывался перед выбросом исключения о том, что функция не найдена/не зарегистрирована ("800A01B6: Объект не поддерживает это свойство или метод").

Чтобы было возможным писать подобный код (используя большую библиотеку объявленных, но не зарегистрированных функций):

+ открыть спойлер
var host = {
  "activex": function(progid){ return new ActiveXObject(progid); },
  "alert": function(msg){ WScript.Echo(msg); },
  "exit": function(code){ WScript.Quit(code); }
};

// Сгенерированный ассоциативный массив с описаниями для регистрации функций из DLL.
var function_defs= {
  // WINUSERAPI int WINAPI MessageBoxW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType);
  "MessageBoxW": ["user32", "MessageBoxW", "i=hppu", "r=l"]
};

var DWX = host.activex("DynamicWrapperX");
if(DWX.Version(7) < 0x2000100010001) host.exit(1);

// Хотелось бы дополнительно загружать функции по мере необходимости, а не перед использованием.
// DWX.Register("user32", "MessageBoxW", "i=hppu", "r=l"); // HWND,LPCWSTR,LPCWSTR,UINT; int

DWX.OnFunctionNotFound = function(func_name) {
  var opts, res = 0;
  if(opts = function_defs[func_name]) {
    DWX.Register(opts[0], opts[1], opts[2], opts[3]);
    res = 1;
  }
  return res;
};

try {
  var ret = DWX.MessageBoxW(0, "Dynamic register function is successful!", "JScript", 0x40);
  host.alert("return code: " + ret);
} catch(err) {
  host.alert("Test failed...");
}

Описывая логику в псевдокоде, типа так:

+ открыть спойлер
DWX.__CallProc__ = function(__procname__) {
  try {
    call __proc__
  } catch() {

    // Вот что-то подобное?
    if(DEFINED(this->OnFunctionNotFound) && this->OnFunctionNotFound(__procname__)) {
      try {
        call __proc__
        jmp success
      } catch() {}
    }
    
    throw "800A01B6: doesn't support";
  }
success:
  return eax
}

Как вы смотрите на такое предложение?

122

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Предложение интересное, но надо подумать, как это реализовать. Кстати, может, стоит сделать в более общем виде, т.е. событие OnError с указанием кода ошибки. Ведь функция может не найтись и в DLL, да и DLL может не оказаться, и мало ли что ещё. Реализовывать каждую ошибку как событие с отдельным именем будет громоздко, я думаю. А так вы либо изначально ограничите вызов обработчика нужным вам кодом ошибки, либо он будет вызываться при любой ошибке и по её коду решать, как реагировать. Что-то в таком духе.

123

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

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

124

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Посмотрел в сторону подключения к событиям через WScript.ConnectObject, но это какая-то жесть. Нужно реализовать 5 входящих интерфейсов и вшить в DLL библиотеку типов, описывающую исходящий интерфейс. Причём непонятно, каким он, собственно, должен быть. Думаю пойти более простым путём, просто сделать метод OnError, который принимает ссылку на функцию-обработчик. А передавать ей можно объект Error, через методы которого обработчик может извлекать всю нужную информацию и инструктировать DWX о дальнейших действиях.

125 (изменено: maksim32, 2019-03-25 22:53:14)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Мне больше нравится второй, более простой вариант, когда функционал библиотеки доступен сам по себе. С WScript.ConnectObject работать не приходилось, думаю, эта зависимость будет лишняя. Да и в приложениях с HTML-интерфейсом (mshta) будет не легко получить к этому доступ.
Спасибо, что приняли во внимание моё пожелание!

126

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Задача была вытащить из базы данных избранную функцию.

Зачем там интерфейсы?
Зачем коннектиться к какому-то объекту?
Зачем отслеживать события?

Обычную GetLastError, и всё.
При ошибке вернуть -1.

127 (изменено: YMP, 2019-03-27 11:12:34)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Ничего не понял. При чём тут GetLastError?

128

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Посмотрите его первый код.
Он предлагает создать метод .activex, передавать ему параметры,
которые будут инициализировать метод .Register.
В библиотеке будет куча API-функций.
Параметром передавать необходимую API-функцию, параметры к этой функции,
и типы этих параметров (ещё и DLL-ку тоже надо передавать),
чтобы её зарегистрировать в качестве объекта (DWX).
Т.е., динамически регистрировать функцию в любом месте кода.

А GetLastError будет указывать на ошибку API, если таковая будет присутствовать.

Вы же говорите, что надо инициализировать какие-то пять интерфейсов.

129

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

По-моему, вы не улавливаете, о чём речь. Метод activex вообще тут не при делах. Требуется возможность назначать скриптовую функцию как обработчик ошибки в случае, если идёт попытка вызвать через DWX функцию, которая не была предварительно зарегистрирована. DWX должен передать обработчику имя ненайденного метода, а обработчик соответствующую функцию должен зарегистрировать, если она есть в библиотеке. DWX соответственно либо делает повторный поиск метода и исполняет его, либо возвращает ошибку.

130

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

maksim32
Я пока отказался от планов насчёт всех ошибок, т.к. не вижу реалистичных сценариев их использования, и реализовал только метод OnMemberNotFound. Он принимает ссылку на функцию, а функции передаёт имя ненайденного метода. В общем, всё как в вашем коде, только подправить OnFunction на OnMember. OnFunctionNotFound скорее подошло бы для функции, не найденной в DLL, а то, что в объекте, это уже метод или свойство. Пробная версия здесь: https://yadi.sk/d/4k-v9xsEf7f-qg

131 (изменено: maksim32, 2019-04-01 16:44:39)

Re: WSH: обсуждаем DynamicWrapperX от YMP - 2

Parazit, динамически регистрировать функцию в любом месте кода можно методом DWX.Register, тут всё хорошо.
Вопрос в том, чтобы вообще руками не регистрировать, а регистрация происходила автоматически при первом вызове. К тому же, не для всех функций регистрация заключается лишь в передачи модуля, имени, типов аргументов ("i=") и возвращаемого значения ("o=") из массива.
Для функции SetClassLongPtrW, например, регистрация различается в зависимости от разрядности хоста:

+ открыть спойлер
if(bitness === 64) {
  DWX.Register("user32","SetClassLongPtrW","i=hlp","r=p"); // HWND,int,LONG_PTR; ULONG_PTR
} else {
  DWX.Register("user32:SetClassLongW","SetClassLongPtrW","i=hll","r=u"); // HWND,int,LONG; DWORD
}

А для функции GetModuleFileNameExW, в зависимости от версии системы, регистрация выполняется даже из разных модулей (лучше переделать без try-catch, но пока так):

+ открыть спойлер
try { // for NT5.1 or later
  DWX.Register("psapi","GetModuleFileNameExW","i=hhpu","r=u"); // HANDLE,HMODULE,LPWSTR,DWORD; DWORD
} catch(e) {
  try { // for NT6.1 or later
    DWX.Register("kernel32:K32GetModuleFileNameExW","GetModuleFileNameExW","i=hhpu","r=u"); // HANDLE,HMODULE,LPWSTR,DWORD; DWORD
  } catch(e) {
    host.error(new Error("Функция GetModuleFileNameExW не найдена!"));
    host.exit(1);
  }
}

Пробовал по-разному такую функциональность реализовать, но вариант каждый вызов winapi-функции оборачивать в try-catch не выход, а при реализации обёрточной функции встаёт проблема передачи аргументов (+ лишняя нагрузка на каждый вызов winapi-функции, а, например, 3d рендринг и без того ограничен подобными накладными затратами, да и при обычном изменении размеров окна перерисовка затратна), к тому же некрасивый код выходит:

+ открыть спойлер
var host = {
  "activex": function(progid){ return new ActiveXObject(progid); },
  "error": function(msg){ if(host.activex("WScript.Shell").Popup(msg instanceof Error && msg.message || msg, 0, "JScript host", 48 + 1) === 2) host.exit(1); },
  "exit": function(code){ WScript.Quit(code || 0); }
};

var DWX = host.activex("DynamicWrapperX");
if(DWX.Version(7) < 0x2000100010001) host.exit(1);

function define(name) {
  // захардкожу
  if(name === "MessageBoxW") DWX.Register("user32", "MessageBoxW", "i=hppu", "r=l"); // HWND,LPCWSTR,LPCWSTR,UINT; int
  return true;
}

function call(name, args) {
  var retval;
  var call_internal = function() {
    // так не прокатывает
    // return DWX[name].apply(DWX, args);
    
    // а так костыль страшный
    switch(args.length) {
    case 0: return DWX[name]();
    case 1: return DWX[name](args[0]);
    case 2: return DWX[name](args[0], args[1]);
    case 3: return DWX[name](args[0], args[1], args[2]);
    case 4: return DWX[name](args[0], args[1], args[2], args[3]);
    // ...
    }
  };
  try {
    retval = call_internal();
  } catch(err) {
    if(define(name)) {
      try {
        retval = call_internal();
      } catch(err) {
        host.error(new Error("Функция " + name + " недоступна."));
        host.exit(1);
      }
    } else {
      host.error(new Error("Функция " + name + " не определена."));
      host.exit(1);
    }
  }
  return retval;
}

// Эстетически это выглядит страшнее, чем DWX.MessageBoxW(...)
call("MessageBoxW", [0, "Dynamic load function is success!", "JScript", 0x40]);

До этого момента проходилось либо регистрировать большое множество ненужных функций даже для вывода helloworld, в случае использования моей библиотеки функций, либо по мере необходимости копировать из неё определения по-отдельности, но ручная работа «линковщика» удовольствия не доставляет, гораздо удобнее иметь одну внешнюю библиотеку для проектов.


YMP, спасибо вам большое! Работает)
Я тоже не вижу, только если в целях унификации механизма. Хотя ошибку "модуль не найден" в некоторых случаях тоже можно обработать, организовав дополнительный поиск, но т.к. эта ошибка возникает при регистрации функции, там же можно и перехват исключения организовать: в дополнительном инструменте необходимости, на мой взгляд, нет.
На «событийном механизме» не настаиваю, но до более красивого варианта организовывать динамическую регистрацию функций я пока не додумался. На названии не настаиваю тем более, я лишь для примера писал

С названием OnMemberNotFound согласен. Только нашёл странность в её поведении: вернув true получаем ошибку (как и при возврате false), т.к. true преобразуется к -1 (что делает невозможным возвращать результат сравнения без конструкции a == b ? 1 : 0). Кажется лучше сделать проверку на 0: если ноль – ошибка, не ноль – повторная попытка вызова.

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

Т.е. вместо

cmp eax,1
je short -79

сделать

cmp eax,0
jne short -79

Если править бинарник, в случае 32-разрядной версии по смещению 0xAC0 в файле произвести замену 83F801 74B1 -> 83F800 75B1.
https://pp.userapi.com/c854124/v854124697/15ab4/rc7sY0Vl7RA.jpg