2012-02-09 30 views
7

Tôi gặp sự cố với con trỏ tùy chỉnh trong ứng dụng WPF. Tôi sử dụng đoạn mã sau để tạo ra các Cursor đối tượng:SafeFileHandle.Close ném ngoại lệ nhưng xử lý hợp lệ và hoạt động

[DllImport("user32.dll")] 
private static extern IntPtr CreateIconIndirect(ref IconInfo icon); 

[DllImport("user32.dll")] 
[return: MarshalAs(UnmanagedType.Bool)] 
private static extern bool GetIconInfo(IntPtr hIcon, ref IconInfo pIconInfo); 

private static Cursor CreateCursor(string cursorName, System.Drawing.Bitmap bmp, 
    int xHotspot, int yHotspot, out SafeFileHandle handle) 
{ 
    IconInfo tmp = new IconInfo(); 
    GetIconInfo(bmp.GetHicon(), ref tmp); 
    tmp.xHotspot = xHotspot; 
    tmp.yHotspot = yHotspot; 
    tmp.fIcon = false; 

    IntPtr ptr = CreateIconIndirect(ref tmp); 
    handle = new SafeFileHandle(ptr, true); 

    if (handle.IsClosed) 
    { 
     return null; 
    } 

    Cursor cur = CursorInteropHelper.Create(handle); 

    return cur; 
} 

Khi tôi đóng ứng dụng của tôi và GC bắt đầu nhặt thùng rác, nó ném một ngoại lệ:

System.Runtime.InteropServices.SEHException was unhandled 
    Message=External component has thrown an exception. 
    Source=mscorlib 
    ErrorCode=-2147467259 
    StackTrace: 
     at Microsoft.Win32.Win32Native.CloseHandle(IntPtr handle) 
     at Microsoft.Win32.SafeHandles.SafeFileHandle.ReleaseHandle() 
     at System.Runtime.InteropServices.SafeHandle.InternalDispose() 
     at System.Runtime.InteropServices.SafeHandle.Dispose(Boolean disposing) 
     at System.Runtime.InteropServices.SafeHandle.Dispose() 
     at System.Windows.Input.Cursor.Finalize() 
    InnerException: 

tôi đã làm một số nghiên cứu thêm bằng cách đặt điểm ngắt trên if (handle.IsClosed) và sử dụng cửa sổ ngay lập tức để gọi handle.Close(). Một số của SafeFileHandle 's gần tốt, những người khác ném cùng một ngoại lệ — ngay lập tức sau khi xử lý được tạo ra.

Và để làm mọi thứ trở nên thú vị, các tay cầm sẽ hoạt động tốt. IsInvalid là sai, IsClosed là sai và con trỏ xuất hiện. Nó chỉ là một số tay cầm không bao giờ có thể được đóng lại.

Vì tôi không bao giờ có ý định đóng các tay cầm theo cách thủ công và chúng sẽ chỉ đóng trong khi hoàn thành các đối tượng Cursor khi ứng dụng đóng, tôi có thể bỏ qua chúng. Tôi đã không cố gắng xây dựng bản phát hành bên ngoài VS2010 và tôi không biết nếu điều đó sẽ gây ra một hộp thoại tai nạn xuất hiện. Nhưng ngay cả khi tôi có thể bỏ qua chúng, nó vẫn còn lộn xộn. Vì vậy, về cơ bản tôi đang tìm kiếm bất kỳ thông tin về những gì có thể sai ở đây, nơi để tìm cách thử và gỡ lỗi này ... tất cả mọi thứ có vẻ là trong mã nguồn gốc hoặc GC và tôi không thể gỡ lỗi bất kỳ của nó .

Trả lời

15

Bạn đang gói các HICON trở về từ CreateIconIndirect trong một SafeFileHandle đó, trên phát hành, gọi CloseHandle trên HICON thay vì cần DestroyIcon. Không quấn HICON trong SafeFileHandle nhưng thay vào đó, riêng SafeHandle:

class SafeIconHandle : SafeHandleZeroOrMinusOneIsInvalid 
{ 
    [DllImport("user32.dll", SetLastError = true)] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    internal static extern bool DestroyIcon(
     [In] IntPtr hIcon); 

    private SafeIconHandle() 
     : base(true) 
    { 
    } 

    public SafeIconHandle(IntPtr hIcon) 
     : base(true) 
    { 
     this.SetHandle(hIcon); 
    } 

    protected override bool ReleaseHandle() 
    { 
     return DestroyIcon(this.handle); 
    } 
} 
+0

Cảm ơn! Tôi khá mới để WPF, không bao giờ thực hiện WinForms, và đây là lần đầu tiên tôi phải đối phó với mã nguồn gốc. Và cảm ơn bạn đã xóa nhận xét và đưa ra câu trả lời. :) –

+1

@RyanP Bạn được chào đón. Những thứ như vậy rất dễ bỏ lỡ, đặc biệt là nếu mọi thứ dường như hoạt động ở cái nhìn đầu tiên. – ordag

+0

Cảm ơn giải pháp đó! – Kai