snoop,spy实用程序,使用一些强大的技术(可能某种反射)来检查运行的WPF应用程序。最有趣的是事实上,SNNOP能够读出整个物体结构。

几天前,我下载了窥探源代码并花了一些时间研究内部行为。不幸的是,我找不到窥探是如何做这些事情的,所以我希望任何人都能帮助我。

在工作中,我目前正在编写编码的UI测试框架,如果我访问应用程序的对象结构,那么它将是非常棒的,因为这允许我不仅要求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;
.

这对我来说已经有了很大的帮助,但要发现它也很有意思,窥探如何将自己注入另一个过程。

有帮助吗?

解决方案

您可以使用WPF VisualTreeHelper和/或LogicalTreeHelper来完成窥探功能。一旦掌握了任何Visual元素,就会遍历其整个Visual树,以查看它包含的所有元素。Visual Tree Helper 这里

所以在您的UI测试中,获取主窗口并遍历其Visual树以查找所需的任何元素,然后在该元素上执行所需的任何验证或操作。

此外,您可以使用system.diagnostics.process.mainWindowHandle获取现有进程的Windows句柄,然后使用窗口的句柄创建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一样。

对于一个小型测试框架我构建我注入代码以添加一个小的代理对象,以便我可以轻松控制应用程序(按按钮,更改值,在ViewModels上执行函数)。

上面的答案对我不起作用。似乎有点含糊。我在接受的答案上扩展了这段代码:

    var allProcesses = Process.GetProcesses();
    var filteredProcess = allProcesses.Where(p => p.ProcessName.Contains(ProcessSearchText)).First();
    var windowHandle = filteredProcess.MainWindowHandle;
    var hwndSource = HwndSource.FromHwnd(windowHandle);
.

这个答案似乎更完整,如果接受的答案为任何人工作,就会为别人工作。但是,此代码的最后一行返回NULL。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top