【问题产生】

问题最初是在administrator权限下,visual studio 打开网络磁盘下的文件报错。经过几次调试,最终发现是问题是在管理员权限下,vs无法访问网络磁盘。

Console.Write( System.IO.File.Exists(path));

该结果返回False。为了确认是由于权限问题引起,使用非管理员权限打开vs,运行上面的程序,结果返回True。

至此问题确立:win7/win8下,使用管理员权限打开VisualStudio,无法访问网络磁盘。

【问题分析】

首先让我想到的是很久之前,发现用管理员权限打开VisualStudio后,没办法把文件直接拖拽到VS中打开,我的理解是,管理员权限下的VS比普通文件有更高的“安全级别”,windows不允许从低级别向高级别发送调用命令,事实上也确实如此。

解决方案一:使用系统administrator账户

实验一:

  1. 进入C:\Windows目录
  2. 找到并打开notepad.exe(用户权限)
  3. 拖拽其他文本文件到打开的记事本应用,发现是可以正常打开的,然后关闭所有文件
  4. 右键以管理员权限打开notepad.exe
  5. 再拖拽同样的文本文件到记事本应用,这时候可以看到是没有办法将文件拖拽进来的

知道问题由权限引起,那么接下来就是如何设置权限。


由于VS是管理员权限而其他文件是用户权限,所以考虑使用administrator账户,让所有文件都拥有管理员权限。

  1. 运行lusrmgr.msc
  2. 本地用户和组–用户–administrator–去掉“账号已禁用”的勾,确认退出
  3. 切换用户,使用administrator用户登录

ps:win7家用版没有lusrmgr.msc,开启administrator的方法这里不再细说。

这时候所有文件都拥有管理员权限,测试一下问题,发现可以正常返回True了。但使用Administrator是一种不安全的方式。而且也比较麻烦,所以继续探究解决方案。


解决方案二:干掉UAC

在网上看到一篇论文《Vista系统管理员权限下文件禁止拖拽解决方案》,这和我的问题非常相近,文章提了三点:介绍UIPI,提出修改注册表的方式解决问题,提出使用windows api方式解决问题。

UIPI:User Interface Privilege Isolation(用户界面特权隔离),详细的介绍可以参考微软白皮书,简单来说,它是UAC的核心,做安全权限用的。说到这里,问题更专业化了,MSDN的Blog中有人遇到了同样的问题(Pat’s Windows Development Blog),这里面用专业的术语描述了我最开始的理解:

Lower Privilege Processes Can’t Interfere with Higher Privilege Processes

当然,里面也提出了解决方案:不要使用管理员权限,或者不要开启uac。

实验二:

在UIPI的微软白皮书中提到使用“Process Explorer”查看UIPI,这里也作为一个实验:

  1. 下载Process Explorer
  2. 打开Process Explorer,在GridView的Header上右键,选择Select Columns,勾选Integrity Level
  3. 观察所有应用的UIPI,如果是以普通用户权限打开,那么我们最多能看到Medium的level
  4. 如果用右键管理员打开,所有的UIPI才可以看到

这个实验也说明了低权限不能够访问高权限的问题。


现在回到论文中,里面提到通过修改注册表的方式关闭UIPI:
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Policies\System下的EnableUIPI设置成0

进入注册表编辑器,发现并没有这样一个值,不过却发现了EnableLUA,其实EnableUIPI是visita下的值,而在win7/win8下则是EnableLUA.

EnableLUA的值设成0,重启计算机,然后以管理员权限运行VS,测试问题,结果返回True。其实关闭UAC和使用administrator账户是一样的效果,都是获取了最高权限,但都是不安全的,能不能寻找一个简单又安全的方法来解决问题?

ps:论文中提到的第三点是使用windows api,有兴趣的可以阅读ChangeWindowMessageFilter相关资料,其原理是将拖拽等操作添加到白名单,这样就不会被UIPI拦截。但我们的问题并不是拖拽问题,而是找不到路径,所以这里不再过多讨论。


解决方案三:在管理员权限下配置磁盘映射

经过上面的分析,对UAC逐步有了更深的理解,但想一想,跟UAC扯上关系,不管哪一种方法都麻烦,而且在调试中又发现了下面的问题:

实验三:

  1. 配置一个网络磁盘映射(Z盘)
  2. 用普通用户权限打开记事本或者VS—文件—打开,观察文件资源管理器。这里是可以看到Z盘的。
  3. 用管理员权限打开记事本或者VS—文件—打开,再观察文件资源管理器。发现根本就没有Z盘。

其实问题一开始就走弯路了,难怪System.IO.File.Exists(path)会找不到路径,这里压根就没有Z盘。那我们在这里配置一下网络磁盘映射Y盘:

配置完成后可以看到Y盘了,然后运行一下程序,找找Y盘的路径,结果返回True。然而我们在“我的电脑”中却看不到Y盘,如果以普通用户权限打开文件资源管理器,也看不到Y盘(除非是administrator账户,Z盘Y盘都可见),这么说来,管理员权限和用户权限下的Z盘Y盘就像是在两个世界,这也就是UAC的功能不是么?隔离,sandbox!


【问题总结】

至此所有问题全部解决。解决方法如下:

  1. 使用administrator账户

  2. HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Policies\SystemEnableLUA值改为0,重启即可

  3. 在管理员权限下打开VS或者其他工具,在文件资源管理器中设置网络磁盘映射即可