2009-11-19 57 views
1

我有一个正常的dll,导出了以下函数。将结构数组从c#传递给常规dll

extern "C" __declspec(dllexport) int FindNearestStuff(double _latitude, double _longitude , LocationStruct * locations[]) 

LocationStruct很简单

struct LocationStruct 
    { 
    long positionIndex; 
    long item; 
    }; 

我tryign使用从C#调用它

[DllImport("myclever.dll", CharSet = CharSet.None)] 
     private static extern int FindNearestStuff(double _latitude, double _longitude, 
                ref LocationStruct [] locations); 

这一切都冷静和时髦的,我可以进入从DLL函数调试器。 在dll里LocationStruct数组填充正确,并且都非常好。

我的问题是,当它从DLL返回时,LocationStruct阵列是不回来的数据 - 只是空值...

我缺少什么?

+0

结构LocationStruct \t \t { \t \t \t长roadIndex; \t \t \t long tdist; \t \t}; 和在c# 内部结构LocationStruct \t \t { \t \t \t公众诠释roadIndex; //它在C代码中的一长 \t \t \t public int tdist; //它的一个长C代码 \t \t}; – buzz 2009-11-19 03:00:50

+0

我不认为P/Invoke可以在这里处理双重间接(通过C#端的'ref'传递数组,C++端指向指针)。你真的需要它吗? C++中不会有指向结构数组中第一个元素的指针吗? – 2009-11-19 03:16:48

+0

我能想到的最简单的方法是使用不安全的C#。还要记住使用StructLayout.Sequential – 2009-11-19 03:34:57

回答

0

我不确定你能否自动做到这一点,因为C#没有办法知道位置变量中返回了多少项目(我假设FindNearestStuff的返回值是条目数在位置)

你将不得不使用Marshall类和处理这样的手动元帅数据:

[DllImport("myclever.dll", CharSet = CharSet.None)] 
private static extern int FindNearestStuff(double _latitude, double _longitude, 
              out IntPtr locations); 

public static LocationStruct[] FindNearestStuff(double latitude, double longitude) { 
    IntPtr locationsPtr = IntPtr.Zero; 
    int numLocations = FindNearestStuff(latitude, longitude, out locationsPtr); 

    LocationsStruct[] locations = new LocationsStruct[numLocations]; 

    for (int i = 0; i < numLocations; i++) { 

      // locationsPtr is a pointer to the struct, so read the value 
      // at locationPtr which will be the address of the struct and 
      // then manually marshal the struct from that address 
      locaitonsStruct[i] = (LocationStruct)Marshal.PtrToStructure(
       Marshal.ReadIntPtr(locationsPtr), typeof(LocationsStruct)); 

      // Move to the location pointer to the next address of a 
      // pointer to a struct 
      locationsPtr += IntPtr.Size; 
    } 

    return locations; 
} 

我还没有真正尝试过这种所以买者自负。

1

非常感谢您的帮助 - 您肯定会把我放在正确的方向,我真的很感谢您的帮助!

这是似乎为我工作的解决方案;

[DllImport("myclever.dll", CharSet = CharSet.None)] 
     private static extern int FindNearestStuff(double _latitude, double _longitude, IntPtr locations); 


public static int FindNearestStuff(double _latitude, double _longitude, LocationStruct[] locations) 
     { 
      int returnValue = -1; 
      LocationStruct temp; 
      temp.roadIndex = 1; 
      temp.tdist = 1; 
      int iStructSize = Marshal.SizeOf(temp); 
      try 
      { 
       IntPtr locationsPtr = IntPtr.Zero; 

       IntPtr buffer = Marshal.AllocHGlobal(iStructSize * 10); 
       FindNearestRoads(_latitude, _longitude, buffer); 
       for (int i = 0; i < 10; i++) 
       { 
        IntPtr ptr = new IntPtr(buffer.ToInt32() + iStructSize * i); 
        locations[i] = (LocationStruct)Marshal.PtrToStructure(ptr, typeof(LocationStruct)); 

       } 

       returnValue = 0; 
      } 
      catch 
      { 
      } 
      return returnValue; 
     } 
+0

,当然不会忘记到 Marshal.FreeHGlobal(buffer); ! – buzz 2009-11-19 06:04:01

+1

如果这对你有效,你确实在你的原始代码中有过多的间接性,就像Pavel暗示的那样,你不需要做所有这些分配并复制自己,你应该能够把你的原始函数声明,并删除参数修饰符。 – 2009-11-19 13:02:07