Process that started in an MDI Container stays always on top - c#

I am working on a Winforms product. This product has an MDI main window, data presentation forms and a software that is developed for this project which is started in the Main Window if the related button is clicked. The software is called as a process when the button is clicked and it's parent is set to the main window. Let's say the software is the TeraTerm for the demonstration.
private void barButtonItem2_ItemClick(object sender, ItemClickEventArgs e)
{
Process p2 = new Process();
ProcessStartInfo ps2 = new ProcessStartInfo(#"C:\Program Files (x86)\teraterm\ttermpro.exe", "");
p2 = Process.Start(ps2);
p2.EnableRaisingEvents = true;
var processResult = p2.WaitForInputIdle(10000); // Allow the process to open it's window
appWin1 = p2.MainWindowHandle;
// Put it into this form
Utilities.HideMinimizeButton(p2.MainWindowHandle);
Utilities.SetWindowPos(p2.MainWindowHandle, Utilities.HWND_BOTTOM, 0, 0, 0, 0, Utilities.SETPOS_FLAGS);
Utilities.SetParent(p2.MainWindowHandle, this.Handle);
}
Utilities class is basically a dll import class for the window handling of the processes. Its code is:
public static class Utilities
{
public static int GWL_STYLE = -16;
public static int WS_BORDER = 0x00800000; //window with border
public static int WS_DLGFRAME = 0x00400000; //window with double border but no title
public static int WS_CAPTION = WS_BORDER | WS_DLGFRAME; //window with a title bar
public static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
public static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2);
public static readonly IntPtr HWND_TOP = new IntPtr(0);
public static readonly IntPtr HWND_BOTTOM = new IntPtr(1);
public const UInt32 SWP_NOSIZE = 0x0001;
public const UInt32 SWP_NOOWNERZORDER = 0x0200;
public const UInt32 SWP_NOMOVE = 0x0002;
public const UInt32 SWP_SHOWWINDOW = 0x0040;
public const UInt32 SWP_NOZORDER = 0x0040;
public const UInt32 SETPOS_FLAGS = SWP_NOSIZE | SWP_SHOWWINDOW;
public const int SW_MAXIMIZE = 3;
public const int SW_MINIMIZE = 6;
public const int SW_SHOWDEFAULT = 10;
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
[DllImport("user32.dll")]
internal extern static int SetWindowLong(IntPtr hwnd, int index, int value);
[DllImport("user32.dll")]
internal extern static int GetWindowLong(IntPtr hwnd, int index);
[DllImport("user32")]
public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
internal static void HideMinimizeAndMaximizeButtons(IntPtr hwnd)
{
const int GWL_STYLE = -16;
const long WS_MINIMIZEBOX = 0x00020000L;
const long WS_MAXIMIZEBOX = 0x00010000L;
long value = GetWindowLong(hwnd, GWL_STYLE);
SetWindowLong(hwnd, GWL_STYLE, (int)(value & ~WS_MINIMIZEBOX & ~WS_MAXIMIZEBOX));
}
internal static void HideMinimizeButton(IntPtr hwnd)
{
const int GWL_STYLE = -16;
const long WS_MINIMIZEBOX = 0x00020000L;
const long WS_MAXIMIZEBOX = 0x00010000L;
long value = GetWindowLong(hwnd, GWL_STYLE);
SetWindowLong(hwnd, GWL_STYLE, (int)(value & ~WS_MINIMIZEBOX));
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
}
This code is works to put my process as an MDI child. The problem is; the process window is always top of the every child form. I tried calling SetWindowPos with HWND_BOTTOM but no luck.
You may see from here and here the process is at the top even it is not activated.

I achieved success using most of the code you used. Here is my image:
There are a number of minor but obviously important issues in your posted code, making it impossible to know what you're actually doing that is causing the error.
You call the HideMinimizeButton method but do not provide its definition. In my working code, I called the HideMinimizeAndMaximizeButtons method you expose in your Utilities class.
You omitted your static extern for GetWindowsLong and SetWindowLong, so we can't see what you did there...
Your SetWindowLong call in your utilities class tries to cast the final argument to int when the SetWindowsLong WinAPI function I see says that it should be uint.
My version of your Utilities class looks like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace WindowsFormsApp8
{
class Utilities
{
public static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
public static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2);
public static readonly IntPtr HWND_TOP = new IntPtr(0);
public static readonly IntPtr HWND_BOTTOM = new IntPtr(1);
public const UInt32 SWP_NOSIZE = 0x0001;
public const UInt32 SWP_NOOWNERZORDER = 0x0200;
public const UInt32 SWP_NOMOVE = 0x0002;
public const UInt32 SWP_SHOWWINDOW = 0x0040;
public const UInt32 SWP_NOZORDER = 0x0040;
public const UInt32 SETPOS_FLAGS = SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE;
[DllImport("user32")]
public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll")]
static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, uint dwNewLong);
internal static void HideMinimizeAndMaximizeButtons(IntPtr hwnd)
{
const int GWL_STYLE = -16;
const long WS_MINIMIZEBOX = 0x00020000L;
const long WS_MAXIMIZEBOX = 0x00010000L;
long value = GetWindowLong(hwnd, GWL_STYLE);
SetWindowLong(hwnd, GWL_STYLE, (uint)(value & ~WS_MINIMIZEBOX & ~WS_MAXIMIZEBOX));
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
}
}
Clearly, this works for me. If it works for you too, kindly accept as the answer.

