Start a process...

  • Thread starter Thread starter pacemkr
  • Start date Start date
P

pacemkr

Is it possible to start a process (using Process.Start or other
methods) as a modal window? Meaning, I dont want the C# form that
started the process to become "current" untill the started process is
closed.

Thanks in advance.
Any help is greatly apreciated.
Nick Z.
 
Hi,

You might use Process.Handle and WaitHandle class to wait for the Process'
end.
 
Wouldn't this freeze the application. For example if I use
Process::WaitForExit the C# application freezes untill the process is
closed (ie. no event are handled, window is not repainted etc.). Plus
it still doesn't prevent the user form making the C# application window
active.
 
Mostly I'm looking for a way to simulate this behavior:

When you call MessageBox.Show() for example, the message box has
exclusive focus. if you try using the parent window the message box
blinks and remains the active window.
 
Create a modal window, override Closing method and there check with
WaitHandle.WaitOne method (use the overloaded method that takes waiting time
as a parameter - set it to minimum) to check if the process has finished. If
it isn't then just cancel the closing (e.Cancel = true).
 
Mostly I'm looking for a way to simulate this behavior:

When you call MessageBox.Show() for example, the message box has
exclusive focus. if you try using the parent window the message box
blinks and remains the active window.

Hi,
You can override WndProc method of your form. There, check if the
message received is WM_ACTIVATEAPP (look at MSDN docs for
Control.WndProc method and the example in there). If your form has
received this message, you can check if the child process is still
running, get its handle and send it an activation message.

Sunny
 
I just tried this and for some reason it doesnt work. The logic seems
to be right, thank you. But I dont know what the problem is, bellow is
the code from WndProc of my app window.

protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
const int WM_ACTIVATEAPP = 0x001C;
// Listen for operating system messages.
switch (m.Msg)
{
// The WM_ACTIVATEAPP message occurs when the application
// becomes the active application or becomes inactive.
case WM_ACTIVATEAPP:

// The WParam value identifies what is occurring.
bool appActive = ((int)m.WParam != 0);



if(appActive && profileEditor != null)
{
IntPtr profileEditorHandle = profileEditor.MainWindowHandle;

SendMessage(profileEditorHandle,WM_ACTIVATEAPP,true,profileEditor.Id);

/*FLASHWINFO fInfo = new FLASHWINFO();
fInfo.cbSize = (uint)Marshal.SizeOf(fInfo);
fInfo.hwnd = profileEditorHandle;
fInfo.dwFlags = 1;
fInfo.uCount = 3;
fInfo.dwTimeout = 100;

FlashWindowEx(ref fInfo);*/
}

// Invalidate to get new text painted.
this.Invalidate();

break;
}
}
 
Miha, I'm not entirely sure what you mean.

I have a C# app calling Process::Start on a C++ app that I want to have
exclusive focus as long as its open. In that context, do you mean
overriding the closing event in the C++ app?

As far as I understand, what you are suggesting prevents the C++ app
from closing untill its finished. That is not what I am trying to
accomplish.

My task:
From withing C# app check if C++ is finished, if not, do not attempt to
steal focus from it.

Thanks.
 
Got it to work, here is the code. I included the needed API interop as
well. Thanks for the help Sunny and Miha.

[StructLayout(LayoutKind.Sequential)]
public struct FLASHWINFO
{
public UInt32 cbSize;
public IntPtr hwnd;
public UInt32 dwFlags;
public UInt32 uCount;
public UInt32 dwTimeout;
}

[DllImport("user32.dll")]
static extern Int16 FlashWindowEx(ref FLASHWINFO pwfi);

[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);

protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
const int WM_ACTIVATEAPP = 0x001C;
// Listen for operating system messages.
switch (m.Msg)
{
// The WM_ACTIVATEAPP message occurs when the application
// becomes the active application or becomes inactive.
case WM_ACTIVATEAPP:

// The WParam value identifies what is occurring.
bool appActive = ((int)m.WParam != 0);

if(profileEditor != null)
{
profileEditor.Refresh();
}


if(appActive && profileEditor != null && !profileEditor.HasExited
)
{
IntPtr profileEditorHandle = profileEditor.MainWindowHandle;

SetForegroundWindow(profileEditorHandle);

FLASHWINFO fInfo = new FLASHWINFO();
fInfo.cbSize = (uint)Marshal.SizeOf(fInfo);
fInfo.hwnd = profileEditorHandle;
fInfo.dwFlags = 1;
fInfo.uCount = 3;
fInfo.dwTimeout = 100;

FlashWindowEx(ref fInfo);
}

// Invalidate to get new text painted.
this.Invalidate();
break;
}
}
 
Hi,
your first line is invoking the base WndProc. But whne you activate your
form, and the child process is running, you do want to stop the
activation, so you have to stop the message there. I would move the
base.WndProc in the else statement of if(appActive...).

That way, all messages unrelated to activation, or if the form should be
activated (I.e. no child process), will be passed to the base class and
everything will work OK. But if there is activation message and child
process running, the child process will be activated to front and the
activation of your form will not continue (not invoking base.WndProc).

Sunny
 
Back
Top