blono/win にまたいくつかの API を追加したので、サービスからのプロセスの起動がコーディングしやすくなった
main.go
func GetActiveSession() uint32 {
var si *win.WTS_SESSION_INFO
var count uint32
if win.WTSEnumerateSessions(win.WTS_CURRENT_SERVER_HANDLE, 0, 1, &si, &count) != 0 {
defer win.WTSFreeMemory(uintptr(unsafe.Pointer(si)))
size := int(unsafe.Sizeof(win.WTS_SESSION_INFO{}))
for i := 0; i < int(count); i++ {
sipi := unsafe.Pointer(uintptr(unsafe.Pointer(si)) + uintptr(i*size))
sii := *(*win.WTS_SESSION_INFO)(sipi)
if sii.State == win.WTSActive {
return sii.SessionId
}
}
}
return 0
}
func CreateProcessAsUser(app, param string, token win.HANDLE, creationFlags uint32, env uintptr, ppi *win.PROCESS_INFORMATION) win.BOOL {
var pi win.PROCESS_INFORMATION
var si win.STARTUPINFO
var arg string
si.Cb = uint32(unsafe.Sizeof(si))
si.LpDesktop = NewUTF16(`winsta0\default`)
if param == "" {
arg = app
} else {
arg = app + " " + param
}
result := win.CreateProcessAsUser(token, nil, &arg, nil, nil, win.FALSE, creationFlags, env, nil, &si, &pi)
if ppi == nil {
win.CloseHandle(pi.HThread)
win.CloseHandle(pi.HProcess)
} else {
*ppi = pi
}
return result
}
func CreateProcessAsActiveUser(app, param string, ppi *win.PROCESS_INFORMATION) win.BOOL {
activeSession := GetActiveSession()
var userToken win.HANDLE
if win.WTSQueryUserToken(activeSession, &userToken) != 0 {
defer win.CloseHandle(userToken)
var linkedToken win.HANDLE
var size uint32 = uint32(unsafe.Sizeof(linkedToken))
if win.GetTokenInformation(userToken, win.TokenLinkedToken, uintptr(unsafe.Pointer(&linkedToken)), size, &size) != 0 {
defer win.CloseHandle(linkedToken)
var duplicatedToken win.HANDLE
if win.DuplicateTokenEx(linkedToken, win.MAXIMUM_ALLOWED, nil, win.SecurityImpersonation, win.TokenPrimary, &duplicatedToken) != 0 {
var creationFlags uint32 = win.CREATE_NEW_CONSOLE | win.NORMAL_PRIORITY_CLASS
var env uintptr
if win.CreateEnvironmentBlock(&env, duplicatedToken, win.TRUE) != 0 {
creationFlags |= win.CREATE_UNICODE_ENVIRONMENT
defer win.DestroyEnvironmentBlock(env)
}
return CreateProcessAsUser(app, param, duplicatedToken, creationFlags, env, ppi)
}
}
}
return win.FALSE
}
Go で Windows Service を作成する で作成した Windows サービスから呼び出すことで動作を確認可能。