-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathapi_helpers_windows.go
171 lines (154 loc) · 5 KB
/
api_helpers_windows.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
// -----------------------------------------------------------------------------
// ZR Library: Windows 32 API zr-win/[api_helpers_windows.go]
// (c) [email protected] License: MIT
// -----------------------------------------------------------------------------
package win
// # Call Stack Functions
// FuncName(callDepth int) string
// LineNo(callDepth int) int
//
// # Helper Functions
// BOOLResult(result uintptr) BOOL
// ErrorName(errNo DWORD) string
// PWSTRFromString(s string) *WCHAR
// StringFromPWSTR(s LPWSTR) string
// UintptrFromString(s *string) uintptr
// WriteWSTR(ptr *uintptr, s string)
//
// # Internal
// abort(funcName string, err error)
import (
"bytes"
"fmt"
"runtime"
"strings"
"syscall"
"unsafe"
)
// -----------------------------------------------------------------------------
// # Call Stack Functions
// ShowResultStatus specifies if BOOLResult should print (to the console)
// the result of the last Win32 API function call. Used for debugging.
var ShowResultStatus = false
// FuncName _ _
func FuncName(callDepth int) string {
programCounter, _, _, _ := runtime.Caller(callDepth)
funcName := runtime.FuncForPC(programCounter).Name()
return funcName
} // FuncName
// LineNo _ _
func LineNo(callDepth int) int {
_, _, lineNo, _ := runtime.Caller(callDepth)
return lineNo
} // LineNo
// -----------------------------------------------------------------------------
// # Helper Functions
// BOOLResult converts a function call result to a BOOL value.
func BOOLResult(result uintptr) BOOL {
if result == FALSE && ShowResultStatus {
err := GetLastError()
fmt.Printf("win.%s() == FALSE. GetLastError() == %d - %s\r\n",
FuncName(2), err, ErrorName(err))
}
return BOOL(result)
} // BOOLResult
// ErrorName returns the Windows error description given an error number.
// It calls FormatMessage() Win32 API function to get the message text.
func ErrorName(errNo DWORD) string {
err := errNo
if err == 0 {
err = GetLastError()
}
if err == 0 {
return "no error"
}
// static buffer for the error description
const BufferSize = 256
var buf256 [BufferSize]WCHAR
// get the error description from the OS
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM|
FORMAT_MESSAGE_IGNORE_INSERTS, // dwFlags
nil, // lpSource
err, // dwMessageId
DWORD(MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)), // dwLanguageID
LPWSTR(&buf256[0]), // lpBuffer
BufferSize, // nSize
nil, // arguments
)
// build result string
var retBuf bytes.Buffer
for _, ch := range buf256 {
if ch == 0 {
break
}
retBuf.WriteRune(rune(ch))
}
return retBuf.String()
} // ErrorName
// PWSTRFromString _ _
func PWSTRFromString(s string) *WCHAR {
if s == "" {
return (*WCHAR)(nil)
}
if strings.Contains(s, "\x00") {
count := strings.Count(s, "")
ret := make([]WCHAR, count)
for i, r := range s {
ret[i] = WCHAR(r)
}
return (*WCHAR)(&ret[0])
}
ret, _ := syscall.UTF16PtrFromString(s)
return (*WCHAR)(ret)
} // PWSTRFromString
// StringFromPWSTR returns a Go string given a Windows API
// PWSTR (pointer to a wide string).
func StringFromPWSTR(s LPWSTR) string {
ptr := unsafe.Pointer(s)
var retBuf bytes.Buffer
for {
ch := rune(*((*WCHAR)(ptr)))
if ch == 0 {
break
}
ptr = unsafe.Pointer(uintptr(ptr) + 2)
retBuf.WriteRune(ch)
}
return retBuf.String()
} // StringFromPWSTR
// UintptrFromString _ _
func UintptrFromString(s *string) uintptr {
if *s == "" {
return 0
}
var ret *uint16
// Some Windows API functions like GetTextExtentPoint32() panic when given
// a string containing NUL. This block checks & returns the part before NUL.
zeroAt := strings.Index(*s, "\x00")
if zeroAt == -1 {
ret, _ = syscall.UTF16PtrFromString(*s)
return uintptr(unsafe.Pointer(ret))
}
if zeroAt == 0 {
return 0
}
ret, _ = syscall.UTF16PtrFromString((*s)[:zeroAt])
return uintptr(unsafe.Pointer(ret))
} // UintptrFromString
// WriteWSTR _ _
func WriteWSTR(ptr *uintptr, s string) {
for _, r := range s + "\x00" {
wch := WCHAR(r)
*(*WCHAR)(unsafe.Pointer(ptr)) = wch
*ptr += unsafe.Sizeof(wch)
}
} // WriteWSTR
// -----------------------------------------------------------------------------
// # Internal
// abort terminates the running application after printing the
// supplied name of the calling function and an error description.
func abort(funcName string, err error) {
panic(fmt.Sprintf("%s failed: %v", funcName, err))
} // abort
// end