Form doesn't load in while loop - c#

I have a class defined to get live capture from a camera, and a form button "END CAPTURE" that should halt the capture; and an typical Application.Exit() button.
However, for some reason the while loop as shown below doesn't load the form even when the condition is met. To debug this, I commented out the while loop to see if it snaps at least 1 image; and it does (as shown in fig). What makes the while loop not to load the form and show the output continuously ?
while (!terminated)
{
// CAMERA ACQUISITION CODE
}
Figure of single while loop run:
Full program for reference:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
using mv.impact.acquire;
using mv.impact.acquire.examples.helper;
namespace mv_BlueFoxControl
{
public partial class Form1 : Form
{
private bool button1WasClicked = false;
public Bitmap SnappedBitmap = null;
public static Image PersistentImage = null;
public Form1()
{
InitializeComponent();
mv.impact.acquire.LibraryPath.init(); // this will add the folders containing unmanaged libraries to the PATH variable.
Device pDev = DeviceManager.getDevice(0);// Get a pointer to the first device found
if (pDev == null)
{
Console.WriteLine("Unable to continue! No device found! Press any key to end the program.");
//Console.Read();
Environment.Exit(1);
}
Console.WriteLine("Initialising the device. This might take some time...");
try
{
pDev.open();//start the sensor
Console.WriteLine("Device opened successfully...");
}
catch (ImpactAcquireException e)
{
// throw error code if the same device is already opened in another process...
Console.WriteLine("An error occurred while opening the device " + pDev.serial +
"(error code: " + e.Message + "). Press any key to end the application...");
//Console.ReadLine();
Environment.Exit(1);
}
bool terminated = false;// Bool terminated was here.
Console.WriteLine("Press CAPTURE to end the application");
// create thread for live capture
Thread thread = new Thread(delegate()//Start live acquisition
{
DeviceAccess.manuallyStartAcquisitionIfNeeded(pDev, fi);
Request pRequest = null;
// we always have to keep at least 2 images as the display module might want to repaint the image, thus we
// can free it unless we have a assigned the display to a new buffer.
Request pPreviousRequest = null;
int timeout_ms = 500;
int cnt = 0;
int requestNr = Device.INVALID_ID;
Console.WriteLine(terminated);
while (!terminated)
{
// CAMERA ACQUISITON CODE
}
DeviceAccess.manuallyStopAcquisitionIfNeeded(pDev, fi);
// free the last potential locked request
if (pRequest != null)
{
pRequest.unlock();
}
// clear the request queue
fi.imageRequestReset(0, 0);
// extract and unlock all requests that are now returned as 'aborted'
requestNr = Device.INVALID_ID;
while ((requestNr = fi.imageRequestWaitFor(0)) >= 0)
{
pRequest = fi.getRequest(requestNr);
Console.WriteLine("Request {0} did return with status {1}", requestNr, pRequest.requestResult.readS());
pRequest.unlock();
}
});//End of thread
Console.WriteLine(" End Thread");
thread.Start();
if (button1WasClicked)
{
terminated = true;
}
Console.WriteLine("Program termination");
Console.WriteLine(terminated);
thread.Join();
}
private void button2_Click(object sender, EventArgs e)
{
Application.Exit();
}
private void button1_Click(object sender, EventArgs e)
{
button1WasClicked = true;
}
}
}

Because of thread.Join(); The application will wait that the thread ends (which will not end until you press the button) and so the constructor is never finished.
You have to initialize a Thread field and only close it when you press the button.
Try this:
public partial class Form1 : Form
{
//...
private Thread _cameraThread;
public Form1()
{
//... the previous code
_cameraThread = new Thread(delegate()//Start live acquisition
{
// thread logic
});
_cameraThread.Start();
}
private void button2_Click(object sender, EventArgs e)
{
Application.Exit();
}
private void button1_Click(object sender, EventArgs e)
{
button1WasClicked = true;
//set the flag and wait for the thread to finish
_cameraThread.Join();
Console.WriteLine("Program termination");
}
}

Related

