C#如何使用SHBrowseForFolder导出中文文件夹详解

2020-01-05 10:03:47王冬梅

简单介绍一下 Win32API 所有接口的结构体 都是参照SHBrowseForFolder函数而写 , Win32Instance 主要是精确的获取当前进程的ID

接下来是 获取文件夹路径的简单例子


//-------------------------------------------------------------------------
private void __SelectFolder(out string directoryPath)
{
 directoryPath = "null";
 try
 {
 IntPtr pidlRet = IntPtr.Zero;
 int publicOptions = (int)Win32API.BffStyles.RestrictToFilesystem |
 (int)Win32API.BffStyles.RestrictToDomain;
 int privateOptions = (int)Win32API.BffStyles.NewDialogStyle;

 // Construct a BROWSEINFO.
 Win32API.BROWSEINFO bi = new Win32API.BROWSEINFO();
 IntPtr buffer = Marshal.AllocHGlobal(1024);
 int mergedOptions = (int)publicOptions | (int)privateOptions;
 bi.pidlRoot = IntPtr.Zero;
 bi.pszDisplayName = buffer;
 bi.lpszTitle = "文件夹";
 bi.ulFlags = mergedOptions;

 Win32Instance w = new Win32Instance();
 bool bSuccess = false;
 IntPtr P = w.GetHandle(ref bSuccess);
 if (true == bSuccess)
 {
  bi.hwndOwner = P;
 }

 pidlRet = Win32API.Shell32.SHBrowseForFolder(ref bi);
 Marshal.FreeHGlobal(buffer);

 if (pidlRet == IntPtr.Zero)
 {
  // User clicked Cancel.
  return;
 }
 
 byte[] pp = new byte[2048];
 if (0 == Win32API.Shell32.SHGetPathFromIDList(pidlRet, pp))
 {
  return;
 }

 int nSize = 0;
 for (int i = 0; i < 2048; i++)
 {
  if (0 != pp[i])
  {
  nSize++;
  }
  else
  {
  break;
  }

 }

 if (0 == nSize)
 {
  return;
 }

 byte[] pReal = new byte[nSize];
 Array.Copy(pp, pReal, nSize);
 // 关键转码部分
 Gb2312Encoding gbk = new Gb2312Encoding();
 Encoding utf8 = Encoding.UTF8;
 byte[] utf8Bytes = Encoding.Convert(gbk, utf8, pReal);
 string utf8String = utf8.GetString(utf8Bytes);
 utf8String = utf8String.Replace("", "");
 directoryPath = utf8String.Replace("", "/") + "/";

 }
 catch (Exception e)
 {
 Console.WriteLine("获取文件夹目录出错:" + e.Message);
 }
}

以上用到的一个GBK转码库 位置查看 - github传送门

0x01.GBK转码

以下是关键的一段代码:


Gb2312Encoding gbk = new Gb2312Encoding();
Encoding utf8 = Encoding.UTF8;
byte[] utf8Bytes = Encoding.Convert(gbk, utf8, pReal);
string utf8String = utf8.GetString(utf8Bytes);
utf8String = utf8String.Replace("", "");