2、计划任务不显示UI的问题

计划任务不显示UI的问题

1、原因:

在windows7以上系统,使用system权限启动的进程默认是没有ui界面,这是windows系统出于安全考虑的限制。防止用户在高权限下误删重要的文件。

2、解决方案:

1、降权

解决的办法:降权,即将权限降低。

下面给出降权的实例代码:

本质上是拿到当前用户的token,才能降权成功。

DWORD GetActiveSessionID() {
  DWORD dwSessionId = 0;
  PWTS_SESSION_INFO pSessionInfo = NULL;
  DWORD dwCount = 0;

  WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSessionInfo,
                       &dwCount);

  for (DWORD i = 0; i < dwCount; i++) {
    WTS_SESSION_INFO si = pSessionInfo[i];
    if (WTSActive == si.State) {
      dwSessionId = si.SessionId;
      break;
    }
  }

  WTSFreeMemory(pSessionInfo);
  return dwSessionId;
}

const wstring GetAppPath() {
  static wstring szRootPath;
  if (szRootPath == (L"")) {
    TCHAR szPath[_MAX_PATH];
    GetModuleFileName(NULL, szPath, _MAX_PATH);
    wstring strFullPath = szPath;
    szRootPath = strFullPath;
  }
  return szRootPath;
}

BOOL TriggerAppExecute(std::wstring wstrCmdLine /*, INT32& n32ExitResult*/) {
  DWORD dwProcesses = 0;
  BOOL bResult = FALSE;

  DWORD dwSid = GetActiveSessionID();

  DWORD dwRet = 0;
  PROCESS_INFORMATION pi;
  STARTUPINFO si;
  HANDLE hProcess = NULL, hPToken = NULL, hUserTokenDup = NULL;
  if (!WTSQueryUserToken(dwSid, &hPToken)) {
    PROCESSENTRY32 procEntry;
    DWORD dwPid = 0;
    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnap == INVALID_HANDLE_VALUE) {
      return FALSE;
    }

    procEntry.dwSize = sizeof(PROCESSENTRY32);
    if (Process32First(hSnap, &procEntry)) {
      do {
        if (_wcsicmp(procEntry.szExeFile, (L"explorer.exe")) == 0) {
          DWORD exeSessionId = 0;
          if (ProcessIdToSessionId(procEntry.th32ProcessID, &exeSessionId) &&
              exeSessionId == dwSid) {
            dwPid = procEntry.th32ProcessID;
            break;
          }
        }

      } while (Process32Next(hSnap, &procEntry));
    }
    CloseHandle(hSnap);

    // explorer进程不存在
    if (dwPid == 0) {
      return FALSE;
    }

    hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwPid);
    if (hProcess == NULL) {
      return FALSE;
    }

    if (!::OpenProcessToken(hProcess, TOKEN_ALL_ACCESS_P, &hPToken)) {
      CloseHandle(hProcess);
      return FALSE;
    }
  }

  if (hPToken == NULL) {
    return FALSE;
  }

  TOKEN_LINKED_TOKEN admin;
  bResult =
      GetTokenInformation(hPToken, (TOKEN_INFORMATION_CLASS)TokenLinkedToken,
                          &admin, sizeof(TOKEN_LINKED_TOKEN), &dwRet);

  if (!bResult)  // vista 以前版本不支持TokenLinkedToken
  {
    TOKEN_PRIVILEGES tp;
    LUID luid;
    if (LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) {
      tp.PrivilegeCount = 1;
      tp.Privileges[0].Luid = luid;
      tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    }
    //复制token
    DuplicateTokenEx(hPToken, MAXIMUM_ALLOWED, NULL, SecurityIdentification,
                     TokenPrimary, &hUserTokenDup);
  } else {
    hUserTokenDup = admin.LinkedToken;
  }

  LPVOID pEnv = NULL;
  DWORD dwCreationFlags = CREATE_PRESERVE_CODE_AUTHZ_LEVEL;

  // hUserTokenDup为当前登陆用户的令牌
  if (CreateEnvironmentBlock(&pEnv, hUserTokenDup, TRUE)) {
    //如果传递了环境变量参数,CreateProcessAsUser的
    // dwCreationFlags参数需要加上CREATE_UNICODE_ENVIRONMENT,
    //这是MSDN明确说明的
    dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
  } else {
    //环境变量创建失败仍然可以创建进程,
    //但会影响到后面的进程获取环境变量内容
    pEnv = NULL;
  }

  ZeroMemory(&si, sizeof(si));
  si.cb = sizeof(si);
  si.dwFlags = STARTF_USESHOWWINDOW;
  si.wShowWindow = SW_SHOW;
  ZeroMemory(&pi, sizeof(pi));

  bResult = CreateProcessAsUser(hUserTokenDup,         // client's access token
                                GetAppPath().c_str(),  // file to execute
                                (LPTSTR)wstrCmdLine.c_str(),  // command line
                                NULL,  // pointer to process SECURITY_ATTRIBUTES
                                NULL,  // pointer to thread SECURITY_ATTRIBUTES
                                FALSE,            // handles are not inheritable
                                dwCreationFlags,  // creation flags
                                pEnv,  // pointer to new environment block
                                NULL,  // name of current directory
                                &si,   // pointer to STARTUPINFO structure
                                &pi    // receives information about new process
  );

  if (!bResult) {
    OutputDebugStringW(
        (std::wstring(L"error code:") + std::to_wstring(GetLastError()))
            .c_str());
  } else {
    OutputDebugStringW((std::wstring(L"create as user ok:")).c_str());
  }

  if (pi.hProcess) {
    CloseHandle(pi.hThread);
    CloseHandle(pi.hProcess);
  }

  if (hUserTokenDup != NULL) CloseHandle(hUserTokenDup);
  if (hProcess != NULL) CloseHandle(hProcess);
  if (hPToken != NULL) CloseHandle(hPToken);
  if (pEnv != NULL) DestroyEnvironmentBlock(pEnv);

  return TRUE;
}

