15. maj 2006 - 15:16Der er
8 kommentarer og 1 løsning
Finde et vindue med win32 API
Hej folkens!
Jeg vil gerne lave sådan en lille app der kan klikke på knapper og lave muse kliks osv osv. i andre applikationer.
Såvidt jeg er nået frem til skal man have fat i noget af det gamle Win32 API for at kunne gøre det. Man kan anvende EnumChildWindows, FindWindowEx og sikkert en masse andre. Ud fra dem kan lave en GetClassName GetWindowText så man har noget data så man kan finde vinduet igen.
Men jeg har ikke kunne finde en måde at indentificere et vindue unikt? Sætter man to TextBokse ind på en dialog har de samme classname så hvordan identificere jeg et vindue unikt?
Støv, fibre og metalliske partikler kan påvirke både uptime, levetid og driftssikkerhed. Derfor arbejder flere datacentre systematisk med contamination control.
Du får handles serveret bl.a. ved findwindow og getwindow. Følgende kode finder alle synlige vinduer: IntPtr hWnd = GetTopWindow(null); System.Text.StringBuilder str = new System.Text.StringBuilder(200); while (!hWnd.Equals(IntPtr.Zero)) { if (IsWindowVisible(hWnd)) { GetWindowText(hWnd, str, 200); MessageBox.Show(str.ToString()); } hWnd = GetWindow(hWnd, GW_HWNDNEXT); // Finder næste sibling }
Koden viser blot deres navne, men da du jo har hWnd som er handlet og 100 % unikt, så har du vel hvad du skal bruge. GetWindow, GetTopWindow, IsWindowVisible og GetWindowText er alle win32 API kald og GW_HWNDNEXT er en konstant defineret bl.a. i winuser.h fra C++ (der fandt jeg den anyway ;P)
Problemmet stikker en anelse dybere, den del du har vist der har jeg helt på plads. Men du skal tænke på jeg skal kunne lukke applikationen ned og starte den op igen og så på ny finde vinduet. Det kan du jo ikke gøre ud fra en handle da et vindue får et nt handle hver gang en applikation startes op. Så det man kan finde et vindue ud fra er et ClassName og en Text. Men hvis du tager en alm. .net dialog og smider to tekstbokse på vil du opdage at de begge har samme classname og samme text hvis de begge er tomme. Så jeg skal ud over classname have et eller andet unikt som adskiller de to.
brug, WM_GETCONTROLNAME, og kald dit vindue (textbox eller den control du vil ha' fat i). Søg google på WM_GETCONTROLNAME for at få en beskrivelse af dens virkemåde.
hvis denne kode skal returnere noget du skal bruge skal du nok rette '0' til '\0' i ByteArrayToString metoden.
Så: hvis du skal finde en bestemt kontrol bliver du nok nødt til at løbe alle child kontroller igennem på formen og matche alle kontroller op imod det navn du søger. Men den del har du vist tjek på.. ;)
fuld source code: using System; using System.Text; using System.ComponentModel; using Microsoft.Win32; using System.Runtime.InteropServices;
namespace WindowsApplication1 { /// <summary> /// Summary description for NativeMethods. /// </summary> public class NativeMethods {
[DllImport("kernel32.dll")] public static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId); [DllImport("kernel32.dll")] public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, UIntPtr dwSize, uint flAllocationType, PageProtection flProtect); [DllImport("user32.dll", SetLastError = true)] public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId); [DllImport("kernel32.dll")] public static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, UIntPtr dwSize, uint dwFreeType); [DllImport("kernel32.dll")] public static extern bool CloseHandle(IntPtr hObject); [DllImport("kernel32.dll")] public static extern IntPtr MapViewOfFile(IntPtr hFileMappingObject, uint dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, UIntPtr dwNumberOfBytesToMap); [DllImport("kernel32.dll")] public static extern bool UnmapViewOfFile(IntPtr lpBaseAddress); [DllImport("kernel32.dll", SetLastError = true)] public static extern IntPtr CreateFileMapping(IntPtr hFile, IntPtr lpFileMappingAttributes, PageProtection flProtect, int dwMaximumSizeHigh, int dwMaximumSizeLow, string lpName); [DllImport("user32.dll")] public static extern IntPtr SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam); [DllImport("kernel32.dll")] public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer, UIntPtr nSize, IntPtr lpNumberOfBytesRead); [DllImport("Kernel32.dll", EntryPoint = "RtlMoveMemory", SetLastError = false)] public static extern void MoveMemoryFromByte(IntPtr dest, ref byte src, int size); [DllImport("Kernel32.dll", EntryPoint = "RtlMoveMemory", SetLastError = false)] public static extern void MoveMemoryToByte(ref byte dest, IntPtr src, int size); [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] public static extern int RegisterWindowMessage(string lpString);
//=========== Win95/98/ME Shared memory staff=============== public const int STANDARD_RIGHTS_REQUIRED = 0xF0000; public const short SECTION_QUERY = 0x1; public const short SECTION_MAP_WRITE = 0x2; public const short SECTION_MAP_READ = 0x4; public const short SECTION_MAP_EXECUTE = 0x8; public const short SECTION_EXTEND_SIZE = 0x10; public const int SECTION_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_WRITE | SECTION_MAP_READ | SECTION_MAP_EXECUTE | SECTION_EXTEND_SIZE; public const int FILE_MAP_ALL_ACCESS = SECTION_ALL_ACCESS;
//============NT Shared memory constant====================== public const short PROCESS_VM_OPERATION = 0x8; public const short PROCESS_VM_READ = 0x10; public const short PROCESS_VM_WRITE = 0x20; public const long PROCESS_ALL_ACCESS = 0x1F0FFF; public const short MEM_COMMIT = 0x1000; public const short MEM_RESERVE = 0x2000; public const short MEM_DECOMMIT = 0x4000; public const int MEM_RELEASE = 0x8000; public const int MEM_FREE = 0x10000; public const int MEM_PRIVATE = 0x20000; public const int MEM_MAPPED = 0x40000; public const int MEM_TOP_DOWN = 0x100000;
/// <summary> /// Summary description for WinFormsUtilities. /// </summary> public class WinFormsUtilities { private static int GetControlNameMessage = 0;
public static string GetWinFormsId(IntPtr hWnd) { return XProcGetControlName(hWnd, GetControlNameMessage); }
protected static string XProcGetControlName(IntPtr hwnd, int msg) { //define the buffer that will eventually contain the desired window's WinFormsId
byte[] bytearray = new byte[65535];
//allocate space in the target process for the buffer as shared memory IntPtr bufferMem = IntPtr.Zero; //base address of the allocated region for the buffer IntPtr written = IntPtr.Zero; //number of bytes written to memory IntPtr retHandle = IntPtr.Zero; bool retVal;
//creating and reading from a shared memory region is done differently in Win9x then in newer OSs IntPtr processHandle = IntPtr.Zero; IntPtr fileHandle = IntPtr.Zero;
if (!(Environment.OSVersion.Platform == PlatformID.Win32Windows)) { try { uint size; //the amount of memory to be allocated size = 65536;
if (processHandle.ToInt64() == 0) { throw new Win32Exception(); }
bufferMem = NativeMethods.VirtualAllocEx(processHandle, IntPtr.Zero, new UIntPtr(size), NativeMethods.MEM_RESERVE | NativeMethods.MEM_COMMIT, PageProtection.ReadWrite);
if (bufferMem.ToInt64() == 0) { throw new Win32Exception(); }
//send message to the control's hWnd for getting the specified control name retHandle = NativeMethods.SendMessage(hwnd, msg, new IntPtr(size), bufferMem);
//now read the TVITEM's info from the shared memory location retVal = NativeMethods.ReadProcessMemory(processHandle, bufferMem, bytearray, new UIntPtr(size), written); if (!retVal) { throw new Win32Exception(); } } finally { //free the memory that was allocated retVal = NativeMethods.VirtualFreeEx(processHandle, bufferMem, new UIntPtr(0), NativeMethods.MEM_RELEASE); if (!retVal) { throw new Win32Exception(); } NativeMethods.CloseHandle(processHandle); } } else { try { int size2; //the amount of memory to be allocated size2 = 65536;
fileHandle = NativeMethods.CreateFileMapping(new IntPtr(NativeMethods.INVALID_HANDLE_VALUE), IntPtr.Zero, PageProtection.ReadWrite, 0, size2, null); if (fileHandle.ToInt64() == 0) { throw new Win32Exception(); } bufferMem = NativeMethods.MapViewOfFile(fileHandle, NativeMethods.FILE_MAP_ALL_ACCESS, 0, 0, new UIntPtr(0)); if (bufferMem.ToInt64() == 0) { throw new Win32Exception(); } NativeMethods.MoveMemoryFromByte(bufferMem, ref bytearray[0], size2);
retHandle = NativeMethods.SendMessage(hwnd, msg, new IntPtr(size2), bufferMem);
//read the control's name from the specific shared memory for the buffer NativeMethods.MoveMemoryToByte(ref bytearray[0], bufferMem, 1024);
} finally { //unmap and close the file NativeMethods.UnmapViewOfFile(bufferMem); NativeMethods.CloseHandle(fileHandle); } }
//get the string value for the Control name return ByteArrayToString(bytearray);
eksempel på kald: private void button1_Click(object sender, EventArgs e) { IntPtr hWnd = new IntPtr(0x0001080A); string name = WinFormsUtilities.GetWinFormsId(hWnd); int k = 8;
Du er en skat mester. Var på ved ud i noget EnumChildWindows og så finde ud af hvis der var flere ved samme navn ville jeg bruge index på kontrolen. Men den der løsning er bedre da den tager mindre cpu. Smid et svar.
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.