title: Running a Process (WITH GUI) on Windows XP Logon Screen (.NET / Pinvoke)
body: <p>I need to write a small <strong>service</strong> that runs an application (with gui, e.g. <em>calc.exe</em>) on the logon-screen.</p>
  
  <p>I already found this question (and answer):
  <a href="https://stackoverflow.com/questions/3070152/running-a-process-at-the-windows-7-welcome-screen">Running a process at the Windows 7 Welcome Screen</a></p>
  
  <p>please read the code-comments if you don't understand how this works:</p>
  
  <pre><code>        // grab the winlogon process
          Process winLogon = null;
          foreach (Process p in Process.GetProcesses())
          {
              if (p.ProcessName.Contains("winlogon"))
              {
                  winLogon = p;
                  break;
              }
          }
          // grab the winlogon's token
          IntPtr userToken = IntPtr.Zero;
          if (!OpenProcessToken(winLogon.Handle, TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE, out userToken))
          {
              log("ERROR: OpenProcessToken returned false - " + Marshal.GetLastWin32Error());
          }
  
          // create a new token
          IntPtr newToken = IntPtr.Zero;
          SECURITY_ATTRIBUTES tokenAttributes = new SECURITY_ATTRIBUTES();
          tokenAttributes.nLength = Marshal.SizeOf(tokenAttributes);
          SECURITY_ATTRIBUTES threadAttributes = new SECURITY_ATTRIBUTES();
          threadAttributes.nLength = Marshal.SizeOf(threadAttributes);
          // duplicate the winlogon token to the new token
          if (!DuplicateTokenEx(userToken, 0x10000000, ref tokenAttributes, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,
              TOKEN_TYPE.TokenImpersonation, out newToken))
          {
              log("ERROR: DuplicateTokenEx returned false - " + Marshal.GetLastWin32Error());
          }
          TOKEN_PRIVILEGES tokPrivs = new TOKEN_PRIVILEGES();
          tokPrivs.PrivilegeCount = 1;
          LUID seDebugNameValue = new LUID();
          if (!LookupPrivilegeValue(null, SE_DEBUG_NAME, out seDebugNameValue))
          {
              log("ERROR: LookupPrivilegeValue returned false - " + Marshal.GetLastWin32Error());
          }
          tokPrivs.Privileges = new LUID_AND_ATTRIBUTES[1];
          tokPrivs.Privileges[0].Luid = seDebugNameValue;
          tokPrivs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
          // escalate the new token's privileges
          if (!AdjustTokenPrivileges(newToken, false, ref tokPrivs, 0, IntPtr.Zero, IntPtr.Zero))
          {
              log("ERROR: AdjustTokenPrivileges returned false - " + Marshal.GetLastWin32Error());
          }
          PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
          STARTUPINFO si = new STARTUPINFO();
          si.cb = Marshal.SizeOf(si);
          si.lpDesktop = "Winsta0\\Winlogon";
          // start the process using the new token
          if (!CreateProcessAsUser(newToken, "calc.exe", null, ref tokenAttributes, ref threadAttributes,
              true, (uint)CreateProcessFlags.CREATE_NEW_CONSOLE | (uint)CreateProcessFlags.INHERIT_CALLER_PRIORITY, IntPtr.Zero,
              "C:\\Windows\\System32", ref si, out pi))
          {
              log("ERROR: CreateProcessAsUser returned false - " + Marshal.GetLastWin32Error());
          }
  
          Process _p = Process.GetProcessById(pi.dwProcessId);
          if (_p != null)
          {
              log("Process " + _p.Id + " Name " + _p.ProcessName);
          }
          else
          {
              log("Process not found");
          }
  </code></pre>
  
  <p>It works with Windows 7. With XP I get error 1349 <code>ERROR_BAD_TOKEN_TYPE</code> while calling <code>CreateProcessAsUser</code> (MSDN: <em>The type of the token is inappropriate for its attempted use.</em>).</p>
  
  <p>How to realize this in Windows XP? It does not have to be the code from above but it should work as a service (with system-account?).</p>
  
  <p>Thanks for your support
  Fluxer</p>