Launching application from server creates Open File for lifetime of application

I launch a program located on one of my file servers. After launching the program it shows as an Open file in Computer Management.
Is there a way I can close this open file while my program runs so it doesn't show up in Computer Management?
My code is below. I'd be happy to take suggestions on improving my program, but I'm really just looking for a solution to stop all these Open Files from appearing.
Program.cs -- starts the program, handles logic to launch my application
using System;
using System.Windows.Forms;
using System.Diagnostics;
namespace IT_TaskbarApp
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
string programName = "TEG System Helper";
//Process[] proc = Process.GetProcessesByName(programName);
if (Process.GetProcessesByName(programName).Length == 1)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Primary());
}
else
{
foreach (Process p in Process.GetProcessesByName(programName))
{
if (Process.GetCurrentProcess().Id != p.Id)
{
p.CloseMainWindow();
p.Close();
p.Kill();
p.Dispose();
}
}
Main();
}
}
}
}
Primary.cs -- creates an icon in the system icons which I can use to send notifications and easily access utilities within our organization
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Windows.Forms;
namespace IT_TaskbarApp
{
public partial class Primary : Form
{
private NotifyIcon notifyIcon;
private ContextMenu contextMenu;
private MenuItem[] menuItem = new MenuItem[8];
private IContainer components;
//private Boolean SendNotices = true;
private DateTime startTime = DateTime.Now;
private DateTime currentTime;
private Icon tegroupIcon = new Icon(Assembly.GetExecutingAssembly().GetManifestResourceStream("IT_TaskbarApp.Src.tegroup.ico"));
private string prevNotification = "";
private bool isRunning = true;
private BackgroundWorker bgNotify = new BackgroundWorker();
private const string programName = "TEG System Helper";
public Primary()
{
this.FormClosing += Primary_FormClosing; //remove ghost icon in taskbar
ForeColor = Color.Blue;
BackColor = Color.Green;
components = new Container();
contextMenu = new ContextMenu();
for (int i = 0; i < menuItem.Length; i++)
{
menuItem[i] = new MenuItem();
menuItem[i].Index = i;
menuItem[i].Click += new EventHandler(LoadProcess);
}
menuItem[0].Text = programName;
menuItem[1].Text = "Knowledge Base";
menuItem[2].Text = "Policies";
menuItem[3].Text = "Feedback";
menuItem[4].Text = "Global Shop Search";
menuItem[5].Text = "-";
menuItem[6].Text = "Submit Ticket";
menuItem[7].Text = "Send Email";
//initialize contextMenu
contextMenu.MenuItems.AddRange(menuItem);
// Create the NotifyIcon.
notifyIcon = new NotifyIcon(components)
{
Icon = tegroupIcon,
BalloonTipIcon = new ToolTipIcon(),
ContextMenu = contextMenu, //the menu when right clicked
Text = programName,
Visible = true,
BalloonTipTitle = programName,
};
notifyIcon.DoubleClick += new EventHandler(Icon_DoubleClick);
InitializeComponent();
bgNotify.WorkerSupportsCancellation = true;
bgNotify.WorkerReportsProgress = true;
bgNotify.DoWork += NotifyUser;
bgNotify.ProgressChanged += SendNotice;
//bgNotify.RunWorkerCompleted += BgNotify_RunWorkerCompleted; //enable this to perform an action when the thread dies
bgNotify.RunWorkerAsync();
//Thread tNotify = new Thread();
}
#region SupportedFunctions
private void NotifyUser(object Sender, EventArgs e)
{
Console.WriteLine("enter");
while (isRunning)
{
currentTime = DateTime.Now;
#region DisplayCurrentTime
if (currentTime.Hour < 10 || currentTime.Minute < 10)
{
if (currentTime.Hour < 10)
{
if (currentTime.Minute < 10)
{
Console.WriteLine("0{0}:0{1}", currentTime.Hour, currentTime.Minute);
}
else
{
Console.WriteLine("0{0}:{1}", currentTime.Hour, currentTime.Minute);
}
}
else
{
if (currentTime.Minute < 10)
{
Console.WriteLine("{0}:0{1}", currentTime.Hour, currentTime.Minute);
}
}
}
else
{
Console.WriteLine("{0}:{1}", currentTime.Hour, currentTime.Minute);
}
#endregion
FileStream fs = new FileStream("\\\\te-admin\\public\\TaskbarNotices.txt", FileMode.Open);
StreamReader sr = new StreamReader(fs);
string noticeText = sr.ReadToEnd();
sr.Close();
fs.Close();
if (noticeText != "" && noticeText != prevNotification)
{
prevNotification = noticeText;
bgNotify.ReportProgress(1);
}
else
{
bgNotify.ReportProgress(2);
}
Console.WriteLine("Inner Text: {0} TOF: {1}", noticeText, noticeText != "");
Thread.Sleep(10000);
}
}
private void SendNotice(object Sender, ProgressChangedEventArgs e)
{
if (e.ProgressPercentage == 1)
{
Console.WriteLine("notification sent");
this.notifyIcon.BalloonTipText = prevNotification;
this.notifyIcon.ShowBalloonTip(1500);
}
}
private void LoadProcess(object Sender, EventArgs e)
{
if (Sender is MenuItem)
{
MenuItem tempMenu = Sender as MenuItem;
string ProgramTag = "http://";
switch (tempMenu.Index)
{
case 0: //home page
ProgramTag += "teg";
break;
case 1: //docviewer
ProgramTag += "teg/docViewer";
break;
case 2: //policies
ProgramTag += "teg/Policies";
break;
case 3: //feedback
ProgramTag += "teg/Feedback";
break;
case 4: //inventory search
ProgramTag = "http://searchglobalshop/inventory/index.aspx";
break;
case 6: //submit ticket
ProgramTag = "https://timberlandgroup.on.spiceworks.com/portal/tickets";
break;
case 7: //send email
string sendto = "admin#tewinch.com";
string emailSubject = "Assistance Request";
string emailBody = "";
string mailto = string.Format("mailto:{0}?Subject={1}&Body={2}", sendto, emailSubject, emailBody);
ProgramTag = Uri.EscapeUriString(mailto);
break;
}
/*
Try to launch the choice the user made with the default processing method.
Should the default method fail we try to control how the process is run.
We open internet explorer and then we show them what to do otherwise.
*/
#region LaunchSelectedProcess
try
{
if (ProgramTag != "" && ProgramTag != "http://")
Process.Start(ProgramTag);
}
catch (System.ComponentModel.Win32Exception)
{
try
{
if (ProgramTag.StartsWith("http://") || ProgramTag.StartsWith("https://"))
Process.Start("iexplore.exe", ProgramTag);
}
catch (System.ComponentModel.Win32Exception)
{
Process.Start("control.exe", "/name Microsoft.DefaultPrograms");
string message = "";
if (tempMenu.Index <= 6)
{
message = "You must have a default browser set\n\tClick [Set Default Program]\n";
if (Environment.OSVersion.ToString().Contains("NT 10.")) //windows 10
{
message += "\tUnder [Web Browser] Edge is currently set as default\n\tClick on Microsoft Edge\n\tSelect the browser you use";
}
else //windows 7 -- "NT 6.1")
{
message += "Select the browser you use\n\tClick [Set this program as default]";
}
}
else
{
if (Environment.OSVersion.ToString().Contains("NT 10.")) //windows 10
{
message += "Please setup a default email application";
}
}
message += "\n\nIf this issue persists please contact your Administrator.\nPhone: 519-537-6262\nEmail: admin#tewinch.com";
MessageBox.Show(message, "Application Warning", MessageBoxButtons.OK, MessageBoxIcon.Information);
//if ( == DialogResult.OK)
}
}
#endregion
}
}
private void Icon_DoubleClick(object Sender, EventArgs e)
{
Process.Start("http://teg");
}
#endregion
#region BuiltFunctions
private void Primary_FormClosing(object sender, FormClosingEventArgs e)
{
notifyIcon.Icon = null;
notifyIcon.Dispose();
isRunning = false;
Dispose(true);
}
private void InitializeComponent()
{
this.SuspendLayout();
//
// Primary
//
this.Icon = tegroupIcon;
this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
this.CausesValidation = false;
this.ClientSize = new System.Drawing.Size(120, 23);
this.ControlBox = false;
this.Enabled = false;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "Primary";
this.Opacity = 0D;
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.WindowState = System.Windows.Forms.FormWindowState.Minimized;
this.ResumeLayout(false);
}
protected override void Dispose(bool disposing)
{
// Clean up any components being used.
if (disposing)
if (components != null)
components.Dispose();
base.Dispose(disposing);
}
#endregion
}
}
Instead of cancelling the program on start up, I kill the other running instances of the program. The idea is that if any issues arise with the program I just launch another instance and resolve the issues. Right now not much can go wrong but we will be developing this program to complete many more tasks in the future.
The only area I can see which would keep a file open is when I pull an Embedded Resource tegroup.ico I was looking to see if I missed something while opening this, but I couldn't see a way to close the ManifestResourceStream after reading it in.
Any tips/suggestions would be wonderful but again, I really just want to know if there's a way I can close these Open Files
Example below
Open File after app launch
I might be trying to solve something which is a known result of using Application.Run() if this is the case then please suggest alternatives I can use. My other ideas would be loading the program into memory and launching it locally, using the .exe on the server as a starting point for this method though.
I believe that Windows doesn't load an entire executable into ram. It isn't just about files from the resource section of a PE file. Portions of the exe are only loaded when referenced and even after loading everything there is to load, Windows will maintain an open file handle until the process closes. Trying to close that handle yourself is a bad idea.
c/c++ allow a "SWAPFILE" flag to be specified that tells windows to put the whole thing into the page file but I don't know how you would do that with c# and I don't know if that would even stop windows from keeping the handle open anyways (I doubt it).
If this is truly important, iffin' I were your exe... I would:
Check a mutex for an existing running instance, exit if exist
Check where I was running from.
If running from temp, set a mutex that I am running and just run.
If not running from temp, copy myself to %temp%, start that copy, and exit.
Good luck.

