2011-01-31 22 views
13

我是一個應用程序的子類。我的子類窗口過程是在一個DLL中。我在DLL中的子類代碼看起來有點像這樣(剝離下來,刪除了其他不相關的部分)。CallbackOnCollectedDelegate檢測到

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); 
    } 
} 

現在,即使我在委託的類級靜態實例變量持有的強引用WndProc中,我得到這個錯誤。

CallbackOnCollectedDelegate檢測

消息:回調被上型的 垃圾收集代表 '!PowerPointAddIn1 FooBar的+ WndProcDelegateType ::調用' 製成。 這可能會導致應用程序崩潰, 損壞和數據丟失。當通過 代表非託管代碼,他們必須保持 活着的託管應用程序,直到 它保證,他們將永遠不會調用 。

我在做什麼錯?

回答

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

這就使得C#創建的即時委託對象。它將代碼翻譯爲:

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

這是一個問題,委託對象沒有被引用到任何地方。接下來的垃圾收集將會破壞它,從非託管代碼下拉出地毯。你已經在你的代碼中做了正確的事情,你忘記了使用它。修復:

oldWndProc = SetWindowLong(hWnd, GWL_WNDPROC, newWndProc); 

從NativeWindow的派生自己的類,並使用其AssignHandle()方法是更好的捕鼠器BTW。當看到WM_DESTROY消息時調用ReleaseHandle()。

+1

謝謝你的幫助,你的回答是正確的,但我仍然得到例外。錯誤的代碼在發佈這個問題之前,我已經做了修改,我在兩個地方發佈了代碼,併發布了以前的代碼,我沒有改變,但我仍然得到這個例外 – 2011-01-31 20:37:39

9

叫我瘋了,但存儲參考應解決此問題:

private static readonly WndProcDelegateType _reference = MyWndProc; 
+2

謝謝。我以爲我已經有了一個參考。無論如何,你的聲明和我的唯一區別是我使用了新的操作符,而你沒有。我按照你的建議嘗試了它,但它仍然拋出相同的異常。 :-( – 2011-01-31 20:40:21

+1

)如果是這麼簡單,我不會在搜索結果中使用谷歌搜索... – BrainSlugs83 2014-04-26 07:43:30

2

可以在調用返回後調用回調函數,受管理的調用方必須採取措施確保委託保持未收集狀態,直到回調函數結束。有關防止垃圾收集的詳細信息,請參閱使用平臺調用進行互操作封送。

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