The source files for this module are listed below. You can also download the module C_DesktopWaiter as a zip archive; this archive contains all the source files and documentation.
CDesktopWaiter can make your code wait until the desktop that your application is running on is active again (e.g. the user logged back in from the Windows login screen).
This source code also uses our C_Timer and C_SignalSlot classes. You can also download these at our website.
Windows 2000 and higher has the concept of multiple desktops. Generally all applications run on one desktop, and the Windows logon prompt and screensavers also run in their own private desktops. Sometimes it is necessary to know what desktop the user is looking at; is the user busy in the logon desktop or the screensaver desktop, or is he active on the desktop our application runs on? The class CDesktopWaiter can wait for the desktop of the currently running application (actually thread) to become active.
You can consult with the method OurDesktopActive anytime to check if our desktop is active. In case you do need to wait for our desktop to become active and do not want to use a polling loop, you can call the StartWaiting method. This method will return immediately if our desktop is the active one, but starts a poll on a timer (500 msec.) if it isn't and then returns as well. Once our desktop becomes active again, the CDesktopWaiter object will raise the CUserOnOurDesktopEvent event to notify you our desktop is active.
Each file belonging to this source code module is listed below.
/*******************************************************************************
Version: 4
Author: Carl Colijn, TwoLogs
Contact: c.colijn@twologs.com
Source: https://www.twologs.com/sourcecode
This code is freely distributable, as long as this comment remains intact.
If you find this source useful, you may use this code in your own projects
free of charge, but some acknowledgement to the author of this code is always
appreciated :)
The source is however distributed 'as is' without waranty and/or support, and
may not be fit for each and every application. Use it at your own discretion
and at your own risk.
The source already has undergone testing. This doesn't mean however that all
bugs are removed from this piece of code. If you find one of them, please
contact me about it. I can however not guarantee when and if the bug will be
fixed.
More information about this module can be found in the accompanying HTML file.
*******************************************************************************/
#ifndef INCLUDE_TWOLOGS_COMMON_DESKTOPWAITER_H
#define INCLUDE_TWOLOGS_COMMON_DESKTOPWAITER_H
#include <windows.h>
#include "../C_Timer/Timer.h"
// Notifies when the user is back on our desktop
struct TUserOnOurDesktopEvent: public TEventTypeNoResult {
};
// The logon waiter
class TDesktopWaiter:
public TSlot<TTimerWentOffEvent>,
public TSignal<TUserOnOurDesktopEvent> {
public:
// Con- & destructor
TDesktopWaiter();
virtual ~TDesktopWaiter();
// Starts waiting till the user is on our desktop, if not doing so already
// A timer will be attached to the given window for polling reasons
// When waiting is done, the TUserOnOurDesktopEvent will be raised
// Returns if we started waiting (if our desktop is not active yet)
bool StartWaiting(HWND window);
// Returns if our own desktop is active
bool OurDesktopActive();
private:
// Whether we're waiting
bool m_waiting;
// Our polling timer
TTimer m_timer;
// Gets the name of the given desktop
std::wstring GetDesktopName(HDESK desktop);
// Events
bool OnEvent(TTimerWentOffEvent& event);
};
#endif // INCLUDE_TWOLOGS_COMMON_DESKTOPWAITER_H
/*******************************************************************************
Version: 4
Author: Carl Colijn, TwoLogs
Contact: c.colijn@twologs.com
Source: https://www.twologs.com/sourcecode
This code is freely distributable, as long as this comment remains intact.
If you find this source useful, you may use this code in your own projects
free of charge, but some acknowledgement to the author of this code is always
appreciated :)
The source is however distributed 'as is' without waranty and/or support, and
may not be fit for each and every application. Use it at your own discretion
and at your own risk.
The source already has undergone testing. This doesn't mean however that all
bugs are removed from this piece of code. If you find one of them, please
contact me about it. I can however not guarantee when and if the bug will be
fixed.
More information about this module can be found in the accompanying HTML file.
*******************************************************************************/
#include "DesktopWaiter.h"
// Con- & destructor
TDesktopWaiter::TDesktopWaiter():
m_waiting(false) {
// Connect to our timer
TSlot<TTimerWentOffEvent>::Connect(&m_timer);
}
TDesktopWaiter::~TDesktopWaiter() {
// Kill any timer we're waiting on
m_timer.Stop(false);
}
// Starts waiting till the user is on our desktop, if not doing so already
// A timer will be attached to the given window for polling reasons
// When waiting is done, the TUserOnOurDesktopEvent will be raised
// Returns if we started waiting (if our desktop is not active yet)
bool TDesktopWaiter::StartWaiting(HWND window) {
// Look if our desktop is active
bool needToWait = !OurDesktopActive();
// And look if to start waiting
if (needToWait && !m_waiting) {
// Yes -> init our timer on this window
m_timer.Initialize(window);
// And start it
m_timer.Start(500);
m_waiting = true;
}
// And return if we're waiting
return needToWait;
}
// Gets the name of the given desktop
std::wstring TDesktopWaiter::GetDesktopName(HDESK desktop) {
// Get it's name using a small buffer first
std::wstring desktopName;
desktopName.resize(256);
DWORD neededNameSize;
BOOL infoGotten = GetUserObjectInformation(
desktop,
UOI_NAME,
const_cast<wchar_t*>(desktopName.c_str()),
255,
&neededNameSize
);
if (infoGotten) {
// Done -> return the name
desktopName.at(neededNameSize) = L'\0';
desktopName.resize(neededNameSize);
} else {
// Couldn't -> get the full size name
desktopName.resize(neededNameSize + 1);
infoGotten = GetUserObjectInformation(
desktop,
UOI_NAME,
const_cast<wchar_t*>(desktopName.c_str()),
neededNameSize,
&neededNameSize
);
if (infoGotten) {
// Done -> make sure the name is correctly truncated
desktopName.at(neededNameSize) = L'\0';
desktopName.resize(neededNameSize);
}
}
// And return the found name
return desktopName;
}
// Returns if our own desktop is active
bool TDesktopWaiter::OurDesktopActive() {
// Get the active desktop
SetLastError(0);
HDESK activeDesktop = OpenInputDesktop(0, FALSE, DESKTOP_READOBJECTS);
bool ourDesktopActive = true;
if (activeDesktop == NULL && GetLastError() == 0) {
// Couldn't, but no error -> must be the Winlogon desktop
ourDesktopActive = false;
} else if (activeDesktop != NULL) {
// Done -> get our desktop
HDESK ourDesktop = GetThreadDesktop(GetCurrentThreadId());
// Get the names of the desktops
std::wstring ourDesktopName = GetDesktopName(ourDesktop);
std::wstring activeDesktopName = GetDesktopName(activeDesktop);
// Look if our desktop is active
ourDesktopActive =
0 == wcscmp(ourDesktopName.c_str(), activeDesktopName.c_str());
// And close the active desktop, if needed
CloseDesktop(activeDesktop);
}
// And return if our desktop is active
return ourDesktopActive;
}
// Events
bool TDesktopWaiter::OnEvent(TTimerWentOffEvent& event) {
// Look if our desktop is active now
if (OurDesktopActive()) {
// Yes -> stop the timer
m_timer.Stop(false);
m_waiting = false;
// And notify everyone who needs to know
TUserOnOurDesktopEvent event;
TSignal<TUserOnOurDesktopEvent>::RaiseEvent(event);
}
return true;
}