我有一个使用DefineDosDevice函数创buildDOS设备的本地系统帐户下运行的Windows服务。 该服务正在W2K8远程桌面服务器上运行。 如果设备是使用服务凭证创build的,则它们将在GLOBAL设备名称空间中创build,因此可供所有用户看到。 我需要这些设备只对特定的交互会话可见。
我通过模仿在其会话中希望驱动器出现的用户来实现这一点。 这是非常简单的,只要会话ID是可用的。 下面是我写的一个简单的testing应用程序来说明问题:
int _tmain(int argc, _TCHAR* argv[]) { BOOL result = TRUE; if(argc > 3 && !wcscmp(argv[2], L"/i")) { HANDLE hToken = 0; DWORD dwSessionId = _wtoi(argv[3]); result = WTSQueryUserToken(dwSessionId, &hToken); if(result) result = ImpersonateLoggedOnUser(hToken); } if(result) { LPTSTR drive = argv[1]; DefineDosDevice(DDD_REMOVE_DEFINITION, drive, NULL); result = DefineDosDevice(0, drive, L"C:\\test"); } if(!result) { printf("Error: %d\n", GetLastError()); } return 0; }
为了testing这段代码,我创build了一个在LocalSystem帐户下启动一个命令shell的服务:
sc创buildtest_svc binpath =“cmd / K start”type = own type = interact
此服务无法启动,但在失败之前,它会生成一个在LocalSystem帐户下运行的命令shell。
从LocalSystem cmd.exe运行:
MySubst.exe x:/我2
调用ImpersonateLoggedOnUser(),然后调用DefineDosDevice()
从运行在用户会话中的cmd.exe运行:
MySubst.exe y:
其中调用DefineDosDevice 而不调用ImpersonateLoggedOnUser()。
这工作。 从cmd.exe我可以访问两个驱动器X:和Y :. 我可以从开始菜单启动notepad.exe,并查看X:和Y:驱动器。 此外,如果我用不同的用户创build一个新的terminal服务会话,我不会看到X:或Y :.
但是,资源pipe理器只显示“所有计算机”下的Y:驱动器。 Y:是通过在目标会话中运行cmd.exe运行我的testing应用程序而创build的驱动器,即未完成模拟。 如果我从任务pipe理器重新启动explorer.exe,则显示X:和Y:驱动器。
我也使用SysInternals中的WinObj.exe来检查定义的Win NT设备。 我所看到的是:
- Sessions - 0 - DosDevices 00000000-000057607
(57607是与我正在冒充的会话关联的login会话的ID)
“00000000-000057607”的内容是:
Global SymbolicLink \Global?? X: SymbolicLink \\??\C:\test Y: SymbolicLink \\??\C:\test
根据WinObj,这两个DOS设备是相同的。 它们属于同一个会话和login会话。 它们是相同的NT对象的符号链接。
怎么可能是其中一个出现在资源pipe理器中,另一个则不是。
@arx和@HarryJohnston是在钱上。 如果我从与explorer相同的会话中的线程广播WM_DEVICECHANGE消息,则新驱动器出现在“我的电脑”中。 代码如下:
DWORD recipients = BSM_ALLDESKTOPS | BSM_APPLICATIONS; DEV_BROADCAST_VOLUME msg; ZeroMemory(&msg, sizeof(msg)); msg.dbcv_size = sizeof(msg); msg.dbcv_devicetype = DBT_DEVTYP_VOLUME; msg.dbcv_unitmask = 1 << ('X' - 'A'); long success = BroadcastSystemMessage(0, &recipients, WM_DEVICECHANGE, DBT_DEVICEARRIVAL, (LPARAM)&msg);