Using NET Generic List ToArray in a Wrapper COM call causes an access violation, am I missing something?

I had a problem while trying to pass an array back to a COM call.

Basically, I have a general list of classes that I want to return to a COM call, you cannot use generics in COM, so it must be strongly typed. I decided that just going back .ToArray () in the list would give me what I needed.

When I use it in VB6, it works fine. In the debugger. When I compile the application and run it as a regular executable file, it crashes with memory access violation. I'm pretty dumb. I can not catch any errors in the VB or .NET component, so I assume that something is interfering with the COM translation.

Cannot execute "return a" in getList ()

The application event log contains this error:

Application error project1.exe, version 1.0.0.0, stamp 49fb60d8, failure module msvbvm60.dll, version 6.0.98.2, stamp 4802a186, debug? 0, error address 0x00106154.

Here is the VB6 code for reference, it is stupidly simple.

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

And the .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();
        }
    }
}

The problem is with late binding on the VB side. Using an early boundary grid solves the problem, here is the final VB code for the test application:

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
+3
source share
1 answer

It seems that the problem may be related to late and early binding. If you declare c2 as a type, it should fix this error. Here is another site that is facing a similar problem.

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

, , .ToArray . :

//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

, , , . , AppDomain ThreadAbort StackOverflow - , - . , .

+4

Source: https://habr.com/ru/post/1707499/


All Articles