2010-10-04 71 views
0

我們在c#和c dll之間編有以下代碼編組。但是,在C dll函數內打印值時,與雙數組屬性相關的值全部爲0.0000000。對於有問題的代碼,我已經提出了一些評論。通過引用將具有雙重成員數組的C#數組結構傳遞給C DLL

我們錯過任何配置編組行爲的事情嗎?

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Runtime.InteropServices; 
namespace ConsoleApplication 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      MonteCarlo montecarlo = new MonteCarlo(); 
      montecarlo.RunMonteCarlo(); 
     } 
    } 
    class MonteCarlo 
    { 

     [DllImport("MonteCarloCUDA.dll")] 
     public static extern int MonteCarloPrint([In, Out]PurchaseOrder[] purchaseorders, int length); 

     public void RunMonteCarlo() 
     { 

      PurchaseOrder[] purchaseorders = new PurchaseOrder[3]; 

      purchaseorders[0] = new PurchaseOrder(); 
      purchaseorders[0].Value1 = "AAAAA"; 
      purchaseorders[0].Value2 = 0.111; 
      purchaseorders[0].Value3 = new double[2]; // Assign the values to array of double 
      purchaseorders[0].Value3[0] = 0.11111; 
      purchaseorders[0].Value3[1] = 0.22222; 

      purchaseorders[1] = new PurchaseOrder(); 
      purchaseorders[1].Value1 = "BBB"; 
      purchaseorders[1].Value2 = 0.222; 
      purchaseorders[1].Value3 = new double[2]; 
      purchaseorders[1].Value3[0] = 0.33333; 
      purchaseorders[1].Value3[1] = 0.44444; 

      purchaseorders[2] = new PurchaseOrder(); 
      purchaseorders[2].Value1 = "CCC"; 
      purchaseorders[2].Value2 = 0.333; 
      purchaseorders[2].Value3 = new double[2]; 
      purchaseorders[2].Value3[0] = 0.55555; 
      purchaseorders[2].Value3[1] = 0.66666; 

      int result = MonteCarloPrint(purchaseorders, purchaseorders.Length); 

      Console.ReadKey(); 
     } 

     [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] 
     public unsafe struct PurchaseOrder 
     { 
      public string Value1; 

      public double Value2; 

      public double[] Value3; // Array of double member 
     } 
    } 
} 

// C代碼

#include <stdio.h> 

typedef struct PurchaseOrder 
{ 
    char* Value1; 
    double Value2; 
    double* Value3; 
}; 



__declspec(dllexport) int __stdcall MonteCarloPrint(PurchaseOrder *hostPurchaseOrders, int length) 
{  
    printf("\nSize of PurchaseOrder: %d",sizeof(PurchaseOrder)); 

    for (int i = 0; i < length; i++) 
    {   
     printf("\n\nAddress: %u",hostPurchaseOrders+i);   
     printf("\nValue1: %s",(hostPurchaseOrders+i)->Value1); 
     printf("\nValue2: %f",(hostPurchaseOrders+i)->Value2); 
     printf("\nValue3[0]: %f",(hostPurchaseOrders+i)->Value3[0]); 
     printf("\nValue3[1]: %f",(hostPurchaseOrders+i)->Value3[1]); 

    } 
}} 

從C DLL函數

 
Size of PurchaseOrder: 24 

Address: 13180880 
Value1: AAAAA 
Value2: 0.111000 
Value3[0]: 0.000000 // No value are marshalled 
Value3[1]: 0.000000 

Address: 13180904 
Value1: BBB 
Value2: 0.222000 
Value3[0]: 0.000000 
Value3[1]: 0.000000 

Address: 13180928 
Value1: CCC 
Value2: 0.333000 
Value3[0]: 0.000000 
Value3[1]: 0.000000 
+0

斯特拉特福德,已經多次嘗試改進源代碼的格式。不要撤消它。混淆你的代碼並不會讓你得到更好的答案。 – dtb 2010-10-05 00:00:38

回答

1

取下函數[DllImport]申報財產包的打印結果,這是錯誤的。您在C代碼中未使用#pragma pack指令,Pack的默認值是適當的。如果它已經生效,那麼你的C代碼將報告16個。

你正在看到24,因爲有4個字節的填充,用於在結構的末端對齊填充的雙字節和4個字節,以使雙對齊當這個結構被用在一個數組中時。 4 + 4 + 8 + 4 + 4 = 24。實際包裝爲8,默認值。

您可以通過交換Value2和Value3來獲得更高的效率,以獲得16字節的結構,不需要填充。如果它很重要。這就是JIT編譯器的功能。


下一個問題更加棘手,P/Invoke編組將把嵌入數組編組爲SAFEARRAY。您可以使用此代碼解決非管理端的問題:

#include "stdafx.h" 
#include <stdio.h> 
#include <objidl.h> 

struct PurchaseOrder 
{ 
    char* Value1; 
    double Value2; 
    LPSAFEARRAY Value3; 
    int fence; 
}; 


extern "C" 
__declspec(dllexport) int __stdcall MonteCarloPrint(PurchaseOrder *hostPurchaseOrders, int length) 
{  
    printf("\nSize of PurchaseOrder: %d",sizeof(PurchaseOrder)); 

    for (int i = 0; i < length; i++) 
    {   
     printf("\n\nAddress: %u",hostPurchaseOrders+i);   
     printf("\nValue1: %s",(hostPurchaseOrders+i)->Value1); 
     printf("\nValue2: %f",(hostPurchaseOrders+i)->Value2); 
     double* arrayPtr; 
     if (S_OK == SafeArrayAccessData((hostPurchaseOrders+i)->Value3, (void**)&arrayPtr)) { 
      printf("\nValue3[0]: %f", arrayPtr[0]); 
      printf("\nValue3[1]: %f", arrayPtr[1]); 
     } 
    } 
    return 0; 
} 

我使用C++編譯器編寫代碼,您可能需要調整。

+0

嗨漢斯,我從[StructLayout(LayoutKind.Sequential,Pack = 1,CharSet = CharSet.Ansi)]中刪除了pack = 1,但問題仍然存在。 vlaue3由0.00000填充,購買訂單的尺寸爲24. – Stratford 2010-10-05 00:07:58

+0

@Stratford - 發佈更新。 – 2010-10-05 00:39:35