簡體   English   中英

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

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

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

任何一個告訴以后如何繼續。 我想將參數從C#發送到C ++ DLL。 我在Google上搜索了很多網站,但沒有解決方案。

C功能

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

C#函數我想用以下參數調用此函數

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

提前致謝。

有多種方法可以實現...這里只是幾個...但是我概述了您需要注意的其他信息。


正確導出/導入“查找”功能

首先,您需要確保正確定義了“導出的” C函數和DllImport (如果已經進行了此工作,則忽略此部分)。

如果您的C函數被編譯為使用cdecl調用約定(通常是C / C ++項目中的默認約定),則需要在DllImport上使用CallingConvention = CallingConvention.Cdecl

[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,或者可能使用空字符串,等等

通常,類似的函數具有另一個參數,該參數表示數組中項數的“計數”,因此不需要“標記”。

對於下面的示例,我將假設它最后使用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.

或者,您可以自己執行封送處理邏輯(根據需要重新排列和擴展代碼以清理內存等):

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM