TECHNOLOGIES
FORUMS
JOBS
BOOKS
EVENTS
INTERVIEWS
Live
MORE
LEARN
Training
CAREER
MEMBERS
VIDEOS
NEWS
BLOGS
Sign Up
Login
No unread comment.
View All Comments
No unread message.
View All Messages
No unread notification.
View All Notifications
Answers
Post
An Article
A Blog
A News
A Video
An EBook
An Interview Question
Ask Question
Forums
Monthly Leaders
Forum guidelines
Manoj Kumawat
NA
244
2.4k
Print Pdf from windows service and keep working after logoff
Jan 25 2018 4:29 AM
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
/// <summary>
/// Initializes a new instance of the <see cref="ProcessStarter"/> class.
/// </summary>
public
ProcessStarter() { }
/// <summary>
/// Initializes a new instance of the <see cref="ProcessStarter"/> class.
/// </summary>
/// <param name="processName">Name of the process.</param>
/// <param name="fullExeName">Full name of the exe.</param>
public
ProcessStarter(
string
processName,
string
fullExeName)
{
processName_ = processName; processPath_ = fullExeName; }
/// <summary>
/// Initializes a new instance of the <see cref="ProcessStarter"/> class.
/// </summary>
/// <param name="processName">Name of the process.</param>
/// <param name="fullExeName">Full name of the exe.</param>
/// <param name="arguments">The arguments.</param>
public
ProcessStarter(
string
processName,
string
fullExeName,
string
arguments)
{
processName_ = processName; processPath_ = fullExeName; arguments_ = arguments; }
/// <summary>
/// Gets the current user token.
/// </summary>
/// <returns></returns>
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; }
/// <summary>
/// Runs this instance.
/// </summary>
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);
}
/// <summary>
/// Stops this instance.
/// </summary>
public
void
Stop()
{
Process[] processes = Process.GetProcesses();
foreach
(Process current
in
processes)
{
if
(current.ProcessName == processName_)
{
current.Kill();
}
}
}
/// <summary>
/// Waits for exit.
/// </summary>
/// <returns></returns>
public
int
WaitForExit()
{
WaitForSingleObject(processInfo_.hProcess, INFINITE);
int
errorcode = GetLastError();
return
errorcode;
}
#region IDisposable Members
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public
void
Dispose()
{
}
#endregion
private
string
processPath_ =
string
.Empty;
private
string
processName_ =
string
.Empty;
private
string
arguments_ =
string
.Empty;
private
PROCESS_INFORMATION processInfo_;
/// <summary>
/// Gets or sets the process path.
/// </summary> ///
<value>The process path.</value>
public
string
ProcessPath
{
get
{
return
processPath_;
}
set
{
processPath_ = value;
}
}
/// <summary>
/// Gets or sets the name of the process.
/// </summary>
/// <value>The name of the process.</value>
public
string
ProcessName
{
get
{
return
processName_; }
set
{ processName_ = value; }
}
/// <summary>
/// Gets or sets the arguments.
/// </summary>
/// <value>The arguments.</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
Reply
Answers (
1
)
Get the ID of a Newly Inserted Row
AjaxControlToolKit not working after publishing