How can I create a button click handler?

I have a number of buttons which flicker at different frequencies in my Wondows Form Application. When a specific frequency is measured on the head by an electrode, the signal undergoes signalprocessing in MATLAB, hereafter the frequency found are sent to the application, where the specific value from the UDP connection should press the button which have this specific flickering frequency. I am a bit lost how to create this button handler, using the data I get from Matlab. My thought is:
Value from connection ->
if value == 6
{
button1 is clicked
}
elseif value == 6.5
{
button2 is clicked
}
and so forth.
Any ideas any one ?
if(returnData == String.Empty)
{
}
else
{
button2.PerformClick();
}
Here the returnData is the ongiong incomming data from the UDP connection to MATLAB, you this would work ?
And for another question, I am having a bit of trouble with UDP connection, I would like if it could receive the data I am sending, right now, I have to press a button to open and recieve data, I have made it like this, because I could not update the data otherwise. In mind, I am a novice to C#.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
namespace WindowsFormsApplication4
{
public partial class Form1 : Form
{
//public UdpClient receivingUdpClient = null;
public string returnData;
//public byte[] Receive(ref IPEndPoint remoteEP);
// private Print print = null;
//while (true)
//{
public UdpClient receivingUdpClient = new UdpClient(8051);
//bool done = false;
//Creates an IPEndPoint to record the IP Address and port number of the sender.
// The IPEndPoint will allow you to read datagrams sent from any source.
//while (true)
//{
public IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8051);
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
label1.Visible = false;
label2.Visible = false;
}
void button1_Click(object sender, EventArgs e)
{
label1.Visible = false;
try
{
//while (true)
//{
// Blocks until a message returns on this socket from a remote host.
Byte[] receiveBytes = receivingUdpClient.Receive(ref RemoteIpEndPoint);
returnData = Encoding.ASCII.GetString(receiveBytes);
Console.WriteLine("This is the message you received " +
returnData.ToString());
Console.WriteLine("This message was sent from " +
RemoteIpEndPoint.Address.ToString() +
" on their port number " +
RemoteIpEndPoint.Port.ToString());
// }
}
catch (Exception err)
{
Console.WriteLine(err.ToString());
}
if(returnData == String.Empty)
{
}
else
{
button2.PerformClick();
}
}
void button2_Click(object sender, EventArgs e)
{
if (SPELL.Text == String.Empty)
{
SPELL.Text = SPELL.Text + returnData;
label1.Visible = true;
}
else
{
SPELL.Text = null;
SPELL.Text = SPELL.Text + returnData;
label1.Visible = true;
label2.Visible = true;
}
}
}
}
This is my small test program in VIsual Studio so far.
Thanks.
If you want to simulate a button click from code behind, you could simply call the button's handler wherever you want the call to be made.
E.g.
if (value == 6)
{
this.button1_click(this,new EventArgs()) //button1 is clicked
}
else if (value == 6.5)
{
this.button2_click(this,new EventArgs()) //button2 is clicked
}
I'd recommend you better move the button handler's logic to a separate method and call the method instead of calling the handler directly.

