c# - 从处理 NativeWindow 中的 WM_GETOBJECT 返回 IOleCommandTarget

标签 c# com wndproc native-methods nativewindow

我正在尝试从面板控制句柄中检索 IOleCommandTarget 引用,以便我可以对其调用 IOleCommandTarget.Exec()。

NativeMethods.IOleCommandTarget target = null;
if (GetObjectFromHandle<NativeMethods.IOleCommandTarget>(panel.Handle, out target))
{
    Guid guidCmdGroup = commandID.Guid;
    handled = (target.Exec(ref guidCmdGroup, commandID.ID, 0, null, 0) == NativeMethods.S_OK);
}

private static bool GetObjectFromHandle<T>(IntPtr hwnd, out T value)
{
    Guid guid = typeof(T).GUID;
    object obj = null;
    var hr = NativeMethods.AccessibleObjectFromWindow(hwnd, 0, ref guid, ref obj);
    if (hr == NativeMethods.S_OK)
    {
        value = (T)obj;
        return true;
    }
    value = default(T);
    return false;
}

在我的 NativeMethods.cs 中:

[ComImport]
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("B722BCCB-4E68-101B-A2BC-00AA00404770")]
public interface IOleCommandTarget
{
    [return: MarshalAs(UnmanagedType.I4)]
    [PreserveSig]
    int QueryStatus(ref Guid pguidCmdGroup, int cCmds, [In, Out] NativeMethods.OLECMD prgCmds, [In, Out] IntPtr pCmdText);
    [return: MarshalAs(UnmanagedType.I4)]
    [PreserveSig]
    int Exec(ref Guid pguidCmdGroup, int nCmdID, int nCmdexecopt, [In, MarshalAs(UnmanagedType.LPArray)] object[] pvaIn, int pvaOut);
}

[DllImport("oleacc.dll")]
public static extern int AccessibleObjectFromWindow(
        IntPtr hwnd,
        uint id,
        ref Guid iid,
        [In, Out, MarshalAs(UnmanagedType.IUnknown)] ref object ppvObject);

为了能够返回一个 IOleCommandTarget 引用,我创建了一个实现 NativeWindow 和 IOleCommandTarget 的 CommandTargetWindow 类,并且我覆盖了 WndProc 以拦截 AccessibleObjectFromWindow() 发送的 WM_GETOBJECT 消息:

public sealed class CommandTargetWindow : NativeWindow,
    NativeMethods.IOleCommandTarget,
    IDisposable
{
    private IWin32Window _parent;

    public CommandTargetWindow(IWin32Window parent)
    {
        _parent = parent;
        base.AssignHandle(parent.Handle);
    }

    [PermissionSetAttribute(SecurityAction.Demand, Unrestricted = true)]
    protected override void WndProc(ref System.Windows.Forms.Message m)
    {
        if (m.Msg == NativeMethods.WM_GETOBJECT)
        {
            //How do I pass back an IOleCommandTarget through the message?
        }
        base.WndProc(ref m);
    }
}

问题是,如上面的评论所述,如何通过消息传回 IOleCommandTarget?

我们通过实现接口(interface) IRawElementProviderSimple(而不是 IOleCommandTarget)并使用定义的静态方法 AutomationInteropProvider.ReturnRawElementProvider() 来实现自动化目的,在其他地方做类似的事情:

[PermissionSetAttribute(SecurityAction.Demand, Unrestricted = true)]
protected override void WndProc(ref System.Windows.Forms.Message m)
{
    if ((m.Msg == NativeMethods.WM_GETOBJECT) && (m.LParam.ToInt32() == AutomationInteropProvider.RootObjectId))
    {
        m.Result = AutomationInteropProvider.ReturnRawElementProvider(
            Handle, m.WParam, m.LParam, (IRawElementProviderSimple)this);

        return;
    }
    base.WndProc(ref m);
}

有什么想法吗?

最佳答案

事实证明我需要使用我在 NativeMethods.cs 中定义的 COM 方法 LresultFromObject

[DllImport("oleacc.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern IntPtr LresultFromObject(ref Guid refiid, IntPtr wParam, IntPtr pAcc);

现在在我的 WndProc 中,我调用 LresultFromObject 以返回 m.Result 中的 IOleCommandTarget 句柄:

[PermissionSetAttribute(SecurityAction.Demand, Unrestricted = true)]
protected override void WndProc(ref System.Windows.Forms.Message m)
{
    if (m.Msg == (int)NativeMethods.WindowMessage.GETOBJECT)
    {
        if (m.LParam.ToInt32() == AutomationInteropProvider.RootObjectId)
        {
            m.Result = AutomationInteropProvider.ReturnRawElementProvider(
                Handle, m.WParam, m.LParam, (IRawElementProviderSimple)this);

            return;
        }
        else if (m.LParam == (IntPtr)NativeMethods.OBJID_NATIVEOM)
        {
            IntPtr handle = Marshal.GetComInterfaceForObject(this, typeof(NativeMethods.IOleCommandTarget));
            Guid unknownGuid = typeof(NativeMethods.IUnknown).GUID;
            m.Result = NativeMethods.LresultFromObject(ref unknownGuid, m.WParam, handle);
            return;
        }
    }
    base.WndProc(ref m);
}

关于c# - 从处理 NativeWindow 中的 WM_GETOBJECT 返回 IOleCommandTarget,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6459778/

相关文章:

c# - 如何在 C# 中刷新列表框?

C# 表单控件 move

c# - 可拖动的 WinForm 问题

c# - 是否可以从 .NET 测试暴露于 COM 的程序集?

c# - 从 javascript 调用 C# BHO 方法

c# - 捕获鼠标触摸win窗体的标题栏

c# - 防止接口(interface)在其他程序集中实现

c# - 如何使用 JSONConvert 将变量 Result 转换为对象?

c# - 如何在自适应对话框 HttpRequest 中从 xml 转换为 json?

c# - x86 与在 x64 上编译的 COM Interop