I'm in the process of converting my Microsoft SDK Beta code to the Microsoft SDK Official Release that was released February 2012.
I added a generic PauseKinect() to pause the Kinect. My pause will really only remove the event handler that updated the image
Pros:
No Reinitialization (30+ second wait time)
Cons:
Kinect still processing images
Pause Method (Color Only)
internal void PauseColorImage(bool isPaused)
{
if (isPaused)
{
_Kinect.ColorFrameReady -= ColorFrameReadyEventHandler;
//_Kinect.ColorStream.Disable();
}
else
{
_Kinect.ColorFrameReady += ColorFrameReadyEventHandler;
//_Kinect.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30);
}
}
PROBLEM:
Even though I'm removing the event why is it still getting triggered?
NOTE:
Also when I pause the color image I'm also pausing the depth and skeleton in their object.
SIDE NOTE:
If I uncomment my code it works fine, but then it'll take forever to reinitialize which is not what I want to do.
MS in Reflector
public void AddHandler(EventHandler<T> originalHandler)
{
if (originalHandler != null)
{
this._actualHandlers.Add(new ContextHandlerPair<T, T>(originalHandler, SynchronizationContext.Current));
}
}
public void RemoveHandler(EventHandler<T> originalHandler)
{
SynchronizationContext current = SynchronizationContext.Current;
ContextHandlerPair<T, T> item = null;
foreach (ContextHandlerPair<T, T> pair2 in this._actualHandlers)
{
EventHandler<T> handler = pair2.Handler;
SynchronizationContext context = pair2.Context;
if ((current == context) && (handler == originalHandler))
{
item = pair2;
break;
}
}
if (item != null)
{
this._actualHandlers.Remove(item);
}
}
public void Invoke(object sender, T e)
{
if (this.HasHandlers)
{
ContextHandlerPair<T, T>[] array = new ContextHandlerPair<T, T>[this._actualHandlers.Count];
this._actualHandlers.CopyTo(array);
foreach (ContextHandlerPair<T, T> pair in array)
{
EventHandler<T> handler = pair.Handler;
SynchronizationContext context = pair.Context;
if (context == null)
{
handler(sender, e);
}
else if (this._method == ContextSynchronizationMethod<T>.Post)
{
context.Post(new SendOrPostCallback(this.SendOrPostDelegate), new ContextEventHandlerArgsWrapper<T, T>(handler, sender, e));
}
else if (this._method == ContextSynchronizationMethod<T>.Send)
{
context.Send(new SendOrPostCallback(this.SendOrPostDelegate), new ContextEventHandlerArgsWrapper<T, T>(handler, sender, e));
}
}
}
}
After posting an identical question on the Microsoft forum and talking to multiple Microsoft representatives they basically said the only way to do a "pause" is to enable/disable the streams (uncomment my comments). Without saying it straight forward its a bug in the SDK. They are going to talk to the people in the development team and try to fix the issue in future releases.
EDIT
In the May 2012 Release it is STILL not fixed. Thanks Microsoft!
Related
The problem is with the button:contains('Deal') selector, the button containing deal does exist on the page and Watin can find it without problems when running in main thread.
// Add bet, deal cards and wait for animation
private void dealCards()
{
// Start the game if chip exists
if (browser.Image(Find.BySrc(chipURL)).Exists)
{
browser.Image(Find.BySrc(chipURL)).Click();
// This is where the thread stops
browser.Button(Find.BySelector("button:contains('Deal')")).Click();
Thread.Sleep(dealCardsAnimationTime);
if (Convert.ToInt32(browser.Span(Find.ByClass("player-points")).Text) == 21)
{
consoleTextBox.AppendText("You won by blackjack.");
gameOver = true;
}
return;
}
}
Update:
Browser is a Internet Explore window that I interact with using WatiN, other than the UI changes, the problem seems to be that WatiN can't find the button.
However it's still somewhat related to multithreading, as the same code works fine without multithreading and the element that it's searching for does exist.
Update 2: Changed title and description of problem as the old one appeared to be unrelated.
Context ( in case it's necessary )
// When bet button is clicked
private void button2_Click(object sender, EventArgs e)
{
blackjackThread = new Thread(blackjackGame);
if (dealInProgress == false)
{
blackjackThread.Start();
// blackjackGame();
}
}
// Blackjack deal handler
private void blackjackGame()
{
consoleTextBox.AppendText("\r\n");
resetVariables();
dealCards();
if (gameOver == true)
{
checkResult();
dealInProgress = false;
blackjackThread.Abort();
return;
}
checkCards();
logPoints();
while (gameOver == false)
{
botAction();
}
checkResult();
dealInProgress = false;
blackjackThread.Abort();
return;
}
We have a WPF with a tab control being the primary UI for displaying customer details, each open customer gets its own tab.
Within the customer tabs we have another tab control that allows switching between various subsets of information, 2 of these use the Webbrowser control with IHTMLChangeSink functionality to monitor for hidden divs meant to trigger logic in the app.
Previously we were experiencing a very large memory leak when a Customer tab was closed, the cause of this was found to be the event handler created by RegisterForDirtyRange. To resolve the memory leak the Dispose methods were modified to call UnregisterForDirtyRange, using AutoIT to rapidly open and close customer tabs we were able to prove that the memory leak was fixed; this was done on a developer class machine.
Once this change was rolled out to testers we started seeing the application crash, in the event log we saw that the call to UnregisterForDirtyRange was throwing a ComException with HRESULT E_FAIL. Since we never saw this come up on the developer hardware and on the testers machines there was no guaranteed way to produce the crash I am thinking that there is some kind of race condition that is amplified when run on less powerful hardware.
Given this information my question is with regards to the internal workings of the Unregister call, can anyone think of what might be causing this exception?
My initial thought was that maybe the Notify method was running at the time of dispose so I tried introducing a lock between the dispose and notify but this didn't change anything.
Here is a stripped down version of the tab control that wraps the Web Browser:
public partial class BrowserTabWidget : BrowserWidget, IHTMLChangeSink
{
private static Guid _markupContainer2Guid = typeof(IMarkupContainer2).GUID;
private IMarkupContainer2 _container;
private uint _cookie;
public BrowserTabWidget()
{
InitializeComponent();
if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
{
Loaded += OnLoaded;
}
}
protected override void DisposeControls()
{
if (_container != null)
{
_container.UnRegisterForDirtyRange(_cookie);
Marshal.ReleaseComObject(_container);
}
WebBrowser.LoadCompleted -= OnWebBrowserLoadCompleted;
WebBrowser.Dispose();
}
public override string CurrentUri
{
get { return (string)GetValue(CurrentUriProperty); }
set
{
NavigateTo(value);
SetValue(CurrentUriProperty, value);
}
}
private void NavigateTo(string value)
{
WebBrowser.Navigate(new Uri(value));
}
public static readonly DependencyProperty CurrentUriProperty = DependencyProperty.Register("CurrentUri", typeof(string), typeof(BrowserTabWidget), new FrameworkPropertyMetadata(CurrentUriChanged));
public static void CurrentUriChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var widget = (BrowserTabWidget)d;
d.Dispatcher.BeginInvoke(
DispatcherPriority.Normal,
new Action(() => widget.NavigateTo(e.NewValue.ToString())));
}
private void InitializeWebBrowser()
{
WebBrowser.LoadCompleted += OnWebBrowserLoadCompleted;
WebBrowser.Navigate(new Uri(viewModel.InitialUrl));
}
void OnWebBrowserLoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e)
{
_container = GetMarkupContainer();
_container.RegisterForDirtyRange(this, out _cookie);
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
Loaded -= OnLoaded;
Load();
}
private void Load()
{
InitializeWebBrowser();
}
private IMarkupContainer2 GetMarkupContainer()
{
var oDocument = WebBrowser.Document as IHTMLDocument2;
var pDocument = Marshal.GetIUnknownForObject(oDocument);
IntPtr pMarkupContainer;
Marshal.QueryInterface(pDocument, ref _markupContainer2Guid, out pMarkupContainer);
var oMarkupContainer = Marshal.GetUniqueObjectForIUnknown(pMarkupContainer);
Marshal.Release(pDocument);
Marshal.Release(pMarkupContainer);
return (IMarkupContainer2)oMarkupContainer;
}
public void Notify()
{
var document = WebBrowser.Document as HTMLDocument;
if (document != null)
{
//Parse Dom for hidden elements and trigger appropriate event handler
}
}
}
Hmya, E_FAIL, the curse of COM. Useless to ever diagnose anything, it is just a teacher's grade for the quality of the error reporting. I wrote the same code in Winforms to get something to testable, no repro. It is nevertheless very easy to force a repro. Given that the method takes only one argument, there's only one thing that can go wrong:
if (_container != null)
{
_container.UnRegisterForDirtyRange(_cookie);
_container.UnRegisterForDirtyRange(_cookie); // Kaboom!!!
Marshal.ReleaseComObject(_container);
}
Bad cookie. Criminal that they don't return E_INVALIDARG btw.
I could not test your exact code of course, it does have problems. Most severe one I see and the repro case is that there is no protection against calling DisposeControls() more than once. In general it is never wrong to dispose objects more than once, I have no insight if that's a realistic failure mode in your project. Otherwise very simple to protect yourself against this. Including catch-and-swallow code:
protected override void DisposeControls()
{
if (_container == null) return;
try {
_container.UnRegisterForDirtyRange(_cookie);
}
catch (System.Runtime.InteropServices.COMException ex) {
if (ex.ErrorCode != unchecked((int)0x80004005)) throw;
// Log mishap...
}
finally {
Marshal.ReleaseComObject(_container);
_container = null;
_cookie = 0;
WebBrowser.LoadCompleted -= OnWebBrowserLoadCompleted;
WebBrowser.Dispose();
}
}
Another thing I noticed in my test version of your code is that you don't appear to have any protection against the browser navigating to another page by any other means than WebBrowser.Navigate(). Or the LoadCompleted event firing more than once, it does for the stackoverflow.com home page for example. Or any web page that uses frames. That's a leak. Make it resilient by having your OnWebBrowserLoadCompleted() event handler also unregister the cookie if it is set.
I working on a Windows Phone 7 app with Text-To-Speech capabilities. I'm using Text-To-Speech with Microsoft Translator Service and the following C# code...
// Text-To-Speech with Microsoft Translator Service (http://translatorservice.codeplex.com/)
private void TextToSpeech_Play(object sender, EventArgs e)
{
SpeechSynthesizer speech = new SpeechSynthesizer(CLIENT_ID, CLIENT_SECRET);
//string content = "This is a beautiful day!";
string language = "en";
//speech.SpeakAsync(content, language);
foreach (UIElement element in todayschapter.Children)
{
if (element is TextBlock)
{
string content = (element as TextBlock).Text;
speech.SpeakAsync(content, language);
}
}
}
In this instance, todayschapter is a StackPanel and its Children are TextBlocks. I'm wanting to simply play audio of each TextBlock, in succession. The problem is that it is play the audio of EVERY TextBlock at the same time.
I have a sneaking suspicion that the problem is SpeakAsync(), but I'm not sure. The documentation shows Speak(), but that isn't available (maybe a different version) in the Visual Studio methods helper dropdown (little thing that shows as you type - not sure what it's called).
Is there a way to make it wait for each play to finish before playing the next? Is foreach not the right choice, for this?
As always, if my code just looks stupid, please recommend better ways. I'm very much a beginner programmer.
Just use the Speak instead of the async call, since you want to have it one after another anyway.
The SpeakAsync call is indeed the problem. Unfortunately, since SpeakAsync doesn't return a Task, you can't just convert this to await SpeakAsync() (which would be the most straightforward conversion).
And, looking at the source code, it doesn't fire an event to tell when it's done. So let's add one (in SpeechSynthesizer.cs):
public event EventHandler<SpeechEventArgs> SpeakCompleted;
public void SpeakAsync(string text, string language)
{
this.GetSpeakStreamAsyncHelper(text, language, result =>
{
if (result.Error == null)
{
SoundEffect effect = SoundEffect.FromStream(result.Stream);
FrameworkDispatcher.Update();
effect.Play();
this.OnSpeakCompleted(new SpeechEventArgs(result.Error)); // added to call completion handler
}
else
{
this.OnSpeakFailed(new SpeechEventArgs(result.Error));
}
});
}
// new function
private void OnSpeakCompleted(SpeechEventArgs e)
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
if (SpeakCompleted != null)
SpeakCompleted(this, e);
});
}
Now, you'll need to handle the SpeakCompleted event and start speaking the next string.
Something like this (I haven't even compiled this, so be warned):
private Queue<string> utterances;
private SpeechSynthesizer speech;
private void TextToSpeech_Play(object sender, EventArgs e)
{
speech = new SpeechSynthesizer(CLIENT_ID, CLIENT_SECRET);
speech.SpeechCompleted += new EventHandler<SpeechEventArgs>(TextToSpeech_Completed);
foreach (UIElement element in todayschapter.Children)
{
if (element is TextBlock)
{
string content = (element as TextBlock).Text;
utterances.Enqueue(content);
}
}
TextToSpeech_Completed(null, null); // start speaking the first one
}
private void TextToSpeech_Completed(object sender, SpeechEventArgs e)
{
if (utterances.Any())
{
string contents = utterances.Dequeue();
speech.SpeakAsync(contents);
}
}
I have a base form that I use when calling 2 forms. Previously when calling the forms I didn't dispose of them, but I have found that reusing them, they would stay in memory and not get collected. So I have instead used a using statement instead to clear the memory, and all my problem are fixed.
But now a new problem arises, one that I had previously when testing my app with mono on Linux. I though it might be a mono specific problem, but since adding the using statement the same thing happens on my Windows machine. So it might just be that the Garbage Collector on Mono is different and was disposing properly of my forms.
Here is my problem I have a thread that I start to extract files in the background And I have progress bar telling me the progress, before using the dispose if I closed the form and reopened it my files extracted correctly and the progress bar was working fine. But now they work fine the first time, but if I reopen the form or the other one that has the same base, the extraction is not working, no files are extracted because I have a null exception when reporting the progress.
private void ExtractFiles()
{
Zip.ExtractProgress += new EventHandler<ExtractProgressArgs>(Utils_ExtractProgress);
Thread t = new Thread(new ThreadStart(Zip.ExtractZip));
t.IsBackground = true;
t.Start();
FilesExtracted = true;
}
void Utils_ExtractProgress(object sender, ExtractProgressArgs e)
{
UpdateProgress(e.Pourcentage);
}
private delegate void UpdateProgressDelegate(int Pourc);
private void UpdateProgress(int Pourc)
{
lock (this)
{
if (Progress.ProgressBar.InvokeRequired)
{
UpdateProgressDelegate del = new UpdateProgressDelegate(UpdateProgress);
Progress.ProgressBar.BeginInvoke(del, Pourc);
} else
{
Progress.Value = Pourc;
}
}
}
This code is in my BaseForm, the Progress control isn't null, but all of it's properties have null exceptions. So when checking if Invoked is required it raises an Null exception.
Here is my Zip.Extract method
public static event EventHandler<ExtractProgressArgs> ExtractProgress;
static ExtractProgressArgs Progress;
internal static void ExtractZip()
{
try
{
using (ZipFile zip = ZipFile.Read(Variables.Filename))
{
Progress = new ExtractProgressArgs();
Progress.TotalToTransfer = Convert.ToInt32(zip.Sum(e => e.UncompressedSize));
zip.ExtractProgress += new EventHandler<ExtractProgressEventArgs>(zip_ExtractProgress);
Old = 0; New = 0;
foreach (ZipEntry item in zip)
{
item.Extract(Variables.TempFolder, ExtractExistingFileAction.OverwriteSilently);
}
}
} catch (Exception)
{
}
}
static long Old;
static long New;
static void zip_ExtractProgress(object sender, ExtractProgressEventArgs e)
{
if (e.EventType == ZipProgressEventType.Extracting_EntryBytesWritten)
{
New = e.BytesTransferred;
Progress.Transferred += New - Old;
Old = e.BytesTransferred;
if (ExtractProgress != null)
{
ExtractProgress(e.CurrentEntry, Progress);
}
} else if (e.EventType == ZipProgressEventType.Extracting_AfterExtractEntry)
{
Old = 0;
}
}
Might be because my Zip.Extract is static? I have almost no knowledge of multi-threading, like synchronization, etc.
The short answer is yes, some of your problems are due to the static nature of those operations.
You should be able to resolve the problem by removing the static declarations from your Zip class and then creating an instance of it as needed.
Hey guys, I just wanted to verify what I'm doing is correct. It came to our attention that a Windows Service had a pretty serious memory leak. I was able to track it down to how Workflow was being called. I reworked it a bit to stop the memory leak, but I wanted to validate that the code is doing what I think it is. Note I do not know the first thing about Workflow, so I'm coming to you.
Basically, the code was executing the Workflow on a thread, but was not removing the handler to WorkflowRuntime.Terminated. I am trying to ensure that the Workflow is executed asynchronously. Here are the relevant portions of code:
Checking to ensure there is only once instance of the WorkflowRuntime:
private static void _CheckRuntimeInstance()
{
lock (_padlock)
{
if (_wfRuntime == null)
{
_wfRuntime = new WorkflowRuntime();
ManualWorkflowSchedulerService schedulerService = new ManualWorkflowSchedulerService();
_wfRuntime.AddService(schedulerService);
_wfRuntime.StartRuntime();
}
}
}
Inside a static method, creating the specific WorkflowInstance to run:
_CheckRuntimeInstance();
// create the instance
WorkflowInstance instance = _wfRuntime.CreateWorkflow(typeof(WorkflowType),parameters);
instance.Start();
Guid instanceId = instance.InstanceId;
ThreadPool.QueueUserWorkItem(CallbackMethod, instanceId);
Thread callback method:
private static void DeviceLocationAssignmentCallback(Object state)
{
Guid instanceId = (Guid)state;
EventHandler<WorkflowTerminatedEventArgs> workflowTerminatedHandler = null;
EventHandler<WorkflowCompletedEventArgs> workflowCompletedHandler = null;
workflowTerminatedHandler = delegate(object sender, WorkflowTerminatedEventArgs e)
{
if (instanceId == e.WorkflowInstance.InstanceId)
{
// Remove event registration.
_wfRuntime.WorkflowTerminated -= workflowTerminatedHandler;
_wfRuntime.WorkflowCompleted -= workflowCompletedHandler;
if (e.Exception != null)
{
// Log error.
}
}
};
_wfRuntime.WorkflowTerminated += workflowTerminatedHandler;
workflowCompletedHandler = delegate(object sender, WorkflowCompletedEventArgs e)
{
if (instanceId == e.WorkflowInstance.InstanceId)
{
// Remove event registrations.
_wfRuntime.WorkflowTerminated -= workflowTerminatedHandler;
_wfRuntime.WorkflowCompleted -= workflowCompletedHandler;
}
};
_wfRuntime.WorkflowCompleted += workflowCompletedHandler;
_wfRuntime.GetService<ManualWorkflowSchedulerService>().RunWorkflow(instanceId);
}
EDIT: Changed the title of the post to get more views.