0

I am having trouble figuring out how to pass a buffer address from C# to C. I have checked several references. One seems to explain how (passing pointers referencing memory allocated in managed code to unmanaged) but when I mimic it I can't get it to work.

The output should be "This is data" but what comes out is "buffer=System.Char[]".

If I use the debugger I can see that the string "This is data" is in fact being copied properly but the address of 'buffer' in the C function is different than the address of 'buffer' in the C# code. So I'm thinking the referenced link above is assuming some other knowledge of C# which is not explained. Or maybe I just don't understand the additional answers.

Here is my code:

XBaseNamespace.cs
-----------------
//  XBase functions
using System;
using System.Runtime.InteropServices;

namespace XBaseNamespace.SecondNamespace
{
    class XBaseFunctions
    {
        [DllImport("W:\\C_sharp\\Call_C\\Debug\\C_dll.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern void ProcessBigBuffer([MarshalAs(UnmanagedType.LPArray)] char[] buffer);
    }

}

Program.cs
----------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using XBaseNamespace.SecondNamespace;


namespace Call_C
{
    class Program
    {

        static void Main()
        {
            char[] buffer = new char[1000];
            // initialize the buffer
            // and then process it
            XBaseFunctions.ProcessBigBuffer(buffer);
            Console.WriteLine("buffer={0}\n", buffer);
            Console.WriteLine("Press any key to exit...");
            Console.ReadKey();
        }
    }
}

c_dll.c
-------
//  C DLL experiment

#include <stdio.h>
#include <string.h>

#define DSI_DLL __declspec(dllexport) 
#define CALL_TYPE //__stdcall
DSI_DLL void CALL_TYPE ProcessBigBuffer( char* buffer )
{
    strcpy( buffer, "This is data" );
}
Community
  • 1
  • 1
eddyq
  • 879
  • 1
  • 13
  • 25
  • you should check the `fixed` statement. https://msdn.microsoft.com/en-us/library/f58wzh21.aspx – Jeroen van Langen Oct 27 '15 at 14:14
  • 3
    FYI to see buffer as text in the console you need to `new string(buffer)` – Alex K. Oct 27 '15 at 14:15
  • 1
    @JeroenvanLangen `fixed` isn't the issue. – GreatAndPowerfulOz Oct 27 '15 at 14:22
  • 1
    `char[]` does not print to a string like C does, you need to make a string out of it before you can print it, just like @AlexK. said. In C, char[] is analogous to a string, that is not true in C#. – Ron Beyer Oct 27 '15 at 14:23
  • I tried several variants of using 'new string(buffer)' but all give a syntax error. Can you please be more specific? – eddyq Oct 27 '15 at 15:13
  • `char[] buffer = { 'H', 'i' }; string text = new string(buffer); Console.WriteLine("buffer={0}\n", text);` – Alex K. Oct 27 '15 at 15:29
  • To be more clear on how I plan to use buffer ... buffer will be some data read from a disk file using C. The data will consist of strings, ints, longs, shorts, etc. My code will later know the format of the buffer and will access it accordingly. I could use a struct if that is better for C# so the CLI knows the format of the buffer. – eddyq Oct 27 '15 at 15:31

1 Answers1

0

I realize I had used 'char' because I'm so used to C. I should have used 'byte'. Now the buffer displays as I would expect. Here is how I did it:

XBaseNamespace.cs
-----------------
[DllImport("W:\\Dropbox\\DSI (His)\\Windows Apps\\Debug\\DsiLibrary_CSharp.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern int XBaseRead(UIntPtr pDefineFile, [MarshalAs(UnmanagedType.LPArray)] byte[] buffer, long bytes, bool reverse, O_FLAG oflag);

Program.c
---------
byte[] buffer = new byte[160];
XBaseFunctions.XBaseRead(df2500VENDR, buffer, 160, false, XBaseFunctions.O_FLAG._O_BINARY);
foreach (byte i in buffer)
{
    Console.Write("{0:X2} ", i);
}
eddyq
  • 879
  • 1
  • 13
  • 25