解决:启用多线程调用webBrowsers函数报错:指定的转换无效

这里就需要委托。 定义一个 委托。加载之后给他绑定一个方法Callback,也就是所说的回掉函数。

然后写一个线程,线程需要一个object 的参数。将你定义的委托当作参数传进线程中的方法。

 在线程中去计时。做成一个while(true)的循环,循环内停十分钟,

然后使用beiginInvoke调用委托,自然会触发主线程中的callback方法。

在callback 方法内,由于是主线程,你就可以对你任意的控件进行操作了 
Thread t = null;//创建线程,用来定时刷新数据。    
         CallBackDelegate cbd = null;
        public delegate void CallBackDelegate();
 
       private void Form1_Load(object sender, EventArgs e)
        {
            cbd = CallBack;//设置回掉函数
        }
 
       private void  Callback()
        {
            //可以对主线程进行操作
        }
    
        private void MyTimmer(object obj)
         {
             try
             {
                 while (true)
                 {
                      Thread.Sleep(5000);// 每次间隔的时间,自己设定
 
                     CallBackDelegate cbd = obj as CallBackDelegate;
 
                     this.BeginInvoke(cbd);//调用回掉。如果需要参数可以加上参数
                    
                 }
             }
             catch
             
             }
         }
 
       有了如上代码,在写一个按钮 作为开始按钮,触发MyTimmer
        private void button1_Click(object sender, EventArgs e)
        {
             t = new Thread(MyTimmer);
            t.IsBackground = true;
            t.Start(cbd);
        }
 参考地址:https://bbs.csdn.net/topics/391818531?page=1
完整代码:

using CodePayPro.Business;
using CodePayPro.Common;
using NSoup;
using NSoup.Nodes;
using NSoup.Select;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using System.Windows.Forms;
using Utility;


