请问怎样通过管道输出一个Ctrl+C?

DDGG 2008-06-02 09:19:46
做了一个cmd.exe的UI版。就是在后台运行了一个cmd.exe,通过管道获取它的输出显示在窗体上,并通过管道将用户打在文本框的命令重定向到它的输入。
现在有一个问题,怎么发送一个Ctrl+C给它呢?Ctrl+Break也行。但是不可以用TerminateProcess()的方式,因为只是要输出一个Ctrl+C停止当前操作,不是要关掉整个命令行。

谢谢!
...全文
683 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
xzlcc 2011-02-16
  • 打赏
  • 举报
回复
我也有此问题,不知楼主是否已解决!?
僵哥 2008-06-11
  • 打赏
  • 举报
回复
//续上
static DWORD g_dwCtrlRoutineAddr=NULL;
static HANDLE g_hAddrFoundEvent=NULL;

//--------------------------------------------------------------------
BOOL WINAPI MyHandler(DWORD dwCtrlType) {
// test
//__asm { int 3 };
if (CTRL_C_EVENT!=dwCtrlType) {
return FALSE;
}

//printf("Received ctrl-break event\n");
if (NULL==g_dwCtrlRoutineAddr) {

// read the stack base address from the TEB
#define TEB_OFFSET 4
DWORD * pStackBase;
__asm { mov eax, fs:[TEB_OFFSET] }
__asm { mov pStackBase, eax }

// read the parameter off the stack
#define PARAM_0_OF_BASE_THEAD_START_OFFSET -3
g_dwCtrlRoutineAddr=pStackBase[PARAM_0_OF_BASE_THEAD_START_OFFSET];

// notify that we now have the address
if (!SetEvent(g_hAddrFoundEvent)) {
// printf("SetEvent failed with 0x08X.\n", GetLastError());
}
}
return TRUE;
}


//--------------------------------------------------------------------
RETVAL GetCtrlRoutineAddress(void) {
RETVAL rv=EXIT_OK;

// must be cleaned up
g_hAddrFoundEvent=NULL;

// create an event so we know when the async callback has completed
g_hAddrFoundEvent=CreateEvent(NULL, TRUE, FALSE, NULL); // no security, manual reset, initially unsignaled, no name
if (NULL==g_hAddrFoundEvent) {
_JumpLastError(rv, error, "CreateEvent");
}

// request that we be called on system signals
if (!SetConsoleCtrlHandler(MyHandler, TRUE)) {
_JumpLastError(rv, error, "SetConsoleCtrlHandler");
}

// generate a signal
if (!GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0)) {
_JumpLastError(rv, error, "GenerateConsoleCtrlEvent");
}

// wait for our handler to be called
{
DWORD dwWaitResult=WaitForSingleObject(g_hAddrFoundEvent, INFINITE);
if (WAIT_FAILED==dwWaitResult) {
_JumpLastError(rv, error, "WaitForSingleObject");
}
}

_Verify(NULL!=g_dwCtrlRoutineAddr, rv, error);

error:
if (NULL!=g_hAddrFoundEvent) {
if (!CloseHandle(g_hAddrFoundEvent)) {
_TeardownLastError(rv, "CloseHandle");
}
}
return rv;
}

extern "C" int send_break(DWORD dwPid)
{
RETVAL rv;

HANDLE hRemoteProc=NULL;
HANDLE hRemoteProcToken=NULL;

rv=GetCtrlRoutineAddress();
_JumpIfError(rv, error, "GetCtrlRoutineAddress");

printf("Sending signal to process %d...\n", dwPid);
rv=AdvancedOpenProcess(dwPid, &hRemoteProc);
_JumpIfErrorStr(rv, error, "AdvancedOpenProcess", dwPid);

rv=StartRemoteThread(hRemoteProc, g_dwCtrlRoutineAddr);
_JumpIfError(rv, error, "StartRemoteThread");

//done:
rv=EXIT_OK;
error:
if (NULL!=hRemoteProc && GetCurrentProcess()!=hRemoteProc) {
if (!CloseHandle(hRemoteProc)) {
_TeardownLastError(rv, "CloseHandle");
}
}
if (EXIT_OK!=rv) {
// printf("0x%08X == ", rv);
// PrintError(rv);
}
return rv;
}


