我正在运行对依赖项不足(缺少dll)的应用程序的自动测试,并收到此错误消息:
当测试运行器杀死应用程序时,上面的消息框不会消失。显然它是由csrss.exe拥有的,不能被杀死。
我的问题是,关闭此消息框的唯一方法是手动登录到该计算机并单击该消息窗口上的X.还有另一种方式吗?
请注意,我可以轻松修复依赖项错误,但是当遇到此类错误时,我希望能够以一种强大的方式终止正在测试的应用程序及其所有消息。
答案 0 :(得分:3)
首先尝试避开对话框:在测试运行器中调用SetErrorMode(SEM_FAILCRITICALERRORS)
,如果加载程序无法解析每个导入,这将导致对CreateProcess
的调用无声地失败。
如果要创建查询函数以便判断进程是否可以加载,请在调用CREATE_SUSPENDED
时添加CreateProcess
标志,如果成功则调用TerminateProcess
。
答案 1 :(得分:1)
你可以做下一步:
1)在会话中获取 csrss.exe 进程ID
2)通过EnumWindows
枚举窗口,对于每个窗口查询,它处理id(GetWindowThreadProcessId
),将其与 csrss.exe 进程ID进行比较。 if equal - 获取窗口类名称(GetClassName
),如果是L"#32770"
- 将WM_CLOSE
消息发送到此窗口
3)如果你想要更精确 - 在找到L"#32770"
窗口类之后,通过GetWindowText
查询窗口标题文本并确保它以"module.exe - "
开头或者你的exe如何命名?
struct FIND_WND_CONTEXT
{
PCWSTR szCaptionBegin;
ULONG lenCaptionBegin;
ULONG dwProcessId;
};
BOOL CALLBACK EnumWndProc(HWND hwnd, FIND_WND_CONTEXT& fwc)
{
ULONG dwProcessId;
if (GetWindowThreadProcessId(hwnd, &dwProcessId) && dwProcessId == fwc.dwProcessId)
{
PWSTR Name = (PWSTR)alloca( max(fwc.lenCaptionBegin * sizeof(WCHAR), sizeof(L"#32770") + sizeof(WCHAR)) );
if (GetClassNameW(hwnd, Name, sizeof(L"#32770") + sizeof(WCHAR)) && !wcscmp(Name, L"#32770"))
{
if (GetWindowText(hwnd, Name, fwc.lenCaptionBegin))
{
_wcslwr(Name);
if (!wcscmp(Name, fwc.szCaptionBegin))
{
PostMessage(hwnd, WM_CLOSE, 0, 0);
}
}
}
}
return TRUE;
}
void CloseTest()
{
const WCHAR module_exe[] = L"module.exe - ";
FIND_WND_CONTEXT fwc = { module_exe, RTL_NUMBER_OF(module_exe) };
if (fwc.dwProcessId = GetMySessionCsrssId())
{
EnumWindows((WNDENUMPROC)EnumWndProc, (LPARAM)&fwc);
}
}
ULONG GetMySessionCsrssId()
{
ULONG cb = 0, rcb = 0x10000;
static volatile UCHAR guz;
PVOID stack = alloca(guz);
union {
PVOID buf;
PBYTE pb;
PSYSTEM_PROCESS_INFORMATION pspi;
};
ULONG SessionId;
ProcessIdToSessionId(GetCurrentProcessId(), &SessionId);
NTSTATUS status;
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
if (0 <= (status = ZwQuerySystemInformation(SystemProcessInformation, buf, cb, &rcb)))
{
ULONG NextEntryOffset = 0;
do
{
pb += NextEntryOffset;
STATIC_UNICODE_STRING(csrss, "csrss.exe");
if (pspi->SessionId == SessionId && RtlEqualUnicodeString(&pspi->ImageName, &csrss, TRUE))
{
return PtrToUlong(pspi->UniqueProcessId);
}
} while (NextEntryOffset = pspi->NextEntryOffset);
return 0;
}
} while (status == STATUS_INFO_LENGTH_MISMATCH);
return 0;
}
有人当然会问 - 为什么要使用“无证件”,(“不再可用”(这直接在于msdn - 从win200到最新的win10 1703),“不支持”,等等)ZwQuerySystemInformation
和{ {1}}代替SystemProcessInformation
+ CreateToolhelp32Snapshot
+ Process32First
?因为我们需要获得进程的Process32Next
信息。 SYSTEM_PROCESS_INFORMATION
包含SessionId
成员的PROCESSENTRY32
,而psapi shell因此原因未知原因会删除此成员 - ProcessIdToSessionId
- 此处ULONG SessionId
- 它已丢弃。当然我们可以通过添加对Tabs or spaces?的调用来检索SessionId
,但是这个函数在内部通过Id打开进程,用于查询SessionId。但是对于open SessionId
,你需要在你的toke中启用 SeDebugPriviledge (+ 3额外调用内核 - 打开进程,查询信息,关闭句柄)