UDN
Search public documentation

DLLBind
Licensees can log in.

Red links require licensee log in.

Interested in the Unreal engine?
Check out the licensing page.

Questions about UDN itself?
Contact the UDN Staff

Calling DLLs from UnrealScript (DLLBind)

Document Summary: This document describes how to call functions in DLLs from UnrealScript.

Document Changelog: Created by Jack Porter.

Overview

Starting from the December 2009 version, UnrealScript has the ability to call functions implemented in a Windows DLL. This functionality is intended for use by UDK developers, and for mod makers developing extensions to 3rd party Unreal Engine 3 products. Full-license Unreal Engine 3 developers are able to create Native Classes to call native code directly and should not use this feature. It is disabled by default in licensee source code. To enable it, enable the libffi section of UE3BuildWin32.cs.

UnrealScript side

A single UnrealScript class can bind to only a single DLL. The DLL to bind to is specified with the DLLBind directive, and the DLL name to bind to is specified in parentheses. Do not include a path or .DLL extension. DLLs can only be loaded from the Binaries\Win32\UserCode folder.

Imported functions are declared like UnrealScript functions using the dllimport function directive.

DLL import functions must be declared final, and it is not possible to create a subclass of a DLLBind class.

For example:

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);

When the TestDLLPlayerController class is loaded, it will bind to Binaries\Win32\UserCode\TestDLL.dll. If the DLL cannot be bound, a warning will be printed in the log. It will attempt to find entry points to three exports in the DLL (CallDLL1, CallDLL2 and CallDLL3). Once bound, these functions can be called as normal from other UnrealScript functions. If the bind fails, making a call to one of these functions will have no effect.

DLL side

These functions can be implemented in a C++ DLL like this:

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);
      // reverse the out parameter string
      int len = wcslen(s);
      for(int i=0; i<len>>1;i++)
      {
         wchar_t temp = s[i];
         s[i] = s[len-i-1];
         s[len-i-1] = temp;
      }
   }

   __declspec(dllexport) FVector* CallDLL2(float x, float y, float z)
   {
      static FVector result;   // declared static so that the struct's memory is still valid after the function returns.
      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);
   }
}

Unloading

When the DLLBind class's Class object is destroyed, the DLL will be unloaded using the FreeLibrary API. This should occur when the last reference to the Class object is deleted and garbage collection occurs. You should be able to perform cleanup in your DLL's DllMain() function by responding to the DLL_PROCESS_DETACH fdwReason.

Supported Parameter Types

The following parameter types are supported:

UnrealScript type C type  
int value int value (32-bit) passed by value
int value[..] int* value (32-bit) passed by reference
out int value int* value (32-bit) passed by reference
float value float value passed by value
float value[..] float* value passed by reference
out float value float* value passed by reference
byte value unsigned char value passed by value
byte value[..] unsigned char* value passed by reference
out byte value unsigned char* value passed by reference
string value wchar_t* value passed by reference
out string value wchar_t* value passed by reference SEE WARNINGS BELOW
struct foo struct foo* value passed by reference. The DLL should declare a struct to match the UnrealScript struct.
out struct foo struct foo* value passed by reference

The following return types are supported:

UnrealScript type C type  
int int (32-bit) returns value directly
float float value returns value directly
byte unsigned char returns value directly
bool unsigned int (32-bit) returns value directly, non-zero is true
string wchar_t* pointer value is strcpy'd into a UnrealScript string. SEE WARNINGS BELOW
struct foo struct foo* struct data is memcpy'd into the UnrealScript struct. SEE WARNINGS BELOW

Limitations

  • Only Unicode (UTF-16) strings are supported. Compile your DLL with Unicode enabled.
  • As only the 32-bit version of UDK is currently available, only 32-bit DLLs are supported. At such time as a 64-bit version of UDK is available, 64-bit DLLs will be supported.
  • DLLs can only be loaded from Binaries\Win32\UserCode.
  • Under Win32, only stdcall is supported. (See this link for information about calling conventions).

Warnings

  • When modifying a string out parameter, the new string must be the same length or shorter than the previous value of the string passed in. This can be achieve by initializing the string in UnrealScript to something longer than the maximum value the DLL will store. Failure to do this will likely overwrite memory and cause a crash.
  • When returning structs or strings, the DLL returns a pointer and Unreal will copy the value back to UnrealScript. However the DLL is responsible for allocating the memory to store the data pointed to. For example, it could return a pointer to a static variable, as is done in CallDLL2. Returning a pointer to a variable declared on the stack will result in corrupt data or a crash, because the stack is destroyed when the DLL function returns.
  • In UnrealScript struct members are aligned on 4-byte boundaries, so you should use the /Zp4 compiler option when building your DLL.
  • It is possible to declare structs containing Unreal data types that the DLL cannot understand. It is not recommended you do this!
  • The current working directory will be set to the Binaries\Win32 folder and NOT UserCode, so your DLL should be aware of this if using LoadLibrary to load another DLL or other kind of file access using relative paths. The February 2010 version will be updated to change into the UserCode folder before calling any DLLBind functions.

Example