代码之家  ›  专栏  ›  技术社区  ›  Sarah Weinberger

AllowAutoPlay从不被调用

  •  1
  • Sarah Weinberger  · 技术社区  · 6 年前

    我有一个WinForms应用程序。就在Program.cs中创建实际表单之前,我实例化了一个 Autoplay AllowAutoPlay() .

    我错过什么了吗?

    public class RunningObjectTableEntry : IDisposable
    {
        private const int ROTFLAGS_REGISTRATIONKEEPSALIVE = 1;
    
        private HRESULT cookie;
        private IRunningObjectTable rot = null;
        private IMoniker monkey = null;
    
        private RunningObjectTableEntry() { }
    
        public RunningObjectTableEntry(object obj)
        {
            this.AddToROT(obj);
        }
    
        public void AddToROT(object obj)
        {
            int hr = GetRunningObjectTable(0, out rot);
            if (hr != 0)
            {
                throw new COMException("Could not retrieve 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);
            }
    
            UInt32 iResult = (UInt32)rot.Register(ROTFLAGS_REGISTRATIONKEEPSALIVE, obj, monkey);   // Weak reference, but allow any user
    
            if (65536 == iResult)
                iResult = (UInt32)rot.Register(ROTFLAGS_REGISTRATIONKEEPSALIVE, obj, monkey);
    
            cookie = (HRESULT)iResult;
        }
    
        public void RemoveFromROT()
        {
            if (cookie != 0)
            {
                try
                {
                    // Get the running object table and revoke the cookie
                    rot.Revoke((int)cookie);
                    cookie = 0;
                }
                finally
                {
                    if (rot != null) while (Marshal.ReleaseComObject(rot) > 0) ;
                }
            }
        }
    
        [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
    
        public void Dispose()
        {
            if (null != monkey)
                Marshal.ReleaseComObject(monkey);
            rot.Revoke((int)cookie);
            Marshal.ReleaseComObject(rot);
        }
    
        #endregion
    }
    
    [ComVisible(true)]
    [Guid("331F1768-05A9-4ddd-B86E-DAE34DDC998A")]
    [ClassInterface(ClassInterfaceType.None)]
    public class Autoplay : IQueryCancelAutoPlay, IDisposable
    {
        private RunningObjectTableEntry rotEntry;
    
        public Autoplay()
        {
            rotEntry = new RunningObjectTableEntry(this);
        }
    
        public void RemoveFromROT()
        {
            this.rotEntry?.RemoveFromROT();
        }
        #region IQueryCancelAutoPlay Members
    
        public int AllowAutoPlay(string pszPath, AutorunContent dwContentType, string pszLabel, int dwSerialNumber)
        {
            String msgUser = $"AllowAutoPlay: Path={pszPath}, ContentType={dwContentType.ToString()}, Label={pszLabel}, SerialNumber={dwSerialNumber.ToString()}";
            System.Diagnostics.Debug.WriteLine(msgUser);
            MessageBox.Show(msgUser);
        }
    
        #endregion
    
        #region IDisposable Members
    
        public void Dispose()
        {
            rotEntry.Dispose();
        }
    
        #endregion
    }
    

    第二次调用的cookie很好,一致,但在131073或0x00020001处很好。

    Prevent Autoplay , 65536 error ,和 CodeProject

    断点或消息框都不显示。

    我使用Visual Studio 2017在Windows 10上运行。

    2 回复  |  直到 6 年前
        1
  •  1
  •   Sarah Weinberger    6 年前

    交流专家 response 答案是

    dbtoth作者评论:2003-07-30除了以上工作正常 一个小故障。。。因为代码只有在窗口 有焦点,

    值得注意的一个关键因素是“窗口”。我在问题中给出的原稿只有一种形式非常有效。我的主要应用程序有几个表单打包在一起,所以如果其中任何一个有焦点,那么代码将无法工作。

    我的应用程序首先创建一个FrmMain,但除此之外,我还有各种子窗体。只有最上面的窗体(窗口)才能获取消息,这意味着为了安全起见,所有子窗体都需要QueryCancelAutoPlay的其中一个窗体。

        2
  •  0
  •   Sarah Weinberger    6 年前

    我苦苦挣扎,终于找到了一个真正的解决办法,我想与大家分享。

    QueryCancelAutoPlay Windows SDK Inspect WndProc()

    我也不喜欢只有活动窗口才得到的 查询取消播放

    我曾经沿着这里提到的答案开始走,但不管出于什么原因放弃了它。

    我现在在设置区域有两个组合框控件。一个是Windows默认值,另一个是应用程序默认值。然后,我将启动时的应用程序设置为应用程序版本,并在应用程序退出时重置为Windows默认选项,该选项存储在组合框中。

    private const String RegKey_UserChosen_StorageOnArrival = @"Software\Microsoft\Windows\CurrentVersion\Explorer\AutoplayHandlers\UserChosenExecuteHandlers\StorageOnArrival";
    private const String RegKey_Event_StorageOnArrival = @"Software\Microsoft\Windows\CurrentVersion\Explorer\AutoplayHandlers\EventHandlersDefaultSelection\StorageOnArrival";
    private const String RegValue_NoAction = @"MSTakeNoAction";
    private const String RegValue_OpenFolder = @"MSOpenFolder";
    
    public static Boolean SetExplorerAutoplay(String regValue)
    {
        try
        {
            // Open first key needed.
            using (RegistryKey oKey = Registry.CurrentUser.OpenSubKey(ExplorerAutoplay.RegKey_UserChosen_StorageOnArrival, true))
            {
                // Set the default value. To set the default value do not use "(Default)", but rather leave blank.
                oKey.SetValue(String.Empty, regValue);
            }
    
            // Open second key needed.
            using (RegistryKey oKey = Registry.CurrentUser.OpenSubKey(ExplorerAutoplay.RegKey_Event_StorageOnArrival, true))
            {
                // Set the default value. To set the default value do not use "(Default)", but rather leave blank.
                oKey.SetValue(String.Empty, regValue);
            }
    
            return true;
        }
    
        catch (Exception)
        {
        }
    
        return false;
    }
    
    public static Boolean GetExplorerAutoplay(out AutoPlayDriveAction action, out String regValue)
    {
        action = AutoPlayDriveAction.Invalid;
        regValue = null;
        try
        {
            // Only one of the keys is necessary, as both are the same.
            using (RegistryKey oKey = Registry.CurrentUser.OpenSubKey(ExplorerAutoplay.RegKey_UserChosen_StorageOnArrival, true))
            {
                // Get the default value.
                object oRegValue = oKey.GetValue(String.Empty);
                regValue = oRegValue?.ToString();
                if (true == regValue.Equals(ExplorerAutoplay.RegValue_NoAction))
                    action = AutoPlayDriveAction.TakeNoAction;
                else if (true == regValue.Equals(ExplorerAutoplay.RegValue_OpenFolder))
                    action = AutoPlayDriveAction.OpenFolder;
            }
    
            return true;
        }
    
        catch (Exception)
        {
        }
    
        return false;
    }
    
    public enum AutoPlayDriveAction
    {
        Invalid,
        TakeNoAction,
        OpenFolder,
    }