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  }