0

我正在使用一些代码,这些代码使用 Microsoft.WindowsAPICodePack 来提供 Vista 风格的通用对话框 ( IFileOpenDialog, IFileSaveDialog) 的 C# 包装器。我想在OnFileOk事件回调中添加对所选项目的验证,这主要是有效的,但它的一个方面是提取对话框的 HWND 以用作显示的消息框的父级。Microsoft 提供了有关如何执行此操作的文档:

调用进程可以使用对话框本身的窗口句柄作为 UI 的父级。可以通过首先调用IOleWindow::QueryInterface然后使用该句柄调用IOleWindow::GetWindow来获取该句柄,如本例所示。

https://msdn.microsoft.com/en-us/library/windows/desktop/bb776913(v=vs.85).aspx

我在代码中添加了IOleWindow接口的定义:

[ComImport,
Guid(ShellIIDGuid.IOleWindow),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IOleWindow
{
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    void ContextSensitiveHelp(
        [In] bool fEnterMode);

    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    IntPtr GetWindow();
}

...

    internal const string IOleWindow = "00000114-0000-0000-C000-000000000046";

当我将IFileDialog传递的内容转换OnFileOk为时IOleWindow(我最近没有对 COM 互操作做太多工作,但这包含了QueryInterface底层 COM 世界中的调用,对吗?),没有发生错误,并且IOleWindow引用不是null. 但是,当我打电话时GetWindow,它似乎总是返回IntPtr.Zero。我尝试用out参数而不是返回值声明方法,并得到相同的结果:没有错误,但总是IntPtr.Zero.

有没有人看到我做错了什么?我没有做错什么,但有时你不能得到一个窗口句柄?

4

1 回答 1

1

@Hans Passant 的回答令人不快。COM 接口中方法的顺序很重要,我的顺序错了,就这么简单。我从按字母顺序排序的文档中获得订单,而不是从实际的 IDL 中获得订单。:-P

错误的顺序,仅用于人眼:

正确的顺序,实际的 IDL:

(我不知道 GitHub 上的 @tpn 是谁,这个链接可能会中断,但如果确实如此,那么只需从 Windows SDKIOleWindow中查找文件OleIdl.idl。:-))

于 2019-01-07T19:56:50.637 回答