C# FindWindowEx - I Can't Find Teamviewer Panel - c#

I have a program running on my PC that controls another machine via TeamViewer. It all works fine except that sending a mouse click requires TeamViewer to be in the foreground. I have code that sends mouse clicks to programs like Notepad where the edit panel is called "Edit." But the TeamViewer panel is called TV_REMOTEDESKTOP_CLASS and FindWindowEx fails to find its handle.
Here is my code:
IntPtr handle = WinGetHandle("axie_machine");
if (handle != IntPtr.Zero)
{
var panel = FindWindowEx(handle, IntPtr.Zero, "TV_REMOTEDESKTOP_CLASS", null);
PerformRightClick(panel, new Point(200, 200));
}
Here is the image of Spy++ showing the details of the panel
FindWindowEx returns 0x000000.
Can anyone see what I am doing wrong with FindWindowEx and point in the right direction?

Assuming by WinGetHandle("axie_machine"), you're getting the handle of the TeamViewer window using (part of) its title, then, you're actually getting the handle of the top-level window which your target window whose class is "TV_REMOTEDESKTOP_CLASS" is not a child of. It is one of its descendants, but not a direct child. There's one parent window in between as you can see here:
So, change your code to get the parent window of your target "panel" and then use that to get to the target. The code should looks something like the following:
IntPtr tvWindowHandle = WinGetHandle("axie_machine");
if (tvWindowHandle != IntPtr.Zero)
{
var panelParent = FindWindowEx(tvWindowHandle, IntPtr.Zero, "ATL:03B8D350", null);
if (panelParent != IntPtr.Zero)
{
var panel = FindWindowEx(panelParent, IntPtr.Zero, "TV_REMOTEDESKTOP_CLASS", null);
PerformRightClick(panel, new Point(200, 200));
}
}
Note: You might want to double-check the class of the parent window. It was "ATL:03B8D350" in my version of TV but it might be different for you if you're using another version.

Related

Can't select text in RichEditComponent control

I want to keep my app's window in front of another programs's window.
My app is created with WPF, I set owner with another window's hwnd like this:
// this: my wpf window
WindowInteropHelper helper = new WindowInteropHelper(this);
//The hwnd is handle of window that other program I want to follow
helper.Owner = new IntPtr(hwnd);
Everything is perfect, but I can't select text with mouse within RichEditComponent of the window (the hwnd window).
Any idea to fix this?
Don't know other program write with which language,maybe c++. Handle of other program's window obtained with windows api "FindWindowEx".
If your other program is a Winforms program, you need to add a reference to
System.Windows.Forms.Integration.dll
and add a call to ElementHost.EnableModelessKeyboardInterop(Window window) like shown below:
WindowInteropHelper helper = new WindowInteropHelper(this);
helper.Owner = new IntPtr(hwnd);
ElementHost.EnableModelessKeyboardInterop(this);
because apparently Winforms and WPF have different ways of handling text input (and therefore also affecting text selection - more specific, copy & paste of selected text - as well).
Other than that, the issue might be the HWND pointer - how do you obtain it?
e.g. this is how you can obtain the main window handle by specifying a process name:
Process process = Process.GetProcessesByName("...")[0];
IntPtr hwnd = process.MainWindowHandle;
I had resolved the question by detect Mouse drag event use global hook. When drag start,cancel set owner,and then,when drag finished,set owner with the follow window again.
Use MouseKeyHook to detect global mouse drag event.
https://www.nuget.org/packages/MouseKeyHook
Thanks #Thomas Flinkow again,for your help!

WPF web browser UI element refresh

