簡體   English   中英

Windows 7 + .NET 4.0中“Marshal.StructureToPtr”的訪問沖突異常(Windows XP + .NET 3.5正常)

[英]Access violation exception at 'Marshal.StructureToPtr' in Windows 7 + .NET 4.0 (Windows XP + .NET 3.5 works fine)

這是我的代碼:

internal void Show()
{
    if (Parent == null)
        throw new NullReferenceException();
    EDITBALLOONTIP ebt = new EDITBALLOONTIP();
    ebt.cbStruct = Marshal.SizeOf(ebt);
    ebt.pszText = Text;
    ebt.pszTitle = Caption;
    ebt.ttiIcon = (int)Icon;
    IntPtr ptrStruct = Marshal.AllocHGlobal(Marshal.SizeOf(ebt));
    Marshal.StructureToPtr(ebt, ptrStruct, true); // Here we go.
    // Access violation exception in Windows 7 + .NET 4.0
    // In Windows XP + .NET 3.5, it works just fine.

    // ... Some other code ...

    Marshal.FreeHGlobal(ptrStruct);
}

這是結構:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private struct EDITBALLOONTIP
{
    internal int cbStruct;
    internal string pszTitle;
    internal string pszText;
    internal int ttiIcon;
}

為什么這在Windows XP + .NET 3.5中運行良好並在Windows 7 + .NET 4.0中引發異常? 可能是CharSet有問題嗎?

=====================解決=======================

解決方案和解釋

如你所見Marshal.StructureToPtr(ebt,ptrStruct, true ); 將第三個參數設置為true。 這意味着系統將嘗試釋放最后為ptrStruct分配的內存。 但是當第一次調用方法Show()時,沒有為該結構分配內存(ptrStruct = IntPtr.Zero)。 因此系統將嘗試釋放位於零指針的內存。 當然它會引發異常。 Windows XP只是忽略了這一點,但Windows 7卻沒有。

這是最好的解決方案恕我直言:

   Marshal.StructureToPtr(ebt, ptrStruct, false);
   //Working...
   //Free resources
   Marshal.FreeHGlobal(ptrStruct);

我不想在這里添加一個答案,因為你已經解決了你的問題,我會說不會對你所遇到的問題提供任何答案,但它不適合作為評論,因為我提供了一些代碼。 所以我不得不在這里發布它作為答案。

您可能已經知道它(並且沒有這樣編寫,因此您的問題中的代碼更簡單),但我只是想說,在分配非托管內存時應該在任何地方使用的最佳實踐是封裝代碼在try / finally塊中,以確保始終釋放內存,即使拋出異常:

private static void Test()
{
    IntPtr ptrStruct = IntPtr.Zero;

    try
    {
        Marshal.AllocHGlobal(0x100);

        // Some code here
        // At some point, an exception is thrown
        throw new IndexOutOfRangeException();
    }
    finally
    {
        // Even if the exception is thrown and catch
        // from the code that calls the Test() method,
        // the memory will be freed.
        if (ptrStruct != IntPtr.Zero)
        {
            Marshal.FreeHGlobal(ptrStruct);
        }
    }
}

try
{
    Test();
}
catch (IndexOutOfRangeException)
{
    // Catches the exception, so the program won't crash
    // but it'll exit the Test() method, so the try/finally
    // ensures it won't leave without freeing the memory
    Debugger.Break();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM