Snoop使用什么技术来检查WPF应用程序
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Snoop使用什么技术来检查WPF应用程序相关的知识,希望对你有一定的参考价值。
间谍实用程序Snoop使用一些强大的技术(可能是某种反射)来检查正在运行的WPF应用程序。最有趣的是,Snnop能够读出整个对象结构。
几天前,我下载了Snoop源代码,并花了一些时间研究内部行为。不幸的是,我还没知道Snoop是如何做这些事情的,所以我希望任何人都可以帮助我。
在工作中我正在编写一个Coded UI Testing-Framework,如果我可以访问应用程序的对象结构,那将是非常棒的,因为这样我不仅可以断言UI状态。
更新:
这是所需的代码:
string filePath = "WpfApp.exe";
AppDomain appDomain = AppDomain.CurrentDomain;
byte[] bytes = System.IO.File.ReadAllBytes(filePath);
Assembly ass = appDomain.Load(bytes);
ass.EntryPoint.Invoke(null, new object[] { });
IntPtr handle = Process.GetCurrentProcess().MainWindowHandle;
Window w = System.Windows.Interop.HwndSource.FromHwnd(handle).RootVisual as Window;
这对我来说已经是一个很大的帮助,但是了解Snoop如何将自己注入另一个进程也很有趣。
您可以使用WPF VisualTreeHelper和/或LogicalTreeHelper来完成Snoop的功能。一旦掌握了任何视觉元素,您几乎可以遍历其整个可视树以查看它包含的所有元素。视觉树帮手here
因此,在UI测试中,抓住主窗口并遍历其可视树以查找所需的任何元素,然后对该元素执行所需的任何验证或操作。
此外,您可以使用System.Diagnostics.Process.MainWindowHandle从现有进程获取窗口句柄,然后使用窗口的句柄创建一个wpf窗口。它已经有一段时间了,所以我不记得具体细节而不做更多的研究。以下代码可能会有所帮助:
Window window = (Window)System.Windows.Interop.HwndSource.FromHwnd(process.MainWindowHandle).RootVisual;
更新:
好的,我找到了Snoop用来提供注入能力的基本代码位置。让我惊讶的是代码写的C.可能有一个原因。
这就是代码(我希望可以在这里发布):
//-----------------------------------------------------------------------------
//Spying Process functions follow
//-----------------------------------------------------------------------------
void Injector::Launch(System::IntPtr windowHandle, System::String^ assembly, System::String^ className, System::String^ methodName)
{
System::String^ assemblyClassAndMethod = assembly + "$" + className + "$" + methodName;
pin_ptr<const wchar_t> acmLocal = PtrToStringChars(assemblyClassAndMethod);
HINSTANCE hinstDLL;
if (::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)&MessageHookProc, &hinstDLL))
{
LogMessage("GetModuleHandleEx successful", true);
DWORD processID = 0;
DWORD threadID = ::GetWindowThreadProcessId((HWND)windowHandle.ToPointer(), &processID);
if (processID)
{
LogMessage("Got process id", true);
HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID);
if (hProcess)
{
LogMessage("Got process handle", true);
int buffLen = (assemblyClassAndMethod->Length + 1) * sizeof(wchar_t);
void* acmRemote = ::VirtualAllocEx(hProcess, NULL, buffLen, MEM_COMMIT, PAGE_READWRITE);
if (acmRemote)
{
LogMessage("VirtualAllocEx successful", true);
::WriteProcessMemory(hProcess, acmRemote, acmLocal, buffLen, NULL);
_messageHookHandle = ::SetWindowsHookEx(WH_CALLWNDPROC, &MessageHookProc, hinstDLL, threadID);
if (_messageHookHandle)
{
LogMessage("SetWindowsHookEx successful", true);
::SendMessage((HWND)windowHandle.ToPointer(), WM_GOBABYGO, (WPARAM)acmRemote, 0);
::UnhookWindowsHookEx(_messageHookHandle);
}
::VirtualFreeEx(hProcess, acmRemote, 0, MEM_RELEASE);
}
::CloseHandle(hProcess);
}
}
::FreeLibrary(hinstDLL);
}
}
Snoop不会从外部检查WPF。它将自身注入应用程序,并实际添加放大或窥探窗口。这也是为什么当您退出窥探时,检查窗口实际上保持打开状态。
所以'检查'代码只是检查它想要的窗口,它可以使用所有可用的WPF函数来执行此操作。就像前面提到的VisualTreeHelper和LogicalTreeHelper一样。
对于一个小的测试框架,我构建了我注入的代码来添加一个小代理对象,这样我就可以轻松地控制应用程序(按下按钮,更改值,在视图模型上执行函数等)。
上面的答案对我不起作用。看起来有点模糊。我用这段代码稍微扩展了接受的答案:
var allProcesses = Process.GetProcesses();
var filteredProcess = allProcesses.Where(p => p.ProcessName.Contains(ProcessSearchText)).First();
var windowHandle = filteredProcess.MainWindowHandle;
var hwndSource = HwndSource.FromHwnd(windowHandle);
如果接受的答案适用于任何人,这个答案似乎更完整,并将适用于其他人。但是,这段代码的最后一行为我返回null。
以上是关于Snoop使用什么技术来检查WPF应用程序的主要内容,如果未能解决你的问题,请参考以下文章
是否有适用于 Windows 窗体的 Snoop (WPF) 或 FireBug (ASP.NET) 之类的东西? [关闭]
在 Snoop 中使用 PowerShell 脚本进行更高级的 UI 调试