Использование Golang для простоя Windows (GetLastInputInfo или аналогичный)
Есть ли пример или способ получения простоя системы Windows с помощью Go?
Я просматривал документацию на сайте Golang, но мне кажется, что мне не хватает того, как получить доступ (и использовать) API для получения системной информации, включая время простоя.
3 ответа
На веб-сайте Go жестко задана документация для стандартных пакетов библиотек в Linux. Вам нужно будет получить godoc и запустить его самостоятельно:
go get golang.org/x/tools/cmd/godoc
godoc --http=:6060
затем откройте http://127.0.0.1:6060/
в вашем веб-браузере.
Следует отметить пакет syscall
, который предоставляет средства для доступа к функциям в DLL, включая помощники UTF-16 и функции генерации обратного вызова.
Выполнение быстрого рекурсивного поиска дерева Go говорит о том, что у него нет API для GetLastInputInfo()
в частности, поэтому, если я что-то упустил, вы сможете вызывать эту функцию непосредственно из DLL:
user32 := syscall.MustLoadDLL("user32.dll") // or NewLazyDLL() to defer loading
getLastInputInfo := user32.MustFindProc("GetLastInputInfo") // or NewProc() if you used NewLazyDLL()
// or you can handle the errors in the above if you want to provide some alternative
r1, _, err := getLastInputInfo.Call(uintptr(arg))
// err will always be non-nil; you need to check r1 (the return value)
if r1 == 0 { // in this case
panic("error getting last input info: " + err.Error())
}
Ваш случай включает в себя структуру. Насколько я знаю, вы можете просто воссоздать структуру структуры (сохраняя поля в том же порядке), но вы должны преобразовать любой int
поля в оригинале int32
иначе все будет сломано на 64-битной Windows. Обратитесь к странице типов данных Windows на MSDN для соответствующих эквивалентов типов. В вашем случае это будет
var lastInputInfo struct {
cbSize uint32
dwTime uint32
}
Потому что это (как и многие структуры в Windows API) имеет cbSize
поле, которое требует, чтобы вы инициализировали его с размером структуры, мы должны сделать это тоже:
lastInputInfo.cbSize = uint32(unsafe.Sizeof(lastInputInfo))
Теперь нам просто нужно передать указатель на это lastInputInfo
переменная для функции:
r1, _, err := getLastInputInfo.Call(
uintptr(unsafe.Pointer(&lastInputInfo)))
и просто не забудьте импортировать syscall
а также unsafe
,
Все аргументы в DLL/LazyDLL.Call()
являются uintptr
, как это r1
вернуть. _
return никогда не используется в Windows (это связано с используемым ABI).
Поскольку я рассмотрел большую часть того, что вам нужно знать, чтобы использовать Windows API в Go, что вы не можете почерпнуть из прочтения syscall
Документы, я также скажу (и это не имеет отношения к вышеупомянутому вопросу), что если функция имеет версии ANSI и Unicode, вы должны использовать версии Unicode (W
суффикс) и функции преобразования UTF-16 в пакете syscall
для лучших результатов.
Я думаю, что это вся информация, которая понадобится вам (или кому-либо другому) для использования Windows API в программах Go.
Относительно ответа от andlabs. Это готовый пример использования:
import (
"time"
"unsafe"
"syscall"
"fmt"
)
var (
user32 = syscall.MustLoadDLL("user32.dll")
kernel32 = syscall.MustLoadDLL("kernel32.dll")
getLastInputInfo = user32.MustFindProc("GetLastInputInfo")
getTickCount = kernel32.MustFindProc("GetTickCount")
lastInputInfo struct {
cbSize uint32
dwTime uint32
}
)
func IdleTime() time.Duration {
lastInputInfo.cbSize = uint32(unsafe.Sizeof(lastInputInfo))
currentTickCount, _, _ := getTickCount.Call()
r1, _, err := getLastInputInfo.Call(uintptr(unsafe.Pointer(&lastInputInfo)))
if r1 == 0 {
panic("error getting last input info: " + err.Error())
}
return time.Duration((uint32(currentTickCount) - lastInputInfo.dwTime)) * time.Millisecond
}
func main() {
t := time.NewTicker(1 * time.Second)
for range t.C {
fmt.Println(IdleTime())
}
}
Это код печати простой каждую секунду. Попробуйте запустить и не трогайте мышь / клавиатуру
Если вы готовы использовать существующий пакет вместо реализации своего собственного, см. следующий репозиторий от lextoumbourou:
https://github.com/lextoumbourou/idle
пример использования:
package main
import (
"fmt"
"github.com/lextoumbourou/idle"
)
func main() {
idleTime, _ := idle.Get()
fmt.Println(idleTime)
}
печатает время простоя текущего пользователя