UDN
Search public documentation:
DLLBindKR
English Translation
日本語訳
中国翻译
Interested in the Unreal Engine?
Visit the Unreal Technology site.
Looking for jobs and company info?
Check out the Epic games site.
Questions about support via UDN?
Contact the UDN Staff
日本語訳
中国翻译
Interested in the Unreal Engine?
Visit the Unreal Technology site.
Looking for jobs and company info?
Check out the Epic games site.
Questions about support via UDN?
Contact the UDN Staff
언리얼스크립트에서 DLL 호출하기 (DLLBind)
개요
언리얼스크립트 측
DLLBind
디렉티브에 지정되어 있으며, 바인드할 DLL명은 접두사에 지정되어 있습니다. 경로나 .DLL 확장자를 포함하지 마십시오. DLL은 Binaries\Win32\UserCode 폴더에서만 로드 가능합니다.
임포트된 함수는 dllimport
함수 디렉티브를 사용하여 언리얼스크립트 함수처럼 선언됩니다.
DLL 임포트 함수는 final로 선언해야 하며, 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의 세 익스포트 지점(CallDLL1, CallDLL2, CallDLL3)에서 도입 지점 검색을 시도합니다. 바인드되면, 이 함수는 다른 언리얼스크립트 함수와 마찬가지로 호출 가능해 집니다. 바인드가 실패하면, 이 함수를 호출해도 아무 효과가 없습니다.
DLL 측
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); } }
언로드
지원 파라미터 유형
언리얼스크립트 유형 | C 유형 | |
int 값 | int 값 (32비트) | 값 전달 |
int 값[..] | int* 값 (32비트) | 참조 전달 |
out int 값 | int* 값 (32비트) | 참조 전달 |
float 값 | float 값 | 값 전달 |
float 값[..] | float* 값 | 참조 전달 |
out float 값 | float* 값 | 참조 전달 |
byte 값 | unsigned char 값 | 값 전달 |
byte 값[..] | unsigned char* 값 | 참조 전달 |
out byte 값 | unsigned char* 값 | 참조 전달 |
string 값 | wchar_t* 값 | 참조 전달 |
out string 값 | wchar_t* 값 | 참조 전달 아래 경고 참고 |
struct foo | struct foo* 값 | 참조 전달. DLL에서 구조체를 선언하여 언리얼스크립트 구조체에 일치시켜야 합니다. 구조체 내부의 문자열에 관한 정보는 아래를 참고하십시오. |
out struct foo | struct foo* 값 | 참조 전달 |
언리얼스크립트 유형 | C 유형 | |
int | int (32비트) | 값 직접 반환 |
float | float | 값 직접 반환 |
byte | unsigned char | 값 직접 반환 |
bool | unsigned int (32비트) | 값 직접 반환, non-zero=true |
string | wchar_t* | 포인터 값이 언리얼스크립트 문자열에 strcpy됩니다. 아래 경고 참고 |
struct foo | struct foo* | 구조체 데이터가 언리얼스크립트 구조체에 memcpy됩니다. 아래 경고 참고 |
제한사항
- 유니코드(UTF-16) 문자열만 지원됩니다. 유니코드를 활성화시키고 DLL을 컴파일하십시오.
- 현재 UDK는 32비트 버전만 가능하므로, 32비트 DLL만 지원됩니다. UDK 64비트 버전이 나오면, 64비트 DLL도 지원될 것입니다.
- DLL은 Binaries\Win32\UserCode 에서만 로드 가능합니다.
- Win32에서는 stdcall만 지원됩니다. (호출 용례에 대한 정보)
디버깅
- DLL 의 Debug 빌드가 올바르게 바인드되면, UDK.exe 에 디버거를 부착할 수 있을 것이며, DLL 내에 브레이크포인트를 설정할 수 있을 것입니다.
- 다른 이에게 배포하려면 DLL 을 Release 모드로 컴파일해야 하며, 그렇지 않으면 C 런타임의 디버그 버전이 사용할 수 없는 상태가 되기에 문제가 생길 것입니다.
언리얼스크립트 문자열, 구조체에서의 문자열 사용 관련
- Data, 문자열에 할당된 메모리를 가리키는 32비트 포인터
- ArrayNum, 현재 문자열의 (NULL 종료자를 포함한) 16비트 워드(UTF-16 글자) 수를 저장하는 32비트 int. 보통 wcslen(Data)+1 이며, 빈 문자열은 0.
- ArrayMax, 현재 문자열에 할당된 메모리의 16비트 워드 수를 저장하는 a 32비트 int.
struct FString { wchar_t* Data; int ArrayNum; int ArrayMax; }; struct MyPlayerStruct { FString PlayerName; FString PlayerPassword; float Health; float Score; };UnrealScript:
struct MyPlayerStruct { var string PlayerName; var string PlayerPassword; var float Health; var float Score; };알림
- 구조체가 출력 파라미터인 경우, 구조체 내부 문자열의 값을 ArrayMax 길이까지 바꿀 수 있습니다. 나중에 ArrayNum을 맞춰주기만 하면요. 첨부된 StringDLL 예제를 참고하십시오.
- Data 포인터를 배치 및 재배치 시도하지 마십시오. DLL이 언리얼의 메모리 할당기를 사용하지 않습니다.
- ArrayMax 값을 수정하지 마십시오.
- 문자열이 포함된 구조체를 반환하지 마십시오. 구조체 변수가 소멸되면 언리얼이 Data 메모리를 해방(free)하려 하기 때문입니다.
경고
- 출력 파라미터의 문자열을 수정할 때, 바뀌는 문자열 길이는 전달된 기존 문자열 길이 이하여야 합니다. 이는 언리얼스크립트의 문자열에다 DLL이 저장하게될 최대값보다 긴 초기값을 설정하여 수행할 수 있습니다. 이렇게 하지 못하면 메모리를 덮어쓰게 되어 크래시가 생길 수 있습니다.
- 구조체나 문자열을 반환할 때, DLL은 포인터를 반환하며 언리얼은 그 값을 언리얼스크립트에 다시 복사합니다. 그러나 지정된 데이터 저장 메모리 할당을 관장하는 것은 DLL입니다. 예로 CallDLL2 에서처럼 정적 변수에 포인터를 반환할 수도 있습니다. 스택에 선언된 변수에다 포인터를 반환하면 데이터 유실되거나 크래시가 납니다. 왜냐면 스택은 DLL 함수가 반환될 때 소멸되기 때문입니다.
- 언리얼스크립트에서 구조체 멤버는 4바이트 경계로 정렬되므로, DLL을 빌드할 때는 /Zp4 컴파일러 옵션을 사용해야 합니다.
- DLL에 안쓰이는 언리얼 데이터 유형을 포함하여 구조체를 선언할 수는 있습니다. 물론 비추입니다!
- 언리얼스크립트 문자열을 포함하는 구조체를 반환하려 하지 마십시오. 위의 지침만 따른다면 출력 파라미터에는 괜찮습니다.
- 2010년 2월 UDK 이전에, 현 작업 디렉토리는 UserCode가 아닌 Binaries\Win32 폴더로 설정되어 있었습니다. 2010년 2월 버전부터 DLLBind 함수 호출 이전에는 작업 디렉토리가 UserCode 폴더로 바뀌었습니다.
예제
- DLLBind_Example.zip - 기본 DLLBind 예제
- StringDLL.zip - 문자열이 포함된 구조체 사용법 예제
- ArrayDLL.zip - 메모리 재할당 포함 DLL 내 동적 배열 사용법을 보여주는 고급 예제