UDN
Search public documentation
DLLBind
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 theDLLBind 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 |
| 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.
