【Unity编辑器开发】工具开发之Windows单选或多选文件踩坑记录

  最近在项目组做了一个导表工具,旧版本功能只能指定某个文件夹对整个文件夹下的Excel文件进行文件导表批处理,但是策划有个新需求是导出单个文件,在根据需求维护导表工具迭代时时我想何不多做个彩蛋功能,导出单个或者多个文件?那说做就做,开始踩坑。

  旧版本的文件夹选择代码是调用了Unity自带的EditorUtility.OpenFolderPanel实现的。功能如下

string path = EditorUtility.OpenFolderPanel("自定义标题",Application.dataPath,"默认文件名");

  以上代码的返回值是你选中的文件夹路径,那选择文件的话我第一个想法就是查看Unity是否支持选择文件,那查看文档后发现EditorUtility.OpenFilePanel,看名字十分符合我的需求啊,赶紧试试。

string path = EditorUtility.OpenFilePanel("自定义标题", Application.dataPath, "文件筛选后缀");

  使用后发现确实能够选择某一个文件正确打印这个文件的路径,但是!不支持多选。。。那如果我是用户,只能单选不能多选导出总感觉欠缺了点什么,那为了不让我的策划用户们感觉欠缺灵魂,就继续研究。继续研究API发现Unity自带的EditorUtility并不支持多选这个功能,那没办法,不能使用拿来主义的话那就只能借助C#原生来调用Windows的文件弹窗了。

首先新建一个脚本,里面附上如下代码

using System;
using System.Runtime.InteropServices;


//unity3d调用win32打开对话框
[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 title = null;
    public int flags = 0;
    public short fileOffset = 0;
    public short fileExtension = 0;
    public String defExt = null;
    public IntPtr custData = IntPtr.Zero;
    public IntPtr hook = IntPtr.Zero;
    public String templateName = null;
    public IntPtr reservedPtr = IntPtr.Zero;
    public int reservedInt = 0;
    public int flagsEx = 0;
}

