距离现在挺久的一件事了,刚好打开csdn刷了会,兴致来了,记录下消遣一下时间。
背景
在实际工作中,负责开发维护一款windows平台的软件,依赖于electron。
有次不知道为啥一个远古遗留问题划给了我:我们的软件,第一次开启后,想导入文件总是看不到共享网盘(偶现)。
定位的过程挺有意思的,虽然最后啥也没能改变,但是还是觉得可以分享一下。
前人栽树
以前的老前辈有遇到过类似的问题,备注过,说是vscode从来没有这个问题;而vscode使用的是更新的electron,所以若想解决此问题,需要更新electron的版本。但是他们在更新electron版本的过程中出现了某些问题,导致这件事被搁置了。
所以,直接用vscode试试,发现果然vscode能看到。
那就去看vscode源码打开文件夹UI时用的接口,调到最后,还是electron的那个接口(electron.dialog.showOpenDialog)。难道果然是electron接口变了,修复了这个“bug”?
想去看electron接口的C++层封装。但是比较新的版本有些难顶,那就曲线救国,找我们软件electron版本所使用的接口,为啥会有问题。
然后,发现electron的打开资源管理器导文件的接口依赖于WTL库,大概是9.1版本,使用了一个windows家的SHBrowseForFolder接口。再想进一步,已经没得源码了。看着msdn上的简单介绍,我已经开始准备放弃了。
不抛弃不放弃
菜比加愣头青的精神,让我在眯了会之后,又振作了起来。
既然都找到接口了,那先试试网盘+SHBrowseForFolder接口放一块搜吧。换了好几个关键字,你还别说,真在程序员的天堂搜到了一些信息:
https://stackoverflow.com/questions/25221546/shbrowseforfolder-not-showing-mapped-drives
OK,新概念,windows的UAC(题外话:windows internals里面的安全章节中有介绍)。
大概就是呢,以管理员权限运行的进程,在使用SHBrowseForFolder接口时,会看不到映射网盘。
而我们工程的electron进程所使用的token间接继承于安装程序,安装程序在安装时获取了管理员权限。
插曲
在此之间,我自己用管理员权限打开过vscode,为啥会没有问题呢?
经过老半天的思索,发现我是在本身已经开了一个vscode窗口的前提下再用管理员权限打开vscode的。在未打开的前提下用管理员权限打开,一样会看不到映射网盘。
不想再确认这些细节了,猜测vscode应该有一个unique的主进程管理渲染进程,若已经存在这个主进程,那开启新窗口的请求会由这个已存在的主进程来处理。
然后还试过html打开资源管理器的原生input标签,也是看不到。
总之,真相大白了。
回到问题
那么,既然是windows的系统机制,有没有办法能实现第一次从安装程序界面打开程序,可以看到映射网盘呢?
理论上是有的,使用管理员权限在windows的进程中找一个普通权限的进程,获取其token,再用这个token打开我们软件。(题外话:官网的archive/codeplex.com/?p=uachelpers现在已经找不到了):
https://github.com/falahati/UACHelper
但是一方面工作量有点大,另一方面不太推荐这种tricky:
https://docs.microsoft.com/zh-cn/archive/blogs/winsdk/dealing-with-administrator-and-standard-users-context
问题是弄清了:
安装程序后,直接在安装程序界面打开软件会复现这个问题;且之后手动使用管理员权限打开软件,也能复现这个问题。
最后呢,啥也没改。
更新:
除了改应用程序,这个问题其实与Windows操作系统的安全策略相关。映射网盘不可见,本质是因为【Mapped drives are not available from an elevated prompt when UAC is configured to Prompt for credentials】:
When UAC is enabled, the system creates two logon sessions at user
logon. Both logon sessions are linked to one another. One session
represents the user during an elevated session, and the other session
where you run under least user rights. When drive mappings are
created, the system creates symbolic link objects (DosDevices) that
associate the drive letters to the UNC paths. These objects are
specific for a logon session and are not shared between logon
sessions.
也就是说,用户态设置的盘符和提权态设置的盘符是不一样的;那么要想让提权态的应用程序也看到,就要在两种权限状态下都设置此盘符。
根据以上微软的官方链接,方法有(第二种已经亲测有用):
1 使用管理员权限的.bat命令再创建一次盘符。
2 注册表增加项:EnableLinkedConnections。