none
在执行Invoke出现"索引超出了数组界限。" RRS feed

  • 问题

  •     public static class PublicData
        {
            public static class Behavior
            {
                public const string Delay = "delay";
                public const string Click = "click";
                public const string ifexist = "ifexist";
                public const string ifnotexist = "ifnotexist";
                public const string exist = "exist";
            }
            public static class ElementSearchType
            {
                public const string ID = "id";
                public const string InnerText = "innertext";
                public const string OuterText = "outertext";
                public const string OuterHtml = "outerhtml";
            }
            public static class RegString
            {
                public const string sRegDelay = @"^delay[\p{Z}]+(?<Time>\d+)$";
                public const string sRegClick = @"^click[\p{Z}]+(?<SearchType>id|innertext|outertext|outerhtml)[\p{Z}]+(?<SearchContent>[\S\p{Z}]+)$";
                public const string sRegIfGoto = @"^(?<IfType>ifexist|ifnotexist)[\p{Z}]+(?<Condition>[\S\p{Z}]+)[\p{Z}]+goto[\p{Z}]+(?<label>\S+)$";
                public const string sRegLabel = @"^(?<Label>\S+):$";
                public const string sRegExist = @"^(?<SearchType>id|innertext|outertext|outerhtml)[\p{Z}]+(?<SearchContent>[\S\p{Z}]+)$";
                public const string sRegRandomGoto = @"^random[\p{Z}]+(?<Ratio>\d+(\.\d+)?)[\p{Z}]+goto[\p{Z}]+(?<Label>\S+)$";
            }
        }
        /// <summary>
        /// 游戏管控
        /// </summary>
        public class GameController
        {
            private delegate void StatementExecuseHandle(string Statement);
            int iIndex;
            bool blIsAutoAttack = false;
            System.Threading.Thread thrdAutoAttack;
            string[] sScriptContent;
            WebBrowser webBrowser;
            volatile int iCurrentStep;
            volatile bool blShouldWait;
            volatile int iDelay;
            Random rndRandom;
            System.Text.RegularExpressions.Regex reDelay;
            System.Text.RegularExpressions.Regex reClick;
            System.Text.RegularExpressions.Regex reIfGoto;
            System.Text.RegularExpressions.Regex reLabel;
            System.Text.RegularExpressions.Regex reExist;
            System.Text.RegularExpressions.Regex reRandomGoto;
            public GameController(int index)
            {
                iIndex = index;
                Initial();
            }
            public GameController(int index, WebBrowser Browser, string[] ScriptContent)
            {
                iIndex = index;
                webBrowser = Browser;
                sScriptContent = ScriptContent;
                Initial();
            }
            private void Initial()
            {
                reDelay = new System.Text.RegularExpressions.Regex(PublicData.RegString.sRegDelay, 
                    System.Text.RegularExpressions.RegexOptions.Compiled | System.Text.RegularExpressions.RegexOptions.Multiline | System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                reClick = new System.Text.RegularExpressions.Regex(PublicData.RegString.sRegClick, 
                    System.Text.RegularExpressions.RegexOptions.Compiled | System.Text.RegularExpressions.RegexOptions.Multiline | System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                reIfGoto = new System.Text.RegularExpressions.Regex(PublicData.RegString.sRegIfGoto, 
                    System.Text.RegularExpressions.RegexOptions.Compiled | System.Text.RegularExpressions.RegexOptions.Multiline | System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                reLabel = new System.Text.RegularExpressions.Regex(PublicData.RegString.sRegLabel, 
                    System.Text.RegularExpressions.RegexOptions.Compiled | System.Text.RegularExpressions.RegexOptions.Multiline | System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                reExist = new System.Text.RegularExpressions.Regex(PublicData.RegString.sRegExist, 
                    System.Text.RegularExpressions.RegexOptions.Compiled | System.Text.RegularExpressions.RegexOptions.Multiline | System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                reRandomGoto = new System.Text.RegularExpressions.Regex(PublicData.RegString.sRegRandomGoto, 
                    System.Text.RegularExpressions.RegexOptions.Compiled | System.Text.RegularExpressions.RegexOptions.Multiline | System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                rndRandom = new Random();
            }
            public void Dispose()
            {
                if (thrdAutoAttack != null)
                    if (thrdAutoAttack.ThreadState != System.Threading.ThreadState.Stopped)
                        thrdAutoAttack.Abort();
                if (webBrowser != null)
                    if (!webBrowser.IsDisposed)
                        webBrowser.Dispose();
            }
            /// <summary>
            /// 是否进行挂机。挂机前应先设置脚本内容
            /// </summary>
            public bool IsAutoAttack
            {
                get
                {
                    return blIsAutoAttack;
                }
                set
                {
                    if (blIsAutoAttack != value)
                    {
                        blIsAutoAttack = value;
                        if (blIsAutoAttack)
                        {
                            iCurrentStep = 0;
                            thrdAutoAttack = new System.Threading.Thread(new System.Threading.ThreadStart(AutoAttack));
                            thrdAutoAttack.Priority = System.Threading.ThreadPriority.BelowNormal;
                            thrdAutoAttack.Start();
                        }
                        else
                        {
                            if (thrdAutoAttack != null)
                                if (thrdAutoAttack.ThreadState != System.Threading.ThreadState.Stopped)
                                    thrdAutoAttack.Abort();
                        }
                    }
                }
            }
            private void AutoAttack()
            {
                iCurrentStep = 0;
                while (blIsAutoAttack)
                {
                    string sCurrentStep = sScriptContent[iCurrentStep].Trim();
                    if (sCurrentStep.Length > 0)
                    {
                        blShouldWait = true;
                        iDelay = 0;
                        ExecuseStatement(sScriptContent[iCurrentStep]);
                        while (blShouldWait) System.Threading.Thread.Sleep(10);
                        if (iDelay > 0) System.Threading.Thread.Sleep(iDelay);
                    }
                    iCurrentStep++;
                    if (iCurrentStep >= sScriptContent.Length) iCurrentStep = 0;
                }
            }
            private void ExecuseStatement(string Statement)
            {
                if (webBrowser.InvokeRequired)
                {
    //下面这句会出错,提示“索引超出了数组界限。” webBrowser.Invoke(new StatementExecuseHandle(ExecuseStatement), new string[] { Statement }); } else { #region 执行脚本 System.Text.RegularExpressions.MatchCollection mcMatches; string sT = Statement; string sTT = string.Empty; mcMatches = reLabel.Matches(sT); if (mcMatches.Count == 0)//标签 { mcMatches = reDelay.Matches(sT); if (mcMatches.Count > 0)//延时 { iDelay = int.Parse(mcMatches[0].Groups["Time"].Value); } else { mcMatches = reIfGoto.Matches(sT); if (mcMatches.Count > 0)//跳转 { bool blShouldJump = false; string sIfType = mcMatches[0].Groups["IfType"].Value; string sCondition = mcMatches[0].Groups["Condition"].Value; string sLabel = mcMatches[0].Groups["Label"].Value; mcMatches = reExist.Matches(sCondition); if (mcMatches.Count > 0) { HtmlElement heT = SearchHtmlElement(mcMatches[0].Groups["SearchContent"].Value, GetSearchType(mcMatches[0].Groups["SearchType"].Value.ToLower())); blShouldJump = sIfType.ToLower() == PublicData.Behavior.ifexist ? (heT != null) : (heT == null); } else { //语法错误 MessageBox.Show(string.Format("在{0}行中\r\n{1}\r\n{2}", new object[] { iCurrentStep, sScriptContent[iCurrentStep], sCondition }), "语法错误"); } if (true)//可以跳转 { int iStepJump= GetLabelIndex(reLabel, sScriptContent, sLabel); if (iStepJump >= 0) { iCurrentStep = iStepJump; } else { //无效的标签被指定 MessageBox.Show(string.Format("在{0}行中\r\n{1}\r\n{2}", new object[] { iCurrentStep, sScriptContent[iCurrentStep], sLabel }), "无效的标签被指定"); } } } else { mcMatches = reClick.Matches(sT); if (mcMatches.Count > 0)//点击 { HtmlElement heT = SearchHtmlElement(mcMatches[0].Groups["SearchContent"].Value, GetSearchType(mcMatches[0].Groups["SearchType"].Value.ToLower())); if (heT != null) { heT.InvokeMember("Click"); } else { IsAutoAttack = false; MessageBox.Show(string.Format("{0}\r\n{1}", new object[] { sT, mcMatches[0].Groups["SearchContent"].Value }), "无效的元素特征"); } } else { mcMatches = reRandomGoto.Matches(sT);//随机跳转 if (mcMatches.Count > 0) { double dblT = rndRandom.NextDouble(); if (dblT > 1 - double.Parse(mcMatches[0].Groups["Ratio"].Value)) { string sLabel = mcMatches[0].Groups["Label"].Value; int iStepJump = GetLabelIndex(reLabel, sScriptContent, sLabel); if (iStepJump >= 0) { iCurrentStep = iStepJump; } else { //无效的标签被指定 MessageBox.Show(string.Format("在{0}行中\r\n{1}\r\n{2}", new object[] { iCurrentStep, sScriptContent[iCurrentStep], sLabel }), "无效的标签被指定"); } } } else { IsAutoAttack = false; MessageBox.Show(string.Format("在{0}行中\r\n{1}", new object[] { iCurrentStep, sScriptContent[iCurrentStep] }), "无效语句"); } } } } } #endregion blShouldWait = false; } } private int GetLabelIndex(System.Text.RegularExpressions.Regex reLabel, string[] sScriptContent, string sLabel) { int I = -1; while (I < sScriptContent.Length) { System.Text.RegularExpressions.Match match = reLabel.Match(sScriptContent[I]); if (match != null) if (match.Groups["Label"].Value == sLabel) break; } return I; } private ElementSearchTypeEnum GetSearchType(string SearchTypeString) { return SearchTypeString == PublicData.ElementSearchType.ID ? ElementSearchTypeEnum.ByID : (SearchTypeString == PublicData.ElementSearchType.InnerText ? ElementSearchTypeEnum.ByInnerText : (SearchTypeString == PublicData.ElementSearchType.OuterText ? ElementSearchTypeEnum.ByOuterText : (SearchTypeString == PublicData.ElementSearchType.OuterHtml ? ElementSearchTypeEnum.ByOuterHtml : ElementSearchTypeEnum.Unknow))); } public WebBrowser Browser { get { return webBrowser; } set { if (webBrowser != value) webBrowser = value; } } /// <summary> /// 脚本内容 /// </summary> public string[] ScriptContent { get { return sScriptContent; } set { IsAutoAttack = false; sScriptContent = value; } } public int index { get { return iIndex; } } /// <summary> /// 查找网页元素 /// </summary> /// <param name="ToSearch">条件字符串</param> /// <param name="SearchType">搜索类型</param> /// <returns>查找结果,无法找到时返回null</returns> public HtmlElement SearchHtmlElement(string ToSearch, ElementSearchTypeEnum SearchType) { HtmlDocument hdToSearch = webBrowser.Document; HtmlElement heT = null; switch (SearchType) { case ElementSearchTypeEnum.ByID://作为id查找 heT = hdToSearch.Body.All[ToSearch]; break; case ElementSearchTypeEnum.ByInnerText://查innertext foreach (HtmlElement heTT in hdToSearch.Body.All) { if (heTT.InnerText == ToSearch) { heT = heTT; break; } } break; case ElementSearchTypeEnum.ByOuterText://查outertext foreach (HtmlElement heTT in hdToSearch.Body.All) { if (heTT.OuterText == ToSearch) { heT = heTT; break; } } break; case ElementSearchTypeEnum.ByOuterHtml://查outerhtml ToSearch = System.Text.RegularExpressions.Regex.Unescape(ToSearch); foreach (HtmlElement heTT in hdToSearch.Body.All) { if (heTT.OuterHtml == ToSearch) { heT = heTT; break; } } break; } return heT; } }

    下面是脚本的内容:
    start:
    click innertext 铜钱;
    delay 10000;
    click id bt_exit;
    delay 500;
    random 0.7 goto start;
    click id chatTab0;
    delay 500;
    random 1 goto start;

    程序出错位置已经在上面标出了。主要出在Ramndom的二句脚本

    2009年9月27日 1:16

答案

全部回复

  • 测试了一下,只要把调用SearchHtmlElement函数的语句屏蔽掉就不会出错。

    为什么?
    2009年9月27日 2:47
  • 也许是你数据库定义的字段大小问题,你的输入值超出了字段范围

    我有几次就是这样
    2009年9月27日 3:11
  • 也许是你数据库定义的字段大小问题,你的输入值超出了字段范围

    我有几次就是这样

    没用到数据库;输入值的字段范围你还是指数据库的吧?我这是在事件调用里出错,涉及到WebBrowser。
    2009年9月27日 3:23
  • 因为在排错的时候把SearchHtmlElement()这个函数屏蔽掉就不会出错,怀疑是线程转换的时候WebBrowser被异线程调用.可仔细检查了代码后,又排除掉这个可能.但为什么会出错呢?
    高手们,都出来吧,别潜水了...
    2009年9月27日 9:18
  • 问题可能出在 hdToSearch.Body.All[ToSearch];这句上,你的ToSearch变量指定的值根本不在HTML文档中,所以导致那个错误。
    你可以编写一个非常简单的HTML页面,然后测试一下你的程序。或者作为测试或调试,你可以遍历“All”里面的控件,看是否存在ToSearch指定的值。

    理解的越多,需要记忆的就越少
    2009年9月27日 12:39
    版主
  • 问题可能出在 hdToSearch.Body.All[ToSearch];这句上,你的ToSearch变量指定的值根本不在HTML文档中,所以导致那个错误。
    你可以编写一个非常简单的HTML页面,然后测试一下你的程序。或者作为测试或调试,你可以遍历“All”里面的控件,看是否存在ToSearch指定的值。

    理解的越多,需要记忆的就越少

    试验过,错不在那句.
    因为我的脚本里所指定的HtmlElement.id都是存在的,所以hdToSearch.Body.All[ToSearch]可以得到相应的HtmlElement.
    另外,hdToSearch.Body.All[ToSearch]不应该出错.如果不存在相应id的HtmlElent,hdToSearch.Body.All[ToSearch]返回的是空值,而不是出错.
    2009年9月27日 13:04
  • 你用一个background worker看看能不能抓住异常

    The following is signature, not part of post
    Please mark the post answered your question as the answer, and mark other helpful posts as helpful.
    Visual C++ MVP
    2009年9月27日 16:53
    版主
  • 试验过了,同样的结果.
    2009年9月27日 17:42
  • 你应该可以在异常抛出那一行断下来。难道你的程序停在的地方是BackgroundWorker.RunWorkerAsync?

    The following is signature, not part of post
    Please mark the post answered your question as the answer, and mark other helpful posts as helpful.
    Visual C++ MVP
    2009年9月27日 17:58
    版主
  • Sorry,停的地方是在老地方:

    webBrowser.Invoke(new StatementExecuseHandle(ExecuseStatement), new string[] { Statement });
    BackgroundWorker.RunWorkerAsync,这句不会出错.
    BackgroundWorker工作完成的事件也不会被激发,因为我的程序
            private void AutoAttack()
            {
                iCurrentStep = 0;
                while (blIsAutoAttack)//在外部设定,如果不为false根本就不会退出这个线程的
                {
                    string sCurrentStep = sScriptContent[iCurrentStep].Trim();
                    if (sCurrentStep.Length > 0)
                    {
                        blShouldWait = true;
                        iDelay = 0;
                        //只要线程不终止,会一直调用ExecuseStatement
                        ExecuseStatement(sScriptContent[iCurrentStep]);
                        //等待脚本解释完成,blShouldWait在脚本解释完成后,在外部设置
                        while (blShouldWait) System.Threading.Thread.Sleep(10);
                        //下面这句在脚本经过解释后,如果需要延时的话,线程休眠
                        if (iDelay > 0) System.Threading.Thread.Sleep(iDelay);
                    }
                    iCurrentStep++;
                    if (iCurrentStep >= sScriptContent.Length) iCurrentStep = 0;
                }
            }
    蒋先生.这种错误以前我也有碰过,现在忘了当时是怎么解决的.以前发生错误的时候是处理大文本,现在是WebBrowser...
    2009年9月28日 9:41
  • 使用了BackgroundWorker后,出错提示是:调用的目标发生了异常。
    出错的位置则跑到Application.Run(new frmMain());

    还是抓不到真正的出错位置.

    2009年9月28日 12:07
  • ecuseStatement(sScriptContent[iCurrentStep]);之前加一句
    Debug.Assert(iCurrentStep< sScriptContent.Length);


    The following is signature, not part of post
    Please mark the post answered your question as the answer, and mark other helpful posts as helpful.
    Visual C++ MVP
    2009年9月28日 16:21
    版主
  • ecuseStatement(sScriptContent[iCurrentStep]);之前加一句
    Debug.Assert(iCurrentStep< sScriptContent.Length);


    蒋先成,虽然不知道加了Debug.Assert()有什么作用,但试了一下.没有任何反应,该出错的还是出错.

    本来我也以为为是ecuseStatement()传递参数的时候出错,所以干脆就把ecuseStatement()传递的参数去掉,改为二个线程都去读写在类定义的变量volatile int iCurrentStep;
    但还是在这里提示出错.
    2009年9月29日 9:17
  • 没有提示断言失败吗?
    那说明索引并没有越界!
    周雪峰
    2009年9月29日 11:21
    版主
  • 数组不可能越界.已经在代码中做了限制了.

    这段代码就只引用了WebBrowser,但从代码中可以看出来,所有的对WebBrowser都是在主线程(也就是WebBrowser所在的线程)完成的.
    所以,现在最大的可能就是WebBrowser在多次调用Document.ExecCommand()方法后产生错误,也就是说,是不是可以得出这样的结论:HtmlDocument.ExecCommand并不是线程安全的?
    2009年9月29日 16:23
  • 哪个高手觉得有能力帮我,可以加我QQ:89608359,我传完整代码.
    2009年9月30日 16:49
  • 已在CSDN解决

    2009年10月1日 14:45