PrintQueue.Refresh() 抛出错误指出 "The calling thread cannot access this object because a different thread owns it"
PrintQueue.Refresh() throws error stating that "The calling thread cannot access this object because a different thread owns it"
我正在尝试创建 Windows 服务,打印,但我似乎卡在了刷新PrintQueue。
它表示另一个线程拥有该对象。
这是我得到的错误
at System.Windows.Threading.Dispatcher.VerifyAccess()
at System.Printing.PrintQueue.VerifyAccess()
at System.Printing.PrintQueue.Refresh()
at PrinterService.Service.<Print>d__20.MoveNext() in C:\Users\user\source\repos\PrinterService\PrinterService\Service.cs:line 237
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at PrinterService.Service.<timer_Elapsed>d__16.MoveNext() in C:\Users\user\source\repos\PrinterService\PrinterService\Service.cs:line 70
at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<>c.<ThrowAsync>b__6_1(Object state)
at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
at System.Threading.ThreadPoolWorkQueue.Dispatch()
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
这是代码
public Service1()
{
InitializeComponent();
timer = new Timer(30*1000); //Set time, in this case it's gonna be 30 seconds
timer.Elapsed += timer_Elapsed; //Add event that runs after the above set time elapsed
// We don't want the timer to start ticking again till we tell it to.
timer.AutoReset = false;
}
protected override void OnStart(string[] args)
{
timer.Start();
}
private void timer_Elapsed(object sender, ElapsedEventArgs e)
{
new Thread(async () =>
{
timer.AutoReset = false; //Stop timer while we do our stuff
List<string> pdfList = await GetPrintJobs(); //Get print jobs
List<string> responses = await Print(pdfList); //Print and collect responses
if (responses.Count > 0) //If there is any successful prints we respond
foreach (string response in responses)
await Response(response, "success");
timer.AutoReset = true; //Start countdown when we finished doing our stuff
}).Start();
}
private static async Task<List<string>> Print(List<string> pdfList)
{
List<string> successfullPrints = new List<string>();
using (LocalPrintServer printServer = new LocalPrintServer(PrintSystemDesiredAccess.AdministrateServer))
{
string localPrinter = printServer.DefaultPrintQueue.Name; //Default printer's name
using (PrintQueue queue = new PrintQueue(printServer, localPrinter, PrintSystemDesiredAccess.AdministratePrinter))
{
while (queue.NumberOfJobs > 0)
{
DeletePrinterJobQueue();
queue.Refresh(); //FIRST ERROR IS THROWN HERE
}
for (int i = 0; i < pdfList.Count; i++)
{
//Start printing
await new PDFtoPrinterPrinter().Print(new PrintingOptions(localPrinter, pdfList[i]));
queue.Refresh(); //ANOTHER ERROR HERE
bool error = false;
string reasonOfError = null;
PrintSystemJobInfo jobInfo = queue.GetPrintJobInfoCollection().FirstOrDefault(x => x.Name.Equals(nameOfFile));
if (jobInfo == null)
error = true;
else
{
while (!error && jobInfo != null) //While the job exists AND there is no error
{
/*
* ...check statuses
* ...of the PrintQueue
*/
queue.Refresh(); //ANOTHER ERROR HERE
jobInfo = queue.GetPrintJobInfoCollection().FirstOrDefault(x => x.Name.Equals(nameOfFile)); //THIS LINE THROWS THE SAME ERROR AS THE REFRESH ONE
}
}
queue.Refresh(); //ANOTHER ERROR HERE
//if there is no error, we add the file's ID to the list, else we send an error response
if (!error)
successfullPrints.Add(nameOfFile);
else
{
await Response(nameOfFile, reasonOfError);
break;
}
}
}
}
return successfullPrints;
}
protected override void OnStop()
{
timer.Stop();
}
一个奇怪的事情是有时第一次刷新运行良好,它只在第二次或第三次时抛出错误。
我认为问题与事件有关,也许?
任何帮助将不胜感激!
由于您正在处理线程仿射组件,我的建议是在启动服务的线程上同步完成所有工作。换句话说,不要使用 Timer
,不要使用 Thread
构造函数,也不要使用 async/await。要 运行 在当前线程上定期执行一些工作,您可以执行一个循环,并使用 Thread.Sleep
方法在循环内注入延迟:
protected override void OnStart(string[] args)
{
while (true)
{
// Here do the periodic work
Thread.Sleep(30 * 1000);
}
}
当您必须调用像 PDFtoPrinterPrinter.Print
这样的异步方法时,不要 await
它。而是使用 .GetAwaiter().GetResult()
技巧同步等待它:
new PDFtoPrinterPrinter()
.Print(new PrintingOptions(localPrinter, pdfList[i])).GetAwaiter().GetResult();
这不是最复杂的方法,但应该足以完成工作。
我正在尝试创建 Windows 服务,打印,但我似乎卡在了刷新PrintQueue。
它表示另一个线程拥有该对象。
这是我得到的错误
at System.Windows.Threading.Dispatcher.VerifyAccess()
at System.Printing.PrintQueue.VerifyAccess()
at System.Printing.PrintQueue.Refresh()
at PrinterService.Service.<Print>d__20.MoveNext() in C:\Users\user\source\repos\PrinterService\PrinterService\Service.cs:line 237
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at PrinterService.Service.<timer_Elapsed>d__16.MoveNext() in C:\Users\user\source\repos\PrinterService\PrinterService\Service.cs:line 70
at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<>c.<ThrowAsync>b__6_1(Object state)
at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
at System.Threading.ThreadPoolWorkQueue.Dispatch()
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
这是代码
public Service1()
{
InitializeComponent();
timer = new Timer(30*1000); //Set time, in this case it's gonna be 30 seconds
timer.Elapsed += timer_Elapsed; //Add event that runs after the above set time elapsed
// We don't want the timer to start ticking again till we tell it to.
timer.AutoReset = false;
}
protected override void OnStart(string[] args)
{
timer.Start();
}
private void timer_Elapsed(object sender, ElapsedEventArgs e)
{
new Thread(async () =>
{
timer.AutoReset = false; //Stop timer while we do our stuff
List<string> pdfList = await GetPrintJobs(); //Get print jobs
List<string> responses = await Print(pdfList); //Print and collect responses
if (responses.Count > 0) //If there is any successful prints we respond
foreach (string response in responses)
await Response(response, "success");
timer.AutoReset = true; //Start countdown when we finished doing our stuff
}).Start();
}
private static async Task<List<string>> Print(List<string> pdfList)
{
List<string> successfullPrints = new List<string>();
using (LocalPrintServer printServer = new LocalPrintServer(PrintSystemDesiredAccess.AdministrateServer))
{
string localPrinter = printServer.DefaultPrintQueue.Name; //Default printer's name
using (PrintQueue queue = new PrintQueue(printServer, localPrinter, PrintSystemDesiredAccess.AdministratePrinter))
{
while (queue.NumberOfJobs > 0)
{
DeletePrinterJobQueue();
queue.Refresh(); //FIRST ERROR IS THROWN HERE
}
for (int i = 0; i < pdfList.Count; i++)
{
//Start printing
await new PDFtoPrinterPrinter().Print(new PrintingOptions(localPrinter, pdfList[i]));
queue.Refresh(); //ANOTHER ERROR HERE
bool error = false;
string reasonOfError = null;
PrintSystemJobInfo jobInfo = queue.GetPrintJobInfoCollection().FirstOrDefault(x => x.Name.Equals(nameOfFile));
if (jobInfo == null)
error = true;
else
{
while (!error && jobInfo != null) //While the job exists AND there is no error
{
/*
* ...check statuses
* ...of the PrintQueue
*/
queue.Refresh(); //ANOTHER ERROR HERE
jobInfo = queue.GetPrintJobInfoCollection().FirstOrDefault(x => x.Name.Equals(nameOfFile)); //THIS LINE THROWS THE SAME ERROR AS THE REFRESH ONE
}
}
queue.Refresh(); //ANOTHER ERROR HERE
//if there is no error, we add the file's ID to the list, else we send an error response
if (!error)
successfullPrints.Add(nameOfFile);
else
{
await Response(nameOfFile, reasonOfError);
break;
}
}
}
}
return successfullPrints;
}
protected override void OnStop()
{
timer.Stop();
}
一个奇怪的事情是有时第一次刷新运行良好,它只在第二次或第三次时抛出错误。
我认为问题与事件有关,也许?
任何帮助将不胜感激!
由于您正在处理线程仿射组件,我的建议是在启动服务的线程上同步完成所有工作。换句话说,不要使用 Timer
,不要使用 Thread
构造函数,也不要使用 async/await。要 运行 在当前线程上定期执行一些工作,您可以执行一个循环,并使用 Thread.Sleep
方法在循环内注入延迟:
protected override void OnStart(string[] args)
{
while (true)
{
// Here do the periodic work
Thread.Sleep(30 * 1000);
}
}
当您必须调用像 PDFtoPrinterPrinter.Print
这样的异步方法时,不要 await
它。而是使用 .GetAwaiter().GetResult()
技巧同步等待它:
new PDFtoPrinterPrinter()
.Print(new PrintingOptions(localPrinter, pdfList[i])).GetAwaiter().GetResult();
这不是最复杂的方法,但应该足以完成工作。