3

Hi I am trying to access a c++ array of struct from c#. The struct itself also contains an array of strings and a String. The details are below. It's not working.. does not crash but does not transfer the data across (e.g. get nulls in the array, and random number in numberOfRows integer of struct/class). See my comments at the end of the code listing. Any suggestions?

c++ cppClassLib.cpp

// This is the main DLL file.



  #include "stdafx.h"
    #include <Objbase.h>

    #include "cppClassLib.h"

    #include <string.h>
    //#include <malloc.h>

    namespace cppClassLib {

    /*
    http://msdn.microsoft.com/en-us/magazine/cc164123.aspx
    http://stackoverflow.com/questions/9093292/use-a-c-library-from-c-sharp-code
    http://stackoverflow.com/questions/5671658/what-does-invalid-managed-unmanaged-type-combination-mean
    http://stackoverflow.com/questions/2338146/returning-pointers-from-unmanaged-to-managed-code
    CoTaskMemAlloc http://msdn.microsoft.com/en-us/library/windows/desktop/ms692727%28v=vs.85%29.aspx
    */

    char *createStr(char *input)
    {
        int len = strlen(input)+1;

        // can't use malloc because it needs to
        //  be accessible from another process.
        // can't use CoTaskMemAlloc because get an
        // error when trying to link, not found.
        //char *newStr = (char *)CoTaskMemAlloc(len);
        //char *newStr = (char *)malloc(len);

        char *newStr = (char *)GlobalAlloc(GPTR,len);
        //char* newStr = new char[len];
        strcpy_s(newStr, len, input);
        return newStr;
    }

    int Class1::getMatrixNumberOfRowsInColumnZero(int maxColumns, Class1::columnT *matrix)
    {
        if (maxColumns < 1) {
            return 0;
        }
        return matrix[0].numberOfRows;
    }

    int Class1::getMatrix(int maxColumns, Class1::columnT *matrix)
    {
        if (maxColumns < 2) {
            return 0;
        }
        int numberOfColumns = 2;

        //Class1::columnT *column0 = (Class1::columnT *)GlobalAlloc(GPTR,sizeof(Class1::columnT));
        Class1::columnT *column0 = &(matrix[0]);
        column0->columnName = createStr("Col0");
        int numRows = 2;
        column0->numberOfRows = numRows;
        char **rows = (char **)GlobalAlloc(GPTR,sizeof(char *)*numRows);
        rows[0] = createStr("C0R0");
        rows[1] = createStr("C0R1");
        column0->rows = rows;

        Class1::columnT *column1 = &(matrix[1]);
        //Class1::columnT *column1 = (Class1::columnT *)GlobalAlloc(GPTR,sizeof(Class1::columnT));
        column1->columnName = createStr("Col1");
        numRows = 2;
        column1->numberOfRows = numRows;
        rows = (char **)GlobalAlloc(GPTR,sizeof(char *)*numRows);
        rows[0] = createStr("C1R0");
        rows[1] = createStr("C1R1");
        column1->rows = rows;

        //matrix[0]=column0;
        //matrix[1]=column1;
        //(matrix[0])->columnName = createStr("Test0");

        return numberOfColumns; // 2
    }

    int Class1::getInt(void)
    {
        return 1234;
    }

    char* Class1::getHi(void)
    {
        //char *result = createStr("Hello");
        //return result;
        //return createStr("hello");
        return createStr("hello");
    }

    char** Class1::getHeaderList(void)
    {
        char** list;
        list = (char **)GlobalAlloc(GPTR,sizeof(char *)*2);
        list[0]=createStr("test1");
        list[1]="test2";
        return list;
    }

    int Class1::getHeaderListTwo(int maxsize, char ***result)
    {
        char** list;
        int len = 2;
        if (maxsize < len) {
            return NULL;
        }
        list = (char **)GlobalAlloc(GPTR,sizeof(char *)*maxsize);
        list[0]=createStr("test01");
        list[1]="test02";
        for (int i=2; i<maxsize; ++i) {
            list[i]="";
        }
        *result = list;
        return len;
    }

    char* Class1::getHi2(void)
    {
        return "Hi";
    }

    char* Class1::getHi3(void)
    {
        return "Hi!";
    }

    void Class1::getData(int *totalColumns,
                    char** headers[2],
                    char** items[2][3])
    {
        *totalColumns = 2;
        *headers[0]=createStr("Testing");
        *headers[1]=createStr("Pets");
        *items[0][0]=createStr("test1");
        *items[0][1]=createStr("test2");
        *items[0][2]=createStr("test3");
        *items[1][0]=createStr("Cats");
        *items[1][1]=createStr("Dogs");
        *items[1][2]=createStr("Fish");
    }

}

