【问题标题】:SaveFileDialog fails to return in Windows XPSaveFileDialog 在 Windows XP 中无法返回
【发布时间】:2012-01-19 11:39:55
【问题描述】:

我在 Windows 7 上使用 Winforms,在 Visual Studio 2010 中使用 C#。 目前在 Windows 7 中,安装和调试器都可以使用以下代码。但是,当程序安装在 Windows XP 中时,永远不会到达最后一行。

此代码从 MenuStrip 调用,然后传递给后续方法以根据在菜单中单击的项目执行操作。但是,这不是 SaveFileDialog 失败的唯一地方,它总是在 ShowDialog() 方法上失败。

MenuItem 的代码:

            private void saveOnlyPlaylistToolStripMenuItem_Click(object sender, EventArgs e)
            {
                try
                {
                    MainMenuClick(sender, e);
                }
                catch (Exception ex)
                {
                    StackTrace st = new StackTrace();
                    string methodName = st.GetFrame(1).GetMethod().Name;
                    Logger.LogToFile("Failure in " + methodName + ": " + ex.Message);
                }
            }

失败的代码:

            Logger.LogToFile("Entered Save Only Playlist.");
            SaveFileDialog sfd = new SaveFileDialog();
            string playlistSaveLocation = config["PlaylistLocation"];
            if (!Directory.Exists(playlistSaveLocation))
                Directory.CreateDirectory(playlistSaveLocation);
            sfd.InitialDirectory = playlistSaveLocation;
            sfd.Filter = "L Playlist (*.lpl)|*.lpl";

            DialogResult result = sfd.ShowDialog();
            Logger.LogToFile("Result of Dialog: " + result.ToString());

我不知道为什么最后一行没有被调用,感觉 SaveFileDialog 的 ShowDialog() 方法没有完成。之后程序继续正常运行,但不再与文件目录交互,无法创建新进程。

调试器中没有错误,事件日志也没有。我已经使用 Visual Studio 2010 在 Windows XP 上对其进行了重建,并且运行良好,该错误似乎仅在该程序在 Windows 7 中创建然后安装在 Windows XP 上时出现。 Windows 7 是 64 位。

我应该注意,我从 Debug -> Exceptions 抛出了所有异常。

我已经四处搜索,似乎没有很多像 SaveFileDialog 这样的基本方法失败的案例,关于可能导致此问题的任何想法?


基于以下答案的进一步分析使我相信这可能与调用 SaveFileDialog 的方式有关。由于这是从 MenuStrip 调用的,我相信它会作为一个单独的线程出现。这可能是 ShowDialog() 方法永远不会返回的原因,但我无法确定为什么会这样。为了找到问题,我创建了一个单独的窗口窗体,它什么都不做,只是有一个按钮来打开一个保存文件对话框。此按钮有效,并正确返回,但在将控制权返回给原始线程后,它似乎再次失败。这一切都基于我为调试目的而放置的日志记录。

记录代码:

            public static void LogToFile(string message, FileInfo fInfo)
            {
                try
                {
                    if (!fInfo.Exists)
                        using (FileStream fs = fInfo.Create()) ;

                    message = DateTime.Now.ToString("yyyy-MM-dd hh-mm-ss") + ": " + message;

                    File.AppendAllText(fInfo.FullName, message + "\n");
                }
                catch (Exception ex)
                {
                    StackTrace st = new StackTrace();
                    string methodName = st.GetFrame(1).GetMethod().Name;
                    MessageBox.Show("Failure in " + methodName + ": " + ex.Message);
                }
            }

附加窗口的代码:

            public partial class Buffer : Form
            {
                public Buffer()
                {
                    InitializeComponent();
                }

                private void Buffer_Load(object sender, EventArgs e)
                {
                    Logger.LogToFile("Entered Save Only Playlist.");
                    SaveFileDialog sfd = new SaveFileDialog();
                    sfd.Filter = "Playlist (*.lpl)|*.lpl";
                    DialogResult result = System.Windows.Forms.DialogResult.Cancel;
                    try
                    {
                        result = sfd.ShowDialog();
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show("Dialog problem: " + ex.Message);
                    }
                    Logger.LogToFile("Result of Dialog: " + result.ToString());
                    MessageBox.Show("Result of Dialog: " + result.ToString());
                    DialogResult = result;
                }
            }

上面的代码有效,MessageBox.Show() 实际显示了对话框结果。

