Static variable initialized in App_Launching suddenly null - c#

Windows Phone 8 project. I have a class that holds a reference to an image. I initialize said reference in the Launching event handler in the app class:
private void Application_Launching(object sender, LaunchingEventArgs e)
{
TheClass.Load();
}
//Elsewhere...
class TheClass
{
static private int[] s_Pixels = null;
static public void Load()
{
BitmapImage bi = new BitmapImage(new Uri("/res/image.png", UriKind.Relative));
bi.CreateOptions = BitmapCreateOptions.BackgroundCreation;
bi.ImageOpened += OnImageLoaded;
bi.ImageFailed += OnImageFailed;
}
private static void OnImageLoaded(object o, RoutedEventArgs a)
{
BitmapImage bi = o as BitmapImage;
s_Pixels = new WriteableBitmap(bi).Pixels;
}
// And consumers call this one:
static public WriteableBitmap GetImage()
{
if (s_Pixels == null)
SendDebugReport();
}
}
This code works fo me. And yet I'm getting those debug reports, indicating that s_Pixels is null. I can't reproduce it, but my users obviously can. There's a code path that leads to GetImage() being called without a prior call to Load().
It's Load that's not being called, not that I call Load and OnImageLoaded never happens.
There are no other assignments to s_Pixels anywhere.
I do check for image loading errors. There's an ImageFailed event handler that leaves a log trace. It's never invoked, and why would it be - the image in question is in the app's resources.
How is that even possible? How can a Windows Phone app initialize and load without Launching being invoked?

Application_Launching is only called when your application starts anew. If you send it to the background, and the system eventually tombstones it, and then the user reactivates it, your static data will be gone, but Launching will not be called. Instead, you will get a call to Application_Activated.
So, basically, you need to run all static initialization both on the Launching and on the Activated methods.
You can most probably reproduce the problem your users are seeing by forcing the tombstoning of your app with Visual Studio: Check the "Tombstone upon deactivation while debugging" on the Debug tab of your project's options, run the app under debugger, press the Windows key when the app is running, and the switch back to the app.

Related

Making file picker asynchronous - Windows Phone 8.1

I tried to make File open picker asynchronous using TaskComplectionSource however sometimes I get my application closed with -1 return value, sometimes I get exception like:
[System.Runtime.InteropServices.COMException] = {System.Runtime.InteropServices.COMException (0x80004005): Unspecified error
Unspecified error
at Windows.Storage.Pickers.FileOpenPicker.PickSingleFileAndContinue()
at PhotosGraphos.Mobile.Common.StorageFileExtensions.<PickSingleFileAsyncMobile..
Code:
public static class StorageFileExtensions
{
private static TaskCompletionSource<StorageFile> PickFileTaskCompletionSource;
private static bool isPickingFileInProgress;
public static async Task<StorageFile> PickSingleFileAsyncMobile(this FileOpenPicker openPicker)
{
if (isPickingFileInProgress)
return null;
isPickingFileInProgress = true;
PickFileTaskCompletionSource = new TaskCompletionSource<StorageFile>();
var currentView = CoreApplication.GetCurrentView();
currentView.Activated += OnActivated;
openPicker.PickSingleFileAndContinue();
StorageFile pickedFile;
try
{
pickedFile = await PickFileTaskCompletionSource.Task;
}
catch (TaskCanceledException)
{
pickedFile = null;
}
finally
{
PickFileTaskCompletionSource = null;
isPickingFileInProgress = false;
}
return pickedFile;
}
private static void OnActivated(CoreApplicationView sender, IActivatedEventArgs args)
{
var continuationArgs = args as FileOpenPickerContinuationEventArgs;
sender.Activated -= OnActivated;
if (continuationArgs != null && continuationArgs.Files.Any())
{
StorageFile pickedFile = continuationArgs.Files.First();
PickFileTaskCompletionSource.SetResult(pickedFile);
}
else
{
PickFileTaskCompletionSource.SetCanceled();
}
}
}
What's weird - this bug is hardly reproduced while debugging. Does anyone have any idea what could be reason of that?
Don't do that (don't try to turn Continuation behaviour into async). Why?
Normally when your app is put into the background (for example when you call file picker), it's being suspended, and here is one small pitfall - when you have a debugger attached, your app will work without being suspended. Surely that can cause some troubles.
Note also that when you normally run your app and you fire a picker, then in some cases your app can be terminated (low resources, user closes it ...). So you need here two things which are added by VS as a template: ContinuationManager and SuspensionManager. More you will find at MSDN. At the same link you will find a good procedure to debug your app:
Follow these steps to test the case in which your app is terminated after calling the AndContinue method. These steps ensure that the debugger reattaches to your app after completing the operation and continuing.
In Visual Studio, right-click on your project and select Properties.
In Project Designer, on the Debug tab under Start action, enable Do not launch, but debug my code when it starts.
Run your app with debugging. This deploys the app, but does not run it.
Start your app manually. The debugger attaches to the app. If you have breakpoints in your code, the debugger stops at the breakpoints. When your app calls the AndContinue method, the debugger continues to run.
If your app calls a file picker, wait until you have opened the file provider (for example, Phone, Photos, or OneDrive). If your app calls an online identity provider, wait until the authentication page opens.
On the Debug Location toolbar, in the Process dropdown list, select the process for your app. In the Lifecycle Events dropdown list, select Suspend and Shutdown to terminate your app but leave the emulator running.
After the AndContinue operation completes, the debugger reattaches to your app automatically when the app continues.
I've changed file picker to standard way provided by #Romasz - it still was crashing. I've been debugging it for hours and I get same COMException but sometimes with information provided:
"GetNavigationState doesn't support serialization of a parameter type which was passed to Frame.Navigate"
It seems that code with TaskCompletionSource works and there is nothing wrong with that. I found out in msdn documentation for Frame
Note: The serialization format used by these methods is for internal use only. Your app should not form any dependencies on it. Additionally, this format supports serialization only for basic types like string, char, numeric and GUID types.
And I was passing my model-class object in navigation parameter - so it was kept in navigation stack therefore it couldn't be serialized. The lesson is: do not use non-primitive types for navigation parameter - Frame.Navigate should disallow such navigation and throw exception - but it doesn't..
EDIT:
Another bug - if you bind tapped (let say button tapped) or event like that to command which launch FileOpenPicker you need to check if picker.PickFile.. was called before - otherwise when you tap fast on that button you'll get few calls to picker.PickFile.. and UnauthorizedAccessException will be thrown.

