好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

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

前言

从业以来,数次踩中编码的坑, 这次又马失前蹄 , 真是事不过三此非彼白.

本来这个小问题不打算拿出来说 , 但是翻看谷歌发现若干年前也有寥寥数人遇到碰到这个问题 ,而且都并没有给出一个可行的解决方案 ,现在问题依然挂在CSDN等地方 , 似乎不会再有人去回答了, 或者其实题主们后面解决了但并没有回头来提供解决方案. 现在由我来]终结此贴]

SHBrowseForFolder是一个可以用于获取文件夹路径的Windows API。使用起来可以方便很多,文中将详细介绍关于 C# 使用SHBrowseForFolder 导出 中文文件夹的相关内容 ,下面话不多说了,来一起看看详细的介绍吧

0x00.使用SHBrowseForFolder选择文件夹

(大段代码来袭 , 不想看可直接拉到底看关键的几行)

底层接口 – 选择文件夹相关

?

//-------------------------------------------------------------------------

class Win32API

{

  // C# representation of the IMalloc interface.

  [InterfaceType(ComInterfaceType.InterfaceIsIUnknown),

  Guid( "00000002-0000-0000-C000-000000000046" )]

  public interface IMalloc

  {

  [PreserveSig]

  IntPtr Alloc([In] int cb);

  [PreserveSig]

  IntPtr Realloc([In] IntPtr pv, [In] int cb);

  [PreserveSig]

  void Free([In] IntPtr pv);

  [PreserveSig]

  int GetSize([In] IntPtr pv);

  [PreserveSig]

  int DidAlloc(IntPtr pv);

  [PreserveSig]

  void HeapMinimize();

  }

 

  [StructLayout(LayoutKind.Sequential, Pack = 8)]

  public struct BROWSEINFO

  {

  public IntPtr hwndOwner;

  public IntPtr pidlRoot;

  public IntPtr pszDisplayName;

  [MarshalAs(UnmanagedType.LPTStr)]

  public string lpszTitle;

  public int ulFlags;

  [MarshalAs(UnmanagedType.FunctionPtr)]

  public Shell32.BFFCALLBACK lpfn;

  public IntPtr lParam;

  public int iImage;

  }

 

  [Flags]

  public enum BffStyles

  {

  RestrictToFilesystem = 0x0001, // BIF_RETURNONLYFSDIRS

  RestrictToDomain = 0x0002, // BIF_DONTGOBELOWDOMAIN

  RestrictToSubfolders = 0x0008, // BIF_RETURNFSANCESTORS

  ShowTextBox = 0x0010, // BIF_EDITBOX

  ValidateSelection = 0x0020, // BIF_VALIDATE

  NewDialogStyle = 0x0040, // BIF_NEWDIALOGSTYLE

  BrowseForComputer = 0x1000, // BIF_BROWSEFORCOMPUTER

  BrowseForPrinter = 0x2000, // BIF_BROWSEFORPRINTER

  BrowseForEverything = 0x4000, // BIF_BROWSEINCLUDEFILES

  }

 

  [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]

  public class OpenFileName

  {

  public int structSize = 0;

  public IntPtr dlgOwner = IntPtr.Zero;

  public IntPtr instance = IntPtr.Zero;

  public String filter = null ;

  public String customFilter = null ;

  public int maxCustFilter = 0;

  public int filterIndex = 0;

  public String file = null ;

  public int maxFile = 0;

  public String fileTitle = null ;

  public int maxFileTitle = 0;

  public String initialDir = null ;

  public String id="codetool">

简单介绍一下 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( "\0" , "" );

  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( "\0" , "" );

谷歌上找到的一个方案是把项目编码全部改为unicode , 但是C#项目里貌似没这个设定 , 所以使用SHGetPathFromIDList拿出的数据直接转码即可支持中文.(全部为英文的路径也不会有影响)

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对服务器之家的支持。

原文链接:http://shadowkong测试数据/archives/2409

dy("nrwz");

查看更多关于C#如何使用SHBrowseForFolder导出中文文件夹详解的详细内容...

  阅读:35次