In C# WPF, I made a custom UI element that looks like a window so that I can have a mini-desktop environment in my WPF application. This "WindowControl" class has maximize, minimize, close, scaling, translation, etc...
This window UI contains a canvas, which is where other embedded UI elements goes. For example, I can embed a TreeView in the canvas of my WindowControl and move it around the screen just like as if you opened Windows Explorer in your OS.
Everything is working EXCEPT for the web browser. When I put the built-in web browser control into the canvas of my WindowControl class, it will NOT refresh. I DON'T mean refresh the url of the browser. I mean refresh the UI element itself. As I move my WindowControl class (with embedded web browser) around the screen, the web browser is leaving screen artifacts all over the place.
THE ACTUAL QUESTION IS: How do you force the built-in web browser UI element in C# WPF to re-draw itself so that it does not leave artifacts when being resized/translated?
I would include my code... but the WindowControl class alone is nearly 1000 lines, and that would not be pleasant on this forum.
So far I have tried the following (none worked):
webBrowser.Measure();
webBrowser.Arrange();
webBrowser.Dispatcher.Invoke(DispatcherPriority.Render, new Action(() => { }));
webBrowser.Width = XX;
webBrowser.Height = XX;
webBrowser.ActualWidth = XX;
webBrowser.ActualHeight = XX;
// As sugguested by Noseratio
IntPtr hwnd;
((IOleWindow)webBrowser.Document).GetWindow(out hwnd);
UpdateWindow(hwnd);
I'd try forcing the update with UpdateWindow (untested):
Get HWND of WebBrowser.Document via IOleWindow
IntPtr hwnd;
((IOleWindow)_webBrowser.Document).GetWindow(out hwnd);
Call UpdateWindow via p/invoke:
UpdateWindow(hwnd);
For WinForms:
Error can't convert ... 'System.Windows.Forms.HtmlDocument' in 'PInvoke.NativeMethods.IOleWindow'
Solution
public IntPtr GetHandle()
{
HtmlDocument doc = Document;
if (doc == null || doc.DomDocument == null) return IntPtr.Zero;
IntPtr hwnd;
((NativeMethods.IOleWindow)(doc.DomDocument)).GetWindow(out hwnd);
return hwnd;
}

Modal WPF dialog does not invoke at center of the invoking window

I'm trying to invoke a WPF dialog from a child window of a Win32 application and was able to achieve this using the Window Handle (HWND) of the invoking window and passing it to the WPF code where I use the WindowInteropHelper class to set the Owner property to the handle of the invoking window. The code snippet below shows the WPF code where I'm setting the Owner property.
public void ShowModal(IntPtr ownerWindow)
{
WindowInteropHelper helper = new WindowInteropHelper(this);
helper.Owner = ownerWindow;
this.ShowDialog();
}
I'm getting the HWND of the invoking dialog using the Windows function as shown below:
HWND handle = GetTopWindow(GetActiveWindow());
While this works as expected functionally (the WPF dialog invokes as a modal dialog), it gets invoked at the top left corner of the screen. I've even set the WindowStartupLocation="CenterOwner" property in the XAML code. It works perfectly fine when invoked from a WPF window but not when Win32 window is involved. I guess I'm missing something in the WPF-Win32 interop here although it seems to me that the problem lies with the HWND retrieved from GetTopWindow(GetActiveWindow()).
UPDATE: I replaced the above code to get the HWND of the invoking window to the code below and now the WPF dialog always invokes at the center of the screen irrespective of the position of the window that invokes it.
HWND hWnd = GetActiveWindow();
if (hWnd != NULL)
{
hWnd = FindWindowEx(hWnd, NULL, "Window1", NULL);
if (hWnd != NULL)
{
hWnd = FindWindowEx(hWnd, NULL, "Window2", NULL);
}
}
Here Window2 is the Window that invokes the WPF dialog.
In your ShowModal() can you try :
this.Owner = App.MainWindow;

Trying to get a "button" from a child window

