Duplicate PrintJob.JobID on PrintQueueWatch .Net library - c#

First of all, I work on windows XP, excel 2003, VS 2010, .NET 4.0 and I gather information of every print using PrintQueueWatch .Net library.
What I have seen so far is, when I print an excel active sheet with more than one copies jobdeleted event fires more than one. What I expected was that because I print one document one jobID would be made for the whole session but job deleted is fired for every single copy. So If I print one page with 3 copies I get at least 3 jobIDs. The real problem is now. When I print one page with 3 for example copies after the first copy the other 2 copies get twice in jobdeleted so I get exactly 3 unique PrintJob.jobID but 5 times(18, 19, 19, 20, 20).
My question is why job deleted is fired more than once in a print session and especially why in every copy.

The Microsoft Office applications actually do some behind the scenes stuff to take over from the standard printer libraries when handling copies. This allows them to, for example, offer page collation and copy collation options that the printer driver themselves do not offer.
They do this by (in many circumstances) creating a separate print job for each copy and these then process in the usual fashion with their own print job id, using the JOB_INFO_3 structure.
When a job is deleted but it still has linked jobs not yet deleted it raises the event but actually does not delete. Only when the whole chain is deleted does the actual delete function complete.
Unfortunately I never coded any handling of JOB_INFO_3 but should you wish so to do the code is on GitHub.

Related

Traversing all files in windows pc and create report due to creation date in an efficient way in C#

My client wanted me to write a simple desktop app such that :
User will select a date. Then the program will travel all files in the windows pc and then create an excel report for all files which are created before the selected date.
Actually it seems really simple application. However, my client told me he has petabytes of data which made me think the app would run for hours even days. I need a really smart solution for that. For instance despite the possibility of a crash or unexpected error etc, I am planning to divide the report into parts and create a new excel file for each 50000 records. In addition, the application should continue from where it left off. In another words, if the application is closed, the application should not start scanning all over again. What is the most logical way for the program to work efficiently and continue from where it left off? What comes to my mind is to put a tick on the folders so that the already looked folders are not looked at again. What is the best way to implement this logic in C#? Is it efficient to create a separate list for the visited folders and then first look if the folder is alreay in list? Which data structures would you use for this problem and how would you implement this?
Thanks.

How to trigger VBA code in Access when underlying SQL table is updated?

