I am creating a windows service that will print pdf in time interval.
I have done some research on this and found a class
- public class ProcessStarter : IDisposable
- {
- #region Import Section
- private static uint STANDARD_RIGHTS_REQUIRED = 0x000F0000;
- private static uint STANDARD_RIGHTS_READ = 0x00020000;
- private static uint TOKEN_ASSIGN_PRIMARY = 0x0001;
- private static uint TOKEN_DUPLICATE = 0x0002;
- private static uint TOKEN_IMPERSONATE = 0x0004;
- private static uint TOKEN_QUERY = 0x0008;
- private static uint TOKEN_QUERY_SOURCE = 0x0010;
- private static uint TOKEN_ADJUST_PRIVILEGES = 0x0020;
- private static uint TOKEN_ADJUST_GROUPS = 0x0040;
- private static uint TOKEN_ADJUST_DEFAULT = 0x0080;
- private static uint TOKEN_ADJUST_SESSIONID = 0x0100;
- private static uint TOKEN_READ = (STANDARD_RIGHTS_READ | TOKEN_QUERY);
- private static uint TOKEN_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID);
- private const uint NORMAL_PRIORITY_CLASS = 0x0020;
- private const uint CREATE_UNICODE_ENVIRONMENT = 0x00000400;
- private const uint MAX_PATH = 260;
- private const uint CREATE_NO_WINDOW = 0x08000000;
- private const uint INFINITE = 0xFFFFFFFF;
- [StructLayout(LayoutKind.Sequential)]
- public struct SECURITY_ATTRIBUTES
- {
- public int nLength;
- public IntPtr lpSecurityDescriptor;
- public int bInheritHandle;
- }
- public enum SECURITY_IMPERSONATION_LEVEL
- {
- SecurityAnonymous, SecurityIdentification, SecurityImpersonation, SecurityDelegation
- }
- public enum TOKEN_TYPE
- {
- TokenPrimary = 1, TokenImpersonation
- }
- public enum WTS_CONNECTSTATE_CLASS
- {
- WTSActive, WTSConnected, WTSConnectQuery, WTSShadow, WTSDisconnected, WTSIdle, WTSListen, WTSReset, WTSDown, WTSInit
- }
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
- public struct STARTUPINFO
- {
- public Int32 cb;
- public string lpReserved;
- public string lpDesktop;
- public string lpTitle;
- public Int32 dwX;
- public Int32 dwY;
- public Int32 dwXSize;
- public Int32 dwYSize;
- public Int32 dwXCountChars;
- public Int32 dwYCountChars;
- public Int32 dwFillAttribute;
- public Int32 dwFlags;
- public Int16 wShowWindow;
- public Int16 cbReserved2;
- public IntPtr lpReserved2;
- public IntPtr hStdInput;
- public IntPtr hStdOutput;
- public IntPtr hStdError;
- }
- [StructLayout(LayoutKind.Sequential)]
- internal struct PROCESS_INFORMATION
- {
- public IntPtr hProcess;
- public IntPtr hThread;
- public int dwProcessId;
- public int dwThreadId;
- }
- [StructLayout(LayoutKind.Sequential)] private struct WTS_SESSION_INFO
- {
- public Int32 SessionID;
- [MarshalAs(UnmanagedType.LPStr)]
- public String pWinStationName;
- public WTS_CONNECTSTATE_CLASS State;
- }
- [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
- static extern uint WTSGetActiveConsoleSessionId();
- [DllImport("wtsapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
- static extern bool WTSQueryUserToken(int sessionId, out IntPtr tokenHandle);
- [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
- public extern static bool DuplicateTokenEx(IntPtr existingToken, uint desiredAccess, IntPtr tokenAttributes, SECURITY_IMPERSONATION_LEVEL impersonationLevel, TOKEN_TYPE tokenType, out IntPtr newToken);
- [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
- static extern bool CreateProcessAsUser(IntPtr token, string applicationName, string commandLine, ref SECURITY_ATTRIBUTES processAttributes, ref SECURITY_ATTRIBUTES threadAttributes, bool inheritHandles, uint creationFlags, IntPtr environment, string currentDirectory, ref STARTUPINFO startupInfo, out PROCESS_INFORMATION processInformation); [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
- static extern bool CloseHandle(IntPtr handle);
- [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
- static extern int GetLastError();
- [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
- static extern int WaitForSingleObject(IntPtr token, uint timeInterval); [DllImport("wtsapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
- static extern int WTSEnumerateSessions(System.IntPtr hServer, int Reserved, int Version, ref System.IntPtr ppSessionInfo, ref int pCount);
- [DllImport("userenv.dll", CharSet = CharSet.Auto, SetLastError = true)]
- static extern bool CreateEnvironmentBlock(out IntPtr lpEnvironment, IntPtr hToken, bool bInherit);
- [DllImport("wtsapi32.dll", ExactSpelling = true, SetLastError = false)]
- public static extern void WTSFreeMemory(IntPtr memory);
- [DllImport("userenv.dll", SetLastError = true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- static extern bool DestroyEnvironmentBlock(IntPtr lpEnvironment);
- #endregion
-
-
-
- public ProcessStarter() { }
-
-
-
-
-
- public ProcessStarter(string processName, string fullExeName)
- {
- processName_ = processName; processPath_ = fullExeName; }
-
-
-
-
-
-
- public ProcessStarter(string processName, string fullExeName, string arguments)
- {
- processName_ = processName; processPath_ = fullExeName; arguments_ = arguments; }
-
-
-
-
- public static IntPtr GetCurrentUserToken()
- {
- IntPtr currentToken = IntPtr.Zero;
- IntPtr primaryToken = IntPtr.Zero;
- IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;
- int dwSessionId = 0;
- IntPtr hUserToken = IntPtr.Zero;
- IntPtr hTokenDup = IntPtr.Zero;
- IntPtr pSessionInfo = IntPtr.Zero;
- int dwCount = 0; WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, ref pSessionInfo, ref dwCount);
- Int32 dataSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO));
- Int32 current = (int)pSessionInfo;
- for (int i = 0; i < dwCount; i++)
- {
- WTS_SESSION_INFO si = (WTS_SESSION_INFO)Marshal.PtrToStructure((System.IntPtr)current, typeof(WTS_SESSION_INFO));
- if (WTS_CONNECTSTATE_CLASS.WTSActive == si.State)
- {
- dwSessionId = si.SessionID;
- break;
- }
- current += dataSize;
- }
- WTSFreeMemory(pSessionInfo);
- bool bRet = WTSQueryUserToken(dwSessionId, out currentToken);
- if (bRet == false)
- {
- return IntPtr.Zero;
- }
- bRet = DuplicateTokenEx(currentToken, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, IntPtr.Zero, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, TOKEN_TYPE.TokenPrimary, out primaryToken);
- if (bRet == false)
- {
- return IntPtr.Zero;
- }
- return primaryToken; }
-
-
-
- public void Run()
- {
- IntPtr primaryToken = GetCurrentUserToken();
- if (primaryToken == IntPtr.Zero)
- {
- return;
- }
- STARTUPINFO StartupInfo = new STARTUPINFO();
- processInfo_ = new PROCESS_INFORMATION();
- StartupInfo.cb = Marshal.SizeOf(StartupInfo);
- SECURITY_ATTRIBUTES Security1 = new SECURITY_ATTRIBUTES();
- SECURITY_ATTRIBUTES Security2 = new SECURITY_ATTRIBUTES();
- string command = "\"" + processPath_ + "\""; if ((arguments_ != null) && (arguments_.Length != 0))
- {
- command += " " + arguments_;
- }
- IntPtr lpEnvironment = IntPtr.Zero;
- bool resultEnv = CreateEnvironmentBlock(out lpEnvironment, primaryToken, false);
- if (resultEnv != true)
- {
- int nError = GetLastError();
- }
- CreateProcessAsUser(primaryToken, null, command, ref Security1, ref Security2, false, CREATE_NO_WINDOW | NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT, lpEnvironment, null, ref StartupInfo, out processInfo_);
- DestroyEnvironmentBlock(lpEnvironment);
- CloseHandle(primaryToken);
- }
-
-
-
- public void Stop()
- {
- Process[] processes = Process.GetProcesses();
- foreach (Process current in processes)
- {
- if (current.ProcessName == processName_)
- {
- current.Kill();
- }
- }
- }
-
-
-
-
- public int WaitForExit()
- {
- WaitForSingleObject(processInfo_.hProcess, INFINITE);
- int errorcode = GetLastError();
- return errorcode;
- }
- #region IDisposable Members
-
-
-
- public void Dispose()
- {
- }
- #endregion
- private string processPath_ = string.Empty;
- private string processName_ = string.Empty;
- private string arguments_ = string.Empty;
- private PROCESS_INFORMATION processInfo_;
-
-
-
- <value>The process path.</value>
- public string ProcessPath
- {
- get
- {
- return processPath_;
- }
- set
- {
- processPath_ = value;
- }
- }
-
-
-
-
- public string ProcessName
- {
- get{ return processName_; }
- set { processName_ = value; }
- }
-
-
-
-
- public string Arguments
- {
- get { return arguments_; }
- set { arguments_ = value; }
- }
- }
and calling this class like this
- string pdfPrinterLocation = @"C:\Program Files (x86)\Adobe\Reader 11.0\Reader\AcroRd32.exe";
- string pdfArguments = "/t /o C:\Windows\TEMP\761372.pdf";
- ProcessStarter processStarter = new ProcessStarter("AcroRd32", pdfPrinterLocation, pdfArguments);
- processStarter.Run();
- processStarter.WaitForExit();
- processStarter.Stop();
This code is working fine and doing great job.
But This is working only when some user logged in in system. Means when I login then it's working. But when I logoff my user then it's not working. When I lock my system then it's working but when logoff and switch user then it's not working.
I have checked service logs for checking where the issue is.
So I found this statement in Run method
- IntPtr primaryToken = GetCurrentUserToken();
- if (primaryToken == IntPtr.Zero) { return; }
When user logged in then primaryToken is good but when signout or switch user then it is IntPtr.Zero.
Then I have checked GetCurrentUserToken method. and I found that this method is creating token for current logged in user token. that's why this is not working after logoff.
But I want printing after logoff.
In this Run method CreateProcessAsUser is used for creating print process.
But I don't know how can I create process without user. There is a method CreateProcess. Perhaps it will create process without user token I don't know much about it. Found this here.
But it is also not working. Even it is not working while user logged in.
I want to print pdf files in some interval using windows services. And It should be keep working after user logoff or switch user or lock.
Anyone know how can I achieve this?
Thanks