1// +build windows
2
3package ole
4
5import (
6	"syscall"
7	"time"
8	"unsafe"
9)
10
11func getIDsOfName(disp *IDispatch, names []string) (dispid []int32, err error) {
12	wnames := make([]*uint16, len(names))
13	for i := 0; i < len(names); i++ {
14		wnames[i] = syscall.StringToUTF16Ptr(names[i])
15	}
16	dispid = make([]int32, len(names))
17	namelen := uint32(len(names))
18	hr, _, _ := syscall.Syscall6(
19		disp.VTable().GetIDsOfNames,
20		6,
21		uintptr(unsafe.Pointer(disp)),
22		uintptr(unsafe.Pointer(IID_NULL)),
23		uintptr(unsafe.Pointer(&wnames[0])),
24		uintptr(namelen),
25		uintptr(GetUserDefaultLCID()),
26		uintptr(unsafe.Pointer(&dispid[0])))
27	if hr != 0 {
28		err = NewError(hr)
29	}
30	return
31}
32
33func getTypeInfoCount(disp *IDispatch) (c uint32, err error) {
34	hr, _, _ := syscall.Syscall(
35		disp.VTable().GetTypeInfoCount,
36		2,
37		uintptr(unsafe.Pointer(disp)),
38		uintptr(unsafe.Pointer(&c)),
39		0)
40	if hr != 0 {
41		err = NewError(hr)
42	}
43	return
44}
45
46func getTypeInfo(disp *IDispatch) (tinfo *ITypeInfo, err error) {
47	hr, _, _ := syscall.Syscall(
48		disp.VTable().GetTypeInfo,
49		3,
50		uintptr(unsafe.Pointer(disp)),
51		uintptr(GetUserDefaultLCID()),
52		uintptr(unsafe.Pointer(&tinfo)))
53	if hr != 0 {
54		err = NewError(hr)
55	}
56	return
57}
58
59func invoke(disp *IDispatch, dispid int32, dispatch int16, params ...interface{}) (result *VARIANT, err error) {
60	var dispparams DISPPARAMS
61
62	if dispatch&DISPATCH_PROPERTYPUT != 0 {
63		dispnames := [1]int32{DISPID_PROPERTYPUT}
64		dispparams.rgdispidNamedArgs = uintptr(unsafe.Pointer(&dispnames[0]))
65		dispparams.cNamedArgs = 1
66	} else if dispatch&DISPATCH_PROPERTYPUTREF != 0 {
67		dispnames := [1]int32{DISPID_PROPERTYPUT}
68		dispparams.rgdispidNamedArgs = uintptr(unsafe.Pointer(&dispnames[0]))
69		dispparams.cNamedArgs = 1
70	}
71	var vargs []VARIANT
72	if len(params) > 0 {
73		vargs = make([]VARIANT, len(params))
74		for i, v := range params {
75			//n := len(params)-i-1
76			n := len(params) - i - 1
77			VariantInit(&vargs[n])
78			switch vv := v.(type) {
79			case bool:
80				if vv {
81					vargs[n] = NewVariant(VT_BOOL, 0xffff)
82				} else {
83					vargs[n] = NewVariant(VT_BOOL, 0)
84				}
85			case *bool:
86				vargs[n] = NewVariant(VT_BOOL|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(*bool)))))
87			case uint8:
88				vargs[n] = NewVariant(VT_I1, int64(v.(uint8)))
89			case *uint8:
90				vargs[n] = NewVariant(VT_I1|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(*uint8)))))
91			case int8:
92				vargs[n] = NewVariant(VT_I1, int64(v.(int8)))
93			case *int8:
94				vargs[n] = NewVariant(VT_I1|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(*uint8)))))
95			case int16:
96				vargs[n] = NewVariant(VT_I2, int64(v.(int16)))
97			case *int16:
98				vargs[n] = NewVariant(VT_I2|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(*int16)))))
99			case uint16:
100				vargs[n] = NewVariant(VT_UI2, int64(v.(uint16)))
101			case *uint16:
102				vargs[n] = NewVariant(VT_UI2|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(*uint16)))))
103			case int32:
104				vargs[n] = NewVariant(VT_I4, int64(v.(int32)))
105			case *int32:
106				vargs[n] = NewVariant(VT_I4|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(*int32)))))
107			case uint32:
108				vargs[n] = NewVariant(VT_UI4, int64(v.(uint32)))
109			case *uint32:
110				vargs[n] = NewVariant(VT_UI4|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(*uint32)))))
111			case int64:
112				vargs[n] = NewVariant(VT_I8, int64(v.(int64)))
113			case *int64:
114				vargs[n] = NewVariant(VT_I8|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(*int64)))))
115			case uint64:
116				vargs[n] = NewVariant(VT_UI8, int64(uintptr(v.(uint64))))
117			case *uint64:
118				vargs[n] = NewVariant(VT_UI8|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(*uint64)))))
119			case int:
120				vargs[n] = NewVariant(VT_I4, int64(v.(int)))
121			case *int:
122				vargs[n] = NewVariant(VT_I4|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(*int)))))
123			case uint:
124				vargs[n] = NewVariant(VT_UI4, int64(v.(uint)))
125			case *uint:
126				vargs[n] = NewVariant(VT_UI4|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(*uint)))))
127			case float32:
128				vargs[n] = NewVariant(VT_R4, *(*int64)(unsafe.Pointer(&vv)))
129			case *float32:
130				vargs[n] = NewVariant(VT_R4|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(*float32)))))
131			case float64:
132				vargs[n] = NewVariant(VT_R8, *(*int64)(unsafe.Pointer(&vv)))
133			case *float64:
134				vargs[n] = NewVariant(VT_R8|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(*float64)))))
135			case string:
136				vargs[n] = NewVariant(VT_BSTR, int64(uintptr(unsafe.Pointer(SysAllocStringLen(v.(string))))))
137			case *string:
138				vargs[n] = NewVariant(VT_BSTR|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(*string)))))
139			case time.Time:
140				s := vv.Format("2006-01-02 15:04:05")
141				vargs[n] = NewVariant(VT_BSTR, int64(uintptr(unsafe.Pointer(SysAllocStringLen(s)))))
142			case *time.Time:
143				s := vv.Format("2006-01-02 15:04:05")
144				vargs[n] = NewVariant(VT_BSTR|VT_BYREF, int64(uintptr(unsafe.Pointer(&s))))
145			case *IDispatch:
146				vargs[n] = NewVariant(VT_DISPATCH, int64(uintptr(unsafe.Pointer(v.(*IDispatch)))))
147			case **IDispatch:
148				vargs[n] = NewVariant(VT_DISPATCH|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(**IDispatch)))))
149			case nil:
150				vargs[n] = NewVariant(VT_NULL, 0)
151			case *VARIANT:
152				vargs[n] = NewVariant(VT_VARIANT|VT_BYREF, int64(uintptr(unsafe.Pointer(v.(*VARIANT)))))
153			case []byte:
154				safeByteArray := safeArrayFromByteSlice(v.([]byte))
155				vargs[n] = NewVariant(VT_ARRAY|VT_UI1, int64(uintptr(unsafe.Pointer(safeByteArray))))
156				defer VariantClear(&vargs[n])
157			case []string:
158				safeByteArray := safeArrayFromStringSlice(v.([]string))
159				vargs[n] = NewVariant(VT_ARRAY|VT_BSTR, int64(uintptr(unsafe.Pointer(safeByteArray))))
160				defer VariantClear(&vargs[n])
161			default:
162				panic("unknown type")
163			}
164		}
165		dispparams.rgvarg = uintptr(unsafe.Pointer(&vargs[0]))
166		dispparams.cArgs = uint32(len(params))
167	}
168
169	result = new(VARIANT)
170	var excepInfo EXCEPINFO
171	VariantInit(result)
172	hr, _, _ := syscall.Syscall9(
173		disp.VTable().Invoke,
174		9,
175		uintptr(unsafe.Pointer(disp)),
176		uintptr(dispid),
177		uintptr(unsafe.Pointer(IID_NULL)),
178		uintptr(GetUserDefaultLCID()),
179		uintptr(dispatch),
180		uintptr(unsafe.Pointer(&dispparams)),
181		uintptr(unsafe.Pointer(result)),
182		uintptr(unsafe.Pointer(&excepInfo)),
183		0)
184	if hr != 0 {
185		err = NewErrorWithSubError(hr, BstrToString(excepInfo.bstrDescription), excepInfo)
186	}
187	for i, varg := range vargs {
188		n := len(params) - i - 1
189		if varg.VT == VT_BSTR && varg.Val != 0 {
190			SysFreeString(((*int16)(unsafe.Pointer(uintptr(varg.Val)))))
191		}
192		if varg.VT == (VT_BSTR|VT_BYREF) && varg.Val != 0 {
193			*(params[n].(*string)) = LpOleStrToString(*(**uint16)(unsafe.Pointer(uintptr(varg.Val))))
194		}
195	}
196	return
197}
198