Jump to content
Sign in to follow this  
jstump1

convert interactive service to use WTSSendMessage function?

Recommended Posts

jstump1

Hello -

I have an energy-saving app that I use on Windows XP that is going to need a couple of modifications to work on Windows Vista, 7, 8, and on.

It is an AutoIt app that I run as an interacitve service under the local system account using srvany.exe. The program creates one dialogue box that asks the user if they want to continue working or to shutdown. The app continues to work on Win 7, but the Interactive Services Detection notificaton is a problem. Most users ignore it or don't have a clue what it is, so they never see the msgbox asking if they want to continue working.

I read Microsoft's info on this redesign issue - see http://msdn.microsoft.com/en-us/library/windows/desktop/ms683502(v=vs.85).aspx and this whitepaper http://msdn.microsoft.com/en-us/windows/hardware/gg463353.aspx

Can anyone tell me if it is possible to redesign my program to use the WTSSendMessage function that Microsoft recommends?

I am attaching most of my project, excluding EXEs. If it gets completed I'll post it to the sample scripts forum. This program records info necessary for implementing wake-on-lan (via another autoit script), plus it shuts down PCs using some intelligence and a flexible schedule.

TIA

James

EDIT: So it looks like WTSAPI32.DLL is what I am looking for since it contains the function. I'll have to figure out how to call the dll and use the function with it.

InstallScheduledShutdown.zip

Edited by jstump1

Share this post


Link to post
Share on other sites
jstump1

To further clarify what I want to accomplish: I want to send a message to the logged-on user asking them to respond OK or cancel. Currently it is done with a msgbox, but I need to do it with a remote desktop function instead. The AutoIt script runs under the localsystem account, so it can't interact with the desktop of the logged on user for windows versions above XP.

$UserResponse = MsgBox(1, "Scheduled Power Action", "Your computer is scheduled to " & $UserActionMessage & ". Click CANCEL to keep working.", $ShutDownWindowTimeout)

This code instead needs to use dllcall to Wtsapi32.dll. Function called will be WTSSendMessage, on session host computer 'WTS_CURRENT_SERVER_HANDLE', session id 0 (console user).

Working with dlls looks a bit over my head. I need some help from someone who can explain how to handle variables, structures, pointers, etc. I don't understand all the variable types and how to match a type in autoit to the types and structure Microsoft documents. I see the documentation, but I do not have understanding yet. Thanks

Edited by jstump1

Share this post


Link to post
Share on other sites
jstump1

OK - So I am starting to figure this out on my own. I'm getting closer, but it still doesn't work on Windows 7. It works OK on XP because the console session id is 0. On windows vista and above it is different. I need help getting dllcall to work for Windows 7.

For some reason the below script works OK, except for the DllCall functions. Please help. On XP the DllCall functions do not return a result or @error but the second DllCall works, first one does nothing I can tell. On Win 7 neither DllCall works or returns anything - not even an @ error.

$ShutDownWindowTimeout = "30"
$UserActionMessage = "SHUTDOWN"
$pTitle = DllStructCreate("char Title[32]")
MsgBox(0, "DllStructCreate Title", @error)
$pMessage = DllStructCreate("char Message[128]")
MsgBox(0, "DllStructCreate Message", @error)
$pResponse = DllStructCreate("DWORD Response")
MsgBox(0, "DllStructCreate Response", @error)
$SessionId = DllCall("kernel32.dll", "DWORD", "WTSGetActiveConsoleSessionId")
MsgBox(0, "DllCall Kernel32 SessionId,@error", $SessionId & "," & @error)
DllStructSetData($pTitle, "Title", "Scheduled Power Action")
MsgBox(0, "DllStructSetData Title,@error", DllStructGetData($pTitle, "Title") & "," & @error)
DllStructSetData($pMessage, "Message", "Your computer is scheduled to " & $UserActionMessage & ". Click CANCEL to keep working.")
MsgBox(0, "DllStructSetData Message,@error", DllStructGetData($pMessage, "Message") & "," & @error)
$DllCallResponse = DllCall("wtsapi32.dll","BOOLEAN","WTSSendMessageA","HANDLE","WTS_CURRENT_SERVER_HANDLE","DWORD",$SessionId,"str",DllStructGetData($pTitle, "Title"),"DWORD",DllStructGetSize($pTitle),"str",DllStructGetData($pMessage, "Message"),"DWORD",DllStructGetSize($pMessage),"UINT","1L","DWORD",$ShutDownWindowTimeout,"DWORD",DllStructGetPtr($pResponse),"BOOLEAN","1")
MsgBox(0, "DllCall Response,@error", $DllCallResponse,@error)
MsgBox(0, "DllCall pointer response", DllStructGetData($pResponse, "Response"))
Edited by jstump1
My eyes could not even read the text at the original size!

Share this post


Link to post
Share on other sites
jstump1

OK - I finally solved this. I didn't catch the info in the documentation on DllCall that the result from the function is an array. With that info I was finally able to figure out how to make the API call necessary ;)

Example code:

#include <WinAPI.au3>
$ShutDownWindowTimeout=800
$UserActionMessage = "SHUTDOWN"
$pTitle = DllStructCreate("char Title[32]")
$pMessage = DllStructCreate("char Message[128]")
$pResponse = DllStructCreate("DWORD Response")
$KernelCall = DllOpen(@SystemDir & "Kernel32.dll")
$SessionId = DllCall($KernelCall, "DWORD", "WTSGetActiveConsoleSessionId")
DllClose($KernelCall)
DllStructSetData($pTitle, "Title", "Scheduled Power Action")
DllStructSetData($pMessage, "Message", "Your computer is scheduled to " & $UserActionMessage & ". Click CANCEL to keep working.")
$wtsapiCall = DllOpen(@SystemDir & "Wtsapi32.dll")
$SendMessageResult = DllCall($wtsapiCall,"BOOL","WTSSendMessageA","HANDLE","WTS_CURRENT_SERVER_HANDLE","DWORD",$SessionId[0],"str",DllStructGetData($pTitle, "Title"),"DWORD",DllStructGetSize($pTitle),"str",DllStructGetData($pMessage, "Message"),"DWORD",DllStructGetSize($pMessage),"DWORD","1L","DWORD",$ShutDownWindowTimeout,"DWORD",DllStructGetPtr($pResponse),"BOOL","1")
MsgBox(0, "WinAPILastError", _WinAPI_GetLastError() & "," & _WinAPI_GetLastErrorMessage())
MsgBox(0, "DllCall Response,@error", $SendMessageResult[0] & "," & $SendMessageResult[1] & "," & $SendMessageResult[2] & "," & $SendMessageResult[3] & "," & $SendMessageResult[4] & "," & $SendMessageResult[5] & "," & $SendMessageResult[6] & "," & $SendMessageResult[7]& $SendMessageResult[8] & "," & $SendMessageResult[9] & "," & $SendMessageResult[10])
MsgBox(0, "DllCall pointer response", DllStructGetData($pResponse, "Response"))
DllClose($wtsapiCall)

Share this post


Link to post
Share on other sites
robinj

Just taking a look at your code because I want a service I am writing to pop up a status message on screen with option to abort. I take it that your code has two components, one running in system account and one under the user account? not able to access you code since zip file is password protected....

Robin

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×