2011-08-29 22:43:54 -06:00
|
|
|
// Copyright 2010 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package runtime_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"syscall"
|
|
|
|
"testing"
|
2011-11-02 13:54:16 -06:00
|
|
|
"unsafe"
|
2011-08-29 22:43:54 -06:00
|
|
|
)
|
|
|
|
|
2011-10-15 00:29:25 -06:00
|
|
|
type DLL struct {
|
|
|
|
*syscall.DLL
|
|
|
|
t *testing.T
|
|
|
|
}
|
2011-08-29 22:43:54 -06:00
|
|
|
|
2011-10-15 00:29:25 -06:00
|
|
|
func GetDLL(t *testing.T, name string) *DLL {
|
|
|
|
d, e := syscall.LoadDLL(name)
|
|
|
|
if e != nil {
|
|
|
|
t.Fatal(e)
|
2011-08-29 22:43:54 -06:00
|
|
|
}
|
2011-10-15 00:29:25 -06:00
|
|
|
return &DLL{DLL: d, t: t}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (d *DLL) Proc(name string) *syscall.Proc {
|
|
|
|
p, e := d.FindProc(name)
|
|
|
|
if e != nil {
|
|
|
|
d.t.Fatal(e)
|
2011-08-29 22:43:54 -06:00
|
|
|
}
|
2011-10-15 00:29:25 -06:00
|
|
|
return p
|
|
|
|
}
|
2011-08-29 22:43:54 -06:00
|
|
|
|
2011-10-15 00:29:25 -06:00
|
|
|
func TestStdCall(t *testing.T) {
|
|
|
|
type Rect struct {
|
|
|
|
left, top, right, bottom int32
|
|
|
|
}
|
2011-08-29 22:43:54 -06:00
|
|
|
res := Rect{}
|
|
|
|
expected := Rect{1, 1, 40, 60}
|
2011-10-15 00:29:25 -06:00
|
|
|
a, _, _ := GetDLL(t, "user32.dll").Proc("UnionRect").Call(
|
2011-08-29 22:43:54 -06:00
|
|
|
uintptr(unsafe.Pointer(&res)),
|
|
|
|
uintptr(unsafe.Pointer(&Rect{10, 1, 14, 60})),
|
|
|
|
uintptr(unsafe.Pointer(&Rect{1, 2, 40, 50})))
|
|
|
|
if a != 1 || res.left != expected.left ||
|
|
|
|
res.top != expected.top ||
|
|
|
|
res.right != expected.right ||
|
|
|
|
res.bottom != expected.bottom {
|
|
|
|
t.Error("stdcall USER32.UnionRect returns", a, "res=", res)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-14 00:19:45 -06:00
|
|
|
func Test64BitReturnStdCall(t *testing.T) {
|
|
|
|
|
|
|
|
const (
|
|
|
|
VER_BUILDNUMBER = 0x0000004
|
|
|
|
VER_MAJORVERSION = 0x0000002
|
|
|
|
VER_MINORVERSION = 0x0000001
|
|
|
|
VER_PLATFORMID = 0x0000008
|
|
|
|
VER_PRODUCT_TYPE = 0x0000080
|
|
|
|
VER_SERVICEPACKMAJOR = 0x0000020
|
|
|
|
VER_SERVICEPACKMINOR = 0x0000010
|
|
|
|
VER_SUITENAME = 0x0000040
|
|
|
|
|
|
|
|
VER_EQUAL = 1
|
|
|
|
VER_GREATER = 2
|
|
|
|
VER_GREATER_EQUAL = 3
|
|
|
|
VER_LESS = 4
|
|
|
|
VER_LESS_EQUAL = 5
|
|
|
|
|
|
|
|
ERROR_OLD_WIN_VERSION = 1150
|
|
|
|
)
|
|
|
|
|
|
|
|
type OSVersionInfoEx struct {
|
|
|
|
OSVersionInfoSize uint32
|
|
|
|
MajorVersion uint32
|
|
|
|
MinorVersion uint32
|
|
|
|
BuildNumber uint32
|
|
|
|
PlatformId uint32
|
|
|
|
CSDVersion [128]uint16
|
|
|
|
ServicePackMajor uint16
|
|
|
|
ServicePackMinor uint16
|
|
|
|
SuiteMask uint16
|
|
|
|
ProductType byte
|
|
|
|
Reserve byte
|
|
|
|
}
|
|
|
|
|
2011-10-15 00:29:25 -06:00
|
|
|
d := GetDLL(t, "kernel32.dll")
|
2011-09-14 00:19:45 -06:00
|
|
|
|
|
|
|
var m1, m2 uintptr
|
2011-10-15 00:29:25 -06:00
|
|
|
VerSetConditionMask := d.Proc("VerSetConditionMask")
|
|
|
|
m1, m2, _ = VerSetConditionMask.Call(m1, m2, VER_MAJORVERSION, VER_GREATER_EQUAL)
|
|
|
|
m1, m2, _ = VerSetConditionMask.Call(m1, m2, VER_MINORVERSION, VER_GREATER_EQUAL)
|
|
|
|
m1, m2, _ = VerSetConditionMask.Call(m1, m2, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL)
|
|
|
|
m1, m2, _ = VerSetConditionMask.Call(m1, m2, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL)
|
2011-09-14 00:19:45 -06:00
|
|
|
|
|
|
|
vi := OSVersionInfoEx{
|
|
|
|
MajorVersion: 5,
|
|
|
|
MinorVersion: 1,
|
|
|
|
ServicePackMajor: 2,
|
|
|
|
ServicePackMinor: 0,
|
|
|
|
}
|
|
|
|
vi.OSVersionInfoSize = uint32(unsafe.Sizeof(vi))
|
2011-10-15 00:29:25 -06:00
|
|
|
r, _, e2 := d.Proc("VerifyVersionInfoW").Call(
|
2011-09-14 00:19:45 -06:00
|
|
|
uintptr(unsafe.Pointer(&vi)),
|
|
|
|
VER_MAJORVERSION|VER_MINORVERSION|VER_SERVICEPACKMAJOR|VER_SERVICEPACKMINOR,
|
2011-10-15 00:29:25 -06:00
|
|
|
m1, m2)
|
2011-09-14 00:19:45 -06:00
|
|
|
if r == 0 && e2 != ERROR_OLD_WIN_VERSION {
|
|
|
|
t.Errorf("VerifyVersionInfo failed: (%d) %s", e2, syscall.Errstr(int(e2)))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-29 22:43:54 -06:00
|
|
|
func TestCDecl(t *testing.T) {
|
|
|
|
var buf [50]byte
|
2011-10-15 00:29:25 -06:00
|
|
|
a, _, _ := GetDLL(t, "user32.dll").Proc("wsprintfA").Call(
|
2011-08-29 22:43:54 -06:00
|
|
|
uintptr(unsafe.Pointer(&buf[0])),
|
|
|
|
uintptr(unsafe.Pointer(syscall.StringBytePtr("%d %d %d"))),
|
2011-10-15 00:29:25 -06:00
|
|
|
1000, 2000, 3000)
|
2011-08-29 22:43:54 -06:00
|
|
|
if string(buf[:a]) != "1000 2000 3000" {
|
|
|
|
t.Error("cdecl USER32.wsprintfA returns", a, "buf=", buf[:a])
|
|
|
|
}
|
|
|
|
}
|
2011-08-30 06:02:02 -06:00
|
|
|
|
|
|
|
func TestCallback(t *testing.T) {
|
2011-10-15 00:29:25 -06:00
|
|
|
d := GetDLL(t, "user32.dll")
|
|
|
|
isWindows := d.Proc("IsWindow")
|
2011-08-30 06:02:02 -06:00
|
|
|
counter := 0
|
|
|
|
cb := syscall.NewCallback(func(hwnd syscall.Handle, lparam uintptr) uintptr {
|
|
|
|
if lparam != 888 {
|
|
|
|
t.Error("lparam was not passed to callback")
|
|
|
|
}
|
2011-10-15 00:29:25 -06:00
|
|
|
b, _, _ := isWindows.Call(uintptr(hwnd))
|
2011-08-30 06:02:02 -06:00
|
|
|
if b == 0 {
|
|
|
|
t.Error("USER32.IsWindow returns FALSE")
|
|
|
|
}
|
|
|
|
counter++
|
|
|
|
return 1 // continue enumeration
|
|
|
|
})
|
2011-10-15 00:29:25 -06:00
|
|
|
a, _, _ := d.Proc("EnumWindows").Call(cb, 888)
|
2011-08-30 06:02:02 -06:00
|
|
|
if a == 0 {
|
|
|
|
t.Error("USER32.EnumWindows returns FALSE")
|
|
|
|
}
|
|
|
|
if counter == 0 {
|
|
|
|
t.Error("Callback has been never called or your have no windows")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestCallbackInAnotherThread(t *testing.T) {
|
|
|
|
// TODO: test a function which calls back in another thread: QueueUserAPC() or CreateThread()
|
|
|
|
}
|