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

How to p/invoke the following c++ code

Hi there,

i have a c++ dll with two functions in it. The functions look like this:

bool Open (CHAR *file)

bool Read (TCHAR *buffer, unsigned int uiSize)

What i want to do is calling these two functions from within my c#
code. As i understand it the Open function wants a pointer to a filename,
and the Read function wants a pointer to a buffer to which the read string
is written to, and the size of the buffer.

(Quick hint: I know opening/reading from textfiles work in c# aswell, but
this task needs me to use this dll)

Please help me writing up the proper p/invoke (DllImport) code including an example
that shows the use of the p/invoked code, including the return value.

Thank you,
Jesssi
0
jessicasmith
Asked:
jessicasmith
  • 5
  • 4
  • 2
1 Solution
 
jessicasmithAuthor Commented:
Hello A.,

can you please provide a working example for my functions?

Thank you,
Jessi
0
 
elticCommented:
Try this two calls. Your .NET runtime marshalles the used data types automatically
to the requested character-pointer.

using System.Text;
using System.Runtime.InteropServices;

[DllImport("DllName.dll")]
static extern bool Open (string file)

[DllImport("DllName.dll")]
static extern bool Read (StringBuilder buffer, UInt32 uiSize)

static void Main()
{
        if (Open("MyFile.txt"))
        {
              StringBuilder sb = new StringBuilder(255); /// Insert your buffer size here
              while(Read(sb, 255))
              {
                        Console.WriteLine(sb.ToString());
              }
        }
        else
        {
               throw (new System.IO.IOException("Error opening file"));
        }
}
0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
jessicasmithAuthor Commented:
Hello eltic,

i tried your sample - without success. I always receive an IOException.

The owner of the c++ dll told me that the memory allocations have to
be strictly seperated. Therefore i cannot use a string class as filename
in the Open function.

Can you rewrite the example so that it assigns explicit pointers (IntPtr ?)
to the functions?

Thank you,
Jessie
0
 
AgariciCommented:
[DllImport("kernel32.dll")]
static extern bool GetDiskFreeSpace(
   [MarshalAs(UnmanagedType.LPTStr)]
   string rootPathName );
0
 
elticCommented:
using System.Text;
using System.Runtime.InteropServices;

[DllImport("DllName.dll")]
static extern bool Open (IntPtr fileName)

[DllImport("DllName.dll")]
static extern bool Read (StringBuilder buffer, UInt32 uiSize)

private IntPtr CopyToUnmanaged(string str)
{
      byte[] bStr = Encoding.Default.GetBytes(str + "\0");
      IntPtr handle = Marshal.AllocHGlobal(Convert.ToInt32(bStr.Length));
      if (handle != IntPtr.Zero)
      {
            Marshal.Copy(bStr, 0, handle, bStr.Length);
      }
      return handle;
}

static void Main()
{
        IntPtr ptr = CopyToUnmanaged("MyFile.txt");
        if (Open(ptr))
        {
              StringBuilder sb = new StringBuilder(255); /// Insert your buffer size here
              while(Read(sb, 255))
              {
                        Console.WriteLine(sb.ToString());
              }
        }
        else
        {
               throw (new System.IO.IOException("Error opening file"));
        }
}
0
 
jessicasmithAuthor Commented:
Hello eltic,

you example works now !!

It opens the testfile and shows me content. Though the content only
containt "boxes", which I assume are something like null bytes?

It doesnt show the ascii text in the testfile. This, so I think is due to
the fact that the Read function isnt working with Pointers - unlike
your fixed Open function.

Can you fix the Read function so it uses IntPtr's too? I am positive
that is the final catch, and the points will be yours.

Thank you,
Jessie
0
 
elticCommented:
Sorry, forgot to fix ot, too:

[DllImport("DllName.dll")]
        static extern bool Open(IntPtr fileName);

        [DllImport("DllName.dll")]
        static extern bool Read(IntPtr buffer, UInt32 uiSize);

        private static IntPtr CopyToUnmanaged(string str)
        {
            byte[] bStr = Encoding.Default.GetBytes(str + "\0");
            IntPtr handle = Marshal.AllocHGlobal(Convert.ToInt32(bStr.Length));
            if (handle != IntPtr.Zero)
            {
                Marshal.Copy(bStr, 0, handle, bStr.Length);
            }
            return handle;
        }

        static void Main()
        {
            IntPtr ptr = CopyToUnmanaged("MyFile.txt");
            if (Open(ptr))
            {
                IntPtr buffer = Marshal.AllocHGlobal(255);
                try
                {
                    while (Read(buffer, 255))
                    {
                        string bufferText = Marshal.PtrToStringAnsi(buffer);
                        /// Do something with the text
                    }
                }
                finally
                {
                    Marshal.FreeHGlobal(buffer);
                }
            }
            else
            {
                throw (new System.IO.IOException("Error opening file"));
            }
            Marshal.FreeHGlobal(ptr);
        }
0
 
jessicasmithAuthor Commented:
Hello Eltic,

thank you for fixing this.

However (*yawn*), i am missing the function Marshal.PtrToStringAnsi().

This is most likely due to the fact that i am using the .NET Compact Framework (2.0).
Any alternative for that available?

When i use

    string bufferText = Marshal.PtrToUni(buffer);

the result is the same as previously (null bytes).

When i use

    string bufferText = Marshal.PtrToBSTR(buffer);

then i receive a out of memory exception.


Any idea how to solve this? (we are almost there :-))

Thank you,
Jessi
0
 
elticCommented:
Replace the following lines:

while (Read(buffer, 255))
{
     string bufferText = Marshal.PtrToStringAnsi(buffer);
     /// Do something with the text
}

with this:

while (Read(buffer, 255))
{
     byte[] textBuffer = new byte[255];
     Marshal.Copy(buffer, textBuffer, 0, 255);
     string text = System.Text.Encoding.ASCII.GetString(textBuffer);
     /// Do something with the text
}
0
 
jessicasmithAuthor Commented:
Hello eltic,

yes that works perfectly :-))

And the points are all yours!

Thank you,
Jessi
0

Featured Post

New feature and membership benefit!

New feature! Upgrade and increase expert visibility of your issues with Priority Questions.

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