I want to attach a form to another window (of another process). I try to do this by using
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
setParentWindow(myWindowHwnd, newParentHwnd);
In doing so my form becomes attached, but is also invisible. Question "Attach window .." solves this issue for a WPF Window, basically by using
HwndSourceParameters parameters = new HwndSourceParameters();
...
HwndSource src = new HwndSource(parameters);
I have tried to transfer this to my form, but I am unable to do so (e.g. how to handle src.RootVisual = (Visual)window.Content; ? -> Complete source).
Another comment says, I need to modify the windows style:
For compatibility reasons, SetParent does not modify the WS_CHILD or WS_POPUP window styles of the window whose parent is being changed. Therefore, if hWndNewParent is NULL, you should also clear the WS_CHILD bit and set the WS_POPUP style after calling SetParent. Conversely, if hWndNewParent is not NULL and the window was previously a child of the desktop, you should clear the WS_POPUP style and set the WS_CHILD style before calling SetParent.
Here I miss the corresponding API for doing so, can I do it directly from C# or have I to use another DllImport again?
Good or evil - SetParent() win32 API between different processes advises against attaching windows in different processes at all, but at least I want to try.
Question:
What would I need to do to get the form window visible? If the approach with WS_Child is the correct one, how would I set it? Or is the WPF approach the way to go, but how would I apply it to an windows form?
-- Findings (later added) --
Modify the windows style of another application using winAPI shows how to modify the style from C# / PInvoke
Find all windows styles here, C# syntax at the bottom.
-- Findings due to discussion with Alan --
I did run my program on Win XP to crosscheck (see Alan's answer below and the comments). At least I do now see something. Since I have added the coordinates as of Alan's examples, my window now shines through in notepad when moving over the other window near the left upper corner. You can still see the text typed in notepad as overlay. Under Win 7 (32) I do see nothing at all.
Now I need to find out whether this can be written in a stable way, appearing on Win 7 as well.
Nevertheless, I still cannot click any buttons on my form, needs to be solved too.
Here is a working example. The hosting app is a simple WinForms application with a blank form (not included here), while the "guest app" has a main form (code behind included below) with some controls, including a test button to display a message after changing the guest form's parent.
The usual caveats linked to in the OP's question apply to this, too.
public partial class GuestForm: Form
{
[DllImport("user32.dll")]
public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll")]
public static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
public static int GWL_STYLE = -16;
public static int WS_CHILD = 0x40000000;
public GuestForm()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show("done");
}
private void button2_Click(object sender, EventArgs e)
{
Process hostProcess = Process.GetProcessesByName("HostFormApp").FirstOrDefault();
if (hostProcess != null)
{
Hide();
FormBorderStyle = FormBorderStyle.None;
SetBounds(0, 0, 0, 0, BoundsSpecified.Location);
IntPtr hostHandle = hostProcess.MainWindowHandle;
IntPtr guestHandle = this.Handle;
SetWindowLong(guestHandle, GWL_STYLE, GetWindowLong(guestHandle, GWL_STYLE) | WS_CHILD);
SetParent(guestHandle, hostHandle);
Show();
}
}
}
#Horst Walter Hey man, I'm not sure if you've fixed the issue, but I just found a solution to this..
For me the issue was the transparency of the main form you want inside the other form.
Just disable transparency and it should work.
Related
I can't disable my application's close button using Win32 in C#. All other application close buttons are disabled via this code:
const int MF_BYCOMMAND = 0;
const int MF_DISABLED = 2;
const int SC_CLOSE = 0xF060;
[DllImport("user32")]
static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
var sm = GetSystemMenu(hwnd, false);
EnableMenuItem(sm, SC_CLOSE, MF_BYCOMMAND | MF_DISABLED);
But my application uses a ribbon control, and its close button can't be disabled via this code. I tried other ribbon control applications, but still the same issue occurs. Check this UISpy Image Guide, how can I disable this close button?
I already tried more than 10 other applications with this code, and it works perfectly fine. Only ribbon control applications are not working (tested in 3 Ribbon Applications).
So far I make a window - active, to send text using SendKeys, but I want to do it in background using SendMessage
IntPtr main = FindWindow(null, "Label Code (Scan)");
if (!main.Equals(IntPtr.Zero))
{
if (SetForegroundWindow(main))
{
SendKeys.SendWait(code);
SendKeys.SendWait("{ENTER}");
}
}
I have tried something like:
IntPtr main = FindWindow(null, "Label Code (Scan)");
SendMessage(main, 0x000C, 0, "Hello");
But it renames window's title to "Hello". Looks like, I need to find child window, but can't find out about lpszClass.
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
The controls in the window are not real Windows Controls. They are drawn and managed by the Window itselt. However, the window may support the Windows Automation framework to allow interacting with the controls.
Use the tool Inspect to check whether the window supports Windows Automation API.
If it does, use the classes in System.Windows.Automation with the information you see in the Inspect tool to set the text.
I need to restore ("un-minimize") a WPF window that has already been created but the window that's currently on top (not necessarily WPF) can't lose focus or activation. I have tried using all WIN32 functions I can find, to no avail. Getting really frustrated by now, would really appreciate any pointers and tips.
Obviously just changing to WindowState.Normal in WPF doesn't cut it as this makes the window receive focus and activation as-well. I have also tried all sorts of combinations with setting Hidden and IsEnabled while restoring.
I have tried WIN32 SetWindowPos with HWND_TOP, HWND_TOPMOST etc. but this function is not intended to restore windows and will only change position of already "displayed" windows.
Tried WIN32 ShowWindow and SetWindowPlacement but no luck there either. Tried a desperate attempt at adding a HwndHook to try and listen for WM_SETFOCUS and restoring focus to the original window but i only get zero for the last focused window handle..
Edit - Solution with window extension after tip from Joel Lucsy:
public static class RestoreWindowNoActivateExtension
{
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool ShowWindow(IntPtr hWnd, UInt32 nCmdShow);
private const int SW_SHOWNOACTIVATE = 4;
public static void RestoreNoActivate(this Window win)
{
WindowInteropHelper winHelper = new WindowInteropHelper(win);
ShowWindow(winHelper.Handle, SW_SHOWNOACTIVATE);
}
}
Call ShowWindow passing the SW_SHOWNOACTIVATE flag.
I am having trouble trying to bring my application window to the front (i.e on top of all other windows). I want the user to be able to double click the notifyIcon in the system tray, and If the application already has a window open for it to be bought to the front. I have tried using the following two P/inovkes but neither seem to work consistently. Does anybody have any idea how to bring a window to the front/top?
[DllImport("user32.dll")]
private static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll")]
tatic extern bool SetForegroundWindow(IntPtr hWnd);
ShowWindowAsync(ADProcess.MainWindowHandle, SW_RESTORE);
SetForegroundWindow(ADProcess.MainWindowHandle);
Given the little info you have provided the best guess I can make is that you have a timing issue with the call to ShowWindowAsync which runs asynchronously followed by the call to SetForgroundWindow.
Have you tried using ShowWindow to see if that works correctly?
I have a small windows.form that I use to present information when the mouse is over a regions on a windows.Form, however it takes the focus from the parent window when it is set to visible. Is there w way of preventing this - it causes the main form to flicker as it toggles between in focus and out.
c#, .net 2.0, system.windows.forms
Paste this into your popup form class, it prevents it from being activated when shown:
protected override bool ShowWithoutActivation {
get { return true; }
}
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
ShowWindow(popupForm.Handle, 8);
See ShowWindow Function for additional commands.