简体   繁体   English

使用RtlMoveMemory将VB6转换为C#

[英]Converting VB6 using RtlMoveMemory to C#

I am attempting to convert an existing VB6 application to C#. 我正在尝试将现有的VB6应用程序转换为C#。 The application must use an API that was also written in VB6 and is an ActiveX DLL. 该应用程序必须使用也是用VB6编写的并且是ActiveX DLL的API。 I am using the .NET Interop functionality to wrap this API so that I can use it in C#. 我正在使用.NET Interop功能包装此API,以便可以在C#中使用它。

The problem is a bit of code that gets a byte array, and then uses RtlMoveMemory() to move it into a Struct. 问题是一些代码获取了字节数组,然后使用RtlMoveMemory()将其移至Struct中。 With the C# code given below, I get a System.ArgumentException "Value does not fall within the expected range" exception. 使用下面给出的C#代码,我得到一个System.ArgumentException“值不在期望范围内”异常。 I have tried various permutations of this implementation, as well as some Marshalling, but I am a bit out of my depth in this area. 我已经尝试了此实现的各种排列以及编组,但是我对这方面的知识有些不了解。 Everything I tried resulted in some form of unhandled exception. 我尝试的所有操作均导致某种形式的未处理异常。

A solution using RtlMoveMemory() would be fine, but a solution using Marshalling would be even better. 使用RtlMoveMemory()的解决方案会很好,但是使用编组的解决方案会更好。 Hopefully it's just a matter of connecting the dots. 希望这只是连接点的问题。

VB6 Code: 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# Code: 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));

The relevant API documentation for ReadEvent() (I don't have access to the source code): 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.

You can use fixed memory with a pinned pointer (remember that C# uses managed memory, so the system is free to move your objects around in memory). 您可以使用带有固定指针的固定内存(请记住,C#使用托管内存,因此系统可以自由地在内存中移动对象)。

Use: 采用:

[DllImport("Kernel32.dll", EntryPoint = "RtlMoveMemory")]
private static unsafe extern void MoveMemory(void* dest, void* src, int size);

and in your method, something like: 在您的方法中,类似:

fixed (byte* p = pointer )
{
    // RtlMoveMemory call
}

The Other way is to use Marshal.PtrToStructure() . 另一种方法是使用Marshal.PtrToStructure()

The best answer was provided in a comment on my original question. 在对我的原始问题的评论中提供了最佳答案。 It suggests using the BitConverter class instead of marshalling, but since the commenter didn't provide it as an answer, here it is: 它建议使用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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM