1

WinForms アプリケーションがあります。Program.cs で実際のフォームを作成する直前に、Autoplayクラスをインスタンス化します。必須の最初の戻り値 65536 の後、登録は成功しますが、 への呼び出しはありません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
}

2 番目の呼び出しの Cookie は問題なく一貫していますが、131073 または 0x00020001 では問題ありません。

次の記事を使用しました: Prevent Autoplay 、65536 error、およびCodeProject

ブレークポイントもメッセージ ボックスも表示されません。

Visual Studio 2017 を使用して Windows 10 で実行しています。

考え?

4

2 に答える 2

1

Exchange Expertの応答が答えです。つまり、

dbtoth 著者のコメント: 2003-07-30 上記は、1 つの小さな不具合を除いて正常に動作しています...コードは、ウィンドウにフォーカスがある場合にのみ動作するため、

注目すべき重要な要素は「ウィンドウ」です。私の質問で私が与えたオリジナルは、1つのフォームだけでうまく機能します。私の主なアプリケーションには複数のフォームがまとめられているため、それらのいずれかにフォーカスがあると、コードは機能しません。

上記のコードと WndProc バリアントは、Windows が QueryCancelAutoPlay メッセージを送信することに依存しています。

私のアプリケーションは最初に FrmMain を作成しますが、その上にさまざまな子フォームがあります。最上位のフォーム (ウィンドウ) のみがメッセージを取得します。つまり、安全のために、すべての子フォームに QueryCancelAutoPlay のいずれかのフォームが必要です。

于 2018-10-02T17:57:17.127 に答える