Solved

Importing a C-style .dll AND marshalling confusing data types.

Posted on 2004-03-25
2
1,726 Views
Last Modified: 2012-06-27
I am using the .NET Interop services to import a .dll written in C.  One of the functions in the .dll has some very confusing data types.  I'm new to marshalling data types - anyone want to help?

//// The original C-style function declaration looks something like this:
__int32 FunctionName( void * A, const char * B, unsigned char * C, unsigned __int32 D, unsigned char ** E, unsinged __int32 * F, unsigned char ** G, unsigned __int32 * G);

//// My C# code will look something like this:
using System;
using System.Runtime.InteropServices;

namespace SomeNamespace
{
   public class SomeClass
   {
        [ DllImport( "SomeLibrary.dll" )]
        public static extern int FunctionName( ..... WHAT SHOULD I DO NEXT ????? )
   }
}

//////////
So, my question is: what C# treatment do I give all those ugly C-style data types???

Thanks!!!
0
Comment
Question by:TheGooch
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 2
2 Comments
 
LVL 48

Expert Comment

by:AlexFM
ID: 10684760
All pointers (including **) should be passed as IntPtr.
Rwad about Marshal class. You need its functions to prepare input parameters to this function and to read output parameters.
For example, if A parameter expects pointer to some data, allocate memory block in C# using Marshal.AllocHGlobal Method. It returns IntPtr. Fill this block using unsafe programming and pass IntPtr to FunctionName.
If B points to ansi string, use Marshal.StringToHGlobalAnsi Method to allocate this string on non-managed heap and pass result IntPtr to the function.
Double pointer (**) may be passed as IntPtr ref or out parameter.
0
 
LVL 48

Accepted Solution

by:
AlexFM earned 500 total points
ID: 10685572
After reading your question I decided to make small C# PInvoke exersize. I hope it can help you. Consider the following C Dll:

// Function gets void* pointer and increments
// 3 starting bytes in it
SERVERDLL_API void Function1(void* p)
{
    char* pc = (char*) p;

    (*pc++)++;
    (*pc++)++;
    (*pc++)++;
}

// Function gets const pointer to string
SERVERDLL_API void Function2(const char* p)
{
    MessageBox(NULL, p, NULL, MB_OK);
}


// Function gets pointer to integer
SERVERDLL_API void Function3(int* p)
{
    *p = 10;
}

// Function gets char** and allocates ansi string
SERVERDLL_API void Function4(char** p)
{
    *p = new char[20];
    strcpy(*p, "string from C");
}

// Function releases char* string
SERVERDLL_API void Release(char* p)
{
    delete[] p;
}

This is C# console application which calls all these functions:


namespace PInvokeClient
{
    class Class1
    {

        #region void* parameter (Test 1)

        [DllImport ("ServerDll.dll")]
        public static extern void Function1(IntPtr p);

        static void Test1()
        {
            // allocate memory on unmanaged heap
            IntPtr ptr = Marshal.AllocHGlobal(3);

            // Fill is with 3 bytes
            unsafe
            {
                byte* pByte = (byte*)ptr;

                *pByte = 50;
                *(pByte+1) = 51;
                *(pByte+2) = 52;
            }

            Function1(ptr);   // increment each bytes

            // read result (output is 51, 52, 53)
            unsafe
            {
                byte* pByte = (byte*)ptr;

                Console.WriteLine( *pByte );
                Console.WriteLine( *(pByte+1) );
                Console.WriteLine( *(pByte+2) );
            }

            // free memory
            Marshal.FreeHGlobal(ptr);
        }
        #endregion


        #region const char* parameter (Test 2)

        [DllImport ("ServerDll.dll")]
        public static extern void Function2(IntPtr p);

        static void Test2()
        {
            String s = @"String from C#";

            // allocate string on unmanaged heap
            IntPtr ptr = Marshal.StringToHGlobalAnsi(s);

            Function2(ptr);


            // free memory
            Marshal.FreeCoTaskMem(ptr);
        }
        #endregion


        #region int* parameter (Test 3)

        [DllImport ("ServerDll.dll")]
        public static extern void Function3(IntPtr p);

        static void Test3()
        {
            // allocate memory on unmanaged heap
            IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(int)));

            Function3(ptr);

            // read result
            unsafe
            {
                int* pInt = (int*)ptr;

                Console.WriteLine( *pInt );
            }

            // free memory
            Marshal.FreeHGlobal(ptr);
        }
        #endregion

        #region char** parameter (Test 4)

        [DllImport ("ServerDll.dll")]
        public static extern void Function4(out IntPtr p);
        [DllImport ("ServerDll.dll")]
        public static extern void Release(IntPtr p);

        static void Test4()
        {
            IntPtr ptr;

            Function4(out ptr);

            string s = Marshal.PtrToStringAnsi(ptr);

            Console.WriteLine(s);

            Release(ptr);

        }
        #endregion


        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main(string[] args)
        {
            Test1();
            Test2();
            Test3();
            Test4();
        }
    }
}

As you see, handling of C function parameters depends on their type and function algorithm. Marshal class and unsafe programming make C# program flexible enough to call various C functions.

Read also this article:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/html/csharp09192002.asp
0

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Return array 3 35
Stop Git from being my repository 1 51
c# ftp code 3 56
How to input barcode scanner data into textbox in C#  ? 13 67
Real-time is more about the business, not the technology. In day-to-day life, to make real-time decisions like buying or investing, business needs the latest information(e.g. Gold Rate/Stock Rate). Unlike traditional days, you need not wait for a fe…
Performance in games development is paramount: every microsecond counts to be able to do everything in less than 33ms (aiming at 16ms). C# foreach statement is one of the worst performance killers, and here I explain why.
I've attached the XLSM Excel spreadsheet I used in the video and also text files containing the macros used below. https://filedb.experts-exchange.com/incoming/2017/03_w12/1151775/Permutations.txt https://filedb.experts-exchange.com/incoming/201…

751 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question