Native функции: Часть 1: Порядок действий и простейший пример | |
Итак, обозначим порядок наших действий:
- Написать нативку и скомпилировать dll
- Добавить объявление написанной нативки в common.j
- Написать код, использующий нативку
- Запустить игру
Для начала возьмём классический пример "Hello world": напишем функцию,
которая не принимает параметров, а возвращает некоторую строку. Вот наш
test.cpp
#include <windows.h>
#include <stdio.h>
#define jNATIVE __stdcall
#define jAPI __cdecl
#define jString long
#define jInt long
#define jReal long
typedef void(jAPI *jpAddNative)(void *routine, char *name, char *prototype);
typedef jString(jAPI *jpStrMap)(const char *str);
typedef const char*(jAPI *jpStrGet)(jString strid);
jpAddNativejAddNative = NULL;
jpStrMapjStrMap = NULL;
jpStrGetjStrGet = NULL;
jString jNATIVE test()
{
char *s = "ZOMG TEH FUNC!";
return jStrMap(s);
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
if (ul_reason_for_call != DLL_PROCESS_ATTACH) return TRUE;
DisableThreadLibraryCalls(hModule);
HMODULE hjApi = GetModuleHandle("japi.dll");
jAddNative = (jpAddNative)GetProcAddress(hjApi, "jAddNative");
jStrMap= (jpStrMap)GetProcAddress(hjApi, "jStrMap");
jStrGet= (jpStrGet)GetProcAddress(hjApi, "jStrGet");
jAddNative((void *)test, "test", "()S");
return TRUE;
}
|
Два важных места здесь - это:
jString jNATIVE test() {
char *s = "ZOMG TEH FUNC!";
return jStrMap(s);
и
jAddNative((void *)test, "test", "()S");
Третий аргумент функции jAddNative определяет типы, передаваемые функции и
возвращаемые ей.
Теперь скомпилируем DLL. Для этого в командной строке напишем
bcc32 -WD -e"test.dll" test.cpp
-WD значит компилировать dll, -e определяет выходной файл и test.cpp -
соответственно наш файл с исходным текстом.
Следующим шагом нам необходимо добавить эту функцию в common.j (если у вас
его нет, всегда можно достать последнюю версию из war3patch.mpq):
native test takes nothing returns string
Теперь создадим карту, в которой будет вызвана наша функция. Назовем её
test.w3m и сохраним в папку Maps директории Warcraft. В карте создадим триггер
Test, выполняющийся при инициализации и в действия добавим:
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,test())
Не забудьте импортировать в карту измененный common.j с путем
"scripts\common.j", иначе при сохранении будет выдана ошибка.
Пришло время запускать игру. Распакуйте Grimoire в какую-то директорию
неподалёку и приготовьтесь печатать. Открываем startwar3.bat, пишем и
сохраняем:
bin\exehack.exe -s war3.lua -loadfile "Maps\test.w3m"
Теперь редактируем ongameload.lua, вот всё, что должно в нем
остаться:
loaddll("bin\\japi.dll") loaddll("bin\\test.dll")
|