Unreal Tournament: Работа с DLL

Программирование в UDK.

UnrealScript

К одному классу UnrealScript можно прикрепить только один DLL-файл. Библиотеки могут быть загружены из каталога Binaries\Win32\UserCode.
Импортированная функции объявляется как функция UnrealScript с использованием директивы dllimport.
Когда импортированная из DLL функция полностью объявляется, становится невозможным создать подкласс для класса DLLBind.
Например:
class TestDLLPlayerController extends PlayerController
DLLBind(TestDLL);
dllimport final function CallDLL1(out string s);
dllimport final function vector CallDLL2(float x, float y, float z);
dllimport final function bool CallDLL3(string s, int i[2], out float f, out vector v);
Когда класс TestDLLPlayerController загружен, он начинает вызывать Binaries\Win32\UserCode\TestDLL.dll. Если DLL не может быть вызвана, в логах появится соответствующая заметка. Функция попытается найти позицию для аттача DLL (их 3 - CallDLL1, CallDLL2 и CallDLL3). По завершению эта функция может быть вызвана как и все обычные функции UnrealScript. Если не удастся приаттачить, то эта функция попросту не будет работать.

DLL

Функции могут быть реализованы в DLL при помощи C++ следующим образом:
extern "C"
{
   struct FVector
   {
      float x,y,z;
   };

   __declspec(dllexport) void CallDLL1(wchar_t* s)
   {
      MessageBox(0, s, L"Inside the DLL: CallDLL1", MB_OK);
      // возвращаем строковый параметр
      int len = wcslen(s);
      for(int i=0; i<len>>1;i++)
      {
         wchar_t temp = s__;
         s__ = s[len-i-1];
         s[len-i-1] = temp;
      }
   }

   __declspec(dllexport) FVector* CallDLL2(float x, float y, float z)
   {
      static FVector result;   // объявление в памяти и возврат функции.
      result.x = x;
      result.y = y;
      result.z = z;
      return &result;
   }

   __declspec(dllexport) bool CallDLL3(wchar_t* s, int i[2], float* f, FVector* V)
   {
      wchar_t temp[1024];
      swprintf_s(temp, 1024, L"string: %s, i: {%d,%d}, float: %f, V was (%f,%f,%f)", s, i[0], i[1], *f, V->x, V->y, V->z);
      V->x = (float)i[0];
      V->y = (float)i[1];
      V->z = (*f);
      return (MessageBox(0, temp, L"Inside the DLL: CallDLL3", MB_OKCANCEL) == IDOK);
   }
}

Выгрузка при помощи API

Когда класс объекта класса DLLBind (ток не путайтесь, один класс относится к объекту, второй к библиотеке) уничтожен, DLL будет выгружена при помощи FreeLibrary API. Если быть точнее, то это произойдет когда будет удалена последняя ссылка на класс объекта. Затем вручную мы должны очистить нашу библиотеку функцией DllMain().

Поддерживаемые типы параметров

Поддерживаются следующие типы параметров:
Тип в UnrealScriptТип в СиКомментарий
int valueint value (32-bit)Передает значение value
int value[..]int* value (32-bit)Передает ссылку reference
out int valueint* value (32-bit)Передает ссылку reference
float valuefloat valueПередает значение value
float value[..]float* valueПередает ссылку reference
out float valuefloat* valueПередает ссылку reference
byte valueunsigned char valueПередает значение value
byte value[..]unsigned char* valueПередает ссылку reference
out byte valueunsigned char* valueПередает ссылку reference
string valuewchar_t* valueПередает ссылку reference
out string valuewchar_t* valueПередает ссылку reference (смотрите предупреждение ниже!)
struct foostruct foo* valueПередает ссылку reference. DLL должна объявить структуру в соответствии со структурой UnrealScript
out struct foostruct foo* valueПередает ссылку reference
Поддерживаются следующие типы возврата значения:
Тип в UnrealScript Тип в CиКомментарий
IntInt (32-bit)Непосредственно возвращает значение
floatfloat valueНепосредственно возвращает значение
byteunsigned charНепосредственно возвращает значение
boolunsigned int (32-bit)Непосредственно возвращает значение (отличное от нуля будет равно true)
stringwchar_t *указатель значения strcpy'd в строке UnrealScript. См. предупреждение ниже
struct foostruct foo*структура данных memcpy'd в структуре UnrealScript. См. предупреждение ниже
Ограничения
  • Поддерживаются только строки Unicode (UTF-16). DLL необходимо компилировать с Юникодом.
  • Для 32-разрядной версии UDK доступны только 32-разрядные библиотеки DLL. Аналогично для 64-разрядной версии.
  • Библиотеки могут быть загружены только из каталога Binaries\Win32\UserCode.
  • Под Win32, поддерживается только STDCALL (это вызов конвенций).
Предупреждения
  • При изменении строки из параметра, новая строка должна быть короче или же равная по длине предыдущему значению строки. В противном случае возможна перезапись данных в памяти или же вовсе крах системы.
  • При возврате структур или строки, DLL возвращает указатель и Unreal копирует значение обратно в UnrealScript. Однако DLL отвечает за распределение памяти для хранения данных указателя. Например, она может вернуть указатель на статическую переменную, как это делается в CallDLL2. Возврат указателя на переменную, объявленную в стеке приведет к фатал еррору, потому что стек разрушается, когда DLL возвращает функцию.
  • В UnrealScript структуры выравниваются на 4 байта, поэтому желательно использовать опцию / Zp4 при компилировании вашего DLL.
  • Можно объявить структуру, содержащую тип данных Unreal. Однако DLL этого не поймет. Так что делать так не рекомендую.
Собственно в конце статьи, прикрепляю пример реализации вызова функции из DLL в UDK.

Просмотров: 3 534

3 комментария удалено
OBowb #4 - 9 лет назад -1
чета я нифига не понял