Enumerate all controls inside window - c#

I'm trying to enumerate all controls inside a window using user32.dll, but I don't know exactly what I need to do.
I'm using EnumWindows and EnumChildWindows, but it doesn't retrieve all controls inside a window.
I want to get the text of some labels in a Delphi application.
I tried using Spy++, but it doesn't list too.

IList<IntPtr> childern = new List<IntPtr>();
WNDENUMPROC enumChildProc = delegate(IntPtr hwnd, IntPtr param)
{
childern.Add(hwnd);
return true;
};
EnumChildWindows(Hwnd, enumChildProc, IntPtr.Zero);
return childern;
which Hwnd is the parent window handle

Delphi labels are non-windowed. That means that you cannot ever hope to obtain window handles for them since they are not windows.
If the Delphi VCL properly supported automation then you'd be able to use UI Automation to inspect the text of these controls. But the VCL only supports automation by dint of the underlying Win32 controls doing so. Since labels aren't windowed controls, again you are out of luck.
The only thing that can realistically hope to read this text is Delphi code inside the process. It does not sound as though that will be viable for you.

Related

Windows Forms Control.CreateControl() equivalent in WPF

normally I use UserControls from WinForms and can then have them created with the CreateControl() method and displayed in another application. But now I wanted to try this with WPF. But there I can't find a way to create the UserControl and then get the corresponding handle.
I tried it with
HwndSource hwndSource = PresentationSource.FromVisual(Control) as HwndSource;
if (hwndSource != null)
{
handle = hwndSource.Handle;
}
but i got no handle.
Then there is this possibility, which theoretically works, but only for Windows
IntPtr handle = new WindowInteropHelper(myWindow).EnsureHandle();
Normal Usage with WinForms Controls on a Sample:
MyCoolControl control = new MyCoolControl();
control.CreateControl();
SendHandleToSomethingElse(control.Handle.ToInt32());
and now i need this for WPF :D
Unlike a Windows Forms control, a WPF control doesn't have its own HWND handle.
In WPF only the top-level window has a handle and the controls are rendered as content inside this HWND.
Please refer to the docs for more information about how WPF uses HWNDs.

forward winapi events to another window

What i have now: my app in C# is half-transparent, and does not catch winapi events - every click, drag etc is catch by underlaying window, which is separate app (like webbrower). I use this to overlay information on top of what browser shows. This is my code for this:
int exstyle = GetWindowLong(this.Handle, GWL_EXSTYLE);
exstyle |= WS_EX_TRANSPARENT;
SetWindowLong(this.Handle, GWL_EXSTYLE, exstyle);
IntPtr hwndf = this.Handle;
IntPtr hwndParent = GetDesktopWindow();
SetParent(hwndf, hwndParent);
But now, i would like to send all events to both my app window (which is half-transparent on top) and web browser (under my app). So for example if i click, the click works in both windows as if they were on top. I imagine that only way to do that is to catch all events and then forward them to lower window, but is there any way to do that?
I use winforms as window lib.
What i do now is not that important, because i want to normally consume events, then forward them to underlaying window. So this is something completly different from what i'm doing now with WS_EX_TRANSPARENT. The point of this is to drag content in both windows simultaneously. If there is any better way of doing it, i would be glad to hear it.
As least what i need is to transfer drag events to both windows, and all other events to underlaying window (not under my control). So, perhaps it will be easier to stay with my window as WS_EX_TRANSPARENT (makes events pass-thru to underlaying window) and simply install global hook to receive drag events? What do you think?
BTW i don't have experience with Winapi, so solution might be obvious.
You can capture Windows events sent your own form by overloading WndProc on the form, or alternatively by calling user32!GetMessage
You can send messages to other Windows forms via the user32!PostMessage or user32!SendMessage apis (read PostMessage function on msdn).
You could try forwarding the event after the underlying form has handled it. Something like
protected override void OnDragOver(DragEventArgs drgevent)
{
base.OnDragOver(drgevent);
MyControl.ForwardDragEvent(drgevent);
}
In MyControl:
public void ForwardDragEvent(DragEventArgs drgevent)
{
base.OnDragOver(drgevent);
//Or call your own method to handle the event
}
I have used this to forward scroll-events, in my case however, only one of the controls handled the event..

How to call native code which draw in WPF Image from C# code?

I have a native library (no sources available) wrapped into C# code.
The following C# declaration exists:
[DllImport(DRIVER_DLL_NAME,
CallingConvention = CallingConvention.Cdecl,
EntryPoint = "RenderBitmap")]
private static extern int RenderBitmap(int hWnd);
I need to call this function from my WPF C# project.
I have a working sample code for Windows forms:
System.Windows.Forms.PictureBox DisplayWindow;
...
RenderBitmap(DisplayWindow.Handle.ToInt32());
And I have not found how to do so with WPF System.Windows.Controls.Image instead of System.Windows.Forms.PictureBox - there is no Handle property or something similar.
Moreover I found in "WPF and Win32 Interoperation" the following statement:
"When you create a WPF Window, WPF creates a top-level HWND, and uses an HwndSource to put the Window and its WPF content inside the HWND. The rest of your WPF content in the application shares that singular HWND.".
It seems that HWND handle does not exist at all for Image.
How to call native code which draw in WPF Image from C# code?
WPF Controls does not have handles like in WinForms. Only main window handle is accessible:
For instance, in main window class (or use Application.Current.MainWindow):
var handle = (new WindowInteropHelper(this)).Handle;
var hwnd = HwndSource.FromHwnd(handle);
So looks like you've to consider another approach instead of native calls.
BTW, why you need such a low level drawing functionality? I just can assume that you simply want to reuse already implemented one for WinForms. Perhaps you can achieve the same using built in WPF features.