Related

Process frozen when I try to start it hooked to a panel

I need to launch an external .exe application within my windows forms app on a panel. If I start the process, without placing it on the panel, it's fine but if I place it on the panel the program freezes and does nothing.
I tried to google the problem but I did not find anything,can you help me?.
[DllImport("user32.dll")]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll")]
static extern bool MoveWindow(IntPtr Handle, int x, int y, int w, int h, bool repaint);
[DllImport("USER32.DLL")]
public static extern int GetWindowLong(IntPtr hWnd, int nIndex);
private const int GWL_STYLE = (-16);
public static int WS_BORDER = 0x00800000;
public static int WS_CAPTION = WS_BORDER;
[DllImport("user32.dll")]
private static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
private const int SW_SHOWMAXIMIZED = 3;
string projectDirectory = "C:\\Users\\anten\\OneDrive\\Desktop\\together\\VisualSharp7\\bin\\Debug";
Visual_Sharp7.StartInfo.WorkingDirectory = projectDirectory;
Visual_Sharp7.StartInfo.FileName = "VisualSharp7.exe";
if (Visual_Sharp7.Start())
{
IntPtr ptr = IntPtr.Zero;
while ((ptr = Visual_Sharp7.MainWindowHandle) == IntPtr.Zero) ;
int WS_VISIBLE = GetWindowLong(Visual_Sharp7.MainWindowHandle, GWL_STYLE);
SetWindowLong(Visual_Sharp7.MainWindowHandle, GWL_STYLE, (WS_VISIBLE & ~WS_CAPTION));
SetParent(Visual_Sharp7.MainWindowHandle, panelMain.Handle);
ShowWindow(Visual_Sharp7, SW_SHOWMAXIMIZED);
}

Window on top of everything like mouse cursor

