在.NET中子类化Excel 2010时出现异常

在.NET中子类化Excel 2010时出现异常,excel,vsto,subclassing,Excel,Vsto,Subclassing,我试图从VSTO外接程序中对Excel2010的主窗口进行子类化。当程序关闭时,这会导致异常和Excel崩溃 因此,我创建了一个小示例,在我的机器上重现错误。显然,调用WM_CLOSE时,调用CallWindowProc会引发ThreadAbortException Public Class ThisAddIn Private Const GWL_WNDPROC As Integer = -4 Private Delegate Function WndProcDelegate( _

我试图从VSTO外接程序中对Excel2010的主窗口进行子类化。当程序关闭时,这会导致异常和Excel崩溃

因此,我创建了一个小示例,在我的机器上重现错误。显然,调用WM_CLOSE时,调用CallWindowProc会引发ThreadAbortException

Public Class ThisAddIn

Private Const GWL_WNDPROC As Integer = -4

Private Delegate Function WndProcDelegate( _
    ByVal hWnd As IntPtr, _
    ByVal msg As Int32, _
    ByVal wParam As Int32, _
    ByVal lParam As Int32) As Int32

Private Declare Function SetWindowLong _
    Lib "user32.dll" Alias "SetWindowLongA" ( _
        ByVal hWnd As IntPtr, _
        ByVal nIndex As Int32, _
        ByVal dwNewLong As IntPtr) As Int32

Private Declare Function SetWindowLong _
    Lib "user32.dll" Alias "SetWindowLongA" ( _
        ByVal hWnd As IntPtr, _
        ByVal nIndex As Int32, _
        ByVal dwNewLong As WndProcDelegate) As IntPtr

Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" _
    (ByVal lpPrevWndFunc As IntPtr, ByVal hWnd As IntPtr, ByVal msg As Integer, _
     ByVal wParam As Integer, ByVal lParam As Integer) As Integer

<System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.FunctionPtr)> _
    Private mWndProc As WndProcDelegate

Private mPrevWindowProc As IntPtr

Private Sub ThisAddIn_Startup(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Startup
    mWndProc = New WndProcDelegate(AddressOf SubWndProc)

    mPrevWindowProc = SetWindowLong(New IntPtr(Application.Hwnd), GWL_WNDPROC, mWndProc)
End Sub

Private Sub ThisAddIn_Shutdown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shutdown
    SetWindowLong(New IntPtr(Application.Hwnd), GWL_WNDPROC, mPrevWindowProc)
End Sub

Private Function SubWndProc( _
        ByVal hWnd As IntPtr, _
        ByVal msg As Int32, _
        ByVal wParam As Int32, _
        ByVal lParam As Int32) As Int32

    Try
        Return CallWindowProc(mPrevWindowProc, hWnd, msg, wParam, lParam)
    Catch ex As Exception
        Windows.Forms.MessageBox.Show(ex.ToString)
    End Try
End Function

End Class
公共类此插件
私有常量GWL_WNDPROC作为整数=-4
私有委托函数WndProcDelegate(_
ByVal hWnd作为IntPtr_
ByVal msg作为Int32_
ByVal wParam作为Int32_
ByVal lParam作为Int32)作为Int32
私有声明函数SetWindowLong_
Lib“user32.dll”别名“SetWindowLongA”(_
ByVal hWnd作为IntPtr_
ByVal nIndex作为Int32_
ByVal dwNewLong作为IntPtr)作为Int32
私有声明函数SetWindowLong_
Lib“user32.dll”别名“SetWindowLongA”(_
ByVal hWnd作为IntPtr_
ByVal nIndex作为Int32_
ByVal dwNewLong(作为WNDPROCDERegate)作为IntPtr
专用声明函数CallWindowProc Lib“user32”别名“CallWindowProcA”_
(ByVal lpPrevWndFunc作为IntPtr,ByVal hWnd作为IntPtr,ByVal msg作为整数_
ByVal wParam为整数,ByVal lParam为整数)为整数
_
作为WndProcDelegate的专用mWndProc
作为IntPtr的专用mPrevWindowProc
Private Sub ThisAddIn_Startup(ByVal sender作为对象,ByVal e作为System.EventArgs)处理Me.Startup
mWndProc=新WndProcDelegate(子WNDProc的地址)
mPrevWindowProc=SetWindowLong(新的IntPtr(Application.Hwnd)、GWL_WNDPROC、mWndProc)
端接头
Private Sub ThisAddIn_Shutdown(ByVal sender作为对象,ByVal e作为System.EventArgs)处理Me.Shutdown
SetWindowLong(新的IntPtr(Application.Hwnd)、GWL_WNDPROC、mPrevWindowProc)
端接头
私人职能分部(_
ByVal hWnd作为IntPtr_
ByVal msg作为Int32_
ByVal wParam作为Int32_
ByVal lParam作为Int32)作为Int32
尝试
返回CallWindowProc(mPrevWindowProc、hWnd、msg、wParam、lParam)
特例
Windows.Forms.MessageBox.Show(例如ToString)
结束尝试
端函数
末级
这是发生在我的机器上还是我做错了什么

顺便说一句,如果我在WM_CLOSE或WM_DESTROY事件中恢复WndProc,这没有什么区别,Excel仍然会崩溃


Excel 2010、Windows XP和VS 2008似乎没有简单的解决方案。至少我找到了一个解决方法:在接收WM_CLOSE恢复原始WndProc时,
PostMessage(WM_CLOSE)
(因此它将由WndProc处理)并返回。有些狡猾,如果用户取消保存更改对话框,它会使窗口不分类,但总比什么都没有好。