我正在尝试将现有的VB6应用程序转换为C#。应用程序必须使用也是用VB6编写的API,它是一个ActiveX DLL。我正在使用.NET Interop功能来包装此API,以便我可以在C#中使用它。
问题是获取字节数组的一些代码,然后使用RtlMoveMemory()将其移动到Struct中。使用下面给出的C#代码,我得到一个System.ArgumentException" Value不在预期范围内"例外。我已经尝试了这种实现的各种排列,以及一些编组,但我在这方面有点超出我的深度。我尝试过的所有内容都会导致某种形式的未处理异常。
使用RtlMoveMemory()的解决方案没问题,但使用编组的解决方案会更好。希望它只是连接点的问题。
VB6代码:
Public Declare Sub MoveIt Lib "kernel32.dll" Alias "RtlMoveMemory" (dest As Any, src As Any, ByVal bytes As Long)
Type IntEventStruct
TTag As Double
quality As Long
Value As Single
End Type
Dim byteBuff(PACKETSIZE - 1) As Byte
Dim dEvent As IntEventStruct
Call DWApi.ReadEvent(code, DBIndex, TTStr, interval, byteBuff, errMsg)
Call MoveIt(dEvent, byteBuff(0), Len(dEvent))
C#代码:
[DllImport("kernel32.dll", EntryPoint="RtlMoveMemory")]
static extern void MoveIt(Object Destination, Object Source, long Length);
public struct ReadEventStruct
{
public double TimeTag;
public int Quality;
public float Value;
}
byte[] byteBuff = new byte[BUFFER_SIZE];
ReadEventStruct dwRead = new ReadEventStruct();
this.dw.ReadEvent(pt.Plant, pt.Index, pt.Time, pt.Interval, ref byteBuff, ref errMsg);
MoveIt(dwRead, byteBuff, Marshal.SizeOf(dwRead));
ReadEvent()的相关API文档(我无法访问源代码):
This routine retrieves process data for a specified point at a single time.
Calling convention:
Call DWPCAPI.ReadEvent(Plant As String, _
iChannel As Long, _
StartT As String, _
Interval as Single, _
Buffer() As Byte, _
ErrMsg As String)
Buffer( ): Byte buffer containing returned data.
答案 0 :(得分:0)
您可以使用固定内存和固定指针(请记住C#使用托管内存,因此系统可以自由地在内存中移动对象)。
使用:
[DllImport("Kernel32.dll", EntryPoint = "RtlMoveMemory")]
private static unsafe extern void MoveMemory(void* dest, void* src, int size);
并在您的方法中,例如:
fixed (byte* p = pointer )
{
// RtlMoveMemory call
}
其他方式是使用Marshal.PtrToStructure()
。
答案 1 :(得分:0)
我对原始问题的评论中提供了最佳答案。它建议使用BitConverter
类而不是编组,但由于评论者没有提供它作为答案,这里是:
ReadEventStruct dwRead = new ReadEventStruct();
Array buffer = new byte[BUFFER_SIZE];
this.dw.ReadEvent(pt.Plant, pt.Index, pt.Time, pt.Interval, ref buffer, ref errMsg);
byte[] byteBuffer = (byte[])buffer; // Convert to byte[] so BitConverter class can be used
dwRead.TimeTag = BitConverter.ToDouble(byteBuffer, 0); // First 8 bytes are TimeTag (double)
dwRead.Quality = BitConverter.ToInt32(byteBuffer, 8); // Next 4 bytes are Quality (integer)
dwRead.Value = BitConverter.ToSingle(byteBuffer, 12); // Last 4 bytes are Value (float)