Asynccallback in dll causes Form to freeze

I have a form Form1 with a button and text box.
When I click on the button I should get some data from USB device.
For some reason it works correctly only about 2% (I was able to get 2 correct responses out of 100 clicks).
Here is the code for the Form1:
namespace Test_onForm1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Lib1.FindHID.TransferInputAndOutputReports(0xC0); //request specific data from USB device
}
}
}
The code handling USB communication is in DLL Lib1 (fragments of the code below):
namespace Lib1
{
public static class FindHID
{
private static void TransferInputAndOutputReports(UInt16 repType)
{
//some code here sending request to USB device... and then read what came from USB
ReadInput();
//some code here
}
// Read an Input report.
private static void ReadInput()
{
Byte[] inputReportBuffer = null;
inputReportBuffer = new Byte[MyHid.Capabilities.InputReportByteLength];
IAsyncResult ar = null;
if (fileStreamDeviceData.CanRead)
{
// RUNS UP TO THIS POINT and then Form1 freezes most of the time
fileStreamDeviceData.BeginRead(inputReportBuffer, 0, inputReportBuffer.Length, new AsyncCallback(GetInputReportData), inputReportBuffer);
}
}
private static void GetInputReportData(IAsyncResult ar)
{
// RARELY GETS HERE
Byte[] inputReportBuffer = null;
inputReportBuffer = (byte[])ar.AsyncState;
fileStremDeviceData.EndRead(ar); //waits for read to complete
// then code to update Form1
}
}
}
}
When it doesn't work it stops around fileStreamDeviceData.BeginRead and then Form1 freezes.
For testing I created a completely new project and instead of using a DLL I copied all DLL code to the Form1.
This option works perfectly fine 100% of the time.
So my question is why it doesn't work with DLL?
Update: when I get lucky and it start working then it works indefinitely until I close application. Then, I have to keep trying to get it to work again.
How to troubleshoot this problem?
Most likely the problem is that the code in EndRead is trying to update the form, but it's not on the UI thread. You have to synchronize with the UI thread, either by doing Form.Invoke or some way notifying the form that the data is ready so that the UI thread can do the update.
SOLVED!
Found on Microsoft website:
"The default implementation of BeginRead on a stream calls the Read method synchronously, which means that Read might block on some streams."
I was using .NET Framework 4.0 on Visual Studio 2010.
Decided to update to .NET Framework 4.5 which has Stream.ReadAsync method instead. However, I couldn't implement Stream.ReadAsync on Visual Studio 2010 (don't know the reason, maybe needs update to 2012?).
So, with updated Framework 4.5 I tried my code and it works ALL THE TIME EVERY TIME.

