2

I have a huge C++ structure with a lot of validation code in C++, that I want to import in a C# project. I'm able to transfer all value except the CHAR* and CHAR[].

With a CHAR*, my string is full of chiness caracter BUT, if i go look in memory, my string is there, i can see "This is a test #1".

With a CHAR[x], I can see only the 1rst char, same in memory.

In the following test, i can extract the integer : value1 = data.Value1; and value 1 is 123, but the the CHAR.

Question: What i miss, why i can't get the value with a char array. Thank you

The C++ DLL

//This is the main DLL file.
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>

extern "C"
{
  public struct Data
  {
    int Value1;
    char* pValue2;
    char Value3[1024];
  };

  typedef int( *FN_CCP_INVOKE_NEW_BOARD_OPTIMIZER) (struct Data* data);

  FN_CCP_INVOKE_NEW_BOARD_OPTIMIZER _pInvokeCallback;

  int __declspec(dllexport)  DLLTestCPlusPlus_Initialize()
  {
    return 0;
  }

  int __declspec(dllexport) DLLTestCPlusPlus_RegisterDllInvokeProcessCallback(void* fnInvokeCaller)
  {
    _pInvokeCallback = (FN_CCP_INVOKE_NEW_BOARD_OPTIMIZER)fnInvokeCaller;

    struct Data data;

    // INT
    data.Value1 = 123;

    // CHAR*
    data.pValue2 = new char[1024];
    sprintf(data.pValue2, "This is a test #1");

    // CHAR [1024]
    sprintf(data.Value3, "This is a test #2");

    if (_pInvokeCallback)
    {
      _pInvokeCallback(&data);
    }

    return 0;
  }
}

And here's the C# program that import the DLL.

using System;
using System.Runtime.InteropServices;

  public unsafe struct Data
  {
    public int Value1;
    public char* pValue2;
    public fixed char Value3[1024];
  }

  public static class Interop
  {
    public delegate Int32 Callback([MarshalAs(UnmanagedType.Struct)] Data data);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool SetDllDirectory(string lpPathName);


    [DllImport("C:\\DATA\\CODE\\ApplicationTestCSharp\\x64\\Debug\\DLLTestCPlusPlus.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern Int32 DLLTestCPlusPlus_Initialize();

    [DllImport("C:\\DATA\\CODE\\ApplicationTestCSharp\\x64\\Debug\\DLLTestCPlusPlus.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern Int32 DLLTestCPlusPlus_RegisterDllInvokeProcessCallback([MarshalAs(UnmanagedType.FunctionPtr)] Callback handler);
  }

  public class MyTest
  {
    private Interop.Callback _callback = null;

    public MyTest()
    {
      int returnCode = 0;

      returnCode = Interop.DLLTestCPlusPlus_Initialize();

      _callback = new Interop.Callback(CallbackHandler);

      returnCode = Interop.DLLTestCPlusPlus_RegisterDllInvokeProcessCallback(_callback);
    }

    private Int32 CallbackHandler(Data data)
    {
      int value1 = 0;
      string value2 = "";
      string value3 = "";

      unsafe
      {
        // INT
        value1 = data.Value1;

        // CHAR* - MUST BE "This is a test #1"
        value2 = new string(data.pValue2);

        // CHAR [1024] - "This is a test #2"
        value3 = new string(data.Value3);
      }

      return 1;
    }
  }

  class Program
  {
    static void Main(string[] args)
    {
      MyTest myTest = new MyTest();

    }
  }
2
  • Hanzi suggests that you're passing ASCII text to something expecting UTF-16. P/Invoke lets you specify what type of text it is. Commented Sep 21, 2017 at 12:49
  • On the C# side, in your unsafe struct, use byte instead of char and convert to text using Encoding.Default.GetString. Commented Sep 21, 2017 at 13:01

1 Answer 1

2

Ok i found it, i made that change in the structure declaration

   /*
      public char* pValue2;
      public fixed char Value3[1024];
      */
      [MarshalAs(UnmanagedType.LPStr)] public String pValue2;
      [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)] public String pValue3;

And pull the data like that!

  // CHAR* - "This is a test #1";
  // value2 = new string(data.pValue2);
     value2 = data.pValue2

  // CHAR [1024] - "This is a test #2"
  //value3 = new string(data.Value3);
    value3 = data.pValue3;
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.