Click here to Skip to main content
15,886,067 members
Articles / Programming Languages / C++

Virtual Desktop: A Simple Desktop Management Tool

Rate me:
Please Sign up or sign in to vote.
4.83/5 (46 votes)
25 Jul 2008CPOL5 min read 230.2K   11.9K   143  
This article gives you an overview of Windows Station, Windows Desktop and how to work with them. It also has a sample application (Virtual Desktop) demonstrating multiple desktop management.
#include "StdAfx.h"
#include "DesktopManager.h"
#include "SHLWAPI.h"
#include "CommonDef.h"

extern void DebugPrintErrorMessage(TCHAR *pszErrorString = NULL, bool bDisplayMsg = false, TCHAR *pszMsgCaption = NULL);

StringVector CDesktopManager::m_szDesktopNames;

//Function enumerates all the desktops of the windows station.
BOOL CALLBACK EnumDesktopProc(LPTSTR lpszDesktopName, LPARAM lParam)
{
	try
	{
		//Adding Desktop Name To DesktopName List.
		CDesktopManager::AddDesktop(lpszDesktopName);
	}
	catch(...)
	{
		DebugPrintErrorMessage(_T("\nEnumDesktopProc:\tException caught in EnumDesktopsProc."));
	}

	return TRUE;
}

CDesktopManager::CDesktopManager(void)
{
	//Populates all the desktop names.
	PopulateDesktopList();
}

CDesktopManager::~CDesktopManager(void)
{
	ReleaseMemory();
}

bool CDesktopManager::PopulateDesktopList(void)
{
	bool bReturn = false;
	try
	{
		HWINSTA hWindowsStation = GetProcessWindowStation();
		if(NULL == hWindowsStation)
			throw false;

		ReleaseMemory();

		bReturn = (FALSE != EnumDesktops(hWindowsStation, &EnumDesktopProc, NULL)); //m_szDesktopNames));
	}
	catch(bool bThrowVal)
	{
		bReturn = bThrowVal;
	}
	catch(...)
	{
		DebugPrintErrorMessage(_T("\nCDesktopManager::PopulateDesktopList:\tException caught in CDesktopManager::PopulateDesktopList"));
	}

	return bReturn;
}

//Returns the number of desktops in the window station.
int CDesktopManager::GetDesktopCount(void)
{
	//Refresh the list.
	PopulateDesktopList();
	return (int) m_szDesktopNames.size();
}

//Release the memory to avoid memory leak.
void CDesktopManager::ReleaseMemory(void)
{
	int iSize = (int) m_szDesktopNames.size();
	for(int iCount =0;iCount < iSize;iCount ++)
	{
		if(m_szDesktopNames[iCount] != NULL)
		{
			delete m_szDesktopNames[iCount];
			m_szDesktopNames[iCount] = NULL;
		}
	}

	m_szDesktopNames.clear();
}

//Switch between desktops.
bool CDesktopManager::SwitchDesktop(TCHAR *pszDesktopName)
{
	bool bReturn = false;
	try
	{
		if (NULL == pszDesktopName)
		{
			OutputDebugString(_T("\nCDesktopManager::SwitchDesktop:\tNULL DesktopName in CDesktopManager::SwitchToDesktop"));
			throw false;
		}

		/*if( !_tcsicmp(_T("Winlogon"), szDesktopName) || !_tcsicmp(_T("Disconnect"), szDesktopName))
		{
			TCHAR szErrorMsg[ARRAY_SIZE] = {_T("You can not switch to ")};
			_tcscat_s(szErrorMsg, ARRAY_SIZE -1, szDesktopName);
			_tcscat_s(szErrorMsg, ARRAY_SIZE -1, _T(" Desktop."));
			MessageBox(NULL, szErrorMsg, TXT_MESSAGEBOX_TITLE, MB_ICONINFORMATION);
			throw false;
		}*/

		//Open desktop handle to switch to.
		HDESK hDesktopToSwitch = OpenDesktop(pszDesktopName, DF_ALLOWOTHERACCOUNTHOOK, TRUE, GENERIC_ALL);
		if(NULL == hDesktopToSwitch)
		{
			TCHAR *pszError = NULL;
			TCHAR szErrorMsg[ARRAY_SIZE] = {0};
			int iErrorCode = GetLastError();
			if(5 == iErrorCode)
			{
				
				FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 
								NULL, iErrorCode, 0, (LPWSTR) &pszError, 0, NULL);

				wsprintf(szErrorMsg, _T("Failed to switch to %s desktop.\n\t %s"), pszDesktopName, pszError);
				MessageBox(NULL, szErrorMsg, TXT_MESSAGEBOX_TITLE, MB_ICONINFORMATION | MB_TOPMOST | MB_TASKMODAL);
				OutputDebugString(pszError);
			}

			wsprintf(szErrorMsg, _T("\nCDesktopManager::SwitchDesktop:\tOpenDesktop Failed in CDesktopManager::SwitchToDesktop. Last Error : %s"), pszError);
			OutputDebugString(szErrorMsg);

			throw false;
		}

		//Switch the desktop.
		if(FALSE == ::SwitchDesktop(hDesktopToSwitch))
		{
			OutputDebugString(_T("\nCDesktopManager::SwitchDesktop:\tSwitchDesktop Failed in CDesktopManager::SwitchToDesktop"));
			throw false;
		}
 
		//Close the desktop handle.
		CloseDesktop(hDesktopToSwitch);
		bReturn = true;
	}
	catch(bool bThrownVal)
	{
		bReturn = bThrownVal;
	}
	catch(...)
	{
		bReturn = false;
		DebugPrintErrorMessage(_T("\nCDesktopManager::SwitchDesktop:\tException caught in CDesktopManager::SwitchToDesktop"));
	}
	return bReturn;
}


