2012-11-01 18 views
5

Şu anda RFID kartları ile iletişim için Visual Studio 2012'de bir yazılım yazıyorum. Delphi'de kart okuyucusu ile iletişim kurmak için yazılmış bir DLL var.C# uygulama tüm sistemi donuyor

Sorun şu ki: Yazılımım VS2012 yüklü olan makinelerde düzgün çalışıyor. Diğer sistemlerde, kendisini veya tüm sistemi donduruyor. x32 ve x64 yapılandırması ile Win XP/7/8'de denedim. .NET 4.0 kullanıyorum.

Okuyucuya bağlandıktan sonra, yazılım okuyucular RF alanında envanter kartlarına bir komutla okuyucuyu (200 ms hızında) seçen bir backgroundWorker'ı başlatır. Çarpışma genellikle ca. Okuyucu bağlandıktan 10 ila 20 saniye sonra. DLL Delphi ile yazılmış

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

[DllImport("tempConnect.dll", CallingConvention = CallingConvention.StdCall)] 
private static extern int inventory(int maxlen, [In] ref int count, 
             IntPtr UIDs, UInt32 HFOffTime); 
, kod DLL komut: İşte kod yerde bir bellek sızıntısı olabilir düşünüyorum

function inventory (maxlen: Integer; var count: Integer; 
        UIDs: PByteArray; HFOffTime: Cardinal = 50): Integer; STDCALL; 

ama hiçbir fikrim yok

: ...


DÜZENLEME bulmak için nasılYukarıdaki koduma bazı fikirler (açık GC.Collect(), try-catch-nihayet) ekledim, ancak hala çalışmıyor.

if (!bgw_inventory.IsBusy) 
    bgw_inventory.RunWorkerAsync(); 

Async backgroundworker yapar:

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

DÜZENLEME

aksiyon, her 200ms çalıştırır: Burada

getCardID() çağrıları koddur

Ti Şimdi kodda bazı küçük reworks (güncellemeler) yaptım. Şimdi sadece App. "tempConnect.dll" de 0xC00000FD (Yığın taşması) ile kilitleniyor. Bu, VS2012 yüklü Sistemlerde veya DLL'yi yerel Delphi ile kullanırsam gerçekleşmez! Başka bir fikri olan var mı?


DÜZENLEME Şimdi bunun yığıt var günlüğü DLL yapılan ve garip bir şey buldum: o denilen ve benim C# Programm çağrılan geçtiyse , yığıt yukarı ve aşağı sürekli değişiyor. Eğer doğal bir Deplhi Programından aynısını yaparsam, stacksize sabittir! Yani daha fazla araştırma yapacağım, ama gerçekten bir fikrim yok, ne aramam gerekiyor ...

+0

Sadece bir şüpheniz, bunun sizin sorununuzunuzla ilgili olduğunu sanmıyorum, fakat 'inventory()' işlevini çağırdıktan sonra kodu çözümlemeniz, UIDS'nin boş olmadığını kontrol ediyorsunuz. Bu yapı, UIDS değerinin "envanter" fonksiyonunun içinde null olarak ayarlanabileceğini göstermektedir. Eğer durum buysa - referans ile UIDS'i paslatmamalısınız? –

+0

En içteki try-catch işleyicisine, 'Marshal.FreeHGlobal() 'çağrısına ulaşılmadan önce istisna yapıldığında mevcut kod sızabilir. Marshal.FreeHGlobal() 'ın çağrısının yapıldığı bir 'son' cümleciğine bu işleyiciye eklemenizi öneririm. Böylelikle, bir şeyler yanlış gitmiş olsa bile, tahsis edilen hafızanın serbest kalmasını sağlarsınız. Ayrıca, hata maddesinin yakalama maddesinin içinde günlüğe kaydedilmesini öneririm, çünkü şu anda 'zero.ToString()' dönüş değeri 'envanter() tarafından döndürülen meşru bir değer olup olmadığını anlayamazsınız. . –

+0

Lütfen getCardID() 'yi çağıran kodu gönderir misiniz? Bunu sormamın nedeni, yalnızca envanterin() birden fazla iş parçacığı tarafından eşzamanlı olarak çağrılabilmesi olasılığının olmadığını doğrulamaktır. Eğer iş parçacığı güvenli olacak şekilde tasarlanmamışsa, bu, yaşadığınız donmaların bir nedeni olabilir. Şerefe! –

cevap

1

Bu Marshal nesnesini nasıl kullandığımız konusunda biraz endişeliyim. Bellek sızıntısından korktuğunuzda, belleği sık sık ayırıyor gibi görünüyor, ancak onu açık bir şekilde serbest bıraktığını görmüyorum. Çöp toplayıcı , (operatif kelime) bununla ilgilenmelidir, ancak siz kendiniz karışımda yönetilmeyen bir kodunuz olduğunu söylüyorsunuz. Yayınlanan bilgilerin yönetilmeyen kodun nerede başladığını anlatması zor.

Bazı iyi teknikler, .NET'te bellek sızıntıları bulmaya yardımcı olmak için this question'a bakın. Bu, kodun yönetilen ucunda belleğin nasıl kullanıldığına dair bir ton bilgi verecektir (yani, doğrudan kontrol). Sistemin genel sağlığına dikkat çekmek için Windows Performans İzleyicisi'ni kesme noktaları ile kullanın. .NET davranıyor gibi görünüyor, ancak WPM bazı keskin sivri gösteriyorsa, muhtemelen yönetilmeyen kodda. Buradaki kullanımınızı gerçekten kontrol edemezsiniz, bu nedenle muhtemelen o noktadaki belgelere geri dönme vakti gelmiştir.