I have several applications that are part of a suite of tools that various developers at our studio use. these applications are mainly command line apps that open a DOS cmd shell. These apps in turn start up a GUI application that tracks output and status (via sockets) of these command line apps.
The command line apps can be started with the user is logged in, when their workstation is locked (they fire off a batch file and then immediately lock their workstation), and when they are logged out (via a scheduled task). The problems that I have are with the last two cases.
If any of these apps fire off when the user is locked or logged out, these command will spawn the GUI windows which tracks the output/status. That's fine, but say the user has their workstation locked -- when they unlock their workstation, the GUI isn't visible. It's running the task list, but it's not visible. The next time these users run some of our command line apps, the GUI doesn't get launched (because it's already running), but because it's not visible on the desktop, users don't see any output.
What I'm looking for is a way to tell from my command line apps if they are running behind a locked workstation or when a user is logged out (via scheduled task) -- basically are they running without a user's desktop visible. If I can tell that, then I can simply not start up our GUI and can prevent a lot of problem.
These apps that I need to test are C/C++ Windows applications.
I hope that this make sense.
I found the programmatic answer that I was looking for. It has to do with stations. Apparently anything running on the desktop will run on a station with a particular name. Anything that isn't on the desktop (i.e. a process started by the task manager when logged off or on a locked workstation) will get started with a different station name. Example code:
HWINSTA dHandle = GetProcessWindowStation();
if ( GetUserObjectInformation(dHandle, UOI_NAME, nameBuffer, bufferLen, &lenNeeded) ) {
if ( stricmp(nameBuffer, "winsta0") ) {
// when we get here, we are not running on the real desktop
return false;
}
}
If you get inside the 'if' statement, then your process is not on the desktop, but running "somewhere else". I looked at the namebuffer value when not running from the desktop and the names don't mean much, but they are not WinSta0.
Link to the docs here.
You might be able to use SENS (System Event Notification Services). I've never used it myself, but I'm almost positive it will do what you want: give you notification for events like logon, logoff, screen saver, etc.
I know that's pretty vague, but hopefully it will get you started. A quick google search turned up this, among others: http://discoveringdotnet.alexeyev.org/2008/02/sens-events.html
I have successfully used this approach to detect whether the desktop is locked on Windows:
bool isDesktopLocked = false;
HDESK inputDesktop = OpenInputDesktop(0, FALSE,
DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW |
DESKTOP_ENUMERATE | DESKTOP_SWITCHDESKTOP |
DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS |
DESKTOP_WRITE);
if (NULL == inputDesktop)
{
isDesktopLocked = true;
}
else
{
CloseDesktop(inputDesktop);
}
Related
I have a C++ windows service running on system privileges and I need to make some changes in some of my DLLs that are loaded to several windows processes (explorer.exe, etc.).
The only time to do so is when these processes are down. I'm trying to make to impact to the UX minimal, so I don't wan't to force quit those or to popup any annoying message boxes and ask the user to do so.
I have tried to start this task on the startup of my service, the issue is several of these processes start before I finished it.
I'm trying to understand if there is a way to delay the start of processes on Windows startup, until I finish my task. Is there any event or anything familiar that I can set that will block those?
The other option is to do the needed task on shutdown. I did not find a way to do so yet, and all the related questions seem a bit old (how to delay shutdown and run a process in window service
), and regard to older version of windows.
This solution needs to be compatible with Windows versions greater than 7.
You can do this by using MoveFileEx and setting MOVEFILE_DELAY_UNTIL_REBOOT which will replace the file at the next reboot.
This should be well before any other processes have started, but without more details on your usecase its hard to tell if this'll work for you. Either way, searching for this flag should give you lots of information about this kind of issue.
According to the documentation, this has been supported since XP.
I'd like to know what is the Windows API function (if any exists) that provides information about the last Windows reboot source. There are three main possible causes:
The computer crashed on a blue screen
A user or a program shutdown/restarted the computer
A power lost
The more details I can get the better. However, I need to know at least which reason it is from the main ones.
I need to support Windows Vista and Windows 7.
Answer:
It seems that there is no direct API to get that information. Instead, we have to harvest the Windows Event Log. System reboot information is located in Event Viewer/Windows Logs/System. Here is the various information provided by the event ids:
6005: Windows start-up
6006: Windows shutdown (properly)
6008: Windows shutdown (unexpectedly)
I do not yet get the difference between power lost and system crash, but it's a good start.
This article explains in detail how to find the reason for last startup/shutdown. In my case, this was due to windows SCCM pushing updates even though I had it disabled locally. Visit the article for full details with pictures. For reference, here are the steps copy/pasted from the website:
Press the Windows + R keys to open the Run dialog, type eventvwr.msc, and press Enter.
If prompted by UAC, then click/tap on Yes (Windows 7/8) or Continue (Vista).
In the left pane of Event Viewer, double click/tap on Windows Logs to expand it, click on System to select it, then right click on
System, and click/tap on Filter Current Log.
Do either step 5 or 6 below for what shutdown events you would like to see.
To see the dates and times of all user shut downs of the computer
A) In Event sources, click/tap on the drop down arrow and check the USER32 box.
B) In the All Event IDs field, type 1074, then click/tap on OK.
C) This will give you a list of power off (shutdown) and restart
shutdown type of events at the top of the middle pane in Event Viewer.
D) You can scroll through these listed events to find the events
with power off as the shutdown type. You will notice the date and
time, and what user was responsible for shutting down the computer per
power off event listed.
E) Go to step 7.
To see the dates and times of all unexpected shut downs of the computer
A. In the All Event IDs field type 6008, then click/tap on OK.
B. This will give you a list of unexpected shutdown events at the
top of the middle pane in Event Viewer. You can scroll through these
listed events to see the date and time of each one.
When finished, you can close Event Viewer.
Other useful event IDs (source)
ID
Description
41
The system has rebooted without cleanly shutting down first.
1074
The system has been shutdown properly by a user or process.
1076
Follows after Event ID 6008 and means that the first user with shutdown privileges logged on to the server after an unexpected restart or shutdown and specified the cause.
6005
The Event Log service was started. Indicates the system startup.
6006
The Event Log service was stopped. Indicates the proper system shutdown.
6008
The previous system shutdown was unexpected.
6009
The operating system version detected at the system startup.
6013
The system uptime in seconds.
Take a look at the Event Log API. Case a) (bluescreen, user cut the power cord or system hang) causes a note ('system did not shutdown correctly' or something like that) to be left in the 'System' event log the next time the system is rebooted properly. You should be able to access it programmatically using the above API (honestly, I've never used it but it should work).
You may automate your investigation for the last 5 days with this powershell script:
$today = Get-Date
$startDay = $today.AddDays(-5)
$eventIds=(6005,6006,6008,6009,1074,1076,12,13,43,109)
$systEvents=Get-WinEvent -LogName System
$rebootEvents=$systEvents| Where-Object {$_.TimeCreated -gt $startDay} | Where-Object {$_.Id -in $eventIds}
format-table TimeCreated,Id,Message -AutoSize -wrap -InputObject $rebootEvents
I have a remote desktop and i'm trying to run a simple script to prevent idle session timeout, which is 3 min (quite annoying). The script should, for example, press "A" key every 2.5 min or so.
Problem is, the remote desktop window is often inactive/minimized and:
1) if i try to run such a script "inside" the remote desktop, i still get disconnected, despite it actually works (continues to type or create/delete files etc even as the "idle timer expired" message is on screen). i believe the system wants some "external" action.
2) if i run the script on my PC, it doesn'do anything at all on the remote desktop (i had an open notebook there, and there was no typing):
ControlSend("[CLASS:TscShellContainerClass]", "", "[CLASS:OPContainerClass; INSTANCE:1]", "{A}")
I think the problem lies with the "controlid" part, which i got via autoit window info. If i set controlid as "" - it works, but only if the window is currently active.
I've seen a registry key solution, but doesn't seem to work for me.
If anyone has any ideas about fixing this, please, don't hold back:)
I know it's late but here's the ONLY thing I could get to work; it involved activating the window. I tried ControlFocus but to no avail, so here's what I got.
You should be able to modify your script as needed.
#include<Array.au3>
OPT("WinTitleMatchMode",2)
$a = WinList("Remote Desktop Connection")
;_ArrayDisplay($A)
ConsoleWrite(UBound($A)& #CRLF)
FOR $N = 1 to $A[0][0]
$hActiveWindow = WinGetHandle("")
WinActivate($a[$N][1]) ;comment if using controlfocus
;ControlFocus($a[$N][1],"","") ;comment if using winactivate
ControlSend($a[$N][1],"","","^+{ESC}")
WinActivate($hActiveWindow)
Next
How can i programatically check if the windows shell (explorer) has loaded all startup programs & the user login process is over ?
There is a somewhat documented event you can wait for, but it is signaled when explorer has started loading. On XP this event is called "msgina: ShellReadyEvent" and "ShellDesktopSwitchEvent" on Vista. I linked to the sources of some alternative shells in a post related to this event.
Another alternative would be to listen for the Taskbar Creation Notification message. It can fire more than once so you would need to keep track of that.
On Vista+ there is one last alternative that might just work: Programs set to run at startup are part of a job object so they cannot run at high priority. If your program runs at startup you could maybe check for this, either by using IsProcessInJob or SetPriorityClass+GetPriorityClass in a loop. (SetPriorityClass will lie about its return value IIRC)
I'm using QTP 10 together with VMWare to test a Siebel Application.
I'm executing the following code to click on a Save button.
Browser("Siebel").Dialog("Filedownload").WinButton("Save").Click
The code works perfectly fine when I'm connected to the VM via Remote Desktop.
On the other side, when I'm starting the QTP test through the scheduler, without having a Remote Desktop connection, the code above fails without any error message. The WinButton is simply not clicked.
Any idea?
Just to add from my experience.
In some companies I worked for I couldn't change screensaver or standby settings due to security policy. A PC was bringing up screensaver during long synchronization periods (like generating really big report), and execution was broken.
To avoid that I created simple "Anti Sleep" function that slightly "moves" mouse every 5 minutes.
http://automation-beyond.com/2009/08/18/anti-sleep-function/
Private Const SleepTime_Max = 300 ‘ 5 minutes
Public Function AntiSleep()
Dim iter
Dim objTimer
Dim objDeviceReplay
Dim intTimeElapsed
Set objTimer = MercuryTimers(“AntiSleep”)
intTimeElapsed = CInt(objTimer.ElapsedTime/1000)
If intTimeElapsed = 0 Then
MercuryTimers(“AntiSleep”).Start
Exit Function
End If
If intTimeElapsed < SleepTime_Max Then
Exit Function
End If
Set objDeviceReplay = CreateObject(“Mercury.DeviceReplay”)
For iter = 100 To 110
objDeviceReplay.MouseMove iter,300
Next
MercuryTimers(“AntiSleep”).Start
Set objDeviceReplay = Nothing
End Function
Example of using it in a custom synchronization function:
http://automation-beyond.com/2009/08/20/gui-object-synchronization-custom-function/
Thank you,
Albert Gareev
QTP can't interact with a locked desktop, that's why it'll only work for you when logged in interactively either locally or over RDP. It's a well known limitation of QTP, most automation engineers go through this pain at some point. :)
To be more specific, it can't interact with Win32 objects (can't think of a better way of putting it), so it'll interact with basic browser controls on a locked desktop no problem, but browser popups and Windows applications can't be interacted with in those circumstances.
I strongly recommend (if your system policy allows) that you install something like UltraVNC or another VNC variant to interact with your remote machines. That way you can leave the remote machine's desktop logged on and active at all times. Since it's a VM that shouldn't cause you any major security problems either. Make sure you turn off any screen savers and don't auto-lock the desktop too. QTP should work just fine for you if you do that.