int main(int argc, char *argv[])
{
      bool result = TriggerAppExecute(parameter);
      // 如果成功 直接返回,失败
      if (result) {
        OutputDebugStringW(L"降权失败,等待。。。。");
      }
    return 0;
}
2、降权失败

上面降权有个前置条件就是用户必须是登录的状态。

举个例子:如果用户把机器开起来了。但是没有登录到系统中。此时由于拿不到当前的用户的token,所以会造成降权失败。

那该怎么办?

试想下如果用户没有登录,那么你的UI是不是没有必要显示。即使是显示了,也没有人看。

所以用户登录到系统中,此时再显示ui时机刚刚好。

那么问题来了?如何知道用户登录到了系统。

嘿嘿,windows中有个消息通知,我们可以注册回调函数。只要用户登录了,就会收到消息。此时,你在进行降权操作就没有问题。

给出实例代码,新建一个控制程序:

进程启动后,先把退出系统,再输入账号和密码,此时就会打印attention, user logon消息,说明消息监听成功。

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
                            LPARAM lParam) {
  switch (uMsg) {
    case WM_WTSSESSION_CHANGE: {
      // 处理用户登录和注销消息
      switch (wParam) {
        case WTS_SESSION_LOGON:
          // 用户登录
          printf("attention, user logon")
          break;
        case WTS_SESSION_LOGOFF:
          // 用户注销
          printf("attention, user logoff")
          break;
      }
    } break;
  }

  // 调用默认窗口过程函数处理其他消息
  return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

int main() {
  // 注册回调函数
  bool result = WTSRegisterSessionNotification(GetConsoleWindow(),
                                               NOTIFY_FOR_ALL_SESSIONS);
  SetWindowLongPtr(GetConsoleWindow(), GWLP_WNDPROC, (LONG_PTR)WindowProc);
  getchar();
  // 取消消息监听
  WTSUnRegisterSessionNotification(GetConsoleWindow());

  return 0;
}

3、总结

至此,计划任务遇到的问题也已经解决了。

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。
04-26
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值