CDN_SELCHANGE 文件打开对话框生成的通知消息适用于 32 位版本,不适用于 64 位版本

CDN_SELCHANGE notification message generated by the FileOpenDialog work for 32bit build not for 64bit build

我从 Microsoft 编写的网站下载 "Extensible Dialogs Source"(C# 使用 P/Invoke) 来展示如何放置 Windows 表单控件在一个常见的文件对话框中。 (如:添加预览功能)。 本项目有测试客户端代码,就是打开一个对话框,点击图片后,可以在对话框右侧预览图片。 测试客户端代码在 32 位构建 中运行良好,但在 64 位构建.

中不起作用

经过一些调试,我发现这是因为在 64 位构建中,CDN_SELCHANGE 来自

的通知消息
    [DllImport("ComDlg32.dll", CharSet = CharSet.Unicode)]
    internal static extern bool GetOpenFileName( ref OpenFileName ofn );

无法在 c# 代码中正确识别或处理。

// WM_NOTIFY - we're only interested in the CDN_SELCHANGE notification message
// we grab the currently-selected filename and fire our event
case WindowMessage.Notify:
{
    IntPtr ipNotify = new IntPtr( lParam );
    OfNotify ofNot = (OfNotify)Marshal.PtrToStructure( ipNotify, typeof(OfNotify) );
    UInt16 code = ofNot.hdr.code;
    if( code == CommonDlgNotification.SelChange )
    {
       // This is the first time we can rely on the presence of the content panel
       // Resize the content and user-supplied panels to fit nicely
       FindAndResizePanels( hWnd );

       // get the newly-selected path
       IntPtr hWndParent = NativeMethods.GetParent( hWnd );
       StringBuilder pathBuffer = new StringBuilder(_MAX_PATH);
       UInt32 ret = NativeMethods.SendMessage( hWndParent, CommonDlgMessage.GetFilePath, _MAX_PATH, pathBuffer );
       string path = pathBuffer.ToString();

       // copy the string into the path buffer
       UnicodeEncoding ue = new UnicodeEncoding();
       byte[] pathBytes = ue.GetBytes( path );
       Marshal.Copy( pathBytes, 0, _fileNameBuffer, pathBytes.Length );

       // fire selection-changed event
       if( SelectionChanged != null ) SelectionChanged( path );
     }
     return IntPtr.Zero;
}

即使我 select OpenFileDialog 中的不同文件,ofNot.hdr.code 始终为 0,因此,应用程序永远不会在 if( code == CommonDlgNotification.SelChange ) 之后遇到代码块。 任何人都可以使这个测试示例在 64 位构建中工作吗?提前致谢!

示例代码下载link:ExtensibleDialogsSource.msi

感谢大家的回复,我找到了解决办法。某些 结构定义在应用于 64 位应用程序 时是错误的 。 在 NativeMethods.cs(由 Microsoft 编写,可能不针对 64 位应用程序)中,它定义了

/// <summary>
/// Part of the notification messages sent by the common dialogs
/// </summary>
[StructLayout(LayoutKind.Explicit)]
internal struct NMHDR
{
    [FieldOffset(0)]    public IntPtr   hWndFrom;
    [FieldOffset(4)]    public UInt16   idFrom;
    [FieldOffset(8)]    public UInt16   code;
};

/// <summary>
/// Part of the notification messages sent by the common dialogs
/// </summary>
[StructLayout(LayoutKind.Explicit)]
internal struct OfNotify
{
    [FieldOffset(0)]    public NMHDR    hdr;
    [FieldOffset(12)]   public IntPtr   ipOfn;
    [FieldOffset(16)]   public IntPtr   ipFile;
};

由于 IntPtr 的大小已更改从 4 个字节到 8 个字节。 所以我们需要重新定义结构.

[StructLayout(LayoutKind.Explicit)]
internal struct NMHDR
{
    [FieldOffset(0)]
    public IntPtr hWndFrom;
    [FieldOffset(8)]
    public IntPtr idFrom;
    [FieldOffset(16)]
    public UInt16 code;
};

/// <summary>
/// Part of the notification messages sent by the common dialogs
/// </summary>
[StructLayout(LayoutKind.Explicit)]
internal struct OfNotify
{
    [FieldOffset(0)]
    public NMHDR hdr;
    [FieldOffset(20)]
    public IntPtr ipOfn;
    [FieldOffset(28)]
    public IntPtr ipFile;
};

现在它适用于 64 位应用程序。

在我看来,如果可能的话,我们最好使用.Net lib,这样可以使生活更轻松。

NMHDR idFrom在MSDN2005中不是IntPtr,而是UINT。后来它被记录为 UINT_PTR...