0

I've written some WMI code that works really well on most machines. However on some machines (nearly all SSD based macs) this code causes a HUGE performance problem. It causes the WMIPrvSe process to keep hitting I/O Other. If you run another app doing the same watching then it slows to a crawl to the point where the software becomes unusable.

            System.Management.WqlEventQuery     queryIn;
            System.Management.WqlEventQuery     queryOut;
            System.Management.ManagementScope   scope   = new System.Management.ManagementScope( "root\\CIMV2" );
            scope.Options.EnablePrivileges      = true;

            try
            {
                queryIn = new System.Management.WqlEventQuery();
                queryIn.EventClassName          = "__InstanceCreationEvent";
                queryIn.WithinInterval          = new TimeSpan( 0, 0, 1 );
                //queryIn.GroupWithinInterval       = new TimeSpan( 0, 0, 0 );
                queryIn.Condition               = @"TargetInstance ISA 'Win32_DiskDrive' AND TargetInstance.InterfaceType = 'USB'";
                mUSBWatcherIn = new System.Management.ManagementEventWatcher( scope, queryIn );

                //adds event handler that’s is fired when the insertion event occurs
                mUSBWatcherIn.EventArrived += new System.Management.EventArrivedEventHandler( USBInserted );

                queryOut = new System.Management.WqlEventQuery();
                queryOut.EventClassName         = "__InstanceDeletionEvent";
                queryOut.WithinInterval         = new TimeSpan( 0, 0, 1 );
                //queryOut.GroupWithinInterval  = new TimeSpan( 0, 0, 0 );
                queryOut.Condition              = @"TargetInstance ISA 'Win32_DiskDrive' AND TargetInstance.InterfaceType = 'USB'";
                mUSBWatcherOut = new System.Management.ManagementEventWatcher( scope, queryOut );

                //adds event handler that’s is fired when the insertion event occurs
                mUSBWatcherOut.EventArrived += new System.Management.EventArrivedEventHandler( USBRemoved );

                mUSBWatcherIn.Start();//run the watcher
                mUSBWatcherOut.Start();
            }
            catch (Exception e)
            {
                System.Windows.Forms.MessageBox.Show( e.Message );
                StopUSBWatcher();
            }

Does anyone have any idea what could be going on here? If I remove this code then it works perfectly. On other machines, it works perfectly. Its very strange. Any ideas hugely appreciated!

Goz
  • 61,365
  • 24
  • 124
  • 204

1 Answers1

0

so I've not worked out what was causing the problem but I have now implemented identical functionality using WM_DEVICECHANGE.

Here is my interop setup:

    [System.Runtime.InteropServices.DllImport( "user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto, CallingConvention = System.Runtime.InteropServices.CallingConvention.StdCall )]
    private static extern IntPtr RegisterDeviceNotification(IntPtr recipient, IntPtr notificationFilter, int flags);

    [System.Runtime.InteropServices.DllImport( "user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto, CallingConvention = System.Runtime.InteropServices.CallingConvention.StdCall )] 
    private static extern bool UnregisterDeviceNotification(IntPtr handle);

    [System.Runtime.InteropServices.DllImport( "user32.dll", SetLastError = true )]
    static extern IntPtr GetWindowLongPtr( IntPtr hWnd, int nIndex );

    [System.Runtime.InteropServices.DllImport( "user32.dll", SetLastError = true )]
    static extern int GetWindowLong( IntPtr hWnd, int nIndex );

    [System.Runtime.InteropServices.DllImport( "user32.dll", SetLastError = true )]
    static extern IntPtr SetWindowLongPtr( IntPtr hWnd, int nIndex, IntPtr newLong );

    [System.Runtime.InteropServices.DllImport( "user32.dll", SetLastError = true )]
    static extern int SetWindowLong( IntPtr hWnd, int nIndex, int newLong );


    delegate IntPtr WndProcDelegate( IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam );

    [System.Runtime.InteropServices.DllImport("user32.dll")]
    static extern IntPtr CallWindowProc( IntPtr lpPrevWndFunc, IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam );

    public const    int             GWLP_WNDPROC    = -4;

    [System.Runtime.InteropServices.StructLayout( System.Runtime.InteropServices.LayoutKind.Sequential )]
    private struct DevBroadcastDeviceinterface
    {
        internal int Size;
        internal int DeviceType;
        internal int Reserved;
        internal Guid ClassGuid;
        internal short Name;
    }

    const int DBT_DEVTYPVOLUME = 0x00000002;  
    const int DBT_DEVTYPDEVICEINTERFACE = 5;

    static readonly Guid GuidDevinterfaceUSBDevice = new Guid( "A5DCBF10-6530-11D2-901F-00C04FB951ED" );

And the actual setup code is as follows:

        DevBroadcastDeviceinterface dbi = new DevBroadcastDeviceinterface
           {
               DeviceType = DBT_DEVTYPDEVICEINTERFACE,//DBT_DEVTYPVOLUME,
               Reserved = 0,
               ClassGuid = GuidDevinterfaceUSBDevice,
               Name = 0
           };

        dbi.Size = System.Runtime.InteropServices.Marshal.SizeOf( dbi );
        IntPtr buffer = System.Runtime.InteropServices.Marshal.AllocHGlobal( dbi.Size );
        System.Runtime.InteropServices.Marshal.StructureToPtr( dbi, buffer, true );

        IntPtr i = RegisterDeviceNotification( Handle, buffer, 0 );

        System.Runtime.InteropServices.Marshal.FreeHGlobal( buffer );

        if ( IntPtr.Size == 4 )
        {
            oldWndProc  = new IntPtr( SetWindowLong( Handle, GWLP_WNDPROC, System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate( newWndProc ).ToInt32() ) );
        }
        else
        { 
            oldWndProc  = SetWindowLongPtr( Handle, GWLP_WNDPROC, System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate( newWndProc ) );
        }
Goz
  • 61,365
  • 24
  • 124
  • 204