FileOpenDialog 生成的 CDN_SELCHANGE 通知消息适用于 32 位构建而不是 64 位构建
Posted
技术标签:
【中文标题】FileOpenDialog 生成的 CDN_SELCHANGE 通知消息适用于 32 位构建而不是 64 位构建【英文标题】:CDN_SELCHANGE notification message generated by the FileOpenDialog work for 32bit build not for 64bit build 【发布时间】:2015-11-08 12:25:58 【问题描述】:我从 Microsoft 编写的网站下载“可扩展对话框源”(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;
即使我在 OpenFileDialog 中选择了不同的文件,ofNot.hdr.code
始终为 0,因此,应用程序在if( code == CommonDlgNotification.SelChange )
之后永远不会遇到代码块。
任何人都可以让这个测试样本在 64 位版本中工作吗?提前致谢!
示例代码下载链接:ExtensibleDialogsSource.msi
【问题讨论】:
这是扩展文件对话框的错误方法。使用 IFileDialogCustomize。 我的水晶球说 OfNotify 声明是错误的。 NMHDR.idFrom 很容易摸索,比如应该是 IntPtr。 NMHDR.code 可见错误,不是 UInt16。 是的,你是对的!非常感谢! 【参考方案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,这可以让生活更轻松。
【讨论】:
【参考方案2】:NMHDR idFrom 不是 IntPtr,而是 MSDN2005 中的 UINT。后来它被记录为 UINT_PTR...
【讨论】:
以上是关于FileOpenDialog 生成的 CDN_SELCHANGE 通知消息适用于 32 位构建而不是 64 位构建的主要内容,如果未能解决你的问题,请参考以下文章
Delphi自定义组件如何在属性面板中实现打开文件的对话框?
System.Windows.Forms.SaveFileDialog 不强制执行默认扩展名
全能代码生成器,自动生成前后端代码生成项目框架生成JavaBean生成数据库文档自动化部署项目(TableGo v8.0.0)