使用Marshal.Copy进行C#AcessExceptionViolation

时间:2015-07-08 17:14:27

标签: c# c++ struct vb6

我正在将程序从VB转换为C#,它与外部程序MMTTY.EXE进行通信。这个程序有VB6.0的ActiveX控件,我在Visual Studio 2013中加入了我的C#项目。

VB中的代码是:

Dim m_nmmr(63) As Long
Private Sub XMMR_OnNotifyNMMR(pNMMR As Long)
Call CopyMemory(m_nmmr(0), pNMMR, 64 * 4)   'Windows API CopyMemory()*

当MMTTY.EXE有数据并且pNMMR指向的数据被复制到m_nmmr(63)缓冲区时,会产生此事件。

我做的C#程序是:

[DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
    static extern void CopyMemory(Int32[] Destination, IntPtr Source, uint Length);
private void XMMR_OnNotifyNMMR(object sender,      AxXMMTLib._DXMMREvents_OnNotifyNMMREvent e)
    {            
        IntPtr ptr = (IntPtr)e.pNMMR;
        Int32[] m_nmmr = new Int32[63];
        Marshal.Copy(ptr, m_nmmr, 0, 63);
    }*

但是当我执行它时,我得到一个AccessViolationException。它告诉我在受保护的内存中尝试写入或读取。

我该如何解决这个问题?任何想法?

这是VB6.0原始方法的帮助:

void OnNotifyNMMR(long * pNMMR) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~   该事件在TXM_LEVLEL消息到达的时刻生成。 pNMMR指向的NMMR结构由

定义
#pragma pack(push, 1)
typedef struct {
    DWORD   m_markfreq;
    DWORD   m_spacefreq;
    DWORD   m_siglevel;
    DWORD   m_sqlevel;
    DWORD   m_codeswitch;
    DWORD   m_codeview;
    DWORD   m_notch1;
    DWORD   m_notch2;
    DWORD   m_baud;
    DWORD   m_fig;
    DWORD   m_radiofreq;
    DWORD   m_Reserved[53];
}NMMR;
#pragma pack(pop)

如果应用程序使用此结构,则不必响应所有XMMR事件。由于NMMR结构只包含LONG变量,因此可以将其复制到VB Long数组中。数组的索引在XMMT.ocx中有几个名称,例如xr_markfreq。有关详细信息,请参阅XMMR的预定义常量。

[Example]
    Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)

Dim m_nmmr(63) As Long

Private Sub XMMR_OnNotifyNMMR(pNMMR As Long)
    Call CopyMemory(m_nmmr(0), pNMMR, 64 * 4)   'Windows API CopyMemory()
    |
    MarkFreq = m_nmmr(xr_markfreq)
    SpaceFreq = m_nmmr(xr_spacefreq)
       |
    'Pass pNMMR to the control for the supplemental control
    Call XMMSpec.UpdateByNMMR(pNMMR)    'Update the frequency property of XMMSpec control
    Call XMMLvl.DrawByNMMR(pNMMR)   'Draw the level indicator
End Sub

1 个答案:

答案 0 :(得分:0)

63是问题:

在VB6中,63是顶部索引(0..63)。

在C#中,63是元素的COUNT(0..62)。

所以你错过了4个字节。你可以通过一个小的控制台程序,第一次分配的断点来简单地检查这个:

    static void Main(string[] args)
    {
        int[] test = new int[1];
        test[0] = 1;
        test[1] = 2; // <- this will crash
    }