2009-05-01 7 views
3

Ich habe ein Problem beim Versuch, ein Array an einen COM-Aufrufer zurückzugeben.Verwendung von NET Generic List ToArray in einem COM Called Wrapper verursacht Zugriffsverletzung, fehlt mir etwas?

Grundsätzlich habe ich eine generische Liste von Klassen, die ich an den COM-Aufrufer zurückgeben möchte, können Sie nicht Generics in COM verwenden, so dass es stark typisiert werden muss. Ich dachte, ich würde einfach ein. ToArray() auf der Liste zurückgeben, würde mir geben, was ich brauche.

Wenn ich es in VB6 verwende, funktioniert es perfekt. Im Debugger. Wenn ich die App kompiliere und sie als reine ausführbare Datei ausführe, stürzt sie mit einer Speicherzugriffsverletzung ab. Ich bin ziemlich ratlos. Ich kann keine Fehler in VB oder in der .NET-Komponente abfangen, daher vermute ich, dass etwas in der COM-Übersetzung verloren geht.

Es schlägt fehl, auf "return a" in getList()

Anwendungsereignisprotokoll enthält diesen Fehler:

Fehlgeschlagene Anwendung project1.exe, Version 1.0.0.0, Stempel 49fb60d8, Modul msvbvm60.dll Verwerfungen, Version 6.0.98.2, Stempel 4802a186, debuggen? 0, Fehleradresse 0x00106154.

Hier ist der VB6-Code als Referenz, es ist dumm einfach.

Private Sub Form_Load() 
    Dim c1 As IClass1 
    Dim c2 

    Set c1 = New Class1 

    For Each c2 In c1.getList 
    Debug.Print c2.Value 
    Next 

End Sub 

Und der .NET-Code:

using System; 
using System.Collections.Generic; 
using System.Text; 
using System.Runtime.InteropServices; 

namespace TestCOM 
{ 

    public interface IClass1 
    { 
     List<IClass2> MyList { get; } 

     IClass2[] getList(); 
    } 

    public class Class1 : IClass1 
    { 
     public List<IClass2> MyList { get; private set; } 

     public Class1() 
     { 
      this.MyList = new List<IClass2>(); 
      this.MyList.Add(new Class2()); 
      this.MyList.Add(new Class2()); 
     } 

     public IClass2[] getList() 
     { 
      try 
      { 
       System.IO.File.WriteAllText(@"C:\COMLog1.txt", "Hi."); 
       IClass2[] a = new IClass2[this.MyList.Count]; 
       System.IO.File.WriteAllText(@"C:\COMLog1.txt", "Bye."); 
       for (int i = 0; i < this.MyList.Count; i++) 
       { 
        a[i] = this.MyList[i]; 
       } 
       System.IO.File.WriteAllText(@"C:\COMLog1.txt", "Sup."); 

//The logging appears on disk all the way to here, so the failure appears to be in the interop layer. 

       return a; 
      } 
      catch (Exception e) 
      { 
       System.IO.File.WriteAllText(@"C:\COMLog.txt", string.Format("Error:\n{0}", e.Message)); 
      } 
      return null; 
     } 
    } 

    public interface IClass2 
    { 
     int Value { get; } 
    } 
    public class Class2: IClass2 
    { 
     public int Value { get; private set; } 

     public Class2() 
     { 
      Random r = new Random(); 
      this.Value = r.Next(); 
     } 
    } 
} 

Das Problem aus der späten Bindung auf der VB Seite stammt. Mit einem frühen gebundenen Array löst das Problem, hier ist der letzte VB-Code für die Testanwendung:

Private Sub Form_Load() 
    Dim c1 As IClass1 
    Dim c2() As IClass2 
    Dim x 

    Set c1 = New Class1 

    c2 = c1.getList 

    For Each x In c2 
    Debug.Print x.Value 
    Next 

End Sub 
+1

* Wo * nicht abstürzen oder? Haben Sie einige Debugging-Ausgaben eingegeben, um den genauen Standort und die Zustände der Objekte für den Absturz zumindest zu lokalisieren? –

+0

Es stürzt bei getList ab, ich habe versucht, es zu versuchen/zu fangen und den gefangenen Fehler in einer Datei zu protokollieren. Der Fehler scheint nicht von .NET gefangen werden. – Boarder2

+0

Gibt es FatalExecutionErrors im Ereignisprotokoll? –

Antwort

4

Es scheint, dass das Problem mit spät sein kann und die frühen Bindung. Wenn Sie c2 als Typ deklarieren, sollte dieser Fehler behoben werden. Hier ist eine andere Seite, die ein ähnliches Problem behandelt.

http://weblogs.asp.net/psteele/archive/2007/02/06/com-interop-does-not-like-uninitialized-arrays.aspx

Was nicht in der Lage, den Fehler zu erfassen, es sieht aus wie die .ToArray Funktion für generische Listen ist in der Lage, die Daten korrumpieren. Hier ist ein Code vom Reflektor:

//You can see that the function calls Array.Copy 
Public Function ToArray() As T() 
    Dim destinationArray As T() = New T(Me._size - 1) {} 
    Array.Copy(Me._items, 0, destinationArray, 0, Me._size) 
    Return destinationArray 
End Function 

//You can see from the ReliabilityContract that this method is set to 
//Consistency.MayCorruptInstance and Cer.MayFail 
<ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)> _ 
Public Shared Sub Copy(ByVal sourceArray As Array, _ 
    ByVal sourceIndex As Integer, ByVal destinationArray As Array, _ 
    ByVal destinationIndex As Integer, ByVal length As Integer) 
     Array.Copy(sourceArray, sourceIndex, destinationArray, _ 
     destinationIndex, length, False) 
End Sub 

Darüber hinaus ist hier einige Dokumentation, die erklären kann, warum Sie den Fehler nicht richtig abfangen können. Grundsätzlich könnte die gesamte AppDomain beschädigt werden oder es könnte ein ThreadAbort oder ein StackOverflow oder ein anderer kritischer Fehler auftreten, der dazu führt, dass die gesamte Verarbeitung abgebrochen wird. Der zweite Link beschreibt, wie diese Art von Problemen gelöst werden kann.

+0

Ausgezeichnet, danke! Das Problem scheint mit der späten Bindung zu sein. Durch Ändern des VB-Codes in den obigen Beitrag wurden die Zugriffsverletzungsfehler behoben. Vielen Dank! – Boarder2