我目前正在寫一個軟件在Visual Studio 2012與RFID卡通信。 我得到了一個用Delphi編寫的DLL來處理與讀卡器的通信。C#應用程序與非託管DLL凍結整個系統
問題是:我的軟件在裝有VS2012的機器上運行良好。在其他系統上,它凍結了自己或整個系統。 我在配置x32和x64的Win XP/7/8上試過了。 我正在使用.NET 4.0。
連接到閱讀器後,軟件啓動一個backgroundWorker,該閱讀器使用命令在閱讀器射頻場中盤點卡片(以200毫秒的速率)輪詢閱讀器。美國的崩潰發生在約。讀取器連接10到20秒後。下面是代碼:
[DllImport("tempConnect.dll", CallingConvention = CallingConvention.StdCall)]
private static extern int inventory(int maxlen, [In] ref int count,
IntPtr UIDs, UInt32 HFOffTime);
public String getCardID()
{
if (isConnectet())
{
IntPtr UIDs = IntPtr.Zero;
int len = 2 * 8;
Byte[] zero = new Byte[len];
UIDs = Marshal.AllocHGlobal(len);
Thread.Sleep(50);
Marshal.Copy(zero, 0, UIDs, len);
int count = 0;
int erg;
String ret;
try
{
erg = inventory(len, ref count, UIDs, 50);
}
catch (ExternalException) // this doesn't catch anything (iI have set <legacyCorruptedStateExceptionsPolicy enabled="true"/>)
{
return "\0";
}
finally
{
ret = Marshal.PtrToStringAnsi(UIDs, len);
IntPtr rslt = LocalFree(UIDs);
GC.Collect();
}
if (erg == 0)
return ret;
else
return zero.ToString();
}
else
return "\0";
}
的DLL是用Delphi編寫,代碼DLL命令是:
function inventory (maxlen: Integer; var count: Integer;
UIDs: PByteArray; HFOffTime: Cardinal = 50): Integer; STDCALL;
我覺得有可能是內存泄漏的地方,但我不知道如何找到它......
編輯:
我在上面的代碼中添加了一些想法(顯式GC.Collect(),try-catch-finally),但它仍然不起作用。
下面是代碼,調用getCardID():
的操作,運行每200ms:
if (!bgw_inventory.IsBusy)
bgw_inventory.RunWorkerAsync();
異步BackgroundWorker的作用:
private void bgw_inventory_DoWork(object sender, DoWorkEventArgs e)
{
if (bgw_inventory.CancellationPending)
{
e.Cancel = true;
return;
}
else
{
String UID = reader.getCardID();
if (bgw_inventory.CancellationPending)
{
e.Cancel = true;
return;
}
if (UID.Length == 16 && UID.IndexOf("\0") == -1)
{
setCardId(UID);
if (!allCards.ContainsKey(UID))
{
allCards.Add(UID, new Card(UID));
}
if (readCardActive || deActivateCardActive || activateCardActive)
{
if (lastActionCard != UID)
actionCard = UID;
else
setWorkingStatus("OK", Color.FromArgb(203, 218, 138));
}
}
else
{
setCardId("none");
if (readCardActive || deActivateCardActive || activateCardActive)
setWorkingStatus("waiting for next card", Color.Yellow);
}
}
}
編輯
Ti現在我已經在代碼上做了一些小修改(上面的更新)。現在只有應用程序。在「tempConnect.dll」處與0xC00000FD(堆棧溢出)崩潰。 這不會發生在安裝了VS2012的系統上,或者如果我使用本機Delphi的DLL! 有沒有人有任何其他想法?
編輯
現在我所做的DLL記錄它的堆棧大小,並發現了一些奇怪的: 如果這就是所謂的從我的C#PROGRAMM調查,堆棧大小是不斷變化的上下。 如果我從一個自然的Deplhi程序做同樣的工作,stacksize是不變的! 所以我會做進一步調查,但我沒有真正的想法,我有什麼搜索...
只有一個疑問,我不認爲它與你的問題有關,而是在調用inventory()函數後分析代碼,你正在檢查UIDS是否爲空。這個結構表明UIDS的值可能在'inventory'函數內設置爲null。如果是這樣的話 - 你不應該通過參考找到UIDS嗎? – 2012-11-01 18:18:49
在調用Marshal.FreeHGlobal()之前,如果在最內層的try-catch處理程序中引發異常,則當前代碼可能會泄漏。我建議在這個處理程序中添加一個'finally'子句,其中調用Marshal.FreeHGlobal()'完成。這樣你可以確保分配的內存被釋放,即使出現了問題。我還建議在catch子句中記錄錯誤,因爲此時你不能分辨'zero.ToString()'的返回值是否是'inventory()'返回的合法值,或者出錯了。 – 2012-11-01 18:42:55
請問您可以發佈調用'getCardID()'的代碼嗎?我問這個問題的原因只是爲了驗證inventory()不可能被多個線程同時調用。如果它不是線程安全的,那可能是您遇到凍結的原因。乾杯! – 2012-11-01 19:15:43