//Creats new desktop.
bool CDesktopManager::CreateDesktop(TCHAR *pszDesktopName)
{
	bool bReturn = false;
	try
	{
		if(NULL == pszDesktopName)
		{
			OutputDebugString(_T("\nCDesktopManager::CreateDesktop:\tNULL DesktopName in CDesktopManager::CreateDesktop"));
			throw false;
		}

		//Setting the desktop security attributes.
		SECURITY_ATTRIBUTES sAttribute = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
		HDESK hNewDesktop = NULL;

		//Creating a new desktop with all access.
		hNewDesktop = ::CreateDesktop(pszDesktopName, NULL, NULL, DF_ALLOWOTHERACCOUNTHOOK, GENERIC_ALL, &sAttribute);

		if(NULL == hNewDesktop)
		{
			TCHAR *pszError = NULL, szErrorMsg[ARRAY_SIZE] = {0};
			FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 
				NULL, GetLastError(), 0, (LPWSTR) &pszError, 0, NULL);
			OutputDebugString(_T("\n\t\t"));
			OutputDebugString(pszError);

			_tcscpy_s(szErrorMsg, ARRAY_SIZE, pszError);
			LocalFree( pszError);

			MessageBox(NULL, szErrorMsg, TXT_MESSAGEBOX_TITLE, MB_ICONERROR | MB_TOPMOST | MB_TASKMODAL);
			throw szErrorMsg;
		}

		int iCount = 0;
		//Checking whether desktop name already exists.
		for(iCount = (int) m_szDesktopNames.size();0 < iCount;iCount--)
			if(_tcsicmp(pszDesktopName, m_szDesktopNames[iCount - 1]) == 0)
				break;

		if(iCount <= 0)
		{
			OutputDebugString(_T("\nCDesktopManager::CreateDesktop:\tCreating New Desktop"));

			TCHAR szExplorerFile[ARRAY_SIZE]= {0};

			GetWindowsDirectory(szExplorerFile, ARRAY_SIZE -1);
			_tcscat_s(szExplorerFile, ARRAY_SIZE -1, _T("\\Explorer.Exe"));

			LaunchApplication(szExplorerFile, pszDesktopName);
		}

		//Closing the desktop handle.
		if(NULL != hNewDesktop)
			CloseDesktop(hNewDesktop);

		bReturn = PopulateDesktopList();
	}
	catch(TCHAR *pErrorMsg)
	{
		OutputDebugString(_T("\nCDesktopManager::CreateDesktop:\tException Caught In CDesktopManager::CreateDesktop."));
		DebugPrintErrorMessage(pErrorMsg);
		bReturn = false;
	}
	catch(...)
	{
		bReturn = false;
		DebugPrintErrorMessage(_T("\nCDesktopManager::CreateDesktop:\tException Caught In CDesktopManager::CreateDesktop."));
	}
	return bReturn;
}

//Returns the desktop name at specified index.
void CDesktopManager::GetDesktopName(int iIndex, TCHAR *pszDesktopName)
{
	try
	{
		if (iIndex < (int) m_szDesktopNames.size())
			_tcscpy_s(pszDesktopName, _tcslen(m_szDesktopNames[iIndex]) + 1, m_szDesktopNames[iIndex]);
	}
	catch(...)
	{
		DebugPrintErrorMessage(_T("\nCDesktopManager::GetDesktopName:\tException caught in CDesktopManager::GetDesktopName."));
	}
}

//Adds the specified desktop name into the list.
void CDesktopManager::AddDesktop(TCHAR *pszDesktopName)
{
	try
	{
		//m_szDesktopNames[m_iDesktopCount] = new TCHAR[_tcslen(lpszDesktopName) + 1];
		m_szDesktopNames.push_back(new TCHAR[_tcslen(pszDesktopName) + 1]);
		ZeroMemory(m_szDesktopNames[m_szDesktopNames.size() - 1], _tcslen(pszDesktopName) + 1);
		_tcscpy_s(m_szDesktopNames[m_szDesktopNames.size() - 1], _tcslen(pszDesktopName) + 1, pszDesktopName);

		//m_iDesktopCount++;
	}
	catch(...)
	{
		DebugPrintErrorMessage(_T("\nCDesktopManager::AddDesktop\tException caught in CDesktopManager::AddDesktop."));
	}
}

