2016-08-03 9 views
-1

これはシステムサービスです。 ImpersonateLoggedOnUser()の後、私はCreateProcessAsUser()を正常に呼び出すことができます。しかし、それは1つのWindows APIを呼び出すことができませんSetDisplayConfig()。エラーは5です(ERROR_ACCESS_DENIED)。以下のコードをご覧ください。ImpersonateLoggedOnUser()の後、なぜWindows API SetDisplayConfig()を呼び出すことができませんでしたか?

// This function is called in a System service. 
void SetDisplayToExtendMode() 
{ 
    DWORD dwSessionId = WTSGetActiveConsoleSessionId(); 
    if (dwSessionId == 0xFFFFFFFF) 
    { 
     qCritical() << "Failed to get active console session Id when setting extend mode for display!"; 
    } 

    HANDLE hUserToken = NULL; 
    if (WTSQueryUserToken(dwSessionId, &hUserToken) == FALSE) 
    { 
     qCritical() << "Failed to query user token when setting extend mode for display!"; 
    } 

    HANDLE hTheToken = NULL; 
    if (DuplicateTokenEx(hUserToken, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, 0, SecurityImpersonation, TokenPrimary, &hTheToken) == TRUE) 
    { 

     if (ImpersonateLoggedOnUser(hTheToken) == TRUE) 
     { 
      DWORD dwCreationFlags = HIGH_PRIORITY_CLASS | CREATE_NEW_CONSOLE; 

      LPVOID pEnv = NULL; 
      if (CreateEnvironmentBlock(&pEnv, hTheToken, TRUE) == TRUE) 
      { 
       dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT; 
      } 

      // Way 1: Call Windows API directly. 
      // Fail. Error code is ERROR_ACCESS_DENIED 
      LONG errCode = SetDisplayConfig(0, NULL, 0, NULL, SDC_TOPOLOGY_EXTEND | SDC_APPLY); 
      if (errCode != ERROR_SUCCESS) 
      { 
       qCritical() << "Failed to set Windows Display to Extended mode! Error is " << errCode; 
       if (errCode == ERROR_ACCESS_DENIED) 
       { 
        qCritical() << "ACCESS denied!"; 
       } 
      } 

      STARTUPINFO si = { sizeof(si) }; 
      PROCESS_INFORMATION pi; 
      SECURITY_ATTRIBUTES Security1 = { sizeof(Security1) }; 
      SECURITY_ATTRIBUTES Security2 = { sizeof(Security2) }; 


      std::wstring command = L"C:\\Users\\SomeUser\\Desktop\\QT_Projects\\build\\release\\TestSetDisplay.exe"; 
      TCHAR commandLine[MAX_PATH]; 
      _tcscpy_s(commandLine, MAX_PATH, command.c_str()); 

      // Way 2: This way can be successful. 
      BOOL bResult = CreateProcessAsUser(
       hTheToken, 
       NULL, // (LPWSTR)(path), 
       (LPWSTR)(commandLine), 
       &Security1, 
       &Security2, 
       FALSE, 
       dwCreationFlags, 
       pEnv, 
       NULL, 
       &si, 
       &pi 
       ); 

      if (!bResult) 
      { 
       qCritical() << "Failed to CreateProcessAsUser()"; 
      } 

      RevertToSelf(); 

      if (pEnv) 
      { 
       DestroyEnvironmentBlock(pEnv); 
      } 
     } 
     CloseHandle(hTheToken); 
    } 
    CloseHandle(hUserToken); 
} 

ので、ImpersonateLoggedOnUser()後、どのように呼び出すためのWindows API SetDisplayConfig()に成功?
また、1つのシステムサービスで、1つのWindows APIをユーザーとして呼び出す方法はありますか? (このケースでは、SetDisplayConfig()を呼び出すの目的は、モードを拡張するための表示モードを設定することである。この表示モードは、ユーザごとに設定されている。だから、システムサービスとして、それは最初impersonateLoggedOnUser()する必要があるかもしれません。)

+1

おそらく、偽装されたユーザーがサービスのレジストリ(HKEY_CURRENT_USERが指しているもの、おそらくSetDisplayConfigがユーザーごとの設定を保存しているもの)にアクセスできないためです。 –

答えて

1

SetDisplayConfigドキュメントから

ERROR_ACCESS_DENIED発信者がコンソール セッションにアクセスできない。このエラーは、呼び出し元プロセスが現在のデスクトップへのアクセス を持たない場合、またはリモートセッションで実行されている場合に発生します。

、あなたが

を書いたこれはシステムサービスです。

ただし、システムサービスは対話型デスクトップにアクセスできません。

+1

正確です。 https://blogs.msdn.microsoft.com/oldnewthing/20110928-00/?p=9533も参照してください。偽装はすべてアクセス制御モデルに関するものであり、万能のソリューションではありません。 –

+0

@ RbMm、おそらくあなたは正しいです。シンプルにするには、**システムサービスがアクティブユーザーの表示モードを拡張に設定できるかどうかです** **「インタラクティブセッションから呼び出す」とはどういう意味ですか?どのウィンドウAPIを呼び出す必要がありますか? – HappyCoder

+0

ターミナルセッションの外観[TokenSessionId] [1]では、セッションはそのアドレス空間( "セッションスペース"と呼ばれる領域)にマップされたwin32k.sysの独自のコピーを持っています。その結果、異なるグローバルバースが生じる。ここで 'gProtocolType'の問題は、[this] [2]を見てください - あなたはc0000022(STATUS_ACCESS_DENIED)です。サービスプロセスからは不可能です。 'gProtocolType'に関する[look] [3]関連の問題 [1]:https://msdn.microsoft.com/en-us/library/windows/desktop/aa379626(v=vs.85).aspx [ 2]:http://i.imgur.com/blIRidH.png [3]:http://www.codeproject.com/Articles/20866/ClearType-over-Remote-Desktop-in-Windows-XP?msg = 2511636 – RbMm

関連する問題