Open an Application .exe window inside another application - c#

I have an application in WPF running. I would like that, when a button is clicked inside this application, another application opens, with its window maximized. However, I don't want my first application to stop and wait. I want both to be open and running independently.
When the button is clicked again, in case the application is minimized, the application is maximized. In case it is not, it is open again.
How is it possible using C#? I have tried the following:
Process process = Process.GetProcesses().FirstOrDefault(f => f.ProcessName.Contains("Analysis"));
ShowWindow((process ?? Process.Start("..\\..\\..\\MS Analysis\\bin\\Debug\\Chemtech.RT.MS.Analysis.exe")).MainWindowHandle.ToInt32(), SW_MAXIMIZE);
But the window does not open, even though the process does start.

var hwnd = ..;
ShowWindow(hwnd, SW_MAXIMIZE);
BringWindowToTop(hwnd);
[DllImport("user32.dll", SetLastError=true)]
static extern bool BringWindowToTop(IntPtr hWnd)

Related

LoadKeyboardLayout() fails to change Keyboard Layout if the Windows Taskbar has current focus

I am changing the Keyboard Layout in Windows programmatically with global hot keys using:
IntPtr fGWindow = GetForegroundWindow();
SendMessage(fGWindow.ToInt32(), WM_INPUTLANGCHANGEREQUEST_as_unit, IntPtr.Zero, LoadKeyboardLayout(LANG, KLF_SUBSTITUTE_OK));
The code works perfectly except when I click the Windows Taskbar using the mouse (giving it current focus). In that situation, the message is sent but LoadKeyboardLayout() does noting.
Using HWND_BROADCAST instead of GetForegroundWindow() does not help.
UPDATE / More information:
The pointer obtained by GetForegroundWindow() when I click the taskbar (giving it focus) belongs to explorer.exe. In that situation the code is not working.
Here is the solution, basically adjustments are needed if the current foreground window is the system tray:
IntPtr shell_TrayWnd = FindWindow("Shell_TrayWnd", null);
if (fGWindow == shell_TrayWnd)
{
IntPtr vHandle = FindWindow("Progman", "Program Manager"); // Desktop Handler.
SetForegroundWindow(vHandle);
SendMessage(vHandle.ToInt32(), WM_INPUTLANGCHANGEREQUEST_as_unit, new IntPtr(-1), LoadKeyboardLayout(LANG, KLF_NOTELLSHELL));
}

Hide parent window, but show child window

