簡體   English   中英

將C#結構傳遞給C ++非托管DLL返回錯誤的結果

[英]Passing C# struct to C++ unmanaged DLL returning incorrect result

我有一個在Visual Studio 2017中開發並在64位環境中編譯的簡單C ++ win32 DLL,具有以下代碼:

typedef struct sum {
    struct  {
        int num1;
        int num2;
    } nums;
} sum1;

extern "C" {

__declspec(dllexport) int initialize(sum1 *summing)
{
    int res;
    res = summing->nums.num1 + summing->nums.num2;
    return res;
}

}

上面的代碼包含一個方法,該方法通過將typedef結構作為參數返回兩個整數的和。

我有一個使用PInvoke消耗此Win32 C ++ DLL的C#客戶端應用程序。 以下是我的C#客戶端應用程序的代碼:

[StructLayout(LayoutKind.Sequential)]
public struct nums
{
    public int a;
    public int b;
}

[StructLayout(LayoutKind.Sequential)]
public struct mydef
{
    public IntPtr sum;
}

public class LibWrap
{    
    [DllImport("C++.dll", EntryPoint = "initialize")]
    public static extern int Initialize(ref mydef mydef);
}

class Program
{
    static void Main(string[] args)
    {
        mydef mydef = new mydef();
        nums nums;
        nums.a = 6;
        nums.b = 6;

        IntPtr buffer1 = Marshal.AllocCoTaskMem(Marshal.SizeOf(nums));
        Marshal.StructureToPtr(nums, buffer1, false);
        mydef.sum = buffer1;

        int res = LibWrap.Initialize(ref mydef);

        Console.WriteLine(res);
    }
}

使用上面的代碼,我期望輸出為'12',但是我將輸出為'-1504178328'。

我是一位完全沒有C ++經驗的C#開發人員。 請幫我解決這個問題。

使用更簡單的P / Invoke包裝器:

public static class LibWrap
{
    [DllImport("C++.dll", EntryPoint = "initialize")]
    public static extern int Initialize(ref Nums nums);

    [StructLayout(LayoutKind.Sequential)]
    public struct Nums
    {
        public int a;
        public int b;
    }
}

並像這樣使用它:

void CSharpExample()
{
    LibWrap.Nums nums;
    nums.a = 6;
    nums.b = 7;
    int res = LibWrap.Initialize(ref nums);
    Console.WriteLine(res);
}

在您的示例中,您不需要任何內存分配和封送處理,因為:

  • LibWrap.Nums是一個結構,因此CSharpExample()局部變量nums完全分配在堆棧上。
  • 通過ref將托管結構LibWrap.Nums傳遞給LibWrap.Initialize將指針傳遞給堆棧上的局部變量nums
  • LibWrap.Initialize是同步調用的,因此,傳遞給它的指針在LibWrap.Initialize函數退出后不會在任何地方使用。 這很重要,因為一旦CSharpExample()退出,指針就會變得無效。

在C#端,您沒有正確處理嵌套結構。 嘗試以下方法:

[StructLayout(LayoutKind.Sequential)]
public struct mynums {
    public int num1;
    public int num2;
}

[StructLayout(LayoutKind.Sequential)]
public struct sum1 {
    public mynums nums;
}

public class LibWrap {
    [DllImport("C++.dll", EntryPoint = "initialize")]
    public static extern int Initialize(ref sum1 summing);
}

class Program {
    static void Main(string[] args) {
        sum1 mysum;
        mysum.nums.num1 = 6;
        mysum.nums.num2 = 6;
        int res = LibWrap.Initialize(ref mysum);
        Console.WriteLine(res);
    }
}

話雖這么說,擁有唯一的數據成員是另一個結構的結構是多余的和不必要的。 您應該完全刪除外部結構,例如:

struct nums {
    int num1;
    int num2;
};

extern "C" {

__declspec(dllexport) int initialize(nums *summing) {
    return summing->num1 + summing->num2;
}

}
[StructLayout(LayoutKind.Sequential)]
public struct nums {
    public int num1;
    public int num2;
}

public class LibWrap {
    [DllImport("C++.dll", EntryPoint = "initialize")]
    public static extern int Initialize(ref nums summing);
}

class Program {
    static void Main(string[] args) {
        nums mynums;
        mynums.num1 = 6;
        mynums.num2 = 6;
        int res = LibWrap.Initialize(ref mynums);
        Console.WriteLine(res);
    }
}

暫無
暫無

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

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