App Freezes When Screensaver Settings Changed In Windows 7 - System.Threading.Timer The Culprit?

I have a C#/TCP/Winform app that's been running for quite some time, but one of my users has discovered an issue that I can replicate easily, but that I can't seem to solve.
If the app is open on Windows 7 and the user then changes any option in their screensaver settings - be it the screensaver being used or the time - the app freezes and the UI becomes non-responsive. Clicking anywhere on the form just gets the system "ding."
When the app is run through Visual Studio in debug mode, the problem ceases to exist, but once out of the confines of VS, goes back to freezing.
After some tinkering and testing, I seem to have narrowed down my problem to a System.Threading.Timer that runs once every second. I've been steadily paring down what the timer does and discovered that even if the timer's event does nothing, it still locks the app. If I disable the timer in the code or cancel the timer in the app prior to changing the Screensaver settings, then the app will return to functional after a screensaver change (though it still seems to freeze for about 2-3 seconds).
This code here, seems to be all that is necessary to make the app freezable (within the WinForm code):
/// <summary>
/// Starts the countdown timer for unit alerts
/// </summary>
private void startCountDownTimer()
{
Object timeState = new object();
this._timerCall = new System.Threading.TimerCallback(this.countDown);
this._countdownTimer = new System.Threading.Timer(_timerCall, timeState, 0, 1000);
}
/// <summary>
/// Invokes the countdown logic for unit alerts
/// </summary>
/// <param name="state"></param>
private void countDown(Object state)
{
// REMOVED AND STILL FREEZING
}
Note that this freeze happens even with the contents of countDown commented out so that the timer is doing nothing other than firing once per second.
If I launch process and then attach a remote debugger to it, there is nothing in the output that indicates that anything is wrong with the application. The form actually still fires events like "Activated":
*** MAIN WINDOW ACTIVATED ***
*** MAIN WINDOW ACTIVATED ***
However nothing else seems to be firing and the application has to be either killed or shut down via EndTask. If EndTask is used while the debugger is still attached, I suddenly get errors:
A first chance exception of type 'System.InvalidOperationException' occurred in System.Windows.Forms.dll
===================================
ERR: Invoke or BeginInvoke cannot be called on a control until the window handle has been created.
at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous)
at System.Windows.Forms.Control.BeginInvoke(Delegate method, Object[] args)
at System.Windows.Forms.Control.BeginInvoke(Delegate method)
at Wcsg.UI.Windows.CadClient.client_MessageReceived(TcpMessageReceivedEventArgs mrea) in C:\Users\---------\Documents\Visual Studio 2010\Projects\Dispatch-DEVELOPMENT\CadClient\Forms\CadClientForm.cs
at Wcsg.Net.Tcp.WcsgTcpClient.processStream(Int32 count)
at Wcsg.Net.Tcp.WcsgTcpClient.performSocketRead(IAsyncResult ar)
---------------------
The errors that I do finally get would seem to be linked to the closing of the form while it finally gets around to processing the messages on the socket.
I'm looking for any sort of direction to look here.
* EDIT *
I was asked about the Main method in the program when the expected workaround (see answer) didn't work. Here is the Main code:
[STAThread]
static void Main(String[] args)
{
// check for other running CadClients
bool createdNew = _mutex.WaitOne(TimeSpan.Zero, false);
if (createdNew) // first-run, launch Status Monitor on load
{
List<String> newArgs = new List<string>(args);
newArgs.Add("-SM");
args = newArgs.ToArray();
}
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
AppDomain currentDomain = AppDomain.CurrentDomain;
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
// try to catch issue 13445 -- see testing notes
CadClient cc = new CadClient(args);
CadExceptionHandler ceh = new CadExceptionHandler(ref cc);
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(ceh.CurrentDomain_UnhandledException);
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(ceh.Application_ThreadException);
Application.Run(cc);
}
* EDIT *
I should probably add the Splashscreen code as well:
private void showSplashScreen()
{
WaitCallback wcb = new WaitCallback(doSplashScreen);
ThreadPool.QueueUserWorkItem(wcb);
}
private void doSplashScreen(object state)
{
if (this._splash == null)
this._splash = new SplashForm(this);
this._splash.FormClosed += new FormClosedEventHandler(_splash_FormClosed);
this._splash.Show();
while (this._splash != null && !this._splash.WorkDone)
Application.DoEvents();
this._splash.Close();
}
The method showSplashScreen() is called within the main form's constructor - originally before and now after the InitializeComponents() call. The splash screen displays updates its display while the main app validates some security. Then it turns into a login screen and then displays more udpates while the main app loads data from the server. Once the main form indicates (via event) that it has completed its work, the SplashScreen is closed.
Used the comment from #HansPassant and found that the showSplash method for our splash/login screen was not being called before Application.Run, but WAS being called before our main form's InitializeComponent method. Moved this.showSplash to the line immediately below InitializeComponent() and recompiled and the problem seems to be gone.