I'm working on an application that should do the following on start-up:
Connect to an external application using COM (AutoCAD).
Send message to the application to run some DLL code (opens a window).
Hide AutoCAD's window, but keep the DLL's window visible.
I've successfully completed the first 2 steps, but the third is giving me some issues.
I do not know if it is possible to make a child window visible while it's parent is not visible. Every time that I make the child visible or make it the top most window, AutoCAD becomes visible as well.
My objective is to run my DLL code, but keep AutoCAD running in the background, completely invisible to my users. The DLL must be loaded, through AutoCAD, because it allows me to work with AutoCAD's .NET interface as opposed to COM.
In any case, I'm curious if what I'm trying to do is possible, perhaps through some Windows API calls or perhaps something in .NET.
PS: I'm unsure if this window relationship is really a parent-child one. I'm assuming it is though because my window belongs to the AutoCAD application instance due to the DLL loading.
Any help is greatly appreciated. Thanks! :)
EDIT:
DLL Code to create a window.
//CommandMethod is an AutoCAD attribute for entering into the DLL. This code is called
//when the user attempts the command "AUTOCADCOMMANDNAME" or can be done by simulating
//the command programmatically.
[CommandMethod("AUTOCADCOMMANDNAME", CommandFlags.Session)]
public void CommandEntry()
{
MainWindow mainWin = new MainWindow();
mainWin.ShowDialog();
}
Main Application Code
public static void Main()
{ //Use a utility class to create a connection to AutoCAD via COM
AcadApplication acadApp = ACUtil.GetAcadInstance(out createdNewInstance);
acadApp.Visible = false;
//Irrelevant code omitted...
acadApp.ActiveDocument.SendCommand("AUTOCADCOMMANDNAME");
acadApp.Quit(); //Exit AutoCAD application
//Note: doesn't quit until mainWin closes because of ShowDialog()
}
Can't be done. Parent windows control child window visibility.
Your best alternative is to make the DLL window a top-level window (but owned by the AutoCAD window).
Note that the DLL window will still be part of the AutoCAD thread.
What you want can be achieved, despite what others may think. You just need to think about the problem in a different way. Don't think about parent and child Windows... instead, think about a splash screen Window.
Typically, splash screens appear before the main application Window, but does that make them the parent? No, it doesn't. Normally, they'd be closed after the main Window has opened, but there is no reason why you couldn't hide it instead of closing it.
To find out how to do this in WPF, please refer to my answer from the How to open a child Window like a splash screen before MainWindow in WPF? question, here on Stack Overflow. Extending that answer a little bit, I should point out that you won't need to use a Timer. Instead of the code from the linked page, you could do something like this:
private void OpenMainWindow()
{
autoCadWindow.Visiblity = Visibility.Collapsed;
MainWindow mainWindow = new MainWindow();
mainWindow.Show();
}
Haha! I found it!
So, I ended up calling the SetWindowPos function in the Windows API and supplied the handle for AutoCAD window. I did this inside my main application:
[DllImport("User32.dll")]
static extern bool SetWindowPos(IntPtr hwnd, IntPtr hwndInsertAfter, int x, int y, int w, int h, uint flags);
public const int SWP_HIDEWINDOW = 0x0080;
public static void Main()
{
//...Setup AutoCAD...
//Change window size and hide it before calling to open mainWin inside the DLL.
SetWindowPos(new IntPtr(acadApp.HWND), new IntPtr(1), 0, 0, 0, 0, SWP_HIDEWINDOW);
//Display mainWin by entering the DLL.
acadApp.ActiveDocument.SendCommand("AUTOCADCOMMANDNAME");
//Terminate application as before...
}
Basically I'm telling the AutoCAD window to hide by modifying the HWND directly. I also set the dimensions to width=0 and height=0 which causes the window to take up the minimum size possible. Unfortunately, the window will flicker once, but for my purposes, that is negligible. If anyone can find a way to remove the flicker, that would be great! :)
EDIT: When using SetWindowPos, Windows tends to remember the values entered for the next time that application window is shown. This means that if not restored properly, then the next time the user opens AutoCAD manually, it will have the coordinates of 0,0 and the minimum width/height.
To change that behavior, it is necessary to obtain the window information. For my program, I used GetWindowRect obtain the original settings. Before closing my program, I restored those settings using SetWindowPos. See the code below for details:
First, import necessary WINAPI functions and structs:
[DllImport("User32.dll")]
static extern bool GetWindowRect(IntPtr hwnd, out RECT rect);
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
Obtain original settings before modifying window:
RECT originalRect;
GetWindowRect(new IntPtr(acadApp.HWND), out originalRect);
Modify the window to hide (and resize):
SetWindowPos(new IntPtr(acadApp.HWND), new IntPtr(1), 0, 0, 0, 0, SWP_HIDEWINDOW);
Restore original settings before quitting:
SetWindowPos(new IntPtr(acadApp.HWND), new IntPtr(1),
originalRect.Left,
originalRect.Top,
originalRect.Right - originalRect.Left,
originalRect.Bottom - originalRect.Top, 0);

Why doesn't getting the handle of the foreground window work in my scenario?

