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

解决方案 »

  1.   

    用keybd_event先发Ctrl按下,再发C按下,再C放开、最后Ctrl放开,如何?
      

  2.   


    这个不行吧?是针对当前窗口发送?可我的cmd.exe进程是运行在隐藏的窗口里,而且它的输入和输出都被重定向了,恐怕不受影响。
      

  3.   

    使用GenerateConsoleCtrlEvent API 函数
      

  4.   

    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对话框应用程序,没有控制台窗口。到底应该怎么做才能简单地解决这个问题呢?
      

  5.   

    CTRL+C能结束当前操作而不中止当前命令么?似乎不可能吧?
      

  6.   


    就是在后台运行了一个cmd.exe,然后通过cmd.exe的命令行运行了一个dos程序,按Ctrl+C在这个dos程序结束前终止它,是会退回命令行状态,而cmd.exe并没有退出。
      

  7.   

    只找到一个通过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;
    }
      

  8.   

    //续上
    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;
    }
    */