namespace CodePayPro.Auto
{
#region 参考资料
//SendMessage:https://blog.csdn.net/chen504390172/article/details/18525823
//
#endregion
public partial class Form1 : Form
{
/*
也就是说你并不能解决在子线程中去控制主窗体控件的问题。
这里就需要委托。 定义一个 委托。加载之后给他绑定一个方法Callback,也就是所说的回掉函数。

然后写一个线程,线程需要一个object 的参数。将你定义的委托当作参数传进线程中的方法。

在线程中去计时。做成一个while(true)的循环,循环内停十分钟,

然后使用beiginInvoke调用委托,自然会触发主线程中的callback方法。

在callback 方法内,由于是主线程,你就可以对你任意的控件进行操作了
*/

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
public Form1()
{
InitializeComponent();
webBrowser1.Navigate("https://consumeprod.alipay.com/record/advanced.htm");
//注册一个事件
webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
this.webBrowser1.ScriptErrorsSuppressed = true;//就不会报脚本错误了
}


Thread t = null;//创建线程,用来定时刷新数据。
//定义一个委托
public delegate void CallBackDelegate();
CallBackDelegate cbd = null;
private void Form1_Load_1(object sender, EventArgs e)
{
//加载之后给他绑定一个方法Callback,也就是所说的回掉函数。
cbd = CallBack;//设置回掉函数
}
//写一个线程,线程需要一个object 的参数。将你定义的委托当作参数传进线程中的方法。
private void MyTimmer(object obj)
{
try
{
while (true)
{
Thread.Sleep(10 * 1000);// 每次间隔的时间,自己设定
CallBackDelegate cbd = obj as CallBackDelegate;
this.BeginInvoke(cbd);//调用回掉。如果需要参数可以加上参数
}
}
catch
{
}
}
/// <summary>
/// 回调函数
/// </summary>
private void CallBack()
{
//可以对主线程进行操作
try
{
//webBrowser1.Navigate("https://consumeprod.alipay.com/record/advanced.htm");
//切换到账号密码登录
HtmlElement ui_nav = webBrowser1.Document.GetElementById("J-loginMethod-tabs");
if (ui_nav != null)
{
ui_nav.Children[1].InvokeMember("click");
}
HtmlElement tbUserId = webBrowser1.Document.GetElementById("J-input-user");//账号
HtmlElement tbPwd = webBrowser1.Document.GetElementById("password_rsainput");//密码
HtmlElement btnSubmit = webBrowser1.Document.GetElementById("J-login-btn");
if (tbUserId != null && tbPwd != null)
{
string payAccount = GetPayVal()[0];
string payPwd = GetPayVal()[1];
if (payAccount.IsNotNullOrEmpty() && payPwd.IsNotNullOrEmpty())
{
tbUserId.SetAttribute("value", payAccount);
tbPwd.SetAttribute("value", payPwd);
btnSubmit.Style = " position: fixed;z-index: inherit;top: 0px;left: 0px;";
if (MoNiclick())
{
btnSubmit.InvokeMember("click");
}
}
}
else
{

AddAlipayTradeData();
}
}
catch (Exception ex)
{
throw;
}
}
private void button1_Click(object sender, EventArgs e)
{
HtmlElement btnSubmit = webBrowser1.Document.GetElementById("J-login-btn");
if (btnSubmit != null)
{
btnSubmit.Style = " position: fixed;z-index: inherit;top: 0px;left: 0px;";
MoNiclick();
btnSubmit.InvokeMember("click");
}
else
{
AddAlipayTradeData();//执行采集数据
}
//定时执行采集交易数据
t = new Thread(MyTimmer);
t.IsBackground = true;
t.Start(cbd);
}
//注册一个事件,实现切换到账密输入的面板,然后输入账密
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
try
{
//切换到账号密码登录
HtmlElement ui_nav = webBrowser1.Document.GetElementById("J-loginMethod-tabs");
ui_nav.Children[1].InvokeMember("click");
string strhtml = webBrowser1.Document.Body.InnerHtml;
HtmlElement tbUserId = webBrowser1.Document.GetElementById("J-input-user");//账号
HtmlElement tbPwd = webBrowser1.Document.GetElementById("password_rsainput");//密码
HtmlElement btnSubmit = webBrowser1.Document.GetElementById("J-login-btn");
if (tbUserId == null || tbPwd == null)
{
return;
}
//赋值
tbUserId.SetAttribute("value", "pingjumy1@pingjumy.com");
tbPwd.SetAttribute("value", "Zz1314520");
//tbUserId.SetAttribute("value", GetPayVal()[0]);
//tbPwd.SetAttribute("value", GetPayVal()[1]);
}
catch (Exception ex)
{
//throw;
}
}
/// <summary>
/// 获取账号密码
/// </summary>
/// <returns></returns>
public List<string> GetPayVal()
{
string txtPath = ConfigurationManager.AppSettings["pay_path"];
string strValue = new CommonFunction().Read(txtPath);
return strValue.Split(',').ToList();
}

/// <summary>
/// 将元素定位到浏览器的左上角,这样程序便快速的找到要点击的元素。
/// </summary>
private bool MoNiclick()
{
int x = 0; // X coordinate of the click
int y = 0; // Y coordinate of the click
IntPtr handle = webBrowser1.Handle;
StringBuilder className = new StringBuilder(100);
while (className.ToString() != "Internet Explorer_Server") // The class control for the browser
{
handle = GetWindow(handle, 5); // Get a handle to the child window
GetClassName(handle, className, className.Capacity);
}
IntPtr lParam = (IntPtr)((y << 16) | x); // The coordinates
IntPtr wParam = IntPtr.Zero; // Additional parameters for the click (e.g. Ctrl)
const uint downCode = 0x201; // Left click down code
const uint upCode = 0x202; // Left click up code

SendMessage(handle, downCode, wParam, lParam); // Mouse button down
SendMessage(handle, upCode, wParam, lParam); // Mouse button up
return true;
}
#region 模拟百度点击搜索
//相关链接:https://blog.csdn.net/yuanzhugen/article/details/40263213
//private void button1_Click(object sender, EventArgs e)
//{
// HtmlDocument doc = this.webBrowser1.Document;
// HtmlElement keyword = doc.GetElementById("kw");
// keyword.InnerText = "冰川时代";
// doc.GetElementById("su").InvokeMember("click");
//}
#endregion
/// <summary>
/// 定时执行采集交易数据
/// </summary>
//public void TimerClick()
//{
// #region 定时器事件

// System.Timers.Timer aTimer = new System.Timers.Timer();
// aTimer.Elapsed += new ElapsedEventHandler(TimedEvent);
// aTimer.Interval = 10 * 1000; //配置文件中配置的秒数
// aTimer.Enabled = true;
// #endregion
//}

//private void TimedEvent(object sender, EventArgs e)
//{
// try
// {
// webBrowser1.Navigate("https://lab.alipay.com/consume/record/items.htm");
// HtmlElement btnSubmit = webBrowser1.Document.GetElementById("J-login-btn");
// if (btnSubmit != null)
// {
// btnSubmit.Style = " position: fixed;z-index: inherit;top: 0px;left: 0px;";
// MoNiclick();
// btnSubmit.InvokeMember("click");
// }
// else
// {
// AddAlipayTradeData();
// }
// }
// catch (Exception ex)
// {
// throw;
// }
//}
//模拟登陆---基本方法
//public bool SubmitAlipay()
//{
// webBrowser1.Navigate("https://lab.alipay.com/consume/record/items.htm");
// //切换到账号密码登录
// HtmlElement ui_nav = webBrowser1.Document.GetElementById("J-loginMethod-tabs");
// ui_nav.Children[1].InvokeMember("click");
// string strhtml = webBrowser1.Document.Body.InnerHtml;
// HtmlElement tbUserId = webBrowser1.Document.GetElementById("J-input-user");//账号
// HtmlElement tbPwd = webBrowser1.Document.GetElementById("password_rsainput");//密码
// HtmlElement btnSubmit = webBrowser1.Document.GetElementById("J-login-btn");
// if (tbUserId == null || tbPwd == null)
// {
// return false;
// }
// //赋值
// tbUserId.SetAttribute("value", "qhtzkj@163.com");
// tbPwd.SetAttribute("value", "Clan1688");
// btnSubmit.InvokeMember("click");
// return true;
//}
private string GetWebClient(string url)
{
string strHTML = "";
WebClient myWebClient = new WebClient();
Stream myStream = myWebClient.OpenRead(url);
StreamReader sr = new StreamReader(myStream, System.Text.Encoding.GetEncoding("GBK"));
strHTML = sr.ReadToEnd();
myStream.Close();
return strHTML;
}
/// <summary>
/// 采集支付宝交易数据
/// </summary>
/// <param name="strhtml"></param>
/// <returns></returns>
public Opresult AddAlipayTradeData()
{
try
{
HtmlElement searchBtn = webBrowser1.Document.GetElementById("J-set-query-form");//搜索查询按钮
searchBtn.InvokeMember("click");
//webBrowser1.Navigate("https://consumeprod.alipay.com/record/advanced.htm");
string strhtml = webBrowser1.Document.Body.InnerHtml;

int startIndex = strhtml.IndexOf("<table");
int endIndex = strhtml.IndexOf("</table>");
string tableHtml = strhtml.Substring(startIndex, endIndex + 8 - startIndex);

Document htmlDoc = NSoupClient.Parse(tableHtml);
Elements trEle = htmlDoc.GetElementsByTag("tbody");
List<Hashtable> hashList = new List<Hashtable>();
foreach (Element item in trEle)
{
foreach (var child in item.Children)
{
if (child.Children[0].ClassName() != "number")
{
break;
}
Hashtable hash = new Hashtable();
for (int i = 0; i < child.Children.Count; i++)
{
hash.Add(child.Children[i].ClassName(), child.Children[i].Text());
}
hashList.Add(hash);
}
}
string strJson = JsonExtend<List<Hashtable>>.ToJson(hashList);
if (hashList.Count > 0)
{
return new AlipayTradeDataBLL().AddRange(hashList);
}
}
catch (Exception ex)
{
return new Opresult() { errcode = -1, errmsg = ex.Message.ToString() };
}
return new Opresult() { errcode = -1, errmsg = "操作失败,请稍后再试" };
}

private void Form1_KeyDown(object sender, KeyEventArgs e)
{

}
}
}

原文地址:https://www.cnblogs.com/xuanhai/p/9243956.html