枚举WindowStation及其desktop输出如下:
WindowStation0:WinSta0
Desktop:Default;Desktop:Disconnect;Desktop:Winlogon;
WindowStation1:Service-0x0-3e7$
WindowStation2:Service-0x0-3e4$
WindowStation3:Service-0x0-3e5$
WindowStation4:msswindowstation
Desktop:mssrestricteddesk;
可是我获取不了当前显示的desktop的DC句柄。我尝试把在DC上画图,可是都不成功。
不是service模式到是运行正常。
请大侠帮忙!!!
6 个解决方案
#1
枚举测试代码:
int n=0;
void LogEvent(char *pStr)
{
FILE* pf=fopen("c:\\users\\paul\\desktop\\service\\TestGetDesktop.txt","at");
if(pf)
{
fwrite(pStr,1,strlen(pStr),pf);
fclose(pf);
}
}
BOOL CALLBACK EnumDesktopProc(
LPTSTR lpszDesktop,
LPARAM lParam
)
{
char buf[1024]={0};
wsprintf(buf,"Desktop:%s;",lpszDesktop);
HDESK hdCurrent=OpenDesktop(lpszDesktop,0,FALSE,MAXIMUM_ALLOWED);
USEROBJECTFLAGS uoFlags;
unsigned long pSize;
if( GetUserObjectInformation(hdCurrent, UOI_FLAGS, &uoFlags, sizeof(uoFlags), &pSize) == 0 )
LogEvent("GetUserObjectInformation call failed.\n");
else
{
SetProcessWindowStation((HWINSTA)lParam);
SetThreadDesktop(hdCurrent);
{
HBRUSH hredBr=CreateSolidBrush ( RGB(255,0,0));
HDC hdekdc=GetWindowDC(GetDesktopWindow());
HDC hrootdc = CreateDC(("DISPLAY"),NULL,NULL,NULL);
RECT rect={0,0,500,500};
FillRect(hrootdc,&rect,hredBr);
FillRect(hdekdc,&rect,hredBr);
DeleteDC(hrootdc);
DeleteDC(hdekdc);
}
}
CloseDesktop(hdCurrent);
LogEvent(buf);
return TRUE;
}
int i=0;
BOOL CALLBACK EnumWindowStationProc(
LPTSTR lpszWindowStation,
LPARAM lParam
)
{
char buf[1024]={0};
wsprintf(buf,"\nWindowStation%d:%s\n",i++,lpszWindowStation);
LogEvent(buf);
HWINSTA hwinsta=OpenWindowStation(lpszWindowStation,FALSE,MAXIMUM_ALLOWED);
if(hwinsta)
{
EnumDesktops(hwinsta,EnumDesktopProc,(long)hwinsta);
}
CloseWindowStation(hwinsta);
return TRUE;
}
BOOL EnumWindowStationAndDesktop()
{
EnumWindowStations(EnumWindowStationProc,NULL);
return TRUE;
}
主函数调用EnumWindowStationAndDesktop();
int n=0;
void LogEvent(char *pStr)
{
FILE* pf=fopen("c:\\users\\paul\\desktop\\service\\TestGetDesktop.txt","at");
if(pf)
{
fwrite(pStr,1,strlen(pStr),pf);
fclose(pf);
}
}
BOOL CALLBACK EnumDesktopProc(
LPTSTR lpszDesktop,
LPARAM lParam
)
{
char buf[1024]={0};
wsprintf(buf,"Desktop:%s;",lpszDesktop);
HDESK hdCurrent=OpenDesktop(lpszDesktop,0,FALSE,MAXIMUM_ALLOWED);
USEROBJECTFLAGS uoFlags;
unsigned long pSize;
if( GetUserObjectInformation(hdCurrent, UOI_FLAGS, &uoFlags, sizeof(uoFlags), &pSize) == 0 )
LogEvent("GetUserObjectInformation call failed.\n");
else
{
SetProcessWindowStation((HWINSTA)lParam);
SetThreadDesktop(hdCurrent);
{
HBRUSH hredBr=CreateSolidBrush ( RGB(255,0,0));
HDC hdekdc=GetWindowDC(GetDesktopWindow());
HDC hrootdc = CreateDC(("DISPLAY"),NULL,NULL,NULL);
RECT rect={0,0,500,500};
FillRect(hrootdc,&rect,hredBr);
FillRect(hdekdc,&rect,hredBr);
DeleteDC(hrootdc);
DeleteDC(hdekdc);
}
}
CloseDesktop(hdCurrent);
LogEvent(buf);
return TRUE;
}
int i=0;
BOOL CALLBACK EnumWindowStationProc(
LPTSTR lpszWindowStation,
LPARAM lParam
)
{
char buf[1024]={0};
wsprintf(buf,"\nWindowStation%d:%s\n",i++,lpszWindowStation);
LogEvent(buf);
HWINSTA hwinsta=OpenWindowStation(lpszWindowStation,FALSE,MAXIMUM_ALLOWED);
if(hwinsta)
{
EnumDesktops(hwinsta,EnumDesktopProc,(long)hwinsta);
}
CloseWindowStation(hwinsta);
return TRUE;
}
BOOL EnumWindowStationAndDesktop()
{
EnumWindowStations(EnumWindowStationProc,NULL);
return TRUE;
}
主函数调用EnumWindowStationAndDesktop();
#2
Vista中服务程序与应用程序所在的session不同。
#4
引用的代码:
HANDLE hThisProcess = GetCurrentProcess(); // 获取当前进程句柄
// 打开当前进程令牌
HANDLE hTokenThis = NULL;
OpenProcessToken(hThisProcess, TOKEN_ALL_ACCESS, &hTokenThis);
// 复制一个进程令牌,目的是为了修改session id属性,以便在其它session中创建进程
HANDLE hTokenDup = NULL;
DuplicateTokenEx(hTokenThis, MAXIMUM_ALLOWED,NULL, SecurityIdentification, TokenPrimary, &hTokenDup);
DWORD dwSessionId = WTSGetActiveConsoleSessionId(); // 获取活动session id
SetTokenInformation(hTokenDup, TokenSessionId, &dwSessionId, sizeof(DWORD)); // 把session id设置到备份的令牌中
// 好了,现在要用新的令牌来创建一个服务进程。注意:是“服务”进程!如果需要以用户身份运行,必须在前面执行LogonUser来获取用户令牌
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(STARTUPINFO));
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = "WinSta0\\Default";
LPVOID pEnv = NULL;
DWORD dwCreationFlag = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
CreateEnvironmentBlock(&pEnv, hTokenDup, FALSE); // 创建环境块
// 创建新的服务进程,这个进程应该接收参数来调用SHChangeNotify,它将工作在新的session 1中
CreateProcessAsUser(hTokenDup, NULL, _T("C:\\myservice.exe -Notify"), NULL, NULL, FALSE, dwCreationFlag, pEnv, NULL, &si, &pi);
还不是很明白,这个是一个service程序麽?还是有两个?运行后的新进程是服务?
最主要的是怎么把这代码使用到我的service里面?
这方面看不懂,望多指点下!
HANDLE hThisProcess = GetCurrentProcess(); // 获取当前进程句柄
// 打开当前进程令牌
HANDLE hTokenThis = NULL;
OpenProcessToken(hThisProcess, TOKEN_ALL_ACCESS, &hTokenThis);
// 复制一个进程令牌,目的是为了修改session id属性,以便在其它session中创建进程
HANDLE hTokenDup = NULL;
DuplicateTokenEx(hTokenThis, MAXIMUM_ALLOWED,NULL, SecurityIdentification, TokenPrimary, &hTokenDup);
DWORD dwSessionId = WTSGetActiveConsoleSessionId(); // 获取活动session id
SetTokenInformation(hTokenDup, TokenSessionId, &dwSessionId, sizeof(DWORD)); // 把session id设置到备份的令牌中
// 好了,现在要用新的令牌来创建一个服务进程。注意:是“服务”进程!如果需要以用户身份运行,必须在前面执行LogonUser来获取用户令牌
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(STARTUPINFO));
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = "WinSta0\\Default";
LPVOID pEnv = NULL;
DWORD dwCreationFlag = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
CreateEnvironmentBlock(&pEnv, hTokenDup, FALSE); // 创建环境块
// 创建新的服务进程,这个进程应该接收参数来调用SHChangeNotify,它将工作在新的session 1中
CreateProcessAsUser(hTokenDup, NULL, _T("C:\\myservice.exe -Notify"), NULL, NULL, FALSE, dwCreationFlag, pEnv, NULL, &si, &pi);
还不是很明白,这个是一个service程序麽?还是有两个?运行后的新进程是服务?
最主要的是怎么把这代码使用到我的service里面?
这方面看不懂,望多指点下!
#5
这段代码在已有的服务进程中执行,你需要监控用户是否已经登录到桌面了,并获取这个桌面的SESSION ID,原理大概是这样的:
打开自己的进程令牌
复制一个新令牌
对新令牌设置用户桌面的SESSION ID
用新令牌创建一个进程,程序名就是服务程序EXE的路径,帐户还是LocalSystem,唯一的区别就是这个进程运行在桌面所在的SESSION中,虽然不是真正的服务,但是跟服务权限相同。
在新的进程中控制桌面。
XP及以前的版本中,服务和第一个用户桌面共享session 0,所以代码没问题,但是在VISTA中,服务运行在session 0中,用户桌面从session 1开始的,跨session是无法访问窗口的,必须用一个相同session的程序才能访问桌面。
打开自己的进程令牌
复制一个新令牌
对新令牌设置用户桌面的SESSION ID
用新令牌创建一个进程,程序名就是服务程序EXE的路径,帐户还是LocalSystem,唯一的区别就是这个进程运行在桌面所在的SESSION中,虽然不是真正的服务,但是跟服务权限相同。
在新的进程中控制桌面。
XP及以前的版本中,服务和第一个用户桌面共享session 0,所以代码没问题,但是在VISTA中,服务运行在session 0中,用户桌面从session 1开始的,跨session是无法访问窗口的,必须用一个相同session的程序才能访问桌面。
#6
哦,谢谢!
#1
枚举测试代码:
int n=0;
void LogEvent(char *pStr)
{
FILE* pf=fopen("c:\\users\\paul\\desktop\\service\\TestGetDesktop.txt","at");
if(pf)
{
fwrite(pStr,1,strlen(pStr),pf);
fclose(pf);
}
}
BOOL CALLBACK EnumDesktopProc(
LPTSTR lpszDesktop,
LPARAM lParam
)
{
char buf[1024]={0};
wsprintf(buf,"Desktop:%s;",lpszDesktop);
HDESK hdCurrent=OpenDesktop(lpszDesktop,0,FALSE,MAXIMUM_ALLOWED);
USEROBJECTFLAGS uoFlags;
unsigned long pSize;
if( GetUserObjectInformation(hdCurrent, UOI_FLAGS, &uoFlags, sizeof(uoFlags), &pSize) == 0 )
LogEvent("GetUserObjectInformation call failed.\n");
else
{
SetProcessWindowStation((HWINSTA)lParam);
SetThreadDesktop(hdCurrent);
{
HBRUSH hredBr=CreateSolidBrush ( RGB(255,0,0));
HDC hdekdc=GetWindowDC(GetDesktopWindow());
HDC hrootdc = CreateDC(("DISPLAY"),NULL,NULL,NULL);
RECT rect={0,0,500,500};
FillRect(hrootdc,&rect,hredBr);
FillRect(hdekdc,&rect,hredBr);
DeleteDC(hrootdc);
DeleteDC(hdekdc);
}
}
CloseDesktop(hdCurrent);
LogEvent(buf);
return TRUE;
}
int i=0;
BOOL CALLBACK EnumWindowStationProc(
LPTSTR lpszWindowStation,
LPARAM lParam
)
{
char buf[1024]={0};
wsprintf(buf,"\nWindowStation%d:%s\n",i++,lpszWindowStation);
LogEvent(buf);
HWINSTA hwinsta=OpenWindowStation(lpszWindowStation,FALSE,MAXIMUM_ALLOWED);
if(hwinsta)
{
EnumDesktops(hwinsta,EnumDesktopProc,(long)hwinsta);
}
CloseWindowStation(hwinsta);
return TRUE;
}
BOOL EnumWindowStationAndDesktop()
{
EnumWindowStations(EnumWindowStationProc,NULL);
return TRUE;
}
主函数调用EnumWindowStationAndDesktop();
int n=0;
void LogEvent(char *pStr)
{
FILE* pf=fopen("c:\\users\\paul\\desktop\\service\\TestGetDesktop.txt","at");
if(pf)
{
fwrite(pStr,1,strlen(pStr),pf);
fclose(pf);
}
}
BOOL CALLBACK EnumDesktopProc(
LPTSTR lpszDesktop,
LPARAM lParam
)
{
char buf[1024]={0};
wsprintf(buf,"Desktop:%s;",lpszDesktop);
HDESK hdCurrent=OpenDesktop(lpszDesktop,0,FALSE,MAXIMUM_ALLOWED);
USEROBJECTFLAGS uoFlags;
unsigned long pSize;
if( GetUserObjectInformation(hdCurrent, UOI_FLAGS, &uoFlags, sizeof(uoFlags), &pSize) == 0 )
LogEvent("GetUserObjectInformation call failed.\n");
else
{
SetProcessWindowStation((HWINSTA)lParam);
SetThreadDesktop(hdCurrent);
{
HBRUSH hredBr=CreateSolidBrush ( RGB(255,0,0));
HDC hdekdc=GetWindowDC(GetDesktopWindow());
HDC hrootdc = CreateDC(("DISPLAY"),NULL,NULL,NULL);
RECT rect={0,0,500,500};
FillRect(hrootdc,&rect,hredBr);
FillRect(hdekdc,&rect,hredBr);
DeleteDC(hrootdc);
DeleteDC(hdekdc);
}
}
CloseDesktop(hdCurrent);
LogEvent(buf);
return TRUE;
}
int i=0;
BOOL CALLBACK EnumWindowStationProc(
LPTSTR lpszWindowStation,
LPARAM lParam
)
{
char buf[1024]={0};
wsprintf(buf,"\nWindowStation%d:%s\n",i++,lpszWindowStation);
LogEvent(buf);
HWINSTA hwinsta=OpenWindowStation(lpszWindowStation,FALSE,MAXIMUM_ALLOWED);
if(hwinsta)
{
EnumDesktops(hwinsta,EnumDesktopProc,(long)hwinsta);
}
CloseWindowStation(hwinsta);
return TRUE;
}
BOOL EnumWindowStationAndDesktop()
{
EnumWindowStations(EnumWindowStationProc,NULL);
return TRUE;
}
主函数调用EnumWindowStationAndDesktop();
#2
Vista中服务程序与应用程序所在的session不同。
#3
先切换SESSION ID来创建一个服务进程副本(
例子代码),然后再做上面的操作。
#4
引用的代码:
HANDLE hThisProcess = GetCurrentProcess(); // 获取当前进程句柄
// 打开当前进程令牌
HANDLE hTokenThis = NULL;
OpenProcessToken(hThisProcess, TOKEN_ALL_ACCESS, &hTokenThis);
// 复制一个进程令牌,目的是为了修改session id属性,以便在其它session中创建进程
HANDLE hTokenDup = NULL;
DuplicateTokenEx(hTokenThis, MAXIMUM_ALLOWED,NULL, SecurityIdentification, TokenPrimary, &hTokenDup);
DWORD dwSessionId = WTSGetActiveConsoleSessionId(); // 获取活动session id
SetTokenInformation(hTokenDup, TokenSessionId, &dwSessionId, sizeof(DWORD)); // 把session id设置到备份的令牌中
// 好了,现在要用新的令牌来创建一个服务进程。注意:是“服务”进程!如果需要以用户身份运行,必须在前面执行LogonUser来获取用户令牌
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(STARTUPINFO));
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = "WinSta0\\Default";
LPVOID pEnv = NULL;
DWORD dwCreationFlag = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
CreateEnvironmentBlock(&pEnv, hTokenDup, FALSE); // 创建环境块
// 创建新的服务进程,这个进程应该接收参数来调用SHChangeNotify,它将工作在新的session 1中
CreateProcessAsUser(hTokenDup, NULL, _T("C:\\myservice.exe -Notify"), NULL, NULL, FALSE, dwCreationFlag, pEnv, NULL, &si, &pi);
还不是很明白,这个是一个service程序麽?还是有两个?运行后的新进程是服务?
最主要的是怎么把这代码使用到我的service里面?
这方面看不懂,望多指点下!
HANDLE hThisProcess = GetCurrentProcess(); // 获取当前进程句柄
// 打开当前进程令牌
HANDLE hTokenThis = NULL;
OpenProcessToken(hThisProcess, TOKEN_ALL_ACCESS, &hTokenThis);
// 复制一个进程令牌,目的是为了修改session id属性,以便在其它session中创建进程
HANDLE hTokenDup = NULL;
DuplicateTokenEx(hTokenThis, MAXIMUM_ALLOWED,NULL, SecurityIdentification, TokenPrimary, &hTokenDup);
DWORD dwSessionId = WTSGetActiveConsoleSessionId(); // 获取活动session id
SetTokenInformation(hTokenDup, TokenSessionId, &dwSessionId, sizeof(DWORD)); // 把session id设置到备份的令牌中
// 好了,现在要用新的令牌来创建一个服务进程。注意:是“服务”进程!如果需要以用户身份运行,必须在前面执行LogonUser来获取用户令牌
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(STARTUPINFO));
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = "WinSta0\\Default";
LPVOID pEnv = NULL;
DWORD dwCreationFlag = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
CreateEnvironmentBlock(&pEnv, hTokenDup, FALSE); // 创建环境块
// 创建新的服务进程,这个进程应该接收参数来调用SHChangeNotify,它将工作在新的session 1中
CreateProcessAsUser(hTokenDup, NULL, _T("C:\\myservice.exe -Notify"), NULL, NULL, FALSE, dwCreationFlag, pEnv, NULL, &si, &pi);
还不是很明白,这个是一个service程序麽?还是有两个?运行后的新进程是服务?
最主要的是怎么把这代码使用到我的service里面?
这方面看不懂,望多指点下!
#5
这段代码在已有的服务进程中执行,你需要监控用户是否已经登录到桌面了,并获取这个桌面的SESSION ID,原理大概是这样的:
打开自己的进程令牌
复制一个新令牌
对新令牌设置用户桌面的SESSION ID
用新令牌创建一个进程,程序名就是服务程序EXE的路径,帐户还是LocalSystem,唯一的区别就是这个进程运行在桌面所在的SESSION中,虽然不是真正的服务,但是跟服务权限相同。
在新的进程中控制桌面。
XP及以前的版本中,服务和第一个用户桌面共享session 0,所以代码没问题,但是在VISTA中,服务运行在session 0中,用户桌面从session 1开始的,跨session是无法访问窗口的,必须用一个相同session的程序才能访问桌面。
打开自己的进程令牌
复制一个新令牌
对新令牌设置用户桌面的SESSION ID
用新令牌创建一个进程,程序名就是服务程序EXE的路径,帐户还是LocalSystem,唯一的区别就是这个进程运行在桌面所在的SESSION中,虽然不是真正的服务,但是跟服务权限相同。
在新的进程中控制桌面。
XP及以前的版本中,服务和第一个用户桌面共享session 0,所以代码没问题,但是在VISTA中,服务运行在session 0中,用户桌面从session 1开始的,跨session是无法访问窗口的,必须用一个相同session的程序才能访问桌面。
#6
哦,谢谢!