FileOpenDialog生成的CDN_SELCHANGE通知消息适用于32位构建而不适用于64位构建

时间:2015-08-15 10:19:52

标签: c# winapi pinvoke 32bit-64bit

我从Microsoft编写的网站下载“Extensible Dialogs Source”( C#using 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;
}

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

示例代码下载链接:ExtensibleDialogsSource.msi

2 个答案:

答案 0 :(得分:1)

感谢所有好评,我找到了解决方案。某些结构定义错误适用于 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,这可以让生活更轻松。

答案 1 :(得分:0)

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

相关问题