现在我得到了这样的功能描述
int ReadCard(char *room,char *gate,char *stime, char *guestname, char *guestid, char *lift, char *track1, char *track2, long *cardno, int *st, int *Breakfast);`
这就是我做的事情
room := ""
gate := ""
stime := ""
guestname := ""
guestid := ""
lift := ""
track1 := ""
track2 := ""
cardno := int64(0)
st := int64(0)
Breakfast := int64(0)
MAINDLL, _ := syscall.LoadLibrary("xxxxx.dll")
defer syscall.FreeLibrary(MAINDLL)
readCard, _ := syscall.GetProcAddress(MAINDLL, "ReadCard")
r1, r2, errno := syscall.Syscall12(readCard,
11,
uintptr(unsafe.Pointer(&room)),
uintptr(unsafe.Pointer(&gate)),
uintptr(unsafe.Pointer(&stime)),
uintptr(unsafe.Pointer(&guestname)),
uintptr(unsafe.Pointer(&guestid)),
uintptr(unsafe.Pointer(&lift)),
uintptr(unsafe.Pointer(&track1)),
uintptr(unsafe.Pointer(&track2)),
uintptr(cardno),
uintptr(st),
uintptr(Breakfast),
0)
fmt.Println(r1, "\n", r2, "\n", errno)`
当我运行此代码时,我得到了
r1:0 r2:917452 errno:<nil>
但是当我打印房间或其他参数时,它的价值不会改变, dll文件中的这个函数会改变我发送的参数,我怎么能得到那些值?
答案 0 :(得分:0)
To retrieve C's NULL terminated string, use pointer to pre-allocated byte slice instead of string
. You need to make sure that the byte slice has enough space for storing the character, otherwise your program may crash due to memory access violation.
For long *
and int *
type, address to the variable is needed, e.g. use uintptr(unsafe.Pointer(&cardno))
instead of uintptr(cardno)
. In your current implementation, the value pointed by the variable is converted to a pointer. All uintptr(cardno)
, uintptr(st)
, uintptr(Breakfast)
point to the same pointer (pointer to NULL
in C) since they're all initialized to 0.
The code looks like:
const maxSize = 100 //Adjust the value to your need
room := make([]byte, maxSize)
gate := make([]byte, maxSize)
stime := make([]byte, maxSize)
guestname := make([]byte, maxSize)
guestid := make([]byte, maxSize)
lift := make([]byte, maxSize)
track1 := make([]byte, maxSize)
track2 := make([]byte, maxSize)
//The following variable type is correct for 64-bit DLL.
//For 32-bit DLL, instead of int64, use int32.
cardno := int64(0)
st := int64(0)
Breakfast := int64(0)
MAINDLL, _ := syscall.LoadLibrary("xxxxx.dll")
defer syscall.FreeLibrary(MAINDLL)
readCard, _ := syscall.GetProcAddress(MAINDLL, "ReadCard")
r1, r2, errno := syscall.Syscall12(readCard,
11,
uintptr(unsafe.Pointer(&room[0])),
uintptr(unsafe.Pointer(&gate[0])),
uintptr(unsafe.Pointer(&stime[0])),
uintptr(unsafe.Pointer(&guestname[0])),
uintptr(unsafe.Pointer(&guestid[0])),
uintptr(unsafe.Pointer(&lift[0])),
uintptr(unsafe.Pointer(&track1[0])),
uintptr(unsafe.Pointer(&track2[0])),
uintptr(unsafe.Pointer(&cardno)),
uintptr(unsafe.Pointer(&st)),
uintptr(unsafe.Pointer(&Breakfast)),
0)
fmt.Println(r1, "\n", r2, "\n", errno)
Note that in the above example, we're using &room[0]
intead of room
, since we need to pass address of underlying byte array instead of address of the slice descriptor (See https://blog.golang.org/go-slices-usage-and-internals).
Finally, the byte slice which holds NULL terminated string must be converted to go
's string
, e.g. using:
func cstr(buf []byte) string {
str := string(buf)
for i, r := range str {
if r == 0 {
return string(buf[:i])
}
}
return str
}
//usage example
sRoom := cstr(room)
//see the difference
fmt.Printf("`%s` => `%s`\n", string(room), sRoom)
Other implementation example, see How can I convert a null-terminated string in a byte buffer to a string in Go?.