🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: borland.public.cppbuilder.nativeapi
Article #4914

Re: Spawning and controlling

#4914
From: Denville Longhurst
Date: Sat, 12 Nov 2005 10:17
595 lines
17042 bytes
Good grief !!

Well, thanks for that, I'll work my way through it

Most sincerely,
Denville.

"Michael Gillen" <michael@gillenconsultinggroup-nospam.com> wrote in message 
news:4374e9ea@newsgroups.borland.com...
> Denville Longhurst wrote:
>
>> Hi
>>
>> From within my application, I would like to spawn an arbitrary third 
>> party application (say
>> foo.exe) in the following way:
>>
>> 1. Check whether foo.exe is already running so that I don't attempt to 
>> run it twice;
>> 2. Spawn foo.exe
>> 3. Make foo's parent my application, so that it displays within one of my 
>> windows;
>> 4. From my app, terminate foo.exe
>>
>> I can probably cope with (3), but I am at a loss about how to do the 
>> rest.
>
>
> This bunch of code should give you the needed tools. This requires Win2000 
> or better, however,
> since I never implemented backwards compatability.
>
>
> /*********** PROCCONTROL.H *************/
> #ifndef ProcControlH
> #define ProcControlH
>
> #include <vcl.h>
> #include <Wbemcli.h>
> #include <tlhelp32.h>
>
> #define TA_FAILED 0
> #define TA_SUCCESS_CLEAN 1
> #define TA_SUCCESS_KILL 2
> #define TA_SUCCESS_16 3
>
>
> int __fastcall TerminateAppByName(AnsiString ExeName, int timeout = 2000);
> bool __fastcall IsProcessRunning(AnsiString ExeName);
> AnsiString __fastcall GetProcessFilePath(AnsiString ExeName);
> HWND WINAPI WindowFromFileName(AnsiString ExeName);
> void __fastcall LaunchApplication(AnsiString ExeName, bool wait = false);
>
>
> //---------------------------------------------------------------------------
> #endif
>
> /*********** PROCCONTROL.CPP *************/
> #include "ProcControl.h"
> #include "utilcls.h"
>
> IWbemLocator *pLoc;
> IWbemServices *pSvc;
> IEnumWbemClassObject *pEnum;
> IWbemClassObject *pProcesses;
>
> typedef struct
> {
> DWORD   dwID ;
> DWORD   dwThread ;
> } TERMINFO ;
>
> // Declare Callback Enum Functions.
> BOOL CALLBACK TerminateAppEnum( HWND hwnd, LPARAM lParam ) ;
> BOOL CALLBACK Terminate16AppEnum( HWND hwnd, LPARAM lParam ) ;
>
>
> DWORD WINAPI TerminateApp( DWORD dwPID, DWORD dwTimeout ) ;
> DWORD WINAPI Terminate16App( DWORD dwPID, DWORD dwThread, WORD w16Task, 
> DWORD dwTimeout );
>
> //---------------------------------------------------------------------------
> // IsProgramRunning(AnsiString exefile)
> // Determine if program 'exefile' is running.
> //---------------------------------------------------------------------------
> bool __fastcall IsProcessRunning(AnsiString ExeName)
> {
> HANDLE hSnap;
> PROCESSENTRY32 process;
> BOOL f;
>
> hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
> if ( hSnap == NULL )
> return false; // NOT RUNNING!!
>
> process.dwSize = sizeof(PROCESSENTRY32);
> f = Process32First(hSnap, &process);
>
> while ( f )
> {
> AnsiString file(ExtractFileName(process.szExeFile));
> if ( file.AnsiCompareIC(ExeName) == 0 )
> {
> CloseHandle(hSnap);
> return true; // PROGRAM IS RUNNING!
> }
> f = Process32Next(hSnap, &process);
> }
> CloseHandle(hSnap);
> return false; // NOT RUNNING!!
> }
>
> //---------------------------------------------------------------------------
> // IsProgramRunning(AnsiString exefile)
> // Determine if program 'exefile' is running.
> // Return the full path to the executable if it IS running, else NULL.
> //---------------------------------------------------------------------------
> int __fastcall TerminateAppByName(AnsiString ExeName, int timeout)
> {
> DWORD dwID = 0;
> GetWindowThreadProcessId(WindowFromFileName(ExeName), &dwID) ;
> int ret = TerminateApp( dwID, timeout );
>  return ret;
> /*
> if(ret == TA_FAILED)
>   OutputDebugString("The shutdown failed");
> if(ret == TA_SUCCESS_CLEAN)
>   OutputDebugString("The process was shutdown using WM_CLOSE.");
> if(ret == TA_SUCCESS_KILL)
>  OutputDebugString("The process was shut down with TerminateProcess().");
> */
> }
>
> //---------------------------------------------------------------------------
> bool __fastcall InitCom()
> {
> HRESULT hres;
>
> hres = CoInitializeEx(0, COINIT_MULTITHREADED); //Initialize COM.
>
> if ( FAILED(hres) )
> {
> ShowMessage("Failed to initialize COM library. Error code = 
> "+IntToHex((int)hres,8));
> return false;
> }
>
> hres =  CoInitializeSecurity(
> NULL, // security descriptor
> -1, // use this simple setting
> NULL, // use this simple setting
> NULL, // reserved
> RPC_C_AUTHN_LEVEL_CONNECT, // Windows NT 4/Windows 2000 authentication 
> level
> RPC_C_IMP_LEVEL_IMPERSONATE, // impersonation level
> NULL, // use this simple setting
> EOAC_NONE, // no special capabilities
> 0); // reserved
>
> if ( FAILED(hres) )
> {
> ShowMessage("Failed to initialize security. Error code = 
> "+IntToHex((int)hres,8));
> CoUninitialize();
> return false;
> }
> return true;
> }
>
> //---------------------------------------------------------------------------
> AnsiString __fastcall GetProcessFilePath(AnsiString ExeName)
> {
> AnsiString ExePath = NULL;
>
> HRESULT hres;
> pLoc = 0;
>
> //IWbemLocator interface for obtaining the initial namespace pointer to
> //the Windows Management on a particular host computer.
> hres = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, 
> IID_IWbemLocator, (LPVOID *)
> &pLoc);
>
> if ( FAILED(hres) )
> {
> ShowMessage("Failed to create IWbemLocator object. Err code = 
> "+IntToHex((int)hres,8));
> CoUninitialize();
> return NULL;
> }
>
> pSvc = 0;
> hres = pLoc->ConnectServer(L"\\\\.\\root\\cimv2", NULL, NULL, 0, NULL, 0, 
> 0, &pSvc);
>
> if ( FAILED(hres) )
> {
> ShowMessage("Could not connect. Error code = "+IntToHex((int)hres,8));
> CoUninitialize();
> return NULL;
> }
>
> // Set the proxy so that impersonation of the client occurs.
> hres = CoSetProxyBlanket(pSvc,
> RPC_C_AUTHN_WINNT, // NTLM authentication service
> RPC_C_AUTHZ_NONE, // default authorization service...
> NULL, // no mutual authentication
> RPC_C_AUTHN_LEVEL_CONNECT, // authentication level
> RPC_C_IMP_LEVEL_IMPERSONATE, // impersonation level
> NULL, // use current token
> EOAC_NONE); // no special capabilities
>
>
>
> if ( FAILED(hres) )
> {
> ShowMessage("Could not set proxy blanket. Error code = 
> "+IntToHex((int)hres,8));
> pSvc->Release();
> pLoc->Release();
> CoUninitialize();
> return NULL;
> }
>
> BSTR className = SysAllocString(L"Win32_Process");
>
> hres = pSvc->GetObject(className, 0, NULL, &pProcesses, NULL );
> //Retrieves an class object.
>
> ULONG puReturned;
>
> //Create instance for enumeration ports
>
> hres=pSvc->CreateInstanceEnum( className, NULL, NULL, &pEnum );
>
> //no need in variable className now.
> SysFreeString(className);
>
> if ( hres != 0 )
> {
> ShowMessage("Error");
> return NULL;
> }
>
> // Retrieve the objects in the result set.
> for ( ;; )
> {
>
> ULONG uReturned = 0;
>
> hres = pEnum->Next(
> WBEM_INFINITE, // Time out
> 1, // One object
> &pProcesses,
> &uReturned
> );
>
> if ( uReturned == 0 )
> {
> break;
> }
>
> IWbemClassObject *pObj1;
>
> VARIANT Val;
> VARIANT Val1;
> VARIANT Val2;
> VARIANT Val3;
> VariantInit(&Val);
> VariantInit(&Val1);
> VariantInit(&Val2);
> VariantInit(&Val3);
>
> CIMTYPE pvtType;
> BSTR Name1 = SysAllocString(L"ExecutablePath");
> BSTR Name2 = SysAllocString(L"Name");
> BSTR Name3 = SysAllocString(L"Handle");
> LPSTR PathToProcess1=0;
> LPSTR NameProc1=0;
> LPSTR Handle1=0;
>
>
> hres=pProcesses->Get(Name1,0,&Val1,&pvtType,NULL);
>
> if ( Val1.vt == VT_NULL )
> PathToProcess1="UNKNOWN";
> else
> PathToProcess1=WideToAnsi(Val1.bstrVal);
>
>
> hres=pProcesses->Get(Name2,0,&Val2,&pvtType,NULL);
> if ( Val2.vt == VT_NULL )
> NameProc1="UNKNOWN";
> else
> NameProc1=WideToAnsi(Val2.bstrVal);
>
> hres=pProcesses->Get(Name3,0,&Val3,&pvtType,NULL);
> if ( Val3.vt == VT_NULL )
> continue;
> else
> Handle1=WideToAnsi(Val3.bstrVal);
>
> SysFreeString(Name1);
> SysFreeString(Name2);
> SysFreeString(Name3);
> VariantClear(&Val);
> VariantClear(&Val1);
> VariantClear(&Val2);
> VariantClear(&Val3);
>
> if ( !stricmp(NameProc1, ExeName.c_str()) )
> ExePath = PathToProcess1;
>
> if ( Handle1 )
> delete []Handle1;
> if ( PathToProcess1 && (AnsiString(PathToProcess1) != "UNKNOWN") )
> delete []PathToProcess1;
> if ( NameProc1 )
> delete []NameProc1;
>
> }
> return ExePath;
> }
>
> /*-------------------------------------------------------------
> BaseFileNamePtr(const char *full_name)
>
> Get the address of the base file name
> from a string which may contain a path
>
> Returns a pointer to the base file name
>
> Calling parameters
>   full_name  the name of the file
>
> Win API functions used
>   none
>
> Other functions used
>   strrchr
>
> Globals and constants used
>   none
> -------------------------------------------------------------*/
> static char *WINAPI BaseFileNamePtr(const char *full_name)
> {
> char *p = strrchr((char *) full_name, '\\');
>
> if ( p )
> {
> ++p;
> } else
> {
> p = (char *) full_name;
> }
>
> return p;
> }
> //---------------------------------------------------------------------------
>
> //-------------------------------------------------------------
> // ProcIDOrHwnd is a union used for communication
> // with the Enum Windows procedure
> //-------------------------------------------------------------
> union ProcIDOrHwnd
> {
> DWORD proc_id;
> HWND  hwnd;
> };
>
> /*-------------------------------------------------------------
> EWProc(HWND hwnd, LPARAM l)
>
> Service procedure for an EnumWindows call
> Compare the process id for the owner of the
> window to that passed by the caller and
> if they match, save the window handle in the
> union whose address is the calling parameter
>
> Calling parameters
>   hwnd  handle of a window that was found
>     by the EnumWindows function
>   l     address of a ProcIDOrHwnd union
>     which contains the process id of the
>     window to be found
>
> On return the union's hwnd member will be the
> handle of the found window.  If none was found
> then it will be the process id.
>
> Win API functions used
>   GetWindowThreadProcessId
>
> Other functions used
>   none
>
> Globals and constants used
>   none
> -------------------------------------------------------------*/
> static BOOL EWProc(HWND hwnd, LPARAM l)
> {
> DWORD   proc_id;
> ProcIDOrHwnd *pih = reinterpret_cast<ProcIDOrHwnd*>(l);
>
> GetWindowThreadProcessId(hwnd, &proc_id);
>
> if ( proc_id == pih->proc_id )
> {
> pih->hwnd = hwnd;
> return FALSE;
> }
>
> return TRUE;
> }
> /*---------------------------------------------------------------------------
> WindowFromFile(const char *file_name)
>
> Find a window which was created by a program
> whose file name is given
>
> Calling arguments
>   file_name  The name of the file. It may
> contain a path, but the path
> part is not used.
>
> Returns the HWND of the window which was found
> or NULL if no window was found
>
> Windows API functions used
>   CreateToolhelp32Snapshot
>   Process32First
>   Process32Next
>   CloseHandle
>   EnumWindows
>
> Other functions used
>   BaseFileNamePtr
>   stricmp
>
> Globals and constants used
>   none
> -------------------------------------------------------------*/
> HWND WINAPI WindowFromFileName(AnsiString ExeName)
> {
> HWND   found_hwnd = NULL;
> HANDLE snap_hand =
> CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
>
> if ( (int) snap_hand != -1 )
> {
> DWORD    proc_id = 0;
> PROCESSENTRY32 pe32;
> char    *base_file_name = BaseFileNamePtr(ExeName.c_str());
> OutputDebugString(base_file_name);
>
> pe32.dwSize = sizeof(pe32);
>
> // cycle through each process
> if ( Process32First(snap_hand, &pe32) )
> {
> do
> {
> char *base_name = BaseFileNamePtr(pe32.szExeFile);
>
> // if the process' file name is the same capture
> // the process id and break out of the loop
> if ( !stricmp(base_file_name, base_name) )
> {
> proc_id = pe32.th32ProcessID;
> break;
> }
> } while ( Process32Next(snap_hand, &pe32) );
>
> CloseHandle(snap_hand);
> }
>
> // if a process id was found
> if ( proc_id )
> {
> ProcIDOrHwnd pih;
> pih.proc_id = proc_id;
> // find a window owned by that process
> EnumWindows((WNDENUMPROC)(EWProc), reinterpret_cast<LPARAM>(&pih));
>
> // if a window was found
> if ( pih.proc_id != proc_id )
> {
> found_hwnd = pih.hwnd; // save the window handle to return to caller
> }
> }
> }
> return found_hwnd;
> }
> //---------------------------------------------------------------------------
> void __fastcall LaunchApplication(AnsiString ExeName, bool wait)
> {
> String CmdLine = ExeName;
> if ( !FileExists(CmdLine) )
> {
> MessageDlg(CmdLine +AnsiString(" does not exist!"), mtError, 
> TMsgDlgButtons() << mbOK, 0);
> return;
> }
>
> Application->ProcessMessages();
>
> // initialize STARTUPINFO struct
> STARTUPINFO si;
> memset(&si, 0, sizeof(STARTUPINFO));
> si.cb = sizeof(STARTUPINFO);
> si.dwFlags = STARTF_USESHOWWINDOW;
> si.wShowWindow = SW_SHOWNORMAL;
> PROCESS_INFORMATION ProcessInfo;
> if ( CreateProcess
> (
> NULL, // pointer to name of executable module
> CmdLine.c_str(), // pointer to command line string
> NULL, // pointer to process security attributes
> NULL, // pointer to thread security attributes
> true, // handle inheritance flag
> NORMAL_PRIORITY_CLASS, // creation flags
> NULL, // pointer to new environment block
> ExtractFilePath(Application->ExeName).c_str(), // pointer to current 
> directory name
> &si, // pointer to STARTUPINFO
> &ProcessInfo // pointer to PROCESS_INFORMATION
> ) )
> { // body of the if...
> if ( wait )
> WaitForSingleObject(ProcessInfo.hProcess, 20000); // Wait for it to be 
> ready
> Application->ProcessMessages();
> CloseHandle(ProcessInfo.hProcess); // done with these
> CloseHandle(ProcessInfo.hThread);
> }
> }
> //---------------------------------------------------------------------------
>
> //---------------------------------------------------------------------------
> BOOL CALLBACK TerminateAppEnum( HWND hwnd, LPARAM lParam )
> {
> DWORD dwID ;
>
> GetWindowThreadProcessId(hwnd, &dwID) ;
>
> if ( dwID == (DWORD)lParam )
> {
> PostMessage(hwnd, WM_CLOSE, 0, 0) ;
> }
>
> return TRUE ;
> }
> /*----------------------------------------------------------------
> DWORD WINAPI TerminateApp( DWORD dwPID, DWORD dwTimeout )
>
> Purpose: Shut down a 32-Bit Process (or 16-bit process under Win95)
> Parameters: dwPID Process ID of the process to shut down.
> dwTimeout Wait time in milliseconds before shutting down process.
> Return Value:
> TA_FAILED - If the shutdown failed.
> TA_SUCCESS_CLEAN - If the process was shutdown using WM_CLOSE.
> TA_SUCCESS_KILL - if the process was shut down with TerminateProcess().
> NOTE: See header for these defines.
> ---------------------------------------------------------------------------*/
> DWORD WINAPI TerminateApp( DWORD dwPID, DWORD dwTimeout )
> {
> HANDLE hProc ;
> DWORD dwRet ;
>
> // If we can't open the process with PROCESS_TERMINATE rights,
> // then we give up immediately.
> hProc = OpenProcess(SYNCHRONIZE|PROCESS_TERMINATE, FALSE, dwPID);
>
> if ( hProc == NULL )
> {
> return TA_FAILED ;
> }
>
> // TerminateAppEnum() posts WM_CLOSE to all windows whose PID
> // matches your process's.
> EnumWindows((WNDENUMPROC)TerminateAppEnum, (LPARAM) dwPID) ;
>
> // Wait on the handle. If it signals, great. If it times out,
> // then you kill it.
> if ( WaitForSingleObject(hProc, dwTimeout)!=WAIT_OBJECT_0 )
> dwRet=(TerminateProcess(hProc,0)?TA_SUCCESS_KILL:TA_FAILED);
> else
> dwRet = TA_SUCCESS_CLEAN ;
> CloseHandle(hProc);
> return dwRet ;
> }
> //---------------------------------------------------------------------------
>
> -- 
> -Michael Gillen 
Technical Details
Message-ID: <4375c132@newsgroups.borland.com>
Path: arc1-ca.pugleaf.net!g2news1.google.com!news3.google.com!news.glorb.com!npeer.de.kpn-eurorings.net!news-out.newsgroups.com!propagator2-sterling.newsfeeds.com!in.nntp.be!caladan.landsraad.net!newsgroups.borland.com!not-for-mail
References: <4374b248$1@newsgroups.borland.com> <4374e9ea@newsgroups.borland.com>

Show Full Headers
Complete Article Headers
X-Google-Thread: 10cc67,d85ed3b722a8f188
X-Google-Attributes: gid10cc67,public
X-Google-Language: ENGLISH,ASCII-7-bit
From: "Denville Longhurst" <Denville@metco.co.uk>
Newsgroups: borland.public.cppbuilder.nativeapi
References:  <4374b248$1@newsgroups.borland.com> <4374e9ea@newsgroups.borland.com>
Subject: Re: Spawning and controlling
Date: Sat, 12 Nov 2005 10:17:55 -0000
Lines: 597
X-Priority: 3
X-MSMail-Priority: Normal
X-Newsreader: Microsoft Outlook Express 6.00.2900.2180
X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.2180
X-RFC2646: Format=Flowed; Original
NNTP-Posting-Host: 80.0.6.88
Message-ID: <4375c132@newsgroups.borland.com>
X-Trace: newsgroups.borland.com 1131790642 80.0.6.88 (12 Nov 2005 02:17:22 -0700)
Path: arc1-ca.pugleaf.net!g2news1.google.com!news3.google.com!news.glorb.com!npeer.de.kpn-eurorings.net!news-out.newsgroups.com!propagator2-sterling.newsfeeds.com!in.nntp.be!caladan.landsraad.net!newsgroups.borland.com!not-for-mail