//--------------------------------------------------------------------
/*
int main(unsigned int nArgs, char ** rgszArgs) {
RETVAL rv;

HANDLE hRemoteProc=NULL;
HANDLE hRemoteProcToken=NULL;
bool bSignalThisProcessGroup=false;

//printf("test test test\n");

if (2!=nArgs || (('/'==rgszArgs[1][0] || '-'==rgszArgs[1][0])
&& ('H'==rgszArgs[1][1] || 'h'==rgszArgs[1][1] || '?'==rgszArgs[1][1])))
{
PrintHelp();
exit(1);
}

// check for the special parameter
char * szPid=rgszArgs[1];
bSignalThisProcessGroup=('-'==szPid[0]);
char * szEnd;
DWORD dwPid=strtoul(szPid, &szEnd, 0);
if (false==bSignalThisProcessGroup && (szEnd==szPid || 0==dwPid)) {
printf("\"%s\" is not a valid PID.\n", szPid);
rv=ERROR_INVALID_PARAMETER;
goto error;
}


//printf("Determining address of kernel32!CtrlRoutine...\n");
rv=GetCtrlRoutineAddress();
_JumpIfError(rv, error, "GetCtrlRoutineAddress");
//printf("Address is 0x%08X.\n", g_dwCtrlRoutineAddr);

// open the process
if ('-'==rgszArgs[1][0]) {
printf("Sending signal to self...\n");
hRemoteProc=GetCurrentProcess();
} else {
printf("Sending signal to process %d...\n", dwPid);
rv=AdvancedOpenProcess(dwPid, &hRemoteProc);
_JumpIfErrorStr(rv, error, "AdvancedOpenProcess", rgszArgs[1]);
}

rv=StartRemoteThread(hRemoteProc, g_dwCtrlRoutineAddr);
_JumpIfError(rv, error, "StartRemoteThread");

//done:
rv=EXIT_OK;
error:
if (NULL!=hRemoteProc && GetCurrentProcess()!=hRemoteProc) {
if (!CloseHandle(hRemoteProc)) {
_TeardownLastError(rv, "CloseHandle");
}
}
if (EXIT_OK!=rv) {
printf("0x%08X == ", rv);
PrintError(rv);
}
return rv;
}
*/
僵哥 2008-06-11
  • 打赏
  • 举报
回复
只找到一个通过CreateRemoteThread来达到目的的。
/* Copyright (C) 2003 Louis Thomas. License: http://www.latenighthacking.com/projects/lnhfslicense.html */

#include <windows.h>
#include <stdio.h>
#include <malloc.h>
#include <aclapi.h>
//#include <winerror.h>

//####################################################################

typedef unsigned int RETVAL;

#define STRINGIFY(A) #A

#define EXIT_OK 0

#define _TeardownLastError(rv, errorsource) \
{ \
RETVAL rv2__=GetLastError(); \
// printf(errorsource " failed with 0x%08X.\n", rv2__); \
if (EXIT_OK==rv) { \
rv=rv2__; \
} \
}

#define _TeardownIfError(rv, rv2, errorsource) \
if (EXIT_OK!=rv2) { \
// printf(errorsource " failed with 0x%08X.\n", rv2); \
if (EXIT_OK==rv) { \
rv=rv2; \
} \
}

#define _JumpLastError(rv, label, errorsource) \
rv=GetLastError(); \
// printf(errorsource " failed with 0x%08X.\n", rv); \
goto label;

#define _JumpLastErrorStr(rv, label, errorsource, str) \
rv=GetLastError(); \
// printf( errorsource "(%s) failed with 0x%08X.\n", str, rv); \
goto label;

