none
IQueryCancelAutoPlay only called once?

    Question

  • I have registered my class instance in the ROT, and it is called successfully the first time I insert media, but if I remove, then re-add the media, the normal windows dialog appears instead.

    I'm using C#/Interop, so is it possible my class is getting unloaded?

    Here is my code


    This is a class to handle registering an object in the ROT

        public class RunningObjectTableEntry : IDisposable
        {
            private int cookie;
            private IRunningObjectTable rot = null;
            private IMoniker monkey = null;

            private RunningObjectTableEntry() { }

            /// <summary>
            /// Creates a new entry for the given object
            /// </summary>
            /// <param name="obj">Object to make an entry for. Only one object per class should ever be registered.</param>
            public RunningObjectTableEntry(object obj)
            {
                int hr = GetRunningObjectTable(0, out rot);
                if (hr != 0)
                {
                    throw new COMException("Could not retreive running object table!", hr);
                }

                Guid clsid = obj.GetType().GUID;
                hr = CreateClassMoniker(ref clsid, out monkey);
                if (hr != 0)
                {
                    Marshal.ReleaseComObject(rot);
                    throw new COMException("Could not create moniker for CLSID/IID \"" + clsid + "\"!", hr);
                }

                cookie = rot.Register(0x00, obj, monkey);   //weak reference, but allow any user
            }

            [DllImport("ole32.dll", ExactSpelling = true)]
            private static extern int GetRunningObjectTable([MarshalAs(UnmanagedType.U4)] int reserved, out IRunningObjectTable pprot);

            [DllImport("ole32.dll", CharSet=CharSet.Unicode, ExactSpelling=true)]
            private static extern int CreateClassMoniker([In] ref Guid g, [Out] out IMoniker ppmk);

            #region IDisposable Members

            /// <summary>
            /// De-registers the object and class from the Running Object Table
            /// </summary>
            public void Dispose()
            {
                Marshal.ReleaseComObject(monkey);
                rot.Revoke(cookie);
                Marshal.ReleaseComObject(rot);
            }

            #endregion
    }


    Then I have implemented the class

        [ComVisible(true)]
        [Guid("63DA3B72-E9C9-4d40-B7DA-DC537C4C5CC2")]
        [ClassInterface(ClassInterfaceType.None)]
        public class Autoplay : IQueryCancelAutoPlay, IDisposable
        {
            private RunningObjectTableEntry rotEntry;

            public Autoplay()
            {
                rotEntry = new RunningObjectTableEntry(this);
            }

            #region IQueryCancelAutoPlay Members

            public int AllowAutoPlay(string pszPath, Content dwContentType, string pszLabel, int dwSerialNumber)
            {
               

                Console.WriteLine("QueryCancelAutoPlay:");
                Console.WriteLine("   " + pszPath);
                Console.WriteLine("   " + dwContentType.ToString("x"));
                Console.WriteLine("   " + pszLabel);
                Console.WriteLine("   " + dwSerialNumber.ToString());

                return 1;
            }

            #endregion

            #region IDisposable Members

            public void Dispose()
            {
                rotEntry.Dispose();
            }

            #endregion
        }
    Wednesday, September 09, 2009 12:36 AM

Answers

  • This line:
                cookie = rot.Register(0x00, obj, monkey);   //weak reference, but allow any user

    as posted above, was commented wrong (it is only a weak reference).

    I changed it to Registration Keeps Alive (0x01), and now it works.
    • Marked as answer by kcdixon Wednesday, September 09, 2009 4:23 PM
    Wednesday, September 09, 2009 4:23 PM

