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

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

本文关键字:c++ dll 更新 数组 调用 引用 代码      更新时间:2023-10-16

我正在使用c#代码从c ++ dll调用一个函数(名为cbFunction(。我必须将字符串数组(名为strArray(从c#代码作为参数传递给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 code (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"}。

提前感谢!

首先,C#中的char与C++中的char不同。您需要一个 c# 中的sbyte,它与 c++ 中的char相同。为方便起见,我们将使用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 );

编辑

对于完成,有一种更简单的方法可以做到这一点(使用平台调用封送数据,封送不同类型的数组(:

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