WinApi: Get Control Name of COM Forms

自闭症网瘾萝莉.ら 提交于 2019-12-06 10:17:30

问题


I want to replace my current UI automation tool (QTP) with .Net framework. I need to test VB6 (COM) application.

One of the fundamentals of framework is using the form name. So far I failed to find a way to get this data using Win API.

There is only one constrain for the solution and its that the solution MUST rely on .Net code - meaning: no commercials tools allowed.

Does anyone is familiar with this subject?

These links are my major references:

  1. http://msdn.microsoft.com/en-us/library/ms996405(d=printer).aspx

  2. http://blogs.msdn.com/b/brianmcm/archive/2006/01/17/getting-the-winforms-id-of-a-control.aspx

  3. http://blogs.msdn.com/b/brianmcm/archive/2006/01/23/516418.aspx

  4. http://bytes.com/topic/c-sharp/answers/558930-really-need-help-sendmessage-wm_getcontrolname

All of them suggest to use SendMessage in order to retrieve the form's data, which I failed to do.

I will be happy to for any idea for this issue.

Thank you very much.

The C# code

 public static class VbAdapter : IAdapter
{
    /// <summary>
    /// Gets form internal name (design-time name).
    /// </summary>
    /// <param name="hWnd">Form handle</param>
    /// <returns>string. Form's internal name.</returns>
    public static string GetFormInternalName(IntPtr hWnd)
    {
        int _ctrlNameMsg = 0;
        //_ctrlNameMsg = NativeMethods.RegisterWindowMessage("WM_GETCONTROLNAME"); //For .Net forms
        _ctrlNameMsg = NativeMethods.RegisterWindowMessage("Get_CONTROLNAME"); //for vb6 forms

        return GetControlName(hWnd, _ctrlNameMsg);
    }

    /// <summary>
    /// Get control internal name using its handle.
    /// </summary>
    /// <param name="hWnd">Control handle</param>
    /// <param name="msg">Control Name Message</param>
    /// <returns>string.</returns>
    private static string GetControlName(IntPtr hWnd, int msg)
    {
        //vars

        uint size = 65536; //size of memory to be allocated
        byte[] byteArray = new byte[size]; //win form internal name buffer

        IntPtr bufferMem = IntPtr.Zero; //pointer to memory buffer contain the internal name
        IntPtr written = IntPtr.Zero;          //number of bytes written so far
        IntPtr retHandle = IntPtr.Zero;         //returned handle
        IntPtr hProcess = IntPtr.Zero;       //Process handle
        IntPtr fileHandle = IntPtr.Zero;          //File handle

        bool retVal = false;

        //in case non Win32Nt OS version - throw exception
        if (Environment.OSVersion.Platform != PlatformID.Win32NT)
            throw new Win32Exception("Oprating System is not supportted for this module.\nThis module is supportted on Win32Nt OS only.");
        try
        {
            uint procId = GetProcessIdFromHWnd(hWnd);
            //get process deatails
            hProcess = NativeMethods.OpenProcess(
                WindowsConsts.PROCESS_VM_OPERATION |
                WindowsConsts.PROCESS_VM_READ |
                WindowsConsts.PROCESS_VM_WRITE,
                false,
                procId);

            //Todo: Export to OpenProcess Method in native class
            if (hProcess.ToInt64() == 0) throw new Win32Exception();

            bufferMem = NativeMethods.VirtualAllocEx(hProcess,
                IntPtr.Zero,
                new UIntPtr(size),
                WindowsConsts.MEM_RESERVE | WindowsConsts.MEM_COMMIT,
                NativeMethods.PageProtection.ReadWrite);

            //Todo: Export to OpenProcess Method in native class
            if (hProcess.ToInt64() == 0) throw new Win32Exception();

            //Send message to the control requesting it's name
            retHandle = NativeMethods.SendMessage(hWnd, msg, new IntPtr(size), bufferMem);

            //Get TVITEM from shared memory
            if (!NativeMethods.ReadProcessMemory(hProcess, bufferMem, byteArray, new UIntPtr(size), written))
                throw new Win32Exception();
        }
        catch (Exception)
        {
            throw new Win32Exception();
        }

        return ByteArrayToString(byteArray);
    }

    /// <summary>
    /// Converts byte array to string.
    /// </summary>
    /// <param name="byteArray">The byte array.</param>
    /// <returns>string.</returns>
    private static string ByteArrayToString(byte[] byteArray)
    {
        return Encoding.Unicode.GetString(byteArray).TrimEnd('\0');
    }

    /// <summary>
    /// Get the process id using its handle.
    /// </summary>
    /// <param name="hWnd">The handle</param>
    /// <returns>uint. The process Id.</returns>
    private static uint GetProcessIdFromHWnd(IntPtr hWnd)
    {
        uint pId;
        NativeMethods.GetWindowThreadProcessId(hWnd, out pId);

        return pId;
    }
}
 internal class NativeMethods
{
    [DllImport("kernel32.dll")]
    internal static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle,
        uint dwProcessId);

    [DllImport("kernel32.dll")]
    internal static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress,
        UIntPtr dwSize, uint flAllocationType, PageProtection flProtect);

    [DllImport("user32.dll", SetLastError = true)]
    internal static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

    [DllImport("kernel32.dll")]
    internal static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress,
        UIntPtr dwSize, uint dwFreeType);

    [DllImport("kernel32.dll")]
    internal static extern bool CloseHandle(IntPtr hObject);

    [DllImport("kernel32.dll")]
    internal static extern IntPtr MapViewOfFile(IntPtr hFileMappingObject, uint
        dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow,
        UIntPtr dwNumberOfBytesToMap);

    [DllImport("kernel32.dll")]
    internal static extern bool UnmapViewOfFile(IntPtr lpBaseAddress);

    [DllImport("kernel32.dll", SetLastError = true)]
    internal static extern IntPtr CreateFileMapping(IntPtr hFile,
        IntPtr lpFileMappingAttributes, PageProtection flProtect, int dwMaximumSizeHigh,
        int dwMaximumSizeLow, string lpName);

    [DllImport("user32.dll")]
    internal static extern IntPtr SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

    [DllImport("kernel32.dll")]
    internal static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress,
        [Out] byte[] lpBuffer, UIntPtr nSize, IntPtr lpNumberOfBytesRead);

    [DllImport("Kernel32.dll", EntryPoint = "RtlMoveMemory", SetLastError = false)]
    internal static extern void MoveMemoryFromByte(IntPtr dest, ref byte src, int size);

    [DllImport("Kernel32.dll", EntryPoint = "RtlMoveMemory", SetLastError = false)]
    internal static extern void MoveMemoryToByte(ref byte dest, IntPtr src, int size);

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    internal static extern int RegisterWindowMessage(string lpString);

    [Flags]
    internal enum PageProtection : uint
    {
        NoAccess = 0x01,
        Readonly = 0x02,
        ReadWrite = 0x04,
        WriteCopy = 0x08,
        Execute = 0x10,
        ExecuteRead = 0x20,
        ExecuteReadWrite = 0x40,
        ExecuteWriteCopy = 0x80,
        Guard = 0x100,
        NoCache = 0x200,
        WriteCombine = 0x400,
    }
}

来源:https://stackoverflow.com/questions/9151892/winapi-get-control-name-of-com-forms

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!