//Checks whether the specified desktop is current active desktop(deskop of the current thread).
bool CDesktopManager::IsCurrentDesktop(TCHAR *pszDesktopName)
{
	bool bReturn = false;

	try
	{
		TCHAR szCurrentDesktopName[ARRAY_SIZE] = {0};
		DWORD iOutCount = 0;
		HDESK hCurrentDesktop = GetThreadDesktop(GetCurrentThreadId());
		GetUserObjectInformation(hCurrentDesktop, UOI_NAME, szCurrentDesktopName, ARRAY_SIZE - 1, &iOutCount);

		bReturn = (_tcsicmp(pszDesktopName, szCurrentDesktopName) == 0);
	}
	catch(...)
	{
		DebugPrintErrorMessage(_T("\nCDesktopManager::IsCurrentDesktop\tException caught in CDesktopManager::IsCurrentDesktop."));
		bReturn = false;
	}

	return bReturn;
}

//Checks whether the specified desktop is current active desktop(deskop of the current thread).
bool CDesktopManager::GetCurrentDesktopName(TCHAR szDesktopName[ARRAY_SIZE])
{
	bool bReturn = false;

	try
	{
		DWORD iOutCount = 0;
		HDESK hCurrentDesktop = GetThreadDesktop(GetCurrentThreadId());
		if(!GetUserObjectInformation(hCurrentDesktop, UOI_NAME, szDesktopName, ARRAY_SIZE - 1, &iOutCount))
			throw _T("\nCDesktopManager::GetCurrentDesktopName:\t GetUserObjectInformation() failed.");

		bReturn = true;
	}
	catch(TCHAR *pszErrorString)
	{
		DebugPrintErrorMessage(pszErrorString);
	}
	catch(...)
	{
		DebugPrintErrorMessage(_T("\nCDesktopManager::IsCurrentDesktop\tException caught in CDesktopManager::IsCurrentDesktop."));
		bReturn = false;
	}

	return bReturn;
}

bool CDesktopManager::LaunchApplication(TCHAR *pszApplicationFilePath, TCHAR *pszDesktopName)
{
	bool bReturn = false;

	try
	{
		if(!pszApplicationFilePath || !pszDesktopName || !_tcslen(pszApplicationFilePath) || !_tcslen(pszDesktopName))
			throw _T("Invalid Argument.");

		TCHAR szDirectoryName[ARRAY_SIZE] = {0};
		TCHAR szExplorerFile[ARRAY_SIZE]= {0};

		_tcscpy_s(szDirectoryName, _tcslen(pszApplicationFilePath) + 1, pszApplicationFilePath);
		
		if(!PathIsExe(pszApplicationFilePath))
			throw _T("Invalid File Extension");

		PathRemoveFileSpec(szDirectoryName);

		STARTUPINFO sInfo = {0};
		PROCESS_INFORMATION pInfo = {0};

		sInfo.cb = sizeof(sInfo);
		sInfo.lpDesktop = pszDesktopName;

		//Lanuching a application into dekstop
		BOOL bCreateProcessReturn = CreateProcess(pszApplicationFilePath, 
			NULL, 
			NULL, 
			NULL, 
			TRUE, 
			NORMAL_PRIORITY_CLASS, 
			NULL, 
			szDirectoryName, 
			&sInfo, 
			&pInfo);

		TCHAR *pszError = NULL;
		FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 
			NULL, GetLastError(), 0, (LPWSTR) &pszError, 0, NULL);
		OutputDebugString(_T("\n\t\t"));
		OutputDebugString(pszError);

		if(bCreateProcessReturn)
			bReturn = true;
	}
	catch(TCHAR *pszError)
	{
		OutputDebugString(_T("\nCDesktopManager::LaunchApplication\tCustom Exception caught in CDesktopManager::IsCurrentDesktop."));
		DebugPrintErrorMessage(pszError);
		bReturn = false;
	}
	catch(bool)
	{
		DebugPrintErrorMessage(_T("\nCDesktopManager::LaunchApplication\tCustom Exception caught in CDesktopManager::IsCurrentDesktop."));
		bReturn = false;
	}
	catch(...)
	{
		DebugPrintErrorMessage(_T("\nCDesktopManager::LaunchApplication\tException caught in CDesktopManager::IsCurrentDesktop."));
		bReturn = false;
	}

	return bReturn;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
India India
Hello All !
This is Mallinath S. Karkanti, from India. I'm working as a Software Developer in one of the Middle Scale Company... !

Comments and Discussions