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
Solved

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

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

This article introduced a TextBox that supports transparent background.   Introduction TextBox is the most widely used control component in GUI design. Most GUI controls do not support transparent background and more or less do not have the…
This article is for Object-Oriented Programming (OOP) beginners. An Interface contains declarations of events, indexers, methods and/or properties. Any class which implements the Interface should provide the concrete implementation for each Inter…
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…
In an interesting question (https://www.experts-exchange.com/questions/29008360/) here at Experts Exchange, a member asked how to split a single image into multiple images. The primary usage for this is to place many photographs on a flatbed scanner…

839 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