C# 如何在Silverlight中调试使用PInvokes导致的内存相关错误
在运行silverlight 5.0应用程序(其中包含几个Pinvoke)5分钟左右后,出现以下错误:C# 如何在Silverlight中调试使用PInvokes导致的内存相关错误,c#,.net,silverlight,winapi,pinvoke,C#,.net,Silverlight,Winapi,Pinvoke,在运行silverlight 5.0应用程序(其中包含几个Pinvoke)5分钟左右后,出现以下错误: Attempted to read or write protected memory 很可能,我的某个地方出现了内存泄漏 问题是如何调试它?我根本没有得到stacktrace,所以我无法准确地指出有问题的代码 通过注释代码并多次重新运行应用程序,我认为我成功地找到了问题所在,但我无法找出问题所在 潜在违规代码: private void InitUSBEvents() { cons
Attempted to read or write protected memory
很可能,我的某个地方出现了内存泄漏
问题是如何调试它?我根本没有得到stacktrace,所以我无法准确地指出有问题的代码
通过注释代码并多次重新运行应用程序,我认为我成功地找到了问题所在,但我无法找出问题所在
潜在违规代码:
private void InitUSBEvents()
{
const string clsName = "SLUsbClass";
const string wndName = "SLUsbWindow";
Win32.WNDCLASSEX wndClassEx = new Win32.WNDCLASSEX();
wndClassEx.cbSize = Marshal.SizeOf(wndClassEx);
wndClassEx.lpszClassName = clsName;
wndClassEx.lpfnWndProc = WndProc;
rClassAtomValue = Win32.RegisterClassEx2(ref wndClassEx);
windowHandle = Win32.CreateWindowEx2(0, rClassAtomValue, wndName, 0, 0, 0, 0, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
Win32Usb.RegisterKeyboardUsbEvents(windowHandle);
}
[AllowReversePInvokeCalls]
private IntPtr WndProc(IntPtr hWnd, WM msg, IntPtr wParam, IntPtr lParam)
{
switch (msg)
{
case WM.INPUT:
//Console.WriteLine("Key Event");
break;
default:
return Win32.DefWindowProc(hWnd, msg, wParam, lParam);
}
return IntPtr.Zero;
}
PInvoke相关声明:
public class Win32
{
[DllImport("user32.dll", SetLastError = true, EntryPoint = "CreateWindowEx")]
public static extern IntPtr CreateWindowEx(
WindowStylesEx dwExStyle,
string lpClassName,
string lpWindowName,
WindowStyles dwStyle,
int x,
int y,
int nWidth,
int nHeight,
IntPtr hWndParent,
IntPtr hMenu,
IntPtr hInstance,
IntPtr lpParam);
// Create a window, but accept a atom value.
[DllImport("user32.dll", SetLastError = true, EntryPoint = "CreateWindowEx")]
public static extern IntPtr CreateWindowEx2(
WindowStylesEx dwExStyle,
UInt16 lpClassName,
string lpWindowName,
WindowStyles dwStyle,
int x,
int y,
int nWidth,
int nHeight,
IntPtr hWndParent,
IntPtr hMenu,
IntPtr hInstance,
IntPtr lpParam);
[DllImport("kernel32.dll", EntryPoint = "LocalAlloc")]
internal static extern IntPtr LocalAlloc_NoSafeHandle(
LocalMemoryFlags uFlags, IntPtr sizetdwBytes);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr LocalFree(IntPtr hMem);
[DllImport("user32.dll", SetLastError = true, EntryPoint = "RegisterClassEx")]
public static extern UInt16 RegisterClassEx2([In] ref WNDCLASSEX lpwcx);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.U2)]
public static extern short RegisterClassEx([In] ref WNDCLASSEX lpwcx);
[DllImport("user32.dll")]
public static extern IntPtr DefWindowProc(IntPtr hWnd, WM uMsg, IntPtr wParam, IntPtr lParam);
}
public class Win32Usb
{
public static bool RegisterKeyboardUsbEvents(IntPtr hWnd)
{
//Create an array of all the raw input devices we want to
//listen to. In this case, only keyboard devices.
//RIDEV_INPUTSINK determines that the window will continue
//to receive messages even when it doesn't have the focus.
RAWINPUTDEVICE[] rid = new RAWINPUTDEVICE[1];
rid[0].usUsagePage = 0x01;
rid[0].usUsage = 0x06;
rid[0].dwFlags = RIDEV_INPUTSINK;
rid[0].hwndTarget = hWnd;
return RegisterRawInputDevices(rid, (uint)rid.Length, (uint)Marshal.SizeOf(rid[0]));
}
[StructLayout(LayoutKind.Explicit)]
internal class RAWINPUT
{
[FieldOffset(0)]
public RAWINPUTHEADER header;
[FieldOffset(16)]
public RAWMOUSE mouse;
[FieldOffset(16)]
public RAWKEYBOARD keyboard;
[FieldOffset(16)]
public RAWHID hid;
}
[StructLayout(LayoutKind.Sequential)]
internal class RAWINPUTDEVICELIST
{
public IntPtr hDevice;
[MarshalAs(UnmanagedType.U4)]
public int dwType;
}
[StructLayout(LayoutKind.Sequential)]
internal struct RAWINPUTDEVICE
{
[MarshalAs(UnmanagedType.U2)]
public ushort usUsagePage;
[MarshalAs(UnmanagedType.U2)]
public ushort usUsage;
[MarshalAs(UnmanagedType.U4)]
public int dwFlags;
public IntPtr hwndTarget;
}
}
我也没有发现PInvoke声明有任何错误。在Silverlight上调试PInvoke相关错误的好策略有哪些?或者有没有办法强制stacktrace输出?(我已尝试在Debug->Exception中打开要抛出的所有异常)正在垃圾收集传递给
wndClassEx
结构的WndProc
委托。将委托传递给非托管代码时,该委托仅在调用非托管函数时保持活动状态。调用结束后,Silverlight应用程序中不再引用它,因此垃圾收集会认为它已死亡并将其收集
在静态方法中缓存WndProc
委托,使其不会被垃圾收集
在p/Invoke上也可以看到这一点(较旧,但仍然有效)。正在垃圾收集在
wndClassEx
结构中传递的WndProc
委托。将委托传递给非托管代码时,该委托仅在调用非托管函数时保持活动状态。调用结束后,Silverlight应用程序中不再引用它,因此垃圾收集会认为它已死亡并将其收集
在静态方法中缓存WndProc
委托,使其不会被垃圾收集
在p/Invoke上也可以看到这一点(较旧,但仍然有效)。正在垃圾收集在
wndClassEx
结构中传递的WndProc
委托。将委托传递给非托管代码时,该委托仅在调用非托管函数时保持活动状态。调用结束后,Silverlight应用程序中不再引用它,因此垃圾收集会认为它已死亡并将其收集
在静态方法中缓存WndProc
委托,使其不会被垃圾收集
在p/Invoke上也可以看到这一点(较旧,但仍然有效)。正在垃圾收集在
wndClassEx
结构中传递的WndProc
委托。将委托传递给非托管代码时,该委托仅在调用非托管函数时保持活动状态。调用结束后,Silverlight应用程序中不再引用它,因此垃圾收集会认为它已死亡并将其收集
在静态方法中缓存WndProc
委托,使其不会被垃圾收集
在p/Invoke上也可以看到这一点(较旧,但仍然有效)。@shf301是正确的,您需要采取措施阻止收集您的代理。我不想在这里重复他的观点 但是,最重要的是,结构的定义不正确。它们将在32位下工作,但不能在64位下工作。
FieldOffset
的经验法则是,您只能在偏移量为0
的情况下使用它。这条规则允许您编写同时适用于32位和64位的代码。在代码中,您使用了偏移量16
,这对于32位是合适的,但对于64位则不合适。按照此模式定义您的结构:
[StructLayout(LayoutKind.Explicit)]
struct RAWINPUTUNION
{
[FieldOffset(0)]
public RAWMOUSE mouse;
[FieldOffset(0)]
public RAWKEYBOARD keyboard;
[FieldOffset(0)]
public RAWHID hid;
}
[StructLayout(LayoutKind.Sequential)]
struct RAWINPUT
{
public RAWINPUTHEADER header;
public RAWINPUTUNION data;
}
@shf301是正确的,您需要采取措施阻止收集您的代理。我不想在这里重复他的观点 但是,最重要的是,结构的定义不正确。它们将在32位下工作,但不能在64位下工作。
FieldOffset
的经验法则是,您只能在偏移量为0
的情况下使用它。这条规则允许您编写同时适用于32位和64位的代码。在代码中,您使用了偏移量16
,这对于32位是合适的,但对于64位则不合适。按照此模式定义您的结构:
[StructLayout(LayoutKind.Explicit)]
struct RAWINPUTUNION
{
[FieldOffset(0)]
public RAWMOUSE mouse;
[FieldOffset(0)]
public RAWKEYBOARD keyboard;
[FieldOffset(0)]
public RAWHID hid;
}
[StructLayout(LayoutKind.Sequential)]
struct RAWINPUT
{
public RAWINPUTHEADER header;
public RAWINPUTUNION data;
}
@shf301是正确的,您需要采取措施阻止收集您的代理。我不想在这里重复他的观点 但是,最重要的是,结构的定义不正确。它们将在32位下工作,但不能在64位下工作。
FieldOffset
的经验法则是,您只能在偏移量为0
的情况下使用它。这条规则允许您编写同时适用于32位和64位的代码。在代码中,您使用了偏移量16
,这对于32位是合适的,但对于64位则不合适。按照此模式定义您的结构:
[StructLayout(LayoutKind.Explicit)]
struct RAWINPUTUNION
{
[FieldOffset(0)]
public RAWMOUSE mouse;
[FieldOffset(0)]
public RAWKEYBOARD keyboard;
[FieldOffset(0)]
public RAWHID hid;
}
[StructLayout(LayoutKind.Sequential)]
struct RAWINPUT
{
public RAWINPUTHEADER header;
public RAWINPUTUNION data;
}
@shf301是正确的,您需要采取措施阻止收集您的代理。我不想在这里重复他的观点 但是,最重要的是,结构的定义不正确。它们将在32位下工作,但不能在64位下工作。
FieldOffset
的经验法则是,您只能在偏移量为0
的情况下使用它。这条规则允许您编写同时适用于32位和64位的代码。在代码中,您使用了偏移量16
,这对于32位是合适的,但对于64位则不合适。按照此模式定义您的结构:
[StructLayout(LayoutKind.Explicit)]
struct RAWINPUTUNION
{
[FieldOffset(0)]
public RAWMOUSE mouse;
[FieldOffset(0)]
public RAWKEYBOARD keyboard;
[FieldOffset(0)]
public RAWHID hid;
}
[StructLayout(LayoutKind.Sequential)]
struct RAWINPUT
{
public RAWINPUTHEADER header;
public RAWINPUTUNION data;
}
您的大部分
封送处理属性都可以删除。在我看来,它们只是增加了噪音。您的大部分marshallas
属性都可以删除。在我看来,它们只是增加了噪音。您的大部分marshallas
属性都可以删除。在我看来,它们只是增加了噪音。您的大部分marshallas
属性都可以删除。在我看来,它们只是增加了噪音。我能辨别出来