首页
社区
课程
招聘
[求助]请教高手,怎样向一个正在执行的命令行发出一个CTRL+C按键
2006-9-16 09:01 12376

[求助]请教高手,怎样向一个正在执行的命令行发出一个CTRL+C按键

2006-9-16 09:01
12376
我给一个命令行程序做了一个UI界面,UI显示命令行程序执行的进度和信息,但这个命令行程序必须靠CTRL+C才可以停止,我怎么才可以模拟一个CTRL+C按键让这个命令行程序停止呢?我可以得到这个命令行程序的进程句柄和ID。我查了不少资料,一直没有找到答案,那位高手给指点一下!!

另外提醒一下:命令行程序是没有消息循环机制的,所以不要考虑用消息来通知它!

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
点赞7
打赏
分享
最新回复 (13)
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
x12143 2006-9-16 10:27
2
0
不知道你是不是用汇编的!
发送WM_COMMAND消息,将Ctrl+C的按键扫描码附在消息结构中。
自己多试试!
雪    币: 236
活跃值: (26)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
红火蚁 3 2006-9-16 11:37
3
0
HWND hWnd = ::FindWindow(NULL, TEXT("lc.txt - 记事本"));
        if (hWnd == NULL)
        {
                MessageBox(TEXT("没有找到窗口"));
                return ;
        }
        else
        {
                MessageBox(TEXT("找到窗口"));
                ::SetForegroundWindow(hWnd);
                                keybd_event(VK_CONTROL, MapVirtualKey(VK_CONTROL, 0), 0, 0);
                                keybd_event(0x47, MapVirtualKey(0x47, 0), 0, 0);
                                keybd_event(0x47, MapVirtualKey(0x47, 0), KEYEVENTF_KEYUP, 0);
                                keybd_event(VK_CONTROL, MapVirtualKey(VK_CONTROL, 0), KEYEVENTF_KEYUP, 0);
}

这坐了这个简易的程序你看看能不能用
雪    币: 207
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jinyangyb 2006-9-16 13:32
4
0
最初由 x12143 发布
不知道你是不是用汇编的!
发送WM_COMMAND消息,将Ctrl+C的按键扫描码附在消息结构中。
自己多试试!


命令行程序是一个独立的进程,不在UI的进程和线程内,所以你的WM_COMMAND消息是不可能发给他的!如果这么简单我就不用查那么多资料还找不到答案了!
雪    币: 207
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jinyangyb 2006-9-16 13:37
5
0
最初由 红火蚁 发布
HWND hWnd = ::FindWindow(NULL, TEXT("lc.txt - 记事本"));
if (hWnd == NULL)
{
MessageBox(TEXT("没有找到窗口"));
return ;
........


谢谢你的答复!
但是这个命令行程序是没有窗口的,所以FindWindow函数不起作用,我唯一可以得到是这个命令行程序的进程句柄和进程ID
雪    币: 236
活跃值: (26)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
红火蚁 3 2006-9-16 14:50
6
0
有个方法就是进程注入
你在注入的那个DLL里面终止你的程序
这样子就OK了
雪    币: 207
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jinyangyb 2006-9-16 15:05
7
0
最初由 红火蚁 发布
有个方法就是进程注入
你在注入的那个DLL里面终止你的程序
这样子就OK了


我不太明白,你是不是要我使用TerminateProcess函数,这是可以中止那个命令行程序,但这不是我需要的,那样的话,命令行程序不是正常退出,它只能接受CTRL+C才会正常退出。

雪    币: 236
活跃值: (26)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
红火蚁 3 2006-9-16 15:09
8
0
我做了这个程序,实现了关闭那个进程
这个市注入的DLL代码
#include "stdafx.h"
#include "MyInsertDll.h"
#include <windows.h>
#include <winuser.h>

BOOL APIENTRY DllMain( HANDLE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                                         )
{
    switch (ul_reason_for_call)
        {
                case DLL_PROCESS_ATTACH:
                        {                       
                                MessageBox(NULL, TEXT("DLL_PROCESS_ATTACH"), NULL, MB_OK);
                                ExitProcess(1);

                        }
                        break;
                case DLL_THREAD_ATTACH:
                case DLL_THREAD_DETACH:
                case DLL_PROCESS_DETACH:
                        {
                                // 自己处理卸载的代码
                        }
                        break;
    }
    return TRUE;
}

// This is an example of an exported variable
MYINSERTDLL_API int nMyInsertDll=0;

// This is an example of an exported function.
MYINSERTDLL_API int fnMyInsertDll(void)
{
        return 42;
}

// This is the constructor of a class that has been exported.
// see MyInsertDll.h for the class definition
CMyInsertDll::CMyInsertDll()
{
        return;
}
这个是我主程序的代码
void CTestDlg::OnButton1()
{
        // TODO: Add your control notification handler code here
            
                DWORD ProcessID = FindTarget("notepad.exe");
                HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION |PROCESS_VM_WRITE,
                                                  FALSE,
                                                                          ProcessID);

                char lpszDll[] = "c:\\MyInsertDll.dll";

                //HMODULE hDll = LoadLibrary("MyInsertDll.dll");

                DWORD dwSize, dwWritten;
                dwSize = lstrlen(lpszDll) + 1;

                LPVOID lpBuf = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
                if (lpBuf == NULL)
                {
                        MessageBox(TEXT("VirtualAllocEx Failed"));
                        CloseHandle(hProcess);
                }
                if (WriteProcessMemory(hProcess, lpBuf, (LPVOID)lpszDll, dwSize, &dwWritten))
                {
                        if (dwWritten != dwSize)
                        {
                                MessageBox(TEXT("dwWritten != dwSize"));
                                VirtualFreeEx(hProcess, lpBuf, dwSize, MEM_DECOMMIT);
                                CloseHandle(hProcess);
                        }
                }
                else
                {
                        MessageBox(TEXT("WriteProcessMemory Failed"));
                        CloseHandle(hProcess);
                }

                DWORD dwID;
                LPVOID pFunc = LoadLibrary;
                HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pFunc, lpBuf, 0, &dwID);

                WaitForSingleObject(hThread, INFINITE);
        VirtualFreeEx( hProcess, lpBuf, dwSize, MEM_DECOMMIT );
        CloseHandle( hThread );
        CloseHandle( hProcess );
                return ;
}

