2017-02-13 66 views
0

诊断AccessViolationException我有一个在VS2015和.Net 4.5.2在优化的编译的代码

运行当编译和调试未优化运行,那么它的工作原理确定一个大的vb.net 86项目。但是,如果我在优化开启的情况下编译并在Release模式下运行它,那么我会在同一个无害的代码行中得到各种异常。我试图在发布模式下调试它,但是断点是不可靠的。此外,调试它的行为似乎修改了异常。此外,如果我更改代码(例如,将MsgBox放入以显示信息),则问题可能会消失。例如,我将Arraylist更改为List(Of Control),并且问题不再出现在之前的地方,而是现在移到其他地方。

我已收到所有在不同的时间如下: AccessViolationException, 的NullReferenceException(内某处.NET类深) 和FatalExecutionEngineError

在AccessViolationException异常详细信息告诉任何不同之处在于“这是经常的指示其他内存已损坏“。堆栈跟踪没有意义,没有描述它在无效内存地址上的内容。

我也找不到有关编译器中的优化的实际内容的任何有意义的细节 - 一种解决方案可能是关闭优化,但我不明白这样做的好处/负面影响。

优化不可靠吗?如何能够试图确定发生了什么?

我们使用的唯一非托管代码是一些调用来获取与文件扩展相关的图标 - 然后将其克隆到托管对象中,并销毁非托管内存。这是非常标准的,并且从1.1到4.5.2使用了相同的API 10年,而没有发生过这种情况。

我不能创建一个小的项目,再现问题

下面是我们用来提取图标作为它的唯一的潜在原因我现在的代码。它是从别处借来的,我不能确定它是否应该如此好:

Public Class IconExtractor 

<Flags()> Private Enum SHGFI 
    SmallIcon = &H1 
    LargeIcon = &H0 
    Icon = &H100 
    DisplayName = &H200 
    Typename = &H400 
    SysIconIndex = &H4000 
    UseFileAttributes = &H10 
End Enum 

<StructLayout(LayoutKind.Sequential)> 
Private Structure SHFILEINFO 
    Public hIcon As IntPtr 
    Public iIcon As Integer 
    Public dwAttributes As Integer 
    <MarshalAs(UnmanagedType.LPStr, SizeConst:=260)> Public szDisplayName As String 
    <MarshalAs(UnmanagedType.LPStr, SizeConst:=80)> Public szTypeName As String 

    Public Sub New(ByVal B As Boolean) 
     hIcon = IntPtr.Zero 
     iIcon = 0 
     dwAttributes = 0 
     szDisplayName = vbNullString 
     szTypeName = vbNullString 
    End Sub 
End Structure 

Private Declare Auto Function SHGetFileInfo Lib "shell32" (
ByVal pszPath As String, ByVal dwFileAttributes As Integer, 
ByRef psfi As SHFILEINFO, ByVal cbFileInfo As Integer, ByVal uFlags As SHGFI) As Integer 

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

Public Shared Sub GetIconsForFile(ByVal rstrFileName As String, ByRef rzSmallIcon As Icon, ByRef rzLargeIcon As Icon) 
    Dim zFileInfo As New SHFILEINFO(True) 
    Dim cbSizeInfo As Integer = Marshal.SizeOf(zFileInfo) 
    Dim flags As SHGFI = SHGFI.Icon Or SHGFI.UseFileAttributes Or SHGFI.SmallIcon 
    SHGetFileInfo(rstrFileName, 256, zFileInfo, cbSizeInfo, flags) 
    ' Use clone so we can destroy immediately 
    rzSmallIcon = DirectCast(Icon.FromHandle(zFileInfo.hIcon).Clone, Icon) 
    DestroyIcon(zFileInfo.hIcon) 

    zFileInfo = New SHFILEINFO(True) 
    cbSizeInfo = Marshal.SizeOf(zFileInfo) 
    flags = SHGFI.Icon Or SHGFI.UseFileAttributes Or SHGFI.LargeIcon 
    SHGetFileInfo(rstrFileName, 256, zFileInfo, cbSizeInfo, flags) 
    ' Use clone so we can destroy immediately 
    rzLargeIcon = DirectCast(Icon.FromHandle(zFileInfo.hIcon).Clone, Icon) 
    DestroyIcon(zFileInfo.hIcon) 
End Sub 
End Class 

回答

0

我偶然发现了这个解决方案。

我读的SHGetFileInfo 本文档https://msdn.microsoft.com/en-us/library/windows/desktop/bb762179(v=vs.85).aspx ,发现它在言论说:你应该叫从后台线程此功能。如果不这样做可能会导致用户界面停止响应