I have the wonderful job to create a .exe that is called with a shortcut that is called with the windows native shortcut calling way for elements that are in the start menu folder.
It is supposed to do something with one selected file of the topmost Explorer window.
I have found ways to find all selected files across all explorer windows, I know how to get the window handle of the topmost window and I knew how to get all files selected in the topmost window if getting the topmost window handle would work, which it doesn't in my case:
Calling the native method GetForegroundWindow() doesn't give me the handle of the top window, but another one, maybe the one of the program I wrote, which doesn't even use a console window or anything though visible, so I can't even check if it's a handle from my program without changing it in a way to display the console.I want to get the handle of the foreground window by using a keyboard combination that was set in the options of a shortcut.How do I get the window that was in the foreground before I called my program?Or how do I keep my program from stealing focus?Or how do I give the focus back to the last window that had it? / Take it away from the current one.Or how do I get the topmost window of a specific process? (explorer)
"Or how do I keep my program from stealing focus?"
Try this out...
Add this code to your Form:
private const int WS_EX_NOACTIVATE = 0x8000000;
protected override System.Windows.Forms.CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle = cp.ExStyle | WS_EX_NOACTIVATE;
return cp;
}
}
I found my solution.
It feels kind of hacky, but it works reliably.
To explain what it does in short:
1) It collects all current handles of explorer windows and the SHDocVw.IE object behind it (I wonder if there is a better way for this)
2) I am using the absolutely unreliable and weird GetNextWindow() function until I get the first one that was previously collected as explorer handle. This is always the top window. There are usually ~20 handles between the current window and the last selected explorer window.
3) Then I give back the path to the first file selected in that folder window.
This really feels like something that shouldn't be so hard.
I am going over the top with long cat but who cares.
The method should have error handling or checks for undesired states, for example SelectedItems() can be empty or null.
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd);
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
public static string returnSelectedFile()
{
IntPtr windowPtr = GetForegroundWindow();
Dictionary<string, SHDocVw.InternetExplorer> windows = new System.Collections.Generic.Dictionary<string, SHDocVw.InternetExplorer>();
foreach (SHDocVw.InternetExplorer window in new SHDocVw.ShellWindows())
if (Path.GetFileNameWithoutExtension(window.FullName).ToLower().Equals("explorer"))
windows.Add(window.HWND.ToString(), window);
long protectionCounter = 0;
while (true)
{
if (windows.ContainsKey(windowPtr.ToString()) || protectionCounter++ > 9999999)
break;
windowPtr = GetWindow(windowPtr, 2);
}
return ((Shell32.IShellFolderViewDual2)windows[windowPtr.ToString()].Document).SelectedItems().Item(0).Path;
}

Windows +D disabled but not working

I have two windows form MainForm and MinimizedMainForm. I want to disable Windows+D for both the forms. Parent of both forms is a third form FormBase. I have used following code for disabling the Windows+D
private const in GWL_HWNDPARENT =-8
IntPtr hprog = NativeMethods.FindWindowEx(NativeMethods.FindWindowEx(NativeMethods.FindWindow("Progman", "Program Manager"),
IntPtr.Zero, "SHELLDLL_DefView", ""),
IntPtr.Zero, "SysListView32", "FolderView");
NativeMethods.SetWindowLong(this.Handle, GWL_HWNDPARENT, hprog);
Problem I am facing is my MainForm is never getting minimized if I press Win+D.
and for first launch of MinimizedForm if I i press Win+D it doesnt get minimized.
But for second+ time Load of minimizedMainForm if I press Win+D , Form gets minimized. I have added above code on the FormLoad event of both the forms. MinimizedMainForm is opened when i click on panel on MainForm and vice versa. MainForm is the starting form of my project.
What should I do to stop the form from minimizing on 2nd+ loadForm events?
Maybe instead of preventing minimizing of window what can be minimized, you have to create window what can't be minimized instead: MinimizeBox = false ? (it can't be that simple I bet, but i can't write comments, so here comes a solution =D)
Basically Win + D is not for minimizing the windows but for showing desktop. Win+D = Show desktop. So even if your window does not have minimize box, it will get minimized.
Further, when you press Win+D, it is not your application which handles it but it is the windows itself which is handling it so it will never reach to your application at all so it makes no sense if you handle it in your application.
Try finding out some hack where your application is up, you stop windows from processing Win+D key.
There is a key in registry
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer
changing values of hotkeys here will disable the Win+D combination but it is not recommended as you will have to restore it back when you application leaves the focus.
And yes, if you are making a widget, follow the requirements of creating a widget. It will automatically provide you such functionality

Setting my C# form as a child to another application

I'm currently developing a form application which works as an overlay to another program (Skype). Right now, I'm using TopMost = true, but that's a pretty bad solution.
I have a handle to the Skype window, as well as a handle to my own window. How do I make my program fulfill the following three statements:
1. It has to disappear if Skype is minimized
2. It has to appear above Skype
3. It has to appear behind any other application which is above Skype
Above and behind relates to z-order.
I'm currently using the SetWindowLong function, but I cant get the desired results.
[DllImport("user32.dll")]
public static extern int SetWindowLong(HandleRef hWnd, int nIndex, HandleRef dwNewLong);
SetWindowLong(
new HandleRef(child, child.Handle),
-8, // GWL_HWNDPARENT
new HandleRef(owner, owner.Handle));
For #1, my application continually checks if the dimensions of Skype has changed, so I could simply also check if the window is no longer visible. However, I'm completely at loss with #2 and #3.
Thanks in advance.
Kloar

Categories

Resources