Προς το περιεχόμενο

Δολοφονια παραθυρου :-) [C++]


kath

Προτεινόμενες αναρτήσεις

Δημοσ.

Γεια και παλι .

Για ακομα μια φορα χρειαζομαι τις γνωσεις σας για την επιλυση ενος προβληματος.

 

Συγκεκριμενα , θελω να τερματισω μια διεργασια που τρεχει στο background.

Αυτο που ζητω , ειναι με καποιο τροπο να τερματισω την εφαρμογη χρησιμοποιωντας το proccess name και οχι με τον τιτλο παραθυρου , γιατι αλλαζει συνεχως.

 

Καμια προταση ;

 

Ευχαριστω :)

Δημοσ.

Για να διακόψεις την εκτέλεση μιας διεργασίας (process) πρέπει να καλέσεις την ομώνυμη εντολή TerminateProcess μαζί με το ανάλογο process Handle που την προσδιορίζει.

 

Τα Windows προσφέρουν ένα σύνολο εντολών (CreateToolhelp32Snapshot) με το οποίο μπορείς να εξετάσεις τις εκτελούμενες διεργασίες (Process32First & Process32Next) αναζητώντας αυτό που χρειάζεσαι.

 

Η παρακάτω ρουτίνα (Borland C/C++ Builder 2006) υλοποιεί την αναζήτηση της διεργασίας που μας ενδιαφέρει με βάση την ονομασία του αρχείου της και ύστερα ζητά από το σύστημα (δια της OpenProcess) να λάβει ένα Handle στην διεργασία που να επιτραπεί την «αίτηση διακοπής» (PROCESS_TERMINATE). Μετά απλά περνά το συγκεκριμένο Handle στην εντολή TerminateProcess η οποία διακόπτει την εκτέλεση της διεργασίας με βίαιο τρόπο.

 

>
// _KillProcess by DIRECTX (Borland C/C++ Builder 2006)

#include <stdio.h>
#include <conio.h>

#include <windows.h>
#include <tlhelp32.h>
#include <stdlib.h>

//---------------------------------------------------------------------------
BOOL	_KillProcess(char *pszProcName)
{
   // Take a snapshot of the running processes (use 9x - XP compatible API)
HANDLE	hProcSnapshot	=	CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,
													 0),
       	   hProcHandle;
PROCESSENTRY32	procEntry;
BOOL			   bTerminated	=	FALSE;
  char           szDrive[_MAX_DRIVE], szDir[_MAX_DIR],
                 szFName[_MAX_FNAME], szExt[_MAX_EXT];

if(hProcSnapshot!=INVALID_HANDLE_VALUE)
 {
     ZeroMemory(&procEntry,sizeof(procEntry));
     procEntry.dwSize  =  sizeof(procEntry);

     // Start running processes list traverse
	if(Process32First(hProcSnapshot,&procEntry))
	 {
		 do{
             // Windows 9x & Me. return full path+filename info, 2000 & XP not!
             _splitpath(procEntry.szExeFile,szDrive,szDir,szFName,szExt);

             // Did we found the expected process (file) name?
			  if(!lstrcmpi(lstrcat(szFName,szExt),pszProcName))
              {
                 // Attempt to open process for TERMINATION
  					if((hProcHandle=OpenProcess(PROCESS_TERMINATE,FALSE,
											procEntry.th32ProcessID))!=NULL)
   				 {
                           // Ask system to terminate it!
  						 bTerminated	=	TerminateProcess(hProcHandle,0);
  						 CloseHandle(hProcHandle);

  						 // We stop process list traverse on first found process instance
  						 break;
  					 }
  				  }
  			   }while(Process32Next(hProcSnapshot,&procEntry));
  		 }
  		CloseHandle(hProcSnapshot);
  	 }
      
return	bTerminated;
}

int main(int argc, char* argv[])
{
printf("%d\n",_KillProcess("NOTEPAD.EXE"));
getch();
return 0;
}

 

Υ.Γ.

Η παραπάνω ρουτίνα είναι συμβατή με όλες τις εκδόσεις των Windows αφού χρησιμοποιεί το Tool-Help32 API το οποίο είναι μερικός βέβαια συμβατό με τα MS-Windows 2000 & XP αλλά για την παρούσα ανάγκη επαρκές.

 

Ο κώδικας:

>
_splitpath(procEntry.szExeFile,szDrive,szDir,szFName,szExt);

 

Εξασφαλίζει την σωστή λειτουργεία της εντολής τόσο στα 9x & Me. όπου η Process32First & Process32Next επιστρέφουν πλήρες διαδρομής (πχ. C:\Windows\NOTEPAD.EXE) προς την εκτελούμενη διεργασία , σε αντίθεση με τα XP & 2000 που επιστρέφουν μόνο την ονομασία της (πχ. NOTEPAD.EXE)

 

Επίσης εάν υπάρχουν πολλαπλές διεργασίες με την ίδια ονομασία (multi instances) τότε κρίνεται ανεπαρκείς αφού δεν μπορεί να ξεχωρίσει το ζητούμενο ενώ την έχω ρυθμίσει ώστε να διακόπτει (εντολή break) την περαιτέρω αναζήτηση του process list με το κλείσιμο της πρώτης διεργασίας που ικανοποιεί τα κριτήρια μας.

 

Το παράδειγμα απλά κλείνει την πρώτη διεργασία με την ονομασία NOTEPAD.EXE

Δημοσ.

Μου εμφανιζει σφαλμα σε αυτο το κομματι κωδικα :

>
_splitpath(procEntry.szExeFile,&szDrive,&szDir,&szFName,&szExt);

 

