2010-02-17 67 views
2

我已經做了這從C代碼調用非託管函數。 pCallback是一個函數指針,所以託管端是一個委託。與代表問題

[DllImport("MyDLL.dll")] 

public static extern Result SetCallback(
      IntPtr handle, 
      Delegate pCallback, 
      CallbackType Type); 

現在我設置

public delegate void pfnCallback(uint PromptID, ttsEventType evt, IntPtr lData); 

    public Form1() 
    { 
     pfnCallback cb = new pfnCallback(cback); 
     (...) 
     Wrapper.SetCallback(handle, cb, IntPtr.Zero, CallBackType.DEFAULT); 
     (...) 
     } 

它給我一個錯誤說「......路過委託給非託管代碼時,他們必須保持活着......」

任何人都可以幫我 ?

問候

回答

2

你混淆了委託實例的委託類型聲明。是的,你公開了你的委託聲明,那是錯誤的。只有Form1類使用它,它應該是私人的。這是委託人的實例,這是您用新語句創建的實例。

現在,你在Form1構造函數的局部變量存儲的實例。這可以在幾微秒的時間內爲實例提供參考。只要構造函數完成,該引用就消失了,垃圾收集器可以在此之後的任何時刻收集委託實例。它看不到非託管代碼保留對它的引用,收集器只能發現託管代碼所持有的引用。

沒事找事發生在非託管代碼調用上收集委託實例的回調,你會聽到一個響亮的KABOOM。您必須更改您的代碼,以便對該實例進行託管引用。一個簡單的方法就是向Form1類中添加一個私有成員來存儲實例。

即使這樣可能還不夠好,在Form1對象將垃圾在未來的某個時刻收集好。其中還收集委託對象。您還必須確保非託管代碼在發生這種情況後不能使用回調。給定類(Form1)的名稱,在這種情況下不可能發生這種情況。但是,在代碼防禦方面,通過調用重置窗體的FormClosing事件處理函數中的回調函數。

+0

感謝您的答覆。我已經瞭解並嘗試你說什麼。但現在我「M得到一個未處理的win32異常,運行相關的回調時 – jose

+0

也許你應該開始一個新的問題有關。一定要記錄好了,‘我發現了一個異常’是不會幫助任何人的幫助功能。您。 –

3

據我瞭解的信息,你應該這樣做是這樣的:

public delegate void pfnCallback(uint PromptID, ttsEventType evt, IntPtr lData); 

public pfnCallback cb = new pfnCallback(cback); 

public Form1() 
{ 
    (...) 
    Wrapper.SetCallback(handle, cb, IntPtr.Zero, CallBackType.DEFAULT); 
    (...) 
} 
3

我相信你需要擴大CB的範圍,以確保該變量將繼續存在並且只要非託管代碼可能要調用它,就參考回調函數。非託管代碼不參與.NET引用跟蹤,因此如果您不強制引用將保留在.NET代碼中的回調,它將被框架釋放,並且非託管代碼將無法在其後正確調用它那。

+0

它已經明顯和全局聲明 – jose

+0

@jose - 而不是你原來的片斷,「CB」是一個局部變量。實例很重要,而不是類型聲明。 –

0

嘗試回調變量cb全球

+0

它已經全球和公共:( – jose

+0

您的示例代碼表明這是不是全球性的。 – BlueMonkMN

+0

pfnCallback不是變量名。CB是。 – BlueMonkMN