Hiding window from taskbar in C# with WinAPI - c#

Believe me, I have Googled it and expected it to be a fairly easy find - turns out it isn't.
I have my window handle, but no form. How do I do it?
Thanks!

Declare these:
[DllImport("user32.dll", SetLastError = true)]
static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
private const int GWL_EX_STYLE = -20;
private const int WS_EX_APPWINDOW = 0x00040000, WS_EX_TOOLWINDOW = 0x00000080;
And then use this before the form is shown:
SetWindowLong(handle, GWL_EX_STYLE, (GetWindowLong(handle, GWL_EX_STYLE) | WS_EX_TOOLWINDOW) & ~WS_EX_APPWINDOW);
(change handle to whatever your window handle is stored in)

Set Form's ShowInTaskbar property to false.

Related

How to start a process from a Windows Forms (C#) without creating a taskbar icon

I have a Windows Forms application with a button that's supposed to open an exe file.
The default Windows behavior is that the exe file, once opened, will have its own icon appear in the taskbar, however the requirement is for it not to have the icon, and for the window to appear "nested" inside the icon of the Windows Form application from which it originates, so to hide the location of the exe file from users.
I have looked around for a solution, and my understanding is that in order to achieve this, I would have to use the user32.dll library.
I have found some code online that attempts something similar (no window, no taskbar icon), and I am trying to tweak it so that it fits my needs, but so far I am stuck.
This is what I have:
private int GWL_STYLE = -16;
private int GWL_EXSTYLE = -20;
private int WS_EX_APPWINDOW = 262144;
private UInt32 WS_POPUP = 0x80000000;
private UInt32 WS_CHILD = 0x40000000;
[DllImport("user32.dll")]
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
public Process HideProcess(string executablesPath, System.Windows.Forms.Form parentForm) {
Process valueToReturn = null;
if (executablesPath != null && executablesPath.Equals(String.Empty) == false && File.Exists(executablesPath) == true) {
ProcessStartInfo startInfo = new ProcessStartInfo(executablesPath);
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
valueToReturn = Process.Start(startInfo);
int style = GetWindowLong(valueToReturn.MainWindowHandle, GWL_EXSTYLE) & ~WS_EX_APPWINDOW;
SetWindowLong(valueToReturn.MainWindowHandle, GWL_EXSTYLE, style);
SetParent(valueToReturn.MainWindowHandle, parentForm.Handle);
}
return valueToReturn;
}
I have tried several different variations of this method, but I always get close but not exactly where I'd like to be.
The documentation I have found seems a little bit confusing, so I am a little bit stuck and would appreciate some help.

C# Make external application's form type Sizable

Well, I have the code to make it borderless, but I'm having troubles changing it back to sizable
This is the code to make to make it borderless:
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
const int GWL_STYLE = (-16);
const UInt32 WS_VISIBLE = 0x10000000;
SetWindowLong(windowHandle, GWL_STYLE, (IntPtr)(WS_VISIBLE));

Remove titlebar from window. Window process started by different user

I am using this code (on windows 2003) to remove and resize window:
Process process = Process.GetProcessById(12121);
IntPtr mwh = process.MainWindowHandle;
SetWindowLong(mwh, GWL_STYLE, WS_VISIBLE);
ShowWindowAsync(mwh, 3);
SetWindowPos(mwh, new IntPtr(0), 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
And declarations:
[DllImport("user32.dll")]
private static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
[DllImport("USER32.DLL")]
public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags);
static readonly int GWL_STYLE = -16;
static readonly int SWP_NOMOVE = 0x2;
static readonly int SWP_NOSIZE = 0x1;
static readonly int SWP_FRAMECHANGED = 0x20;
static readonly int WS_VISIBLE = 0x10000000;
Everything works correct, when I am resizing window associated with process started by me. But when I want to do this with other users windows, then it does nothing.
How to make it works for other users windows?
The behavior is by design in Windows Vista and later, due to the User Interface Privilege Isolation (UIPI). You could solve it if you have access to the source code of the controlled applications.
Read this answer for more: https://stackoverflow.com/a/15445510.
process.MainWindowHandle is a .NET concept, there is no such thing as a main window in native desktop apps and therefore might not always work correctly on other processes. You should check if mwh is IntPtr.Zero, if it is then you need to use EnumWindows + GetWindowThreadProcessId + IsWindowVisible to find the applications window.
Calling SetWindowLong(mwh, GWL_STYLE, WS_VISIBLE); on a window you did not create is not OK. You need to call GetWindowLong first the get the existing style, remove all the styles you don't want and add WS_POPUP. You might want to remove some of the extended styles as well.

Not take focus, but allow interaction?

The onscreen keyboard in Windows 7 will let you keep focus on a textbox while you type using the keyboard. In C# and .Net, how can I force another application to retain focus while accepting input just like the Win7 onscreen keyboard? Or perhaps a better way to word it, how can I not have my app take focus when interacted with?
I have tried LockSetForegroundWindow and have seen no results with it.
You have to set the WS_EX_NOACTIVATE extended style on your window. The easiest way is by using P/Invoke.
private const int WS_EX_NOACTIVATE = 0x08000000;
private const int GWL_EXSTYLE = -20;
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int GetWindowLong(IntPtr hwnd, int index);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int SetWindowLong(IntPtr hwnd, int index, int newStyle);
...
var window = new Window();
window.SourceInitialized += (s, e) => {
var interopHelper = new WindowInteropHelper(window);
int exStyle = GetWindowLong(interopHelper.Handle, GWL_EXSTYLE);
SetWindowLong(interopHelper.Handle, GWL_EXSTYLE, exStyle | WS_EX_NOACTIVATE);
};
window.Show();
You can also use WPF interop class HwndSource to create your window. Its constructor accepts the extended window style.

Launching another application from C#

I'm trying to launch another application from C# application, is there a way to display this application inside the mainform of my application?
Thanks,
You can start other applications using Process.Start(...):
Process.Start(#"C:\Path\OtherApp.exe");
To embed the application within your form, check out this CodeProject article that demos a technique for hosting other application's windows within your form.
You can try do this via reparenting. See my post on MSDN where I describe this for WPF: Composite "shell" application.
The technique itself would be the same for WinForms. Have a host area in your app. Change the top-level window's style of the target application to WS_CHILD. Call SetParent(), changing the parent of the target window to your host area.
Note that in Win32, only a top-level window has a menu. Thus, changing to WS_CHILD removes the menu.
You can do it in that way :
[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", SetLastError = true)]
private static extern bool MoveWindow(IntPtr hwnd, int x, int y, int cx, int cy, bool repaint);
[DllImport("user32.dll", SetLastError = true)]
static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);
[DllImport("user32.dll")]
static extern IntPtr SetActiveWindow(IntPtr hWnd);
private const int GWL_STYLE = (-16);
private const int WS_VISIBLE = 0x10000000;
private const int WS_MAXIMIZE = 0x01000000;
private void Form1_Load(object sender, EventArgs e)
{
this.SuspendLayout();
Process notepad = new Process();
ProcessStartInfo psi = new ProcessStartInfo("notepad.exe");
psi.WindowStyle = ProcessWindowStyle.Normal;
notepad.StartInfo = psi;
notepad.Start();
this.ResumeLayout();
notepad.WaitForInputIdle(3000);
IntPtr old = SetParent(notepad.MainWindowHandle, this.Handle);
SetWindowLong(notepad.MainWindowHandle, GWL_STYLE, WS_VISIBLE + WS_MAXIMIZE);
MoveWindow(notepad.MainWindowHandle, 100, 100, 400, 400, true);
SetActiveWindow(notepad.MainWindowHandle);
SwitchToThisWindow(notepad.MainWindowHandle, true); }
In this way you have Notepad app in your form ;)
In general, it's next to impossible to display any kind of 3rd party application inside of yours.
If target app supports console interface, I would create my own interface for this app that will translate GUI commands to console commands of target app.

Categories