I need SerialPort event on NewLine received

I need event, that will call my function after full line received, not just one byte.
SerialPort object in .NET has 3 events: DataReceived, ErrorReceived, PinChanged.
When im using DataReceived - event is "firing" after 1 byte, or after "x" bytes defined in "ReceiveByteThreshold" property. Line length may vary, so i cant predict "x".
Can someone give me a hint?
I have to create some buffer, which will collect bytes until LF/CRLF, or there is better approach to problem?
You cannot get this, the only option is SerialPort.ReceivedBytesThreshold to delay the DataReceived event handler call and that's useless for a variable length response.
The workaround is very simple, just call ReadLine() in your DataReceived event handler. That will block on a worker thread, not affecting anything else going on in your program. No danger either of additional events firing while the ReadLine() call is blocking, it is interlocked inside the SerialPort class. Use the ReadTimeout property if necessary if the communication isn't reliable enough so ReadLine() will not block forever. Set it to ten times the expected delay in receiving the longest possible response.
You'll have to do it yourself. Use DataReceived and check each byte. Collect the bytes in a buffer until you get a newline and then handle the buffer as a line at that point.
The hint:
The SerialPort class has a property NewLine to set the value used to interpret the end of a call to the ReadLine method.
Here is my quickly implemented, non blocking, same thread solution. It is a very basic state machine that waits for '\r' and '\n' and then sends all the buffered characters for parsing. You can alter it to whatever line-break value you want by changing the state machine itself.
In this approach you can register for the OnNewLineReceived event and process the data from the SerialStringMessgae eventhandler.
No try/catch overhead. No deadlocks.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace NonBlockingSerialPortReadLine
{
public partial class Form1 : Form
{
System.IO.Ports.SerialPort sp = new System.IO.Ports.SerialPort();
public event EventHandler OnNewLineReceived;
System.Windows.Forms.Timer NewDataTimer = new System.Windows.Forms.Timer();
int StateMachine = 0;
StringBuilder stringBuffer = new StringBuilder();
public Form1()
{
InitializeComponent();
InitTimer();
InitOnNewLineReceived();
}
private void InitTimer()
{
NewDataTimer.Interval = 50;
NewDataTimer.Tick += NewDataTimer_Tick;
}
private void InitOnNewLineReceived()
{
OnNewLineReceived += Form1_OnNewLineReceived;
}
void Form1_OnNewLineReceived(object sender, EventArgs e)
{
SerialStringMessgae STM = e as SerialStringMessgae;
string messgae = STM.message;
// PARSE YOU MESSAGE HERE - the debug line below is not mandatory
System.Diagnostics.Debug.WriteLine(messgae);
}
class SerialStringMessgae : EventArgs
{
public string message;
}
private void StartListeningButton_Click(object sender, EventArgs e)
{
StartListeningButton.Enabled = false;
sp = new System.IO.Ports.SerialPort("COM4",57600, System.IO.Ports.Parity.None, 8, System.IO.Ports.StopBits.One);
try
{
sp.Open();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
return;
}
if (sp.IsOpen)
{
NewDataTimer.Enabled = true;
}
}
void NewDataTimer_Tick(object sender, EventArgs e)
{
string newData = sp.ReadExisting();
foreach (char c in newData)
{
switch (StateMachine)
{
case 0:
// waiting for '\r'
if (c == '\r')
{
StateMachine = 1;
}
else
{
stringBuffer.Append(c);
}
break;
case 1:
// waiting for '\n'
if (c == '\n')
{
if (OnNewLineReceived != null)
{
SerialStringMessgae STM = new SerialStringMessgae();
STM.message = stringBuffer.ToString();
OnNewLineReceived(this, STM);
}
}
// after parsing the message we reset the state machine
stringBuffer = new StringBuilder();
StateMachine = 0;
break;
}
}
}
}
}