c++ cppClassLib.h

    // cppClassLib.h

    #pragma once

    using namespace System;

    #define DllExport   __declspec( dllexport )

    // http://msdn.microsoft.com/en-us/library/3y1sfaz2.aspx

    namespace cppClassLib {

    public class Class1 {
        public:
            struct columnT {  
                int numberOfRows;
                char **rows;
                char *columnName;
            };
            static DllExport int getMatrix(int maxColumns, columnT *matrix);
            static DllExport int getMatrixNumberOfRowsInColumnZero(int maxColumns, columnT *matrix);
            static DllExport void getData(int *totalColumns,
                    char** headers[2],
                    char** items[2][3]);
            static DllExport char *getHi(void);
            static DllExport char *getHi2(void);
            static DllExport char *getHi3(void);
            static DllExport int getInt(void);
            static DllExport char** getHeaderList(void);
            static DllExport int getHeaderListTwo(int maxsize, char ***result);
    };
}

c# Form1.cs

  using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;

    using System.Runtime.InteropServices;

    /*

    http://msdn.microsoft.com/en-us/library/aa288468%28v=vs.71%29.aspx
    http://ondotnet.com/pub/a/dotnet/2002/03/18/customcontrols.html?page=2
    http://www.codeproject.com/Articles/2995/The-Complete-Guide-to-C-Strings-Part-I-Win32-Chara
    http://msdn.microsoft.com/en-us/library/z6cfh6e6.aspx

    */

    namespace listViewFromC
    {
    public partial class Form1 : Form
    {
        /*
        [DllImport("cppClassLib.dll",
        CallingConvention = CallingConvention.Cdecl,
        EntryPoint = "?getInt@Class1@cppClassLib@@QAEHXZ")]
            public static extern int getInt();
        */

        // get EntryPoint using
        // "DLL Export Viewer" software

        [DllImport("cppClassLib.dll",
        CallingConvention = CallingConvention.Cdecl,
        EntryPoint = "?getHi2@Class1@cppClassLib@@SAPADXZ")]
            public static extern String getHi2();

        [DllImport("cppClassLib.dll",
        CallingConvention = CallingConvention.Cdecl,
        EntryPoint = "?getHi@Class1@cppClassLib@@SAPADXZ")]
        [return: MarshalAs(UnmanagedType.LPStr)]  
        public static extern string getHi();

        [DllImport("cppClassLib.dll",
        CallingConvention = CallingConvention.Cdecl,
        EntryPoint = "?getHeaderList@Class1@cppClassLib@@SAPAPADXZ")]
        [return: MarshalAs(UnmanagedType.LPArray, 
            ArraySubType=UnmanagedType.LPStr, SizeConst=2)]
        public static extern String[] getHeaderList();

        [DllImport("cppClassLib.dll",
        CallingConvention = CallingConvention.Cdecl,
        EntryPoint = "?getHeaderListTwo@Class1@cppClassLib@@SAHHPAPAPAD@Z")]
        public static extern int getHeaderListTwo(int maxsize,
            [MarshalAs(UnmanagedType.LPArray,
            ArraySubType = UnmanagedType.LPStr, SizeParamIndex = 0)]
            ref String[] result
            );

        [StructLayout(LayoutKind.Sequential)]  
        public class columnType
        {
            public int numberOfRows;
            [MarshalAs(UnmanagedType.LPArray,
            ArraySubType = UnmanagedType.LPStr)]
            public String[] rows;
            [MarshalAs(UnmanagedType.LPStr)]
            public String columnName;
        }  

        [DllImport("cppClassLib.dll",
        CallingConvention = CallingConvention.Cdecl,
        EntryPoint = "?getMatrix@Class1@cppClassLib@@SAHHPAUcolumnT@12@@Z")]
        public static extern int getMatrix(int maxColumns,
            [MarshalAs(UnmanagedType.LPArray,
            ArraySubType = UnmanagedType.Struct, SizeParamIndex = 0)]
            columnType[] matrix);

        [DllImport("cppClassLib.dll",
        CallingConvention = CallingConvention.Cdecl,
        EntryPoint = "?getMatrixNumberOfRowsInColumnZero@Class1@cppClassLib@@SAHHPAUcolumnT@12@@Z")]
        public static extern int getMatrixNumberOfRowsInColumnZero(int maxColumns,
            [MarshalAs(UnmanagedType.LPArray,
            ArraySubType = UnmanagedType.Struct, SizeParamIndex = 0)]
            columnType[] matrix);

        /*
        [DllImport("kernel32.dll")]
        static extern IntPtr GlobalAlloc(uint uFlags, uint dwBytes);

        const uint GMEM_FIXED = 0x0000;
        const uint GMEM_ZEROINIT = 0x0040;
        const uint GPTR = GMEM_FIXED | GMEM_ZEROINIT;
        */

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //label1.Text = getInt().ToString();
            label1.Text = getHi2();
            listView1.Items.Clear();
            listView1.Items.Add(label1.Text);
            //listView1.
        }

        private void button2_Click(object sender, EventArgs e)
        {
            label1.Text = getHi();
        }

        private void button3_Click(object sender, EventArgs e)
        {
            const int maxsize = 2;
            String[] headerList = new String[maxsize];
            int len = getHeaderListTwo(maxsize, ref headerList);
            MessageBox.Show("Got length " + headerList.Length+" ("+len+")");
            label1.Text="";
            for (int i = 0; i < headerList.Length; ++i)
            {
                if (headerList[i].Length>0)
                {
                    label1.Text += headerList[i].ToString() + " // ";
                }
                else
                {
                    label1.Text += " // ";
                }
            }
        }

        private void button4_Click(object sender, EventArgs e)
        {
            int maxColumns=5;
            int numberOfColumns = 0;
            columnType[] matrix = new columnType[maxColumns];
            for (int i = 0; i < maxColumns; ++i)
            {
                matrix[i] = new columnType();
            }
            matrix[0].numberOfRows = 1; // pick something just to see if we can get it back
            //uint sz = (uint)maxColumns*4;
            //IntPtr matrixIP = GlobalAlloc(GPTR, sz);
            //columnType[] matrix = matrixIP;

            //IntPtr pointerArr = Marshal.AllocHGlobal(maxColumns*4);

            //numberOfColumns = getMatrix(maxColumns, matrix);
            label1.Text = getMatrixNumberOfRowsInColumnZero(maxColumns,matrix).ToString();

            //label1.Text = matrix[0].columnName;
        }
    }
}