Getting the handle of window in C#

I'm trying to do some P/Invoke stuff and need the handle of the current window.
I found Getting the handle of window in C#
But it appears that only works in WPF. Is there a winForms equivalent?
Control.Handle
An IntPtr that contains the window handle (HWND) of the control.
Try this in your form:
IntPtr myHandle = this.Handle;
It will return the handle of the form.

Should Form.ShowDialog(IWin32Window) work with any window handle?

When using System.Windows.Forms.ShowDialog(IWin32Window), should I be able to pass in an IWin32Window representing any window handle and have it be modal with respect to that window?
As part of an Internet Explorer 7 extension I'm trying to open a window modal with respect to an Internet Explorer tab. It's not the currently selected tab, but I can get the hwnd of the tab OK. However, when I pass this to ShowDialog my Form is shown, but it's not modal with respect to anything: I can still do things in Internet Explorer, including in the tab that's supposed to be the owner. My form is shown floating above the Internet Explorer windows and it stays on top, so it's not like it's just opened as a normal form, but it's not correctly modal.
Using Spy++, I can find my form and it's owner handle is correctly set.
Does this mean that something has gone wrong, or I'm doing something wrong? How do I make my form correctly modal?
FYI, I'm using this wrapper class to create an IWin32Window from a hwnd (thanks Ryan!):
/// <summary>
/// Wrapper class so that we can return an IWin32Window given a hwnd
/// </summary>
public class WindowWrapper : System.Windows.Forms.IWin32Window
{
public WindowWrapper(IntPtr handle)
{
_hwnd = handle;
}
public IntPtr Handle
{
get { return _hwnd; }
}
private IntPtr _hwnd;
}
UPDATE: Using Internet Explorer 7 & .NET 2.0
UPDATE: Playing around some more with Spy++ and the handles it exposes, I find that if I use a different hwnd then I can make my window modal to the tab:
I was using the tab's hwnd as suggested by the IWebBrowser2.HWND doc, which in Spy++ appears as class TabWindowClass. It has a child of class Shell DocObject View, which has a child of Internet_Explorer_Server. If I use the hwnd of the Internet Explorer_Server then it works correctly, for example, when I click with the mouse on other tabs, Internet Explorer reacts normally. When I click with the mouse on the tab of interest, it plays the windows d'oh sound and doesn't do anything.
I don't yet know how to programatically get the Internet_Explorer_Server hwnd, but it should be possible.
Also, for what it's worth, while playing with other window handles I was generally able to make my form modal to other applications and dialogs. So I guess the answer to my question is 'many but not all handles'... possibly it depends on the application?
UPDATE: Another side-note: The original reason I wanted to make my form modal to the tab instead of the whole window is that when opening a MessageBox from my form, passing the form as owner, the MessageBox would not always open on top of my form. If a new Internet Explorer tab had just been opened but wasn't active then the MessageBox would be hidden and that tab would start flashing. However, since Internet Explorer was disabled with my form opened modal it wasn't possible to switch to that tab, so Internet Explorer would be frozen. I thought that opening my form modal to the tab would solve this, but I've found another solution is to avoid using MessageBox: if I use a second form and ShowDialog(this) from my first form then the second form correctly opens to the front. So it seems that Form.ShowDialog() works better than MessageBox.Show() in some cases. More discussion in Problems with modal dialogs and messageboxes.
ShowDialog() does two important things. It starts pumping a message loop so it acts modally to the calling code. And it disables any other windows in the application with a EnableWindow(false) API call. The latter is what is not happening in your case. Not entirely surprising, considering that the window that needs to be disabled is not a WF window.
You may need to call EnableWindow() yourself. Be sure to re-enable it in before the dialog closes or Windows will go hunting for another app's window to give the focus to.
Your code is correct. The problem you are likely running into though is that IE has a threading model related to its tabs. I don't know the exact details but the short version is that each tab can and likely is running on a different thread than other tabs.
The Modal'ness of a dialog is specific to the thread where the dialog is running. UI on other threads will be unaffected by a model dialog on another thread. It's entirely possible you are able to access tabs which are running on a different thread for this reason.
Here's a more concise version of Ryan/Rory's WindowWrapper code:
internal class WindowWrapper : IWin32Window
{
public IntPtr Handle { get; private set; }
public WindowWrapper(IntPtr hwnd) { Handle = hwnd; }
}
I have never tried this from an IE extension, but I have a hunch that IE may not "respect" a Win32-style modal window the same way it does a modal window raised from Javascript using window.open().
Have you tested this code against something other than IE, just to confirm it works the way it should for other applications?
here is a build in solution in .NET:
public static NativeWindow FromHandle(IntPtr handle)

Categories