AccessViolationException与RichTextBox.XNA游戏推出的ScrollToCaret形式

本文关键字:ScrollToCaret 形式 游戏 RichTextBox XNA AccessViolationException | 更新日期: 2023-09-27 17:49:23

我遇到了一个有点令人沮丧的障碍与RichTextBox.ScrollToCaret。我有代码打印消息到RichTextBox。当每条消息被发送到表单时,它被分成多行并格式化,然后每一行被连接起来,结果被发送到RichTextBox.Append。然后,进行以下两个调用来滚动到框的底部:

outputBox.Select(outputBox.Text.Length, 0);
outputBox.ScrollToCaret();

当打印一条消息时,它很好。当打印少量消息时,没有问题。当快速连续打印一堆消息时,它将随机地(在它发生之前打印多少条消息)抛出AccessViolationException("试图读取或写入受保护的内存。这通常表明其他内存损坏了。",详细信息在这里)下一次调用Append时在该框上添加下一条消息。这个只有发生在快速连续做的时候,只有当使用RichTextBox。每次ScrollToCaret。下面的代码可以正常工作:

outputBox.Focus();
outputBox.Select(outputBox.Text.Length, 0);

我还发现,即使捕获了异常并将其丢弃,程序仍然会在下次调用Append时挂起。所以,我假设这是一个问题与实际的代码在RichTextBox。有人有什么想法吗?

如果有人需要,我可以发布更多的代码,但情况真的很基本。需要注意的是,没有多线程(除了固有的UI线程),所以发送消息的对象和接收消息的表单在同一个线程上。而且,这是在。net 4.0下。

我发现了解决这个问题的其他问题,但只提供了一个解决方案,没有真正的解释:AccessViolation发生在RichTextBox.ScrollToCaret中。不幸的是,我在线程方面的经验不是我想要的,所以我无法让他们的解决方案正常工作,但幸运的是,我上面发布的工作很好。

<标题>更新1

所以它看起来经过一些测试,就像它与XNA有关,所以这可能是我对如何与线程一起工作的误解。我无法在纯WinForms应用程序中重现错误,但可以通过简单的XNA游戏轻松完成。我把两个都拉上了拉链给你看。为这个错误道歉。https://dl.dropbox.com/u/16985121/StackOverFlowExamples.zip

AccessViolationException与RichTextBox.XNA游戏推出的ScrollToCaret形式

我也有同样的问题。我有一些不同的情况,但基本相同的问题。我混淆了代码与c++/CLI和c#的形式。

c++/CLI中的一个线程调用c#形式的函数,在richtextbox上打印消息。

慢慢地调用这个函数是可以的。但是,如果调用函数发生的非常快,经常,程序随机崩溃。

这是我的代码。
void PrintOutLog(System::String^ s)
    {
        Monitor::Enter(this->richTextBox_LogBox);
        try
        {
            if(this->richTextBox_LogBox->InvokeRequired)
            {
                AddListItem^ d = gcnew AddListItem(this, &PrintOutLog);
                array<Object^>^ myStringArray = {s};
                this->richTextBox_LogBox->BeginInvoke(d, myStringArray);
            }
            else
            {                
                this->richTextBox_LogBox->AppendText(s + "'n");
                this->richTextBox_LogBox->SelectionStart = this->richTextBox_LogBox->Text->Length;
                this->richTextBox_LogBox->ScrollToCaret();
            }
        }
        finally
        {
            Monitor::Exit(this->richTextBox_LogBox);
        }
    }

如果我注释掉后面的两行代码,程序不会因为内存访问冲突而崩溃。

this->richTextBox_LogBox->SelectionStart = this->richTextBox_LogBox->Text->Length;
this->richTextBox_LogBox->ScrollToCaret();

如果我把这两行注释掉,那么当c#表单没有焦点时,richtextbox不会在文本框的末尾显示新的日志消息。

我可以使用你的解决方案,即在放置文本之前获得焦点,但如果我这样做,它总是停留在我最需要保持的其他窗口的顶部。所以我不能那样做。

我查了MSDN页面http://msdn.microsoft.com/en-us/library/system.windows.forms.textboxbase.scrolltocaret.aspx,发现页面中间写着:

如果控件没有焦点,或者插入符号已经位于控件的可见区域,则此方法不起作用。

但我认为这不是真的。似乎当ScrollToCaret()被调用时,焦点不在richtextbox控件上,我可以看到richtextbox的滚动条在获得新消息时向下移动,这意味着它打印消息并更新,即使它没有焦点。

我试图锁定richtextbox是安全的多线程,但它没有解决访问冲突的问题。除了使用focus()函数之外,如果有其他解决方案来解决这个问题就太好了。

谢谢。

在这里发现了另一个问题,这给了我一种完全规避问题的方法,以产生相同的输出,而不会出现任何问题:https://stackoverflow.com/a/8562457/568042

public delegate void WriteLogEntryDelegate(string log_entry);
    void WriteLogEntryCB(string log_entry)
    {
        if (richTextBox1.InvokeRequired == true)
        {
            var d = new WriteLogEntryDelegate(WriteLogEntryCB);
            this.Invoke(d, log_entry);
        }
        else
        {
            richTextBox1.AppendText(log_entry + "'r'n");
            this.richTextBox1.SelectionStart = this.richTextBox1.Text.Length;
            this.richTextBox1.ScrollToCaret();
        }
    }