Click here to Skip to main content
16,020,447 members
Please Sign up or sign in to vote.
2.50/5 (2 votes)
See more:
I'm playing around right now with having a notepad open in a panel (notepad is just a placeholder application not the intended exe that's going to run in the panel)

When I start the process and set the panel as a parent I can use SendKeys to send commands or macros to the exe, but when the exe looses focus no commands can be sent to it. Focusing the panel doesn't focus the exe.

Is there a way to focus the specific exe running inside the panel or do I have to treat it as an external application and search through running processes and select the one I need to focus?

EDIT: So to make clarify it more I am doing this to be able to interact with a completely different exe at my workplace. I will still need to run it inside the form and be able to focus it copy paste from it and input keys into it. So if someone can clarify how exactly I can return focus to the exe running inside my form I'd greatly appreciate it.

What I have tried:

I've tried focusing the panel. Not quite sure yet how to focus a specific runnin application.
Posted
Updated 30-May-16 23:48pm
v2
Comments
Sergey Alexandrovich Kryukov 30-May-16 18:21pm    
Why? why?!
—SA
CHill60 30-May-16 18:41pm    
I think the bit that is missing here is .., how on earth do you run an exe in a "panel"? But yes, if it is an "external" program then find the running process and you can send keys to it.
The real question is ... what are you actually trying to achieve ... it sounds like you are going about the wrong way
BillWoodruff 30-May-16 18:59pm    
While I, too, share your "doubts" about using an .exe in this way, fact is you can rather easily run NotePad in a Panel on a Form, and you can easily direct KeyEvents to it as needed.
CHill60 30-May-16 19:02pm    
I stand corrected on the Panel bit (Actually a little embarrassed .. but it wouldn't be the first time, nor I suspect the last)... but I stand by my "what are you actually trying to achieve" :-)
[no name] 30-May-16 19:05pm    
Read my latest reply to Sergey's answer. I'm on mobile and can't seem to find a way to edit the question. I'm trying to enhance a database client system that is used at my workplace by creating a frame around the exe and using various commands to extract information from said exe

How to do this:

1. build a ProcessInfo that's going to define how your "external app" window appears.

2. use Process.Start with the ProcessInfo to get a handle to an instance of the external app.

3. give the started Process a little time to "settle in."

4. set the Parent Window ... your Panel or other WinForms ContainerControl ... of the Process handle.

5. move the external app window to the place you want it inside your WinForm ContainerControl.

Example code: a WinForm named 'FormWithNotePad with a Panel on it named 'pnlForNotePad:

C#
[DllImport("user32.dll", SetLastError = true)]
private static extern bool MoveWindow(IntPtr hwnd, int x, int y, int cx, int cy, bool repaint);

[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);

// you want to keep a form-scope available reference to the external app
public Process NotePadProcess { set; get; }
 
private void FormWithNotePad_Load(object sender, EventArgs e)
{
    ProcessStartInfo info = new ProcessStartInfo();

    info.UseShellExecute = true;
    info.CreateNoWindow = true;
    info.WindowStyle = ProcessWindowStyle.Normal;
    info.RedirectStandardInput = false;
    info.RedirectStandardOutput = false;
    info.RedirectStandardError = false;
    info.FileName = "notepad.exe";

    NotePadProcess = Process.Start(info);

    // inform user ? throw an error ?
    if (NotePadProcess == null) return;

    NotePadProcess.WaitForInputIdle();

    SetParent(NotePadProcess.MainWindowHandle, pnlForNotePad.Handle);
    
    MoveWindow(NotePadProcess.MainWindowHandle, 0, 0, pnlForNotePad.Width, pnlForNotePad.Height, true);
}
Now, let's consider the issue of Focus in WinForms:

1. as you may know, for every Control there is a 'TabStop Property, and a 'TabOrder value; that governs the order in which a given Control on a Form gets Focus, both when you use the tab-key to move Focus from control to control, and at app start-up ... most of the time.

The control on the Form with current active Focus is returned by the 'ActiveControl property.

Take some time (if you haven't already) to familiarize yourself with 'TabStop and 'TabOrder properties, and the 'ActiveControl property.

2. however, some Controls on a Form get "preference" for taking Focus; TextBox and RichTextBox seem to get this "preference" in my experience.

So, what to with your externa app running in some ContainerControl ... and Focus:

1. set the Form 'KeyPreview Property to 'true.

2. wire-up an EventHandler to the Form 'KeyDown Event

3. plan for how you want other Controls on the Form to get key-strokes: if you have a TextBox on your Form, you almost certainly want the user to be able to type in it.

Example:
C#
// of course you can force Focus back on your external app
private void FocusBackOnTheExternalApp_Click(object sender, EventArgs e)
{
    pnlForNotePad.Focus();
}

private void FormWithNotePad_KeyDown(object sender, KeyEventArgs e)
{
    if (ActiveControl == null
        || pnlForNotePad == this.ActiveControl
        && ! (ActiveControl is TextBoxBase))
    {
        SetForegroundWindow(NotePadProcess.MainWindowHandle);
        SendKeys.SendWait(e.KeyCode.ToString());
        e.Handled = true;
    }
}

// this will have the side-effect of making sure your external app gets the keystrokes
private void FormWithNotePad_Click(object sender, EventArgs e)
{
    ActiveControl = null;
}
In the KeyDown EventHandler shown above, we don't let the external app get the keystrokes if the active control on the form is a TextBox, or RichTextBox ... both inherit from 'TextBoxBase.

Of course, you could configure your Panel, or other ContainerControl, to have another Control on it you would use for some purpose in relationship to the external app.

Other ideas:

1. consider using a Form as the Container ?

2. consider keeping a local copy of the keystrokes sent to the external app ?

3. of course, you can use other Controls on the Form, like a TextBox, as a source of whatever characters you want to send to the external app: just remember that for the external app to receive input via 'SendKeys its Windows handle must be set to 'topmost via the 'SetForegroundWindow API call.
 
Share this answer
 
v2
Comments
[no name] 31-May-16 16:42pm    
This is perfect! All and much more than I needed! Thank you so much.

Just a quick question. Setting the focus on the exe obviously brings it to the front to perform actions even though the program can be minimized or not focused it will still focus it and perform the task. Is it possible to do the same thing, but in the background so it doesn't steal focus away from currently active program or would that require a more in depth interaction with the process? (example: when I press a button it writes junk to notepad then copy pastes it into a textbox and can do that multiple times even if the app is minimized. However if I'm typing something in another window it would steal focus from it obviously. Is it possible to maintain focus on another program while also performing the same thing?)

Hmm maybe not such a quick question, but I don't expect a super detailed answer. Thank you anyway!
BillWoodruff 31-May-16 17:31pm    
Glad you found my response useful ! The quick answer to your question is: "I am not sure" :) It's been a few years since I worked with Process.Start.