I will start by saying that my experience with pinvoke is extremely limited. I know very little of C++, too. But here is my situation...
I have a program in C# that uses pinvoke to get functions like SendMessage and FindWindow and the like from C++. It looks for the name of the window, gets the handles, etc. This works fine right now. I will put the code down a bit lower.
Now I have a situation where I want to find a "button" on one of the child windows. I have the IntPtr of the Actual Child Window, at least I think it is. I am very confused about what is a window and what isn't.
I am trying to use EnumChildWindows and FindWindowByCaption and FindWindowEx etc to go through all of the children and find this button. I can get its "caption" with Spy++, but giving that to the FindWindowByCaption does not yield anything.
This is the code that actually finds the parent window. I am sorry if it is confusing, it is being run against very old software.
This is all in C#, using pInvoke. I try to first get the button I want with this method..
FindWindowByCaption(IntPtr.Zero, "{{Caption as shown by Spy++}}");
This doesn't work, even though I give it the right caption. So I try this... In this example, Handle is the IntPtr of the parent window that contains the button I want to find.
// create a small counter so that we do not try to check
// too many windows and crash the program.
int i = 0;
var previous = new Window();
var current = new Window();
do {
current =
new Window(
InteropServices.FindWindowEx(
Handle,
previous.Handle,
null, null
)
);
if (current == IntPtr.Zero)
break;
// add current to list
// continue
previous = current; // never finds the right button, either.
++i;
} while (i < 500);
But even at this, the control I want is never found. Can anyone help me with this? It is getting very frustrating. I can see the Caption in Spy++, I can see that it has a handle. It does not appear to be anything special.
You need to do the following:
Call FindWindow to find the top-level window. Use either class name, or window title, or both, to identify it.
Call FindWindowEx repeatedly to find child windows. Pass the parent window as hwndParent and NULL as hwndChildAfter. Again use either class name, or window title, or both, to identify the child window.
Eventually you will descend the parent/child window hierarchy until you reach your target window.
So, for an example, consider the following hierarchy, using Spy++ notation:
Window 00001000 "My MainForm window title" "MainFormWindowClass"
|
-- Window 00002000 "Panel container" "PanelWindowClass"
|
-- Window 00003000 "Click me!" "ButtonWindowClass"
You would find this with the following sequence of calls:
HWND main = FindWindow("MainFormWindowClass", NULL); // just use class name
HWND panel = FindWindowEx(main, NULL, "PanelWindowClass", "Panel container");
HWND button = FindWindowEx(panel, NULL, "ButtonWindowClass", "Click me!");
Note that I've written this in C++ to avoid confounding things with p/invoke. And I've also omitted all error checking for the sake of a clean example. You obviously would check for errors.
I suggest that you keep Spy++ at hand and try to write a simple C++ console application that locates your window. Once you know the sequence of calls to FindWindow and FindWindowEx that do the job, translate them to C#.

How to kill a window?

When I click on an ESRI COM toolbar item, it spawns a window - it looks like a Winform. Since I didn't spawn the window directly, I can't just do an Object.Close() on it. What technique can I use to delete a window my application spawned, but that I don't have an object reference of?
I think the easiest way is using p/invoke.
The easiest way:
Use FindWindow() function to get and HWND for that window (in C# its IntPtr, you can use NativeWindow class as a wrapper - http://msdn.microsoft.com/en-us/library/system.windows.forms.nativewindow.aspx#Y114)
Once you have the HWND you can use CloseWindow() to close the window or send a message to the window useing SendMessage(youHWND, WM_CLOSE, IntPtr.Zero, IntPtr.Zero) (WM_CLOSE = 0x0010).
If your window has a parent (you can use spy++ to find that out) you can find your window in a more precise way using FindWindowEx().
Hope it helps!
Good luck!
p.s.
Just to be REALLY sure you're not by accident killing another application's window unexpectedly (if you use FindWindow or FindWindowEx without a parent) you can use GetWindowThreadProcessId() to make sure that the window belongs to your process!
Assuming you don't have the window handle you could interop to Win32 and do the following:
In some method call:
CallBackPtr callback = WindowEnumeration;
EnumWindows(callback, IntPtr.Zero);
Then it will call the following to find the window and close it, just replace <title> with as descriptive a title for the window as you can to prevent closing of windows that were not intended to be closed.
private bool WindowEnumeration(IntPtr hwnd, IntPtr lParam)
{
_windowName.Clear();
if (GetWindowText(hwnd, _windowName, _windowName.Capacity) != 0)
{
if (_windowName.ToString().Contains("<title>"))
{
PostMessage(window, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
}
}
return true;
}
The information for calling Win32 can be found in MSDN or pinvoke.net

Categories

Resources