Thread: EnumWindows + XP

  1. #1
    pronounced 'fib' FillYourBrain's Avatar
    Join Date
    Aug 2002
    Posts
    2,297

    EnumWindows + XP

    I am writing an app that is responsible for shutting down and replacing all instances of another app. I was doing this with EnumWindows, searching for the right window class name and sending a message that will cause it to quit.

    WindowXP however has the option of multiple users being logged in at once. EnumWindows doesn't give me those windows that are on another login. So I can't shut them down. This obviously prevents me from replacing the exe.

    Is there a way of notification across logins that anyone's run across or can you come up with something clever?
    "You are stupid! You are stupid! Oh, and don't forget, you are STUPID!" - Dexter

  2. #2
    &TH of undefined behavior Fordy's Avatar
    Join Date
    Aug 2001
    Posts
    5,793
    Must admit that I have never dealt with multiple users before, but maybe you could try a different approach?

    WinXP allows the use of Psapi.dll to give you lots of power over running processes and threads...maybe that will be more successfull??...have a try and say if it worked

    Code:
    #include <windows.h>
    #include <iostream>
    #include <cstring>
    
    const int MAX_PROCESSES = 300,//arbitary number...maybe more needed
    			MAX_MODULES = 50;//again - maybe more needed
    const char* szPathToChange = "calc.exe";//name of app to kill
    
    	/*Sigh...I have old headers at the moment....so I must load the 
    	PSAPI funcs manually - you might be able to skip this - should you wish to*/
    
    typedef BOOL(WINAPI *ENUMPROCESSMODULES)(HANDLE,HMODULE *, DWORD,LPDWORD);
    typedef BOOL(WINAPI *ENUMPROCESSES)(DWORD *,DWORD,DWORD *);
    typedef DWORD(WINAPI *GETMODULEBASENAME)(HANDLE,HMODULE,LPTSTR,DWORD);
    
    ENUMPROCESSMODULES lpfEnumProcessModules;
    ENUMPROCESSES lpfEnumProcesses;
    GETMODULEBASENAME lpfGetModuleBaseName;
    
    void CheckProcess(DWORD dwPID)
    {
    	HMODULE hModArray[MAX_MODULES];//array of handles to loaded modules
    	DWORD dwNoModules;//number of modules in process
    	char szPath[MAX_PATH+1];//name of module
    
    	//Get process handle
    	HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwPID);
    	if(!dwPID)//if unable to open handle
    	{
    		std::cout << "Unable to open handle to PID - ";
    		std::cout << dwPID << std::endl;
    		return;
    	}
    
    	__try//Structured Exception Handling....ensure close Proc Handle
    	{
    		if(!lpfEnumProcessModules(hProc,hModArray, sizeof(hModArray),
    			&dwNoModules))//find modules in process
    		{
    			std::cout << "Unable to enumerate modules of PID - ";
    			std::cout << dwPID << std::endl;
    			return;
    		}
    
    		for(int i = 0;i < dwNoModules;++i)
    		{
    			if(lpfGetModuleBaseName(hProc,hModArray[i], szPath,
    				MAX_PATH))//Get name of each process
    			{
    				//is it the one we are interested in?
    				if(strcmp(szPath,szPathToChange) == 0)
    				{
    					std::cout << "Found an instance under PID ";
    					std::cout << dwPID << " - Terminating" << std::endl;
    					TerminateProcess(hProc,0);//kill it!
    				}
    			}
    		}
    	}
    	__finally
    	{
    		CloseHandle(hProc);//close handle to opened process
    	}
    }
    
    int main(void)
    {
    	DWORD dwPIDArray[MAX_PROCESSES];//array of Process IDs
    	DWORD dwNoProcesses;//Number of PIDs
    
    	//Load the PSAPI library (WinNT,2k,XP only)
    	HMODULE hLib = LoadLibrary("C:\\WINDOWS\\system32\\PSAPI.dll");
    	if(!hLib)
    	{
    		std::cout << "Unable to load PSAPI" << std::endl;
    		return 1;
    	}
    
    	__try
    	{
    		//find the 3 functions we need for this code
    
    		lpfEnumProcesses = reinterpret_cast<ENUMPROCESSES>
    			(GetProcAddress(hLib,"EnumProcesses"));
    		if(!lpfEnumProcesses)
    		{
    			std::cout << "Unable to find EnumProcesses Func!" << std::endl;
    			return 1;
    		}
    
    		lpfEnumProcessModules = reinterpret_cast<ENUMPROCESSMODULES>
    			(GetProcAddress(hLib,"EnumProcessModules"));
    		if(!lpfEnumProcessModules)
    		{
    			std::cout << "Unable to find EnumProcessModules Func!" << std::endl;
    			return 1;
    		}
    
    		lpfGetModuleBaseName = reinterpret_cast<GETMODULEBASENAME>
    			(GetProcAddress(hLib,"GetModuleBaseNameA"));
    		if(!lpfGetModuleBaseName )
    		{
    			std::cout << "Unable to find GetModuleBaseName Func!" << std::endl;
    			return 1;
    		}
    
    
    		//Now enumerate all processes on system
    		if(!lpfEnumProcesses(dwPIDArray, sizeof(dwPIDArray), &dwNoProcesses))
    		{
    			std::cout << "Unable to enumerate Processes!" << std::endl;
    			return 1;
    		}		
    
    		for(int i = 0;i < dwNoProcesses/sizeof(DWORD);++i)
    		{
    			CheckProcess(dwPIDArray[i]);//examine process
    		}
    	}
    	__finally
    	{
    		FreeLibrary(hLib);//release the library
    	}
    	return 0;
    }

  3. #3
    &TH of undefined behavior Fordy's Avatar
    Join Date
    Aug 2001
    Posts
    5,793
    Damn....doesnt work...

    I created an app to start a process in another user's account....didnt kill it.......I'll keep trying though

  4. #4
    &TH of undefined behavior Fordy's Avatar
    Join Date
    Aug 2001
    Posts
    5,793
    I have a workaround

    You need to get the access token of each logged on user and impersonate them...

    Code:
    void Impersonate(LPSTR szName,LPSTR szPass)
    {
    	HANDLE hUser = 0;
    
    	__try
    	{
    		if(!LogonUser(szName,0,szPass,
    			LOGON32_LOGON_INTERACTIVE,
    			LOGON32_PROVIDER_DEFAULT,&hUser))
    		{
    			std::cout << "Unable to logon" <<std::endl;
    			return;
    		}
    
    
    		if(!ImpersonateLoggedOnUser(hUser))
    		{
    			std::cout << "Unable to impersonate " << szName <<std::endl;
    			return;
    		}
    	}
    	__finally
    	{
    		if(hUser)CloseHandle(hUser);
    	}
    }
    But alas....you need the password of each user...not very extensible..

  5. #5
    &TH of undefined behavior Fordy's Avatar
    Join Date
    Aug 2001
    Posts
    5,793
    Woohoo!...fixed it....

    The problem is that you are barred from accessing handles to processes not created by yourself......but, with a little searching, I found that you can override this if your security token has a SeDebugPrivilege setting (there's an article on MSDN)

    So, to enable this.....in the main procedure, create a TOKEN_PRIVILEGES struct and pass it to BoostPriv (see below)...then at the end of the code, pass the same struct reference again to RestorePriv (again, below)....that will ensure that you have control over standard user created processes...


    Code:
    void BoostPriv(TOKEN_PRIVILEGES &tokPrivNorm)
    {
    	HANDLE hToken = 0;
    
    	__try
    	{
    		if(!OpenProcessToken(GetCurrentProcess(),
    			TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,&hToken))
    		{
    			std::cout << "Unable to access thread's token" << std::endl;
    			return;
    		}
    		TOKEN_PRIVILEGES tokPriv;
    		DWORD dwTokPrivSize = sizeof(TOKEN_PRIVILEGES);
    		tokPriv.PrivilegeCount = 1;
    		tokPriv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    
    		if(!LookupPrivilegeValue(NULL,SE_DEBUG_NAME, 
    			&tokPriv.Privileges[0].Luid))
    		{
    			std::cout << "Unable to lookup privilage" << std::endl;
    			return;
    		}
    
    		if (!AdjustTokenPrivileges(hToken,FALSE,&tokPriv,sizeof(tokPriv),
    			&tokPrivNorm, &dwTokPrivSize))
    		{
    			std::cout << "Unable to alter privilage" << std::endl;
    			return;
    	
    		}
    	}
    	__finally
    	{
    		if(hToken)CloseHandle(hToken);
    	}
    
    
    }
    
    void RestorePriv(TOKEN_PRIVILEGES &tokPrivNorm)
    {
    
    	HANDLE hToken = 0;
    
    	__try
    	{
    		if(!OpenProcessToken(GetCurrentProcess(),
    			TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,&hToken))
    		{
    			std::cout << "Unable to access thread's token" << std::endl;
    			return;
    		}
    
    
    		if (!AdjustTokenPrivileges(hToken,FALSE,&tokPrivNorm,
    			sizeof(tokPrivNorm),0,0))
    		{
    			std::cout << "Unable to restore privilage" << std::endl;
    			return;
    	
    		}
    	}
    	__finally
    	{
    		if(hToken)CloseHandle(hToken);
    	}
    
    
    }

  6. #6
    pronounced 'fib' FillYourBrain's Avatar
    Join Date
    Aug 2002
    Posts
    2,297
    Fordy, you're awesome as usual.

    what you're saying is that I have to set the "thread priviledge" for the app that I'm shutting down? this would enable me to see it across user logins and PostMessage to it?
    "You are stupid! You are stupid! Oh, and don't forget, you are STUPID!" - Dexter

  7. #7
    &TH of undefined behavior Fordy's Avatar
    Join Date
    Aug 2001
    Posts
    5,793
    Originally posted by FillYourBrain
    what you're saying is that I have to set the "thread priviledge" for the app that I'm shutting down? this would enable me to see it across user logins and PostMessage to it?
    Not really...you are just telling the system that the mian thread in your prog is of a sufficient priority to open handles to processes not created by your user account.... if you use the BoostPriv function that I wrote below, the main thread will be given the ability to override any restriction to this.....

    This makes sense as I can manually close any open window on my desktop whether it was created by me or by another user.......in code I just need to assert this right by raising the privalige level of my thread....

    I would stick with the PSAPI funcs I use below......they are greate to use on WinNT platforms and you dont need to bother with open windows and the like....just the process and the loaded exe...

    So, in turn you could use

    BoostPriv (my func)
    EnumProcesses (PSAPI - gives an array of PIDs to all processes)
    OpenProcess (API - hives a handle to the process from a PID)
    EnumProcessModules (PSAPI - gives array of handles to all loaded modules in a process - exe...dll..etc)
    GetModuleBaseName (PSAPI - gives the path to the executable for a loaded module - calc.exe,kernel32.dll etc - so check for the prog you want)
    TerminateProcess (API - force shutdown of a process - if it has a window or not)
    RestorePriv (my func - not critical...but makes sense to restore settings)

  8. #8
    &TH of undefined behavior Fordy's Avatar
    Join Date
    Aug 2001
    Posts
    5,793
    Oh and you might need to be admin on the system you are working on...

  9. #9
    pronounced 'fib' FillYourBrain's Avatar
    Join Date
    Aug 2002
    Posts
    2,297
    ok, well I need it to work even if I'm not logged in as an admin.

    there is the fact that the app I'm shutting down can be aware of this feature. I wonder if I can't use that to my advantage. Can the app perhaps monitor something like perhaps an ini or registry entry that will tell it to shut down? any thoughts on that?
    "You are stupid! You are stupid! Oh, and don't forget, you are STUPID!" - Dexter

  10. #10
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    >>Can the app perhaps monitor something like perhaps an ini or registry entry that will tell it to shut down?

    If the apps know about each other then you could try a broadcast msg. But I don't know how this works over multiple users.

    Intercept these in your main callback using the process ID to identify the different instances of the app.

    Code:
    //register the message
    uiBroadcastMessage = RegisterWindowMessage("NM_QUIT");
    
    //send to and from your app
    PostMessage(HWND_BROADCAST,	uiBroadcastMessage, (WPARAM) GetCurrentProcessId(), (LPARAM) uiAdditionalValue);
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 8
    Last Post: 05-07-2009, 11:31 AM
  2. Trying to Install XP over Vista with SATA HD
    By Shamino in forum Tech Board
    Replies: 2
    Last Post: 12-13-2008, 06:56 PM
  3. Need help with program
    By HAssan in forum C Programming
    Replies: 8
    Last Post: 06-10-2007, 08:05 PM
  4. Question..
    By pode in forum Windows Programming
    Replies: 12
    Last Post: 12-19-2004, 07:05 PM
  5. Windows XP regression over time
    By DavidP in forum A Brief History of Cprogramming.com
    Replies: 15
    Last Post: 12-17-2002, 10:49 AM