我想用.Net框架替换我当前的UI自动化工具(QTP)。 我需要测试VB6(COM)应用程序。
框架的基础之一是使用表单名称。 到目前为止,我没有找到使用Win API获取此数据的方法。
解决方案只有一个限制因素,解决方案必须依赖.Net代码 - 意思是:不允许使用广告工具。
有没有人熟悉这个主题?
这些链接是我的主要参考资料:
http://msdn.microsoft.com/en-us/library/ms996405(d=printer).aspx
http://blogs.msdn.com/b/brianmcm/archive/2006/01/17/getting-the-winforms-id-of-a-control.aspx
http://blogs.msdn.com/b/brianmcm/archive/2006/01/23/516418.aspx
http://bytes.com/topic/c-sharp/answers/558930-really-need-help-sendmessage-wm_getcontrolname
所有人都建议使用SendMessage来检索表单的数据,但我没有这样做。
我很乐意为这个问题提出任何想法。
非常感谢。
C#代码
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,
}
}