目前尚不清楚为什么应该说是从后台线程也不是清楚什么“停止响应”实际上可能本身表现为。

但是,它似乎很可能是什么导致了问题,所以我重构了在单独的线程下执行api调用。这似乎工作。 SHGETFILEINFO的互联网上的许多例子似乎没有考虑单独的线程要求。

我复制了整个重构的代码在这里:

Imports System.Drawing 
Imports System.Runtime.InteropServices 
Imports System.Threading 

''' <summary> 
''' Retrieves the small and large icons registered for a filename based on the file's extension 
''' </summary> 
Public Class FileIcons 

    Private mFileName As String 
    Private mSmallIconHandle As IntPtr 
    Private mSmallIcon As Icon 
    Private mLargeIconHandle As IntPtr 
    Private mLargeIcon As Icon 

    Public Sub New(ByVal rFileName As String) 
     mFileName = rFileName 

     Dim t As New Thread(AddressOf GetIconsForFile) 
     t.SetApartmentState(ApartmentState.STA) 
     t.Start() 
     t.Join() 

     ' Use clone so we can destroy immediately 
     mSmallIcon = DirectCast(Icon.FromHandle(mSmallIconHandle).Clone, Icon) 
     DestroyIcon(mSmallIconHandle) 

     ' Use clone so we can destroy immediately 
     mLargeIcon = DirectCast(Icon.FromHandle(mLargeIconHandle).Clone, Icon) 
     DestroyIcon(mLargeIconHandle) 
    End Sub 

    Public ReadOnly Property SmallIcon As Icon 
     Get 
      Return mSmallIcon 
     End Get 
    End Property 

    Public ReadOnly Property LargeIcon As Icon 
     Get 
      Return mLargeIcon 
     End Get 
    End Property 

    Private Sub GetIconsForFile() 
     ' Go and extract the small and large icons 
     ' Full filename must be < MAX_PATH - which is 260 chars in .Net (apparently) though a file path/length of 256 also causes an error. 
     ' Otherwise SHGetFileInfo gets nothing, Icon.FromHandle then gives "System.ArgumentException: The Win32 handle you passed to Icon is invalid or of the wrong type." 
     ' This needs to be stopped in the calling code, or the resulting error trapped 

     Dim zFileInfo As New SHFILEINFO(True) 
     Dim cbSizeInfo As Integer = Marshal.SizeOf(zFileInfo) 
     Dim flags As SHGFI = SHGFI.Icon Or SHGFI.UseFileAttributes Or SHGFI.SmallIcon 
     SHGetFileInfo(mFileName, 256, zFileInfo, cbSizeInfo, flags) 
     mSmallIconHandle = zFileInfo.hIcon 

     zFileInfo = New SHFILEINFO(True) 
     cbSizeInfo = Marshal.SizeOf(zFileInfo) 
     flags = SHGFI.Icon Or SHGFI.UseFileAttributes Or SHGFI.LargeIcon 
     SHGetFileInfo(mFileName, 256, zFileInfo, cbSizeInfo, flags) 
     mLargeIconHandle = zFileInfo.hIcon 
    End Sub 

#Region "WinAPI" 
    <Flags()> Private Enum SHGFI 
     SmallIcon = &H1 
     LargeIcon = &H0 
     Icon = &H100 
     DisplayName = &H200 
     Typename = &H400 
     SysIconIndex = &H4000 
     UseFileAttributes = &H10 
    End Enum 

    <StructLayout(LayoutKind.Sequential)> 
    Private Structure SHFILEINFO 
     Public hIcon As IntPtr 
     Public iIcon As Integer 
     Public dwAttributes As Integer 
     <MarshalAs(UnmanagedType.LPStr, SizeConst:=260)> Public szDisplayName As String 
     <MarshalAs(UnmanagedType.LPStr, SizeConst:=80)> Public szTypeName As String 

     Public Sub New(ByVal B As Boolean) 
      hIcon = IntPtr.Zero 
      iIcon = 0 
      dwAttributes = 0 
      szDisplayName = vbNullString 
      szTypeName = vbNullString 
     End Sub 
    End Structure 

    Private Declare Auto Function SHGetFileInfo Lib "shell32" (
     ByVal pszPath As String, 
     ByVal dwFileAttributes As Integer, 
     ByRef psfi As SHFILEINFO, 
     ByVal cbFileInfo As Integer, 
     ByVal uFlags As SHGFI) As Integer 

    <DllImport("user32.dll", SetLastError:=True)> 
    Private Shared Function DestroyIcon(ByVal hIcon As IntPtr) As Boolean 
    End Function 
#End Region 

End Class