#define _JumpIfError(rv, label, errorsource) \
if (EXIT_OK!=rv) {\
// printf( errorsource " failed with 0x%08X.\n", rv); \
goto label; \
}

#define _JumpIfErrorStr(rv, label, errorsource, str) \
if (EXIT_OK!=rv) {\
// printf( errorsource "(%s) failed with 0x%08X.\n", str, rv); \
goto label; \
}

#define _JumpError(rv, label, errorsource) \
// printf( errorsource " failed with 0x%08X.\n", rv); \
goto label;

#define _JumpErrorStr(rv, label, errorsource, str) \
// printf( errorsource "(%s) failed with 0x%08X.\n", str, rv); \
goto label;

#define _JumpIfOutOfMemory(rv, label, pointer) \
if (NULL==(pointer)) { \
rv=ERROR_NOT_ENOUGH_MEMORY; \
// printf("Out of memory ('" #pointer "').\n"); \
goto label; \
}

#define _Verify(expression, rv, label) \
if (!(expression)) { \
// printf("Verify failed: '%s' is false.\n", #expression); \
rv=E_UNEXPECTED; \
goto label; \
}


//####################################################################

//--------------------------------------------------------------------
void PrintError(DWORD dwError) {
char * szErrorMessage=NULL;
DWORD dwResult=FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
NULL/*ignored*/, dwError, 0/*language*/, (char *)&szErrorMessage, 0/*min-size*/, NULL/*valist*/);
if (0==dwResult) {
printf("(FormatMessage failed)");
} else {
printf("%s", szErrorMessage);
}
if (NULL!=szErrorMessage) {
LocalFree(szErrorMessage);
}
}


//--------------------------------------------------------------------
RETVAL StartRemoteThread(HANDLE hRemoteProc, DWORD dwEntryPoint){
RETVAL rv;

// must be cleaned up
HANDLE hRemoteThread=NULL;

// inject the thread
hRemoteThread=CreateRemoteThread(hRemoteProc, NULL, 0, (LPTHREAD_START_ROUTINE)dwEntryPoint, (void *)CTRL_C_EVENT, CREATE_SUSPENDED, NULL);
if (NULL==hRemoteThread) {
_JumpLastError(rv, error, "CreateRemoteThread");
}

// wake up the thread
if (-1==ResumeThread(hRemoteThread)) {
_JumpLastError(rv, error, "ResumeThread");
}

// wait for the thread to finish
if (WAIT_OBJECT_0!=WaitForSingleObject(hRemoteThread, INFINITE)) {
_JumpLastError(rv, error, "WaitForSingleObject");
}

// find out what happened
if (!GetExitCodeThread(hRemoteThread, (DWORD *)&rv)) {
_JumpLastError(rv, error, "GetExitCodeThread");
}

if (STATUS_CONTROL_C_EXIT==rv) {
// printf("Target process was killed.\n");
rv=EXIT_OK;
} else if (EXIT_OK!=rv) {
// printf("(remote function) failed with 0x%08X.\n", rv);
//if (ERROR_INVALID_HANDLE==rv) {
// printf("Are you sure this is a console application?\n");
//}
}


error:
if (NULL!=hRemoteThread) {
if (!CloseHandle(hRemoteThread)) {
_TeardownLastError(rv, "CloseHandle");
}
}

return rv;
}

//--------------------------------------------------------------------
void PrintHelp(void) {
printf(
"SendSignal <pid>\n"
" <pid> - send ctrl-break to process <pid> (hex ok)\n"
);
}

//--------------------------------------------------------------------
RETVAL SetPrivilege(HANDLE hToken, char * szPrivilege, bool bEnablePrivilege)
{
RETVAL rv;

TOKEN_PRIVILEGES tp;
LUID luid;

if (!LookupPrivilegeValue(NULL, szPrivilege, &luid)) {
_JumpLastError(rv, error, "LookupPrivilegeValue");
}

tp.PrivilegeCount=1;
tp.Privileges[0].Luid=luid;
if (bEnablePrivilege) {
tp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;
} else {
tp.Privileges[0].Attributes=0;
}

AdjustTokenPrivileges(hToken, false, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL); // may return true though it failed
rv=GetLastError();
_JumpIfError(rv, error, "AdjustTokenPrivileges");

rv=EXIT_OK;
error:
return rv;
}

