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: если ноль – ошибка, не ноль – повторная попытка вызова.
Т.е. вместо
сделать
Если править бинарник, в случае 32-разрядной версии по смещению 0xAC0 в файле произвести замену 83F801 74B1 -> 83F800 75B1.
