Bringing Original W32 Program Back to Focus?

Hi Guys,

I seem to be working a similar problem to jedi06. I've almost got mine working, but the last little bit won't cooperate. Any help would be great.

Basically, I want to have "MyProgram" send a keystroke to "Untitled - Notepad" and then return. I haven't been able to find a direct way, so I've been working in this fashion:

(I use WM_RBUTTONUP to initiate)
Find handles for the two programs
SetForegroundWindow for "Untitled - Notepad"
keybd_event the key to "Untitled - Notepad"
SetForegroundWindow for "MyProgram" - This doesn't quite work!!

The last step is my trouble. "Untitled - Notepad" retains keyboard focus, but the taskbar button for "MyProgram" turns blue signifying something.(?)

I've run this in several compilers (Dev-C++ and two versions of Borland) with the same results. Here's my code (which is a modified version of one of the first Forger's Tutorials):

[code]
#include

const char g_szClassName[] = "myWindowClass";
HWND MHandle, NHandle;
char FaceKey = 'F';

// Step 4: the Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_RBUTTONUP:
NHandle = FindWindow(NULL, "Untitled - Notepad");
MHandle = FindWindow(NULL, "MyProgram");
if (NHandle && MHandle)
{
SetForegroundWindow(NHandle);
keybd_event(FaceKey,0x8f,0 , 0);
keybd_event(FaceKey,0x8f, KEYEVENTF_KEYUP,0);
SetForegroundWindow(MHandle);
SetFocus(MHandle);[green]//I've tried with and without this
//I've also tried a couple other APIs such as
//EnableWindow and SetActiveWindow, the latter
//which says, "An application should call
//SetForegroundWindow if it wants to put itself into
//the foreground."[/green]
}
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;

//Step 1: Registering the Window Class
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

if(!RegisterClassEx(&wc))
{
MessageBox(NULL, "Window Registration Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}

// Step 2: Creating the Window
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
"MyProgram",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 360, 120,
NULL, NULL, hInstance, NULL);

if(hwnd == NULL)
{
MessageBox(NULL, "Window Creation Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}

ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);

// Step 3: The Message Loop
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
[/code]

Thanks for any and all help.

Take Care,
Ed

Comments

  • : Hi Guys,
    :
    : I seem to be working a similar problem to jedi06. I've almost got mine working, but the last little bit won't cooperate. Any help would be great.
    :
    : Basically, I want to have "MyProgram" send a keystroke to "Untitled - Notepad" and then return. I haven't been able to find a direct way, so I've been working in this fashion:
    :
    : (I use WM_RBUTTONUP to initiate)
    : Find handles for the two programs
    : SetForegroundWindow for "Untitled - Notepad"
    : keybd_event the key to "Untitled - Notepad"
    : SetForegroundWindow for "MyProgram" - This doesn't quite work!!
    :
    : The last step is my trouble. "Untitled - Notepad" retains keyboard focus, but the taskbar button for "MyProgram" turns blue signifying something.(?)
    :
    : I've run this in several compilers (Dev-C++ and two versions of Borland) with the same results. Here's my code (which is a modified version of one of the first Forger's Tutorials):
    :
    : [code]
    : #include
    :
    : const char g_szClassName[] = "myWindowClass";
    : HWND MHandle, NHandle;
    : char FaceKey = 'F';
    :
    : // Step 4: the Window Procedure
    : LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
    : {
    : switch(msg)
    : {
    : case WM_RBUTTONUP:
    : NHandle = FindWindow(NULL, "Untitled - Notepad");
    : MHandle = FindWindow(NULL, "MyProgram");
    : if (NHandle && MHandle)
    : {
    : SetForegroundWindow(NHandle);
    : keybd_event(FaceKey,0x8f,0 , 0);
    : keybd_event(FaceKey,0x8f, KEYEVENTF_KEYUP,0);
    : SetForegroundWindow(MHandle);
    : SetFocus(MHandle);[green]//I've tried with and without this
    : //I've also tried a couple other APIs such as
    : //EnableWindow and SetActiveWindow, the latter
    : //which says, "An application should call
    : //SetForegroundWindow if it wants to put itself into
    : //the foreground."[/green]
    : }
    : break;
    : case WM_CLOSE:
    : DestroyWindow(hwnd);
    : break;
    : case WM_DESTROY:
    : PostQuitMessage(0);
    : break;
    : default:
    : return DefWindowProc(hwnd, msg, wParam, lParam);
    : }
    : return 0;
    : }
    :
    : int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    : LPSTR lpCmdLine, int nCmdShow)
    : {
    : WNDCLASSEX wc;
    : HWND hwnd;
    : MSG Msg;
    :
    : //Step 1: Registering the Window Class
    : wc.cbSize = sizeof(WNDCLASSEX);
    : wc.style = 0;
    : wc.lpfnWndProc = WndProc;
    : wc.cbClsExtra = 0;
    : wc.cbWndExtra = 0;
    : wc.hInstance = hInstance;
    : wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    : wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    : wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    : wc.lpszMenuName = NULL;
    : wc.lpszClassName = g_szClassName;
    : wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
    :
    : if(!RegisterClassEx(&wc))
    : {
    : MessageBox(NULL, "Window Registration Failed!", "Error!",
    : MB_ICONEXCLAMATION | MB_OK);
    : return 0;
    : }
    :
    : // Step 2: Creating the Window
    : hwnd = CreateWindowEx(
    : WS_EX_CLIENTEDGE,
    : g_szClassName,
    : "MyProgram",
    : WS_OVERLAPPEDWINDOW,
    : CW_USEDEFAULT, CW_USEDEFAULT, 360, 120,
    : NULL, NULL, hInstance, NULL);
    :
    : if(hwnd == NULL)
    : {
    : MessageBox(NULL, "Window Creation Failed!", "Error!",
    : MB_ICONEXCLAMATION | MB_OK);
    : return 0;
    : }
    :
    : ShowWindow(hwnd, nCmdShow);
    : UpdateWindow(hwnd);
    :
    : // Step 3: The Message Loop
    : while(GetMessage(&Msg, NULL, 0, 0) > 0)
    : {
    : TranslateMessage(&Msg);
    : DispatchMessage(&Msg);
    : }
    : return Msg.wParam;
    : }
    : [/code]
    :
    : Thanks for any and all help.
    :
    : Take Care,
    : Ed
    :
    :

    Try calling
    [code]
    ShowWindow(hwnd, SW_SHOWDEFAULT);
    [/code]
    after the SetForegroundWindow(MHandle);

    Also, you don't have to do a FindWindow for MyProgram. You have the handle in the first argument of the WndProc.

    Greets,
    Eric Goldstein
    www.gvh-maatwerk.nl

  • Thanks Eric,

    But that didn't do it either, in any of the versions. Thanks for the FindWindow reminder, too. I only had that as an extra trial since it wasn't working using hwnd.

    I have also discovered I can't send focus to a second alternate window either. The original (Untitled - Notepad) stays on top. I've been trying BringWindowToTop and several ways to de-activate "Untitled - Notepad" and all I've been able to do is to make "Untitled - Notepad" unusable.

    This should be such a simple task, I can't see a reason why it won't work. I've got to be missing some minor detail somewhere.

    Thanks again.

    Take Care,
    Ed

  • In case any future readers are interested, I have found a solution to my difficulties. Basically, Windows won't give focus back to an application that doesn't belong to the same thread as the alternate window. So I had to use GetWindowThreadProcessId() to get both Ids and then use AttachThreadInput() to link them. After attaching them I was able to use SetForegroundWindow() and then unattach the two programs. I found the basic information to accomplish it at:

    http://www.tek-tips.com/faqs.cfm?fid=4262

    (A thank-you to the author and forum.)

    I've included the entire modified code even though the change was slight, in case a future seeker discovers this thread in the archive.

    [code]
    #include

    const char g_szClassName[] = "myWindowClass";
    HWND NHandle;
    char FaceKey = 'F', EdgeKey = 'E';

    void swapWin(HWND window)
    {
    SetForegroundWindow(window);
    }

    // Step 4: the Window Procedure
    LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
    switch(msg)
    {
    case WM_RBUTTONUP:
    NHandle = FindWindow(NULL, "Untitled - Notepad");
    if (NHandle && hwnd)
    {
    DWORD mId, nId;
    swapWin(NHandle);

    keybd_event(FaceKey,0x8f,0 , 0);
    keybd_event(FaceKey,0x8f, KEYEVENTF_KEYUP,0);

    nId = GetWindowThreadProcessId(NHandle, NULL);
    mId = GetWindowThreadProcessId(hwnd, NULL);

    if (mId && nId)
    {
    AttachThreadInput(mId, nId, TRUE);
    swapWin(hwnd);
    AttachThreadInput(mId, nId, FALSE);
    }
    }
    break;
    case WM_CLOSE:
    DestroyWindow(hwnd);
    break;
    case WM_DESTROY:
    PostQuitMessage(0);
    break;
    default:
    return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
    }

    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpCmdLine, int nCmdShow)
    {
    WNDCLASSEX wc;
    HWND hwnd;
    MSG Msg;

    //Step 1: Registering the Window Class
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = 0;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = g_szClassName;
    wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

    if(!RegisterClassEx(&wc))
    {
    MessageBox(NULL, "Window Registration Failed!", "Error!",
    MB_ICONEXCLAMATION | MB_OK);
    return 0;
    }

    // Step 2: Creating the Window
    hwnd = CreateWindowEx(
    WS_EX_CLIENTEDGE,
    g_szClassName,
    "MyProgram",
    WS_OVERLAPPEDWINDOW,
    430, 450, 360, 120,
    NULL, NULL, hInstance, NULL);

    if(hwnd == NULL)
    {
    MessageBox(NULL, "Window Creation Failed!", "Error!",
    MB_ICONEXCLAMATION | MB_OK);
    return 0;
    }

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    // Step 3: The Message Loop
    while(GetMessage(&Msg, NULL, 0, 0) > 0)
    {
    TranslateMessage(&Msg);
    DispatchMessage(&Msg);
    }
    return Msg.wParam;
    }
    [/code]

    Take Care,
    Ed


  • : In case any future readers are interested, I have found a solution to my difficulties. Basically, Windows won't give focus back to an application that doesn't belong to the same thread as the alternate window. So I had to use GetWindowThreadProcessId() to get both Ids and then use AttachThreadInput() to link them.


    Yeah you probably need your code to be inside the other process to do things like that. There are plenty of ways to get it running inside the other process, some examples from the gurus at Code Project can be found here:

    http://www.thecodeproject.com/system/#General

    For example you could install a global hook and then check if the window responding to it is the one you want, by using EnumWindows etc. If it is, then you can run your code from inside the global hook and you will be allowed to fiddle with focus or whatever you want.

  • : Yeah you probably need your code to be inside the other process to do things like that. There are plenty of ways to get it running inside the other process, some examples from the gurus at Code Project can be found here:
    :
    : http://www.thecodeproject.com/system/#General
    :
    : For example you could install a global hook and then check if the window responding to it is the one you want, by using EnumWindows etc. If it is, then you can run your code from inside the global hook and you will be allowed to fiddle with focus or whatever you want.
    :
    [blue]Thanks Lundin,

    In my specific case, I don't want to alter the second program at all. (I was using Notepad as my experimental file - the final version will have to communicate with a variety of control systems that accept keyboard input to initiate button presses.) I just want to send keystrokes to it. I couldn't figure out any way to send them via messaging and finally settled on the way I explained earlier.

    Thanks again.

    Take Care,
    Ed[/blue]

Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Categories