You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Windows 10更新后VB.NET应用剪贴板访问崩溃问题求助

问题分析

从你提供的dump和代码来看,这个崩溃的根源其实挺清晰的,咱们一步步拆解:

首先看dump里的关键异常码:Second_Chance_Exception_C0000409,它对应的是STATUS_STACK_BUFFER_OVERRUN(栈缓冲区溢出)。这是一个从非托管系统层抛出的异常,你的.NET Try-Catch块根本捕获不到——这就是为什么Visual Studio没返回异常代码、应用直接崩溃的核心原因。

结合场景和代码细节,触发崩溃的因素应该是:

  • Windows 10最新更新修改了剪贴板处理文件拖放列表的底层逻辑,当剪贴板中存在特殊内容(比如超长路径文件、带特殊字符的文件名,或者系统内部的特殊剪贴板格式)时,VB.NET封装的My.Computer.Clipboard.ContainsFileDropList方法在解析数据时触发了栈溢出。
  • 你的定时器周期性轮询剪贴板,频繁的访问操作容易和系统其他进程/服务争抢剪贴板资源,在竞争状态下放大了这个底层兼容性bug。
修复方案

针对这个问题,我给你几个递进的修复思路,从快速止损到彻底解决:

1. 先捕获SEH异常,阻止应用崩溃

原来的Try-Catch只能捕获托管异常,要抓栈溢出这类非托管SEH异常,需要针对性添加捕获逻辑:

Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
    Try
        'Get Clipboard Type
        Select Case True
            Case My.Computer.Clipboard.ContainsFileDropList
                ClipType = "File(s)"
            Case My.Computer.Clipboard.ContainsImage
                ClipType = "Image"
            Case My.Computer.Clipboard.ContainsAudio
                ClipType = "Audio"
            Case My.Computer.Clipboard.ContainsText
                ClipType = "Text"
            Case Else
                ClipType = "Unknown"
        End Select
    Catch ex As System.Runtime.InteropServices.SEHException
        ' 处理栈溢出等非托管异常
        Debug.WriteLine($"SEH Exception: {ex.ToString}")
        ClipType = "Error"
    Catch ex As Exception
        Debug.WriteLine(ex.ToString)
        ClipType = "Error"
    End Try
End Sub

另外,建议在应用启动时注册全局异常捕获事件,兜底处理所有未捕获的异常:

Private Sub MainWindow_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    AddHandler AppDomain.CurrentDomain.UnhandledException, AddressOf UnhandledExceptionHandler
End Sub

Private Sub UnhandledExceptionHandler(sender As Object, e As UnhandledExceptionEventArgs)
    Dim ex As Exception = DirectCast(e.ExceptionObject, Exception)
    Debug.WriteLine($"Unhandled Exception: {ex.ToString}")
    ' 这里可以添加日志记录或弹窗提示
End Sub

2. 改用原生Win32剪贴板API,绕过.NET封装层bug

My.Computer.Clipboard是.NET的高层封装,在新系统下可能存在兼容性问题。改用原生Win32 API直接操作剪贴板,更稳定可靠:
先声明API和常量:

Imports System.Runtime.InteropServices

Public Class ClipboardHelper
    <DllImport("user32.dll", SetLastError:=True)>
    Private Shared Function OpenClipboard(hWndNewOwner As IntPtr) As Boolean
    End Function

    <DllImport("user32.dll", SetLastError:=True)>
    Private Shared Function CloseClipboard() As Boolean
    End Function

    <DllImport("user32.dll", SetLastError:=True)>
    Private Shared Function IsClipboardFormatAvailable(format As Integer) As Boolean
    End Function

    ' 剪贴板格式常量
    Public Const CF_HDROP As Integer = 15 ' 文件拖放列表
    Public Const CF_BITMAP As Integer = 2 ' 图片
    Public Const CF_WAVE As Integer = 12 ' 音频
    Public Const CF_UNICODETEXT As Integer = 13 ' 文本

    Public Shared Function GetClipboardType() As String
        Dim clipType As String = "Unknown"
        Dim retryCount As Integer = 3
        Dim isOpened As Boolean = False

        ' 重试机制,避免剪贴板被占用
        While retryCount > 0 AndAlso Not isOpened
            isOpened = OpenClipboard(IntPtr.Zero)
            If Not isOpened Then
                Threading.Thread.Sleep(100)
                retryCount -= 1
            End If
        End If

        If isOpened Then
            Try
                If IsClipboardFormatAvailable(CF_HDROP) Then
                    clipType = "File(s)"
                ElseIf IsClipboardFormatAvailable(CF_BITMAP) Then
                    clipType = "Image"
                ElseIf IsClipboardFormatAvailable(CF_WAVE) Then
                    clipType = "Audio"
                ElseIf IsClipboardFormatAvailable(CF_UNICODETEXT) Then
                    clipType = "Text"
                End If
            Finally
                CloseClipboard() ' 必须关闭剪贴板释放资源
            End Try
        Else
            clipType = "Unavailable"
        End If

        Return clipType
    End Function
End Class

然后在定时器事件里调用:

Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
    Try
        ClipType = ClipboardHelper.GetClipboardType()
    Catch ex As Exception
        Debug.WriteLine(ex.ToString)
        ClipType = "Error"
    End Try
End Sub

3. 优化剪贴板访问频率,减少资源竞争

如果你的定时器间隔很短(比如几百毫秒),频繁轮询剪贴板很容易和系统其他应用冲突。建议:

  • 把定时器间隔拉长到1-2秒,平衡实时性和稳定性。
  • 或者改为只在窗口激活、用户触发操作时才检查剪贴板,而不是无差别轮询。

内容的提问来源于stack exchange,提问作者samgi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:58:39