Skip to content

Instantly share code, notes, and snippets.

@kostix
Created March 9, 2016 23:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kostix/50830f62972311afa43a to your computer and use it in GitHub Desktop.
Save kostix/50830f62972311afa43a to your computer and use it in GitHub Desktop.
Wrapping Win32 API NetSessionEnum() in Go
package main
import (
"log"
"syscall"
"unicode/utf16"
"unsafe"
"time"
)
type SessionInfo struct {
Cname string
Username string
Time time.Duration
IdleTime time.Duration
}
type sessionInfo10 struct {
Cname *uint16
Username *uint16
Time uint32
IdleTime uint32
}
var (
modNetApi32 = syscall.NewLazyDLL("netapi32.dll")
procNetApiBufferFree = modNetApi32.NewProc("NetApiBufferFree")
procNetSessionEnum = modNetApi32.NewProc("NetSessionEnum")
)
func netApiBufferFree(p unsafe.Pointer) error {
rc, _, _ := syscall.Syscall(procNetApiBufferFree.Addr(), 1, uintptr(p), 0, 0)
if rc != 0 {
return syscall.Errno(rc)
}
return nil
}
func mustFreeNetApiBuffer(p unsafe.Pointer) {
err := netApiBufferFree(p)
if err != nil {
panic(err)
}
}
func NetSessionEnum() (out []SessionInfo, err error) {
var (
pinfo *sessionInfo10
prefmaxlen int32 = -1
entriesread uint32
totalentries uint32
)
rc, _, _ := syscall.Syscall12(procNetSessionEnum.Addr(), 9,
0, 0, 0, 10,
uintptr(unsafe.Pointer(&pinfo)),
uintptr(prefmaxlen),
uintptr(unsafe.Pointer(&entriesread)),
uintptr(unsafe.Pointer(&totalentries)),
0,
0, 0, 0)
defer mustFreeNetApiBuffer(unsafe.Pointer(pinfo))
if rc != 0 {
err = syscall.Errno(rc)
return
}
if entriesread == 0 {
return
}
out = make([]SessionInfo, entriesread)
for i := uint32(0); i < entriesread; i++ {
out[i] = SessionInfo{
Cname: utf16PtrToString(pinfo.Cname),
Username: utf16PtrToString(pinfo.Username),
Time: time.Duration(pinfo.Time) * time.Second,
IdleTime: time.Duration(pinfo.IdleTime) * time.Second,
}
p := uintptr(unsafe.Pointer(pinfo))
p += unsafe.Sizeof(*pinfo)
pinfo = (*sessionInfo10)(unsafe.Pointer(p))
}
return
}
func utf16PtrToString(p *uint16) string {
if p == nil {
return ""
}
s := make([]uint16, 0, 50)
for {
if *p == 0 {
return string(utf16.Decode(s))
}
s = append(s, *p)
pp := uintptr(unsafe.Pointer(p))
pp += 2 // sizeof(uint16)
p = (*uint16)(unsafe.Pointer(pp))
}
}
func main() {
out, err := NetSessionEnum()
if err != nil {
log.Fatal(err)
}
log.Printf("%v\n", out)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment