Solved

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

Posted on 2004-03-25
2
1,721 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
  • 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: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say 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

Extention Methods in C# 3.0 by Ivo Stoykov C# 3.0 offers extension methods. They allow extending existing classes without changing the class's source code or relying on inheritance. These are static methods invoked as instance method. This…
Summary: Persistence is the capability of an application to store the state of objects and recover it when necessary. This article compares the two common types of serialization in aspects of data access, readability, and runtime cost. A ready-to…
The Email Laundry PDF encryption service allows companies to send confidential encrypted  emails to anybody. The PDF document can also contain attachments that are embedded in the encrypted PDF. The password is randomly generated by The Email Laundr…
Exchange organizations may use the Journaling Agent of the Transport Service to archive messages going through Exchange. However, if the Transport Service is integrated with some email content management application (such as an antispam), the admini…

749 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