잡동사니/Go lang

Go in Windows - BSTR

밝은영혼 2019. 12. 29. 12:12

Go언어에서 윈도 dll을 사용할 때 BSTR이라는 데이터 형식은 조금 다르게 처리해야 한다.

BSTR은 uint16 값들의 배열을 가리키는 포인터로 생각할 수 있다.

한 가지 다른 점은 이 포인터 앞에 int32 값으로 문자열의 길이를 가지고 있다는 것이다.

이 때문에 BSTR을 Go언어의 *uint16으로 처리하는 경우 잘못된 메모리 접근(memory access violation)이 발생할 수 있다.

아래와 같은 코드는 제대로 동작할 수도 있고(길이값을 사용하지 않을 때), 아닐 수도 있다(길이값을 사용할 경우).

func WrongBstr(s string) *uint16{
	return syscall.StringToUTF16Ptr(s)
}

대신에 윈도우의 SysAllocString 함수를 이용해야 한다.

var(
	oleaut32       = syscall.NewLazyDLL("oleaut32.dll")
	sysAllocString = oleaut32.NewProc("SysAllocString")
	sysFreeString  = oleaut32.NewProc("SysFreeString")
)

func SysAllocString(s string) *uint16 {
	ret, _, _ := sysAllocString.Call(uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(s))))
	return (*uint16)(unsafe.Pointer(ret))
}

func SysFreeString(bstr *uint16) {
	sysFreeString.Call(uintptr(unsafe.Pointer(bstr)))
}

SysAllocString을 사용한 경우 SysFreeString으로 메모리를 해제해주어야 한다.

  1. BSTR을 요구하는 함수를 호출하는 경우, 사용 후 해제한다.
  2. BSTR을 반환하는 함수를 호출하는 경우, 사용 후 해제한다.
  3. BSTR을 반환하는 함수를 구현하는 경우 할당만하고 해제하지 않는다.