//--------------------------------------------------------------------
RETVAL AdvancedOpenProcess(DWORD dwPid, HANDLE * phRemoteProc) {
RETVAL rv, rv2;

#define NEEDEDACCESS PROCESS_QUERY_INFORMATION|PROCESS_VM_WRITE|PROCESS_VM_READ|PROCESS_VM_OPERATION|PROCESS_CREATE_THREAD

// must be cleaned up
HANDLE hThisProcToken=NULL;

// initialize out params
*phRemoteProc=NULL;
bool bDebugPriv=false;

// get a process handle with the needed access
*phRemoteProc=OpenProcess(NEEDEDACCESS, false, dwPid);
if (NULL==*phRemoteProc) {
rv=GetLastError();
if (ERROR_ACCESS_DENIED!=rv) {
_JumpError(rv, error, "OpenProcess");
}
// printf("Access denied; retrying with increased privileges.\n");

// give ourselves god-like access over process handles
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hThisProcToken)) {
_JumpLastError(rv, error, "OpenProcessToken");
}

rv=SetPrivilege(hThisProcToken, SE_DEBUG_NAME, true);
if (EXIT_OK==rv) {
bDebugPriv=true;
}
_JumpIfErrorStr(rv, error, "SetPrivilege", SE_DEBUG_NAME);

// get a process handle with the needed access
*phRemoteProc=OpenProcess(NEEDEDACCESS, false, dwPid);
if (NULL==*phRemoteProc) {
_JumpLastError(rv, error, "OpenProcess");
}
}

// success
rv=EXIT_OK;

error:
if (ERROR_ACCESS_DENIED==rv && false==bDebugPriv) {
// printf("You need administrative access (debug privilege) to access this process.\n");
}
if (true==bDebugPriv) {
rv2=SetPrivilege(hThisProcToken, SE_DEBUG_NAME, false);
_TeardownIfError(rv, rv2, "SetPrivilege");
}
if (NULL!=hThisProcToken) {
if (!CloseHandle(hThisProcToken)) {
_TeardownLastError(rv, "CloseHandle");
}
}
return rv;
}

DDGG 2008-06-11
  • 打赏
  • 举报
回复
谢谢大家!

多人接受答案了。
DDGG 2008-06-10
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 arong1234 的回复:]
CTRL+C能结束当前操作而不中止当前命令么?似乎不可能吧?
[/Quote]

就是在后台运行了一个cmd.exe,然后通过cmd.exe的命令行运行了一个dos程序,按Ctrl+C在这个dos程序结束前终止它,是会退回命令行状态,而cmd.exe并没有退出。
arong1234 2008-06-10
  • 打赏
  • 举报
回复
CTRL+C能结束当前操作而不中止当前命令么?似乎不可能吧?
DDGG 2008-06-10
  • 打赏
  • 举报
回复
BOOL LaunchAndWait(LPCTSTR lpszAppName, LPSTR lpszParam, WORD nShowWindow /*= SW_SHOW*/,
HANDLE hStdInput /*= NULL*/, HANDLE hStdOutput /*= NULL*/, HANDLE hStdError /*= NULL*/,
HANDLE hEventExit /*= NULL*/)
{
PROCESS_INFORMATION piProcessInfo;
STARTUPINFO siStartupInfo; //This is an [in] parameter
HANDLE aHandles[2];
DWORD dwWaitResult;
CString cstrMsg;
BOOL bResult;

siStartupInfo.cb = sizeof(siStartupInfo); //Only compulsory field
GetStartupInfo(&siStartupInfo);
siStartupInfo.hStdInput = hStdInput;
siStartupInfo.hStdOutput = hStdOutput;
siStartupInfo.hStdError = hStdError;
siStartupInfo.wShowWindow = nShowWindow;
siStartupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;

bResult = CreateProcess(lpszAppName, lpszParam, NULL, NULL, TRUE, CREATE_NEW_PROCESS_GROUP, NULL, NULL, &siStartupInfo, &piProcessInfo);

if (bResult)
{
aHandles[0] = piProcessInfo.hProcess;
aHandles[1] = hEventExit;
dwWaitResult = WaitForMultipleObjects(2, aHandles, FALSE, INFINITE);
if (dwWaitResult == WAIT_FAILED || dwWaitResult - WAIT_OBJECT_0 == 1)
{
int f = GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, piProcessInfo.dwProcessId);
// int f = GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
// 上下两种方式f返回都是0,调用失败。GetLastError()返回6,“无效句柄”。
}
CloseHandle(piProcessInfo.hThread);
CloseHandle(piProcessInfo.hProcess);
}

