如何在C#中调用char* []
任何1告诉以后如何继续。 我想从C#向C ++ DLL发送参数。我搜索了许多网站但没有解决方案。
C函数
public void* find(char*[] argv)
{
}
C#功能 我想用以下参数参数
调用此函数char *Argv[] = { "Tool", "Sachin", "192.168.1.1", "3", "400"};
先谢谢。
答案 0 :(得分:5)
有多种方法可以做到这一点......这里只是一对...但我概述了你需要注意的其他信息。
首先,您需要确保"导出" C函数和DllImport
已正确定义(如果已经有效,则忽略此部分)。
如果您的C函数被编译为使用cdecl
调用约定(通常是C / C ++项目中的默认约定),那么您需要在CallingConvention = CallingConvention.Cdecl
上使用DllImport
,例如
[DllImport("yourdll.dll", CharSet = Ansi, CallingConvention = CallingConvention.Cdecl)]
public IntPtr find([In] String[] args);
如果你的C函数被编译为使用' stdcall'调用约定(通过项目选项或通过在函数定义上放置WINAPI宏或__stdcall装饰),然后你需要使用CallingConvention = CallingConvention.Stdcall
(这是DllImport的默认值),例如。
[DllImport("yourdll.dll", CharSet = Ansi)]
public IntPtr find([In] String[] args);
此外,在定义" C"函数你可以使用extern "C"
来阻止C ++编译器修改函数的名称。
然后使用__declspec(export)
或使用.DEF文件将该函数指定为导出条目。
重要提示:您需要知道"发现"的合同。功能...即。什么意味着表示"结束"该参数列表...它可能使用NULL,或者它可能使用空字符串等。
通常,像这样的函数有另一个参数来表示" count"数组中的项目数量,以便"标记"不需要。
对于下面的示例,我将假设它最后使用NULL ...如果不是这样,你将不得不相应地修改代码。
如果某些参数可能为NULL,那么您必须更改" sentinel"用来表示结束。
// 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);
}