How do I make something happen in my windows phone 7 app only once?

I need to do something only once (in my case creating an instance of a class). The closest thing I can find is putting it in the PhoneApplicationPage_Loaded event handler, or at the top of MainPage.xaml. But this doesn't work for me because I have other pages in my app, so if I navigate from another page back to the MainPage it executes that code again.
Thanks, David
When you create a new project, you will find an App.xaml.cs file added to your project. Here you can add code that is executed at various points in your application lifecycle. You can add code to the method thar handles the Launching event:
// Code to execute when the application is launching (eg, from Start)
// This code will not execute when the application is reactivated
private void Application_Launching(object sender, LaunchingEventArgs e)
{
// your code goes here
}
This code will be executed just once when you application launches.
What you need (I assume) is a singleton class:
public class Singleton
{
private static Singleton instance = new Singleton();
private Singleton()
{
}
public static Singleton GetInstance()
{
return instance;
}
}
Now calling Singleton.GetInstance() from anywhere guarantees that you will get the same instance everytime.

Silverlight 4 Clipboard Security Exception "access is not allowed"?

I'm new in Silverlight and i am doing some tests. With my current test I try to display in real time the current Clipboard content. But there is a weird behaviors with this code :
namespace SilverlightTest
{
public partial class MainPage : UserControl
{
private Timer _timer;
public MainPage()
{
InitializeComponent();
var dispatcher_timer = new DispatcherTimer {Interval = new TimeSpan(0, 0, 0, 5)};
dispatcher_timer.Tick += new EventHandler(timer_Callback);
dispatcher_timer.Start();
}
private void timer_Callback(object state, EventArgs eventArgs)
{
current_clip_board.Content = Clipboard.GetText();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
current_clip_board.Content = Clipboard.GetText();
}
}
}
The button Event and the timer Event are suppose to do exactly the same action.
But it doesn't ! The Button works fine and set the clipboard text into the label but the timer throw an exception :
Clipboard access is not allowed
The question is : why ? :)
Thanks.
PS : I would bet on a thread problem :p
Clipboard access, in a partial trust (in-browser) Silverlight application (the scenario you're likely referring to above), is restricted. The GetText property is accessible only in scenarios that the Silverlight runtime determines were initiated by the user. Your example is perfect -- by a button click for example. A dispatch timer however is not user initiated, so the property throws an exception (this is especially important within the context of a in-browser application, which could be a big security hole if you could create a Silverlight application that just ran silently in the browser, watching the user's clipboard updates without their knowledge).
See this clipboard documentation for more details.
Just trigger Clipboard.ContainsText() instead of Text. The method ContainsText is allowed!
Have you tried this:
private void timer_Callback(object state, EventArgs eventArgs)
{
Dispatcher.Invoke(new System.Threading.ThreadStart(delegate()
{
current_clip_board.Content = Clipboard.GetText();
}
}
edit
After a quick search, it appears that Clipboard is only available in response to a user action see here and here.
In partial trust (the default mode for
browser-hosted Silverlight-based
applications), Silverlight also
restricts clipboard access to its two
key APIs GetText and SetText. These
APIs can only be invoked from within a
context that is determined by the
Silverlight runtime to be in response
to a user-initiated action. For
example, clipboard access is valid
from within a handler for a Click or
KeyDown event. In contrast, clipboard
access is not valid from a handler for
Loaded or from a constructor, and
access attempts throw exceptions.
If your only option is to use a timer, then don't do it at all. The clipboad is a shared resource, and you're going to raise "cannot open clipboard" errors in other programs as they try to access the clipboard. i.e. user copies something from WinWord, WinWord tries to open the clipboard, but can't, because you've got it locked while you're examining it.
Hello this works for me but only in IE Microsoft.LightSwitch.Threading.Dispatchers.Main.BeginInvoke(() => HtmlPage.Window.Eval("window.clipboardData.setData('Text','testtestest')"));
just use getData method

Categories