1

Hey guys I have a problem. I am currently using a code snippet to detect when the system is going to sleep and saving a timestamp as a setting.

Sometimes when the system resumes, the application crashes with the following message: "Managed Debugging Assistant 'CallbackOnCollectedDelegate' : 'A callback was made on a garbage collected delegate of type 'Tray_App.Classes.SleepDetect+DeviceNotifyCallbackRoutine::Invoke'. This may cause application crashes, corruption and data loss. When passing delegates to unmanaged code, they must be kept alive by the managed application until it is guaranteed that they will never be called.'"

Can some maybe help me to solve this problem? Any help is appreciated. I know that some object is referenced after it was disposed, but I do not know how to prevent the disposal. Never worked with delegate so far.

This is my class:

internal class SleepDetect
{
    public SleepDetect()
    {
        //Register event to handle sleep detection
        IntPtr registrationHandle = new IntPtr();
        DeviceNotifySubscribeParameters recipient = new DeviceNotifySubscribeParameters
        {
            Callback = DeviceNotifyCallback,
            Context = IntPtr.Zero
        };
        IntPtr pRecipient = Marshal.AllocHGlobal(Marshal.SizeOf(recipient));
        Marshal.StructureToPtr(recipient, pRecipient, false);
        var result = PowerRegisterSuspendResumeNotification(DeviceNotifyCallbackVal, ref recipient, ref registrationHandle);
        if (result != 0)
            MessageBox.Show(@"Error registering for power notifications: " + Marshal.GetLastWin32Error(), @"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }

    //Sleep detect implementation
    [DllImport("Powrprof.dll", SetLastError = true)]
    static extern uint PowerRegisterSuspendResumeNotification(uint flags, ref DeviceNotifySubscribeParameters recipient, ref IntPtr registrationHandle);
    private const int PbtApmresumeautomatic = 18; // (0x12) - Operation is resuming automatically from a low-power state.This message is sent every time the system resumes.
    private const int PbtApmresumesuspend = 7; // (0x7) - Operation is resuming from a low-power state.This message is sent after PBT_APMRESUMEAUTOMATIC if the resume is triggered by user input, such as pressing a key.
    private const int PbtApmsuspend = 4; // (0x4) - System is suspending operation.
    private const int DeviceNotifyCallbackVal = 2;

    //OS callback delegate definition
    delegate int DeviceNotifyCallbackRoutine(IntPtr context, int type, IntPtr setting);

    //A callback definition
    [StructLayout(LayoutKind.Sequential)]
    struct DeviceNotifySubscribeParameters
    {
        public DeviceNotifyCallbackRoutine Callback;
        public IntPtr Context;
    }

    //Power change event for sleep detection
    private static int DeviceNotifyCallback(IntPtr context, int type, IntPtr setting)
    {
        switch (type)
        {
            case PbtApmsuspend:
                DateTime cur = DateTime.Now;
                Properties.Settings.Default.ShutdownAtDate = cur;
                Properties.Settings.Default.Save();
                break;
            case PbtApmresumeautomatic:
                break;
            case PbtApmresumesuspend:
                break;
        }
        return 0;
    }
}

Thank you very much :)

Shazy
  • 147
  • 1
  • 10

0 Answers0