i have 2 script 1- Soket.cs (Soket Server Working with thread) FormMain.cs(Working Normal) i call a function in FormMain from soket.cs with this code :
public void ResiveFunc(string FuncResive)
{
string FuncName = "";
string FuncValue = "";
for (int i = 0; i <= 2; i++)
{
FuncName += FuncResive[i];
}
for (int j = 4; j <= FuncResive.Length - 1; j++)
{
FuncValue += FuncResive[j];
}
MessageBox.Show(FuncName);
MessageBox.Show(FuncValue);
if (FuncName == "TAB")
{
Form1 mainForm = new Form1();
mainForm.AdverFilter(FuncValue);
}
FuncName = "";
FuncValue = "";
}
i call this AdverFilter() function in FormMain :
public void AdverFilter(string value)
{
Messagebox.show(value);
this.richTextBox1.Text = value;
}
but its dont work!!! Messagebox show fine the value but richtextbox is null...
please tell me how can i fix this problem...!?
Update:
I changed my code to the following:
public void AdverFilter(string value)
{
if (this.InvokeRequired)
{
this.BeginInvoke(new Action<string>(AdverFilter),value);
}
else
{
MessageBox.Show(value);
this.richTextBox1.Text = value;
}
}
This code has no syntax errors, but it still doesn't work. I added MessageBox.Show(richTextBox1.Text); to this code. It shows true but my Richtextbox is null.
EDIT: Ok, that additional code cleared things a bit.
The callback is most likely done through ThreadPool and so the thread's apartment state is MTA. This is a problem because you are creating the form in the callback's thread and the forms require that the apartment state must be STA. Maybe you should create the form in the main thread and then use the ISynchronizeInvoke interface as shown by Fredrik Mörk.
PS. You should use System.String.Substring(...) to get the FuncName and FuncValue:
string FuncName = FuncResive.Substring(0, 3);
string FuncValue = FuncResive.Substring(4);
And why the FuncName and FuncValue values are set to empty string in the end? There is no reason for that.
Related
I am calling a VB 6.0 dll in Parallel.ForEach and expecting all calls to be started simultaneously or at least 2 of them based on my PC's cores or threads availability in thread pool
VB6 dll
Public Function DoJunk(ByVal counter As Long, ByVal data As String) As Integer
Dim i As Long
Dim j As Long
Dim s As String
Dim fno As Integer
fno = FreeFile
Open "E:\JunkVB6Dll\" & data & ".txt" For Output Access Write As #fno
Print #fno, "Starting loop with counter = " & counter
For i = 0 To counter
Print #fno, "counting " & i
Next
Close #fno
DoJunk = 1
End Function
counter is being passed from the caller to control execution time of the call and file is being written to make it an IO based process.
C# caller
private void ReportProgress(int value)
{
progressBar.Value = value;
//progressBar.Value++;
}
private void button1_Click(object sender, EventArgs e)
{
progressBar.Value = 0;
counter = 0;
Stopwatch watch = new Stopwatch();
watch.Start();
//var range = Enumerable.Range(0, 100);
var range = Enumerable.Range(0, 20);
bool finished = false;
Task.Factory.StartNew(() =>
{
Parallel.ForEach(range, i =>
{
#region COM CALL
JunkProject.JunkClass junk = new JunkProject.JunkClass();
try
{
Random rnd = new Random();
int dice = rnd.Next(10, 40);
int val = 0;
if (i == 2)
val = junk.DoJunk(9000000, i.ToString());
else
val = junk.DoJunk(dice * 10000, i.ToString());
System.Diagnostics.Debug.Print(junk.GetHashCode().ToString());
if (val == 1)
{
Interlocked.Increment(ref counter);
progressBar.Invoke((Action)delegate { ReportProgress(counter); });
}
junk = null;
}
catch (Exception excep)
{
i = i;
}
finally { junk = null; }
#endregion
});
}).ContinueWith(t =>
{
watch.Stop();
MessageBox.Show(watch.ElapsedMilliseconds.ToString());
});
}
This line is making a specific call longer than the others.
val = junk.DoJunk(9000000, i.ToString());
Here this second process is causing all calls inside the Parallel.ForEach to stop i.e. no other file is created unless this 2nd call gets completed.
Is it an expected behavior or i am doing something wrong?
As #John Wu suggested that you can create AppDomain to allow COM to run on different App Domain, I believe you could run your parallel like this.
Parallel.ForEach(range, i =>
{
AppDomain otherDomain = AppDomain.CreateDomain(i.ToString());
otherDomain.DoCallBack(delegate
{
//Your COM call
});
});
EDIT
Right.. I am not sure how can you set serializable on VB6.0 class. You can try the other way (Marshaling objects by reference). Noted: I haven't actually tested this, but I would like to know if that will work.
Parallel.ForEach(range, i =>
{
AppDomain otherDomain = AppDomain.CreateDomain(i.ToString());
var comCall = (ComCall) otherDomain.CreateInstanceFromAndUnwrap(Assembly.GetExecutingAssembly().Location, typeof(ComCall).ToString());
comCall.Run();
AppDomain.Unload(otherDomain);
});
and the class
public class ComCall : MarshalByRefObject
{
public void Run()
{
//Your COM Call
}
}
Here is also additional reference regarding the topic.
https://www.codeproject.com/Articles/14791/NET-Remoting-with-an-easy-example
I have to assign values to members(I don't know if this is the right term) of an array. I delcared my array members as follow: (all this code is inside a public class BWClass)
public static BackgroundWorker[] bwCA = new BackgroundWorker[25];
public static int NumbwCA;
private static bool HasRunOnce = false;
public static void BackgroundWorkerInitializer(bool doFirst, int numbwCA)
{
// Okay we got here. So we can presume that array checking (number not exceeding the array) is already done
if (!HasRunOnce)
{
NumbwCA = numbwCA; // for access
} // Now it is impossible to stop less backgroundworkers then started later on in the code
if (doFirst)
{
for (int i = 0; i < NumbwCA; i++)
{
string strpara = (numbwCA.ToString()); // Could also directly write numbwCA.ToString() directly in the RunWorkerAsync() method
bwCA = new BackgroundWorker[NumbwCA];
bwCA[i] = new BackgroundWorker();
bwCA[i].WorkerReportsProgress = true;
bwCA[i].WorkerSupportsCancellation = true;
bwCA[i].DoWork += new DoWorkEventHandler(bwa_DoWork);
bwCA[i].ProgressChanged += new ProgressChangedEventHandler(bwa_ProgressChanged);
bwCA[i].RunWorkerCompleted += new RunWorkerCompletedEventHandler(bwa_RunWorkerCompleted);
bwCA[i].RunWorkerAsync(strpara);
}
}
else // DoSecond
{
// stop the backgroundworkers
for (int i = 0; i < NumbwCA; i++)
{
if (bwCA[i].IsBusy == true)
{
bwCA[i].CancelAsync();
HasRunOnce = false; // If restarting the server is required. The user won't have to restart the progrem then
}
else
{
Console.WriteLine(">>The backgroundworkers are already finished and don't need canceling");
}
}
}
}
Al this code is inside a public class.
I thought that when I do all the array making in a class I won't have the problem of variable scopes anymore. But I was wrong. I still get the Error nullReferenceException when the bwCA[i].IsBusy == true runs. Probably also when anything outside the for loop runs.
I know that I can't use the bwCA[i] outside the loop were it is declared but how do I change this, so that I can access bwCA[i] (anywhere) else in the code (like in the "else // DoSecond)?
btw. I prefer not to use a List
You need to move the array creation outside the loop
// here for instance
bwCA = new BackgroundWorker[NumbwCA];
if (doFirst)
{
for (int i = 0; i < NumbwCA; i++)
{
string strpara = (numbwCA.ToString());
// bwCA = new BackgroundWorker[NumbwCA];
That still leaves a few issues with cleanup and running this Initializer twice.
More general, try to avoid static stuff and you shouldn't be needing 25 Backgroundworkers in the first place.
Tasks are probably more appropriate but we can't tell.
I have script for refresh network with object label and panel but in script using looping mode with 'for'. I want to this real time refresh for 1 sec or 5 sec but because using 'for' make this procces need more time and get stuck screen. how to make the solution more quickly and in real time?
Thanks
public PosPing()
{
InitializeComponent();
RefreshPOS.Tick += new EventHandler(CheckPOSUG);
RefreshPOS.Start();
}
private void CheckPOSUG(object sender, EventArgs e)
{
Panel[] panelUG = new Panel[]{pnlPOSUG1,pnlPOSUG2,pnlPOSUG3,pnlPOSUG4,pnlPOSUG5,pnlPOSUG6,pnlPOSUG7,pnlPOSUG8};
Label[] LabelUG = new Label[]{lblUG1,lblUG2,lblUG3,lblUG4,lblUG5,lblUG6,lblUG7,lblUG8};
Label[] lblSpdUG = new Label[] { lblSpdUG1, lblSpdUG2, lblSpdUG3, lblSpdUG4, lblSpdUG5, lblSpdUG6, lblSpdUG7, lblSpdUG8 };
for (int x = 0; x < 8;x++ )
{
string IP = "192.168.135.1" + (x + 1).ToString();
var ping = new Ping();
var reply = ping.Send(IP, 10 * 1000);
LabelUG[x].Text = "POSBMS10" + x.ToString();
if (reply.Status == IPStatus.Success)
{
lblSpdUG[x].Text = reply.RoundtripTime.ToString() + " " + "ms";
panelUG[x].BackColor = Color.FromName("Lime");
}
else
{
lblSpdUG[x].Text = "Nonaktif";
panelUG[x].BackColor = Color.FromName("ButtonHighlight");
}
}
}
Without a good, minimal, complete code example, it's hard to know for sure how to best answer your question. But it looks like you are trying to ping eight different servers, which are represented by eight set of controls in your form.
If that is correct, then I agree with commenter Hans Passant that you should be using the SendPingAsync() method instead. This will allow you to execute the pings asynchronously, without blocking the UI thread, so that your program can remain responsive.
Because you are dealing with eight different servers, it makes sense to me that you should execute the eight pings asynchronously. To accomplish this, I would refactor the code a bit, putting the server-specific loop body into a separate method, so that each instance can be run concurrently.
Implementing it that way would look something like this:
private async void CheckPOSUG(object sender, EventArgs e)
{
Panel[] panelUG = new Panel[]{pnlPOSUG1,pnlPOSUG2,pnlPOSUG3,pnlPOSUG4,pnlPOSUG5,pnlPOSUG6,pnlPOSUG7,pnlPOSUG8};
Label[] LabelUG = new Label[]{lblUG1,lblUG2,lblUG3,lblUG4,lblUG5,lblUG6,lblUG7,lblUG8};
Label[] lblSpdUG = new Label[] { lblSpdUG1, lblSpdUG2, lblSpdUG3, lblSpdUG4, lblSpdUG5, lblSpdUG6, lblSpdUG7, lblSpdUG8 };
Task[] tasks = new Task[8];
for (int x = 0; x < 8; x++)
{
tasks[x] = PingServer(x, panelUG[x], LabelUG[x], lblSpdUG[x]);
}
try
{
await Task.WhenAll(tasks);
}
catch (Exception e)
{
// handle as appropriate, e.g. log and exit program,
// report expected, non-fatal exceptions, etc.
}
}
async Task PingServer(int index, Panel panel, Label ugLabel, Label spdLabel)
{
// NOTE: String concatenation will automatically convert
// non-string operands by calling calling ToString()
string IP = "192.168.135.1" + (index + 1);
var ping = new Ping();
var reply = await ping.SendPingAsync(IP, 10 * 1000);
ugLabel.Text = "POSBMS10" + x;
if (reply.Status == IPStatus.Success)
{
spdLabel.Text = reply.RoundtripTime + " ms";
// The Color struct already has named properties for known colors,
// so no need to pass a string to look Lime up.
panel.BackColor = Color.Lime;
}
else
{
spdLabel.Text = "Nonaktif";
panel.BackColor = Color.FromName("ButtonHighlight");
}
}
I'm using .NET 3.5 CF and trying to create a textbox which should hide the character written inside it. This works by setting the parameter PasswordChar to = "*". However this change the char to a * directly.
What I want is a "smart" textbox who change the character to a * after a delay (approximate 1 second) which will make the user to get some feedback that correct character was written.
I tried this by creating another thread that should handle this since the user should still be able to write more characters and not wait this delay. I did something like this:
if (UseModernPasswordScreenMaskning)
{
this.Invoke(new UpdateTextCallback(this.UpdateText), new object[]{"*"});
}
private void UpdateText(string text)
{
int k = this.Text.Length;
System.Threading.Thread.Sleep(1000);
this.Text = this.Text.Remove(k - 1, 1);
this.Text = this.Text.Insert(k - 1, "*");
}
It works but the sleep is on my current thread which make next letter written delay by 1 second before it shows up. I want each letter to show directly and change to a *, 1 second after that particular char was written.
As i understand, a "smart" password textbox is
the last character will become * within 1s
if user type a new character, the older one will become * (although it doesn't last 1s)
So
Create a timer callback with 1s interval to change last character to *
In smartTextBox_TextChanged event, change the previous character to *
Here is my code
public void Do(object state)
{
int num = this.textBox1.Text.Count();
if (num > 0)
{
StringBuilder s = new StringBuilder(this.textBox1.Text);
s[num - 1] = '*';
this.Invoke(new Action(() =>
{
this.textBox1.Text = s.ToString();
this.textBox1.SelectionStart = this.textBox1.Text.Count();
timer.Dispose();
timer = null;
}));
}
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
if (timer == null)
{
timer = new System.Threading.Timer(timerCallback, null, 1000, 1000);
}
int num = this.textBox1.Text.Count();
if (num > 1)
{
StringBuilder s = new StringBuilder(this.textBox1.Text);
s[num - 2] = '*';
this.textBox1.Text = s.ToString();
this.textBox1.SelectionStart = num;
}
}
In initialize
timerCallback = new TimerCallback(Do);
I managed to solve it by adding since the line "int num = this.textBox1.Text.Count();" could not be used before that statement:
public void Do(object state)
{
if (this.logonPwTxtBox.InvokeRequired)
{ .. }
}
I wrote a simple class to generate arrays as I needed some hard-coded random arrays for my own debugging purposes, however despite calling the timely operations in a separate worker thread my UI still hangs! Here's the code...
private static Random randGenerator = new Random();
private void generateButton_Click(object sender, EventArgs e)
{
string dataType = "System.";
if (typeComboBox.Text != "Byte")
dataType += signedCheckBox.Checked ? "" : "U";
else if (typeComboBox.Text == "Byte")
dataType += signedCheckBox.Checked ? "S" : "";
dataType += typeComboBox.Text;
generateButton.Enabled = false;
new Thread(() =>
{
Process(Type.GetType(dataType), (int)sizeNumericUpDown.Value, hexCheckBox.Checked);
}).Start();
}
private void Process(Type type, int size, bool hex)
{
StringBuilder sBuilder = new StringBuilder();
sBuilder.Append(string.Format(#"{0}[] values = new {0}[{1}] {{", type.Name, size));
for (int i = 0; i < size; i++)
{
int random = randGenerator.Next(0, GetIntegralMaxValue(type));
sBuilder.Append((hex ? "0x" + random.ToString("x2") : random.ToString()) + (i < size - 1 ? ", " : " };"));
}
outputTextBox.BeginInvoke((MethodInvoker)delegate
{
outputTextBox.Text = sBuilder.ToString();
});
}
private int GetIntegralMaxValue(Type type)
{
var field = type.GetField("MaxValue").GetValue(null);
return Convert.ToInt32(field);
}
I thought that maybe the issue lied with trying to access objects created on the main thread so instead I passed them to the method. I also tried declaring my randGenerator object within the class but still no luck. Could anybody identify the issue?
The TextBox is not designed to hold a large set of data - it becomes very slow when amount of data increases. I would say that populating of the StringBuilder takes about 5% of time while assigning this data to TextBox (which executes in UI thread) takes remaining 95% of time. You can easily check this. Just run this code in debug mode and click "Pause" button during hanging. It should break on "outputTextBox.Text = sBuilder.ToString();" line.