none
Interop Marshalling problem RRS feed

  • Question

  • I'm having a weird problem with the C# code below, I've already tested the dll to be correct, (or the code used in the dll anyway). The error i get is
    System.ExecutionEngineException was unhandled
      Message="Exception of type 'System.ExecutionEngineException' was thrown."
      InnerException:

    and unfortunately it stops there, the location and the error is indicated below in the code.
    A second part of my question is, do i have to keep writing the allocation and marshalling code or is there an attribute i can set or something to make it do it for me, since it's pretty mechanic.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Runtime.InteropServices;
    
    namespace HaskellDLLDemo
    {
        class Program
        {
    
            [DllImport("demo.dll", SetLastError = true)]
            public static extern Int32 foo(Int32 input);
    
            [DllImport("demo.dll", SetLastError = true)]
            public static extern IntPtr typeTest1(Int32 input, [MarshalAs(UnmanagedType.LPTStr)]string name);
    
            [DllImport("demo.dll", SetLastError = true)]
            public static extern IntPtr typeTest2(IntPtr sel);
    
            //[MarshalAs(UnmanagedType.SysInt)]
            public enum ListSelector { first, second }
    
            [StructLayoutAttribute(LayoutKind.Sequential, CharSet=CharSet.Auto)]
            public struct Selector
    	    {
                public ListSelector tag;
                public SelectorUnion elt;
    	    }
    
            [StructLayoutAttribute(LayoutKind.Explicit, CharSet=CharSet.Auto)]
            public struct SelectorUnion
            {
                //nullary constructors are implicitly defined
            }
    
            [StructLayoutAttribute(LayoutKind.Sequential, CharSet=CharSet.Auto)]
            public struct SimpleType
            {
                public Int32 value;
                public string name;
            }
    
            public enum ListTwoCases { nofields, other }
    
            [StructLayoutAttribute(LayoutKind.Sequential, CharSet=CharSet.Auto)]
            public struct TwoCases
            {
                public ListTwoCases tag;
                public TwoCasesUnion elt;
            }
    
            [StructLayoutAttribute(LayoutKind.Explicit, CharSet=CharSet.Auto)]
            public struct TwoCasesUnion
            {
                [FieldOffset(0)]
                public SimpleType other;
            }
           
            static void Main(string[] args)
            {
                Console.Write("Enter a number: ");
                Int32 val = Int32.Parse(Console.ReadLine());
                Console.WriteLine("\nResult: {0}", foo(val));
                Console.WriteLine("\nTesting pointer transfers:");
                IntPtr ptr = typeTest1(val, "Hashcode: " + val.GetHashCode().ToString());
                Console.WriteLine("Pointer: {0}", ptr.ToInt32());
    
                SimpleType test = (SimpleType)Marshal.PtrToStructure(ptr, typeof(SimpleType));
    
                Console.WriteLine("Value: {0} - '{1}'", test.value,test.name);
    
                Console.WriteLine("Testing multiple constructor types and non primitive types");
    
                Console.WriteLine("===> first");
                Selector call = new Selector();
                call.tag = ListSelector.first;
                
                IntPtr ptrx = Marshal.AllocHGlobal(Marshal.SizeOf(call));
                Marshal.StructureToPtr(call, ptrx,false);
    
                printResult(typeTest2(ptrx));
    
                Console.WriteLine("===> second");
                call.tag = ListSelector.second;
    
                Marshal.StructureToPtr(call, ptrx, true);
                printResult(typeTest2(ptrx));
    
                Console.ReadLine();
            }
    
            public static void printResult(IntPtr ptr)
            {
                Console.WriteLine("Pointer: {0}", ptr.ToInt32());
                TwoCases cases = (TwoCases)Marshal.PtrToStructure(ptr, typeof(TwoCases));
                switch (cases.tag)
                {
                    case ListTwoCases.nofields:
                        Console.WriteLine("NOFIELD");
                        break;
                    case ListTwoCases.other:
                        Console.WriteLine("OTHER: SimpleType - {0} # {1} ",cases.elt.other.name, cases.elt.other.value);
                        break;
                    default:
                        break;
                }
            }
        }
    }

    and the structures in C are

    #include <string.h>
    
    typedef struct {
        int value;
        char* name;
    } SimpleType;
    
    enum ListTwoCases {twocasesnofields, twocasesother};
        
    union TwoCasesUnion {
        //nullary constructors are implicitly defined
        struct SimpleType* other;
    };
    
    typedef struct {
        enum ListTwoCases tag;
        union TwoCasesUnion elt;
    } TwoCases;
    
    enum ListSelector {selectorfirst,selectorsecond};
    
    union SelectorUnion {
        //nullary constructors are implicitly defined
    };
    
    typedef struct { 
        enum ListSelector tag;
        union SelectorUnion elt;
    } Selector;
    
    
    Friday, July 31, 2009 4:15 AM

Answers

  • We can't help you find the source code for that DLL.  But that's what you'll need to debug the problem.  Work with the owner of the DLL to sort out any source code licensing issues.

    Hans Passant.
    • Marked as answer by Phyx Sunday, August 2, 2009 12:28 PM
    Sunday, August 2, 2009 10:33 AM
    Moderator

All replies

  • Your unmanaged DLL is corrupting the garbage collected heap.  It isn't obvious from your code how that might happen, look for the problem in the source code for demo.dll

    Hans Passant.
    Friday, July 31, 2009 10:50 AM
    Moderator
  • I can only test the code before it gets compiled into a windows dll, for reasons that I can't seem to find a particulair file to get the c code to compile. But that part is correct. Now assuming the compiler is correct as well, The only thing i could think of is that the c# code/framework is somehow messed up.

    Is there anyway I can check what's really going on. The error generated is extremely unhelpful in this case.

    And I don't know if you might be able to answer the second part of the question?

    "A second part of my question is, do i have to keep writing the allocation and marshalling code or is there an attribute i can set or something to make it do it for me, since it's pretty mechanic."

    Thanks,
    Phyx
    Sunday, August 2, 2009 2:53 AM
  • We can't help you find the source code for that DLL.  But that's what you'll need to debug the problem.  Work with the owner of the DLL to sort out any source code licensing issues.

    Hans Passant.
    • Marked as answer by Phyx Sunday, August 2, 2009 12:28 PM
    Sunday, August 2, 2009 10:33 AM
    Moderator
  • As I have said a couple of times before. I can only test the code before it gets compiled into a DLL. I never said I didn't have access to the code, It's my code, How ever it is haskell code. It's just a few lines of code, which I can prove is correct. That's why i said assuming the compiler is correct in it's compilation, that the DLL is working fine.

    Anyway, thanks for trying, but I really can't consider any of your reply's an answer since they don't really help me at all.

    but since the system will mark one reply as an answer anyway, i'll just go ahead and do it and let the thread die.
    Sunday, August 2, 2009 12:18 PM