我正在尝试调用SHBrowseForFolder
API来提示用户选择一个文件夹,我看到标题static / label字段浮动在树控件之上。
代码是从网上多个地方引用的article下载的,并且从C#转换为VB.NET(它被放入现有的应用程序中)。
如果有人有任何关于正确布局的提示,请赐教。
调用代码很简单:
Using getLocDialog As New FolderBrowserDialog()
getLocDialog.Description = "This is a test"
getLocDialog.ShowDialog()
End Using
接下来,这是代码的VB.NET版本:
Public Class FolderBrowserDialog
Inherits CommonDialog
'---------------------------------------------------------------------------
' instance
'---------------------------------------------------------------------------
Private info As BrowseInfo
Private folder As String = String.Empty
'---------------------------------------------------------------------------
' ctor
'---------------------------------------------------------------------------
Public Sub New()
info = New BrowseInfo()
info.Title = String.Empty
InitCommonControls()
End Sub
'---------------------------------------------------------------------------
' public
'---------------------------------------------------------------------------
Public Shadows Function ShowDialog() As DialogResult
Dim pitemidlist As IntPtr
Try
pitemidlist = SHBrowseForFolder(info.ToByteArray())
Catch mme As MissingMethodException
Throw New PlatformNotSupportedException("Your platform doesn't support the SHBrowseForFolder API", mme)
End Try
If pitemidlist = IntPtr.Zero Then
Return DialogResult.Cancel
End If
'//maxpath unicode chars
Dim buffer As Byte() = New Byte(519) {}
Dim success As Boolean = SHGetPathFromIDList(pitemidlist, buffer)
'//get string from buffer
If success Then
folder = System.Text.Encoding.Unicode.GetString(buffer, 0, buffer.Length)
Dim nullindex As Integer = folder.IndexOf(Convert.ToChar(0))
If nullindex <> -1 Then
folder = folder.Substring(0, nullindex)
End If
End If
LocalFree(pitemidlist)
Return DialogResult.OK
End Function
Public ReadOnly Property SelectedPath() As String
Get
Return folder
End Get
End Property
Public Property Description() As String
Get
Return info.Title
End Get
Set(ByVal value As String)
info.Title = value
End Set
End Property
'---------------------------------------------------------------------------
' private
'---------------------------------------------------------------------------
<DllImport("commctrl", SetLastError:=True)> _
Private Shared Sub InitCommonControls()
End Sub
<DllImport("ceshell", SetLastError:=True)> _
Private Shared Function SHBrowseForFolder(ByVal lpbi As Byte()) As IntPtr
End Function
<DllImport("ceshell", SetLastError:=True)> _
Private Shared Function SHGetPathFromIDList(ByVal pidl As IntPtr, ByVal pszPath As Byte()) As Boolean
End Function
<DllImport("coredll", SetLastError:=True)> _
Private Shared Function LocalFree(ByVal ptr As IntPtr) As IntPtr
End Function
'---------------------------------------------------------------------------
' inner classes
'---------------------------------------------------------------------------
Private Class BrowseInfo
Private m_data As Byte()
Private m_displayname As Byte()
Private m_title As Byte()
Private namehandle As GCHandle
Private titlehandle As GCHandle
Public Sub New()
m_data = New Byte(31) {}
m_displayname = New Byte(511) {}
m_title = New Byte(127) {}
namehandle = GCHandle.Alloc(m_displayname, GCHandleType.Pinned)
titlehandle = GCHandle.Alloc(m_title, GCHandleType.Pinned)
BitConverter.GetBytes(namehandle.AddrOfPinnedObject().ToInt32 + 4).CopyTo(m_data, 8)
BitConverter.GetBytes(titlehandle.AddrOfPinnedObject().ToInt32 + 4).CopyTo(m_data, 12)
End Sub
Public Function ToByteArray() As Byte()
Return m_data
End Function
Protected Overrides Sub Finalize()
namehandle.Free()
titlehandle.Free()
MyBase.Finalize()
End Sub
Public Property Title() As String
Get
Dim ttl As String = System.Text.Encoding.Unicode.GetString(m_title, 0, m_title.Length)
Dim nullindex As Integer = ttl.IndexOf(Convert.ToChar(0))
If nullindex = -1 Then
Return ttl
End If
Return ttl.Substring(0, ttl.IndexOf(Convert.ToChar(0)))
End Get
Set(ByVal value As String)
Dim titlebytes As Byte() = System.Text.Encoding.Unicode.GetBytes(value & Convert.ToChar(0))
If titlebytes.Length > m_title.Length Then
Throw New ArgumentException("Description must be no longer than 64 characters")
End If
Try
Buffer.BlockCopy(titlebytes, 0, m_title, 0, titlebytes.Length)
Catch ex As Exception
End Try
End Set
End Property
Public Property FileName() As String
Get
Dim fn As String = System.Text.Encoding.Unicode.GetString(m_displayname, 0, m_displayname.Length)
Dim nullindex As Integer = fn.IndexOf(Convert.ToChar(0))
If nullindex = -1 Then
Return fn
End If
Return fn.Substring(0, fn.IndexOf(Convert.ToChar(0)))
End Get
Set(ByVal value As String)
Dim filenamebytes As Byte() = System.Text.Encoding.Unicode.GetBytes(value & Convert.ToChar(0))
If filenamebytes.Length > m_title.Length Then
Throw New ArgumentException("SelectedFolder must be no longer than 256 characters")
End If
Buffer.BlockCopy(filenamebytes, 0, m_displayname, 0, filenamebytes.Length)
End Set
End Property
'/*HWND hwndOwner;
'LPCITEMIDLIST pidlRoot;
'LPTSTR pszDisplayName;
'LPCTSTR lpszTitle;
'UINT ulFlags;
'BFFCALLBACK lpfn;
'LPARAM lParam;
'int iImage;*/
End Class
End Class
最初的C#是这样的:
public class FolderBrowserDialog : CommonDialog
{
private BrowseInfo info;
private string folder = string.Empty;
/// <summary>
/// Initializes a new instance of the FolderBrowserDialog class.
/// </summary>
public FolderBrowserDialog()
{
info = new BrowseInfo();
info.Title = string.Empty;
InitCommonControls();
}
/// <summary>
/// Runs a common dialog box with a default owner.
/// </summary>
/// <returns></returns>
public new DialogResult ShowDialog()
{
IntPtr pitemidlist;
try
{
pitemidlist = SHBrowseForFolder(info.ToByteArray());
}
catch(MissingMethodException mme)
{
throw new PlatformNotSupportedException("Your platform doesn't support the SHBrowseForFolder API",mme);
}
if(pitemidlist==IntPtr.Zero)
{
return DialogResult.Cancel;
}
//maxpath unicode chars
byte[] buffer = new byte[520];
bool success = SHGetPathFromIDList(pitemidlist, buffer);
//get string from buffer
if(success)
{
folder = System.Text.Encoding.Unicode.GetString(buffer, 0, buffer.Length);
int nullindex = folder.IndexOf('\0');
if(nullindex!=-1)
{
folder = folder.Substring(0, nullindex);
}
}
LocalFree(pitemidlist);
return DialogResult.OK;
}
/// <summary>
/// Gets the path selected by the user.
/// </summary>
public string SelectedPath
{
get
{
return folder;
}
}
/// <summary>
/// Gets or sets the descriptive text displayed above the tree view control in the dialog box.
/// </summary>
public string Description
{
get
{
return info.Title;
}
set
{
info.Title = value;
}
}
#region P/Invokes
[DllImport("commctrl", SetLastError=true)]
private static extern void InitCommonControls();
[DllImport("ceshell", SetLastError=true)]
private static extern IntPtr SHBrowseForFolder(byte[] lpbi);
[DllImport("ceshell", SetLastError=true)]
private static extern bool SHGetPathFromIDList(IntPtr pidl, byte[] pszPath);
[DllImport("coredll", SetLastError=true)]
private static extern IntPtr LocalFree(IntPtr ptr);
#endregion
#region helper class for BROWSEINFO struct
private class BrowseInfo
{
private byte[] m_data;
private byte[] m_displayname;
private byte[] m_title;
private GCHandle namehandle;
private GCHandle titlehandle;
public BrowseInfo()
{
m_data = new byte[32];
m_displayname = new byte[512];
m_title = new byte[128];
namehandle = GCHandle.Alloc(m_displayname, GCHandleType.Pinned);
titlehandle = GCHandle.Alloc(m_title, GCHandleType.Pinned);
BitConverter.GetBytes((int)namehandle.AddrOfPinnedObject() + 4).CopyTo(m_data, 8);
BitConverter.GetBytes((int)titlehandle.AddrOfPinnedObject() + 4).CopyTo(m_data, 12);
}
public byte[] ToByteArray()
{
return m_data;
}
~BrowseInfo()
{
namehandle.Free();
titlehandle.Free();
}
public string Title
{
get
{
string title = System.Text.Encoding.Unicode.GetString(m_title, 0, m_title.Length);
int nullindex = title.IndexOf('\0');
if(nullindex==-1)
{
return title;
}
return title.Substring(0, title.IndexOf('\0'));
}
set
{
byte[] titlebytes = System.Text.Encoding.Unicode.GetBytes(value + '\0');
if(titlebytes.Length > m_title.Length)
{
throw new ArgumentException("Description must be no longer than 64 characters");
}
try
{
Buffer.BlockCopy(titlebytes, 0, m_title,0, titlebytes.Length);
}
catch
{
}
}
}
public string FileName
{
get
{
string filename = System.Text.Encoding.Unicode.GetString(m_displayname, 0, m_displayname.Length);
int nullindex = filename.IndexOf('\0');
if(nullindex==-1)
{
return filename;
}
return filename.Substring(0, filename.IndexOf('\0'));
}
set
{
byte[] filenamebytes = System.Text.Encoding.Unicode.GetBytes(value + '\0');
if(filenamebytes.Length > m_title.Length)
{
throw new ArgumentException("SelectedFolder must be no longer than 256 characters");
}
Buffer.BlockCopy(filenamebytes, 0, m_displayname,0, filenamebytes.Length);
}
}
/*HWND hwndOwner;
LPCITEMIDLIST pidlRoot;
LPTSTR pszDisplayName;
LPCTSTR lpszTitle;
UINT ulFlags;
BFFCALLBACK lpfn;
LPARAM lParam;
int iImage;*/
}
#endregion
}
其他详细信息:Dev环境是Visual Studio 2008,Compact Framework 3.5。该设备运行Windows CE 4.2。
答案 0 :(得分:1)
我与SHBrowseForFolder
,FolderBrowserDialog
和Windows CE 5.0具有相同的体验。
解决方法可能是为标志设置BIF_STATUSTEXT
。这样,布局就会移位,标题会显示在TreeView上方。
为此,请将数据成员uint m_flags
添加到BrowseInfo
类。在它的构造函数中添加:
const uint BIF_STATUSTEXT = 0x00000004;
m_flags |= BIF_STATUSTEXT;
在ToByteArray()
方法中添加:
BitConverter.GetBytes(m_flags).CopyTo(m_data, 16);