警惕使用System.Environment.CurrentDirectory遇到的坑
今天调试程序的时候遇到一个大坑,程序A(exe)通过Process Start启动程序B(exe)进程,总是报错。
上图是程序结构,为了让所有的程序B实例共享配置,所以把app.ini放在了bin的上级目录。
启动进程代码:
- System.Diagnostics.Process p = new System.Diagnostics.Process();
- p.StartInfo = new ProcessStartInfo(fileName);
- p.Start();
最后定位到配置文件路径读取问题。这是System.Environment.CurrentDirectory遇到大坑。
程序B中有一下代码是用于获取app.ini中的配置:
- DirectoryInfo topDir = Directory.GetParent(System.Environment.CurrentDirectory);
- string iniFileName = Path.Combine(topDir.FullName, "app.ini");
问题症状:
通过程序A启动B,报错。但是通过单独启动程序B正常。
后来发现System.Environment.CurrentDirectory确实是获取当前目录没错,但是如果A程序调用B程序,当B程序里使用了System.Environment.CurrentDirectory获取目录。那么这个B程序里获取的这个目录就不再是B的应用程序所在目录了;而变成了A所在的目录了。
解决方案:
1、使用Application.StartupPath获取目录,需要引用:using System.Windows.Forms,因此这个方法只能用于winform程序。
2、使用AppDomain.CurrentDomain.BaseDirectory,通用方案,可以用于类库。
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
后来发现很多网友和我遇到过一样的问题。
下面引用一下网友写的文章:
https://blog.csdn.net/albert528108/article/details/102958457
- // 获取程序的基目录。
- System.AppDomain.CurrentDomain.BaseDirectory
- // 获取模块的完整路径。
- System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName
- // 获取和设置当前目录(该进程从中启动的目录)的完全限定目录。
- System.Environment.CurrentDirectory
- // 获取应用程序的当前工作目录。
- System.IO.Directory.GetCurrentDirectory()
- // 获取和设置包括该应用程序的目录的名称。
- System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase
- // 获取启动了应用程序的可执行文件的路径。
- System.Windows.Forms.Application.StartupPath
- // 获取启动了应用程序的可执行文件的路径及文件名
- System.Windows.Forms.Application.ExecutablePath
我以前写的代码中获取当前路径基本上都是使用的System.Environment.CurrentDirectory。
但是最近在用另外一个程序A去调用以前的程序B的时候就出现问题了,程序A的作用只是单纯调取程序B的exe文件,在B执行过程中总是真到当前路径这块就出现了问题,实际找到的路径是程序A的路径。
程序A目录:D:\a
程序B目录:D:\b
当程序A调用程序B时,程序B中的Environment.CurrentDirectory结果是D:\a,而不是D:\b!!
经反复测试发现System.Environment.CurrentDirectory确实是获取当前目录没错,但是如果A程序调用B程序 B程序里使用了System.Environment.CurrentDirectory获取目录。那么这个B程序里获取的这个目录就不再是B的应用程序所在目录了;而变成了A所在的目录了。这也就不难发现我在开机时弹出的目录是C:\Windows\System32 因为开机自启动程序也是由windows的某个进程调用的。
当遇到这样的情况时,我自己的解决方案是:
把所有System.Environment.CurrentDirectory改成System.AppDomain.CurrentDomain.BaseDirectory。
网上也有很多人说针对winform可以改成Application.StartupPath。
C# WinForm中AppDomain.CurrentDomain.BaseDirectory与Application.StartupPath的区别示例如下:
1. AppDomain.CurrentDomain.BaseDirectory 返回结果为: D:\xxx\
Application.StartupPath 返回结果为: D:\xxx
2. Application.StartupPath 只能用于WinForm窗体中,而AppDomain.CurrentDomain.BaseDirectory既可以用于WinForm窗体中,也可以用于类库DLL文件中。