github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/pkg/runtime/syscall_windows_test.go (about) 1 // Copyright 2010 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package runtime_test 6 7 import ( 8 "runtime" 9 "syscall" 10 "testing" 11 "unsafe" 12 ) 13 14 type DLL struct { 15 *syscall.DLL 16 t *testing.T 17 } 18 19 func GetDLL(t *testing.T, name string) *DLL { 20 d, e := syscall.LoadDLL(name) 21 if e != nil { 22 t.Fatal(e) 23 } 24 return &DLL{DLL: d, t: t} 25 } 26 27 func (d *DLL) Proc(name string) *syscall.Proc { 28 p, e := d.FindProc(name) 29 if e != nil { 30 d.t.Fatal(e) 31 } 32 return p 33 } 34 35 func TestStdCall(t *testing.T) { 36 type Rect struct { 37 left, top, right, bottom int32 38 } 39 res := Rect{} 40 expected := Rect{1, 1, 40, 60} 41 a, _, _ := GetDLL(t, "user32.dll").Proc("UnionRect").Call( 42 uintptr(unsafe.Pointer(&res)), 43 uintptr(unsafe.Pointer(&Rect{10, 1, 14, 60})), 44 uintptr(unsafe.Pointer(&Rect{1, 2, 40, 50}))) 45 if a != 1 || res.left != expected.left || 46 res.top != expected.top || 47 res.right != expected.right || 48 res.bottom != expected.bottom { 49 t.Error("stdcall USER32.UnionRect returns", a, "res=", res) 50 } 51 } 52 53 func Test64BitReturnStdCall(t *testing.T) { 54 55 const ( 56 VER_BUILDNUMBER = 0x0000004 57 VER_MAJORVERSION = 0x0000002 58 VER_MINORVERSION = 0x0000001 59 VER_PLATFORMID = 0x0000008 60 VER_PRODUCT_TYPE = 0x0000080 61 VER_SERVICEPACKMAJOR = 0x0000020 62 VER_SERVICEPACKMINOR = 0x0000010 63 VER_SUITENAME = 0x0000040 64 65 VER_EQUAL = 1 66 VER_GREATER = 2 67 VER_GREATER_EQUAL = 3 68 VER_LESS = 4 69 VER_LESS_EQUAL = 5 70 71 ERROR_OLD_WIN_VERSION syscall.Errno = 1150 72 ) 73 74 type OSVersionInfoEx struct { 75 OSVersionInfoSize uint32 76 MajorVersion uint32 77 MinorVersion uint32 78 BuildNumber uint32 79 PlatformId uint32 80 CSDVersion [128]uint16 81 ServicePackMajor uint16 82 ServicePackMinor uint16 83 SuiteMask uint16 84 ProductType byte 85 Reserve byte 86 } 87 88 d := GetDLL(t, "kernel32.dll") 89 90 var m1, m2 uintptr 91 VerSetConditionMask := d.Proc("VerSetConditionMask") 92 m1, m2, _ = VerSetConditionMask.Call(m1, m2, VER_MAJORVERSION, VER_GREATER_EQUAL) 93 m1, m2, _ = VerSetConditionMask.Call(m1, m2, VER_MINORVERSION, VER_GREATER_EQUAL) 94 m1, m2, _ = VerSetConditionMask.Call(m1, m2, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL) 95 m1, m2, _ = VerSetConditionMask.Call(m1, m2, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL) 96 97 vi := OSVersionInfoEx{ 98 MajorVersion: 5, 99 MinorVersion: 1, 100 ServicePackMajor: 2, 101 ServicePackMinor: 0, 102 } 103 vi.OSVersionInfoSize = uint32(unsafe.Sizeof(vi)) 104 r, _, e2 := d.Proc("VerifyVersionInfoW").Call( 105 uintptr(unsafe.Pointer(&vi)), 106 VER_MAJORVERSION|VER_MINORVERSION|VER_SERVICEPACKMAJOR|VER_SERVICEPACKMINOR, 107 m1, m2) 108 if r == 0 && e2 != ERROR_OLD_WIN_VERSION { 109 t.Errorf("VerifyVersionInfo failed: %s", e2) 110 } 111 } 112 113 func TestCDecl(t *testing.T) { 114 var buf [50]byte 115 fmtp, _ := syscall.BytePtrFromString("%d %d %d") 116 a, _, _ := GetDLL(t, "user32.dll").Proc("wsprintfA").Call( 117 uintptr(unsafe.Pointer(&buf[0])), 118 uintptr(unsafe.Pointer(fmtp)), 119 1000, 2000, 3000) 120 if string(buf[:a]) != "1000 2000 3000" { 121 t.Error("cdecl USER32.wsprintfA returns", a, "buf=", buf[:a]) 122 } 123 } 124 125 func TestEnumWindows(t *testing.T) { 126 d := GetDLL(t, "user32.dll") 127 isWindows := d.Proc("IsWindow") 128 counter := 0 129 cb := syscall.NewCallback(func(hwnd syscall.Handle, lparam uintptr) uintptr { 130 if lparam != 888 { 131 t.Error("lparam was not passed to callback") 132 } 133 b, _, _ := isWindows.Call(uintptr(hwnd)) 134 if b == 0 { 135 t.Error("USER32.IsWindow returns FALSE") 136 } 137 counter++ 138 return 1 // continue enumeration 139 }) 140 a, _, _ := d.Proc("EnumWindows").Call(cb, 888) 141 if a == 0 { 142 t.Error("USER32.EnumWindows returns FALSE") 143 } 144 if counter == 0 { 145 t.Error("Callback has been never called or your have no windows") 146 } 147 } 148 149 func callback(hwnd syscall.Handle, lparam uintptr) uintptr { 150 (*(*func())(unsafe.Pointer(&lparam)))() 151 return 0 // stop enumeration 152 } 153 154 // nestedCall calls into Windows, back into Go, and finally to f. 155 func nestedCall(t *testing.T, f func()) { 156 c := syscall.NewCallback(callback) 157 d := GetDLL(t, "user32.dll") 158 defer d.Release() 159 d.Proc("EnumWindows").Call(c, uintptr(*(*unsafe.Pointer)(unsafe.Pointer(&f)))) 160 } 161 162 func TestCallback(t *testing.T) { 163 var x = false 164 nestedCall(t, func() { x = true }) 165 if !x { 166 t.Fatal("nestedCall did not call func") 167 } 168 } 169 170 func TestCallbackGC(t *testing.T) { 171 nestedCall(t, runtime.GC) 172 } 173 174 func TestCallbackPanic(t *testing.T) { 175 // Make sure panic during callback unwinds properly. 176 if runtime.LockedOSThread() { 177 t.Fatal("locked OS thread on entry to TestCallbackPanic") 178 } 179 defer func() { 180 s := recover() 181 if s == nil { 182 t.Fatal("did not panic") 183 } 184 if s.(string) != "callback panic" { 185 t.Fatal("wrong panic:", s) 186 } 187 if runtime.LockedOSThread() { 188 t.Fatal("locked OS thread on exit from TestCallbackPanic") 189 } 190 }() 191 nestedCall(t, func() { panic("callback panic") }) 192 panic("nestedCall returned") 193 } 194 195 func TestCallbackPanicLoop(t *testing.T) { 196 // Make sure we don't blow out m->g0 stack. 197 for i := 0; i < 100000; i++ { 198 TestCallbackPanic(t) 199 } 200 } 201 202 func TestCallbackPanicLocked(t *testing.T) { 203 runtime.LockOSThread() 204 defer runtime.UnlockOSThread() 205 206 if !runtime.LockedOSThread() { 207 t.Fatal("runtime.LockOSThread didn't") 208 } 209 defer func() { 210 s := recover() 211 if s == nil { 212 t.Fatal("did not panic") 213 } 214 if s.(string) != "callback panic" { 215 t.Fatal("wrong panic:", s) 216 } 217 if !runtime.LockedOSThread() { 218 t.Fatal("lost lock on OS thread after panic") 219 } 220 }() 221 nestedCall(t, func() { panic("callback panic") }) 222 panic("nestedCall returned") 223 } 224 225 func TestBlockingCallback(t *testing.T) { 226 c := make(chan int) 227 go func() { 228 for i := 0; i < 10; i++ { 229 c <- <-c 230 } 231 }() 232 nestedCall(t, func() { 233 for i := 0; i < 10; i++ { 234 c <- i 235 if j := <-c; j != i { 236 t.Errorf("out of sync %d != %d", j, i) 237 } 238 } 239 }) 240 } 241 242 func TestCallbackInAnotherThread(t *testing.T) { 243 // TODO: test a function which calls back in another thread: QueueUserAPC() or CreateThread() 244 }