为什么模拟会话中定义的DOS设备不会出现在资源管理器中

Fis*_*cle 5 windows impersonation winapi remote-desktop terminal-services

我有一个在本地系统帐户下运行的Windows服务,它使用DefineDosDevice函数创建DOS设备.该服务在W2K8远程桌面服务器上运行.如果使用服务的凭据创建设备,则它们将在GLOBAL设备命名空间中创建,因此对所有用户可见.我需要只对特定交互会话可见的设备.

我通过冒充我希望驱动器出现在其会话中的用户来实现此目的.如果会话ID可用,这是相当简单的.这是我编写的一个简单的测试应用程序来说明问题:

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;
}
Run Code Online (Sandbox Code Playgroud)

为了测试这段代码,我创建了一个在LocalSystem帐户下启动命令shell的服务:

sc create test_svc binpath ="cmd/K start"type = own type = interact

此服务无法启动,但在失败之前,它会生成在LocalSystem帐户下运行的命令shell.

从LocalSystem cmd.exe,我运行:

MySubst.exe x:/ i 2

调用ImpersonateLoggedOnUser(),然后调用DefineDosDevice()

从用户会话中运行的cmd.exe,我运行:

MySubst.exe:

它调用DefineDosDevice 而不调用ImpersonateLoggedOnUser().

这有效.从cmd.exe我可以访问两个驱动器X:和Y:.我可以从开始菜单启动notepad.exe,并查看X:和Y:驱动器.此外,如果我与不同的用户创建一个新的终端服务会话,我看不到X:或Y:.

但是,Explorer仅在"所有计算机"下显示Y:驱动器.Y:是通过在目标会话中运行的cmd.exe运行我的测试应用程序创建的驱动器,即未进行模拟.如果我从任务管理器重新启动explorer.exe,则会显示X:和Y:驱动器.

我还使用了SysInternals的WinObj.exe来检查定义的Win NT设备.我看到的是:

- Sessions
    - 0
        - DosDevices
            00000000-000057607
Run Code Online (Sandbox Code Playgroud)

(57607是与我冒充的会话关联的登录会话的ID)

"00000000-000057607"的内容是:

Global    SymbolicLink    \Global??
X:        SymbolicLink    \\??\C:\test
Y:        SymbolicLink    \\??\C:\test
Run Code Online (Sandbox Code Playgroud)

根据WinObj,两个dos设备是相同的.它们属于同一会话和登录会话.它们是同一NT对象的符号链接.

怎么可能是其中一个出现在资源管理器中而另一个不出现.

Fis*_*cle 4

@arx 和@HarryJohnston 很赚钱。如果我从与资源管理器相同的会话中的线程广播 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);
Run Code Online (Sandbox Code Playgroud)