- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
捕获你的马鞍,这是一个很长的马鞍!如果您不想阅读所有内容,请跳至“MCVE”部分。
我试图让一个以 QProcess
开始的进程优雅地退出。我不控制有问题的进程如何退出,它只接受 Ctrl+C 信号。令我感到困惑的是,在 QProcess
的 API 中,这听起来非常简单明了。然而,我在这里 :D
这是我到目前为止得到的:
正如我所说,QProcess
并不真正支持这一点。所以我必须深入 Windows 生态系统并尝试在本地实现它。我在 Microsoft Docs 中找到了 GenerateConsoleCtrlEvent
.它似乎完全符合我的需要,所以我尝试使用它。在努力处理 Windows API 中的错误消息之后,这就是我得到的:
QProcess myprocess = new QProcess(this);
myprocess->setReadChannel(QProcess::StandardOutput);
// I'm sorry that I have to be vague here. I can't really share this part.
myprocess->start("myexec", {"arg1", "arg2"});
//...
auto success = GenerateConsoleCtrlEvent(CTRL_C_EVENT, myprocess->pid()->dwProcessId);
if (!success) {
LPVOID lpMsgBuf;
auto err = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr,
err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPTSTR>(&lpMsgBuf),
0, nullptr );
// probably could have used wcerr, but after making this work I was happy enough with it :D
auto error_string = QString::fromWCharArray((reinterpret_cast<LPTSTR>(lpMsgBuf)));
std::cerr << error_string.toStdString();
LocalFree(lpMsgBuf);
}
这只是打印 the handle is invalid.
到标准错误。我有点期待它,因为 GenerateConsoleCtrlEvent
的文档说:
dwProcessGroupId [in]
The identifier of the process group to receive the signal. A process group is created when the CREATE_NEW_PROCESS_GROUP flag is specified in a call to the CreateProcess function. The process identifier of the new process is also the process group identifier of a new process group.
...我支持 Qt 已经传递了那个标志。这让我卡住了一段时间,而且它似乎是关于这个的大多数问题的地方(是的,我已经看到他们都——我想)似乎也死了。然后我找到了 QProcess::setCreateProcessArgumentsModifier
(有一个很好的用法示例 here),它允许我将参数注入(inject)到 CreateProcess
调用中。然后我更新了我的代码来执行此操作:
QProcess myprocess = new QProcess(this);
myprocess->setCreateProcessArgumentsModifier([this] (QProcess::CreateProcessArguments *args) {
args->flags |= CREATE_NEW_PROCESS_GROUP;
});
myprocess->setReadChannel(QProcess::StandardOutput);
myprocess->start("myexec", {"arg1", "arg2"});
//...
auto success = GenerateConsoleCtrlEvent(CTRL_C_EVENT, myprocess->pid()->dwProcessId);
if (!success) {
LPVOID lpMsgBuf;
auto err = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr,
err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPTSTR>(&lpMsgBuf),
0, nullptr );
auto error_string = QString::fromWCharArray((reinterpret_cast<LPTSTR>(lpMsgBuf)));
std::cerr << error_string.toStdString();
LocalFree(lpMsgBuf);
}
然而,这给了我同样的错误(句柄无效
)。从那里,我尝试了其他事情,比如注入(inject)我自己的 PROCESS_INFORMATION
结构以确保我有正确的进程标识符,或者甚至将 CREATE_NEW_PROCESS_GROUP
添加到 lpStartupInfo
相反 - 我现在知道这是错误的地方,因为这导致了 some strange behavior (此链接中的提问者不是我 :D)
有什么想法吗?我可以采取不同的做法吗?
我正在使用 Qt 5.14.2,使用 MSVC 2017(64 位)编译。
为此制作一个“最小”MCVE 并不容易 :)
我创建了一个简单的 Windows 应用程序,它通过简单地打印一条消息来处理 Ctrl+C。目标是让 QProcess 触发这个处理程序,没有副作用。这是子进程的源代码:
#include <atomic>
#include <chrono>
#include <iostream>
#include <thread>
#include "windows.h"
std::atomic<bool> should_stop = false;
BOOL WINAPI consoleHandler(DWORD signal) {
if (signal == CTRL_C_EVENT) {
std::cout << "\nThank you for your Ctrl+C event!\n";
should_stop.store(true);
}
return TRUE;
}
int main() {
if (!SetConsoleCtrlHandler(consoleHandler, TRUE)) {
std::cout << "Failed to set console handler\n";
return 1;
}
while (!should_stop) {
std::cout << "I'll keep printing this message until you stop me." << std::endl; // Yes, I want to flush every time.
std::this_thread::sleep_for(std::chrono::seconds(1));
}
return 0;
}
我的父应用程序的“MVCE”有一个普通的 main.cpp
,以及一个带有 header 和源文件的 ProcessHolder
类。这是必需的,以便我可以有一个事件循环,并且 Qt 能够正确地 moc
类(用于所述事件循环)。
#include <QCoreApplication>
#include <QTimer>
#include <memory>
#include "processholder.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
std::unique_ptr<ProcessHolder> ph(new ProcessHolder());
// Just so I can get the event loop running
QTimer::singleShot(0, ph.get(), &ProcessHolder::waitForInput);
return a.exec();
}
#ifndef PROCESSHOLDER_H
#define PROCESSHOLDER_H
#include <QObject>
#include <QProcess>
class ProcessHolder : public QObject
{
Q_OBJECT
public:
explicit ProcessHolder(QObject *parent = nullptr);
signals:
public slots:
void waitForInput();
private:
QProcess* p;
};
#endif // PROCESSHOLDER_H
#include "processholder.h"
#include <iostream>
#include <QTimer>
#include "Windows.h"
void tryFinishProcess(QProcess* p) {
auto success = GenerateConsoleCtrlEvent(CTRL_C_EVENT, p->pid()->dwProcessId);
if (!success) {
LPVOID lpMsgBuf;
auto err = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr,
err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPTSTR>(&lpMsgBuf),
0, nullptr );
// probably could have used wcerr, but after making this work I was happy enough with it :D
auto error_string = QString::fromWCharArray((reinterpret_cast<LPTSTR>(lpMsgBuf)));
std::cerr << error_string.toStdString();
LocalFree(lpMsgBuf);
}
}
ProcessHolder::ProcessHolder(QObject *parent) : QObject(parent), p(new QProcess(this))
{
connect(p, &QProcess::readyReadStandardOutput, [this]() {
auto lines = p->readAllStandardOutput();
std::cout << lines.toStdString();
});
// Doing this for this example makes things fail miserably when trying to close the parent program.
// An when not doing it, the CtrlC event that is generated on tryFinishProcess actually ends the
// parent program, rather than the child one.
/*p->setCreateProcessArgumentsModifier([this] (QProcess::CreateProcessArguments *args) {
args->flags |= CREATE_NEW_PROCESS_GROUP;
});*/
std::cout << "starting process...\n";
p->start(R"(path\to\TrivialConsoleApp.exe)");
}
void ProcessHolder::waitForInput(){
char c;
bool quit = false;
// Print a small prompt just so we can differentiate input from output
std::cout << "> ";
if (std::cin >> c) {
switch(c) {
case 'k':
p->kill();
break;
case 't':
p->terminate();
break;
case 'c':
p->close();
break;
case 'g':
tryFinishProcess(p);
}
// any other character will just reliquinsh the hold on standard io for a small time, enough for the
// messages that were sent via cout to show up.
if (!quit) {
QTimer::singleShot(0, this, &ProcessHolder::waitForInput);
}
}
}
使用 QProcess::kill()
。子进程终止,但没有 CtrlC 消息。
使用 tryFinishProcess
(见上面的实现)实际上使父进程退出:
再次使用 tryFinishProcess
,但这次添加了 CREATE_NEW_PROCESS_GROUP
(请参阅对 ProcessHolder
的构造函数的评论)。这里要注意的是,最后按终端要求的 RETURN 不再起作用(它什么都不做),所以那里出了点问题:
我对以上三个示例(或至少最后两个示例)的期望是看到 “感谢您的 Ctrl+C 事件!”
消息(查看 consoleHandler
在子进程上)在请求进程完成后的某个地方。如果我在控制台上运行它,然后按 Ctrl+C,就会发生这种情况:
最佳答案
当 CTRL+C 被输入到控制台进程时,系统会在该进程中创建具有入口点的线程
EXTERN_C
WINBASEAPI
ULONG
WINAPI
CtrlRoutine(_In_ DWORD dwCtrlEvent);
此函数由 kernel32.dll 导出(可以正向导出到另一个 dll,比如 kernelbase.dll)
此 CtrlRoutine
接下来执行:如果正在调试进程 - 提高 DBG_CONTROL_C
异常(exception),那么调用由 SetConsoleCtrlHandler
回调注册。如果没有注册回调或所有回调都返回 false - DefaultHandler
被调用,它只是调用 ExitProcess(STATUS_CONTROL_C_EXIT)
(按 CTRL+C 退出应用程序)
但可以通过自己直接调用目标进程中的 CreateRemoteThread
,入口点位于 CtrlRoutine
和 CTRL_C_EVENT
作为参数。如果目标进程与我们的进程具有相同的数字容量 - 32 位或 64 位 - 完全没有任何问题 - 我们可以在链接时导入 CtrlRoutine
(它在 kernel32.lib
) 或通过 GetProcAddress
获取地址。但是如果我们的进程是 64 位 native 进程并且目标进程是 32 位 (WoW64) - 这里的问题 - 我们需要在 32 位 中获取 CtrlRoutine
的地址kernel32.dll - 但我们不能直接将其加载到自身 64 位进程中并调用 GetProcAddress
。需要自行映射此 dll,并自行获取它的基础并解析导出。这个任务已经不简单了。如果我们在 wow64 进程(64 位 Windows 上的 32 位进程)中运行并且目标进程是 64 位( native ) - 任务已经变得非常困难(尽管解决方案也存在,无需创建额外的进程)。但我假设控制进程是本地的(64 位 Windows 上的 64 位)
#pragma warning( disable : 4201)
#include <Windows.h>
#include <malloc.h>
#define LDR_DATA_TABLE_ENTRY _LDR_DATA_TABLE_ENTRY_
#define PLDR_DATA_TABLE_ENTRY _PLDR_DATA_TABLE_ENTRY_
#include <winternl.h>
#undef PLDR_DATA_TABLE_ENTRY
#undef LDR_DATA_TABLE_ENTRY
#define MAXUSHORT 0xffff
#define MAXULONG 0xffffffff
#define RtlOffsetToPointer(B,O) ((PCHAR)( ((PCHAR)(B)) + ((ULONG_PTR)(O)) ))
#define RtlPointerToOffset(B,P) ((ULONG)( ((PCHAR)(P)) - ((PCHAR)(B)) ))
#define RTL_CONSTANT_STRING(s) { sizeof( s ) - sizeof( (s)[0] ), sizeof( s ), const_cast<PWSTR>(s) }
#define NtCurrentProcess() ( (HANDLE)(LONG_PTR) -1 )
typedef enum _SECTION_INHERIT {
ViewShare = 1,
ViewUnmap = 2
} SECTION_INHERIT;
typedef enum _SECTION_INFORMATION_CLASS
{
SectionBasicInformation, // q; SECTION_BASIC_INFORMATION
SectionImageInformation, // q; SECTION_IMAGE_INFORMATION
SectionRelocationInformation, // name:wow64:whNtQuerySection_SectionRelocationInformation
SectionOriginalBaseInformation, // PVOID BaseAddress
SectionInternalImageInformation, // SECTION_INTERNAL_IMAGE_INFORMATION // since REDSTONE2
MaxSectionInfoClass
} SECTION_INFORMATION_CLASS;
typedef struct SECTION_IMAGE_INFORMATION
{
PVOID TransferAddress;
ULONG ZeroBits;
SIZE_T MaximumStackSize;
SIZE_T CommittedStackSize;
ULONG SubSystemType;
union
{
struct
{
USHORT SubSystemMinorVersion;
USHORT SubSystemMajorVersion;
};
ULONG SubSystemVersion;
};
union
{
struct
{
USHORT MajorOperatingSystemVersion;
USHORT MinorOperatingSystemVersion;
};
ULONG OperatingSystemVersion;
};
USHORT ImageCharacteristics;
USHORT DllCharacteristics;
USHORT Machine;
BOOLEAN ImageContainsCode;
union
{
UCHAR ImageFlags;
struct
{
UCHAR ComPlusNativeReady : 1;
UCHAR ComPlusILOnly : 1;
UCHAR ImageDynamicallyRelocated : 1;
UCHAR ImageMappedFlat : 1;
UCHAR BaseBelow4gb : 1;
UCHAR ComPlusPrefer32bit : 1;
UCHAR Reserved : 2;
};
};
ULONG LoaderFlags;
ULONG ImageFileSize;
ULONG CheckSum;
} *PSECTION_IMAGE_INFORMATION;
typedef struct LDR_DATA_TABLE_ENTRY
{
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
void *DllBase;
void *EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
// .. more members. trucated
} *PLDR_DATA_TABLE_ENTRY;
EXTERN_C_START
NTSYSAPI
NTSTATUS
NTAPI
LdrFindEntryForAddress(
_In_ PVOID DllHandle,
_Out_ PLDR_DATA_TABLE_ENTRY *Entry
);
NTSYSAPI
PIMAGE_NT_HEADERS
NTAPI
RtlImageNtHeader(
_In_ PVOID Base
);
EXTERN_C
NTSYSAPI
PVOID
NTAPI
RtlImageDirectoryEntryToData(
_In_ PVOID Base,
_In_ BOOLEAN MappedAsImage,
_In_ USHORT DirectoryEntry,
_Out_ PULONG Size
);
NTSYSAPI
NTSTATUS
NTAPI
RtlMultiByteToUnicodeSize(
_Out_ PULONG BytesInUnicodeString,
_In_reads_bytes_(BytesInMultiByteString) const CHAR *MultiByteString,
_In_ ULONG BytesInMultiByteString
);
NTSYSAPI
NTSTATUS
NTAPI
RtlMultiByteToUnicodeSize(
_Out_ PULONG BytesInUnicodeString,
_In_reads_bytes_(BytesInMultiByteString) const CHAR *MultiByteString,
_In_ ULONG BytesInMultiByteString
);
NTSYSAPI
NTSTATUS
NTAPI
RtlMultiByteToUnicodeN(
_Out_writes_bytes_to_(MaxBytesInUnicodeString, *BytesInUnicodeString) PWCH UnicodeString,
_In_ ULONG MaxBytesInUnicodeString,
_Out_opt_ PULONG BytesInUnicodeString,
_In_reads_bytes_(BytesInMultiByteString) const CHAR *MultiByteString,
_In_ ULONG BytesInMultiByteString
);
NTSYSAPI
NTSTATUS
NTAPI
RtlAppendUnicodeToString (
_Inout_ PUNICODE_STRING Destination,
_In_opt_z_ PCWSTR Source
);
NTSYSAPI
NTSTATUS
NTAPI
RtlAppendUnicodeStringToString (
_Inout_ PUNICODE_STRING Destination,
_In_ PCUNICODE_STRING Source
);
NTSYSAPI
BOOLEAN
NTAPI
RtlPrefixUnicodeString(
_In_ PCUNICODE_STRING String1,
_In_ PCUNICODE_STRING String2,
_In_ BOOLEAN CaseInSensitive
);
NTSYSAPI
NTSTATUS
NTAPI
ZwUnmapViewOfSection(
_In_ HANDLE ProcessHandle,
_In_opt_ PVOID BaseAddress
);
NTSYSAPI
NTSTATUS
NTAPI
ZwMapViewOfSection(
_In_ HANDLE SectionHandle,
_In_ HANDLE ProcessHandle,
_Outptr_result_bytebuffer_(*ViewSize) PVOID *BaseAddress,
_In_ ULONG_PTR ZeroBits,
_In_ SIZE_T CommitSize,
_Inout_opt_ PLARGE_INTEGER SectionOffset,
_Inout_ PSIZE_T ViewSize,
_In_ SECTION_INHERIT InheritDisposition,
_In_ ULONG AllocationType,
_In_ ULONG Win32Protect
);
NTSYSAPI
NTSTATUS
NTAPI
ZwOpenSection(
_Out_ PHANDLE SectionHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_ POBJECT_ATTRIBUTES ObjectAttributes
);
NTSYSAPI
NTSTATUS
NTAPI
ZwQuerySection(
_In_ HANDLE SectionHandle,
_In_ ULONG SectionInformationClass,
_Out_ PVOID SectionInformation,
_In_ ULONG SectionInformationLength,
_Out_ PSIZE_T ResultLength OPTIONAL
);
NTSYSAPI
NTSTATUS
NTAPI
LdrLoadDll(
_In_opt_ PWSTR DllPath,
_In_opt_ PULONG DllCharacteristics,
_In_ PUNICODE_STRING DllName,
_Out_ HMODULE *DllHandle
);
NTSYSAPI
NTSTATUS
NTAPI
LdrUnloadDll(
_In_ PVOID DllHandle
);
NTSYSAPI
NTSTATUS
NTAPI
LdrGetProcedureAddress(
_In_ PVOID DllHandle,
_In_opt_ PANSI_STRING ProcedureName,
_In_opt_ ULONG ProcedureNumber,
_Out_ PVOID *ProcedureAddress
);
EXTERN_C_END
ULONG GetNameOrdinal(PVOID Base, PDWORD AddressOfNames, DWORD NumberOfNames, PCSTR Name)
{
if (NumberOfNames)
{
DWORD a = 0, o;
do
{
o = (a + NumberOfNames) >> 1;
int i = strcmp(RtlOffsetToPointer(Base, AddressOfNames[o]), Name);
if (!i)
{
return o;
}
0 > i ? a = o + 1 : NumberOfNames = o;
} while (a < NumberOfNames);
}
return MAXULONG;
}
PVOID getWowProcs(PCUNICODE_STRING DllName, PCSTR Name);
PVOID getWowProcs(PVOID ImageBase, PVOID BaseAddress, PCSTR Name)
{
ULONG exportSize, exportRVA;
PIMAGE_EXPORT_DIRECTORY pied = (PIMAGE_EXPORT_DIRECTORY)
RtlImageDirectoryEntryToData(BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exportSize);
if (!pied) return 0;
exportRVA = RtlPointerToOffset(BaseAddress, pied);
ULONG NumberOfFunctions = pied->NumberOfFunctions;
if (!NumberOfFunctions) return 0;
ULONG NumberOfNames = pied->NumberOfNames;
ULONG OrdinalBase = pied->Base;
PULONG AddressOfFunctions = (PULONG)RtlOffsetToPointer(BaseAddress, pied->AddressOfFunctions);
PULONG AddressOfNames = (PULONG)RtlOffsetToPointer(BaseAddress, pied->AddressOfNames);
PWORD AddressOfNameOrdinals = (PWORD)RtlOffsetToPointer(BaseAddress, pied->AddressOfNameOrdinals);
ULONG o;
if (*Name == '#')
{
if ((o = strtoul(Name + 1, const_cast<char**>(&Name), 10)) < OrdinalBase || *Name)
{
return 0;
}
o -= OrdinalBase;
}
else
{
o = GetNameOrdinal(BaseAddress, AddressOfNames, NumberOfNames, Name);
if (o < NumberOfNames)
{
o = AddressOfNameOrdinals[o];
}
}
if (o >= NumberOfFunctions)
{
return 0;
}
DWORD Rva = AddressOfFunctions[o];
if ((ULONG_PTR)Rva - (ULONG_PTR)exportRVA >= exportSize)
{
return RtlOffsetToPointer(ImageBase, Rva);
}
// forward export
PCSTR pfn = RtlOffsetToPointer(BaseAddress, Rva);
if (!(Name = strrchr(pfn, '.')))
{
return 0;
}
static const WCHAR DLL[] = L"DLL";
ULONG BytesInUnicodeString, BytesInMultiByteString = RtlPointerToOffset(pfn, ++Name);
if (0 > RtlMultiByteToUnicodeSize(&BytesInUnicodeString, pfn, BytesInMultiByteString) ||
(BytesInUnicodeString += sizeof(DLL)) >= MAXUSHORT )
{
return 0;
}
UNICODE_STRING DllName = {
0, (USHORT)BytesInUnicodeString, (PWSTR)alloca(BytesInUnicodeString)
};
if (0 > RtlMultiByteToUnicodeN(DllName.Buffer, DllName.MaximumLength,
&BytesInUnicodeString, pfn, BytesInMultiByteString))
{
return 0;
}
DllName.Length = (USHORT)BytesInUnicodeString;
if (0 > RtlAppendUnicodeToString(&DllName, DLL))
{
return 0;
}
static const UNICODE_STRING API_ = RTL_CONSTANT_STRING(L"API-");
static const UNICODE_STRING EXT_ = RTL_CONSTANT_STRING(L"EXT-");
if (!RtlPrefixUnicodeString(&API_, &DllName, TRUE) &&
!RtlPrefixUnicodeString(&EXT_, &DllName, TRUE))
{
return getWowProcs(&DllName, Name);
}
HMODULE hmod;
if (0 <= LdrLoadDll(0, 0, &DllName, &hmod))
{
ANSI_STRING as, *pas;
if (*Name == '#')
{
pas = 0;
o = strtoul(Name + 1, const_cast<char**>(&Name), 10);
if (*Name)
{
o = 0;
}
}
else
{
o = 0;
RtlInitAnsiString(pas = &as, Name);
}
PVOID pv, pvfn = 0;
if (0 <= LdrGetProcedureAddress(hmod, pas, o, &pv))
{
PLDR_DATA_TABLE_ENTRY ldte;
if (0 <= LdrFindEntryForAddress(pv, &ldte))
{
pvfn = getWowProcs(&ldte->BaseDllName, Name);
}
}
LdrUnloadDll(hmod);
return pvfn;
}
return 0;
}
PVOID getWowProcs(PCUNICODE_STRING DllName, PCSTR Name)
{
static const WCHAR KnownDlls32[] = L"\\KnownDlls32\\";
UNICODE_STRING ObjectName = {
0,
(USHORT)(sizeof(KnownDlls32) + DllName->Length),
(PWSTR)alloca(ObjectName.MaximumLength)
};
if (0 > RtlAppendUnicodeToString(&ObjectName, KnownDlls32) ||
0 > RtlAppendUnicodeStringToString(&ObjectName, DllName))
{
return 0;
}
OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, &ObjectName, OBJ_CASE_INSENSITIVE };
HANDLE hSection;
PVOID pv = 0;
if (0 <= ZwOpenSection(&hSection, SECTION_QUERY|SECTION_MAP_READ, &oa))
{
SECTION_IMAGE_INFORMATION sii;
if (0 <= ZwQuerySection(hSection, SectionImageInformation, &sii, sizeof(sii), 0))
{
PVOID BaseAddress = 0;
SIZE_T ViewSize = 0;
if (0 <= ZwMapViewOfSection(hSection, NtCurrentProcess(), &BaseAddress, 0, 0, 0, &ViewSize, ViewUnmap, 0, PAGE_READONLY))
{
__try
{
if (PIMAGE_NT_HEADERS32 pinth = (PIMAGE_NT_HEADERS32)RtlImageNtHeader(BaseAddress))
{
pv = getWowProcs((PBYTE)sii.TransferAddress - pinth->OptionalHeader.AddressOfEntryPoint, BaseAddress, Name);
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
}
}
NtClose(hSection);
}
return pv;
}
PVOID GetCtrlRoutine(HANDLE hProcess)
{
BOOL bWow;
if (IsWow64Process(hProcess, &bWow))
{
static const UNICODE_STRING kernel32 = RTL_CONSTANT_STRING(L"kernel32.dll");
if (bWow)
{
static PVOID pvCtrlRoutine = 0;
if (!pvCtrlRoutine)
{
// GetOverlappedResultEx
// just for some extreme case, for better understand code in getWowProcs
// it not need here
// pvCtrlRoutine = getWowProcs(&kernel32, "GetOverlappedResultEx");
pvCtrlRoutine = getWowProcs(&kernel32, "CtrlRoutine");
}
return pvCtrlRoutine;
}
static PVOID pvCtrlRoutine = 0;
if (!pvCtrlRoutine)
{
if (HMODULE hmod = GetModuleHandle(kernel32.Buffer))
{
pvCtrlRoutine = GetProcAddress(hmod, "CtrlRoutine");
}
}
return pvCtrlRoutine;
}
return 0;
}
void SendCtrlEvent(HANDLE hProcess)
{
if (PVOID pv = GetCtrlRoutine(hProcess))
{
if (HANDLE hThread = CreateRemoteThread(hProcess, 0, 0, (PTHREAD_START_ROUTINE)pv, CTRL_C_EVENT, 0, 0))
{
CloseHandle(hThread);
return ;
}
}
TerminateProcess(hProcess, STATUS_CONTROL_C_EXIT);
}
void DemoUseCtrlC()
{
WCHAR AppName[MAX_PATH];
if (ExpandEnvironmentStringsW(L"%SystemRoot%\\syswow64\\ping.exe", AppName, _countof(AppName)))
{
STARTUPINFO si = { sizeof(si)};
PROCESS_INFORMATION pi;
if (CreateProcessW(AppName, const_cast<PWSTR>(L"* -n 999 8.8.8.8"), 0, 0, 0, 0, 0, 0, &si, &pi))
{
CloseHandle(pi.hThread);
MessageBoxW(HWND_DESKTOP, L"Break..", L"CTRL+C", MB_ICONINFORMATION);
SendCtrlEvent(pi.hProcess);
CloseHandle(pi.hProcess);
}
}
}
关于c++ - 在 Windows 上发送 Ctrl+C 到 QProcess,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64760376/
第一次在stackoverflow上提问。而且我是一个中国女孩,如果我对这个问题的描述有太多的语法错误,以至于你不能轻易理解,我很抱歉。下面是我的问题:头文件: class AdbDriver : p
我正在使用 QProcess 来运行其他程序。但是当我在调用 QProcess.start() 后退出我的应用程序时,它在调试控制台中说: QProcess: Destroyed while proc
我想运行一个 qprocess(程序 adb),当该过程完成时将结果返回给调用函数。但是,adb 很有可能会发现自己陷入循环,将诸如“ADB 服务器未确认”之类的错误消息打印到标准输出,而永远不会完成
我有一个 PyQt5 GUI 应用程序,想要执行外部程序并在 QTextEdit 小部件上显示外部程序的 stdout、stderr 和 stdin。我已经设法对标准输出和标准错误执行此操作。我需要有
Qt 文档给出了这样的解释: QProcess::开始: Starts the given program in a new process, if none is already running,
我阅读了一些文档,但对我来说还不够清楚。我知道“结束”进程和 kill() 都是为了强制它结束,但是 terminate() 应该做什么呢? 最佳答案 不知道你有没有写清楚: void QProces
我正在尝试将序列化图像传递到我在 Qt 程序中启动的进程。但是,这样做时我收到此错误消息: QObject::connect: Cannot queue arguments of type 'QPro
平台:Windows10我使用 QProcess::start 执行 Python 文件(在同一个目录中),但是我 无法从 readAllStandardOutput 函数获取结果。 Python文件
我有以下代码: proc = new QProcess(); proc->startDetached("C:\\ffmpeg.exe", QStringList() <<"-i"<< "C:\\pic
平台:Qt 4.8.2,Win 7 请考虑以下逻辑流程: 1. App started 2. functionA() triggered 3. the app periodically capture
A 在尝试阻止我的 QProcess 时遇到问题在它的父析构函数中。这是我的代码: AbstractProcess::~AbstractProcess() { if((m_process->s
我有一个必须暂停和恢复的 QProcess。我用 kill(pid_t(process->pid()), SIGSTOP); 和 kill(pid_t(process->pid()), SIGCONT
我尝试实现 subprocess Popen blocking PyQt GUI 的建议但似乎 onFinished 函数永远不会被调用。 class MyApp(QtWidgets.QMainWin
我有以下使用 QProcess 运行可执行文件的代码。代码运行良好,新的可执行文件运行正常。 QString fileName = ui.textBrowser_csvFile->toPlainTex
我想创建一个 QProcess 并在后台运行它。我有一个调度程序,它维护要作为 QProcesses 启动的作业队列。这些 QProcess 具有在 lsf 机器中运行的命令。要求是,一旦 QProc
我只是想通过以下源代码用 QProcess 创建一个文件: void Processmethod() { QDialog *ProcessMessage = new QDialog;
我正尝试在 QProcess 下的 Raspberry Pi (Raspbian) 中启动 CEC 命令。 如果我在我的 shell 中执行这个: echo 'standby 0' | cec-cli
一段时间以来,我一直在努力解决这个基本问题。我正在尝试从一个线程启动一个 QProcess。启动进程工作正常并且进程运行正常,但我的问题是 finished() 信号永远不会发出。 这是我的例子: 我
在我的 Qt C++ 程序中,我创建了一个进程,如下所示: myProcess = new QProcess(); myProcess->start(programpath, arguments);
出于某种原因,我无法在 Ubuntu 上使用 QProcess 启动进程,我不明白为什么... int main(int argc, char *argv[]) { //Run the pro
我是一名优秀的程序员,十分优秀!