Использование 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)
}

печатает время простоя текущего пользователя

Другие вопросы по тегам