selenium - 在 Windows 窗体中嵌入 Selenium ChromeDriver
问题描述
我想将 Selenium 嵌入到ChromeDriver
Windows 窗体面板中。我已经成功地按照这个示例将记事本嵌入到 Windows 窗体中。我认为我遇到问题的问题是MainWindowHandle
从ChromeDriver
. 这是我到目前为止所得到的:(完整代码的pastebin链接:https ://pastebin.com/RNv2vbJ1 )
//----------------------TEST---------------------
ChromeDriverService service = ChromeDriverService.CreateDefaultService();
service.HideCommandPromptWindow = true;
ChromeDriver driver = new ChromeDriver(service);
Console.WriteLine(driver.CurrentWindowHandle);
Process chromeDriverProcess = Process.GetProcessById(service.ProcessId);
//EmbeddedWindowHandle = driver.CurrentWindowHandle;
//----------------------TEST---------------------
ProcessStartInfo processInfo = new ProcessStartInfo("notepad.exe");
Process p = Process.Start(processInfo);
p.WaitForInputIdle();
EmbeddedWindowHandle = p.MainWindowHandle;
SetParent(EmbeddedWindowHandle, panel1.Handle);
MoveWindow(EmbeddedWindowHandle, 0, 0, panel1.Width, panel1.Height, true);
SetWindowLong(EmbeddedWindowHandle, GWL_STYLE, WS_VISIBLE);
解决方案
因此,嵌入控制台应用程序与您的方法有些相似,但并不相同。我发现很多线程说这是不可能的或不起作用
使用 Visual Basic 在 Windows 窗体中嵌入 DOS 控制台
并且有以下链接可以创建您自己的控件作为 CMD
https://www.codeproject.com/Articles/335909/Embedding-a-Console-in-aC-Application
但我终于设法让下面的代码工作
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
private IntPtr cmdPtr;
private int ConsoleWidth;
private IntPtr folderViewPtr;
private const int SWP_NOOWNERZORDER = 0x200;
private const int SWP_NOREDRAW = 0x8;
private const int SWP_NOZORDER = 0x4;
private const int SWP_SHOWWINDOW = 0x0040;
private const int WS_EX_MDICHILD = 0x40;
private const int SWP_FRAMECHANGED = 0x20;
private const int SWP_NOACTIVATE = 0x10;
private const int SWP_ASYNCWINDOWPOS = 0x4000;
private const int SWP_NOMOVE = 0x2;
private const int SWP_NOSIZE = 0x1;
private const int GWL_STYLE = (-16);
private const int GWL_EXSTYLE = (-20);
private const int WS_VISIBLE = 0x10000000;
private const int WM_CLOSE = 0x10;
private const int WS_CHILD = 0x40000000;
public abstract class WS
{
public const uint WS_OVERLAPPED = 0x00000000;
public const uint WS_POPUP = 0x80000000;
public const uint WS_CHILD = 0x40000000;
public const uint WS_MINIMIZE = 0x20000000;
public const uint WS_VISIBLE = 0x10000000;
public const uint WS_DISABLED = 0x08000000;
public const uint WS_CLIPSIBLINGS = 0x04000000;
public const uint WS_CLIPCHILDREN = 0x02000000;
public const uint WS_MAXIMIZE = 0x01000000;
public const uint WS_CAPTION = 0x00C00000; /* WS_BORDER | WS_DLGFRAME */
public const uint WS_BORDER = 0x00800000;
public const uint WS_DLGFRAME = 0x00400000;
public const uint WS_VSCROLL = 0x00200000;
public const uint WS_HSCROLL = 0x00100000;
public const uint WS_SYSMENU = 0x00080000;
public const uint WS_THICKFRAME = 0x00040000;
public const uint WS_GROUP = 0x00020000;
public const uint WS_TABSTOP = 0x00010000;
public const uint WS_MINIMIZEBOX = 0x00020000;
public const uint WS_MAXIMIZEBOX = 0x00010000;
public const uint WS_TILED = WS_OVERLAPPED;
public const uint WS_ICONIC = WS_MINIMIZE;
public const uint WS_SIZEBOX = WS_THICKFRAME;
public const uint WS_TILEDWINDOW = WS_OVERLAPPEDWINDOW;
// Common Window Styles
public const uint WS_OVERLAPPEDWINDOW =
(WS_OVERLAPPED |
WS_CAPTION |
WS_SYSMENU |
WS_THICKFRAME |
WS_MINIMIZEBOX |
WS_MAXIMIZEBOX);
public const uint WS_POPUPWINDOW =
(WS_POPUP |
WS_BORDER |
WS_SYSMENU);
public const uint WS_CHILDWINDOW = WS_CHILD;
//Extended Window Styles
public const uint WS_EX_DLGMODALFRAME = 0x00000001;
public const uint WS_EX_NOPARENTNOTIFY = 0x00000004;
public const uint WS_EX_TOPMOST = 0x00000008;
public const uint WS_EX_ACCEPTFILES = 0x00000010;
public const uint WS_EX_TRANSPARENT = 0x00000020;
//#if(WINVER >= 0x0400)
public const uint WS_EX_MDICHILD = 0x00000040;
public const uint WS_EX_TOOLWINDOW = 0x00000080;
public const uint WS_EX_WINDOWEDGE = 0x00000100;
public const uint WS_EX_CLIENTEDGE = 0x00000200;
public const uint WS_EX_CONTEXTHELP = 0x00000400;
public const uint WS_EX_RIGHT = 0x00001000;
public const uint WS_EX_LEFT = 0x00000000;
public const uint WS_EX_RTLREADING = 0x00002000;
public const uint WS_EX_LTRREADING = 0x00000000;
public const uint WS_EX_LEFTSCROLLBAR = 0x00004000;
public const uint WS_EX_RIGHTSCROLLBAR = 0x00000000;
public const uint WS_EX_CONTROLPARENT = 0x00010000;
public const uint WS_EX_STATICEDGE = 0x00020000;
public const uint WS_EX_APPWINDOW = 0x00040000;
public const uint WS_EX_OVERLAPPEDWINDOW = (WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE);
public const uint WS_EX_PALETTEWINDOW = (WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST);
//#endif /* WINVER >= 0x0400 */
//#if(_WIN32_WINNT >= 0x0500)
public const uint WS_EX_LAYERED = 0x00080000;
//#endif /* _WIN32_WINNT >= 0x0500 */
//#if(WINVER >= 0x0500)
public const uint WS_EX_NOINHERITLAYOUT = 0x00100000; // Disable inheritence of mirroring by children
public const uint WS_EX_LAYOUTRTL = 0x00400000; // Right to left mirroring
//#endif /* WINVER >= 0x0500 */
//#if(_WIN32_WINNT >= 0x0500)
public const uint WS_EX_COMPOSITED = 0x02000000;
public const uint WS_EX_NOACTIVATE = 0x08000000;
//#endif /* _WIN32_WINNT >= 0x0500 */
}
public Form1()
{
InitializeComponent();
this.Width = 700;
this.ConsoleWidth = this.Width;
folderViewPtr = FindWindow("Progman", null);
folderViewPtr = FindWindowEx(folderViewPtr, IntPtr.Zero, "SHELLDLL_DefView", null);
folderViewPtr = FindWindowEx(folderViewPtr, IntPtr.Zero, "SysListView32", "FolderView");
//SetWindowLong(this.Handle, -8, (int)folderViewPtr); //GWL_HWNDPARENT
Process p = Process.Start("cmd.exe", "/k cd %userprofile%\\desktop");
Thread.Sleep(500); // Allow the process to open it's window
cmdPtr = p.MainWindowHandle;
SetParent(cmdPtr, this.Handle);
SetWindowLong(this.Handle, -20, (int)(GetWindowLong(this.Handle, -20) | WS.WS_CLIPCHILDREN ));
// Remove border and whatnot
SetWindowLong(cmdPtr, GWL_STYLE, (int)(WS.WS_VISIBLE ));
long exStyle = GetWindowLong(p.MainWindowHandle, GWL_EXSTYLE);
exStyle &= ~(WS.WS_EX_APPWINDOW | WS.WS_EX_CLIENTEDGE);
SetWindowLong(p.MainWindowHandle, GWL_EXSTYLE, (int)0);
MoveWindow(cmdPtr, -2, -2, this.ConsoleWidth, this.Height, true);
SetWindowPos(this.Handle, (IntPtr)1, this.Left, this.Top, this.Width, this.Height, 0);
timer1.Start();
}
protected override void WndProc(ref Message message)
{
const int WM_SYSCOMMAND = 0x0112;
const int SC_MOVE = 0xF010;
const int WM_WINDOWPOSCHANGING = 0x0046;
switch (message.Msg)
{
case WM_SYSCOMMAND:
int command = message.WParam.ToInt32() & 0xfff0;
if (command == SC_MOVE)
{
//return;
}
break;
case WM_WINDOWPOSCHANGING:
SetWindowPos(this.Handle, (IntPtr)1, this.Left, this.Top, this.Width, this.Height, 0x0004);
Debug.Print("WM_WINDOWPOSCHANGING");
break;
}
base.WndProc(ref message);
}
protected override void OnResize(EventArgs e)
{
if (this.cmdPtr != IntPtr.Zero)
{
MoveWindow(cmdPtr, 0, 0, this.ConsoleWidth, this.Height, true);
}
base.OnResize(e);
}
protected override void OnHandleDestroyed(EventArgs e)
{
if (cmdPtr != IntPtr.Zero)
{
PostMessage(cmdPtr, 0x0010, 0, 0);
}
base.OnHandleDestroyed(e);
}
[DllImport("user32.dll")]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll", SetLastError = true)]
static extern UInt32 GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("User32.dll")]
static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool repaint);
[DllImport("User32.dll")]
static extern bool PostMessage(IntPtr hWnd, uint message, int wparam, int lparam);
[DllImport("User32.dll")]
static extern void SetActiveWindow(IntPtr hWnd);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool IsWindow(IntPtr hWnd);
[DllImport("user32.dll")]
static extern void SetWindowPos(IntPtr hWnd, IntPtr hWndNew, int x, int y, int cx, int cy, UInt32 uFlags);
[DllImport("user32.dll")]
static extern IntPtr GetActiveWindow();
[DllImport("user32.dll")]
static extern IntPtr GetDesktopWindow();
[DllImport("user32.dll")]
static extern IntPtr WindowFromPoint(int xPoint, int yPoint);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll")]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
static extern IntPtr FindWindowEx(IntPtr hWnd, IntPtr hWndA, string lpClassName, string lpWindowName);
private void Form1_Load(object sender, EventArgs e)
{
this.Left = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Right/2 - this.Width/2;
this.Top = 0;
}
private void timer1_Tick(object sender, EventArgs e)
{
//check if cmd still exists
if (!IsWindow(cmdPtr))
{
Application.Exit();
}
}
}
}
推荐阅读
- androidviewclient - 如果我使用 Androidviewclient 有 x,y 坐标,我如何获取文本
- javascript - 使用 passport-google-oauth 向 req.user 添加其他数据
- linux - Python RegEx 捕获数组名称和大小之间的空白
- java - 回收站视图未显示在片段中
- c++ - 使用数组时可能导致此错误的原因是什么?解决方案?
- jquery - 在作为参数传递时显示 #1 的问题
- c# - 将数据库中的二进制图像显示到网格视图中。
- node.js - 为生物医学应用设计后端和前端架构
- python - 从 CMake 运行 pytest 测试,其中测试和源位于不同的文件夹中
- c# - 在 for-each-loop 中等待异步调用