I am working on some code that monitors the printer queue and then uses the event information to collect some specifics about the job, including # pages, orientation, whether or not it was color and how many copies were requested.
I catch the events using the code from Merrion Computing (which is now open source); which handles the interop.
In the case of Color, it is supposed to be stored in JOB_INFO_2.pDeviceMode.dmColor; however no matter how I submit the job (color or black and white using the printer properties printing from several apps, including word and adobe) it always indicates color. I debugged through that code directly, and the interop appears to be correct, so then I used the JobId from the event to query the print system via .NET with the code (below); and it contains exactly the same settings for copies and color.
int iJobId = e.PrintJob.JobId;
LocalPrintServer printServer = new LocalPrintServer();
PrintQueueCollection queueCollection = printServer.GetPrintQueues();
foreach (PrintQueue queue in queueCollection)
{
queue.Refresh();
if(queue.FullName.Equals(e.PrintJob.PrinterName,StringComparison.OrdinalIgnoreCase))
{
int? iPageCount;
PrintJobInfoCollection jobs = queue.GetPrintJobInfoCollection();
foreach(PrintSystemJobInfo job in jobs)
{
job.Refresh();
if(job.JobIdentifier==iJobId)
{
iPageCount = job.NumberOfPages;
}
}
//-- Found the Printer...
int? iCopyCount=queue.CurrentJobSettings.CurrentPrintTicket.CopyCount;
PageOrientation? eOrientation = queue.CurrentJobSettings.CurrentPrintTicket.PageOrientation;
OutputColor? eColor = queue.CurrentJobSettings.CurrentPrintTicket.OutputColor;
Debug.WriteLine("queue=" + queue.FullName + ", Copies=" + iCopyCount.Value + ",Color=" + eColor.ToString() + ", pagecount=" + "unk" /*iPageCount.Value*/ + ", Orientation=", eOrientation.ToString());
Debug.WriteLine("---");
}
}
Has anyone seen a reliable way to retrieve the number of copies and page count (preferably using .NET) for a specific printer job?
I
I did find this post describing the same type of problem, but there wasn't a resolution there.
Determine current print job color using C#
It should also be noted that the WMI Code from the above article also returns color.
I went in an enabled the eventlog for printing (http://www.papercut.com/kb/Main/LogPrintJobsInEventViewer). Looking at the details of the print event; the color setting is as expected "2", which indicates grayscale.
It is pretty clear that the windows subsystem is receiving the requested setting; however I have been unsuccessful to retrieve the value using WMI, System.Printing's namespace, or the interop from Merrion's print monitoring library where the values all indicate that the job is color with the correct number of pages and copies.
Is it possible to grab the spool file generated for this print to check that it is setting the dmColor setting itself?
The setting you are getting from the event log, 2, corresponds to DMCOLOR_COLOR not DMCOLOR_MONOCHROME so it seems the colour setting in the log thinks it is colour too.
It may be that the printer driver is being a bit sneaky in submitting the job as colour when it creates it but then sending a "set device settings" message in the spool that changes it to monochrome? If so there should be an SPT_DEVMODE record in the spool file.
Check this article for a spool file reader: http://www.codeproject.com/Articles/10586/EMF-Printer-Spool-File-Viewer
You need to refresh your jog until the flag IsSpooling becomes false.
for (int i = 0; i < jobs.Count(); i++)
{
try
{
int timeOut = 20000;
var jobInfo = jobs.ElementAt(i);
while (jobInfo.IsSpooling && timeOut > 0)
{
Thread.Sleep(100);
timeOut-=100;
jobInfo.Refresh();
} var pages = Math.Max(jobInfo.NumberOfPages,jobInfo.NumberOfPagesPrinted);
}
}
Related
I have a service which prints. Up until now the service has been printing using the WPF System.Windows.Controls.PrintDialog.PrintDocument method however due to various issues (performance, windows update bugs, 32 bit service on 64bit system issues etc) I am converting to use the traditional System.Drawing.Printing.PrintDocument method.
As this is running as a service I want this to always print using the default printer preferences (which include things like media settings and print speed for industrial label printer such as the Intermec/Honewell PM43)
Previously I had done this using PrintDialog.PrintTicket = PrintQueue.DefaultPrintTicket.Clone
However I cannot find the equivalent method in System.Drawing.Printing.PrintDocument and the service is not picking up the default printer preferences as set in the printer properties (specifically Print Speed in this case)
So what is the equivalent of PrintDialog.PrintTicket = PrintQueue.DefaultPrintTicket.Clone in System.Drawing.Printing.PrintDocument?
The following question helped me find an answer
Can't change DEVMODE of a printer
//Get the registry key containing the printer settings
var regKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("System\\CurrentControlSet\\Control\\Print\\Printers\\" + PrinterName);
if (regKey != null)
{
//Get the value of the default printer preferences
var defaultDevMode = (byte[])regKey.GetValue("Default DevMode");
//Create a handle and populate
var pDevMode = Marshal.AllocHGlobal(defaultDevMode.Length);
Marshal.Copy(defaultDevMode, 0, pDevMode, defaultDevMode.Length);
//Set the printer preferences
pd.PrinterSettings.SetHdevmode(pDevMode);
//Clean up
Marshal.FreeHGlobal(pDevMode);
}
I'm pretty new to c#, I want to make a program that alerts me if I prefixed window sound volume become too high, for example, I have Spotify running in the background suddenly a high pitch sound then i get an alert, is this possible to do for in a low-level way that I can understand?
I already tried, an open source code that uses cscore, I did make some advancement but its way to advance for me to even keep going with that, this is where the source code I use:
Getting individual windows application current volume output level as visualized in audio Mixer
I made it, so it sends a message box with the window name that went to high on sound, but it only worked 1 time after the first time I didn't get any more message boxes, if I could just make it so it keeps sending message boxes would be perfect for me
Edit
I downloaded the source code of the program linked here, it's at the bottom of the link
I changed
var value = audioMeterInformation.GetPeakValue();
to something like 0.9
and added a messagebox around here:
using (var audioMeterInformation = session.QueryInterface<AudioMeterInformation>()) {
var value = audioMeterInformation.GetPeakValue();
if (value != 0) {
if (process != null) {
seenPids.Add(sessionid);
List<double> samples;
if (!sessionIdToAudioSamples.TryGetValue(sessionid, out samples)) {
samples = new List<double>();
sessionIdToAudioSamples[sessionid] = samples;
if(process.MainWindowTitle == "NAME OF MY WINDOW")
{
MessageBox.Show("true");
}
}
var val = audioMeterInformation.GetPeakValue();
samples.Add(val);
truncateSamples(samples);
I'm getting the message box, but just 1 time, if the high volume sound happens again it won't show the message box again, it just happens once per window.
I have impinj speedway reader and I'm using impinj Ocatne SDK for .net and visual studio 2013 (c#) in order to test and deploy the device. As a first exercise, i executed the example "readtags (described below) of Ocatne SDK, so the reader reads the tags many times until I give up running. However, I would like to know how the reader can read tags only once
Thanks
static void Main(string[] args)
{
try
{
// Connect to the reader.
// Change the ReaderHostname constant in SolutionConstants.cs
// to the IP address or hostname of your reader.
reader.Connect(SolutionConstants.ReaderHostname);
// Get the default settings
// We'll use these as a starting point
// and then modify the settings we're
// interested in.
Settings settings = reader.QueryDefaultSettings();
// Tell the reader to include the antenna number
// in all tag reports. Other fields can be added
// to the reports in the same way by setting the
// appropriate Report.IncludeXXXXXXX property.
settings.Report.IncludeAntennaPortNumber = true;
// The reader can be set into various modes in which reader
// dynamics are optimized for specific regions and environments.
// The following mode, AutoSetDenseReader, monitors RF noise and interference and then automatically
// and continuously optimizes the reader’s configuration
settings.ReaderMode = ReaderMode.AutoSetDenseReader;
settings.SearchMode = SearchMode.DualTarget;
settings.Session = 2;
// Enable antenna #1. Disable all others.
settings.Antennas.DisableAll();
settings.Antennas.GetAntenna(1).IsEnabled = true;
// Set the Transmit Power and
// Receive Sensitivity to the maximum.
settings.Antennas.GetAntenna(1).MaxTxPower = true;
settings.Antennas.GetAntenna(1).MaxRxSensitivity = true;
// You can also set them to specific values like this...
//settings.Antennas.GetAntenna(1).TxPowerInDbm = 20;
//settings.Antennas.GetAntenna(1).RxSensitivityInDbm = -70;
// Apply the newly modified settings.
reader.ApplySettings(settings);
// Assign the TagsReported event handler.
// This specifies which method to call
// when tags reports are available.
reader.TagsReported += OnTagsReported;
// Start reading.
reader.Start();
// Wait for the user to press enter.
Console.WriteLine("Press enter to exit.");
Console.ReadLine();
// Stop reading.
reader.Stop();
// Disconnect from the reader.
reader.Disconnect();
}
catch (OctaneSdkException e)
{
// Handle Octane SDK errors.
Console.WriteLine("Octane SDK exception: {0}", e.Message);
}
catch (Exception e)
{
// Handle other .NET errors.
Console.WriteLine("Exception : {0}", e.Message);
}
}
static void OnTagsReported(ImpinjReader sender, TagReport report)
{
// This event handler is called asynchronously
// when tag reports are available.
// Loop through each tag in the report
// and print the data.
foreach (Tag tag in report)
{
Console.WriteLine("voici l'antenne : {0}, EPC : {1} ", tag.AntennaPortNumber, tag.Epc);
}
}
You can write your program to filter and report tag reads in any number of ways. Impinj provides sample code to make it easier for you to get started in terms of data output.
Also, download the latest version of the Octane SDK, open the folder, navigate to "examples", then navigate to (and open) "ReadTagsFiltered" for sample code related to filtering tag reads.
If you set Search Mode to 'Single Target' and use Session 2, the reader will (physically) only read a tag once when it enters the field, and will read it again when it has been out of the field for more than a few seconds. This will enhance the read performance as well (as the reader as more time to read other tags).
You can of course also filter in software, and track which EPCs has already been read.
For more background on Session in RFID, please read here: https://github.com/rainrfid/overview/wiki/2.-The-protocol
When you use Session 2 and Single Target, the tag will respond only once, until it has been out of the field for more than a certain amount of time.
I am trying to write a WLAN fingerprinting program using NativeWifi in C#. To do this i run a loop to get the wlan information many times and then later use matlab to average / analyze the data.
The problem is that i get all the same values, even as i move about the house, when the program is running. From the internet i've seen that there is a cache that stores the data of available networks. I was wondering if there is a system call which resets this cache.
I have also seen this using the cmd call
netsh wlan show networks mode=bssid
this gives me the same values until i open the available wifi networks in my OS and if i run it again after, it will give different values.
edit: This system will be for my use only, so i would be comfortable starting over on a linux platform if there is a known library that can handle this for me. I don't even know what to google to even get the information, though. Anything related to "network cache" takes me to help threads of unrelated topics...
I will provide the relevant part of my code below:
public void get_info_instance(StreamWriter file)
{
try
{
foreach (WlanClient.WlanInterface wlanIface in client.Interfaces)
{
Wlan.WlanBssEntry[] wlanBssEntries = wlanIface.GetNetworkBssList();
foreach (Wlan.WlanBssEntry network in wlanBssEntries)
{
int rss = network.rssi;
byte[] macAddr = network.dot11Bssid;
string tMac = "";
for (int i = 0; i < macAddr.Length; i++)
{
tMac += macAddr[i].ToString("x2").PadLeft(2, '0').ToUpper();
}
file.WriteLine("Found network: " + System.Text.ASCIIEncoding.ASCII.GetString(network.dot11Ssid.SSID).ToString());
file.WriteLine("Signal: " + network.linkQuality + "%");
file.WriteLine("BSS Type: " + network.dot11BssType + ".");
file.WriteLine("RSSID: " + rss.ToString());
file.WriteLine("BSSID: " + tMac);
file.WriteLine(" ");
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Internally, netsh is powered by this API. What this means, is that calling netsh wlan show networks mode=bssid just returns the cache of the networks that showed up during the last scan. This is what you've discovered.
This means that in order to refresh this cache, you need to trigger a scan. If your C# library you are using includes it, you could make this happen on demand with a call to WlanScan. I am not sure which C# wrapper you are using, but it probably includes this function. When you get a scan complete notification (register with source WLAN_NOTIFICATION_SOURCE_ACM and look out for wlan_notification_acm_scan_list_refresh), the cache should be updated.
If you let me know which C# library you are using, maybe I can point you to the relevant functions.
You mentioned that opening the available networks causes the cache to refresh. This is because opening the available networks triggers a call to WlanScan.
Profiles are not relevant to the available network list -- profiles are what the Wlan service uses to keep track of which networks are configured on your machine -- deleting them does not make WlanSvc scan again. It may be a coincidence that deleting them happens to coincide with a scan, but it is more of a side effect than the designed usage.
edit: to subscribe to notifications using the Managed Wifi API you are using, this snippet should work:
wlanIface.WlanNotification += wlanIface_WlanNotification;
And the callback:
static void wlanIface_WlanNotification(Wlan.WlanNotificationData notifyData)
{
if (notifyData.notificationCode == (int)Wlan.WlanNotificationCodeAcm.ScanComplete)
{
Console.WriteLine("Scan Complete!");
}
}
You can test this by running this, then opening the available networks on Windows. You should see "Scan Complete" shortly after you open it each time. You can use a messagebox instead of Console.WriteLine if you prefer.
To trigger a scan yourself:
wlanIface.Scan();
for all
netsh wlan delete profile name=* i=*
you might not want to do it on all interfaces, and hard code the interface in there for faster result
Trying to programmatically get the private working set of a process.
Currently I am able to get the working set without issue but having trouble getting the private working set.
Here's method:
private void GetProcessesForServer(string serverName)
{
var runningProcesses = new Process[0];
try
{
runningProcesses = Process.GetProcesses(serverName);
}
catch (Exception e)
{
ResultsPanel.Controls.Add(new Label { Text = string.Format("There was an error: {0}", e.GetBaseException().Message) });
}
IOrderedEnumerable<CustomProcess> processes = runningProcesses
.Select(process => new CustomProcess(process.Id, process.ProcessName, (process.WorkingSet64 / 1024)))
.ToList()
.OrderBy(process => process.ProcessName);
if (processes.Count() > 0)
ResultsLabel.Text = string.Format("Current running processes on {0}", ServerNamesDropDown.SelectedItem.Text);
ResultsGridView.DataSource = processes;
ResultsGridView.DataBind();
}
So I'm passing in a server name then trying to get all the running processes for that server then binding the list of processes to a grid view. Everything works without any issues however I need to get the private working set - similar to what you see in Windows Task manager - rather than the total working set.
Many thanks,
Tim
On Windows Vista and beyond there is the "Working Set - Private" performance counter in the "Process" category (see msdn).
Given you are on such a platform you could use the System.Diagonstics.PerformanceCounter class to query this information.
To establish a link between a process ID and a given performance counter instance, use the "ID Process" counter of a category. In other words: lookup the instance where the "ID Process" counter is your desired process ID, the read the value of the "Working Set - Private" counter.
Hint: if you need to query all values for all processes use the System.Diagonstics.PerformanceCounterCategory.ReadCategory() call instead, as it is much faster the reading individual counters for all processes/instances.
Update: There is an article on codeproject that shows how to calculate that value on XP/2000, if you must. I have not tested it, so don't blame me ;-)
Update 2: You may also want to checkout this stackoverflow question/answer.