|
Hi everyone,
we have an GUI application that starts and observes several console processes.
Because it can be lots of processes, we are starting these console applications hidden:
Process process = new Process();
process.StartInfo.FileName = dir + @"\ConsoleApp.exe";
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.Start();
So far so good, no shell is showing up!
But if the user closes the user interface (which started these processes) all the console applications are still running. Since they should finish their job, this is more or less ok. But we would like to show each console again, so the user could stop them if necessary or watch output in each shell himself.
Any idea how to show the console applications again?
The preferred approach would be that each console application can show itself. (So they would pop up again even if the GUI simply crashed)
I have looked into the process information, but the MainWindowHandle property is set to null for the console applications, so I can't use it to show the shell.
That's also true for any other combination of startinfo properties which lead to a hidden console.
In contrast, Spy++ shows a hidden window for my hidden console app! So how to obtain the (still hidden) window's handle?
Or any other idea how to show these hidden consoles again?
Cheers, Roland
|
|
|
|
|
Try windows messages. that gets messages accross applications easily AND you let the application itself handle his own properties.
hope this helps.
V.
|
|
|
|
|
Could you please go into details a little more?
What window message would you send to whome?
ShowWindow is also just sending SW_SHOW in the end, but I would need to know the window handle of the console application before I can send it there...
Cheers, Roland
|
|
|
|
|
Look here[^]
key words were C# send window message in google.
V.
|
|
|
|
|
Oh funny reply, dude! Was the question how to send window messages in general?
As I said before, you'd have to know who is the recipient for that message, and actually THAT is the problem.
A hidden application has no idea about it's main window's hwnd. And a console application cannot set it's window title to make other apps find it by FindWindow with given title.
|
|
|
|
|
Don't be so impolite. And I gather you haven't understood my reply, at all.
I guess you'll have to figure it out for yourself then.
I'm sorry I wasn't able to make it more clearer to you.
V.
|
|
|
|
|
Sorry, but from my point of view your post was already inpolite.
I know how to google and how to send messages, I am no noob.
But if you have no window handle as recipient, you will never send messages anywhere.
And the page you linked uses Process' MainWindowHandle property which is always NULL for hidden windows. (As written in my initial post, maybe you have only scanned the first lines of it.)
No window handle, no chance to send the message.
Seems I have really to enumerate over all windows and find the hidden window that belongs to the process... what a hack...
|
|
|
|
|
There was a post on MSDN about this a while ago, How to obtain a Console Window Handle[^] which uses FindWindow to look for a known window title. It seems ok for Windows XP and I wrote a quick test (with no error checking on the Windows API calls).
public partial class ConsoleControllerForm : Form {
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow);
[DllImport("user32.dll")]
private static extern IntPtr FindWindowW(
[In] [MarshalAs(UnmanagedType.LPWStr)] String lpClassName,
[In] [MarshalAs(UnmanagedType.LPWStr)] String WindowName);
private const String KnownConsoleTitle = "TestApp";
private IntPtr handle;
public ConsoleControllerForm() {
InitializeComponent();
}
private void StartBtn_Click(object sender, EventArgs e) {
StartProcess();
FindCmd();
}
private void FindCmd() {
handle = FindWindowW(null, KnownConsoleTitle);
ShowBtn.Enabled = handle != IntPtr.Zero;
}
private void ShowBtn_Click(object sender, EventArgs e) {
ShowWindow(handle, 1);
}
private static void StartProcess() {
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = @"TestApp.exe";
psi.UseShellExecute = true;
psi.CreateNoWindow = false;
psi.WindowStyle = ProcessWindowStyle.Hidden;
Process p = Process.Start(psi);
Thread.Sleep(1000);
}
}
Note the ProcessStartInfo properties are the only combination for which the subsequent ShowWindow actually shows the window and that TestApp.exe explicitly sets it's title to "TestApp" so I know what to look for with FindWindow.
I doubt this approach will solve your problem completely but hopefully it's given you a start.
Alan.
|
|
|
|
|
Hi Alan,
thanks for your reply!
At the moment I really make use of a combination of EnumWindows and GetWindowThreadProcessId to get my own (hidden) window's handle within the console application. But I am not happy about enumerating over all windows.
FindWindow was also my first thought... the problem was that I had no clue what the title is. The shell usually shows the console application's full path in the title. Having multiple instances running, this can be quite difficult to find a specific one.
But you made me think about the window title again, because you really hardcoded a title for a console application. First I thought I could not change it from within the console application itself in C#, since MainWindowTitle is read-only. But then I found the following API method:
[DllImportAttribute("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool SetConsoleTitle(IntPtr lpConsoleTitle);
In this case I can easily set the window title; either by passing it as parameter along with ProcessStartInfo , or simply generating it within the console itself.
Thanks for thought-provoking impulse.
Cheers,
Roland
|
|
|
|
|
If your GUI app crashes, I see no way for it to even try to do this beforehand.
Are you also developing the console apps? If so, maybe the console app can monitor the existence of the GUI app and hide and reshow itself on its own?
|
|
|
|
|
Yes, we create both, the GUI and the Console Apps. The latter one can be executed manually or started through the UI (invisible).
So we are actually realy monitoring the UI, but had no (good) idea how to make the console show itself when the GUI was gone.
But as a result of Alan's thought-provoking impulse I have an idea how to do this now.
Cheers, Roland
|
|
|
|
|
I have been looking all over for an answer to this question and can't find something that fits exactly what I am trying to do.
I have a DataGridView that is bound to a DataTable, which is part of a strongly typed DataSet from a SQL Server DB. I can manually update the DataGridView fine. However, my program has multiple threads, one of which adds and removes rows of the underlying data in the DataTable to which the DataGridView is bound. This itself works ok sometimes, but at other times I receive the following exception:
Exception in DataGridView: System.IndexOutOfRangeException: Index 9 does not have a value at System.Windows.Forms.CurrencyManager.get_Item(Int32 index) at System.Windows.Forms.DataGridView.DataGridViewDataConnection.GetError(Int32 boundColumnIndex, Int32 columnIndex, Int32 rowIndex)
To replaces this default dialog please handle the DataError event.
I have written test code and have confirmed that the problem seems to arise because the DataTable is being changed on a different thread. When I add/remove rows on the GUI thread, all is fine. But when I add/remove rows from a different thread, I get the Exception.
I have tried to use the Delete method rather than the Remove method in the DataTable class, but that does not seem to make a difference. And for purposes of my program, it is highly undesirable to change the structure of the program so that the GUI thread makes the changes to the DataTable. I suppose an option might be to catch the DataError exception and do nothing with it, but that is really a last resort. Please help here!
|
|
|
|
|
Hi,
1. please don't apply PRE tags to text. PRE tags is for special formatting, it applies to code snippets, and tabular data, not regular text.
2. you shouldn't read and write data structures in general from more than one thread without proper locks. Adding/removing a row in a DT or a DGV may (and probably always will) render the internal state invalid for as long as the update takes, so another thread reading it would get confused, obtain wrong data, and maybe even hang. I see basically three ways to resolve your problem:
a) use real locks; as one of the interested parties is the main thread (which displays the DGV for you), this is a no-no, as you shouldn't keep the main thread waiting at all.
b) tell the other thread to have the updates delegated to the main thread; there are at least two ways to get that done:
b1) with Control.Invoke, see this little article[^];
b2) with BackgroundWorker.ReportProgress, which probably is most appropriate for your situation.
c) use two DataTables: one that gets displayed (by the main thread), and one that gets calculated (by the background thread); when the calculation finishes, have the main thread display the new DT rather than the old one. "ping-pong".
Luc Pattyn [My Articles] Nil Volentibus Arduum
modified on Thursday, September 15, 2011 10:52 PM
|
|
|
|
|
Hi All, I need to retrive value of GridView slelected row cell value.
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
AllowSorting="True" >
<Columns>
<asp:BoundField HeaderText="First" DataField="RecNo"/>
<asp:BoundField HeaderText="Second" DataField="DecFN"/>
<asp:BoundField HeaderText="Third" DataField="DecLN"/>
<asp:BoundField HeaderText="Fourth" DataField="DOC"/>
<asp:BoundField HeaderText="Fifth" DataField="UserID"/>
<asp:TemplateField>
<ItemTemplate>
<asp:Button ID="Button1" runat="server" CausesValidation="false" Text="Edit" OnClick="Button1_Click" />
<asp:Button ID="Button2" runat="server" CausesValidation="false" Text="Print" OnClick="Butoon2_Click"/>
</ItemTemplate>
</asp:TemplateField>
</Columns>
<AlternatingRowStyle BackColor="#DDFFEE" />
</asp:GridView>
If I click on button1 or Button2 I want to retrive value of a specefic cell value
thanks,
|
|
|
|
|
Add a CommandName property to your buttons like this.
<asp:Button ID="Button1" runat="server" CausesValidation="false" Text="Edit" OnClick="Button1_Click" CommandName="Button1Command"/>
And then handle the RowCommand event. See below
protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "Button1Command")
{
int index = Convert.ToInt32(e.CommandArgument);
GridViewRow row = GridView1.Rows[index];
}
}
Signature construction in progress. Sorry for the inconvenience.
|
|
|
|
|
hi,
I have below code. how do I replace with regular expression or much sipler to this.?
many thanks
if(!identier.StartsWith("L#")
identifier.Replace(something,"");
if(!identier.StartsWith("X#")
identifier.Replace(something,"");
if(!identier.StartsWith("G#")
identifier.Replace(something,"");
|
|
|
|
|
Looking at your example, the "pattern" that "jumps out at me" is that in each case you are using the first two characters of (what I assume is the string) 'identifier.'
That suggests, to me, a switch/case statement using the first two characters of the 'identifier' string as the 'match' criterion.
But, if your 'heart is set' on a RegEx solution, don't let me deter you
best, Bill
"Beauty is in the eye of the beholder, and it may be necessary from time to time to give a stupid or misinformed beholder a black eye." Miss Piggy"
|
|
|
|
|
it was my mistake..yes...identifier is a string type.
|
|
|
|
|
You can't - your code is wrong, on a number of levels.
Firstly:
if(!identier.StartsWith("L#")
identifier.Replace(something,""); Is incomplete - the if condition is never terminated (you need a ')' in there.
(Assuming you fix that) Secondly:
If identifier starts with "L#" then it won't start with "X#". So, your replace operation will be called by at least one of the first two if conditions, and then always by the third.
(Assuming you fix that) Thirdly:
Strings in .NET are immutable - they cannot be changed - so string.Replace does nothing at all to identifier, but instead generates a new string, which you then discard.
As a result, your entire code block as shown can be replaced by nothing, as it has no effect whatsoever on subsequent code! You don't need a regex for that!
Think again what you are trying to do, and perhaps explain to us what results you are expecting, becauae that is not going to give them to you.
Real men don't use instructions. They are only the manufacturers opinion on how to put the thing together.
Manfred R. Bihy: "Looks as if OP is learning resistant."
|
|
|
|
|
Certainly your first point and conclusion are correct, but the other points assume a String , which may not be a safe assumption. identifier may be a StringBuilder (for instance*) and the StartsWith method may be an Extension Method -- we just don't know, not enough information was provided.
If in fact your third point is incorrect, and identifier is mutable, then your second point is also not valid.
Having said that, I wouldn't bet against your being absolutely correct on all points.
* It could also be some other unknown class.
|
|
|
|
|
I agree with you completely - it's just Occam suggests my answer, given the code quality of the whole fragment
Real men don't use instructions. They are only the manufacturers opinion on how to put the thing together.
Manfred R. Bihy: "Looks as if OP is learning resistant."
|
|
|
|
|
+5 for bringing in my favorite "razor," William of Ockham, as well as, of course, a good, solid, technical answer.
best, Bill
"Beauty is in the eye of the beholder, and it may be necessary from time to time to give a stupid or misinformed beholder a black eye." Miss Piggy"
|
|
|
|
|
+5 for acute analysis thoroughly applied ! best, Bill
"Beauty is in the eye of the beholder, and it may be necessary from time to time to give a stupid or misinformed beholder a black eye." Miss Piggy"
|
|
|
|
|
my requirement is if a string starts with "L#",or "G#" or "X#" i dont want to replace some part of the string. Otherwise I will replace.
for example: string identifier="L#1234";
In this case I dont want to replace any thing there. Otherewise I would replace some part of the string there.
|
|
|
|
|
Then why worry about using a regular expression? There's no need to do this - sometimes it's just easier to directly manipulate a string - in this case, if the second character isn't hash then you don't need to check the first character.
|
|
|
|
|