I am using FindFirstPrinterChangeNotification and FindNextPrinterChangeNotification to catch printing events. However I have noticed that FindNextPrinterChangeNotification does not reliably returns all the events. I have found a guy with the same problem in this article.
Basically, when I debug my program, or put Sleep command like his suggestion when processing an event, FindNextPrinterChangeNotificationskips a lot of events. Also, most of the time I get a lot of SPOOLING status events but miss the DELETED status event (sometimes I get it, but most of the time I cannot), even though I already push the jobs to a Queue for later processing.
Does anyone have this problem too? Also, I am trying the Microsoft PDF Printer, The NumberOfPages increases as the SPOOLING events come, but the NumberOfPagesPrinted does not. Is it intended?
EDIT After some investigation, the events are not actually gone. If I call another print job, the previous events are fired (including the DELETING/DELETED status of previous print job). Can you please suggest what is the problem?
Here's the code for calling FindFirstPrinterChangeNotification:
//We got a valid Printer handle. Let us register for change notification....
_changeHandle = FindFirstPrinterChangeNotification(_printerHandle, (int)PRINTER_CHANGES.PRINTER_CHANGE_JOB, 0, _notifyOptions);
// We have successfully registered for change notification. Let us capture the handle...
_mrEvent.SafeWaitHandle = new Microsoft.Win32.SafeHandles.SafeWaitHandle(_changeHandle, true);
//Now, let us wait for change notification from the printer queue....
_waitHandle = ThreadPool.RegisterWaitForSingleObject(_mrEvent, new WaitOrTimerCallback(PrinterNotifyWaitCallback), _mrEvent, -1, true);
And this is for the FindNextPrinterChangeNotification:
_notifyOptions.Count = 1;
_notifyOptions.dwFlags = PRINTER_NOTIFY_OPTIONS_REFRESH;
int pdwChange = 0;
IntPtr pNotifyInfo = IntPtr.Zero;
bool bResult = FindNextPrinterChangeNotification(_changeHandle, out pdwChange, _notifyOptions, out pNotifyInfo);
I had the same issue then I tried:
_waitHandle = ThreadPool.RegisterWaitForSingleObject(_mrEvent, new WaitOrTimerCallback(PrinterNotifyWaitCallback), _mrEvent, -1, true);
with:
_waitHandle = ThreadPool.RegisterWaitForSingleObject(_mrEvent, new WaitOrTimerCallback(PrinterNotifyWaitCallback), _mrEvent, -1, false);
(false arg in the end)
and seems to work now
Related
I developing a Xamarin application, and I communicating an external custom device. My problem is very strange, firstly the application starting, and connecting automatically to device, so everything is fine. When i suddenly remove the battery from the external device, the bluetooth connection is broken, and it's working fine to, but when I turn on the external device again, my Xamarin application connecting to it very well well, but the subscriptions not working anymore.
I debugged it, but not calling anymore. I think the unsubscribe/subscribe process is wrong.
...
if (ble.GetConnectionStatus())
{
Device.BeginInvokeOnMainThread(() =>
{
...
ble.Adapter.DeviceConnectionLost -= Adapter_DeviceConnectionLost;
ble.Adapter.DeviceConnectionLost += Adapter_DeviceConnectionLost;
ble.PropertyChanged -= Ble_PropertyChanged;
ble.PropertyChanged += Ble_PropertyChanged;
data.PropertyChanged -= data_PropertyChanged;
data.PropertyChanged += data_PropertyChanged;
...
});
...
So it's so strange, because first time this working, when starting the app, but when I call it after reconnect that same subscription not working. So if its wrong, then why working this at very first time?
I have no error, just not fire the functions again after resubscribe.
So as you see, I need to "refresh" the subscription. Is there another way to solve this problem?
If that "button to recreate everything" works, then I see two alternatives.
Option 1:
Have such a button, so that user can manually "fix" the situation.
PRO: Gives the user a solution that is guaranteed to work.
CON: Requires user intervention.
Option 2:
Have a periodic timer, that decides whether/when to forcibly "fix" the situation.
PRO: Automatically recovers.
CON: Risks losing data, if forces a recovery at the same time data is arriving.
In pseudo-code, option 2 might be something like this:
// pseudo-code
static Timer timer = ..start a timer that has an event every 10 seconds.
OnTimerElapsed:
if (!eventSeenRecently)
ForceReset();
eventSeenRecently = false;
..whereever you receive data..
if (..has data..)
eventSeenRecently = true;
The concept is that you keep track of whether data continues to be received. If the device stops sending you information (but you believe it should be), then you "ForceReset" - whatever is needed to get everything going again.
DeviceConnectionLost should also set some flag, that you use to ForceReset when the device "comes back".
// pseudo-code
DeviceConnectionLost:
resetNeeded = true;
OnTimerElapsed:
if (resetNeeded && ..test that device is available again..) {
ForceReset();
resetNeeded = false;
}
Perhaps this custom device has some option or info that can help.
For example, there might be a way to query some id or other info, so you can discover that the device is now "different", in a way that requires the reset. Then the timer does that query, and uses that info to decide to reset.
I got an issue and I don't know why it appears.
I have a InputAdapter which receives randomly generated events for testing purposes.
The following code creates a query which drops a lot of events. which I actually want to be kept.
var atgs = new AdvanceTimeGenerationSettings(config.Input.EventCount,
TimeSpan.FromSeconds(config.Input.Delay), true);
var ats = new AdvanceTimeSettings(atgs, null, AdvanceTimePolicy.Adjust);
var dstream = CepStream<Dataclass>.Create("Data Input Stream", typeof (InAdapterFactory),
config.Input, EventShape.Point, ats);
Query output = dstream.ToQuery(myApplication,
"Sample unbounded query",
"Query with no output adapter",
EventShape.Point,
StreamEventOrder.FullyOrdered);
output.Start();
var instream = output.ToStream<Dataclass>();
Does anyone have an idea why between the DataInputStream and DatainputStream_CleanseInput only a fifth of all events get passed through? See the following pic. Is there a way to avoid that?
https://dl.dropboxusercontent.com/u/15482726/CleanseIssue.jpg
I am very grateful for any help.
Best regards,
Joe
Those are going to be events dropped due to CTI violations. While you have your AdvanceTimePolicy set to Adjust, this only applies to Interval events that cross the CTI span in question. That is, if the Interval event has a start time before the last-issued CTI and an end time after the last-issued CTI, the start time (only) of the Interval event will be adjusted. Point events are always dropped.
We have an application that has a primary window, it can launch multiple other windows, in new browsers. We are using a silverlight application as a coordinating server in the primary window to close all windows that are part of the app, regardless of the way they are opened (we can't guarantee it was via window.open so don't always have a handle to the window in javascript).
On log out, we want to signal all the other windows to perform an auto-save, if necessary, then close down.
So all windows have a silverlight app, they coordinate using localmessagesenders. However, these are asynchronous:
private void ProcessAutosave()
{
foreach (string s in _windows)
{
SendMessage(s, "notify-logout");
}
// code here quoted later...
}
// sendasynch doesn't send until the method terminates, so have to do it in it's own function.
private void SendMessage(string to, string message)
{
var lms = new LocalMessageSender(to);
lms.SendCompleted += new EventHandler<SendCompletedEventArgs>(SenderSendCompleted);
lms.SendAsync(message);
}
Since the ProcessAutosave is called from a javascript onunload event which can't be cancelled, we need this to be synchronous and not complete before we have a response processed from each sub-window so the session state will still be valid etc.
In the SenderSendCompleted we remove items from _windows when they have said they're done.
So I added a loop on the end:
while(_windows.Count > 0) {
Thread.Sleep(1)
}
However, that never terminates, unless I put an iteration counter on it.
Am I the victim of a compiler optimisation meaning the changes in SenderSendCompleted do not affect that while loop, or, have I fundamentally misunderstood something? Or missed something obvious that's staring me in the face?
It sounds like a subtle verson of a race situation due to going sync/async. Couldn't the process in queston also receive notifications from the windows that they have received the message and are shutting down? Once all of the counter messages have been received, then the main app could shut down without the busy wait at the end(?).
I have found a way to work round. However, this does not really "solve" the problem generally, just in my case, which is also only supporting internet explorer.
function WindowCloseEventHandler()
{
var app = // get silverlight app handle...
app.doAutoSave();
var params = 'whatever you need';
var args = new Object();
args.hwnd = window;
window.showModalDialog('blocker.aspx',args,params);
}
function checkAutoSave()
{
var app = // get silverlight app handle...
return app.autosavecomplete();
}
Then in blocker.aspx we display a static "performing logout handlers" type message and do:
function timerTick()
{
if(window.dialogArguments.hwnd.checkAutoSave()) {
window.close();
} else {
setTimeout(timerTick, 500);
}
}
And start the timer on window load.
The child window's silverlight apps are notified to start an autosave, then they notify the parent when they are done. We then poll the parent's status from a modal dialog, which blocks the termination of the WindowCloseEventHandler() which we have wired up to the onclose event of the body.
It's hacky and horrible, but it means silverlight stays asynchronous and we're using a javascript timer so the javascript isn't loading the system.
Of course if the user closes the modal dialogue, there is a potential for issue.
I start the Windows On-Screen-Keyboard like that:
s_onScreenKeyboard = new Process();
s_onScreenKeyboard.StartInfo = new ProcessStartInfo("osk.exe");
s_onScreenKeyboard.EnableRaisingEvents = true;
s_onScreenKeyboard.Exited += new EventHandler(s_onScreenKeyboard_Exited);
s_onScreenKeyboard.Start();
This works fine, but when I try to stop it using the following code, it does not work, i.e. the OSK keeps running and the method returns false:
s_onScreenKeyboard.CloseMainWindow();
if (!s_onScreenKeyboard.HasExited)
{
if (!s_onScreenKeyboard.WaitForExit(1000))
{
s_onScreenKeyboard.Close();
//s_onScreenKeyboard.Kill();
}
}
When uncommenting s_onScreenKeyboard.Kill(); it is closed, but the problem is that osk.exe obviously uses another process called "msswchx.exe" which is not closed if I simply kill the OSK process. This way, I would end up with hundreds of these processes which is not what I want.
Another strange thing is that the CloseMainWindow() call worked at some time, but then it suddenly did not work anymore, and I do not remember what has changed.
Any ideas?
EDIT: I have found a solution myself. Please see my answer for details.
Background:
I am implementing an On-Screen-Keyboard for my application because it should work with a touchscreen. It is important that the keyboard layout matches the layout which is configured in Windows since the application will be shipped to many different countries. Therefore, instead of implementing a custom keyboard control with approx. 537 keyboard layouts (exaggerating a little here...), I wanted to utilize the Windows built-in On-Screen-Keyboard which adapts to the selected keyboard layout automatically, saving a lot of work for me.
I have found the/a solution myself:
When I successfully retrieve the MainWindowHandle after the process has been started, the call to CloseMainWindow() is also successful later on. I do not understand the reason for this, but the important thing is: it works!
BTW, for others having the same problem: The MainWindowHandle is not available immediately after starting the process. Obviously, it takes some milliseconds until the MainWindow is started which is why I use the following code to retrieve the handle:
DateTime start = DateTime.Now;
IntPtr handle = IntPtr.Zero;
while (handle == IntPtr.Zero && DateTime.Now - start <= TimeSpan.FromSeconds(2))
{
try
{
// sleep a while to allow the MainWindow to open...
System.Threading.Thread.Sleep(50);
handle = s_onScreenKeyboard.MainWindowHandle;
}
catch (Exception) { }
}
In this code I continuously get the MainWindowHandle every ~50ms as long as it is still equal to IntPtr.Zero. If the handle could not be retrieved after 2 seconds, I quit the loop to avoid an endless loop in case of error.
You need to wait untill the process finishes initialization, run
Process.WaitForInputIdle Method in order to do that.
I'm working on implementing directshow capability in a C# dll. I'm basing my work off of the C++ based "CameraCapture" example Microsoft provides with the Windows Mobile 6 sdk.
Things were going well (thanks to earlier help on this site), but I've run into a bit of a snag while trying to listen for directshow events in C# land:
I have a thread that loops to listen for dshow events. It waits based on a manual reset event that gets defined here (this is defined at the end of graph initialization: the graph is built, renderstream is called, and controlstream is already blocking dataflow):
DshowRequestMan = new ManualResetEvent(false);
MediaEvent = (IMediaEvent)FilterGraph;
chk(MediaEvent.GetEventHandle(out DshowEventHandle));
DshowRequestMan.Handle = DshowEventHandle; //note: no "SafeHandle" in cf
There are 2 related problems I'm experiencing with this:
When my dshow event handler loop pulls the event via IMediaEvent.GetEvent() using a timeout of 0, I get a "timeout exceeded" hresult (-2147467260) on the third iteration. That third event trigger (and subsequent error) don't occur in the C++ example.
If I ignore the timeout case mentioned above, it will constantly trigger with a 73 event. This kills the processor since the loop basically never pauses.
When the C++ example runs its graph in preview mode, it gets two IMediaEvents: first 13, then 73. After that, it stops triggering until actual capturing is started. My C# version pulls 13, then 73, then 73 again, but with the timeout error.
In short, it seems like that third triggering of the DshowRequestMan shouldn't be happening because there is no dshowevent to actually "get", hence, the timeout.
Not sure what I'm doing wrong- I'm calling "FreeEventParams()" with each iteration... I'm suspecting the ManualResetEvent object is being used incorrectly since I'm just assigning something to its handle property, but the same thing happens when I use a Pinvoked "WaitForSingleObject" to listen to the DshowEventHandle... I'm confused at this point.
Any ideas would be greatly appreciated. Thanks in advance!
Here is my code for filter graph event handling:
while (!_stopReceivingEvents) {
IntPtr eventHandle;
var hr = _mediaEvent.GetEventHandle(out eventHandle);
DsError.ThrowExceptionForHR(hr);
//NOTE: Do not close the event handle, because it is used internally by the filter graph
using (var safeWaitHandle = new SafeWaitHandle(eventHandle, false)) {
using (var waitHandle = new AutoResetEvent(false) {SafeWaitHandle = safeWaitHandle}) {
if (WaitHandle.WaitAll(new[] {waitHandle}, 500)) {
//receive all available events
do {
EventCode eventCode;
IntPtr param1;
IntPtr param2;
hr = _mediaEvent.GetEvent(out eventCode, out param1, out param2, 500);
_mediaEvent.FreeEventParams(eventCode, param1, param2);
if (hr == 0) {
switch (eventCode) {
//add handling code here
}
}
} while (hr == 0);
}
}
}
}
Are you making sure to Reset you event after you get and handle it?
Whatr does your actual wait code look like? The problem is likely that you're waiting for 0ms, which basically means "check the event and return immediately." If you want it to block on the wait (like a native call with WAIT_INFINITE) you need to pass in System.Threading.Timeout.Infinite (which is actually -1).
If you want the checking thread to periodically yield (which is way safer than an infinite wait and will actually allow your app to shut down), then you need to check the return from the wait, and if it's a timeout (0x80004004) then just go back and wait again:
while(!shutdown)
{
if(DshowRequestMan.WaitOne(1000))
{
// handle the event
}
}