button1, button2 and button3 click events work fine so it shows that some of the c++ marshalling to c# is working. button4_click doesn't work.

label1.Text should return 1 since it's just returning matrix[0].numberOfRows but in fact it returns some huge number.

Also the getMatrix call if uncommented, also doesn't work, it does run without crash but then all the elements of the array are empty (not filled with the data that getMatrix is supposed to fill them with).

Mushahid Hussain
  • 4,052
  • 11
  • 43
  • 62
Jevan
  • 131
  • 1
  • 6
  • 1
    You forgot "Pack = 4" on the StructLayout. That might be it.. – Cole Tobin Jul 15 '12 at 07:01
  • Hi I changed [StructLayout(LayoutKind.Sequential)] to [StructLayout(LayoutKind.Sequential, Pack=4)] to make sure that it store the variables every 4 bytes. However I'm still getting random numbers in the label when I run it (should be giving me 1 if it was working). Thanks for the tip though that might be the first step in the solution, though I'm not sure what's next. – Jevan Jul 15 '12 at 07:31
  • (a guess) Try using StdCall instead? (add `__stdcall` declaration to C++ and use `CallingConversion.StdCall`) – Alvin Wong Jul 15 '12 at 07:34
  • @Jevan have you tried stepping though the code? – Cole Tobin Jul 15 '12 at 07:34
  • I read you should be using thiscall instead. Struts are "sequential, 4;int* vtable,data" and you call like (struct*, vars) – Cole Tobin Jul 15 '12 at 07:36
  • As stated by Alvin, it might have something to do with the calling convention. I had a similar problem reading from the C++ array. I solved it by `CallingConvention.ThisCall` but it might depend on 64 vs. 32 bit issues. Moreover, a post that you might find useful http://stackoverflow.com/questions/8199874/c-sharp-and-void-pointers – Digital Da Jul 15 '12 at 07:43
  • It is getting even more confusing because I have a 64bit processor so should I be putting pack=8? – Jevan Jul 15 '12 at 07:53
  • Unfortunately I can't step through the code of the c++ DLL because I have used DllImport in the c#. However I have tried my getMatrix function in a standalone c++ project and it works. I thought one possibility for the reason why its not working could be that the memory is allocated in c# using "new" not GlobalAlloc, so I was going to try allocating it using GlobalAlloc in the c# program. However that seems to return an IntPtr not a columnType[] and I can't seem to be able to convert the IntPtr to a columnType[]. So I had abandoned that thought. – Jevan Jul 15 '12 at 08:04
  • I just tried calling convention ThisCall or StdCall (changing both c++ and c# for the getMatrixNumberOfRowsInColumnZero method however I still get random numbers in the label not "1". – Jevan Jul 15 '12 at 08:05
  • but perhaps I will leave it as ThisCall since that seems to be the general consensus here for what is correct. Really I don't know which one to pick, I would have thought as long as I use the same for c++ and c# it shouldn't matter which one but who knows. – Jevan Jul 15 '12 at 08:06
  • ok i made some progress needs to be [StructLayout(LayoutKind.Sequential, Pack = 4)] public struct columnType – Jevan Jul 15 '12 at 08:29
  • second issue i just found, change to: [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.LPStr)] public String[] rows; – Jevan Jul 15 '12 at 08:37
  • (since it can't marshal as a LPArray) – Jevan Jul 15 '12 at 08:37
  • now it's returning 1- yahoo!! thanks for the tips some of your suggestions also have helped. – Jevan Jul 15 '12 at 08:38
  • actually i can step through it if i put a breakpoint in the c++ and c# code.. i have changed GetMatrix in the c++ code to column0->rows[0] = createStr("C0R0"); column0->rows[1] = createStr("C0R1"); and commented out the GlobalAlloc and i made the ByValArray a constant size using maxRows ie [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.LPStr, SizeConst=maxRows)] public String[] rows; now problem seems to be that the matrix is being lost when it returns from the c++ to the c# ... maybe next step might be to change it to a ref type. – Jevan Jul 15 '12 at 09:11
  • ok its working 100% now. only thing its a pity i have to use a constant array of ByValArray with maxRows=100. Would be better if i could have a variable length array. but i can't see any way of marshalling a variable length array in a struct. if you can see any way of doing that let me know. – Jevan Jul 15 '12 at 09:17
  • i will post the code for the final solution as an "answer" here. – Jevan Jul 15 '12 at 09:18

1 Answers1

1

Here is my solution. The only quirk with this solution is the need for fixed length arrays in the struct, which I would have preferred a variable length array but it wouldn't accept a Marshall of LPArray. Maybe it's not possible.

The main problem I had was that I had declared it as a class instead of a struct. The other issue was the array in the struct was an LPArray unmanaged marshall type, to try and have a variable length array but that didn't work since it needed to be a ByValArray (or SafeArray) for it to work.


cppClassLib.h

// cppClassLib.h

#pragma once

using namespace System;

#define DllExport   __declspec( dllexport )

// http://msdn.microsoft.com/en-us/library/3y1sfaz2.aspx

#define maxRowsCpp 100

namespace cppClassLib {

public class Class1 {
    public:
        struct columnT {  
            int numberOfRows;
            char *rows[maxRowsCpp];
            char *columnName;
        };
        struct columnT2 {  
            int numberOfRows;
        };
        static DllExport int __thiscall getMatrix(int maxColumns, int maxRows, columnT *matrix[]);
        static DllExport int __thiscall getMatrixNumberOfRowsInColumnZero(int maxColumns, columnT matrix[]);
        static DllExport int __thiscall getMatrixNumberOfRowsInColumnZero2(int maxColumns, columnT2 matrix[]);
        static DllExport void getData(int *totalColumns,
                char** headers[2],
                char** items[2][3]);
        static DllExport char *getHi(void);
        static DllExport char *getHi2(void);
        static DllExport char *getHi3(void);
        static DllExport int getInt(void);
        static DllExport char** getHeaderList(void);
        static DllExport int getHeaderListTwo(int maxsize, char ***result);
};

}


cppClassLib.cpp

// This is the main DLL file.

#include "stdafx.h"
#include <Objbase.h>

#include "cppClassLib.h"

#include <string.h>
//#include <malloc.h>

namespace cppClassLib {

/*
http://msdn.microsoft.com/en-us/magazine/cc164123.aspx
http://stackoverflow.com/questions/9093292/use-a-c-library-from-c-sharp-code
http://stackoverflow.com/questions/5671658/what-does-invalid-managed-unmanaged-type-combination-mean
http://stackoverflow.com/questions/2338146/returning-pointers-from-unmanaged-to-managed-code
CoTaskMemAlloc http://msdn.microsoft.com/en-us/library/windows/desktop/ms692727%28v=vs.85%29.aspx
*/

char *createStr(char *input)
{
    int len = strlen(input)+1;

    // can't use malloc because it needs to
    //  be accessible from another process.
    // can't use CoTaskMemAlloc because get an
    // error when trying to link, not found.
    //char *newStr = (char *)CoTaskMemAlloc(len);
    //char *newStr = (char *)malloc(len);

    char *newStr = (char *)GlobalAlloc(GPTR,len);
    //char* newStr = new char[len];
    strcpy_s(newStr, len, input);
    return newStr;
}

int Class1::getMatrixNumberOfRowsInColumnZero(int maxColumns, Class1::columnT matrix[])
{
    if (maxColumns < 1) {
        return 0;
    }
    return (matrix[0]).numberOfRows;
}

int Class1::getMatrixNumberOfRowsInColumnZero2(int maxColumns, Class1::columnT2 matrix[])
{
    if (maxColumns < 1) {
        return 0;
    }
    return (matrix[0]).numberOfRows;
}

int Class1::getMatrix(int maxColumns, int maxRows, Class1::columnT *matrix[])
{
    // require at least able to have 2 rows and 2 columns
    if ((maxColumns < 2) || (maxRows < 2)) {
        return 0;
    }
    int numberOfColumns = 2;
    int numberOfRows = 2;
    //return matrix[0].columnName[0];

    //Class1::columnT *column0 = (Class1::columnT *)GlobalAlloc(GPTR,sizeof(Class1::columnT));
    Class1::columnT *column0 = &(*matrix[0]);
    column0->columnName = createStr("Col0");
    column0->numberOfRows = numberOfRows;
    //char **rows = (char **)GlobalAlloc(GPTR,sizeof(char *)*numRows);
    column0->rows[0] = createStr("C0R0");
    column0->rows[1] = createStr("C0R1");

    Class1::columnT *column1 = &(*matrix[1]);
    //Class1::columnT *column1 = (Class1::columnT *)GlobalAlloc(GPTR,sizeof(Class1::columnT));
    column1->columnName = createStr("Col1");
    column1->numberOfRows = numberOfRows;
    //rows = (char **)GlobalAlloc(GPTR,sizeof(char *)*numRows);
    column0->rows[0] = createStr("C1R0");
    column0->rows[1] = createStr("C1R1");

    return numberOfColumns;
}

int Class1::getInt(void)
{
    return 1234;
}

char* Class1::getHi(void)
{
    //char *result = createStr("Hello");
    //return result;
    //return createStr("hello");
    return createStr("hello");
}

char** Class1::getHeaderList(void)
{
    char** list;
    list = (char **)GlobalAlloc(GPTR,sizeof(char *)*2);
    list[0]=createStr("test1");
    list[1]="test2";
    return list;
}

int Class1::getHeaderListTwo(int maxsize, char ***result)
{
    char** list;
    int len = 2;
    if (maxsize < len) {
        return NULL;
    }
    list = (char **)GlobalAlloc(GPTR,sizeof(char *)*maxsize);
    list[0]=createStr("test01");
    list[1]="test02";
    for (int i=2; i<maxsize; ++i) {
        list[i]="";
    }
    *result = list;
    return len;
}

char* Class1::getHi2(void)
{
    return "Hi";
}

char* Class1::getHi3(void)
{
    return "Hi!";
}

void Class1::getData(int *totalColumns,
                char** headers[2],
                char** items[2][3])
{
    *totalColumns = 2;
    *headers[0]=createStr("Testing");
    *headers[1]=createStr("Pets");
    *items[0][0]=createStr("test1");
    *items[0][1]=createStr("test2");
    *items[0][2]=createStr("test3");
    *items[1][0]=createStr("Cats");
    *items[1][1]=createStr("Dogs");
    *items[1][2]=createStr("Fish");
}

}


c# Form1.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using System.Runtime.InteropServices;

/*

http://msdn.microsoft.com/en-us/library/aa288468%28v=vs.71%29.aspx
http://ondotnet.com/pub/a/dotnet/2002/03/18/customcontrols.html?page=2
http://www.codeproject.com/Articles/2995/The-Complete-Guide-to-C-Strings-Part-I-Win32-Chara
http://msdn.microsoft.com/en-us/library/z6cfh6e6.aspx

 */

namespace listViewFromC
{
public partial class Form1 : Form
{
    const int maxRows = 100;
    /*
    [DllImport("cppClassLib.dll",
    CallingConvention = CallingConvention.Cdecl,
    EntryPoint = "?getInt@Class1@cppClassLib@@QAEHXZ")]
        public static extern int getInt();
    */

    // get EntryPoint using
    // "DLL Export Viewer" software

    [DllImport("cppClassLib.dll",
    CallingConvention = CallingConvention.Cdecl,
    EntryPoint = "?getHi2@Class1@cppClassLib@@SAPADXZ")]
        public static extern String getHi2();

    [DllImport("cppClassLib.dll",
    CallingConvention = CallingConvention.Cdecl,
    EntryPoint = "?getHi@Class1@cppClassLib@@SAPADXZ")]
    [return: MarshalAs(UnmanagedType.LPStr)]  
    public static extern string getHi();

    [DllImport("cppClassLib.dll",
    CallingConvention = CallingConvention.Cdecl,
    EntryPoint = "?getHeaderList@Class1@cppClassLib@@SAPAPADXZ")]
    [return: MarshalAs(UnmanagedType.LPArray, 
        ArraySubType=UnmanagedType.LPStr, SizeConst=2)]
    public static extern String[] getHeaderList();

    [DllImport("cppClassLib.dll",
    CallingConvention = CallingConvention.Cdecl,
    EntryPoint = "?getHeaderListTwo@Class1@cppClassLib@@SAHHPAPAPAD@Z")]
    public static extern int getHeaderListTwo(int maxsize,
        [MarshalAs(UnmanagedType.LPArray,
        ArraySubType = UnmanagedType.LPStr, SizeParamIndex = 0)]
        ref String[] result
        );

    [StructLayout(LayoutKind.Sequential, Pack = 4)]
    public struct columnType
    {
        public int numberOfRows;
        // note: can't marshal rows field as LPArray must be ByValArray or SafeArray
        // for maximum of maxRows rows
        [MarshalAs(UnmanagedType.ByValArray,
        ArraySubType = UnmanagedType.LPStr,
        SizeConst=maxRows)]
        public String[] rows;
        [MarshalAs(UnmanagedType.LPStr)]
        public String columnName;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct columnType2
    {
        public int numberOfRows;
    }

    [DllImport("cppClassLib.dll",
    CallingConvention = CallingConvention.ThisCall,
    EntryPoint = "?getMatrix@Class1@cppClassLib@@SEHHHQAPAUcolumnT@12@@Z")]
    public static extern int getMatrix(int maxColumns,
        int maxRows,
        [MarshalAs(UnmanagedType.LPArray,
        ArraySubType = UnmanagedType.Struct, SizeParamIndex = 0)]
        ref columnType[] matrix);

    [DllImport("cppClassLib.dll",
    CallingConvention = CallingConvention.ThisCall,
    EntryPoint = "?getMatrixNumberOfRowsInColumnZero@Class1@cppClassLib@@SEHHQAUcolumnT@12@@Z")]
    public static extern int getMatrixNumberOfRowsInColumnZero(int maxColumns,
        [MarshalAs(UnmanagedType.LPArray,
        ArraySubType = UnmanagedType.Struct, 
        SizeParamIndex = 0)]
        columnType[] matrix);

    [DllImport("cppClassLib.dll",
    CallingConvention = CallingConvention.ThisCall,
    EntryPoint = "?getMatrixNumberOfRowsInColumnZero2@Class1@cppClassLib@@SEHHQAUcolumnT2@12@@Z")]
    public static extern int getMatrixNumberOfRowsInColumnZero2(int maxColumns,
        [MarshalAs(UnmanagedType.LPArray,
        SizeParamIndex = 0,
        ArraySubType = UnmanagedType.Struct)]
        columnType2[] matrix);

    /*
    [DllImport("kernel32.dll")]
    static extern IntPtr GlobalAlloc(uint uFlags, uint dwBytes);

    const uint GMEM_FIXED = 0x0000;
    const uint GMEM_ZEROINIT = 0x0040;
    const uint GPTR = GMEM_FIXED | GMEM_ZEROINIT;
    */

    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        //label1.Text = getInt().ToString();
        label1.Text = getHi2();
        listView1.Items.Clear();
        listView1.Items.Add(label1.Text);
        //listView1.
    }

    private void button2_Click(object sender, EventArgs e)
    {
        label1.Text = getHi();
    }

    private void button3_Click(object sender, EventArgs e)
    {
        const int maxsize = 2;
        String[] headerList = new String[maxsize];
        int len = getHeaderListTwo(maxsize, ref headerList);
        MessageBox.Show("Got length " + headerList.Length+" ("+len+")");
        label1.Text="";
        for (int i = 0; i < headerList.Length; ++i)
        {
            if (headerList[i].Length>0)
            {
                label1.Text += headerList[i].ToString() + " // ";
            }
            else
            {
                label1.Text += " // ";
            }
        }
    }

    private void button4_Click(object sender, EventArgs e)
    {
        int maxColumns=5;
        int numberOfColumns = 0;
        columnType[] matrix = new columnType[maxColumns];
        for (int i = 0; i < maxColumns; ++i)
        {
            matrix[i] = new columnType();
        }
        matrix[0].numberOfRows = 1; // pick something just to see if we can get it back
        matrix[0].columnName = "ABC";
        // numberOfRows must be less than or equal to maxRows

        columnType2[] matrix2 = new columnType2[maxColumns];
        for (int i = 0; i < maxColumns; ++i)
        {
            matrix2[i] = new columnType2();
        }
        matrix2[0].numberOfRows = 1; // pick something just to see if we can get it back

        //uint sz = (uint)maxColumns*4;
        //IntPtr matrixIP = GlobalAlloc(GPTR, sz);
        //columnType[] matrix = matrixIP;

        //IntPtr pointerArr = Marshal.AllocHGlobal(maxColumns*4);

        //int result = getMatrixNumberOfRowsInColumnZero(maxColumns,matrix);
        //label1.Text = result.ToString();

        numberOfColumns = getMatrix(maxColumns, maxRows, ref matrix);
        label1.Text = matrix[0].columnName;

    }
}
}
Jevan
  • 131
  • 1
  • 6