编程实现RDP登录和SendMessage

3
我需要以编程方式RDP到虚拟机(XP SP3 / .NET3.5 / VS 2008)并进行UI自动化测试(凭据已保存在.rdp文件中)。由于我们的域安全性,我需要以编程方式回答交互式登录的“确定”。在登录后,我能够访问其他对话框窗口并发送消息到按钮等,但我尚未能使我的SendMessage在此初始屏幕上工作。我使用spy++捕获按下Enter键时实际发送的内容,并且似乎可以在运行程序时通过查看spy++日志中的响应来复制这些消息,但无论我在消息中使用什么变量,都没有任何反应。我想知道是否可能以编程方式执行此操作,或者操作系统是否由于安全问题防止此类自动化?在我按下Enter键(在该初始屏幕上似乎任何键都可以)时,我在spy++中看到的消息如下:
WM_KEYDOWN nVirtKey:00FF cRepeat:1 ScanCode:00 fExtended:0 fAltDown:0 fRepeat:0 Up:0
WM_KEYUP   nVirtKey:00FF cRepeat:1 ScanCode:00 fExtended:0 fAltDown:0 fRepeat:1 Up:1

当我运行下面的代码并观察发送到IHWindowClass(hwnd6)窗口的消息时,我发现我向该窗口生成了上述消息。如有帮助将不胜感激!
以下是代码的相关部分:
'UIntPtr ip = new UIntPtr(0x0D); //ENTER
UIntPtr ip2 = new UIntPtr(0xFF); //00FF
UIntPtr kyDwnlParam = new UIntPtr(0x001);
UIntPtr kyUplParam = new UIntPtr(0xc0000001);

// used UISpy to get these class names...
string lpszParentClass = "TscShellContainerClass";
string lpszParentWindow = "test2 - test2 - Remote Desktop Connection";
string lpszClass2 = "TscShellAxHostClass";
string lpszClass3 = "ATL:2D33D580";
string lpszClass4 = "UIMainClass";
string lpszClass5 = "UIContainerClass";
string lpszClass6 = "IHWindowClass";


hWnd2 = FindWindowEx(ParenthWnd, IntPtr.Zero, lpszClass2, IntPtr.Zero);
hWnd3 = FindWindowEx(hWnd2, IntPtr.Zero, lpszClass3, IntPtr.Zero);
hWnd4 = FindWindowEx(hWnd3, IntPtr.Zero, lpszClass4, IntPtr.Zero);
hWnd5 = FindWindowEx(hWnd4, IntPtr.Zero, lpszClass5, IntPtr.Zero);
hWnd6 = FindWindowEx(hWnd5, IntPtr.Zero, lpszClass6, IntPtr.Zero);

string hexValue = hWnd6.ToString("X"); //Convert to hex to use find in spy++

SetForegroundWindow(hWnd6); // for good measure....

// tried this....

SendMessage(hWnd6, (uint)WindowsUtilities.WindowsMessages.WM_KEYDOWN, ip2, kyDwnlParam);
SendMessage(hWnd6, (uint)WindowsUtilities.WindowsMessages.WM_KEYUP, ip2, kyUplParam);

// tried this....

SendMessage(hWnd6, (uint)WindowsUtilities.WindowsMessages.WM_KEYDOWN, ip, kyDwnlParam);
SendMessage(hWnd6, (uint)WindowsUtilities.WindowsMessages.WM_KEYUP, ip, kyUplParam);

// tried this...
SendMessage(hWnd6, (uint)WindowsUtilities.WindowsMessages.WM_CHAR, ip, UIntPtr.Zero);
SendMessage(hWnd6, (uint)WindowsUtilities.WindowsMessages.WM_CHAR, ip, UIntPtr.Zero);'
2个回答

0

正如@Spike所说,您需要发送IME_SETCONTEXT和IME_NOTIFY。 我已经测试了代码,并且它可以获取输入,但是它只发送字母'a',即使我发送VK_A - VK_Z。

                SendMessageKey.SimulateKey.SendMessage((IntPtr)hwnd, SendMessageKey.MessageCode.WM_IME_SETCONTEXT, 0x00000001, 0xc000000f);
                SendMessageKey.SimulateKey.SendMessage((IntPtr)hwnd, SendMessageKey.MessageCode.WM_IME_NOTIFY, 0x00000002, 0x00000000);
                SendMessageKey.SimulateKey.SendMessage((IntPtr)hwnd, SendMessageKey.MessageCode.WM_SETFOCUS, 0x00000000, 0x00000000);

在发送 VK_A(例如)之前,Winspector 还检测到带有未知值/键码 255 的 WM_KEYDOWN + WM_KEYUP。我卡在这里了,很抱歉。 也许你能找出问题所在。


0

你已经接近成功了,还有一些其他的消息需要发送才能使RDP会话准备好接受键盘输入。使用Spy++,你应该已经看到了更多的消息被发送。

我能够通过以下代码将字母'a'输入到记事本窗口(或理论上是RDP会话中的活动窗口):

SendMessage(cWind, (int)WM.IME_SETCONTEXT, new UIntPtr(0x00000001), new UIntPtr(0xC000000F));
SendMessage(cWind, (int)WM.IME_NOTIFY, new IntPtr(0x00000002), new IntPtr(0x00000000));
Thread.Sleep(1);

SendMessage(cWind, (int)WM.SETFOCUS, new UIntPtr(0x00203794), new UIntPtr(0x00000000));
Thread.Sleep(1);
//Random keypress
SendMessage(cWind, (int)WM.KEYDOWN, new UIntPtr(0x000000FF), new UIntPtr(0x00000001));
SendMessage(cWind, (int)WM.KEYUP, new UIntPtr(0x00000041), new UIntPtr(0xC0000001));
Thread.Sleep(1);
//A key presses
SendMessage(cWind, (int)WM.KEYDOWN, new IntPtr(0x00000041), new IntPtr(0x001E0001));
SendMessage(cWind, (int)WM.KEYUP, new UIntPtr(0x00000041), new UIntPtr(0xC01E0001));

可能需要休眠,也可能不需要,但Spy++显示调用返回,因此我在继续之前稍等片刻。您可能还应该“撤消”setfocus/setcontext操作,但对于我的需求来说,这样做已经足够了。(Spy++将揭示详细信息)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接