return bResult;
}


在网上搜索到这篇文章http://www.cppblog.com/cyt/archive/2008/01/08/40723.html,里面提到父进程也要有控制台窗口才能使GenerateConsoleCtrlEvent调用成功,但是我的是MFC对话框应用程序,没有控制台窗口。到底应该怎么做才能简单地解决这个问题呢?
DDGG 2008-06-06
  • 打赏
  • 举报
回复
好的,我要先试一下,稍后来结帖子。
谢谢!
abomber2 2008-06-03
  • 打赏
  • 举报
回复
使用GenerateConsoleCtrlEvent API 函数
KeSummer 2008-06-03
  • 打赏
  • 举报
回复
使用WriteConsoleInput
jameshooo 2008-06-03
  • 打赏
  • 举报
回复
GenerateConsoleCtrlEvent
zyyoung 2008-06-02
  • 打赏
  • 举报
回复
热键
DDGG 2008-06-02
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 cnzdgs 的回复:]
用keybd_event先发Ctrl按下,再发C按下,再C放开、最后Ctrl放开,如何?
[/Quote]

这个不行吧?是针对当前窗口发送?可我的cmd.exe进程是运行在隐藏的窗口里,而且它的输入和输出都被重定向了,恐怕不受影响。
cnzdgs 2008-06-02
  • 打赏
  • 举报
回复
用keybd_event先发Ctrl按下,再发C按下,再C放开、最后Ctrl放开,如何?
包含代码和文档 实验一 实验内容 编写程序,演示多进程并发执行和进程软中断、管道通信。 父进程使用系统调用pipe( )建立一个管道,然后使用系统调用fork()创建两个子进程,子进程1和子进程2; 子进程1每隔1秒通过管道向子进程2发送数据: I send you x times. (x初值为1,每次发送后做加一操作) 子进程2从管道读出信息,并显示在屏幕上。 父进程用系统调用signal()捕捉来自键盘的中断信号(即按Ctrl+C键);当捕捉到中断信号后,父进程用系统调用Kill()向两个子进程发出信号,子进程捕捉到信号后分别输出下列信息后终止: Child Process l is Killed by Parent! Child Process 2 is Killed by Parent! 父进程等待两个子进程终止后,释放管道输出如下的信息后终止 Parent Process is Killed! 实验二 实验内容 过Linux多线程与信号灯机制,设计并实现计算机线程与I/O线程共享缓冲区的同步与通信。 程序要求:两个线程,共享公共变量a 线程1负责计算(1到100的累加,每次加一个数) 线程2负责打印(输出累加的中间结果) 实验三 实验内容 利用多个共享内存(有限空间)构成的环形缓冲,将源文件复制到目标文件,实现两个进程的誊抄。 实验四 实验内容 1、(1)Blink程序的编译和下载 (2)给Blink程序加入printf,在每次定时器事件触发点亮LED的同时通过串口显示信息 (3)修改BLink程序,只使用一个Timer,三个LED灯作为3位的二进制数表示(亮灯为1,不亮为0),按照0-7的顺序循环显示,同时将数值显示在终端上。

15,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