30 C:\prj00sock\main.cpp cannot convert `char (*)[3]' to `char*' for argument `2' to `void _splitpath(const char*, char*, char*, char*, char*)'

Δημοσ.

Ακυρο , το διορθωσα :

>
_splitpath(procEntry.szExeFile,szDrive,szDir,szFName,szExt);

 

..Για αλλη μια φορα σ'ευχαριστω :)

Δημοσ.

Να ρωτησω κατι σχετικο - ασχετο ;

(ελπιζω να μην "κουραζω" ... αλλα αν δεν ρωτησεις δεν μαθαινεις ποτε!)

 

Με βαση τον παραπανω κωδικα , μπορω να αλλαξω την προτεραιοτητα μιας διεργασιας ; η οχι ;

Δημοσ.

Μπορείς με τις παρακάτω αλλαγές:

 

1ον) Αλλάζεις το αιτούμενο δικαίωμα της OpenProcess από PROCESS_TERMINATE σε PROCESS_SET_INFORMATION.

2ον) Αντικαθιστάς την εντολή TerminateProcess με την SetPriorityClass η οποία αλλάζει την προτεραιότητα εκτέλεσης της διεργασίας.

3ον) Ορίζεις την νέα επιθυμητή προτεραιότητα ως (από το Windows API SDK):

HIGH_PRIORITY_CLASS = υψηλή προτεραιότητα,

IDLE_PRIORITY_CLASS = χαμηλή προτεραιότητα,

NORMAL_PRIORITY_CLASS = κανονική προτεραιότητα,

REALTIME_PRIORITY_CLASS = υπερ-υψηλή προτεραιότητα (προσοχή γιατί το σύστημα μπορεί να σταματήσει να ανταποκρίνεται στα αιτήματα άλλων διεργασιών).

 

Ακολουθεί ο μετατρεμμένος κώδικας σε μορφή εντολής _SetProcPriority:

 

>
[size="4"]
// _SetProcPriority by DIRECTX (Borland C/C++ Builder 2006)

#include <stdio.h>
#include <conio.h>

#include <windows.h>
#include <tlhelp32.h>
#include <stdlib.h>

//---------------------------------------------------------------------------
BOOL	_SetProcPriority(char *pszProcName,DWORD dwNewPriority)
{
   // Take a snapshot of the running processes (use 9x - XP compatible API)
   HANDLE	hProcSnapshot	=	CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0),
       	   hProcHandle;
   PROCESSENTRY32	procEntry;
   BOOL		         bNewPriority	=	FALSE;
   char           	szDrive[_MAX_DRIVE], szDir[_MAX_DIR],
                 	szFName[_MAX_FNAME], szExt[_MAX_EXT];

   if(hProcSnapshot!=INVALID_HANDLE_VALUE)
    {
      ZeroMemory(&procEntry,sizeof(procEntry));
      procEntry.dwSize  =  sizeof(procEntry);

      // Start running processes list traverse
      if(Process32First(hProcSnapshot,&procEntry))
    {
     do{
           // Windows 9x & Me. return full path+filename info, 2000 & XP not!
           _splitpath(procEntry.szExeFile,szDrive,szDir,szFName,szExt);

           // Did we found the expected process (file) name?
         if(!lstrcmpi(lstrcat(szFName,szExt),pszProcName))
            {
              // Attempt to open process for TERMINATION    // 1.1+
  		      if((hProcHandle=OpenProcess(PROCESS_SET_INFORMATION,
				    FALSE,procEntry.th32ProcessID))!=NULL)
   	       {
                 // Set process priority class
                 bNewPriority   =  SetPriorityClass(hProcHandle,dwNewPriority);

                 CloseHandle(hProcHandle);

  		         // We stop process list traverse on first found process instance
  		         break;
  		       }
  		    }

  	    }while(Process32Next(hProcSnapshot,&procEntry));
      }
  	 CloseHandle(hProcSnapshot);
    }
  return	bNewPriority;
}

int main(int argc, char* argv[])
{
printf("%d\n",_SetProcPriority("NOTEPAD.EXE",IDLE_PRIORITY_CLASS));
getch();
return 0;
}
[/size]

 

Υ.Γ.

1ον) Η τιμή dwNewPriority της _SetProcPriority ακολουθεί τις προαναφερθείσες προτεραιότητες.

 

2ον) Το παράδειγμα αλλάζει το priority class ενός NOTEPAD instance σε “χαμηλή προτεραιότητα”.

 

3ον) Επειδή έχω ρυθμίσει διαφορετικά τα tabs στο IDE του C/C++ Builder η δομή του κώδικα χάνεται κατά την επικόλληση στο forum..

Δημοσ.

Δουλευει αψογα! κατι μαθαμε και σημερα! :)

Να'σαι καλα .... να βοηθας τον κοσμο !:)

Δημοσ.

Μια ακομα ερωτηση ( :) )...

Για να αποκρυψω ενα παραθυρο , του οποιου δεν γνωριζω τον τιτλο.

Πως μπορω να το αποκρυψω ? ( ξερω το ονομα της διεργασιας).

Δοκιμασα αυτο:

HWND con;

con = FindWindow("hproc00", NULL);

ShowWindow(con, SW_HIDE);

Αλλα δεν δουλευει

Δημοσ.

Εάν δεν γνωρίζεις τον τίτλο του παραθύρου (Window Caption) τότε μπορείς να δοκιμάσεις τον εντοπισμό του με βάση το Class του, με την βοήθεια της FindWindow ή FindWindowEx. Όμως οι συγκεκριμένες ρουτίνες όπως έχω εξηγήσει σε παλαιότερο θέμα, δεν λειτουργούν σωστά σε περιπτώσεις πολλαπλών instances όπου υπάρχουν δηλαδή πολλά παράθυρα με τα ίδια κριτήρια αναζήτησης ή με ιδιόρρυθμα window visibility flags τα οποία αφορούν το Z-Order (πχ. παράθυρα on-top).

 

Τώρα όσον αφορά την περίπτωση σου, από την στιγμή που δεν γνωρίζεις τον τίτλο του παραθύρου της εφαρμογής, έγραψα μια νέα ρουτίνα (_ProcShowWindow) που απλά αλλάζει το visibility state όλων των top-level (parent αν θες) παραθύρων της συγκεκριμένης διεργασίας αφού δεν γνωρίζω κανένα άλλο κριτήριο για αυτά.

 

Ο εντοπισμός του process id που μας ενδιαφέρει γίνεται με βάση τις προηγηθείσες ρουτίνες (_SetProcPriority & _KillProcess) κατάλληλα προσαρμοσμένες (_GetProcID) ώστε να επιστρέφουν μόνο το process id (dwPID) με βάση το όνομα της διεργασίας.

 

Ο εντοπισμός όλων των top-level παραθύρων γίνεται με την βοήθεια της ρουτίνας _ProcShowWindow η οποία είναι συμβατή με τις παραμέτρους της ShowWindow και στηρίζεται στην Windows API function EnumWindows η οποία ορίζει ένα CALLBACK (EWProc) το οποίο διασχίζει την λίστα των διαθέσιμων παραθύρων.

 

Όταν το CALLBACK function EWProc εντοπίσει πως το process id του παράθυρου (GetWindowThreadID) ταιριάζει με αυτό που μας ενδιαφέρει (το περνάμε δια της lParam) τότε αλλάζει το visibility state του με κλήση στην ShowWindowAsync η οποία προτιμάται από την ShowWindow διότι αφορά διαφορετική διεργασία και δεν μπλοκάρει την εκτέλεση της εφαρμογής μας.

 

Τέλος η _bSomethingFound τίθεται σε TRUE με την πρώτη κλήση για αλλαγή του visibility state κάποιου παραθύρου που ταιριάζει με το process id που μας ενδιαφέρει.

 

>
//-_ProcShowWindow (C) BY DIRECTX---------------------------------------------
#include <stdio.h>
#include <conio.h>

#include <windows.h>
#include <tlhelp32.h>
#include <stdlib.h>
#pragma hdrstop

//---------------------------------------------------------------------------
int   _nCmdShow;
BOOL  _bSomethingFound;
//---------------------------------------------------------------------------
DWORD _GetProcID(char *pszProcName)
{
   // Take a snapshot of the running processes (use 9x - XP compatible API)
   HANDLE	hProcSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0),
       	      hProcHandle;
   PROCESSENTRY32 procEntry;
   char            szDrive[_MAX_DRIVE], szDir[_MAX_DIR],
                     szFName[_MAX_FNAME], szExt[_MAX_EXT];

   if(hProcSnapshot!=INVALID_HANDLE_VALUE)
    {
       ZeroMemory(&procEntry,sizeof(procEntry));
       procEntry.dwSize  =  sizeof(procEntry);

       // Start running processes list traverse
if(Process32First(hProcSnapshot,&procEntry))
 {
    do{
                  // Windows 9x & Me. return full path+filename info, 2000 & XP not!
                  _splitpath(procEntry.szExeFile,szDrive,szDir,szFName,szExt);

                  // Did we found the expected process (file) name?
           if(!lstrcmpi(lstrcat(szFName,szExt),pszProcName))
                   return   procEntry.th32ProcessID;   // Return Process ID

              }while(Process32Next(hProcSnapshot,&procEntry));
        }
  	CloseHandle(hProcSnapshot);
    }
  return	0;
}
//---------------------------------------------------------------------------
BOOL  CALLBACK EWProc(HWND hWnd,LPARAM lParam)
{
  // Traverse all top-level windows 
  DWORD dwPID;

  GetWindowThreadProcessId(hWnd,&dwPID);
  if(dwPID==lParam)
   {
     // Process IDs match - apply _nCmdShow to window!
     ShowWindowAsync(hWnd,_nCmdShow);
     _bSomethingFound  =  TRUE;      
   }

  // Continue list traverse
  return   TRUE;
}
//---------------------------------------------------------------------------
BOOL  _ProcShowWindow(char *pszProcName,int nCmdShow)
{
  // Find pszProcName ID
  _bSomethingFound  =  FALSE;
  DWORD dwPID       =  _GetProcID(pszProcName);
  _nCmdShow         =  nCmdShow;

  // Did _GetProcID succeeded?
  if(dwPID)
   EnumWindows((WNDENUMPROC)EWProc,(LPARAM)dwPID);

  // Did we found anything?
  return   _bSomethingFound;
}


#pragma argsused
int main(int argc, char* argv[])
{
  printf("%d\n",_ProcShowWindow("NOTEPAD.EXE",SW_HIDE));
  getch();
  
  return 0;
}
//---------------------------------------------------------------------------

 

Υ.Γ.

1ον)Ο εντοπισμός του process id με βάση το όνομα της διεργασίας επιστρέφει το πρώτο instance οπότε κρίνεται ανεπαρκείς για πολλαπλές διεργασίες με την ίδια ονομασία (multi instances) παρʼ όλα αυτά με ορισμένες αλλαγές στην δομή του κώδικα αυτό διορθώνεται.

 

2ον)Το παράδειγμα κρύβει το παράθυρο ενός NOTEPAD instance.

Δημοσ.

Υπαρχει ενα μικρο προβλημα ομως,

οταν κανω εμφανιση ενος παραθυρου , εμφανιζονται και καποιες "κρυφες" φορμες.Γιατι ;

Αρχειοθετημένο

Αυτό το θέμα έχει αρχειοθετηθεί και είναι κλειστό για περαιτέρω απαντήσεις.

  • Δημιουργία νέου...