Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/windows/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Windows 为什么模拟会话中定义的DOS设备不显示在资源管理器中_Windows_Winapi_Impersonation_Remote Desktop_Terminal Services - Fatal编程技术网

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

Windows 为什么模拟会话中定义的DOS设备不显示在资源管理器中,windows,winapi,impersonation,remote-desktop,terminal-services,Windows,Winapi,Impersonation,Remote Desktop,Terminal Services,我有一个在本地系统帐户下运行的Windows服务,它使用DefinedDevice函数创建DOS设备。该服务正在W2K8远程桌面服务器上运行。如果设备是使用服务的凭据创建的,则它们将在全局设备命名空间中创建,因此对所有用户可见。我需要只对特定交互会话可见的设备 我通过模拟希望驱动器出现在其会话中的用户来实现这一点。这相当简单,只要会话id可用。下面是我编写的一个简单的测试应用程序来说明这个问题: int _tmain(int argc, _TCHAR* argv[]) { BOOL result

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

我通过模拟希望驱动器出现在其会话中的用户来实现这一点。这相当简单,只要会话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;
}
为了测试这段代码,我创建了一个服务,在LocalSystem帐户下启动命令shell:

sc create test\u svc binpath=“cmd/K start”type=own type=interact

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

从LocalSystem cmd.exe,我运行:

MySubst.exe x:/i 2

它调用ImpersonalLoggedOnUser(),然后调用DefinedDevice()

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

MySubst.exe y:

调用DefinedDevice而不调用ImpersonalLoggedOnUser()

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

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

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

- Sessions
    - 0
        - DosDevices
            00000000-000057607
(57607是与我正在模拟的会话关联的登录会话的ID)

“00000000-000057607”的内容如下:

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


怎么可能其中一个出现在Explorer中而另一个没有出现呢。

@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);
DWORD recipients=BSM_所有桌面| BSM_应用程序;
开发广播音量信息;
零内存(&msg,sizeof(msg));
msg.dbcv_size=sizeof(msg);
msg.dbcv_devicetype=DBT_DEVTYP_VOLUME;

msg.dbcv_unitmask=1如果强制退出并重新启动资源管理器,它是否会看到驱动器?仅通过模拟可能无法做到这一点。您可能需要在目标上下文中启动一个实际进程来代表您进行更改。@HarryJohnston重新启动资源管理器确实会导致驱动器显示,但我不确定由此得出什么结论。您可能需要向资源管理器发送一条窗口消息,使其查找新的驱动器号。问题是,我不认为您通常可以从系统服务流程中执行此操作。如果用户登录到会话1,您可以使用Windows XP上的交互式服务,但这是一个非常脆弱的解决方案。(另外,我也不知道该发送什么信息,但我相信会有人发送,或者你自己也可以找到它。)正如哈里·约翰斯顿所说,问题几乎肯定是通知。看起来DefinedDevice会为您执行此操作,但在模拟下是否会出错。由于您的进程在错误的会话中运行,因此您自己执行可能是一个挑战。您最好启动一个新进程来创建在正确的终端服务会话中运行的驱动器号。有一些细节。
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);