|
Then rethink the whole mess.
|
|
|
|
|
How can I get the title of this window and ensure it has certain specific text in it, to separate it from other notepad windows like it in C sharp? I have a program I'm trying to send controls to and the controls differ depending on the title and text of the window. I was using a DLL add on that will not function correctly in win7 because of the different way some GUI windows are drawn, so I wanted to make the entire app .net native.
Thanks for reading.
http://img683.imageshack.us/img683/3281/testgui1.jpg
|
|
|
|
|
There is no standard way to read window titles and text. Every platform (by this, I mean, C++/MFC, Winforms, WPF, etc) stores the title differently. Sometimes applications will store titles themselves if they are owner / custom drawing. As for getting the window text, thats equally impossible. Every control stores it differently. What about item based controls like ListView?
If all you care about is notepad.exe SPECIFICALLY, you can call Win32 GetWindowText() through interop on the window as well as the text box control inside to get it consistently across OSes.
|
|
|
|
|
Thanks for the response.
Notepad (as you guessed) was an example, I would like to be able to do this with any program I decide to build or interact with. Specifically this time, the program I am building now will interact with HP OpenView ticketing system. I believe it is written in Java? (an poorly written at that) and is obnoxious to try and interact with.
|
|
|
|
|
Actually upon further thought, window *title* is probably stored consistently across every app so it doesn't break Windows. The window *contents* on the other hand, you'd have to do that custom for each app pretty much. On some apps it may be *IMPOSSIBLE* to access the contents because they don't have to use native controls and as such, you have no access to that information. Also, keep in mind that string pointers are only valid in the address space of the application. If you look at how Spy++ works, it injects a DLL into the app you are spying on so it can access its pointers.
|
|
|
|
|
You can P/Invoke functions in User32.dll for this - untested, but these declarations should work.
I'll leave it to you how to work out how to use these to get the functionality you desire.
using System;
using System.Runtime.InteropServices;
using System.Text;
internal static class NativeMethods
{
public static bool SetWindowText(IntPtr hWnd)
{
return SetWindowText(hWnd, null);
}
[DllImport("User32.dll", SetLastError = true)]
public static extern bool SetWindowText(IntPtr hWnd, string lpString);
public static string GetWindowText(IntPtr hWnd)
{
int count = GetWindowTextLength(hWnd) + 1;
StringBuilder resultBuilder = new StringBuilder(count);
GetWindowText(hWnd, resultBuilder, count);
return resultBuilder.ToString();
}
[DllImport("User32.dll", SetLastError = true)]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("User32.dll", SetLastError = true)]
public static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("User32.dll", SetLastError = true)]
public static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
}
Dave
Binging is like googling, it just feels dirtier.
Please take your VB.NET out of our nice case sensitive forum.
Astonish us. Be exceptional. (Pete O'Hanlon)
BTW, in software, hope and pray is not a viable strategy. (Luc Pattyn)
modified on Tuesday, June 7, 2011 5:40 PM
|
|
|
|
|
Thank you, I will try that class and see if the getWindowText method can return what I need.
|
|
|
|
|
I screwed up with the last function and the delegate - I have eited my previous post
|
|
|
|
|
DaveyM69 wrote: I have eited my previous post
And are you going to eit that post as well?
|
|
|
|
|
Cheers Pete!
|
|
|
|
|
I've run a test with the code below and it works OK (a few tweaks to earlier code and an additional function).
using System;
using System.Runtime.InteropServices;
using System.Text;
internal static class NativeMethods
{
public static bool SetWindowText(IntPtr hWnd)
{
return SetWindowText(hWnd, null);
}
[DllImport("User32.dll", SetLastError = true)]
public static extern bool SetWindowText(IntPtr hWnd, string lpString);
public static string GetWindowText(IntPtr hWnd)
{
int count = GetWindowTextLength(hWnd) + 1;
StringBuilder resultBuilder = new StringBuilder(count);
GetWindowText(hWnd, resultBuilder, count);
return resultBuilder.ToString();
}
[DllImport("User32.dll", SetLastError = true)]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("User32.dll", SetLastError = true)]
public static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("User32.dll", SetLastError = true)]
public static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
[DllImport("User32.dll", SetLastError = true)]
public static extern bool IsWindowVisible(IntPtr hWnd);
}
private List<IntPtr> windowHandles = new List<IntPtr>();
private bool EnumWindowsProcHandler(IntPtr hWnd, IntPtr lParam)
{
windowHandles.Add(hWnd);
return true;
}
NativeMethods.EnumWindowsProc enumWindowsProc =
new NativeMethods.EnumWindowsProc(EnumWindowsProcHandler);
NativeMethods.EnumWindows(enumWindowsProc, IntPtr.Zero);
foreach (IntPtr hWnd in windowHandles)
{
if (NativeMethods.IsWindowVisible(hWnd))
{
string caption = NativeMethods.GetWindowText(hWnd);
if (!string.IsNullOrEmpty(caption))
{
Console.WriteLine(caption);
if (caption.EndsWith("Microsoft Visual Studio"))
{
NativeMethods.SetWindowText(hWnd, "Changed VS Caption");
}
}
}
}
|
|
|
|
|
Either I throw exception or induce it naturally in DoWork it is not caught and control is not passed to worker completion routine instead getting that exception which I catch in Program.cs file
Type: System.Reflection.TargetInvocationException
Source: mscorlib
Message: Exception has been thrown by the target of an invocation.
Target Site: System.Object _InvokeMethodFast(System.IRuntimeMethodInfo, System.Object, System.Object[], System.SignatureStruct ByRef, System.Reflection.MethodAttributes, System.RuntimeType)
Module Name: mscorlib.dll
Module Path: C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.dll
Stack:
at System.RuntimeMethodHandle._InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeType typeOwner)
at System.RuntimeMethodHandle.InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeType typeOwner)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
at System.Delegate.DynamicInvokeImpl(Object[] args)
at System.Windows.Forms.Control.InvokeMarshaledCallbackDo(ThreadMethodEntry tme)
at System.Windows.Forms.Control.InvokeMarshaledCallbackHelper(Object obj)
at System.Threading.ExecutionContext.runTryCode(Object userData)
at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Windows.Forms.Control.InvokeMarshaledCallback(ThreadMethodEntry tme)
at System.Windows.Forms.Control.InvokeMarshaledCallbacks()
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
Чесноков
|
|
|
|
|
That's normal behavior. The exception doesn't get thrown across the thread boundary.
Of course, a background worker can return any object as a result, so when I use them (And I do, extensively), I do it like this:
private void SomethingBackground(object sender, DoWorkEventArgs e)
{
try
{
}
catch (SomethingSomethingException ex)
{
}
catch (Exception ex)
{
e.Result = ex;
}
}
if (e.Result is Exception)
throw (Exception)e.Result;
else
{
}
If you're doing this a lot, you could even make a generic wrapper to centralize the code... Plenty of options.
Nevermind... Not enough caffeine...
|
|
|
|
|
Will you argue with MSDN?
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.dowork.aspx[^]
If the operation raises an exception that your code does not handle, the BackgroundWorker catches the exception and passes it into the RunWorkerCompleted event handler, where it is exposed as the Error property of System.ComponentModel.RunWorkerCompletedEventArgs. If you are running under the Visual Studio debugger, the debugger will break at the point in the DoWork event handler where the unhandled exception was raised. If you have more than one BackgroundWorker, you should not reference any of them directly, as this would couple your DoWork event handler to a specific instance of BackgroundWorker. Instead, you should access your BackgroundWorker by casting the sender parameter in your DoWork event handler
Чесноков
|
|
|
|
|
Hi Ian,
you've lost me here, in two ways:
1.
I don't understand what "in the caller" would mean, and how you would get that synchronized with the BGW having finisked. You might want to add a bit of code and/or explanation to make that clear.
2.
I also don't see a need to do anything special; in the RunWorkerCompleted event, the e.Error property automatically holds the Exception that caused the DoWork handler to finish prematurely.
Cheers.
Luc Pattyn [My Articles] Nil Volentibus Arduum
The quality and detail of your question reflects on the effectiveness of the help you are likely to get. Please use <PRE> tags for code snippets, they improve readability. CP Vanity has been updated to V2.3
|
|
|
|
|
Yeah, this is what I get for trying to answer questions in the morning when I'm having a bad week... Heh... You're right on both counts. I abstracted all of this away months ago to run background workers with an animated progress dialog, so I can do things like:
x = Util.ProgressDialog.Show(owner, MyWorkerMethod, "Doing something") as MyResultObject;
private void MyWorkerMethod(BackgroundWorker wkr, DoWorkEventArgs e)
{
e.Result = ...
}
|
|
|
|
|
As you did not present any code, I assume that you are having a problem with Control.Invoke Method (Delegate) method.
The exception is not thrown if you try to change some control's properties directly from inside a thread. For example:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
ChangeMyText("Privet");
}
private void ChangeMyText(string myText)
{
label1.Text = myText;
}
The result will be a dead backgroundWorker. It will not say anything but die when it reaches
label1.Text = myText;
and will not throw an exception.
Instead, you have to use
label1.Invoke((Action)delegate
{
label1.Text = myText;
});
____________
Ulugbek
|
|
|
|
|
I have a C# application that is running on many network computers, across multiple subnets. These applications send and retrieve data from an sql server 2008 database. Some computers will be used to update production data for a particular production line. Others will be monitoring any changes.
When a data entry computer sends an update to the database, what I would like to do is notify all computers that are monitoring that specific production line to requery the database to get any changes. I'm really not sure how to go about this. I know Notification Services was removed from sql server. I don't know whether to use direct communication between the updating and monitoring clients (I foresee that being very messy as many computers will be sending updates at nearly the same time) or running some kind of notifying service that the clients subscribe to.
Any help would be greatly appreciated.
|
|
|
|
|
You might want to look at this[^] and see what you can do.
|
|
|
|
|
I wouldn't even consider one client notifying another, and I probably also wouldn't have a server notify multiple clients; in my view all information should be in the server, and all initiative should come from clients. So I'd rather have a data scheme that makes it pretty easy to discover when the last relevant change has been made (a last modified field in simple cases; an action in some/all stored procedures for more complex situations, resulting in a simple table entry somewhere), and have all clients poll that. IMO avoiding the need to know who the interested clients are is well worth the cost of periodic polling.
Luc Pattyn [My Articles] Nil Volentibus Arduum
The quality and detail of your question reflects on the effectiveness of the help you are likely to get. Please use <PRE> tags for code snippets, they improve readability. CP Vanity has been updated to V2.3
|
|
|
|
|
Yeah polling is definately an option we are considering. It's the easiest by far. The problem is, the users are going to want an update every minute. That's a lot of database queries every hour. I was hoping to reduce network chatter while keeping the clients up to date.
|
|
|
|
|
NameNotYetTaken wrote: That's a lot of database queries
depends on your definitions of "many network computers" and "a lot".
One transaction per minute should be negligible. IMO a lot more would be going on when users start hitting the keyboard to enter data, or to request new reports/views.
Luc Pattyn [My Articles] Nil Volentibus Arduum
The quality and detail of your question reflects on the effectiveness of the help you are likely to get. Please use <PRE> tags for code snippets, they improve readability. CP Vanity has been updated to V2.3
|
|
|
|
|
I'm going to stick with polling every few minutes, giving the user the option to manually refresh. It's just so much less work. Thanks for your input.
|
|
|
|
|
Definitely don't try to have each updater inform all the listeners. That way lies madness.
Whether to implement a simple listening/broadcast service or to have clients poll for updates depends on your detailed requirements, like whether you want updates to appear immediately, how many clients there will be, whether you can open enough sockets to have them all listening, etc. If it's important that updates are sent to clients immediately, you should have some sort of publish-subscribe service that they can use. If it isn't, polling the database for changes (have a LastUpdated field somewhere that is trivial to access so the polls are not resource intensive) every 30s or so should do the job, and is less intensive on the server side (since it doesn't need to hold open persistent sockets).
|
|
|
|
|
Hi,
I've done a little bit of research on the subject but couldn't find a clear answer.
Here's the situation: I have two C# projects using WPF and I would like the first project to open a window of the second project. Should I merge the two projects into a single one, or keep them separated?
Thank you in advance.
|
|
|
|
|