2017-02-13 79 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