How to Get Hwnd of Window Opened by Shellexecuteex.. Hprocess

How to get hWnd of window opened by ShellExecuteEx.. hProcess?

First use WaitForInputIdle to pause your program until the application has started and is waiting for user input (the main window should have been created by then), then use EnumWindows and GetWindowThreadProcessId to determine which windows in the system belong to the created process.

For example:

struct ProcessWindowsInfo
{
DWORD ProcessID;
std::vector<HWND> Windows;

ProcessWindowsInfo( DWORD const AProcessID )
: ProcessID( AProcessID )
{
}
};

BOOL __stdcall EnumProcessWindowsProc( HWND hwnd, LPARAM lParam )
{
ProcessWindowsInfo *Info = reinterpret_cast<ProcessWindowsInfo*>( lParam );
DWORD WindowProcessID;

GetWindowThreadProcessId( hwnd, &WindowProcessID );

if( WindowProcessID == Info->ProcessID )
Info->Windows.push_back( hwnd );

return true;
}

....

if( ShellExecuteEx(&sei) )
{
WaitForInputIdle( sei.hProcess, INFINITE );

ProcessWindowsInfo Info( GetProcessId( sei.hProcess ) );

EnumWindows( (WNDENUMPROC)EnumProcessWindowsProc,
reinterpret_cast<LPARAM>( &Info ) );

// Use Info.Windows.....
}

Winapi ShellExecuteEx does not opening the file

The std::wstring returned by stringToLPCTSTR() are temporaries which you use to assign the LPCTSTR members of the struct SHELLEXECUTEINFOW. This means the pointer returned by the respective calls to c_str() may no longer be valid at the time you call ShellExecuteEx(). You need to find a different solution for this, e.g. by using local variables for the std::wstring, but as long as you are only using string literals, you can just do

sei.lpVerb = L"open";
sei.lpFile = L"D:\\file.txt";
sei.lpDirectory = L"D:\\";

ShellExecuteEx and WaitForSingleObject paint corruption to window under

You're not processing any window messages during WaitForSingleObject.

Re the difference between Windows XP and Windows 7, the Desktop Window Manager technology in Windows 7 was introduced with Windows Vista, and was not available in Windows XP. Essentially it provides a layer of indirection between each app's painting actions and the result on screen.

A reasonable way to launch and wait for a program is to disable the main window the window's user interface parts and then poll the program's exit status in a peek-message loop.


