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...
我从 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...