I am programming a mouse cursor to be used in the operating system that has motion blur on Windows 10. I decided to use Unity3D for this because of Unity3D has very powerful in terms of effects and hardware rendering. I coded an overlay window to be rendered as top most. However, context menus on any application are getting rendered on top of the window and the objects on the form are getting behind the context menu. Is there a way to achieve this? I don't need to use Unity3D for this so any suggestions are welcome.
Here is the code I wrote for the window.
using System;
using System.Runtime.InteropServices;
using UnityEngine;
[RequireComponent(typeof(Camera))]
public class TransparentWindow : MonoBehaviour
{
private struct MARGINS
{
public int cxLeftWidth;
public int cxRightWidth;
public int cyTopHeight;
public int cyBottomHeight;
}
// Define function signatures to import from Windows APIs
[DllImport("user32.dll")]
private static extern IntPtr GetActiveWindow();
[DllImport("user32.dll")]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, uint dwNewLong);
[DllImport("Dwmapi.dll")]
private static extern uint DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS margins);
[DllImport("user32.dll", EntryPoint = "SetLayeredWindowAttributes")]
static extern int SetLayeredWindowAttributes(IntPtr hwnd, int crKey, byte bAlpha, int dwFlags);
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
private static extern int SetWindowPos(IntPtr hwnd, int hwndInsertAfter, int x, int y, int cx, int cy, uint uFlags);
[DllImport("user32.dll")]
static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
// Definitions of window styles
const int GWL_STYLE = -16;
const uint WS_POPUP = 0x80000000;
const uint WS_VISIBLE = 0x10000000;
const uint WS_EX_LAYERED = 0x00080000;
const uint WS_EX_TRANSPARENT = 0x00000020;
const uint WS_EX_TOPMOST = 0x00000008;
const int HWND_TOPMOST = -1;
const UInt32 SWP_NOSIZE = 0x0001;
const UInt32 SWP_NOMOVE = 0x0002;
const UInt32 SWP_NOZORDER = 0x0004;
const UInt32 SWP_NOREDRAW = 0x0008;
const UInt32 SWP_NOACTIVATE = 0x0010;
const UInt32 SWP_FRAMECHANGED = 0x0020;
const UInt32 SWP_SHOWWINDOW = 0x0040;
const UInt32 SWP_HIDEWINDOW = 0x0080;
const UInt32 SWP_NOCOPYBITS = 0x0100;
const UInt32 SWP_NOOWNERZORDER = 0x0200;
const UInt32 SWP_NOSENDCHANGING = 0x0400;
const UInt32 SWP_DRAWFRAME = SWP_FRAMECHANGED;
const UInt32 SWP_NOREPOSITION = SWP_NOOWNERZORDER;
const UInt32 SWP_DEFERERASE = 0x2000;
const UInt32 SWP_ASYNCWINDOWPOS = 0x4000;
// This static method is required because legacy OSes do not support
// SetWindowLongPtr
public static IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, uint dwNewLong)
{
if (IntPtr.Size == 8)
return SetWindowLongPtr64(hWnd, nIndex, dwNewLong);
else
return new IntPtr(SetWindowLong32(hWnd, nIndex, dwNewLong));
}
[DllImport("user32.dll", EntryPoint = "SetWindowLong")]
private static extern int SetWindowLong32(IntPtr hWnd, int nIndex, uint dwNewLong);
[DllImport("user32.dll", EntryPoint = "SetWindowLongPtr")]
private static extern IntPtr SetWindowLongPtr64(IntPtr hWnd, int nIndex, uint dwNewLong);
void Start()
{
#if !UNITY_EDITOR // You really don't want to enable this in the editor..
int fWidth = Screen.width;
int fHeight = Screen.height;
var margins = new MARGINS() { cxLeftWidth = -1 };
var hwnd = GetActiveWindow();
SetWindowLong(hwnd, GWL_STYLE, WS_POPUP | WS_VISIBLE);
SetWindowLongPtr(hwnd, -20, WS_EX_TOPMOST | WS_EX_LAYERED | WS_EX_TRANSPARENT); // GWL_EXSTYLE -20
SetLayeredWindowAttributes(hwnd, 0, 255, 2);
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
DwmExtendFrameIntoClientArea(hwnd, ref margins);
#endif
}
void OnRenderImage(RenderTexture from, RenderTexture to)
{
Graphics.Blit(from, to, m_Material);
}
}
Here is the screenshot animation shows my issue. Please see the second mouse cursor in this screenshot which follows operating system's mouse cursor:

Set transparency to a control in windows form

