我正在对依赖项不足(缺少 dll)的应用程序进行自动化测试,并收到以下错误消息:
当测试运行程序终止应用程序时,上面的消息框并没有消失。显然它归 csrss.exe 所有,不能被杀死。
我的问题是,我可以关闭此消息框的唯一方法是手动登录到机器并单击该消息窗口上的 X。还有其他方法吗?
请注意,我可以轻松修复依赖错误,但我想要一种可靠的方法,在遇到此类错误时终止被测应用程序及其所有消息。
首先尝试避免对话框:调用您的测试运行程序,如果加载程序无法解析每个导入SetErrorMode(SEM_FAILCRITICALERRORS)
,这将导致调用静默失败。CreateProcess
如果您想创建一个查询函数以便判断进程是否可以加载,请CREATE_SUSPENDED
在调用时添加标志,如果成功则CreateProcess
调用。TerminateProcess
你可以做下一步:
1) 在会话中获取csrss.exe进程 ID
2) 通过枚举窗口EnumWindows
,对于每个窗口查询它的进程 id ( GetWindowThreadProcessId
),将其与csrss.exe进程 id 进行比较。如果相等 - 获取窗口类名 ( 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
而SystemProcessInformation
不是CreateToolhelp32Snapshot
++ ?因为我们需要获取流程信息。包含成员,而 psapi shell 在此函数上由于未知原因丢弃了这个成员 - - 不在这里- 它丢弃了。当然我们可以通过添加调用来检索,但是这个函数内部通过Id打开进程,用于查询它的SessionId。但是要打开,您需要在您的令牌中启用SeDebugPriviledge(+ 3 次额外调用内核 - 打开进程、查询信息、关闭句柄)Process32First
Process32Next
SessionId
SYSTEM_PROCESS_INFORMATION
ULONG SessionId
PROCESSENTRY32
SessionId
SessionId
ProcessIdToSessionId
csrss.exe