Example, except that it uses CreateProcess (I coded it up without remembering to check the question, and now it's pretty late in the evening, but better with imperfect help than no help, I think):

#include <windows.h>    // UNICODE, NOMINMAX, STRICT, WIN32_LEAN_AND_MEAN
#include <windowsx.h> // Message cracker macros, e.g. HANDLE_WM_DESTROY

#include <assert.h>
#include <stdexcept>
#include <string>
using namespace std;

auto hopefully( bool const condition ) -> bool { return condition; }
auto fail( string const& s ) -> bool { throw runtime_error( s ); }

struct Window_class_id
{
ATOM value;
auto as_pointer() const -> wchar_t const* { return MAKEINTATOM( value ); }
};

auto get_message( MSG& m )
-> bool
{
int const result = GetMessage( &m, 0, 0, 0 );
hopefully( result != -1 )
|| fail( "GetMessage failed" );
return !!result;
}

auto peek_message( MSG& m )
-> bool
{
int const result = PeekMessage( &m, 0, 0, 0, TRUE );
hopefully( result != -1 )
|| fail( "PeekMessage failed" );
return !!result;
}

void empty_message_queue()
{
MSG m;
while( peek_message( m ) )
{
TranslateMessage( &m );
DispatchMessage( &m );
}
}

auto dispatch_messages()
-> DWORD // Exit code from WM_QUIT
{
MSG msg;
while( get_message( msg ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
assert( msg.message == WM_QUIT );
return msg.wParam;
}

auto run( wchar_t const command[] )
-> HANDLE
{
wstring commandline = command;
hopefully( commandline.length() > 0 )
|| fail( "run: Empty command line" );
STARTUPINFO in_params = { sizeof( STARTUPINFO ) };
PROCESS_INFORMATION out_params = {};

bool const success = !!CreateProcess(
nullptr, // app name
&commandline[0],
nullptr, // process attributes
nullptr, // thread attributes
false, // inherit handles
0, // creation flags
nullptr, // environment block
nullptr, // current directory
&in_params, // startup info
&out_params // process info
);
hopefully( success )
|| fail( "run: CreateProcess failed" );
CloseHandle( out_params.hThread );
return out_params.hProcess;
}

namespace main_window
{
namespace command_id {
int const run_fun = 101;
} // namespace command

namespace run_button {
int const id = command_id::run_fun;
} // namespace run_button

namespace command {
void run_fun( HWND const window )
{
EnableWindow( GetDlgItem( window, run_button::id ), false );
UpdateWindow( window );
empty_message_queue();
HANDLE const process = run( L"notepad" );
for( ;; )
{
DWORD const result = WaitForSingleObject( process, 100 );
if( result == WAIT_OBJECT_0 )
{
break;
}
empty_message_queue();
}
CloseHandle( process );
EnableWindow( GetDlgItem( window, run_button::id ), true );
}
} // namespace command

void on_command( HWND const window, int const id )
{
switch( id )
{
case command_id::run_fun: return command::run_fun( window );
}
}

void on_wm_command(
HWND const window,
int const control_or_command_id,
HWND const control,
UINT const notification_code
)
{
if( control == 0 )
{
int const command_id = control_or_command_id;
on_command( window, command_id );
}
else
{
int const control_id = control_or_command_id;
switch( control_id )
{
case run_button::id:
if( notification_code == BN_CLICKED )
{
int const command_id = control_id;
on_command( window, command_id );
}
}
}
}

auto on_wm_create( HWND const window, CREATESTRUCT const* const p_params )
-> bool // `true` if creation succeeded.
{
(void) p_params;
HWND const button_handle = CreateWindow(
L"button", L"Run the fun", WS_CHILD | WS_VISIBLE,
10, 10, 120, 26,
window, // parent
reinterpret_cast<HMENU>( run_button::id ),
GetModuleHandle( 0 ),
0 // lpParam
);
return (button_handle != 0);
}

void on_wm_destroy( HWND const window )
{
(void) window;
PostQuitMessage( 0 );
}

auto CALLBACK message_handler(
HWND const window,
UINT const message_id,
WPARAM const word_param,
LPARAM const long_param
)
-> LRESULT
{
switch( message_id )
{
case WM_COMMAND: return HANDLE_WM_COMMAND(
window, word_param, long_param, on_wm_command );
case WM_CREATE: return HANDLE_WM_CREATE(
window, word_param, long_param, on_wm_create );
case WM_DESTROY: return HANDLE_WM_DESTROY(
window, word_param, long_param, on_wm_destroy );
}
return DefWindowProc( window, message_id, word_param, long_param );
}
} // namespace main_window

auto register_window_class()
-> Window_class_id
{
WNDCLASS params = {};
params.style = CS_DBLCLKS;
params.lpfnWndProc = main_window::message_handler;
params.hInstance = GetModuleHandle( 0 );
params.hIcon = LoadIcon( 0, IDI_APPLICATION );
params.hCursor = LoadCursor( 0, IDC_ARROW );
params.hbrBackground = reinterpret_cast<HBRUSH>( COLOR_WINDOW );
params.lpszClassName = L"MainWindow_class";

ATOM const id = RegisterClass( ¶ms );
hopefully( id != 0 )
|| fail( "RegisterClass failed" );
return {id};
}

auto create_window( Window_class_id const& class_id )
-> HWND
{
HWND const handle = CreateWindow(
class_id.as_pointer(),
L"Fun run",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 380, 221, // x, y, w, h
0, 0, // parent, menu
GetModuleHandle( 0 ),
0 // lpParam
);
hopefully( handle != 0 )
|| fail( "CreateWindow failed" );
return handle;
}

void cpp_main()
{
Window_class_id const class_id = register_window_class();
HWND const window = create_window( class_id );
ShowWindow( window, SW_SHOWDEFAULT );
int const exit_code = static_cast<int>( dispatch_messages() );
hopefully( exit_code == 0 )
|| fail( "WM_QUIT indicated failure" );
}

auto main() -> int
{
try{ cpp_main(); } catch( ... ) { return E_FAIL; }
return 0;
}

How to get the Handle that is executed in winexec or shellexecute?

There is no general way to get "the" window handle of an application because there's no guarantee that any program has one window handle. A program may have many top-level handles (i.e., Microsoft Word, one for each document), or it may have no windows at all. You might question what you really need the window handle for; there could be better ways of doing whatever it is you're trying to do that don't require any specific window handle.

WinExec (which has been deprecated for nearly 15 years, so you should seriously consider not using it anymore) and ShellExecute return absolutely no information about the programs they start, if indeed they start any program at all. (ShellExecute might use DDE to send a command to an already-running instance of the application.) And if they start an application, it might finish running before your program gets to run anymore.

You can use CreateProcess or ShellExecuteEx instead. If they start a program, they will give you a process handle representing the program they started. You can use that to help you get additional information about the program, such as a list of its windows. Don't bother with FindWindow; the caption and window class aren't guaranteed to be unique; a program might use the same class name for many different windows, and multiple instances of a program would use the same class name without much way to select the one you really want.

EnumWindows is a function you can use to get a list of candidate window handles. You give it a function pointer, and it will call that function once for each top-level window on the desktop. You'll need a way of telling it which process you're interested in, and a way for it to return a list of results. The function only accepts one parameter, so the parameter will have to be a pointer to a structure that holds more information:

type
PWindowSearch = ^TWindowSearch;
TWindowSearch = record
TargetProcessID: DWord;
ResultList: TWndList;
end;

TWndList is a type I made up to hold a list of HWnd values. If you have Delphi 2009 or later, you could use TList<HWnd>; for earlier versions, you could use a TList descendant or whatever else you choose.

CreateProcess will tell you the new process ID in the dwProcessID member of the TProcessInformation record it fills; ShellExecuteEx only returns a process handle, so use GetProcessID on that. The window-enumerating function needs a callback function matching this signature:

function SelectWindowByProcessID(Wnd: HWnd; Param: LParam): Bool; stdcall;

You can use EnumWindows to get a handle list like this:

function GetWindowListByProcessID(pid: DWord): TWndList;
var
SearchRec: TWindowSearch;
begin
Result := TWndList.Create;
try
SearchRec.TargetProcessID := pid;
SearchRec.ResultList := Result;
Win32Check(EnumWindows(SelectWindowByProcessID, LParam(@SearchRec)));
except
Result.Free;
raise;
end;
end;

You'll implement the callback function like this:

function SelectWindowByProcessID(Wnd: HWnd; Param: LParam): Bool; stdcall;
var
SearchRec: PWindowSearch;
WindowPid: DWord;
begin
SearchRec := PWindowSearch(Param);
Assert(Assigned(SearchRec));
GetWindowThreadProcessID(Wnd, WindowPid);
if WindowPid = SearchRec.TargetProcessID then
SearchRec.ResultList.Add(Wnd);
Result := True;
end;

Once you have the list, you can inspect other attributes of the window to determine which ones are really the ones you want. You might determine it by window title or class name, or perhaps by the other controls that are one that window.

When you're finished using the process handle, make sure you call CloseHandle on it so the OS can clean up the process's bookkeeping information.

HINSTANCE to HWND

you're right, you need to enum your windows

this question will help you further

Get hwnd by process id c++

HWND g_HWND=NULL;
BOOL CALLBACK EnumWindowsProcMy(HWND hwnd,LPARAM lParam)
{
DWORD lpdwProcessId;
GetWindowThreadProcessId(hwnd,&lpdwProcessId);
if(lpdwProcessId==lParam)
{
g_HWND=hwnd;
return FALSE;
}
return TRUE;
}
EnumWindows(EnumWindowsProcMy,m_ProcessId);

ShellExecute hold screen after execution and wait for character

Change the "cmd.exe" parameters:

string strParameters = "/k terms.exe";

This keeps the console window open, after the command has been executed.

Handle for ShellExecute() - Parent Window?

It is usually 0

hwnd : parent window that will receive a possible messagebox. This parameter is usually 0.

It refers to the top-level window: the window you are opening does not have any parent, and is the main window for the application being executed.

When you are switching between applications (ALT-TAB), you are displaying the next top-level window (the next app with a parent handle equals to 0) in the z-order (for instance).

Of course, the parent to your app can not be the Desktop Window itself:

If you create a child window whose parent is GetDesktopWindow(), your window is now glued to the desktop window. If your window then calls something like MessageBox(), well that's a modal dialog, and then the rules above kick in and the desktop gets disabled and the machine is toast.

For the path, I would advice double quotes surrounding simple quotes: " ' ... ' "

"'C:\\Documents and Settings\\Lab1\\My Documents\\Test.xls'"

Could work also (untested) with double double quotes : " "" ... "" "

"""C:\\Documents and Settings\\Lab1\\My Documents\\Test.xls"""

, as illustrated by this thread.


Actually, as mentioned in your other question by Andy and by Mesidin, and in ShellExecute Function manual, you can open the file, and pass its path in parameter.

ShellExecute( NULL, "open", 
"Test.xls", "C:\\Documents and Settings\\Lab1\\My Documents\\",
NULL, SW_SHOWNORMAL);

That means Excel is the default application for opening .xls extension files though.

Shell Execute bring Window to front

Windows doesn't permit processes to snatch the foreground window unless the user starts them. This is to avoid things like persuading the user to type their bank details into the wrong window. However the current foreground process can pass permission to another process to do this. See AllowSetForegroundWindow for the details. To do this you have to provide the process id for the process that will become foreground and ShellExecute doesn't provide that. However, if you switch to using ShellExecuteEx you can get this from the hProcess member on the SHELLEXECUTEINFO structure.

You can then call SetForegroundWindow in your new process and it will be permitted. Otherwise it just starts flashing on the taskbar.

EDIT

If your initial application is the foreground application and you start a subprocess from that then the subprocess should automatically become foreground as described in the documentation for these functions.

Below is an example of how we can choose to enable and set another application to become the foreground window. In this case it just creates a text file and calls ShellExecuteEx with the open verb. We have to wait for the child process to get going and to have its window prepared and then we can locate the window from the process ID and give it permissions and set its window to be foreground. In this case the launched notepad (or whatever is your "open" verb for .txt files) will be foreground anyway. If you separately run a notepad process and substiture in the process ID for that process where we normally put in the child process ID then we can make another process become foreground -- one that is not part of our process tree. This can be compiled using Visual C++ with cl -nologo -W3 -O2 -MD fg_test.cpp to produce an fg_test.exe.

#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <shellapi.h>

#pragma comment(lib, "shell32")
#pragma comment(lib, "user32")

static void PrintError(LPCTSTR szPrefix, DWORD dwError);
static BOOL CALLBACK OnGetWindowByProcess(HWND hwnd, LPARAM lParam);

typedef struct {
DWORD pid;
HWND hwnd;
} WINDOWPROCESSINFO;

int _tmain(int argc, TCHAR *argv[])
{
SHELLEXECUTEINFO sxi = {0};
sxi.cbSize = sizeof(sxi);
sxi.nShow = SW_SHOWNORMAL;

FILE *fp = NULL;
_tfopen_s(&fp, _T("junk.txt"), _T("wt"));
_fputts(_T("Example text file\n"), fp);
fclose(fp);

sxi.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NOASYNC | SEE_MASK_WAITFORINPUTIDLE;
sxi.lpVerb = _T("open");
sxi.lpFile = _T("junk.txt");
if (!ShellExecuteEx(&sxi))
PrintError(_T("ShellExecuteEx"), GetLastError());
else
{
WINDOWPROCESSINFO info;
info.pid = GetProcessId(sxi.hProcess); // SPECIFY PID
info.hwnd = 0;
AllowSetForegroundWindow(info.pid);
EnumWindows(OnGetWindowByProcess, (LPARAM)&info);
if (info.hwnd != 0)
{
SetForegroundWindow(info.hwnd);
SetActiveWindow(info.hwnd);
}
CloseHandle(sxi.hProcess);

}
return 0;
}

static BOOL CALLBACK OnGetWindowByProcess(HWND hwnd, LPARAM lParam)
{
WINDOWPROCESSINFO *infoPtr = (WINDOWPROCESSINFO *)lParam;
DWORD check = 0;
BOOL br = TRUE;
GetWindowThreadProcessId(hwnd, &check);
_tprintf(_T("%x %x %x\n"), hwnd, check, infoPtr->pid);
if (check == infoPtr->pid)
{
_tprintf(_T("found window %x for process id %x\n"), hwnd, check);
infoPtr->hwnd = hwnd;
br = FALSE;
}
return br;
}

static void
PrintError(LPCTSTR szPrefix, DWORD dwError)
{
LPTSTR lpsz = NULL;
DWORD cch = 0;

cch = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, dwError, LANG_NEUTRAL, (LPTSTR)&lpsz, 0, NULL);
if (cch < 1) {
cch = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_STRING
| FORMAT_MESSAGE_ARGUMENT_ARRAY,
_T("Code 0x%1!08x!"),
0, LANG_NEUTRAL, (LPTSTR)&lpsz, 0,
(va_list*)&dwError);
}
_ftprintf(stderr, _T("%s: %s"), szPrefix, lpsz);
LocalFree((HLOCAL)lpsz);
}


Related Topics



Leave a reply



Submit