I am new in programming. I can’t find a way to set transparency to a control. Please help. Something like, Form.transparency or some thing else.
The most simple way to make a form transparent is just to set the Form.Opacity property to a value.
Or, you can try, API calls for doing that,
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", SetLastError = true)]
static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
static extern bool SetLayeredWindowAttributes(IntPtr hwnd, uint crKey, byte bAlpha, uint dwFlags);
public const int GWL_EXSTYLE = -20;
public const int WS_EX_LAYERED = 0x80000;
public const int LWA_ALPHA = 0x2;
public const int LWA_COLORKEY = 0x1;
For Calling,
SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) ^ WS_EX_LAYERED);
SetLayeredWindowAttributes(Handle, 0, 128, LWA_ALPHA);

How to hide/show a Process using c#?

While executing my program, I want to hide/minimize Microsoft Speech Recognition Application:
alt text http://img143.imageshack.us/img143/9380/minimize.png
and at the end I want to show/maximize using c#!
This process is not started by me so I can't give control the process startInfo.
I've tried to use user32.dll methods such as:
ShowWindow
AnimatedWindows
AnimatedWindows
SetForegroundWindow
SetWindowPos
With all of them I have the same problem.
I can hide the windows (althought I have to call one of the methods two times with SW_HIDE option), but when I call the method with a SW_SHOW flag, it simply doesn't shows..
How can I maximize/show after hiding the process?
Thanks in advance!
Here is some pieces of the code, now implemented to use SetWindowPlacement:
{
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetWindowPlacement(IntPtr hWnd,
[In] ref WINDOWPLACEMENT lpwndpl);
[DllImport("user32.dll")]
public static extern Boolean ShowWindowAsync(IntPtr hWnd, Int32 nCmdShow);
[DllImport("user32.dll")]
public static extern Boolean SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern Boolean ShowWindow(IntPtr hWnd, Int32 nCmdShow);
[DllImport("user32.dll")]
public static extern Boolean AnimateWindow(IntPtr hWnd, uint dwTime, uint dwFlags);
[DllImport("dwmapi.dll")]
public static extern int DwmSetWindowAttribute(IntPtr hwnd, uint dwAttribute, IntPtr pvAttribute, IntPtr lol);
//Definitions For Different Window Placement Constants
const UInt32 SW_HIDE = 0;
const UInt32 SW_SHOWNORMAL = 1;
const UInt32 SW_NORMAL = 1;
const UInt32 SW_SHOWMINIMIZED = 2;
const UInt32 SW_SHOWMAXIMIZED = 3;
const UInt32 SW_MAXIMIZE = 3;
const UInt32 SW_SHOWNOACTIVATE = 4;
const UInt32 SW_SHOW = 5;
const UInt32 SW_MINIMIZE = 6;
const UInt32 SW_SHOWMINNOACTIVE = 7;
const UInt32 SW_SHOWNA = 8;
const UInt32 SW_RESTORE = 9;
public sealed class AnimateWindowFlags
{
public const int AW_HOR_POSITIVE = 0x00000001;
public const int AW_HOR_NEGATIVE = 0x00000002;
public const int AW_VER_POSITIVE = 0x00000004;
public const int AW_VER_NEGATIVE = 0x00000008;
public const int AW_CENTER = 0x00000010;
public const int AW_HIDE = 0x00010000;
public const int AW_ACTIVATE = 0x00020000;
public const int AW_SLIDE = 0x00040000;
public const int AW_BLEND = 0x00080000;
}
public struct WINDOWPLACEMENT
{
public int length;
public int flags;
public int showCmd;
public System.Drawing.Point ptMinPosition;
public System.Drawing.Point ptMaxPosition;
public System.Drawing.Rectangle rcNormalPosition;
}
//this works
param = new WINDOWPLACEMENT();
param.length = Marshal.SizeOf(typeof(WINDOWPLACEMENT));
param.showCmd = (int)SW_HIDE;
lol = SetWindowPlacement(theprocess.MainWindowHandle, ref param);
// this doesn't work
WINDOWPLACEMENT param = new WINDOWPLACEMENT();
param.length = Marshal.SizeOf(typeof(WINDOWPLACEMENT));
param.showCmd = SW_SHOW;
lol = GetWindowPlacement(theprocess.MainWindowHandle, ref param);
NOTE:
Does the SAPI API has a command to minimize this minimize and maximize this window?
As Tomas said, you should try to use the SW_HIDE and SW_SHOW messages.
You do that by knowing the Speech Recognition winwow name and then using something like this:
HWND hc = FindWindow("processname","Windowtitle");
ShowWindow(hc,SW_HIDE);
The whole SetForegroundWindow/ShowWindow set of functions only work when stars align! :) It's usually a matter of calling functions in the right order. Sorry can't help specifically but this might provide some ideas
http://markribau.org/blog/2005/12/29/why-dont-focus-and-setforegroundwindow-work/
Is the procoess still runing if you send it the SW_HIDE message? The application is certainly not using the standard style of GUI, so it may react to the message by closing itself.
If that's the case, you could try other tricks, such as moving the window to some invisible location (e.g. -1000, -1000), which should be also possible using the SetWindowPlacement method that you already imported.