Let me ask you this: are you observing now that a side-effect of calling 'SetForegroundWindow to the .exe process is to take focus away from the other Controls on the Form ? It's a bit late here (GMT+7), but, tomorrow I'll take a look at this ... it's an interesting question.

Keep in mind that one thing you can easily do in WinForms is to "un-plug" an EventHandler using the -= operator, and then, when you need to, plug it in again using the += operator. That's one way to control when the .exe will get the keystrokes. Of course, you could also set a boolean flag to use in the KeyDown EventHandler.

cheers, Bill
[no name] 31-May-16 17:39pm    
It's not as much about the keystrokes in the form. For example the goal is that I work in a program and do stuff there. I feed a number to MY program and it goes and pulls data in the background while I'm doing other stuff. Right now if I initiate the event it focuses the window (as it should) and does stuff there. If I click anywhere else it will continue sending keys but to whatever is currently in focus. I guess a better question is how I can direct my send keys directly to the application I want whether it's focused or not. And if there's a way to sorta separate whatever I'm doing from whatever the program is doing so that my input doesn't mess it up.
The real problems is: embedding notepad in your forms application is apparent abuse of technology.

Indeed, what can you gain with that? Embedding notepad, the product with rudimentary features? Your total effort you need for communication with this application, sharing data, embedding, focusing, will soon exceed the efforts needed to implement you own text-editing component bases, for example, on TextBox.

The answer to your question, if you want to do it your way, would be: use P/Invoke and Windows API related to manipulation with windows: Window Functions (Windows)[^].

You can easily find the documentation on P/Invoke and the use of these function. Sorry, but I don't want to waste more time on the useless. When you solve your particular problem with focusing, probably one of the simplest, you will see that it won't help your to solve a really essential problem: sharing data between edit buffer and your application. Having two different processes, not designed for the collaboration, is the wrong idea in first place.

My real advice is: develop your own editor based on System.Windows.Forms. It also not hard to do with WPF.

—SA
 
Share this answer
 
Comments
[no name] 30-May-16 18:26pm    
Did you read the first part of the question where I clearly state that notepad is just a PLACEHOLDER exe. I will be using a completely different program which is NOT a text editing application, but still requires me to send input into it. Thanks for the suggestion I will look into P/Invoke.
Sergey Alexandrovich Kryukov 30-May-16 18:32pm    
Yes, I did. Sorry if I did not make my answer clear enough or missed this point.

It's harder to explain, but let me try. Forget my assessments of the value of Notepad; indeed, it's irrelevant (sorry again). Main point is different: it's a bad idea to use different processes. Instead of a "completely different program", develop, say, a library assembly. Never stick two different processes in one window or one non-distributed application.

—SA
[no name] 30-May-16 18:57pm    
Ok to clarify a bit more. I'm making a frame around a program I use at work which is a database of sorts. I have no direct access to the back end only the program to pull data. However it is lacking a lot of features which I want to add. This is purely a personal project so unless I can build a library which let's me interact with an exe better than I'm left with using this method.

Currently the method being used is utilizing autohotkey to focus the active window and execute commands that way so I think my way is a bit of an improvement on that.
Sergey Alexandrovich Kryukov 30-May-16 20:05pm    
Okay, as to your question, I answered it. Are you going to accept it formally?

Do whatever you want. But my advice is: don't do it. I don't know how to explain you that it would be the abuse. The anti-pattern is not really technical. You just put yourself in the position where you are using the application which does not do what you want, or someone else made this mistake. You have to face the consequences. If you do software development, you have to secure control on all the components of your product. It means that you have to have full source code or develop it yourself. Everything else may mean eventual death of your project. This is life...

—SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900