写个service程序,在vista下获取不了当前可见的desktop;
枚举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模式到是运行正常。
请大侠帮忙!!!

解决方案 »

  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();
      

  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里面?
    这方面看不懂,望多指点下!
      

  5.   

    这段代码在已有的服务进程中执行,你需要监控用户是否已经登录到桌面了,并获取这个桌面的SESSION ID,原理大概是这样的:
    打开自己的进程令牌
    复制一个新令牌
    对新令牌设置用户桌面的SESSION ID
    用新令牌创建一个进程,程序名就是服务程序EXE的路径,帐户还是LocalSystem,唯一的区别就是这个进程运行在桌面所在的SESSION中,虽然不是真正的服务,但是跟服务权限相同。
    在新的进程中控制桌面。XP及以前的版本中,服务和第一个用户桌面共享session 0,所以代码没问题,但是在VISTA中,服务运行在session 0中,用户桌面从session 1开始的,跨session是无法访问窗口的,必须用一个相同session的程序才能访问桌面。