警惕使用System.Environment.CurrentDirectory遇到的坑

警惕使用System.Environment.CurrentDirectory遇到的坑

430发表于2020-03-18

今天调试程序的时候遇到一个大坑,程序A(exe)通过Process Start启动程序B(exe)进程,总是报错。

from clipboard

上图是程序结构,为了让所有的程序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文件中。



小编蓝狐