简体   繁体   English

如何在c#代码中通过引用调用时从c ++ dll更新数组值?

[英]How to update array values from c++ dll while calling by reference in c# code?

I am calling a function (named cbFunction) from a c++ dll using c# code. 我正在使用c#代码从c ++ dll调用一个函数(名为cbFunction)。 I have to pass array of strings (named strArray) ,from c# code, as arguments to c++ 'cbFunction'. 我必须从c#代码传递字符串数组(名为strArray),作为c ++'cbFunction'的参数。 Inside c++ function, I have to change the array's values. 在c ++函数内部,我必须更改数组的值。 The newly changed values should be read back in c# code. 新更改的值应以c#代码读回。

Problems I face: 我面临的问题:

  1. The base address of strArray in c# and the one received in arguments in c++ dll are totally different. c#中strArray的基地址与c ++ dll中的自变量接收的基地址完全不同。
  2. I can read the array of strings in c++ dll. 我可以在c ++ dll中读取字符串数组。 But, I have to modify the array's values inside c++ function. 但是,我必须在c ++函数中修改数组的值。 When I change those values in c++ function, the change is not reflected in c# code. 当我在c ++函数中更改这些值时,更改不会反映在c#代码中。 ` `

C# code C#代码

public static class Call_API
{
   [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
   private delegate bool CallBackFunction(string[] argv, int argc);

   private static  string[] strArray;

   public static void ChangeValue()
   {
      IntPtr pDll = NativeMethods.LoadLibrary("DllFunctions.dll");
      IntPtr pAddressOfFunctionToCall = NativeMethods.GetProcAddress(pDll, "cbFunction");

      string args = "Hello Disney World";
      strArray = args.Split(' ');
      CallBackFunction cbFunction = ((CallBackFunction)Marshal.GetDelegateForFunctionPointer(
                                                  pAddressOfFunctionToCall, typeof(CallBackFunction));
      if(false == cbFunction(strArray, strArray.Count()))
      {
          //some task
      }
   }
}

c++ dll code (DllFunctions.dll) : C ++ dll代码(DllFunctions.dll):

bool cbFunction(char** argv, int argc)
{
   //Some task

   char VarValue[256] = { 0 };
   std::string s = "Jetix";
   sprintf_s(VarValue, s.c_str());

   strcpy_s(argv[1], sizeof(VarValue), VarValue);
   return false;
}

Based on this code, my expected values at the end in strArray (in c#) are {"Hello", "Jetix", "World"}. 根据此代码,我在strArray(在c#中)末尾的期望值为{“ Hello”,“ Jetix”,“ World”}。

Thanks in advance! 提前致谢!

First of all a char in c# is not the same as char in c++. 首先一个的char在C#中是一样的char在C ++中。 You need an sbyte in c# which is the same as char in c++. 您需要一个sbyte在C#这是相同的char在C ++中。 We will use a byte for convenience. 为了方便起见,我们将使用一个byte It works fine. 工作正常。

Code: 码:

string args = "Hello Disney World";
string[] strArray = args.Split( ' ' );

byte[][] byteArray = new byte[ strArray.Length ][ ];

//convert string to byte array
for( int i = 0; i < strArray.Length; i++ ) {
    byteArray[ i ] = Encoding.ASCII.GetBytes( strArray[ i ] );
}

To get a byte** , you need a byte*[] ( More info Converting from a jagged array to double pointer in C# ): 要获得一个byte** ,您需要一个byte*[] (更多信息,在C#中从锯齿状数组转换为双指针 ):

unsafe
{
    GCHandle[] pinnedArray = new GCHandle[ byteArray.Length ];
    byte*[] ptrArray = new byte*[ byteArray.Length ];

    for( int i = 0; i < byteArray.Length; i++ ) {
        pinnedArray[ i ] = GCHandle.Alloc( byteArray[ i ], GCHandleType.Pinned );
    }

    for( int i = 0; i < byteArray.Length; i++ ) {
        ptrArray[ i ] = (byte *)pinnedArray[ i ].AddrOfPinnedObject();
    }

    fixed ( byte **ptr = &ptrArray[ 0 ] ) {
        IntPtr mptr = (IntPtr)ptr;

        if( false == cbFunction( mptr, strArray.Count() ) ) {
            //some task
        }

    }

    for( int i = 0; i < pinnedArray.Length; i++ )
        pinnedArray[ i ].Free();

}

Your declaration should be: 您的声明应为:

[UnmanagedFunctionPointer( CallingConvention.Cdecl )]
private delegate bool CallBackFunction( IntPtr argv, int argc );

EDIT 编辑

For completion there is an easier way to to do it ( Marshaling Data with Platform Invoke , Marshaling Different Types of Arrays ): 为了完成,有一种更简单的方法( 使用Platform Invoke整理数据整理不同类型的数组 ):

bool cbFunction(char *argv[], int argc)
{
    //Some task
    STRSAFE_LPSTR temp;
    const size_t alloc_size = sizeof(char) * 5; //"Jetix" num of characters

    temp = (STRSAFE_LPSTR)CoTaskMemAlloc( alloc_size );
    StringCchCopyA( temp, alloc_size, (STRSAFE_LPSTR)"Jetix" );

    CoTaskMemFree( argv[1] );
    argv[1] = (char *) temp;

    return false;
}

Call it: 称它为:

string args = "Hello Disney World";
strArray = args.Split(' ');
CallBackFunction cbFunction = ((CallBackFunction)Marshal.GetDelegateForFunctionPointer(
                                pAddressOfFunctionToCall, typeof(CallBackFunction));

if( false == cbFunction(strArray, strArray.Count()) )
{
    //some task
}

And declaration: 并声明:

[UnmanagedFunctionPointer( CallingConvention.Cdecl )]
public delegate bool CallBackFunction( [In, Out] String[] argv, int argc );

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM