我已经搜索了几天,并尝试了我能找到的所有内容,但仍无法使其发挥作用。
详细说明: 我有一个第三方股票交易应用程序调用我的非托管DLL。它提供dll处理/过滤的数据,然后保存到全局环形缓冲区中。环形缓冲区是一个结构数组,长100。所有这些都在股票交易应用程序流程中运行。
我还有一个托管的C#app在不同的进程中调用同一个dll,需要尽可能快速有效地获取全局环缓冲区中的信息。一切正常,除了我只能获取数组中第一个结构的数据。在从C#调用dll后,C#代码不再知道arrayMD是一个结构数组,它在调试器中显示为一个简单的结构。这可能是导致问题的DLL中的memcpy吗?我已经尝试了[In,Out],IntPtr和Marchal.PtrToStructure组合的各种组合。我非常喜欢。任何帮助将不胜感激。
由于
这是我正在尝试的。 在dll方面:
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));
}
在C#方面:
[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);
答案 0 :(得分: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);
答案 1 :(得分: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# - &gt; 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);
答案 2 :(得分:0)
我得到了它的工作。我是不是想要让它变得更难。
我重读了“.NET 2.0互操作性配方:问题解决方案”的第2章。
这是有效的。
在C ++方面,我删除了指针
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));
}
在C#端,我删除了两个(ref)s并添加了[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);
感谢所有提供帮助的人。