All replies

  • This line:
                cookie = rot.Register(0x00, obj, monkey);   //weak reference, but allow any user

    as posted above, was commented wrong (it is only a weak reference).

    I changed it to Registration Keeps Alive (0x01), and now it works.
    • Marked as answer by kcdixon Wednesday, September 09, 2009 4:23 PM
    Wednesday, September 09, 2009 4:23 PM
  • I use your code in my program. but it doesn't work. Please help me! Thank you very much!
    I'm using C#/WPF. Here is my code.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using System.Runtime.InteropServices;
    using System.Runtime.InteropServices.ComTypes;

    namespace test
    {
        /// <summary>
        /// Window1.xaml 的交互逻辑
        /// </summary>
        public partial class Window1 : Window
        {     
            public Window1()
            {
                InitializeComponent();
                Autoplay at = new Autoplay();               //I think there is something wrong, but I don't know how it can be called.
            }

        public class RunningObjectTableEntry : IDisposable
        {
            private int cookie;
            private IRunningObjectTable rot = null;
            private IMoniker monkey = null;

            private RunningObjectTableEntry() { }

            /// <summary>
            /// Creates a new entry for the given object
            /// </summary>
            /// <param name="obj">Object to make an entry for. Only one object per class should ever be registered.</param>
            public RunningObjectTableEntry(object obj)
            {
                int hr = GetRunningObjectTable(0, out rot);
                if (hr != 0)
                {
                    throw new COMException("Could not retreive running object table!", hr);
                }

                Guid clsid = obj.GetType().GUID;
                hr = CreateClassMoniker(ref clsid, out monkey);
                if (hr != 0)
                {
                    Marshal.ReleaseComObject(rot);
                    throw new COMException("Could not create moniker for CLSID/IID \"" + clsid + "\"!", hr);
                }

                cookie = rot.Register(0x01, obj, monkey);   //weak reference, but allow any user
            }

            [DllImport("ole32.dll", ExactSpelling = true)]
            private static extern int GetRunningObjectTable([MarshalAs(UnmanagedType.U4)] int reserved, out IRunningObjectTable pprot);

            [DllImport("ole32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
            private static extern int CreateClassMoniker([In] ref Guid g, [Out] out IMoniker ppmk);

            #region IDisposable Members

            /// <summary>
            /// De-registers the object and class from the Running Object Table
            /// </summary>
            public void Dispose()
            {
                Marshal.ReleaseComObject(monkey);
                rot.Revoke(cookie);
                Marshal.ReleaseComObject(rot);
            }

            #endregion
        }

        public enum AutorunContent
        {
            AutorunInf = 2,
            AudioCD = 4,
            DVDMovie = 8,
            BlankCD = 16,
            BlankDVD = 32,
            UnknownContent = 64,
            AutoPlayPictures = 128,
            AutoPlayMusics = 256,
            AutoPlayMovies = 512
        }

        [ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("DDEFE873-6997-4e68-BE26-39B633ADBE12")]
        public interface IQueryCancelAutoPlay
        {
            [PreserveSig()]
            int AllowAutoPlay([In(), MarshalAs(UnmanagedType.LPWStr)]  string pszPath,
                [In(), MarshalAs(UnmanagedType.LPWStr)]  AutorunContent dwContentType,
                [In(), MarshalAs(UnmanagedType.LPWStr)]  string pszLabel,
                [In(), MarshalAs(UnmanagedType.LPWStr)]  int dwSerialNumber);
        }


        [ComVisible(true)]
        [Guid("63DA3B72-E9C9-4d40-B7DA-DC537C4C5CC2")]
        [ClassInterface(ClassInterfaceType.None)]
        public class Autoplay : IQueryCancelAutoPlay, IDisposable
        {
            private RunningObjectTableEntry rotEntry;

            public Autoplay()
            {
                rotEntry = new RunningObjectTableEntry(this);
            }

            #region IQueryCancelAutoPlay Members

            public int AllowAutoPlay(string pszPath, AutorunContent dwContentType, string pszLabel, int dwSerialNumber)
            {
                Console.WriteLine("QueryCancelAutoPlay:");
                Console.WriteLine("   " + pszPath);
                Console.WriteLine("   " + dwContentType.ToString("x"));
                Console.WriteLine("   " + pszLabel);
                Console.WriteLine("   " + dwSerialNumber.ToString());
                System.Windows.MessageBox.Show("QueryCancelAutoPlay");
                return 1;
            }

            #endregion

            #region IDisposable Members

            public void Dispose()
            {
                rotEntry.Dispose();
            }

            #endregion
        }
    }

    Friday, September 11, 2009 9:03 AM

  •     public enum AutorunContent
        {
            AutorunInf = 2,
            AudioCD = 4,
            DVDMovie = 8,
            BlankCD = 16,
            BlankDVD = 32,
            UnknownContent = 64,
            AutoPlayPictures = 128,
            AutoPlayMusics = 256,
            AutoPlayMovies = 512
        }

        [ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("DDEFE873-6997-4e68-BE26-39B633ADBE12")]
        public interface IQueryCancelAutoPlay
        {
            [PreserveSig()]
            int AllowAutoPlay([In(), MarshalAs(UnmanagedType.LPWStr)]  string pszPath,
                [In(), MarshalAs(UnmanagedType.LPWStr)]  AutorunContent dwContentType,
                [In(), MarshalAs(UnmanagedType.LPWStr)]  string pszLabel,
                [In(), MarshalAs(UnmanagedType.LPWStr)]  int dwSerialNumber);
        }


    Likely the issue is your interface declaration.


        [ComImport]
        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        [Guid("DDEFE873-6997-4e68-BE26-39B633ADBE12")]
        public interface IQueryCancelAutoPlay
        {
            [PreserveSig]
            int AllowAutoPlay(
              [MarshalAs(UnmanagedType.LPWStr)] string pszPath,
              [MarshalAs(UnmanagedType.U4)] Content dwContentType,
              [MarshalAs(UnmanagedType.LPWStr)] string pszLabel,
              [MarshalAs(UnmanagedType.U4)] int dwSerialNumber);
        }

    You should also change your enum to be like this:

        [Flags]
        public enum AutorunContent : int
        {


    Generally if you are having difficulty getting your methods called, look for problems in your interface first
    Friday, September 11, 2009 9:02 PM
  •  public partial class Window1 : Window
        {     
            public Window1()
            {
                InitializeComponent();
                Autoplay at = new Autoplay();               //I think there is something wrong, but I don't know how it can be called.
            }

    Thank you for helping me. I have modified the interface and enum as you shown. But it still doesn't work. The function of AllowAutoPlay doesn't been called.
    I still have problem of how to connect the class "Autoplay" with my class "Window1".
    Monday, September 14, 2009 1:44 AM
  • I find the reason.

    [ComVisible(true)]
        [Guid("63DA3B72-E9C9-4d40-B7DA-DC537C4C5CC2")]
        [ClassInterface(ClassInterfaceType.None)]

    here the classId should be
     331F1768-05A9-4ddd-B86E-DAE34DDC998A
    Friday, September 18, 2009 8:49 AM
  • Sorry for ressurrecting this old thread.

    I also have the problem that the AllowAutoPlay method is not called by Windows (7 x64). I did it the same way as shown in this thread or do I still need to do something else like in the assemblyinfo.cs file or project settings?

    It worked with registering the QueryCancelAutoPlay window message but as this is not sent if my app is in the background it is useless to  me. My app should be notified when a new DVD is inserted so that it can look for files and automatically copy them to hard disk without being the active window as I want to do something else in that time. It seems I have to use a poll timer to check the drive contents which I do not like.

    I am using Visual Studio 2010.

    Thanks for any help or advise.

    Saturday, May 08, 2010 1:10 PM
  • Make sure your class is decorated as such:

    [ComVisible(true)]
        [Guid("MyClassGUID")]
        [ProgId("MyClassProgID")]
        public class MyClass

    Wednesday, July 07, 2010 12:25 AM