Using Window Handle to disable Mouse clicks and Keyboard Inputs using P/Invoke

I need to disable the Mouse Clicks, Mouse movement and Keyboard Inputs for a specific windows for a Kiosk application. Is it feasible using .NET ?
I have removed the menu bar and title bar of a specific window, will that be a starting point to achieve the above requirement ?
The code for removing the menu bar and title bar using window handle :
#region Constants
//Finds a window by class name
[DllImport("USER32.DLL")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
//Sets a window to be a child window of another window
[DllImport("USER32.DLL")]
public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
//Sets window attributes
[DllImport("USER32.DLL")]
public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
//Gets window attributes
[DllImport("USER32.DLL")]
public static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);
[DllImport("user32.dll")]
static extern IntPtr GetMenu(IntPtr hWnd);
[DllImport("user32.dll")]
static extern int GetMenuItemCount(IntPtr hMenu);
[DllImport("user32.dll")]
static extern bool DrawMenuBar(IntPtr hWnd);
[DllImport("user32.dll")]
static extern bool RemoveMenu(IntPtr hMenu, uint uPosition, uint uFlags);
//assorted constants needed
public static uint MF_BYPOSITION = 0x400;
public static uint MF_REMOVE = 0x1000;
public static int GWL_STYLE = -16;
public static int WS_CHILD = 0x40000000; //child window
public static int WS_BORDER = 0x00800000; //window with border
public static int WS_DLGFRAME = 0x00400000; //window with double border but no title
public static int WS_CAPTION = WS_BORDER | WS_DLGFRAME; //window with a title bar
public static int WS_SYSMENU = 0x00080000; //window menu
#endregion
public static void WindowsReStyle()
{
Process[] Procs = Process.GetProcesses();
foreach (Process proc in Procs)
{
if (proc.ProcessName.StartsWith("notepad"))
{
IntPtr pFoundWindow = proc.MainWindowHandle;
int style = GetWindowLong(pFoundWindow, GWL_STYLE);
//get menu
IntPtr HMENU = GetMenu(proc.MainWindowHandle);
//get item count
int count = GetMenuItemCount(HMENU);
//loop & remove
for (int i = 0; i < count; i++)
RemoveMenu(HMENU, 0, (MF_BYPOSITION | MF_REMOVE));
//force a redraw
DrawMenuBar(proc.MainWindowHandle);
SetWindowLong(pFoundWindow, GWL_STYLE, (style & ~WS_SYSMENU));
SetWindowLong(pFoundWindow, GWL_STYLE, (style & ~WS_CAPTION));
}
}
}
Use the EnableWindow API call to do this. I haven't used this in many years but I don't believe there are any cross process issues with this.

Categories