PInvoke管理堆损坏

时间:2013-08-05 20:55:26

标签: .net winapi pinvoke

我正在使用此功能从低级键盘钩子中查找击键...

Const UnicodeBufferExSize As Integer = 64
Public Declare Function ToUnicodeEx Lib "user32" (wVirtKey As UInteger,
    wScanCode As UInteger,
    lpKeyState As Byte(),
    <Out()>
    <MarshalAs(UnmanagedType.LPWStr, SizeConst:=UnicodeBufferExSize)> '<-- Note this line (#A)
    ByVal lpChar As System.Text.StringBuilder,
    cchBuff As Integer,
    wFlags As UInteger,
    dwhkl As IntPtr) As Integer

...

Dim SB As New System.Text.StringBuilder(UnicodeBufferExSize) '<-- And this one (#B)

ToUnicodeEx(CUInt(lParam.vkCode),
            CUInt(lParam.scanCode),
            KeyState,
            SB,
            SB.Capacity, '<-- And this (#C)
            0,
            InputLanguage.CurrentInputLanguage.Handle)

GC.Collect()
Return SB.ToString()

ToUnicodeEx的调用采用一个参数,该参数指示要填充的StringBuilder缓冲区的大小(行#C)。

如果我创建一个没有容量参数的StringBuilder(行#B,当前实现似乎默认为反射的容量为16)并省略SizeConst(行#A),那么通常调用成功但有时会导致托管堆损坏例外。

现在,我已经添加了UnicodeBufferExSize常量,希望解决问题并且似乎已经这样做了 - 但我不知道它是否真正修复了它或者只是让它更罕见。

有人可以解释为什么简单地传递缓冲区大小是不够的?并确认我的解决方案是否正确或是否有任何微妙的错误?

(请注意,对GC.Collect()的调用会更快地触发问题,并且仅用于辅助调试。)

继汉斯的第一次评论之后......

enter image description here

Problem signature:
  Problem Event Name:   APPCRASH
  Application Name: Glue.exe
  Application Version:  3.1.3.0
  Application Timestamp:    52001dc3
  Fault Module Name:    ntdll.dll
  Fault Module Version: 6.1.7601.17725
  Fault Module Timestamp:   4ec4aa8e
  Exception Code:   c0000005
  Exception Offset: 00000000000532d0
  OS Version:   6.1.7601.2.1.0.256.1
  Locale ID:    2057
  Additional Information 1: 355b
  Additional Information 2: 355bc389704a5d6b4e279d0f0bd3355a
  Additional Information 3: 02ad
  Additional Information 4: 02ad05628a0a65c888b4805dfd9c6b58

0 个答案:

没有答案