スヌープはWPFアプリケーションの検査にどのようなテクニックを使用しますか
-
21-12-2019 - |
質問
Snoop、Spyユーティリティは、実行中のWPFアプリケーションを調べるために、いくつかの強力なテクニック(おそらく何らかの反射)を使用します。ほとんどの興味深いは、SNNOPがオブジェクト構造全体を読み出すことができるという事実です。
数日前、私はスヌープソースコードをダウンロードし、内部行動を勉強することにしばらく時間を費やしました。残念なことに、私はまだスヌープがこれらのことをどのようにしているかを見つけることができなかったので、誰かが私を助けることができることを願っています。
職場では現在コード化された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 VisualTrehelperおよび/またはLogicalTreeHelperを使用してスヌープを実行することができます。ビジュアル要素を保持したら、それが含まれているすべての要素を見るためにビジュアルツリー全体をほとんどトラバースすることができます。ビジュアルツリーヘルパー
soあなたのUIテストでは、メインウィンドウをつかみ、目的の要素を見つけてその要素に必要な検証や操作を実行するためにその視覚的ツリーを通過してから実行します。
Window window = (Window)System.Windows.Interop.HwndSource.FromHwnd(process.MainWindowHandle).RootVisual;
. 他のヒント
更新:
大丈夫、私は射出能力を提供するためにスヌープによって使用される基本的なコードの場所を見つけました。コードが書かれている私の驚くべきことには、おそらく理由があります。
そしてそれはコードです(私はそれがここで投稿しても大丈夫だと思います):
//-----------------------------------------------------------------------------
//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);
}
}
. スヌープは外部からWPFを検査しません。それはそれ自身をアプリケーションに注意して、実際に拡大またはスヌープウィンドウをそれに追加します。それはまた、スヌープを終了したとき、検査窓が実際に開いているままにしたのか。
だから「検査」コードはそれが望むウィンドウを調べ、それがそうするためにすべてのAvaible WPF関数を使用することができます。ここで述べたように、VisualTrehelperとLogicalTrehelperのように。
小さなテストフレームワークの場合、私は小さなプロキシオブジェクトを追加するために挿入されたコードを構築するので、私は簡単にアプリケーションを制御することができます(ボタンを押して、値の変更、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を返します。