I just added the feature where I can make my program the default-program for multiple music filetypes by following this question on Stackoverflow
It seemed to work fine, since all of the mp3 files etc has my icon on them in Explorer.
But when I tried starting one (I have handled the arguments just fine) the process itself starts (it shows up in Task Manager) but nothing happens. I even tried adding a Messagebox in the beginning of the "Window.Initialized"-event, but no messagebox came up.
What might be the cause of this problem? I have literally no idea what's wrong.
If you need code or anything, just ask for it since I don't know what to include in this question.
Thank you.
Here's the code for Window_Initialied
private void Window_Initialized(object sender, EventArgs e)
{
MessageBox.Show("asd");
HandleInstances(); // Checks if multiple instances of the program is running. Exits it if there's more than one instance (tried commenting this out, didn't work)
if (Properties.Settings.Default.HasRegisteredFiletypes == false) // Checks if theres a need to add the filetypes
AddExec();
StartWithMusic(Environment.GetCommandLineArgs().ToList()); // Here I call for the arguments. Checks if there are valid files in the arguments (.mp3, .flac etc)
SettingsLoadBGs.IsChecked = Properties.Settings.Default.LoadBGs;
// set accentcolor box
List<AccentColor> ac = new List<AccentColor>();
string userAccent = Mplayer.Properties.Settings.Default.Accent.ToLower();
foreach (Accent c in ThemeManager.DefaultAccents)
{
AccentColor acEnt = new AccentColor();
acEnt.Name = c.Name;
ac.Add(acEnt);
if (c.Name.ToLower() == userAccent)
ThemeManager.ChangeTheme(this, c, Theme.Dark);
}
ThemeManager.IsThemeChanged += new EventHandler<OnThemeChangedEventArgs>(ThemeChanged);
accentChooserBox.ItemsSource = ac;
}
Related
I have a program that runs in the system tray that communicates with our server and "syncs" data based on a users preferenced jobs. The idea is similar to Dropbox, but for our surveying software called 12d Synergy. The idea is that users can sync data without needing to navigate through the softwares Client.
I want to add the functionality so that when the program is syncing, the icon in the system tray changes to indicate that its still syncing, but i can't figure out how to get access to the original object within the portion of the program where the event is located.
My program stucture is as follows (in c#):
Program.cs
using (ProcessingIcon pi = new ProcessingIcon())
{
pi.SetIcon(Resources._12d);
pi.Display();
Application.Run();
}
ProcessingIcon.cs
NotifyIcon ni;
public void SetIcon(Icon path)
{
ni.Icon = path;
}
public void Display()
{
ni.Text = "Sunrise Surveying 12d Synergy Sync Tool";
ni.Visible = true;
ni.ContextMenuStrip = new ContextMenus().Create();
}
ContextMenus.cs
public ContextMenuStrip Create()
{
// Sync Now
item = new ToolStripMenuItem();
item.Text = "Sync Now";
item.Click += new EventHandler(syncNow_Click);
item.Image = Resources.Sync.ToBitmap();
cms.Items.Add(item);
}
void syncNow_Click(object sender, EventArgs e)
{
string[] jobs = Sync.GetSharedFiles();
string[] files = Sync.GetDataToSync(jobs);
Sync.SyncData(files);
}
What i want to happen, is in the syncNow_click, call the ProcessingIcon.SetIcon() to change the icon, but i can't figure out how to get access to an object that exists 3 layers up in the program.
I should note that i am not a programmer, i'm a surveyor with an interest in programming. I am completely self taught, so i know there is probably something relatively simple i'm missing. This is also my first post in StackOverflow, so i'm not 100% how to use this site to the full capability, so if this has been answered somewhere i apologise.
Any help or advice would be greatly appreciated.
So i worked out a way to answer my own question. Just putting it here in case anyone has the same issue. It turned out to be incredibly simple, and purely just by me not fully understanding the classes/objects structure.
I added a constructor for my ContextMenus object which passed in the the NotifyIcon that was calling it. This was passed to a NotifyIcon variable in that class which i could then access.
class ContextMenus
{
public NotifyIcon ni;
public ContextMenus(NotifyIcon ni)
{
this.ni = ni;
}
}
this is my first question on stackoverflow, therefore errors in asking-style aren't on purpose.
I'm both, new to C# as to the concept of event-handling, so
I would like to know, if there is any possibility to have the value of an ToolStripButtonItem-attribute changed by an EventHandler.
The context is the following:
The code starts by initializing the UI which contains some Windows.Forms- Elements.
The ToolStripButtomItem that is of interest for me, has it's Enabled-attribute set to false as default-value. The functionality of this button is to switch into a comparision-view as soon as a certain reference file exists.
This allready can be the case when the programm-start, otherwise the reference file might be created during runtime.
Of course, you could perform
Button.Enabled=System.IO.File.Exists(Reference-File)
with the initilization and than do something like
CreateFile(ReferenceFile){
...
Button.Enabled = true;
}
but this seems rather crude to me.
Instead I would like to something like:
Button.Enabled = new System.EventHandler(this.EnableButton);
with
private void EnableButton(Object sender, EventArgs e){
if(System.IO.FileExists(ReferenceFile)
Button.Enabled = true;
}
What I intend is, to have the button get enabled as soon as the reference-file existst. There are multiple ways to create the reference-file, and there are goint to be even more in the future. To avoid setting the enable-value in each of those createReferenceFile()-Methods, the concept of EventHandling seems quite like the deal to me.
The program I'm trying to run is quite comprehensive, so "polling" is no option at this place.
I suggest to use the FileSystemWatcher and set the enabled property every time it goes of.
private void StartListening(string path)
{
var watch = new FileSystemWatcher();
watch.Path = path;
watch.Filter = "*.*";
watch.Created += UpdateState;
watch.Deleted += UpdateState;
}
void UpdateState(object sender, FileSystemEventArgs e)
{
MyButton.Enabled = File.Exists(#"C:\Folder\File.txt");
}
PS: this is just some very basic example code, you will need to make sure that you have a reference to MyButton and have the correct path there as well ...
As Peter Duniho points out in a comment here, I was fixated on a red herring when I should have been focusing on something else altogether.
When I use Symbol.Barcode.Reader and Symbol.Barcode.ReaderData in one form, they work fine. I use them as I document here.
However, when I go from one form that uses the barcode scanning code to another one that also does, all Dallas breaks loose. I get the following exception in the second form, on startup:
Symbol.Exceptions.OperationFailureException: SCAN_GetInterfaceParams
at Symbol.Barcode.InterfaceParams.GetInterfaceParams()
at Symbol.Barcode.InterfaceParams..ctor(Reader reader)
at Symbol.Barcode.Actions.Enable()
at HHS.frmFind.InitReader()
at HHS.frmFind.textBoxScan_GotFocus(Object sender, EventArgs e)
at System.Windows.Forms.Control.OnGotFocus(EventArgs e)
at System.Windows.Forms.Control.WnProc(WM wm, Int32 wParam, Int32 lParam)
at System.Windows.Forms.Control._InternalWnProc(WM wm, Int32 wParam, Int32 lParam)
at Microsoft.AGL.Forms.WL.SetVis(IntPtr hwnThis, BOOL fVis)
at System.Windows.Forms.Control.set_Visible(Boolean value)
at System.Windows.Forms.Form.ShowDialog()
The barcode scanning code between the two forms is identical, so it's not the code itself (it works fine the first time, in the first form).
The exception occurs immediately in the second form when the textbox that is set up for scanning is entered. It's GotFocus() event fires because the textbox gets focus when the form is displayed; OnGotFocus() calls InitReader(), which then fails. InitReader() is:
private bool InitReader()
{
ExceptionLoggingService.Instance.WriteLog("Reached frmFind.InitReader");
// If reader is already present then retreat
if (this.barcodeReader != null)
{
return false;
}
// Create new reader, first available reader will be used.
this.barcodeReader = new Symbol.Barcode.Reader();
// Create reader data
this.barcodeReaderData = new Symbol.Barcode.ReaderData(
Symbol.Barcode.ReaderDataTypes.Text,
Symbol.Barcode.ReaderDataLengths.MaximumLabel);
// Create event handler delegate
this.barcodeEventHandler = this.BarcodeReader_ReadNotify;
// Enable reader, with wait cursor
this.barcodeReader.Actions.Enable();
this.barcodeReader.Parameters.Feedback.Success.BeepTime = 0;
this.barcodeReader.Parameters.Feedback.Success.WaveFile = "\\windows\\alarm3.wav";
// Attach to activate and deactivate events
this.Activated += ReaderForm_Activated;
this.Deactivate += ReaderForm_Deactivate;
return true;
}
The objects being dealt with there are in Symbol.Barcode.dll, from Motorola. They are declared in the form like so:
private Symbol.Barcode.Reader barcodeReader;
private Symbol.Barcode.ReaderData barcodeReaderData;
If I bypass the first form, which has the same type of barcode scannig code, and go straight to this form, it doesn't crash.
So apparently it's that the closely related bits of code can't coexist. Why not and, more importantly, how can I prevent this revolting development?
UPDATE
With this logging added to InitReader:
private bool InitReader()
{
ExceptionLoggingService.Instance.WriteLog("Reached frmFind.InitReader");
// If reader is already present then retreat
if (this.barcodeReader != null)
{
return false;
}
// Create new reader, first available reader will be used.
ExceptionLoggingService.Instance.WriteLog("Reached frmFind.InitReader #2");
this.barcodeReader = new Symbol.Barcode.Reader();
// Create reader data
ExceptionLoggingService.Instance.WriteLog("Reached frmFind.InitReader #3");
this.barcodeReaderData = new Symbol.Barcode.ReaderData(
Symbol.Barcode.ReaderDataTypes.Text,
Symbol.Barcode.ReaderDataLengths.MaximumLabel);
// Create event handler delegate
ExceptionLoggingService.Instance.WriteLog("Reached frmFind.InitReader #4");
this.barcodeEventHandler = this.BarcodeReader_ReadNotify;
// Enable reader, with wait cursor
ExceptionLoggingService.Instance.WriteLog("Reached frmFind.InitReader #5");
this.barcodeReader.Actions.Enable();
this.barcodeReader.Parameters.Feedback.Success.BeepTime = 0;
this.barcodeReader.Parameters.Feedback.Success.WaveFile = "\\windows\\alarm3.wav";
// Attach to activate and deactivate events
ExceptionLoggingService.Instance.WriteLog("Reached frmFind.InitReader #6");
this.Activated += ReaderForm_Activated;
this.Deactivate += ReaderForm_Deactivate;
ExceptionLoggingService.Instance.WriteLog("Reached frmFind.InitReader #7");
return true;
}
...I see this in the log file after opening the Find form and crashing the app (it hangs for about 20 seconds before disappearing):
Date: 3/19/2009 11:43:38 PM
Message: Reached frmFind.InitReader
Date: 3/19/2009 11:43:38 PM
Message: Reached frmFind.I
...so it's crashing almost instantaneously after this block of code:
if (this.barcodeReader != null)
{
return false;
}
...as it only gets through half of the next logging line before rudely interrupting itself.
UPDATE 2
Fejesjoco may still be right (in his comment below), but I submit this logging code as exhibit "A":
public void WriteLog(string message)
{
if (!HHSConsts.Logging) return;
StringBuilder formattedMessage = new StringBuilder();
formattedMessage.AppendLine("Date: " + DateTime.Now.ToString());
formattedMessage.AppendLine("Message: " + message);
_streamWriter.WriteLine(formattedMessage.ToString());
_streamWriter.Flush();
}
The stream should get flushed after each line is written to the log.
UPDATE 3
The failure is always very consistent as to how long it "hangs" before it crashes; I can see the cursor blinking in the bar code text box of the find form, and it pulsates about 20 times (I actually counted it last time: 24).
This also is a bit odd; in Update 2, I showed the contents of the log file with all the log entries sprinkled into the InitReader method. With those commented out (except for the first one), the log file ends with:
Date: 3/20/2009 12:01:22 AM
Message: Reached frmFind.InitReader
Date: 3/20/2009 12:01:22 AM
Message: From application-wide exception handler: Symbol.Exceptions.OperationFailureException: SCAN_GetInterfaceParams
at Symbol.Barcode.InterfaceParams.GetInterfaceParams()
at Symbol.Barcode.InterfaceParams..ctor(Reader reader)
at Symbol.Barcode.Actions.Enable()
at HHS.frmFind.InitReader()
...so the additional log file entries were preventing the exception msg from getting logged.
UPDATE 4
Actions.Enable?
I was unfamiliar with this, and when I added "Actions." I got a choice between Symbol.Barcode.Actions and Symbol.Generic.Actions.
I chose the first first, but it has no "Enable" method. Adding it scolded me with, "An object reference is required for the non-static field, method, or property 'Symbol.Generic.Actions.Enable()'"
I then commented out the using that was added, entered "Actions." again, and this time chose Symbol.Generic.Actions (and got the same err msg for my troubles).
How can I use Actions.Enable()?
UPDATE 5
C.Evenhuis: by "some events require re-attaching each time they occur" do you mean this:
private void StartRead()
{
// If we have both a reader and a reader data
if ((this.barcodeReader != null) && (this.barcodeReaderData != null))
{
// Submit a read
this.barcodeReader.ReadNotify += this.barcodeEventHandler;
this.barcodeReader.Actions.Read(this.barcodeReaderData);
}
}
private void StopRead()
{
// If we have a reader
if (this.barcodeReader != null)
{
// Flush (Cancel all pending reads)
this.barcodeReader.ReadNotify -= this.barcodeEventHandler;
this.barcodeReader.Actions.Flush();
}
}
...(barcodeReader.ReadNotify is attached in StartRead and detached in StopRead), or is more necessary?
I also have, in InitReader():
this.Activated += ReaderForm_Activated;
this.Deactivate += ReaderForm_Deactivate;
...which are implemented like so:
private void ReaderForm_Activated(object sender, EventArgs e)
{
// If there are no reads pending on barcodeReader start a new read
if (!this.barcodeReaderData.IsPending)
{
this.StartRead();
}
}
private void ReaderForm_Deactivate(object sender, EventArgs e)
{
this.StopRead();
}
InitReader() is called from textBoxScan_GotFocus(); textBoxScan has the focus when the form displays.
UPDATE 6
As to "Explicitly Close() classes before you Dispose() them", I call Dispose on two things, Symbol.Barcode.Reader and Symbol.Barcode.ReaderData, and neither one allows a Close() call.
UPDATE 7
This statement from C. Evenhuis: "you can't have two (foreground) readers enabled" led me to try the following:
private void FrmDelivery_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
this.barcodeReader.Actions.Disable();
}
...which seems to have pretty much done the trick - I can open the Find form without a hang resulting in an eventual crash. I can scan into the Find form after having scanned into the Delivery form. The only (unrelated?) problem that I still see is that my Find form is still partially obscured for some reason...
Symbol Motorola Zebra is building on a legacy C++ library with a legacy .NET wrapper. There are quite some pitfalls (some events require re-attaching each time they occur, some classes require explicit Close() before you Dispose() them, etc).
As you may have found out, you can invoke members of the Symbol classes from multiple threads / forms, but you can't have two (foreground) readers enabled, and some properties can only be set if no background readers are enabled, and there is no way to determine whether there are background readers enabled (ie DataWedge).
At our company we chose to initialize the scanner in the Form.Activated event and deinitialize it in the Deactivated event. Then when scanning was required, a call to Actions.Enable() would do the trick. Setting reader properties is done in try catch blocks :(
Quite odd that your application crashes at GetInterfaceParams, I would expect Setting them to cause trouble. Try your application with the bare minimum; don't set the BeepTime or WaveFile properties.
I'm not familiar with this type of scanner, but I can imagine initreader will do something at a hardware level. It will probably try to open some port. Because the port is already open it fails.
You need to implement a singleton service for your scanner instead of addressing it directly in your form. Then you can initialize the reader once for the complete application and use it wherever you'd like.
This will be a lot more 'SOLID' and thus more maintainable.
This question already has answers here:
Multithreading in C# with Win.Forms control
(2 answers)
Closed 9 years ago.
I'm beginner in C#. And I don't understand why next two examples are giving different results. I'm using microsoft example in msdn. In first example it displays one number in the textbox. In second example it displays all numbers from 0 to 1000 for each thread.
First example:
delegate void SetTextCallback(object text);
private void WriteString(object text)
{
if (this.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(WriteString);
this.BeginInvoke(d, new object[] { text });
}
else
{
for (int i = 0; i <= 1000; i++)
{
textBox1.Text = text.ToString();
}
}
}
Second example:
private void MyApp_Load(object sender, EventArgs e)
{
System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;
}
private void WriteString(object text)
{
for (int i = 0; i <= 1000; i++)
{
textBox1.Text = text.ToString();
}
}
And method which calls these examples
private void button1_Click(object sender, EventArgs e)
{
Thread th_1 = new Thread(WriteString);
Thread th_2 = new Thread(WriteString);
Thread th_3 = new Thread(WriteString);
Thread th_4 = new Thread(WriteString);
th_1.Priority = ThreadPriority.Highest;
th_2.Priority = ThreadPriority.BelowNormal;
th_3.Priority = ThreadPriority.Normal;
th_4.Priority = ThreadPriority.Lowest;
th_1.Start("1");
th_2.Start("2");
th_3.Start("3");
th_4.Start("4");
th_1.Join();
th_2.Join();
th_3.Join();
th_4.Join();
}
Well I analyzed in my VS. I am also new to C#. But what I could infer is the following:
Program 1:
Begin Invoke is aynschronous way of calling a method. Thus it shows only one result at the end. If you have slowly did F11 in VS and observe, not really everytime you get the result 4. But sometime you get 3 too when you do F11 and go step by step at certain places(I mean delaying), due to multi threading. You should remember that, multi threading always never behave in same manner all the time, which means suppose if an application or module in multithreading gives you one result at a time, two times, and 10 times, you cannot be sure that its the correct or optimized code. Because at client environment, due to its own behavior, it can lead to different results which may potentially be unnoticed while debugging or it wont even happen. I read it in a nice blog.
Program 2:
Since its multithreading, I could see the behavior of different threads getting invoked at different time, and as it does the job, I see the textboxes are getting updated quickly in fraction of seconds thats not possible for an human eye to notice, but final result, a single number is displayed. Also you do check for cross thread calls )When you do step into every line of code using F11, you will find this behavior and understand well ) and you order not to catch it. This makes the threads to work together in second case.
This is my inference, but I can say, pretty corny! I don't claim this with confidence, but just my observation :)
Let some great folks chime in with their views to help us :)
Cheers
The code below is one (of three) examples of my grief. It is a simple OpenFileDialog() call which causes the program to crash. On XP, the crash occurs if the dialog stays open for several seconds. On Vista, the crash occurs if the user selects "My Computer". In VS2008, the debugger sometimes catches a stackoverflowexception. If I put a break point in the first line (new ...), vshost.exe crashes. If I put a break point at the ShowDialog() line, I get a FatalExecutionEngineError. If I compile without vshost, the application will run until a random crash (as on XP - there is some amount of time).
There are two other open dialogs that open different types of files, all three of which have the same behavior. Similar code does not show the same behavior in my other projects.
The thread apartment is single. I have tried setting ValidateNames = false. The debugger is falling off the deep-end in most cases.
OpenFileDialog imageDlg = new OpenFileDialog();
imageDlg.Filter = "All Images|*.jpg;*.jpeg;*.png;*.tif;*.tiff;*.bmp|All Files|*.*|JPEGs (*.jpg)|*.jpg|PNGs (*.png)|*.png|TIFFs (*.tiff)|*.tiff|TIFFs (*.tif)|*.tif|BMPS (*.bmp)|*.bmp";
imageDlg.Title = "Select Scan Image";
if (DialogResult.OK == imageDlg.ShowDialog())
{
updateImageDisplay();
}
Event handler code:
//
// setScratchImageButton
//
this.setScratchImageButton.Location = new System.Drawing.Point(191, 15);
this.setScratchImageButton.Name = "setScratchImageButton";
this.setScratchImageButton.Size = new System.Drawing.Size(26, 23);
this.setScratchImageButton.TabIndex = 8;
this.setScratchImageButton.Text = "...";
this.setScratchImageButton.UseVisualStyleBackColor = true;
this.setScratchImageButton.Click += new System.EventHandler(this.setScratchImageButton_Click);
Code called
private void updateImageDisplay()
{
if (null != project.srcImage)
{
imageDisplay.SizeMode = PictureBoxSizeMode.Normal;
if (project.srcImage != null)
{
imageDisplay.ClientSize = new Size(project.srcImage.Width, project.srcImage.Height);
imageDisplay.Image = (Image)project.srcImage;
}
this.ScratchImage.Text = project.srcImageLocation;
}
else
{
imageDisplay.Image = null;
this.ScratchImage.Text = "";
}
ImageDisplayPanel.Refresh();
}
Under what circumstances is the method which displays this dialog being called? The most likely source of this error is that the event is being generated many times and causing many instances of OpenFileDialog to be displayed to the user. They are potentially being displayed on top of each other giving the appearance of only a single dialog.
EDIT
If it's only the debugger scenario that is failing then try turning off implicit function evaluation into debugger property windows (Tools -> Options -> Debugger). It's possible one of the properties on your form is causing a stack overflow when viewed through the debugger.
A DLL I had added to the project was causing heap corruption. The symptom was strange and beautiful crashes.