Writing Control Characters to Standard Input of a Command-Shell Pr

58 views
Skip to first unread message

Mark M

unread,
Jul 31, 2006, 9:29:01 PM7/31/06
to
I am attempting to use a third party command-line utility (WinDump.exe) to
capture network traffic for perfromance analysis. This utility when launched
captures network traffic until Ctrl-C is entered from the keyboard. I launch
this utility (through a batch file) programmatically in a command-shell
process through the Process object with no window (i.e.
myProcess.StartInfo.CreateNoWindow = true). I have re-directed the
StandardInput to a StreamWriter and I need to send a Ctrl-C to this process
through the StreamWriter. Could anyone tell me how to do this?

Thank you much!
--
Mark M

Barry Kelly

unread,
Jul 31, 2006, 10:23:05 PM7/31/06
to
Mark M <Ma...@newsgroups.nospam> wrote:

The Win32 API function 'GenerateConsoleCtrlEvent()' is what you're
looking for.

-- Barry

--
http://barrkel.blogspot.com/

Jeffrey Tan[MSFT]

unread,
Aug 1, 2006, 7:26:06 AM8/1/06
to
Hi Mark,

Thanks for your post!

Barry points out the correct API. However, the solution to your problem is
much complex than I expected. GenerateConsoleCtrlEvent Win32 API has a
special limitation. From MSDN:
"Only those processes in the group that share the same console as the
calling process receive the signal."

While .Net Process class internally encapsulate CreateProcess Win32 API, if
you use windbg to set a breakpoint on KERNEL32!CreateProcessW, you will see
that the dwCreationFlags parameter is passed with 0x4000410 from .Net
Process class, which included CREATE_NEW_CONSOLE(0x10) flag. So the new
lauched process will be openned in a new console window, which does not
meet the GenerateConsoleCtrlEvent API requirement.

So if you use GenerateConsoleCtrlEvent API with Process class, you will
have no lucky.

The only way is p/invoke win32 CreateProcess API manually, and do not
specify CREATE_NEW_CONSOLE(0x10) flag. Then the new lauched process will
share the same console as the calling process.

I have written a little sample project to demonstrate this:


using System;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Threading;
using System.Text;

namespace consoletest
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class Class1
{
/// <summary>
/// The main entry point for the application.
/// </summary>
///
[DllImport("Kernel32.dll")]
public static extern bool GenerateConsoleCtrlEvent(int dwCtrlEvent, int
dwProcessGroupId);

[StructLayout(LayoutKind.Sequential)]
internal class STARTUPINFO
{
public int cb;
public IntPtr lpReserved;
public IntPtr lpDesktop;
public IntPtr lpTitle;
public int dwX;
public int dwY;
public int dwXSize;
public int dwYSize;
public int dwXCountChars;
public int dwYCountChars;
public int dwFillAttribute;
public int dwFlags;
public short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}

[StructLayout(LayoutKind.Sequential)]
internal class PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
}

[DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern bool CreateProcess(string lpApplicationName, string
lpCommandLine, IntPtr lpProcessAttributes, IntPtr lpThreadAttributes, bool
bInheritHandles, int dwCreationFlags, IntPtr lpEnvironment, string
lpCurrentDirectory, STARTUPINFO lpStartupInfo, PROCESS_INFORMATION
lpProcessInformation);


[STAThread]
static void Main(string[] args)
{
STARTUPINFO si =new STARTUPINFO();
si.cb=Marshal.SizeOf(si);
PROCESS_INFORMATION pi=new PROCESS_INFORMATION();
string szCmdLine="ping msjeff1 -t";
Console.WriteLine("Press any key to lauch the process \nand press again
to generate the Ctrl+C signal");
Console.ReadLine();
// Spawn the other processes as part of this Process Group
bool f = CreateProcess(null, szCmdLine, IntPtr.Zero, IntPtr.Zero, true,
0, IntPtr.Zero, null, si, pi);

Console.ReadLine();
bool fResult=GenerateConsoleCtrlEvent(0, 0);
if(!fResult)
{
Console.WriteLine("GenerateConsoleCtrlEvent failed with error
"+Marshal.GetLastWin32Error());
}
Console.ReadLine();
}
}
}

I ignored this limitation at first and wasted a lot of time in test :-(

Further more, there is another issue: since the WinDump.exe is lauched
invisible, you can not simply tell the lauch console application when to
exit by pressing any key. To resolve this problem, you need another
application to controll the stub console application that lauches the
WinDump.exe and use some inter-process communication to tell it to exit
with GenerateConsoleCtrlEvent. You may use .Net Remoting as the IPC
technology or any native Win32 technologies.

Jeffrey Richter has written an article targeting the above problems, you
may give it a good reading:
http://www.microsoft.com/msj/0698/win320698.aspx

Hope this helps.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.

Mark M

unread,
Aug 2, 2006, 6:02:42 PM8/2/06
to
Thanks, Barry and Jeffrey.

I attempted implementing your solution, Jeffrey, and I am now able to
receive the Ctrl-C in the process running WinDump. However, I still seem to
have two other problems that I have not yet successfully resolved.

1) When the Ctrl-C has been received in the process, WinDump correctly
exits, but since it was launched from a batch file, I get the "Terminate
Batch Process (Y/N)" message and although I attempt to send a "y" to the
console, it doesn't close the window. To get around this, I am calling the
content of the batch file (single line) in my application, but this is not
desirable.

2) I would prefer to have this process run invisibly. Currently it displays
in a command window. Is there a way to hide this? I attempted to create a
"parent" command shell process and call your code within it, but then the
process stopped receiving the Ctrl-C again.

Thanks again for your help.
--
Mark M

Jeffrey Tan[MSFT]

unread,
Aug 2, 2006, 11:41:43 PM8/2/06
to
Hi Mark,

Thanks for your feedback!

Yes, I can reproduce your second problem. CreateNoWindow property is
implemented as passing CREATE_NO_WINDOW flag to the CreateProcess API.
Based on the test, if we pass this flag to the console application,
GenerateConsoleCtrlEvent will not close this console application at all.

Based on my research, because the hidden console application does not share
the same console as our calling console application,
GenerateConsoleCtrlEvent will not try to generate Ctrl+C to the hidden
console application. I think this is by design.

I do not think there is a good workaround regarding this issue. Maybe you
should try to kill the hidden console application as a workaround for
Ctrl+C? Anyway, this is not a good design, I think you may have to give
your design a second thought.

Thanks.

Jeffrey Tan[MSFT]

unread,
Aug 6, 2006, 11:19:07 PM8/6/06
to
Hi Mark,

Have you reviewed my last reply? If you have any concern or need any help,
please feel free to tell me, thanks.

Reply all
Reply to author
Forward
0 new messages