Function works when called synchronously, but does not work when called asynchronously

It is my first post on StackOverflow forum so please to be lenient. I have a problem with function which works called synchronously, but doesnot works called asynchronously.
Below You will find function called synchronously:
private void issueInvoices(List<int> lista)
{
foreach (int knh_id in lista)
{
Invoice fs = new Invoice();
fs.FKS_AKCYZA = false;
fs.FKS_CZY_KLON = false;
fs.FKS_DATE = Convert.ToDateTime(MTBDataZapisuDoFK.Text);
fs.NUMBER = knh_id);
}
}
As You can see i passed list to function named issueInvoices list of invoice numbers and in loop i create some invoices.
This function works properly but if i try to call it asynchronously (to display progress bar) my function can not assign to fs.FKS_DATE object dateTime. It looks like static function “Convert.ToDateTime” doesnot work properly. But please take a look on below code where function issueInvoices is called asynchronously…
public delegate void BinaryDelegate(List<int> knh_id);
BinaryDelegate b = new BinaryDelegate(issueInvoices);
IAsyncResult theAsRes = b.BeginInvoke(lista, new AsyncCallback(AddComplete), "Thx U!");
FrmProgressBar fpb=new FrmProgressBar(“Please wait…”);
fpb.Show();
/* below i check how many operation i have to do, if all operations are done, then I close fpb window, program is updating progres bar and in thread make operation issueInvoices*/
while (ilosc_zrobionych != liczbaKontrahentow)
{
fpb.PBStan.Value = (int)((100 * ilosc_zrobionych) / liczbaKontrahentow);
}
fpb.Close();
I put some breakpoints and it looks like program stoping in line, it can conver to datetime, but when i do this synchronously, it works without any errors.
fs.FKS_DATE = Convert.ToDateTime(MTBDataZapisuDoFK.Text);
What could couse this problem and how to resolve it?
Many thanks in advance for reply.
BELOW IS WHOLE CLASS CALLED ASYNCHRONOUSLY:
using System;
using System.Collections.Generic;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Npgsql;
using Castle.ActiveRecord;
using WFR.Model;
using System.Threading;
namespace Faktury_i_Rachunki_2.Forms
{
public partial class FrmEmisjaFakturPotwierdzonych : FrmBaseForm
{
private ArrayList listaSposobowZaplaty;
public List<int> lista;
private int liczbaWygenerowach;
private int liczbaKontrahentow;
private int ilosc_zrobionych;
private FrmProgressBar fpb;
public delegate void BinaryDelegate(List<int> knh_id);
public FrmEmisjaFakturPotwierdzonych()
{
InitializeComponent();
fpb = new FrmProgressBar("Please wait....");
}
private void BtOK_Click(object sender, EventArgs e)
{
BinaryDelegate b = new BinaryDelegate(WyemitujFakture);
lista.Add(12);
lista.Add(13);
lista.Add(17);
lista.Add(1);
liczbaKontrahentow = lista.Count;
if (TBRejestr.Text.Trim() != "")
{
if (liczbaKontrahentow > 0)
{
liczbaWygenerowach = 0;
ilosc_zrobionych = 0;
WyemitujFakture(lista);
IAsyncResult theAsRes = b.BeginInvoke(lista, new AsyncCallback(AddComplete), "THX");
fpb.Show();
while (ilosc_zrobionych != liczbaKontrahentow)
{
fpb.PBStan.Value = (int)((100 * ilosc_zrobionych) / liczbaKontrahentow);
}
fpb.Close();
}
try
{
MessageBox.Show("Wygenerowano " + liczbaWygenerowach.ToString() + " faktur");
}
catch
{
}
}
}
private void WyemitujFakture(List<int> lista)
{
foreach (int knh_id in lista)
{
try
{
if (luk.Count > 0)
{
FakturySprzedazy fs = new FakturySprzedazy();
fs.FKS_AKCYZA = false;
fs.FKS_CZY_KLON = false;
fs.FKS_DATA_DOW_KS = Convert.ToDateTime(MTBDataZapisuDoFK.Text);
fs.FKS_DATA_FAKTURY = Convert.ToDateTime(MTBDataFaktury.Text);
fs.FKS_DATA_SPRZEDAZY = Convert.ToDateTime(MTBDataSprzedazy.Text);
liczbaWygenerowach++;
}
}
catch (Exception ex)
{
MessageBox.Show("Nie można wyemitować faktury dla kontrahenta o id = " + knh_id.ToString() + " " + ex.Message);
}
ilosc_zrobionych++;
}
}
You are accessing a UI control from a background thread:
MTBDataZapisuDoFK.Text
That is not allowed.
Get this value before calling the method, store it in a variable and send the value as an argument to issueInvoices.
The problem is in getting the value of MTBDataZapisuDoFK.Text (which I assume to be a textbox). Getting or setting the text of a textbox means sending messages to its window. But you keep the UI-thread busy in the while loop and therefore it can not process any messages.
Put a call to Application.DoEvents() into the while loop to allow messages to be processed:
fpb.Show();
while (ilosc_zrobionych != liczbaKontrahentow)
{
Application.DoEvents();
fpb.PBStan.Value = (int)((100 * ilosc_zrobionych) / liczbaKontrahentow);
}
fpb.Close();
I assume that the only reason for calling the method asynchronously is to be able to update the UI during processing the WyemitujFakture-method. Using Application.DoEvents() you do not need asynchonous calls:
fpb = new FrmProgressBar("Please wait....");
fpb.Show();
Application.DoEvents();
WyemitujFakture(lista);
fpb.Close();
You should call Application.DoEvents() after you call fpb.Show() to allow the form to be displayed properly. Also you should instantiate the form in the method itself instead of the constructor, because you can not use the same instance again after calling fpb.Close() (it will be disposed).
Then you can update the progress bar in the WyemitujFakture-method:
private void WyemitujFakture(List<int> lista)
{
foreach (int knh_id in lista)
{
try
{
if (luk.Count > 0)
{
FakturySprzedazy fs = new FakturySprzedazy();
fs.FKS_AKCYZA = false;
fs.FKS_CZY_KLON = false;
fs.FKS_DATA_DOW_KS = Convert.ToDateTime(MTBDataZapisuDoFK.Text);
fs.FKS_DATA_FAKTURY = Convert.ToDateTime(MTBDataFaktury.Text);
fs.FKS_DATA_SPRZEDAZY = Convert.ToDateTime(MTBDataSprzedazy.Text);
liczbaWygenerowach++;
}
}
catch (Exception ex)
{
MessageBox.Show("Nie mozna wyemitowac faktury dla kontrahenta o id = " + knh_id.ToString() + " " + ex.Message);
}
ilosc_zrobionych++;
fpb.PBStan.Value = (int)((100 * ilosc_zrobionych) / liczbaKontrahentow);
Application.DoEvents();
}
}

C# TcpClient not sending or reading 100% of data?

Hey all. I'm writing a simple client/server application (just for the experience, networking is fairly new to me) where the client sends the server data and the server outputs it to a textbox. It all works fine, except for one small detail... It seems sometimes a connection is made, but the data isn't being sent or read (can't work out which) and thus nothing is being outputted in the textbox. Every time a connection is made a counter is incremented, same thing when a data block is received. When you compare the two, the number of connections is correct but the data counter is usually lower, sometimes by as much as half. Anyway, if anyone can give me some advice or point me in the right direction, it would be greatly appreciated!
Here's the code if you require it:
(SERVER_CODE)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace Server
{
public partial class Form1 : Form
{
public int Connections = 0;
public int blocks = 0;
public int threads = 0;
public Thread MasterThread;
public TcpListener Master;
public volatile bool Run;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
public void StartMaster()
{
Master = new TcpListener(IPAddress.Any, 1986);
Master.Start();
MasterThread = new Thread(new ThreadStart(RunMaster));
MasterThread.Start();
}
public void RunMaster()
{
threads++;
label6.Text = String.Format("{0}", threads);
while (Run)
{
TcpClient client = Master.AcceptTcpClient();
Connections++;
label4.Text = String.Format("{0}", Connections);
Thread ClientThread = new Thread(new ParameterizedThreadStart(RunClient));
ClientThread.Start(client);
}
Master.Stop();
threads--;
label6.Text = String.Format("{0}", threads);
}
public void RunClient(object tcpClient)
{
TcpClient client = (TcpClient)tcpClient;
byte[] buffer = new byte[4096];
int byteCount = 0;
NetworkStream stream = client.GetStream();
threads++;
label6.Text = String.Format("{0}", threads);
while (Run)
{
try
{
byteCount = stream.Read(buffer, 0, 4096);
}
catch
{
//Connections--;
break;
}
if (byteCount == 0)
{
//Connections--;
break;
}
blocks++;
label5.Text = String.Format("{0}", blocks);
textBox1.AppendText(Encoding.ASCII.GetString(buffer, 0, byteCount) + "\r\n");
}
client.Close();
threads--;
label6.Text = String.Format("{0}", threads);
}
private void button1_Click(object sender, EventArgs e)
{
Run = true;
StartMaster();
}
private void button2_Click(object sender, EventArgs e)
{
Run = false;
}
}
}
(CLIENT_CODE)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace Client
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1986);
TcpClient client = new TcpClient();
try
{
client.Connect(endPoint);
}
catch
{
MessageBox.Show("Connect Error");
}
NetworkStream stream = client.GetStream();
byte[] data = Encoding.ASCII.GetBytes(textBox1.Text);
stream.Write(data, 0, data.Length);
stream.Flush();
client.Close();
}
}
}
Thank-you,
Tristan!.
Well, to start with you're crippling your own diagnostics with this:
catch
{
//Connections--;
break;
}
Why are you swallowing exceptions without any logging etc? Maybe an exception is being thrown, and you have no way of knowing. Ideally you should catch specific exceptions, and when you do catch an exception at least log what's going on.
At the other end of the spectrum, Wireshark should help you to work out whether the data is being sent or not.
I haven't had a thorough look at your code yet, but after a quick glance, you access variables from multiple threads without proper locking. A statement like x++; has to read the value of x, increment it, and write it back. Now if you have two threads doing this, you might run into this situation:
x = 0
Thread 1 Thread 2
------------------------
Read (0)
Read (0)
Increment (1)
Increment (1)
Write (1)
Write (1)
=> x = 1 instead of 2
If you need to access variables from multiple threads, ALWAYS synchronize unless you know exactly what you're doing. For example, create and use a synchronization object like this:
int threads = 0;
object threadSync = new object();
...
lock (threadSync) {
threads++;
}
Then only one thread may access the variable at a time and values are incremented correctly.
Edit: Another problem is that you access visible controls from a different thread than the one that created them. Early .NET versions allowed this, but the newer don't. If you need to update status messages, you need to look at the control's InvokeRequired property and if set to true, use Control.Invoke(...) to call a method that sets the property.

Categories