public class DllTest
{
    [DllImport("Comdlg32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)]
    public static extern bool GetOpenFileName([In, Out] OpenFileName ofn);
}

 

  其实就是C#调用了win32对应的Dll中弹窗的方法,需要注意的是OpenFileName对应的是OPENFILENAME这个结构体,这里附上结构体介绍:

附上这个结构体的介绍:

OPENFILENAME

OPENFILENAME结构包含了GetOpenFileName和GetSaveFileName函 数用来初始化打开或另存为对话框的信息。在用户关闭对话框后,系统返回关于用户的选择信息到这个结构中。

typedef struct tagOFN {
DWORDlStructSize;
HWNDhwndOwner;
HINSTANCEhInstance;
LPCTSTRlpstrFilter;
LPTSTRlpstrCustomFilter;
DWORDnMaxCustFilter;
DWORDnFilterIndex;
LPTSTRlpstrFile;
DWORDnMaxFile;
LPTSTRlpstrFileTitle;
DWORDnMaxFileTitle;
LPCTSTRlpstrInitialDir;
LPCTSTRlpstrTitle;
DWORDFlags;
WORDnFileOffset;
WORDnFileExtension;
LPCTSTRlpstrDefExt;
LPARAMlCustData;
LPOFNHOOKPROClpfnHook;
LPCTSTRlpTemplateName;
#if (_WIN32_WINNT >= 0x0500)
void *pvReserved;
DWORDdwReserved;
DWORDFlagsEx;
#endif // (_WIN32_WINNT >= 0x0500)
} OPENFILENAME, *LPOPENFILENAME;

之后在你需要调用的方法里写上代码

       OpenFileName ofn = new OpenFileName();

            ofn.structSize = Marshal.SizeOf(ofn);

            ofn.filter = "Excel文件(*.xlsx)\0*.xlsx;*.xlsx"; //过滤器 想要显示的文件的格式 (excel格式)         // "All Files\0*.*\0\0"; 所有格式均显示     

            ofn.file = new string(new char[256]);      // 存放目录路径缓冲区  

            ofn.maxFile = ofn.file.Length;

            ofn.fileTitle = new string(new char[64]);

            ofn.maxFileTitle = ofn.fileTitle.Length;

            ofn.initialDir = Application.dataPath;        //默认路径  

            ofn.title = "选择多个excel";       //窗口名称

            ofn.defExt = "XLSX";//显示文件的类型//注意 一下项目不一定要全选 但是0x00000008项不要缺少
            ofn.flags = 0x00080000 | 0x00001000 | 0x00000800 | 0x00000200 | 0x00000008;   //OFN_EXPLORER |OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST| OFN_ALLOWMULTISELECT|OFN_NOCHANGEDIR    

            if (DllTest.GetOpenFileName(ofn))
            {
                Debug.Log("选择的文件路径" + ofn.file);  //显示点击文件路径
            }

  好,万事俱备只欠东风,试一试发现,诶,可以多选,但是点击确定后输出的只是文件夹名称。???,惊了,再试试单选,咦,没问题,那就有意思了,需要再去研究研究官网API。为了方便读者查阅我就附在下面了,如果不想看直接跳过表格看我下面那段话就是解决办法~

成员
lStructSize
指定这个结构的大小,以字节为单位。

Windows 95/98和Windows NT 4.0:特意为Windows 95/98或Windows NT 4.0,及带有WINVER和_WIN32_WINNT >= 0x0500编译时,为这个成员使用OPENFILENAME_SIZE_VERSION_400。

Windows 2000及更高版本:这个参数使用sizeof (OPENFILENAME) 。

hwndOwner
指向所有者对话框窗口的句柄。这个成员可以是任意有效窗口句柄,或如果对话框没有所有者它可以为NULL。
hInstance
如果在Flags成员中设置了OFN_ENABLETEMPLATEHANDLE标记,hInstance成 员指向包含一个对话框模板的内存对象。如果OFN_ENABLETEMPLATE标记被设置,hInstance是一个指向通过lpTemplateName成 员命名的对话框模板的模块。如果两者都没有被设置,这个成员被忽略。

如果OFN_EXPLORER标记被设置,系统使用Explorer风格的默认对话框的子窗口作为指定模板来建立一个对话框。如果 OFN_EXPLORER标记没有被设置,系统使用模板建立一个旧风格的对话框。

lpstrFilter
指向一对以空字符结束的过滤字符串的一个缓冲。缓冲中的最后一个字符串必须以两个NULL字符结束。

第一个字符串是过滤器描述的显示字符串(例如,“文本文件”),第二个字符指定过滤样式(例如,“*.TXT”)。要为一个显示字符串指定多个过滤 样式,使用分号(“;”)分隔样式(例如,“*.TXT;*.DOC;*.BAK”)。一个样式字符串中可以包含有效的文件名字字符及星号(*)通配符。 不能在样式字符串中包含空格。

系统不能改变过滤器的次序。它按lpstrFilter指定的次序显示在文件类型组合框中。

如果lpstrFilter是NULL,对话框不能显示任何过滤器。

lpstrCustomFilter
指向一个静态缓冲,它包含了一对以空字符结束的过滤器字符串,这个字符串是为了保留用户选择的过滤样式。第一个字符串是描述定制过滤器 的显示字符串,第二个字符串是被用户选择的过滤器样式。第一次你的应用程序建立对话框,你指定的第一个字符串可以是任何非空的字符串。当用户选择了一个文 件时,对话框复制当前过滤样式到第二个字符串。保留过滤样式可以是在lpstrFilter缓冲中指定的样式之一,或是用户输入的过滤器样 式。在下一次对话框被建立时系统使用这个字符串去初始化用户自定义的文件过滤器。如果nFilterIndex成员是0,对话框使用定制过 滤器。

如果这个成员是NULL,对话框不能保留用户自定义过滤器样式。

如果这个成员不是NULL,nMaxCustFilter成员的值必须指定以TCHARs为单位的lpstrCustomFilter缓 冲的大小。对于ANSI版本,是字节的个数;对于Unicode版本,是字符的个数。

nMaxCustFilter
指定特意为lpstrCustomFilter准备的以TCHARs为单位的缓冲大小。对于ANSI版 本,是字节的个数;对于Unicode版本,是字符的个数。这缓冲应该最小在40个字符长。如果lpstrCustomFilter成员是 NULL或是指向NULL的字符串,这个成员被忽略。
nFilterIndex
指定在文件类型控件中当前选择的过滤器的索引。缓冲指向被lpstrFilter包含的一对定义了的过滤器的字符串。过 滤器的第一对字符串的索引值为1,第二对为2,等等。0索引指出是通过lpstrCustomFilter指定的定制过滤器。你可以为对话 框指定一个索引作为最初的过滤器描述及过滤器样式。当用户选择了一个文件时,nFilterIndex返回当前显示的过滤器的索引。

如果nFilterIndex是0及lpstrCustomFilter是NULL,系统使用在lpstrFilter缓 冲中的第一个过滤器。如果所有的三个成员都是0或NULL,系统不使用任何过滤器,在对话框的列表文件中不显示任何文件。

lpstrFile
指向包含初始化文件名编辑控件使用的文件名的缓冲。如果不需要初始值,这个缓冲的第一个字符必须是NULL。当 GetOpenFileName或 GetSaveFileName函 数返回成功时,这个缓冲包含驱动器,路径,文件名,及所选择的文件的扩展名。

如果OFN_ALLOWMULTISELECT标记被设置并且用户选择了多个文件,缓冲包含了当前目录下被选择文件的文件名。对于Explorer 风格对话框,目录和文件名字符串是被NULL分开的,在文件名之后有一个额外的NULL。对于旧风格对话框,字符串是被空格分开的并且函数为带有空格的文 件名使用短文件名。你可以使用FindFirstFile函 数在长短文件名之间转换。如果用户只选择了一个文件,lpstrFile字符串在路径和文件名之间没有分隔。

如果缓冲太小,函数返回FALSE并且CommDlgExtendedError函 数返回FNERR_BUFFERTOOSMALL.。既然这样,lpstrFile缓冲的首先两个字节包含必需的大小(字节或字符)。

nMaxFile
指定lpstrFile缓冲的大小,以TCHARs为单位。对于ANSI版本,是字节的个数;对于 Unicode版本,是字符的个数。这个缓冲必须足够存储路径和文件名字符串,包含结尾的null字符。如果缓冲太小,GetOpenFileName和GetSaveFileName函 数返回假(FALSE)缓冲最小应该在256个字符长。
lpstrFileTitle
指向接收选择的文件的文件名和扩展名的缓冲(不带路径信息)。这个成员可以是NULL。
nMaxFileTitle
指定lpstrFileTitle缓冲的大小,以TCHARs为单位。对于ANSI版本,是字节的个数; 对于Unicode版本,是字节的个数。如果lpstrFileTitle是NULL,这个成员被忽略。
lpstrInitialDir
指向以空字符结束的字符串,可以在这个字符串中指定初始目录。Pointer to a null terminated string that can specify the initial directory. 在不同的平台上,为选择初始目录有不同的运算法则。

Windows 2000:

  1. 如果lpstrFile包含了一个路径,这个路径就是初始目录。
  2. 否则,lpstrInitialDir指定的为初始目录。
  3. 如果lpstrInitialDir为NULL,并且当前目录下包含有一些指定过滤器类型的文件,初始目录就是当前目 录。
  4. 否则,如果应用程序在过去使用过打开哐另存为对话框,使用最近选择的路径作为初始目录。然而,如果一个应用程序长时间没有运行过,它保 存的选择的路径将被丢弃。
  5. 否则,初始目录是当前用户的私人文件目录(即我的文档)。
  6. 否则,初始目录是桌面文件夹。

Windows 98:

  1. lpstrInitialDir指定初始目录。
  2. 如果lpstrInitialDir是NULL并且lpstrFile包含了一个路径,那么这个路径就是 初始目录。
  3. 否则,如果当前目录包含了一些指定的过滤类型的文件,那么初始化目录是当前目录。
  4. 否则,初始目录是当前用户的私人文件目录(即我的文档)。

Windows和Windows NT/ 2000的早期版本:

  1. lpstrInitialDir指定初始目录。
  2. 如果lpstrInitialDir是NULL并且lpstrFile包含了一个路径,那么这个路径就是 初始目录。
  3. 否则,初始目录是当前目录。
lpstrTitle
指向在对话框的标题栏中放置的字符串。如果这个成员是NULL,系统使用默认标题(另存为或打开)
Flags
位标记的设置,你可以使用来初始化对话框。当对话框返回时,它设置的这些标记指出用户的输入。这个成员可以是下列标记的组合。
标记含意
OFN_ALLOWMULTISELECT指定文件名列表框允许多选。如果同时你设置了OFN_EXPLORER标记,对话框使用Explorer风格用户界面; 否则它使用旧风格用户界面。

如果用户选择了一个以上的文件,lpstrFile缓冲返回当前目录下所有被选择的文件的文件名。nFileOffset成 员是到第一个文件名的偏移量(字节或字符),并且nFileExtension成员不被使用。对于Explorer风格对话框,目录和文件 名是被NULL分隔的,在最后的文件名后带有额外的NULL。这个格式使Explorer风格的对话框能返回包含空格的长文件名。对于旧风格对话框,目录 和文件字符串是被空格分隔的,函数为带有空格的文件名使用短文件名。你可以使用FindFirstFile函数在短文件名和长文件名之间 转换。

如果你为一个旧风格对话框指定了一个定制的模板,文件名列表框的定义必须包含LBS_EXTENDEDSEL值。

OFN_CREATEPROMPT如果用户指定了一个不存在的文件,这个标记使用对话框能提示用户是否新建这个文件。如果用户选择了新建这个文件,对话框 关闭并且函数返回指定的名字;否则,对话框继续停留。如果你使用带有OFN_ALLOWMULTISELECT标记的这个标记,对话框允许用户去指定一个 不存在的文件。
OFN_DONTADDTORECENTWindows 2000:防止系统为选择的文件增加快捷链接到最近使用文档中。要找回目录的位置,调用 还有CSIDL_RECENT标记的SHGetSpecialFolderLocation函 数。
OFN_ENABLEHOOK激活在lpfnHook成员中指定的钩子函数。
OFN_ENABLEINCLUDENOTIFYWindows 2000:当用户打开一个文件夹时,引起对话框发送CDN_INCLUDEITEM通 知消息到你的OFNHookProc程 序。对话框为在最近打开的文件夹中的每一个项目发送一个通知。这些消息使你能够控制那些在对话框中显示的文件夹项目的列表。
OFN_ENABLESIZINGWindows 2000,Windows 98:使Explorer风格的对话框可以使用鼠标或键盘调 整大小。缺省时,Explorer风格的打开和另存为对话框允许被调整大小,不顾这个标记是否被设置。这标记仅在你提供了一个钩子程序或定制模板时是必需 的。旧风格的对话框不允许调整大小。
OFN_ENABLETEMPLATE指出lpTemplateName成员是指向对话框模板资源的名字,这个模板资源在能被hInstance成 员识别的模块中。

如果OFN_EXPLORER标记被设置,系统使用指定的模板去建立一个对话框,是默认Explorer风格对话框的子窗口。如果 OFN_EXPLORER标记没有被设置,系统使用旧风格的对话框替代默认的对话框。

OFN_ENABLETEMPLATEHANDLE指出hInstance成员能识别的包含预载对话框模板的数据块。如果这个标记被指定的,系统忽略lpTemplateName。

如果OFN_EXPLORER标记被设置,系统使用指定的模板去建立一个对话框,是默认Explorer风格对话框的子窗口。如果 OFN_EXPLORER标记没有被设置,系统使用模板去建立一个旧风格对话框替代默认对话框。

OFN_EXPLORER指出任何打开或另存为对话框使用新的Explorer风格的用户化模块。关于更多的信息,参见Explorer-Style. Hook Procedures和Explorer-Style. Custom Templates。

缺省下,打开和另存为对话框使用Explorer风格用户界面,不顾这个标记是否设置。这个标记仅在你提供了一个钩子程序或定制模板或设置了 OFN_ALLOWMULTISELECT标记时是必需的。

如果你想使用旧风格的界面,省略OFN_EXPLORER 标记,并且提供一个代替的旧风格模板或钩子程序。如果你想用旧风格但不需要一个定制模板或钩子程序,简单的提供一个钩子程序,让它返回FALSE。

OFN_EXTENSIONDIFFERENT指定用户输入的一个文件的扩展名与lpstrDefExt指定的扩展名不同。如果lpstrDefExt是 NULL,函数不使用这个标记。
OFN_FILEMUSTEXIST指定用户仅可以在文件名登录字段中输入已存在的文件的名字。如果这个标记被指定的并且用户输入了一个无效的名字,对话框 程序显示一个等待消息框。如果这个标记被指定,OFN_PATHMUSTEXIST标记也被使用。
OFN_FORCESHOWHIDDENWindows 2000:强制显示系统和隐藏属性的文件,从而压倒用户设置的显示或不显示隐藏文件。否 则,带有系统和隐藏标记的文件不被显示。
OFN_HIDEREADONLY隐藏只读复选框。
OFN_LONGNAMES对于旧风格对话框,这个标记引起对话框使用长文件名。如果这个标记没有被指定,或如果 OFN_ALLOWMULTISELECT标记也被设置,旧风格对话框为带有空格的文件名使用短文件名(8.3格式)。

Explorer风格对话框忽略这个标记,通常显示长文件名。

OFN_NOCHANGEDIR如果当搜索文件时用户改变了目录的时候,恢复当前目录到它的初始值。
OFN_NODEREFERENCELINKS引导对话框为选择的快捷方式(.LNK)文件返回路径和文件名。如果这个值没有被指定,对话框返回这个快捷方式所引用文 件的路径和文件名。
OFN_NOLONGNAMES对于旧风格对话框,这个标识引起对话框去使用短文件名(8.3格式)。

Explorer风格对话框忽略这个标记,通常显示长文件名。

OFN_NONETWORKBUTTON隐藏和显示风格按钮。
OFN_NOREADONLYRETURN指定返回的文件不带有只读复选框,不是在写保护的目录中。
OFN_NOTESTFILECREATE指定文件不是在对话框关闭前建立的。如果应用程序保存文件到一个建立的非映象风格共享上,这个标记应该被指定的。当一个 应用程序指定了这标记,库不能检查写保护,磁盘满,打开驱动器门或网络保护。应用程序使用这个标记必须小心执行文件操作,因为一旦文件被关闭,它不能重新 打开。
OFN_NOVALIDATE指定公共对话框允许在返回的文件名中有无效的字符。典型的,正在调用的程序使用一个钩子程序通过FILEOKSTRING消 息检查文件名。如果在编辑控件中的文本框是空的或只包含了空格,那么文件和目录列表框是被更新的。如果编辑控件中的文本框包含了别的东西,那么nFileOffset 和nFileExtension的设置值是通过分析文本产生的。没有默认的扩展名被添加到文本,也没有文本被复制到lpstrFileTitle指 定的缓冲。

如果通过nFileOffset指定的值比0小,文件是无效的。否则,文件名是有效的。如果OFN_NOVALIDATE没有被指 定,nFileExtension和nFileOffset可以被使用。

OFN_OVERWRITEPROMPT如果选择的文件已经存在,使用另存为对话框产生一个消息框。用户必须确认是否复盖这个文件。
OFN_PATHMUSTEXIST指定用户仅能输入的路径和文件名。如果这个标记被使用并且用户在文件名输入字段中键入了一个用效的路径和文件名,对话框 函数显示一个等待消息。
OFN_READONLY当对话框建立时,显示被选择的只读复选框。这个标记指出当对话框被关闭时只读复选框的状态。
OFN_SHAREAWARE指出如果调用OpenFile函 数因为网络共享冲突而失败,这个错误被忽略并且对话框返回选择的文件名。

如果这个标记没有被设置,当用户选择的文件名发生网络共享冲突时,对话框发送通知到你的钩子程序。如果你设置了OFN_EXPLORER标记,对话 框发送CDN_SHAREVIOLATION消 息到钩子程序。如果你没有设置OFN_EXPLORER,对话框发送SHAREVISTRING注 册的消息到钩子程序。

OFN_SHOWHELP使对话框显示帮助按钮。hwndOwner成员必须指定一个窗口,这个窗口作为接收对话框发送的HELPMSGSTRING注 册的消息,当用户单击帮助按钮时对话框发送这个消息。

当用户单击帮助按钮时,一个Explorer风格的对话框发送CDN_HELP通 知消息到你的钩子程序。

nFileOffset
指定从路径开始到通过lpstrFile指定的文件名字符串基于0的偏移,以TCHARs为单位。对于 ANSI版本,是字节的个数;对于Unicode版本,是字符的个数。例如,如果lpstrFile指向下列的字符串,“c:\dir1 \dir2\file.ext”,这个成员包含指出“file.ext”字符串偏移的位置值13。

如果用户选择了多于一个的文件,nFileOffset是到第一个文件名的偏移。

nFileExtension
指定从路径开始到通过lpstrFile指定的文件名字符串中扩展名基于0的偏移,以TCHARs为单 位。对于ANSI版本,是字节的个数;对于Unicode版本,是字节的个数。例如,如果lpstrFile指向下列的字符 串,“c:\dir1\dir2\file.ext”,这个成员包含的值是18。如果用户没有输入一个扩展名并且lpstrDefExt是 NULL,这个成员指定的偏移是结束字符NULL。如果用户在文件名中输入一个“.”作为最后的字符,这个成员是0。
lpstrDefExt
指向包含默认扩展名的缓冲。如果用户忘记输入扩展名, GetOpenFileName和 GetSaveFileName附 加这个扩展名到文件名中。这个字符串可以是任一长度,但但只有头三个字符被附加。字符串不应该包含一个句点(.)。如果这个成员是NULL并且用户忘记了 输入一个扩展名,那么将没有扩展名被附加。
lCustData
指定应用程序定义的数据,这数据是能被lpfnHook成员识别的系统传到的钩子程序。当系统发送 WM_INITDIALOG消 息到程序,消息的lParam参数指向当对话框建立时指定的OPENFILENAME结构。钩子程序可以使用这个指针获得lCustData的 值。
lpfnHook
指向一个钩子程序。除非Flags成员中包含OFN_ENABLEHOOK标记,要么这个成员将被忽略。

如果在Flags成员中OFN_EXPLORER标记没有被设置,lpfnHook指向一个OFNHookProcOldStyle钩 子程序,这个程序有意的从对话框接收消息。钩子程序返回FALSE传递一个消息到默认的对话框程序或返回TRUE丢弃消息。

如果OFN_EXPLORER被设置,lpfnHook指向一个OFNHookProc钩 子程序。这个钩子程序接收从对话框发出的通知消息。这个钩子程序也接收你通过一个子对话框模板定义的附加控件的消息。钩子程序不有意接收默认对话框的标准 控件的消息。

lpTemplateName
指向一个以空字符结束的字符串,字符串是对话框模板资源的名字,资源保存在能被hInstance成员识别的模块中。对 于有限的对话框资源,这可以是通过 MAKEINTRESOURCE返 回的值。除非在Flags成员中设置了OFN_ENABLETEMPLATE标记,要么这个成员被忽略。

如果OFN_EXPLORER标记被设置,系统使用指定的模板去建立一个对话框,是默认Explorer风格对话框的子窗口。如果 OFN_EXPLORER标记没有被设置,系统使用模板去建立一个旧风格的对话框来替代默认对话框。

pvReserved
保留。
dwReserved
保留。
FlagsEx
Windows 2000:设置位标记,你可以使用来初始化对话框。这个成员可以是下列标记的组合。
标记含意
OFN_EX_NOPLACESBAR如果这个标记被设置,则位置栏被不显示。如果这个标记没有设置,则Explorer风格的对话框包含一般使用文件图标的 位置栏,例如像收藏夹和桌面。

=================================================================================这里是分割线=================================================================================================

好,那研究完文档我就有点思路了,关注其中的lpstrFile字段,解释为:如果OFN_ALLOWMULTISELECT标记被设置并且用户选择了多个文件,缓冲包含了当前目录下被选择文件的文件名。对于Explorer 风格对话框,目录和文件名字符串是被NULL分开的,在文件名之后有一个额外的NULL。对于旧风格对话框,字符串是被空格分开的并且函数为带有空格的文 件名使用短文件名。你可以使用FindFirstFile函 数在长短文件名之间转换。如果用户只选择了一个文件,lpstrFile字符串在路径和文件名之间没有分隔。既然是用Null风格,那对于C#中的String在将字符转换为String时是否在转换的时候默认读到Null就认为是字符串结束,之后返回转换后的字符串呢?这样剩下的数据就丢失了,为了验证这个猜测,我们将ofn.flags进行些许修改,如下

//0x00080000 | ==  OFN_EXPLORER |对于旧风格对话框,目录 和文件字符串是被空格分隔的,函数为带有空格的文件名使用短文件名
//注意 一下项目不一定要全选 但是0x00000008项不要缺少
ofn.flags = 0x00001000 | 0x00000800 | 0x00000200 | 0x00000008; //OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST| OFN_ALLOWMULTISELECT|OFN_NOCHANGEDIR

这样的话就调用了旧风格的对话框,返回的是被空格分开的文件名,没有Null字符不会被String强行结束,再次尝试后果然如我所料~成功解决问题,但是文件名需要进行处理,可以用上述的FindFirstFile函数,也能自己写一个,我就自己写了一个,一起放出来了,大家拿去随便用~

 //短文件名和长文件名之间 转换。
    public string[] ParseFilePaths(string longFilePath)
    {
        string[] paths = longFilePath.Split(' ');
        string[] filepaths = null;
        if (paths.Length > 1)
        {
            filepaths = new string[paths.Length - 1];
            string prefixStr = paths[0];
            for (int i = 1; i < paths.Length; i++)
            {
                filepaths[i - 1] = prefixStr + paths[i];
            }

            return filepaths;
        }
        else
        {
            filepaths = new string[paths.Length];
            filepaths[0] = longFilePath;
            return filepaths;
        }
    }

参考文档:https://www.cnblogs.com/U-tansuo/archive/2012/07/10/GetOpenFileName.html

     https://blog.csdn.net/u012194027/article/details/39968009

     https://docs.microsoft.com/en-us/windows/win32/api/commdlg/nf-commdlg-getopenfilenamea

转载于:https://www.cnblogs.com/moran-amos/p/11342095.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值