• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1448
  • Last Modified:

int** and native Dlls (double pointers,unsafe code etc)

I have to use a native dll that takes a int** as a parameter.

I have linked the dll function correctly ....

  [DllImport(DllPath, CallingConvention = CallingConvention.Cdecl)]
        public static extern int *MethodName(int** x,int n,char* filename);

But I can't for the life of me work out how to make a double pointer in c#.  I can do it for a single array and single pointer ...

int[] sarray = new int[1];
fixed (int* sptr = sarray)
{
}  

I have built a 2d array of ints

int[][] data = new int[n][];

and  I loop through a populate etc

Now how do I get a int** from this?

fixed (int** dptr = data)
{}  ????????????

0
tristan256
Asked:
tristan256
  • 5
  • 4
1 Solution
 
Carl TawnSystems and Integration DeveloperCommented:
Have you just tried passing "data" to the function ? If its a 2D array then the name of the array should also be a pointer-to-pointer to the first block in the second dimension.
0
 
AlexFMCommented:
The answer depends on the way unmanaged function treats int** parameter. It can be pointer to contingous memory block n*m*sizeof(int) - static array, or array of int* pointers (dynamic array). Assuming that this is continguous array, you can make unmanaged memory block with n*m integers and pass pointer to it to unmanaged function.

IntPtr array = Marshal::AllocHGlobal(Marshal::SizeOf(typeof(int))*n*m);

This line allocates unmanaged block for  n*m integers. Now you can fill this block line by line using one of the following ways:
- using Marshal.WriteInt32 Method (IntPtr, Int32, Int32), changing offset from 0 to (n*m-1)*Marshal::SizeOf(typeof(int))
- using Marshal.Copy Method (Int32[], Int32, IntPtr, Int32), copy single-dimentional managed array to unmanaged.

First parameter of MethodName function should have IntPtr type, pass array variable to function.
Replace char* filename with string filename, with CharSet = ANSII.
Replace int* return type to IntPtr and read result using Marshal.ReadInt32 method.

Don't forget to release array after using with Marshal::FreeHGlobal method.
Notice that of this is dynamic array, you need another algorithm.
0
 
AlexFMCommented:
If you have code of MethodName function or unmanaged code which calls it, please post this code. This gives enough information to write C# client code.
0
Cloud Class® Course: Python 3 Fundamentals

This course will teach participants about installing and configuring Python, syntax, importing, statements, types, strings, booleans, files, lists, tuples, comprehensions, functions, and classes.

 
tristan256Author Commented:
Yeah I tried just passing the array hoping it would marashal it for me but I get this error ...

"Cannot marshall parameter #1': There is no marshalling support for nested arrays."

I will find out exactly what the dll is doing and post some of the code.

0
 
AlexFMCommented:
.NET interoperability is based on marshalling data between managed and unmanaged memory. It is implemented using Marshal class functions, which are easy to understand for programmer with C++ experience.
Unsafe pointers support in C# is restricted and I don't suggest to use it for interoperability. Read about Marshal class in MSDN , I hope this can help. You can post more code if necessary.
0
 
tristan256Author Commented:
OK I've found out its contiguous.  

Haven't got any code to post yet, but I will give your suggestions a go and read about the Marshall class.  
0
 
tristan256Author Commented:
ok so I did this ...

change the method ...

        [DllImport(DllPath, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
        public static extern void calibrate(IntPtr x, int n, int k, string filename);

Now build the pointer the unmagaed memory ...

 IntPtr DataPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(int))*NumberOfPixels*ColourDimensions);

for (i = 0; i < NumberOfPixels; i++)
                for(j = 0; j < ColourDimensions; j++)
                    Marshal.WriteInt32(DataPtr, i + j, data[i][j]);

But get this error ...

Attempted to read or write protected memory.  This is often an indication the memory is corrupt.

Any suggestions?
0
 
AlexFMCommented:
Try this:

int offset = 0;

for (i = 0; i < NumberOfPixels; i++)
{
                for(j = 0; j < ColourDimensions; j++)
                {
                    Marshal.WriteInt32(DataPtr,offset, data[i][j]);
                    offset += Marshal.SizeOf(typeof(int));
                }
}

I will test this now.
0
 
AlexFMCommented:
The following test succeeded:

    class Program
    {
        static int[,] intArray = new int[5, 10];

        static void Main(string[] args)
        {
            IntPtr DataPtr = Marshal.AllocHGlobal(
                Marshal.SizeOf(typeof(int)) *
                intArray.GetLength(0) *
                intArray.GetLength(1));

            int offset = 0;

            for (int i = 0; i < intArray.GetLength(0); i++ )
            {
                for (int j = 0; j < intArray.GetLength(1); j++ )
                {
                    Marshal.WriteInt32(DataPtr, offset, intArray[i, j]);
                    offset += Marshal.SizeOf(typeof(int));
                }
            }

            Marshal.FreeHGlobal(DataPtr);
        }
    }
0
 
tristan256Author Commented:
Ooops! Sorry, forgot to accept the answer, worked great.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

  • 5
  • 4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now