VB6 / VC6项目转换为VB.NET / C - >共享内存

时间:2014-07-30 14:07:52

标签: c vb.net ipc

目前我正在开发一个小项目,将软件包从VB6更新为VB.NET和一个小DLL,在VC6中写入更新到最新的Visual Studio版本。

现在我遇到一个小问题: 在VB6中是一个Form应用程序,一个模具VC-Code定义了两个DLL文件。 对于这些应用程序之间的通信,有一个共享内存和许多其他功能进行通信。

这是C:中的共享内存结构

typedef struct MEMORY
{
    double Mem0;        
    int Mem1;       
    short Mem2;
}MEMORY;

MEMORY  *sharedStructMEMORY; // Creating a pointer.


 //This is a function, I call out of VB:
void DLL_API __stdcall Fkt_get_memAddr (MEMORY *pnt_sharedmem)
{
     sharedStructMEMORY = pnt_sharedmem;
};

现在让我们来看看VB.NET代码: 结构:

Public Structure MEMORY
    dim mem1 as double
    dim mem2 as int32
    dim mem3 as short
end structure

功能:

Public Class Dll1
    <DllImport(Dll_Datei_1)> _
    Public Shared Sub Fkt_set_memAddr(<MarshalAs(UnmanagedType.Struct)> ByRef sharedmem As MEMORY)
    End Sub
End Class

现在,如果我像这样调用函数:

public sharedMEM as MEMORY

Fkt_set_memAddr(sharedMEM)

DLL应该从VB.NET结构中获取地址, 所以到现在为止,我能够从同一个内存中写入和读取。

但它不起作用。 总是当我从DLL中的内存设置第一个值时,在调试DLL时,它表示值正确写入。如果我在VB.NET中检查它,值就像

2.5481197073372403e-307

出了什么问题?

感谢您的帮助! 岸堤

1 个答案:

答案 0 :(得分:0)

由于托管对象是可移动的,因此您无法将托管对象的持久地址传递给非托管DLL。
What are pinned objects?。 (fixed在那篇文章中是针对C#的,VB.NET不支持。)

你需要:

  • Marshal.AllocHGlobal分配内存块,将指针传递给DLL,然后按住它。
  • 通过Marshal.PtrToStructure从内存块中读取一个MEMORY。
  • 通过Marshal.StructureToPtr将内存块写入内存块。

我建议您创建一个包装类来执行这些操作,例如:

Imports System.Runtime.InteropServices

' Note: No need to be Structure.
<StructLayout(LayoutKind.Sequential, Pack:=4)>
Public Class MEMORY
    Public mem1 As Double
    Public mem2 As Int32
    Public mem3 As Short
End Class


' Wrapper class to access the memory block.
' Note: This is not thread-safe.
Public Class MEMORYWrapper
    Implements IDisposable

    <DllImport(Dll_Datei_1)> _
    Private Shared Sub Fkt_set_memAddr(ptr As IntPtr)
    End Sub

    ' Holds the pinned address.
    Private _ptrToMemory As IntPtr

    ' Constructor allocates the memory block, and notify its address to DLL.
    ' Note: Creating instances twice could lead you to hell ;-)
    '       Better to be singletonized.
    Public Sub New()
        Me._ptrToMemory = Marshal.AllocHGlobal(Marshal.SizeOf(GetType(MEMORY)))
        Fkt_set_memAddr(Me._ptrToMemory)
    End Sub

    ' Reads a MEMORY from the memory block.
    Public Function ReadMemory() As MEMORY
        Dim mem As MEMORY
        mem = DirectCast(
            Marshal.PtrToStructure(Me._ptrToMemory, GetType(MEMORY)), MEMORY)
        Return mem
    End Function

    ' Writes a MEMORY to the memory block.
    Public Sub WriteMemory(mem As MEMORY)
        Marshal.StructureToPtr(mem, Me._ptrToMemory, False)
    End Sub

    ' Implements IDisposable to free the memory block.

    Private disposedValue As Boolean = False        ' To detect redundant calls

    ' IDisposable
    Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        If Not Me.disposedValue Then
            If disposing Then
                ' TODO: free other state (managed objects).
            End If

            ' TODO: free your own state (unmanaged objects).
            ' Free the memory block.
            Marshal.FreeHGlobal(Me._ptrToMemory)
            Me._ptrToMemory = IntPtr.Zero

            ' TODO: set large fields to null.
        End If
        Me.disposedValue = True
    End Sub


#Region " IDisposable Support "
    ' This code added by Visual Basic to correctly implement the disposable pattern.
    Public Sub Dispose() Implements IDisposable.Dispose
        ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub
#End Region

End Class

' A sample of the usage.
Module Module1

    Private memWrapper As New MEMORYWrapper

    Sub Main()
        Dim m As New MEMORY
        m.mem1 = 0.123
        m.mem2 = 555
        m.mem3 = 432

        memWrapper.WriteMemory(m)

        Dim m2 As MEMORY = memWrapper.ReadMemory()

        Console.WriteLine("{0},{1},{2}", m2.mem1, m2.mem2, m2.mem3)

        memWrapper.Dispose()
    End Sub
End Module