如何在C#中P /调用char * []

use*_*182 1 c# c++ pinvoke

如何char* []在C#中P /调用

任何一个告诉以后如何继续。我想将参数从C#发送到C ++ DLL。我在Google上搜索了很多网站,但没有解决方案。

C功能

public void* find(char*[] argv)
{
}
Run Code Online (Sandbox Code Playgroud)

C#函数我想用以下参数调用此函数

char *Argv[] = { "Tool", "Sachin", "192.168.1.1", "3", "400"};
Run Code Online (Sandbox Code Playgroud)

提前致谢。

Col*_*ith 5

有多种方法可以实现...这里只是几个...但是我概述了您需要注意的其他信息。


正确导出/导入“查找”功能

首先,您需要确保“导出的” C函数和DllImport正确定义(如果您已经进行了此工作,则忽略此部分)。

如果将您的C函数编译为使用cdecl调用约定(通常是C / C ++项目中的默认约定),则需要CallingConvention = CallingConvention.CdeclDllImporteg 上使用

[DllImport("yourdll.dll", CharSet = Ansi, CallingConvention = CallingConvention.Cdecl)]
public IntPtr find([In] String[] args);
Run Code Online (Sandbox Code Playgroud)

如果您的C函数被编译为使用“ stdcall”调用约定(通过项目选项或通过在函数定义上放置WINAPI宏或__stdcall装饰),则需要使用CallingConvention = CallingConvention.Stdcall(无论如何,这是DllImport的默认设置),例如

[DllImport("yourdll.dll", CharSet = Ansi)]
public IntPtr find([In] String[] args);
Run Code Online (Sandbox Code Playgroud)

另外,在定义“ C”函数时,可以使用extern "C"C ++编译器停止处理该函数的名称。

然后__declspec(export),您可以使用或使用.DEF文件将函数指定为导出的条目。


您的“查找”合同是什么?

重要提示:您需要了解“查找”函数的约定...即表示该参数列表的“结尾”的含义...它可能使用NULL,或者可能使用空字符串,等等

通常,类似的函数具有另一个参数,该参数表示数组中项数的“计数”,因此不需要“标记”。

对于下面的示例,我将假设它最后使用NULL ...如果不是那样,则必须相应地修改代码。

如果某些参数可能为NULL,则必须更改用于表示结尾的“前哨”。


您可以在C#和本机类型之间进行“封送处理”(使用“封送处理”属性):

    // Note: this uses a "NULL" to mark the end of the array...
    // because your "find" function doesn't have a "count" parameter, and I'm
    // assuming it uses a NULL parameter to detect the end. 

    IntPtr opaqueresult = find(new string[] { "Tool", "Sachin", "192.168.1.1", "3", "400", null});  // call the function in that DLL.
Run Code Online (Sandbox Code Playgroud)

或者,您可以自己执行封送处理逻辑(根据需要重新排列和扩展代码以清理内存等):

// When need to use IntPtr as we are allocating the native memory.
[DllImport("yourdll.dll", CharSet = Ansi)]
public IntPtr find([In] IntPtr args);

IntPtr []allocatednativestrings;
IntPtr args = AllocateAnsiIntPtrArrayWithSentinel( new string[] { "Tool", "Sachin", "192.168.1.1", "3", "400"}, out allocatednativestrings);

IntPtr opaqueresult = find(args);  // call the function in that DLL.

// If "find" DOESN'T hold onto the pointers passed into it, then you can "free"
// the memory just after you make the call....otherwise you can't...you then
// have to decide how/who has responsibility for freeing that memory and when.

// Free the "strings", and the memory containing the pointers
FreeAnsiIntPtrArrayWithSentinel(args, allocatednativestrings);

(Note: I am only using this bit of hacky code, as it was mentioned in a comment above...
http://www.codeproject.com/Articles/17450/Marshal-an-Array-of-Zero-Terminated-Strings-or-Str ....
the crucial thing is to make sure you "free" the memory properly, when you are finished with it....
this can be done neater...just giving you enough to get the idea) 

public static IntPtr AllocateAnsiIntPtrArrayWithSentinel(string[] InputStrArray, out IntPtr[] InPointers)
{
    int size = InputStrArray.Length + 1; // +1 for NULL sentinel

    //build array of pointers to string
    InPointers = new IntPtr[size];

    int dim = IntPtr.Size * size;

    IntPtr rRoot = Marshal.AllocCoTaskMem(dim);

    int i = 0;
    foreach(string arg in args)
    {
        if (arg == null)
        {
            System.Diagnostics.Debug.Assert(false, "this code needs changing to support NULL arguments");
        }

        InPointers[i++] = Marshal.StringToCoTaskMemAnsi(arg);
    }

    // The NULL sentinel...don't need to do this as already initialized to null...
    // but just making it clearer for you.
    InPointers[size-1] = IntPtr.Zero;

    //copy the array of pointers
    Marshal.Copy(InPointers, 0, rRoot, size);
    return rRoot;
} 

public static void FreeAnsiIntPtrArrayWithSentinel(IntPtr args, IntPtr[] intptrs)
{
    foreach(IntPtr ptr in intptrs)
    {
        if (ptr != IntPtr.Zero) // we need to avoid the sentinel
            Marshal.FreeCoTaskMem(ptr); // free the mem allocated for the string
    }

    // free the memory that contained the list of string pointers and sentinel
    Marshal.FreeCoTaskMem(args);
}
Run Code Online (Sandbox Code Playgroud)