2011-01-31 41 views
13

Tôi đang phân lớp ứng dụng. Thủ tục Window subclassed của tôi nằm trong một DLL. Mã subclassing của tôi bên trong DLL trông hơi giống như thế này (tước xuống, loại bỏ các phần không liên quan khác).CallbackOnCollectedDelegate đã được phát hiện

class FooBar 
{ 
    private delegate int WndProcDelegateType(IntPtr hWnd, int uMsg, 
              int wParam, int lParam); 

    private const int GWL_WNDPROC = (-4); 
    private static IntPtr oldWndProc = IntPtr.Zero; 
    private static WndProcDelegateType newWndProc = new 
                WndProcDelegateType(MyWndProc); 

    internal static bool bHooked = false; 

    [DllImport("user32.dll")] 
    private static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, 
              WndProcDelegateType dwNewLong); 

    [DllImport("user32.dll")] 
    private static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, 
              IntPtr dwNewLong); 


    [DllImport("user32")] 
    private static extern int CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, 
              int Msg, int wParam, int lParam); 

    private static int MyWndProc(IntPtr lhWnd, int Msg, int wParam, int lParam) 
    { 
    switch (Msg) 
    { 
     // the usual stuff 


     // finally 
     return CallWindowProc(oldWndProc, lhWnd, Msg, wParam, lParam); 
    } 


    internal static void Hook() 
    { 
    oldWndProc = SetWindowLong(hWnd, GWL_WNDPROC, newWndProc); 
    bHooked = oldWndProc != IntPtr.Zero; 
    } 

    internal static void Unhook() 
    { 
    if (bHooked) SetWindowLong(hWnd, GWL_WNDPROC, oldWndProc); 
    } 
} 

Bây giờ, mặc dù tôi đang nắm giữ tham chiếu mạnh mẽ đến WndProc trong biến thể hiện tĩnh cấp lớp của đại biểu, tôi nhận được lỗi này.

CallbackOnCollectedDelegate được phát hiện

nhắn: Một callback được thực hiện trên thu gom rác thải đại biểu của loại 'PowerPointAddIn1 Foobar + WndProcDelegateType :: Invoke!'. Điều này có thể gây ra sự cố ứng dụng, tham nhũng và mất dữ liệu. Khi vượt qua đại biểu để mã không được quản lý, họ phải được giữ còn sống bởi ứng dụng được quản lý cho đến khi đảm bảo rằng họ sẽ không bao giờ được gọi là .

Tôi đang làm gì sai?

Trả lời

25
oldWndProc = SetWindowLong(hWnd, GWL_WNDPROC, MyWndProc); 

Đó lực lượng C# để tạo ra một đối tượng delegate on-the-fly. Nó dịch mã này:

oldWndProc = SetWindowLong(hWnd, GWL_WNDPROC, new WndProcDelegateType(MyWndProc)); 

vấn đề là đối tượng đại biểu không được tham chiếu ở bất kỳ đâu. Bộ sưu tập rác tiếp theo sẽ phá hủy nó, kéo tấm thảm ra khỏi dưới mã không được quản lý. Bạn đã làm điều thích hợp trong mã của bạn, bạn chỉ quên sử dụng nó. Khắc phục:

oldWndProc = SetWindowLong(hWnd, GWL_WNDPROC, newWndProc); 

Việc tạo lớp của riêng bạn từ NativeWindow và sử dụng phương thức AssignHandle() của nó là tốt hơn btw. Gọi ReleaseHandle() khi bạn thấy thông báo WM_DESTROY.

+1

Cảm ơn bạn đã giúp đỡ của bạn Câu trả lời của bạn là chính xác nhưng tôi vẫn nhận được ngoại lệ.Tôi rất tiếc rằng tôi đã đăng Tôi đã có những thay đổi trước khi đăng câu hỏi này.Tôi đã có mã ở hai nơi và đăng các mã trước đó, mà tôi đã không thay đổi.Tôi vẫn nhận được ngoại lệ –

+0

Erm, những gì tôi phải xem xét? –

+0

@Hans: Xin lỗi, tôi không hiểu bạn. Tôi có để lại một thứ gì đó không giải thích được không? –

9

Hãy gọi cho tôi điên nhưng lưu trữ một tham chiếu nên giải quyết này:

private static readonly WndProcDelegateType _reference = MyWndProc; 
+2

Cảm ơn bạn. Tôi nghĩ rằng tôi đã có một tài liệu tham khảo. Dù sao, sự khác biệt duy nhất giữa tờ khai của bạn và của tôi là tôi đã sử dụng toán tử mới và bạn đã không. Tôi đã thử nó theo cách bạn đề nghị nhưng nó vẫn ném cùng một ngoại lệ. :-( –

+1

Nếu nó đơn giản, tôi sẽ không được Googling này cho giờ kết thúc ... – BrainSlugs83

2

chức năng gọi lại có thể được gọi sau khi trả về cuộc gọi, người gọi được quản lý phải thực hiện các bước để đảm bảo rằng đại biểu vẫn không bị thu thập cho đến khi chức năng gọi lại kết thúc. Để biết thông tin chi tiết về ngăn chặn việc thu thập rác, hãy xem Interop Marshaling với Platform Invoke.

http://msdn.microsoft.com/en-us/library/eaw10et3.aspx

+1

Cảm ơn bạn. Tôi đang ở giữa một cái gì đó. Tôi sẽ nghiên cứu liên kết bạn đề cập khi tôi có cơ hội. Rất cảm ơn vì sự giúp đỡ của bạn. –

Các vấn đề liên quan