使用GetOpenFileName而不是OpenFileDialog

本文关键字:OpenFileDialog GetOpenFileName 使用 | 更新日期: 2023-09-27 18:22:07

我无法在应用程序中使用OpenFileDialog。

作为替代方案,我使用GetOpenFileName()方法:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace Reader
{
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    public class OpenFileName
    {
        public int lstructSize;
        public IntPtr hwndOwner;
        public IntPtr hInstance;
        public string lpstrFilter = null;
        public string lpstrCustomFilter = null;
        public int lMaxCustomFilter;
        public int lFilterIndex;
        public string lpstrFile = null;
        public int lMaxFile = 0;
        public string lpstrFileTitle = null;
        public int lMaxFileTitle = 0;
        public string lpstrInitialDir = null;
        public string lpstrTitle = null;
        public int lFlags;
        public ushort nFileOffset;
        public ushort nFileExtension;
        public string lpstrDefExt = null;
        public int lCustData;
        public int lpfHook;
        public int lpTemplateName;
    }
    public class OpenDialog
    {
        [DllImport("Comdlg32.dll",CharSet = CharSet.Auto)]
        public static extern bool GetOpenFileName([In, Out] OpenFileName ofn);
    }
}

然后在像这样的按钮的OnClick事件中使用它:

OpenFileName qofn = new OpenFileName();
qofn.lstructSize = Marshal.SizeOf(qofn);
qofn.lpstrFile = "";
qofn.lMaxFile = 256;
qofn.lpstrFileTitle = "";
qofn.lMaxFileTitle = 64;
qofn.hInstance = this.Handle;
source.Text = "Wait...";
if (OpenDialog.GetOpenFileName(qofn))
{
    MessageBox.Show("ofn.file: " + qofn. lpstrFile );
}

当应用程序运行并点击按钮时,我试图打开文件,这就是发生的事情:

第一次尝试:

它返回我的文件的路径,但不是c: ''dira''dirb''dirc''filename.ext我有c: ''dira''dirb''dircfilename.ext文件名前没有"''"

第二次尝试

一切正常

下一个:存在随机崩溃,例如随机访问违规,或者GUI冻结,应用程序的进程甚至在任务管理器中也无法正常运行,或者其他错误。

通常对话框在应用程序崩溃之前工作2-3次。

我的代码出了什么问题?

编辑:

我无法使用OpenFileDialog。我使用的是WinPE 4.0(Windows评估和部署工具包ADK)。当我尝试OpenFileDIalog时,它会抛出运行时错误80040111。这可能是因为核心不受支持(就像服务器核心不支持OpenFileDialog一样,错误也是一样的)。可能在WinPE 4.0上,他们在记事本等应用程序中使用GetOpenFileName。它对他们有效。

使用GetOpenFileName而不是OpenFileDialog

好的,我找到了这个微软的样本,它可以工作:

// Copyright
// Microsoft Corporation
// All rights reserved
// OpenFileDlg.cs
using System;
using System.Text;
using System.Runtime.InteropServices;
/*
typedef struct tagOFN { 
  DWORD         lStructSize; 
  HWND          hwndOwner; 
  HINSTANCE     hInstance; 
  LPCTSTR       lpstrFilter; 
  LPTSTR        lpstrCustomFilter; 
  DWORD         nMaxCustFilter; 
  DWORD         nFilterIndex; 
  LPTSTR        lpstrFile; 
  DWORD         nMaxFile; 
  LPTSTR        lpstrFileTitle; 
  DWORD         nMaxFileTitle; 
  LPCTSTR       lpstrInitialDir; 
  LPCTSTR       lpstrTitle; 
  DWORD         Flags; 
  WORD          nFileOffset; 
  WORD          nFileExtension; 
  LPCTSTR       lpstrDefExt; 
  LPARAM        lCustData; 
  LPOFNHOOKPROC lpfnHook; 
  LPCTSTR       lpTemplateName; 
#if (_WIN32_WINNT >= 0x0500)
  void *        pvReserved;
  DWORD         dwReserved;
  DWORD         FlagsEx;
#endif // (_WIN32_WINNT >= 0x0500)
} OPENFILENAME, *LPOPENFILENAME; 
*/
[ 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 LibWrap
{
    //BOOL GetOpenFileName(LPOPENFILENAME lpofn);
    [ DllImport( "Comdlg32.dll", CharSet=CharSet.Auto )]                
    public static extern bool GetOpenFileName([ In, Out ] OpenFileName ofn );   
}
public class App
{
    public static void Main()
    {
        OpenFileName ofn = new OpenFileName();
        ofn.structSize = Marshal.SizeOf( ofn );
        ofn.filter = "Log files'0*.log'0Batch files'0*.bat'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 = "C:''";
        ofn.title = "Open file called using platform invoke...";
        ofn.defExt = "txt";
        if( LibWrap.GetOpenFileName( ofn ))
        {
            Console.WriteLine( "Selected file with full path: {0}", ofn.file );
            Console.WriteLine( "Selected file name: {0}", ofn.fileTitle );
            Console.WriteLine( "Offset from file name: {0}", ofn.fileOffset );
            Console.WriteLine( "Offset from file extension: {0}", ofn.fileExtension );
        }
    }
}

OpenFileDlg示例(如Arie的答案中使用的示例)在这里可用。

该页面有C#、C++和VB示例。我已经在WinPE 5.1中测试了VB的例子,除了文件类型过滤器之外,它运行得很好;它始终显示所有文件类型。

我惊讶地发现,即使在我的WinPE映像中安装了WinPE NetFX包,OpenFileDialog在WinPE中也不可用,尝试使用它会引发问题中提到的错误。这些使用非托管GetOpenFileName函数的OpenFileDlg示例是我能在WinPE中找到的唯一可供使用的替代方法。