DWORD CTestDlg::FindTarget(LPCTSTR lpszProcess)
{
        DWORD dwRet = 0;
        HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
        PROCESSENTRY32 pe32;
        pe32.dwSize = sizeof(PROCESSENTRY32);
        Process32First(hSnapshot, &pe32);
        do
        {
                if (lstrcmpi(pe32.szExeFile, lpszProcess) == 0)
                {
                        dwRet = pe32.th32ProcessID;
                        break;
                }
        }
        while (Process32Next(hSnapshot, &pe32));
        CloseHandle(hSnapshot);
        return dwRet;
}
你的这个一定有窗口的
不然你的鼠标按键发给谁啊?
我的这个市直接实现关闭进程
可能有的细节你需要在改进改进
雪    币: 236
活跃值: (26)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
红火蚁 3 2006-9-16 15:10
9
0
不然你的鼠标按键发给谁啊?

更正
是键盘按键
雪    币: 207
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jinyangyb 2006-9-16 15:21
10
0
谢谢你!
但我还是有些地方不明白。
雪    币: 207
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jinyangyb 2006-9-16 15:30
11
0
你的这个一定有窗口的
不然你的鼠标按键发给谁啊?
我的这个市直接实现关闭进程
可能有的细节你需要在改进改进

其实我是CreateProcess函数启动了一个批处理命令来执行那个命令行程序,它唯一需要接受的按键就是CTRL+C来中止它,而CreateProcess会产生一个命令cmd的窗口,这就是唯一的窗口了,我也就希望它能接受这个按键,那个命令行程序是一个可执行文件,是别人写的我没有办法修改它的原代码来接受其他的命令。你的程序我基本明白,就是可以退出这个命令行程序,但那个程序如果不是接受CTRL+C中止就不会做一些善后处理工作,导致我得不到需要的东西。所以我一定要用CTRL+C来中止它
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Buddhat 2006-9-16 17:29
12
0
在MSDN中搜索 GenerateConsoleCtrlEvent 这个API,应该是你所要的。
雪    币: 207
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jinyangyb 2006-9-18 08:56
13
0
最初由 Buddhat 发布
在MSDN中搜索 GenerateConsoleCtrlEvent 这个API,应该是你所要的。


这个函数我也早试过了,但没有成功,下面是代码,不知道哪里出错了。
char sCommand = "test.bat"  //这是要执行的批处理,内容是执行一个可执行文件:abc.exe
STARTUPINFO sinfo;
PROCESS_INFORMATION pinfo;

::CreateProcess(NULL, sCommand, NULL, NULL, TRUE,        CREATE_NEW_PROCESS_GROUP, NULL, NULL, &sinfo, &pinfo);

当我需要停止的时候我执行这条语句
::GenerateConsoleCtrlEvent(CTRL_C_EVENT,pinfo.dwProcessId);
结果根本停不下来
雪    币: 207
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jinyangyb 2006-9-18 12:39
14
0
谢谢各位给予帮助的朋友。
问题已经解决了,通过SendInput函数就可以了,我之前一直认为keybd_event和SendInput是等效的,所以没有试。今天抱着试试的想法改为SendInput发送竟然OK了!!但我没明白它们的区别,有哪位朋友知道的,告诉我一声。
游客
登录 | 注册 方可回帖
返回