【问题讨论】:

  • 普通对话框使用 COM,如果您不在单线程单元中,它们会以各种奇怪的方式运行。您的 Main 方法中有 [STAThread] 属性吗?
  • 嘿乔,是的,我的主线程上有 [STAThread]:[STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(新 frmLTSBC()); }
  • 如果注释掉“string playlistSaveLocation...”行和接下来的两行会发生什么? Win7电脑上playlistSaveLocation的值是多少?可能是 UAC 安全性受到干扰。
  • 我实际上已经尝试注释掉 DialogResult result = sfd.ShowDialog() 之前的所有代码,以查看这是否是问题所在。注释掉这些行没有效果,在 Windows 7 和 Windows XP 中 playlistSaveLocation 的值都是 C:\bin\Playlist\
  • shell 对话框,如 SaveFileDialog,允许将 shell 扩展加载到您的进程中。当您打开非托管调试时,您可以在“输出”窗口中看到它们正在加载。那台 XP 机器可能有一个与您的程序或对话框混淆的机器。使用 SysInternals 的 AutoRuns 实用程序将其关闭。

标签: c# visual-studio-2010 windows-7 windows-xp savefiledialog


【解决方案1】:

一般来说,当我遇到这种情况时,我发现我的catch 函数的catch 例程又抛出了一个异常。

试试这个,看看是否有帮助:

private void saveOnlyPlaylistToolStripMenuItem_Click(object sender, EventArgs e) {
  StackTrace st = null;
  string message = null;
  try {
    MainMenuClick(sender, e);
  } catch (Exception ex) {
    st = new StackTrace();
    message = ex.Message;
  }
  if (st != null) {
    try {
      string methodName = st.GetFrame(1).GetMethod().Name;
      Logger.LogToFile("Failure in " + methodName + ": " + ex.Message);
    } catch (Exception ex) {
      MessageBox.Show(ex.Message);
    }
  }
}

编辑:

如果你像这样重写你的 Buffer_Load 方法会怎样:

private void Buffer_Load(object sender, EventArgs e)
{
  Logger.LogToFile("Entered Save Only Playlist.");
  DialogResult result = System.Windows.Forms.DialogResult.None;
  using (SaveFileDialog sfd = new SaveFileDialog())
  {
    sfd.Filter = "Playlist (*.lpl)|*.lpl";
    try
    {
      // Add `this`
      result = sfd.ShowDialog(this);
    }
    catch (Exception ex)
    {
      MessageBox.Show("Dialog problem: " + ex.Message);
    }
  }
  Logger.LogToFile("Result of Dialog: " + result.ToString());
  MessageBox.Show("Result of Dialog: " + result.ToString());
  // leave this line out - it would likely close your form:
  // DialogResult = result;
}

this 关键字有时会有所帮助。

【讨论】:

  • 嘿 JP2Code,我尝试了上面的方法,但它没有生成任何额外的信息。代码似乎只是挂在 ShowDialog() 上。对话框打开,用户选择保存位置和文件名,然后单击“确定”,然后失败。如果用户点击取消,一切都会顺利进行。
  • 我也尝试直接向该行添加一个 try catch 循环,但它没有产生任何结果。感觉 ShowDialog 根本没有完成它的工作。 try { result = sfd.ShowDialog(); } catch (Exception ex) { MessageBox.Show("Dialog problem: " + ex.Message); }code
  • 整个 Buffer 表单主要只是一个附加表单,用于尝试将问题分离出来。我开始认为这个问题可能与整个第二段代码的线程化方式有关。例如,保存文件对话框是在 MenuItem 中定义的,这可能意味着单击该菜单项时创建的后台线程实际上对保存文件对话框造成了破坏。我将尝试将 this 关键字添加到几个不同的位置并测试以查看是否可以解决我的问题。
【解决方案2】:

事实证明,这个问题比我最初意识到的要简单。在 Windows XP 中,保存文件或打开文件对话框将更改工作目录并导致程序查找该位置。不幸的是,我没有在我的 Logger 中预料到这一点,因此日志文件正在移动到一个意外的位置。

            Logger.WriteToFile("DEBUG TEXT", "Debug.log");

意识到这一点后,错误很快就从 SaveFileDialog 中消失了,而是通过确保正确引用了我的所有文件来解决。

            string path = Path.Combine(Application.StartupPath, "Debug.log");
            Logger.WriteToFile("DEBUG TEXT", path);

一个简单的问题,尽管在 Windows 7 中 SaveFileDialog 不会永久更改工作目录,这引起了我的困惑。希望这对遇到此问题的其他人有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-29
    • 1970-01-01
    • 2011-02-08
    • 2013-06-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多