// Copyright 2010-2012 The W32 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 w32 import ( "syscall" "unicode/utf16" "unsafe" ) func MakeIntResource(id uint16) *uint16 { return (*uint16)(unsafe.Pointer(uintptr(id))) } func LOWORD(dw uint32) uint16 { return uint16(dw) } func HIWORD(dw uint32) uint16 { return uint16(dw >> 16 & 0xffff) } func BoolToBOOL(value bool) BOOL { if value { return 1 } return 0 } func UTF16PtrToString(cstr *uint16) string { if cstr != nil { us := make([]uint16, 0, 256) for p := uintptr(unsafe.Pointer(cstr)); ; p += 2 { u := *(*uint16)(unsafe.Pointer(p)) if u == 0 { return string(utf16.Decode(us)) } us = append(us, u) } } return "" } func ComAddRef(unknown *IUnknown) int32 { ret, _, _ := syscall.Syscall(unknown.lpVtbl.pAddRef, 1, uintptr(unsafe.Pointer(unknown)), 0, 0) return int32(ret) } func ComRelease(unknown *IUnknown) int32 { ret, _, _ := syscall.Syscall(unknown.lpVtbl.pRelease, 1, uintptr(unsafe.Pointer(unknown)), 0, 0) return int32(ret) } func ComQueryInterface(unknown *IUnknown, id *GUID) *IDispatch { var disp *IDispatch hr, _, _ := syscall.Syscall(unknown.lpVtbl.pQueryInterface, 3, uintptr(unsafe.Pointer(unknown)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(&disp))) if hr != 0 { panic("Invoke QieryInterface error.") } return disp } func ComGetIDsOfName(disp *IDispatch, names []string) []int32 { wnames := make([]*uint16, len(names)) dispid := make([]int32, len(names)) for i := 0; i < len(names); i++ { wnames[i] = syscall.StringToUTF16Ptr(names[i]) } hr, _, _ := syscall.Syscall6(disp.lpVtbl.pGetIDsOfNames, 6, uintptr(unsafe.Pointer(disp)), uintptr(unsafe.Pointer(IID_NULL)), uintptr(unsafe.Pointer(&wnames[0])), uintptr(len(names)), uintptr(GetUserDefaultLCID()), uintptr(unsafe.Pointer(&dispid[0]))) if hr != 0 { panic("Invoke GetIDsOfName error.") } return dispid } func ComInvoke(disp *IDispatch, dispid int32, dispatch int16, params ...interface{}) (result *VARIANT) { var dispparams DISPPARAMS if dispatch&DISPATCH_PROPERTYPUT != 0 { dispnames := [1]int32{DISPID_PROPERTYPUT} dispparams.RgdispidNamedArgs = uintptr(unsafe.Pointer(&dispnames[0])) dispparams.CNamedArgs = 1 } var vargs []VARIANT if len(params) > 0 { vargs = make([]VARIANT, len(params)) for i, v := range params { //n := len(params)-i-1 n := len(params) - i - 1 VariantInit(&vargs[n]) switch v.(type) { case bool: if v.(bool) { vargs[n] = VARIANT{VT_BOOL, 0, 0, 0, 0xffff} } else { vargs[n] = VARIANT{VT_BOOL, 0, 0, 0, 0} } case *bool: vargs[n] = VARIANT{VT_BOOL | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*bool))))} case byte: vargs[n] = VARIANT{VT_I1, 0, 0, 0, int64(v.(byte))} case *byte: vargs[n] = VARIANT{VT_I1 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*byte))))} case int16: vargs[n] = VARIANT{VT_I2, 0, 0, 0, int64(v.(int16))} case *int16: vargs[n] = VARIANT{VT_I2 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*int16))))} case uint16: vargs[n] = VARIANT{VT_UI2, 0, 0, 0, int64(v.(int16))} case *uint16: vargs[n] = VARIANT{VT_UI2 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*uint16))))} case int, int32: vargs[n] = VARIANT{VT_UI4, 0, 0, 0, int64(v.(int))} case *int, *int32: vargs[n] = VARIANT{VT_I4 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*int))))} case uint, uint32: vargs[n] = VARIANT{VT_UI4, 0, 0, 0, int64(v.(uint))} case *uint, *uint32: vargs[n] = VARIANT{VT_UI4 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*uint))))} case int64: vargs[n] = VARIANT{VT_I8, 0, 0, 0, v.(int64)} case *int64: vargs[n] = VARIANT{VT_I8 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*int64))))} case uint64: vargs[n] = VARIANT{VT_UI8, 0, 0, 0, int64(v.(uint64))} case *uint64: vargs[n] = VARIANT{VT_UI8 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*uint64))))} case float32: vargs[n] = VARIANT{VT_R4, 0, 0, 0, int64(v.(float32))} case *float32: vargs[n] = VARIANT{VT_R4 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*float32))))} case float64: vargs[n] = VARIANT{VT_R8, 0, 0, 0, int64(v.(float64))} case *float64: vargs[n] = VARIANT{VT_R8 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*float64))))} case string: vargs[n] = VARIANT{VT_BSTR, 0, 0, 0, int64(uintptr(unsafe.Pointer(SysAllocString(v.(string)))))} case *string: vargs[n] = VARIANT{VT_BSTR | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*string))))} case *IDispatch: vargs[n] = VARIANT{VT_DISPATCH, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*IDispatch))))} case **IDispatch: vargs[n] = VARIANT{VT_DISPATCH | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(**IDispatch))))} case nil: vargs[n] = VARIANT{VT_NULL, 0, 0, 0, 0} case *VARIANT: vargs[n] = VARIANT{VT_VARIANT | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*VARIANT))))} default: panic("unknown type") } } dispparams.Rgvarg = uintptr(unsafe.Pointer(&vargs[0])) dispparams.CArgs = uint32(len(params)) } var ret VARIANT var excepInfo EXCEPINFO VariantInit(&ret) hr, _, _ := syscall.Syscall9(disp.lpVtbl.pInvoke, 8, uintptr(unsafe.Pointer(disp)), uintptr(dispid), uintptr(unsafe.Pointer(IID_NULL)), uintptr(GetUserDefaultLCID()), uintptr(dispatch), uintptr(unsafe.Pointer(&dispparams)), uintptr(unsafe.Pointer(&ret)), uintptr(unsafe.Pointer(&excepInfo)), 0) if hr != 0 { if excepInfo.BstrDescription != nil { bs := UTF16PtrToString(excepInfo.BstrDescription) panic(bs) } } for _, varg := range vargs { if varg.VT == VT_BSTR && varg.Val != 0 { SysFreeString(((*int16)(unsafe.Pointer(uintptr(varg.Val))))) } } result = &ret return }