3

I have searched for days and have tried everything I could find, but still cannot get this to work.

Details: I have a 3rd party stock trading app that is calling into my unmanaged dll. It is supplying data that the dll processes/filters and then saves into a global ring buffer. The ring buffer is an array of structures, 100 long. All of this runs in the stock trading apps process.

I also have a managed C# app calling into the same dll in a different process that needs to get the info in the global ring buffer as quickly and efficiently as possible. Everything works except that I can only get data for the first structure in the array. Also after the call to the dll from C# the C# code no longer knows that arrayMD is an array of structs, it shows up in the debugger as a simple structure. Could it be the memcpy in the dll causing the problem? I’ve tried all kinds of combinations with [In, Out], IntPtr, and Marchal.PtrToStructure combinations. I am greatly fubar. Any help would be greatly appreciated.

Thanks

Here is what I am attempting. On the dll side:

struct stMD
{
  float Price;
  unsigned int  PriceDir;
  unsigned int  PriceDirCnt;
};

// Global memory
#pragma data_seg (".IPC")
    bool NewPoint = false;      // Flag used to signal a new point.
    static stMD aryMD [100] = {{0}};
#pragma data_seg()

void __stdcall RetrieveMD (stMD *LatestMD [])
{
    memcpy(*LatestMD, aryMD, sizeof(aryMD));
}

On the C# side:

[StructLayout(LayoutKind.Sequential)]
public struct stMD
{
    public float Price;
    public uint PriceDir;
    public uint PriceDirCnt;
};

public static stMD[] arrayMD = new stMD[100];

[DllImport(@"Market.dll")]
public static extern void RetrieveMD(ref stMD[] arrayMD);

RetrieveMD(ref arrayMD);
4

3 回答 3

2

问题是您的 DLL 入口点的定义:

void __stdcall RetrieveMD (stMDP *LatestMD []) 

您没有指定数组的大小,那么 C# 应该如何知道复制了多少元素?这在其他语言中也是一个问题。您的实现只是假设提供的内存足够大以包含 aryMD。但如果不是呢?您刚刚创建了缓冲区溢出。

如果您希望调用者分配数组,则调用者还必须传入数组包含的元素数量。

编辑

C++ 声明应如下所示:

// On input, length should be the number of elements in the LatestMD array.
// On output, length should be the number of valid records copied into the array.
void __stdcall RetrieveMD( stMDP * LatestMD, int * length );

C# 声明将如下所示:

[DllImport(@"Market.dll")]
public static extern void RetrieveMD(
    [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] ref stMD[] arrayMD,
    [In, Out] ref int length);
于 2012-10-24T16:37:49.213 回答
0

I got it working. Was I ever tring to make this harder than it is.

I re-read chapter 2 of ".NET 2.0 Interoperability Recipes: A Problem-Solution Approach".

Here's what works.

On C++ side I removed the pointers

struct stMD 
{ 
float Price; 
unsigned int PriceDir; 
unsigned int PriceDirCnt; 
}; 

// Global memory 
#pragma data_seg (".IPC") 
bool NewPoint = false; // Flag used to signal a new point. 
static stMD aryMD [100] = {{0}}; 
#pragma data_seg() 

void __stdcall RetrieveMD (stMD LatestMD [100]) 
{ 
memcpy(LatestMD, aryMD, sizeof(aryMD)); 
}

On the C# side I removed both (ref)s and added [In, Out]

[StructLayout(LayoutKind.Sequential)] 
public struct stMD 
{ 
    public float Price; 
    public uint PriceDir; 
    public uint PriceDirCnt; 
}; 

public static stMD[] arrayMD = new stMD[100]; 

[DllImport(@"Market.dll")] 
public static extern void RetrieveMD([In, Out] stMD[] arrayMD); 

RetrieveMD(arrayMD); 

Thanks to everyone who offered help.

于 2012-10-24T17:20:15.993 回答
0

我认为,您的问题是您试图通过引用将数组从 C# 传递到 C 中,而您几乎不需要这样做。在您的情况下,您想要发生的只是让 C# 为 100 个结构分配内存,然后将该内存传递给 C 以进行填充。在您的情况下,您正在传递一个指向结构数组的指针,即您并不真正需要的额外间接级别。

您很少看到采用固定大小数组的 C 函数。相反,您的函数通常会在 C 中定义以接受指针和长度,例如:

void __stdcall RetrieveMD (stMDP *LatestMD, int size) 
{
   int count = 0;
   if (size < sizeof(aryMD))
     count = size;
   else
     count = sizeof(aryMD);

   memcpy(LatestMD, aryMD, count);      
}

要从 C# 调用此方法,您需要做两件事。首先,您需要分配一个适当大小的数组以传入。其次,您需要告诉封送代码(执行 C# -> C 复制)如何[MarshalAs]通过属性确定要封送多少数据:

[DllImport(@"Market.dll")]
public static extern void RetrieveMD (
  [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] stMDP[] arrayMD,
  int length
);

var x = new stMDP[100];
RetrieveMD(x, 100);
于 2012-10-24T17:09:40.117 回答