Pregunta

Snoop, la utilidad de espía, utiliza una técnica poderosa (probablemente algún tipo de reflexión) para inspeccionar una aplicación WPF en ejecución.Lo más interesante es el hecho de que SNNOP puede leer la estructura de objeto completa.

Hace unos días descargué el código fuente de Snoop y pasé un tiempo en estudiar el comportamiento interno.Desafortunadamente, no pude averiguar aún cómo Snoop está haciendo estas cosas, así que espero que cualquiera pueda ayudarme.

En el trabajo. Actualmente estoy escribiendo un marco de prueba de UI codificado y sería fantástico si tuviera acceso a las estructuras de objetos de la aplicación porque esto me permitiría no solo afirmar el estado de la UI.

Actualización:

Este es el código necesario:

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;

Esta ya es una gran ayuda para mí, pero también es interesante descubrirlo, cómo Snoop se inyecta en otro proceso.

Otros consejos

Actualización:

De acuerdo, encontré la ubicación del código básico, que se utiliza por Snoop para proporcionar la capacidad de inyección.A mi asombro que el código está escrito C. Probablemente haya una razón para.

y ese es el código (espero que esté bien publicarlo aquí):

//-----------------------------------------------------------------------------
//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 no inspecciona un WPF desde el exterior.Se inyecta en la aplicación y en realidad agrega la ventana magnificante o snoop.Eso también es por qué cuando sale de Snoop, las ventanas de inspección se mantienen abiertas.

Por lo tanto, el código de 'inspección' simplemente inspeccione la ventana que desea y puede usar todas las funciones de WPF disponibles para hacerlo.Al igual que VisualTreeHelper y LogicalTreeHelper, como se mencionó aquí anteriormente.

Para un marco de prueba pequeño que construyo el código inyectado para agregar un pequeño objeto proxy para poder controlar la aplicación fácilmente (presione los botones, cambie valores, ejecute funciones en ViewModels, etc.).

La respuesta anterior no funciona para mí.Parece un poco vago.Me amplié en respuesta aceptada un poco con este código:

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

Esta respuesta parece más completa y funcionará para otros si la respuesta aceptada funciona para cualquier persona.Sin embargo, esta la última línea de este código devuelve nulo para mí.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top