2010-10-04 70 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