繁体   English   中英

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

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

我正在使用c#代码从c ++ dll调用一个函数(名为cbFunction)。 我必须从c#代码传递字符串数组(名为strArray),作为c ++'cbFunction'的参数。 在c ++函数内部,我必须更改数组的值。 新更改的值应以c#代码读回。

我面临的问题:

  1. c#中strArray的基地址与c ++ dll中的自变量接收的基地址完全不同。
  2. 我可以在c ++ dll中读取字符串数组。 但是,我必须在c ++函数中修改数组的值。 当我在c ++函数中更改这些值时,更改不会反映在c#代码中。 `

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代码(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;
}

根据此代码,我在strArray(在c#中)末尾的期望值为{“ Hello”,“ Jetix”,“ World”}。

提前致谢!

首先一个的char在C#中是一样的char在C ++中。 您需要一个sbyte在C#这是相同的char在C ++中。 为了方便起见,我们将使用一个byte 工作正常。

码:

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 ] );
}

要获得一个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();

}

您的声明应为:

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

编辑

为了完成,有一种更简单的方法( 使用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;
}

称它为:

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

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

并声明:

[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