如何在 C# 中调用/调用 char* [] [英] How To P/Invoke char* [] in C#

查看:61
本文介绍了如何在 C# 中调用/调用 char* []的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

How To P/Invoke char* [] in C#

任一个告诉以后如何继续.我想从 C# 向 C++ DLL 发送参数.我用谷歌搜索了很多网站,但没有解决方案.

Any 1 tell how to continue hereafter. I want to send parameters to C++ DLL from C#. I had googled many sites but no solution.

C 函数

public void* find(char*[] argv)
{
}

C# 函数我想用以下参数调用这个函数

C# Function i want invoke this function with following paramter arguments

char *Argv[] = { "Tool", "Sachin", "192.168.1.1", "3", "400"};

提前致谢.

推荐答案

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

There are multiple ways to do it...here are just a couple...but I outline other information you need to be aware of.

首先你需要确保你的导出的"C 函数和 DllImport 被正确定义(如果你已经有了这个,那么忽略这个部分).

First you need to make sure your "exported" C function and the DllImport are defined properly (if you have this working already, then ignore this section).

如果您的 C 函数被编译为使用 cdecl 调用约定(通常是 C/C++ 项目中的默认值),那么您需要使用 CallingConvention = CallingConvention.CdeclDllImport 例如

If your C function is compiled to use the cdecl calling convention (usually the default in C/C++ projects), then you need to use CallingConvention = CallingConvention.Cdecl on the DllImport e.g.

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

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

If your C function is compiled to use the 'stdcall' calling convention (by project options or by putting the WINAPI macro, or __stdcall decoration on the function definition), then you need to use CallingConvention = CallingConvention.Stdcall (which is the default on DllImport anyway) e.g.

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

此外,在定义C"函数时,您可以使用 extern "C" 来阻止 C++ 编译器修改函数名称.

In addition when defining a "C" function you can use extern "C" to stop the the C++ compiler mangling the name of the function.

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

You then either use __declspec(export), or use a .DEF file to specify the function as an exported entry.

重要:你需要知道你的查找"函数的契约......即它将寻找什么来表示该参数列表的结束"...它可能使用 NULL,也可能使用空字符串等.

Important: you need to know the contract of your "find" function...i.e. what will it look for to signify the "end" of that list of arguments...it might use NULL, or it might use an empty string, etc.

通常,像这样的函数有另一个参数,表示数组中项目数的计数",因此不需要标记".

Usually, functions like that, have another parameter that signifies the "count" of the number of items in the array so that a "marker" isn't needed.

对于下面的示例,我将假设它在最后使用 NULL...如果不是这样,您将不得不相应地修改代码.

For the example below, I will assume it uses NULL at the end...you will have to modify the code accordingly if it's not that way.

如果您的某些参数可能为 NULL,那么您将不得不更改用于表示结束的哨兵".

If it's possible for some of your parameters to be NULL, then you will have to change the "sentinel" used to signify the end.

    // 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.

<小时>

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

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

这篇关于如何在 C# 中调用/调用 char* []的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