Background
We have a legacy MS Access application that uses MS SQL tables as the backend, and prints a report (product label) on demand based on a user action. This works as expected, and we'd prefer not to change this part.
I have a new standalone (C# Windows Forms) application running on a different PC that performs some mostly unrelated actions, but requires the user to print the above mentioned label towards the end of the process.
Question
Instead of having the user switch to the legacy Access app on a different PC (which may be at a different location), how can I trigger the Access VBA that runs the report when data is updated from the standalone C# application?
One opproach
I was thinking I could create a table RequestedLabels with columns LabelId, PrinterId. The standalone app would insert a row to request a label, and the MS Access app would query the table at small intervals to see if there are any new labels to be printed for this instance.
However, there are several things I don't like about this approach:
The label should be printed immediately after the request so my query interval would have to be quite small (1-2s max). Even at 2s the delay would be a nuisance. At higher rates I suspect this could interfere with the MS Access application's responsiveness.
This would be running on 10-20 machines at at time so the number of queries to the SQL server would be around 20/sec or more.
The user is only printing labels every few minutes, so most of the processing/network capacity required to do this is wasted.
A better approach
I was hoping for some way to have changes to the underlying data trigger a Form Event in MS Access, or trigger some VBA function that could print the labels on demand.
Caveats
The computers are across two subnets separated by a strict firewall and run mixed OSs both on and off the domain. RPC between PCs has proven to be tricky in the past due to the non-uniform setup.
I would prefer a solution that relies on updating the data on the SQL server, or some other MS SQL feature that both the C# and MS Access applications can take advantage of.
UPDATE:
Since there have been two votes to close, I have refined the wording to focus more clearly on triggering the VBA when the underlying data changes.
You can build a macro in MS Access to send the report to the printer. The report should already have the data you want to print.
Let's say your macro's name is mcrPrintReport
Then you can execute MS Access from the command line to open the Access DB file and run the macro like this:
PathToAccessExe PathToAccessFile /x MacroName
C:\Program Files\Microsoft Office\Office16\MSACCESS.EXE C:\AccessDB.accdb /x mcrPrintReport
You can then schedule this to run on an interval, maybe every 5 minutes, using the Task Scheduler on a dedicated PC.
See this related question also: Running Macro from .bat with another Access db open

Printer spooler api number of copies

I really could use some help, this is a question that alot of people are asking on the internet. I have different setups, tried different ways of testing, it's very frustrating.
First setup:
local printers
local running code
print from pdf or notepad: SUCCES (number of copies are 2)
print from word: FAILED (numberof copies is 1)
Second setup:
local printers that are shared
local running code
print from other computer to shared printers
number of copies isalways 1
Sowhat is everyone missing? What happens that some fields are missing while the printer still should know what to print? What does word that also happen when you print from another computer? Can someone tell me why somethings in windows are so terrible? Everythingshould pass the spooler, sowhy isthedata wrong?
Kinds regards!
A printer prints sheets and pages, so copies is converted to pages at some stage.
The notification data you get depends on both the application that is printing and the system and driver components handling the spooling and rendering. In my experience the data cannot be relied on, and the best data is obtained by parsing the spool file. This may or may not contain the number of copies.
Word has had the "copies problem" for a long time. There was a patch to supposedly fix this, but another opinion is that it's because it uses an unusual way of printing. I'll quote some of the link contents here:
With the infamous Word Copy Count bug… the dmCopies filed is 1 in the
SHD. The correct value is found in the DEVMODE record in the SPL file
(if it's an EMF spool).
The only other way i found was to monitor the PrintedPages field of
the JOB_INFO_2 structure, when the job has been sent to the printer,
and see if it is a multiple of TotalPages.
[...]
What happens is not a Word bug, but a Windows bug. Word calls startDoc
always with copies set to 1. After that calls DocumentProperties and
makes the change in dmCopies and calls ResetDC to make the update. It
is a strange way of printing but not wrong. The problem is that the
shd file and printer_info is not updated with this information, just
keeps the Devmode info set on the StartDoc call.
But the call to the ResetDC generating a new DevMode is kept on the
SPL file. You can get that info too if you hook DocumentProperties
API calls.
Thank you for the answer. Is there a way of catching the document properties when they change?
The JOB_INFO_2 structure does have the same total_pages as pages_printed. So that is not a solution.
The SPL File does contain the QTY for the printer i tested on which is correct. BUT we tested on a lot of printers and we see the QTY is not Always set. So not a 100% solution. But already a good fallback.
So if i can catch the document properties without calling the SPL file that would be wonderful because i guess that's where everything is correct. Isn't it?

Copy to clipboard limitation

As many other question about this topic, I still didn't find something that could avoid my issue.
I'd like to know what are the limitations of the clipboard in term of copy paste processing in time and restrict its copy paste functionality for specific usage and program ID.
Because, I've been developping a software for my company that takes a template in Word/Excel and PowerPoint to make auto generated reports by replacing the picture every day and pasting the new graph and the picture which are in the template.
But, I'm afraid, because it seems to exist some limitations about the copy to clipboard
CopyBitmapToClipboard
ActiveWindow.View.PasteSpecial()
When I copy a table/image into my clipboard and paste it in Word/Excel/PowerPoint it is fine, but if I have now 10 parallel reports which are generated at the same time and use the mechanism of copy paste, it will happen that it will copy it in the Word/Excel/PowerPoint that is currently being used by another report.
Taking in consideration, I have 1 document, and the copy to clipboard of a table that is huge into powerpoint, would take the best case 1 second( which doesn't ), this would mean that in 1 day, I can generate a maximum of
1 copy paste procedure = 1 second
1minute = 60 second means 60 copy paste
1hour = 60min x 60 copy paste
1day = 24hours x 3600 copy paste
Means I have a total of 86400 copy paste/reports. Which is impossible. A document will never take minimum of 1 second to be complete( for reports which are about 20 pages, powerpoint with 30 slides, excel worksheet with 6sheets ). How to avoid that the content copied into clipboard will be pasted in the wrong document, since both documents use the paste fonction.
So, I'd like to know, if it is possible to give a reference into my clipboard, to tell him, to copy only the content inside his word/excel/powerpoint and not to copy what I just copied doing CTRL+C and to do CTRL+V in the wrong document?
At the moment, we have about 50 reports daily to generate( taking in consideration that few months ago we had 2 reports to generate ), which are scheduled in interval of 5 minutes, but what will happen the day we will have 86400 daily reports to generate? The copy paste fonction will screw up all reports and paste in the wrong report. I might not be there to assist it, but I'd like to prevent that impact.
I was writing my software in C#/.NET, but I can't write inside it to catch if a current schedule/report is being generated, because I run a .bat that does the creation of the report with the program I wrote.
**Edited:
Content of my .bat is:
myprogram.exe /objectsourceprogram="" /sourcefile="my template.doc/xls/ppt" /destinationfile="my destination.doc/xls/ppt"
I'm only scheduling my batch file, the only thing that can be done is, waiting that one scheduling is being completed before starting the next one, but this will create intervales
I've dealt with auto-generated reports in Word and Excel as well. You're doing it the slow way, no wonder it's slow - .NET COM interop is quite slow as it its and then your process utilizes other threads, so now you have to take marshalling and synchronizing between threads since Office is single-threaded.
Copy/paste is a high-level, user function and you can use it as a hack but relying on it as a primary way of executing your task is a poor choice.
Better choice: Office APIs (VSTO, anyone?) - I'm pretty sure whatever you've come up with in terms of reports is reproducible through APIs. Beware - too many API calls and your functions can work slower.
Best choice: OpenXML SDK. The learning curve here will likely be steep since you're still using Copy/Paste but the payoff is that your document processing time will be reduced a couple orders of magnitude.

Reconnect to a disconnected Excel COM Interop instance

I have a 3rd party app that is exporting data to Excel using the Excel COM Interop. There is a bug in their program causing it to fail before it makes the Excel instance visible. However from where the exception is happening, according to the displayed stack trace, the information I need has already been written out to the Excel Worksheet.
Is there any way to use the Microsoft.Office.Interop.Excel namespace to connect to a existing excel instance instead of it generating it's own? Or is there any other way I could make that orphaned Excel instance visible so I can save what it completed?
As a note, the EXCEL.exe is still visible in task manager after the program closes so the instance is still live and running after the app has disconnected.
More Details: What the program is doing is exporting a report from it's own (proprietary) database, however for some reason some record in the database became malformed and causes a Integer Overflow error to occur while the report is generating. Looking at the stack trace it appears this integer overflow is happing while it is generating the summery at the end of the report.
For my uses I do not need the summary just the line items from the report, so I hoped to see what work it had done so far but the EXCEL.exe instance it was communicating with is not visible.
If I run the report for a different date range the report generates fine, it is just something about one record on one day that causes this specific set of inputs that causes it to fail.
The support contract with the provider of the app as expired and management is not interested in renewing it as we are in the process of switching to a new vendor (that is why the report is being generated, to be used as the data-source for the data conversion). So I have been tasked with "fixing it" so the data can be moved over.
Final Update: The reason I asked the question was solved. I was able to go through each record via the program itself and I found the record that had one of it's fields set to 16274176.00 (normal values are in the 100's (and don't ask me why what appears to be a float causes a Integer Overflow error)), once I changed that to 0.00 the report printed fine. However I still would like to know if there is a answer to my original question as I think it would be a useful tool in my toolbox.
In regards to your original question, I think it actually might be a possible duplicate of what have been asked here: Get instance of Excel application with C# by Handle
A couple of the answers given points to this blog post: Launching Office Apps Programmatically which gives you a palette of options of how to connect to an already running Office application from managed code.
The blog post as well as the answers given also contains sample code to illustrate how this can be done.

Categories