As a fun office project we are building a cool transitional background Winform's app to replace the standard windows desktop background.
One of the challenges is that we need our WinForm window to sit on top of the desktop background and icons but not the taskbar.
Is there some way to precisely adjust the Z-Index of a winform window so that it sits on top of the windows desktop but still allows the taskbar and other windows to sit on top of it?
Thank you for the assistance in getting this working. The following worked for us.
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
public static extern IntPtr SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int Y, int cx, int cy, int wFlags);
const short SWP_NOMOVE = 0X2;
const short SWP_NOSIZE = 1;
const short SWP_NOZORDER = 0X4;
const int SWP_SHOWWINDOW = 0x0040;
Usage as follows.
// Our desktop is the top most window.
IntPtr desktop = new IntPtr(0);
// The running form we are testing this code with.
IntPtr form1 = System.Windows.Forms.Application.OpenForms[0].Handle;
// So we're setting our window Z-index to that of the desktop,
// but we setting flags for showing the window and then not not moving and resizing it.
SetWindowPos(form1, desktop, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
The Spy++ is really a great tool to learn about the structure of windows and child windows. We found out that setting the IntPtr to Zero will automatically make it select the Desktop (most top) window.
Download spy++ http://mdb-blog.blogspot.com/2010/11/microsoft-spy-or-spyxx-for-download.html then check what's the desktop handle and the start menu handle respectively. This is just to make the proof of concept later you have to find out a better way of taking the handles. Using P\Invoke calls you can get those windows z-order
int GetZOrder(IntPtr hWnd)
{
var z = 0;
for (IntPtr h = hWnd; h != IntPtr.Zero; h = GetWindow(h, 3)) z++;
return z;
}
That code was copied from this question How to get the z-order in windows?
Then you can use SetWindowPos https://msdn.microsoft.com/en-us/library/windows/desktop/ms633545%28v=vs.85%29.aspx to position your own windows exactly where you want it to be. If you are using windows 8 have in mind that a lot of folks have ClassicShell installed on their machines. Good luck.
Related
In WPF is it possible to make a Window "Always on top" of another external process window?
Suppose I would want my application to show always over the "notepad.exe" window only?
You're looking for the SetWindowPos function. In C#, you can implement a wrapper as such:
[DllImport("user32.dll")]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
You can learn more on pinvoke about the supported parameters that you can pass - you will need to reliably identify the window handle for the process, and then overlay the window.
I want to tile two windows programs horizontally in C#. It's for a data view program using Chrome for viewing 2d images and Unity3d is for 3d and navigation.
For example, i can select two programs in windows task manager, and the context has an option to tile them.
Is there a handle in the .Net framework for tiling different program windows?
Probably the best thing is to use MoveWindow (Where hWnd is the window to move):
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
MoveWindow(ApplicationHandle, 600, 600, 600, 600, true);
If you don't know the window pointer, you can use the FindWindow functionality.
Also worth a read is MSDN SetWindowPos (Very similar to MoveWindow).
I need some applications running overnight on Citrix. I don't wish to stay awake all night for that. The Session will timeout and application will be closed. I would not convince the administrator to change the Citrix configuration for this application.
I am trying to create application which will periodically send mouse or keyboard events to the Citrix window. I already have a simple solution which is clicking the mouse.
I wish to have a better solution where everything will be done on background and events would be send just to the Citrix window. Any ideas how to achieve that?
I am using Windows and C# with .NET.
Thank you for any help.
Update #1
I am trying to use Citrix Live Monitoring API as it appears to be a best option. I end up with this:
WFICALib.ICAClient ico = new WFICALib.ICAClient();
int enumHandle = ico.EnumerateCCMSessions();
Console.WriteLine(ico.GetErrorMessage(ico.GetLastError()));
Unfortunately this returns an error message saying:
Live monitoring is disabled
According to documentation it requires following registry keys to be set to 1:
"HKLM\Software\Citrix\ICA Client\CCM\AllowLiveMonitoring(REG_DWORD)"
Problem is that I was unable to find Citrix key in "HKLM\Software\" and it also don't work if I created this keys and values. How do I enable Live Monitoring API?
I have played around with sending input to other windows in the past. I used something like the following:
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern bool SetCursorPos(int x, int y);
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern void mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);
private const int MOUSEEVENTF_LEFTDOWN = 0x02;
private const int MOUSEEVENTF_LEFTUP = 0x04;
private static void LeftMouseClick(Point point)
{
int xpos = (int)point.X;
int ypos = (int)point.Y;
if (SetCursorPos(xpos, ypos))
{
mouse_event(MOUSEEVENTF_LEFTDOWN, xpos, ypos, 0, 0);
mouse_event(MOUSEEVENTF_LEFTUP, xpos, ypos, 0, 0);
}
}
So to make this work you need to inject coordinates that fall within the Citrix Receiver window. I can't recall whether you get any focus/activation issues - I believe the click injection should bring the window into focus. I never did anything particularly serious with this code so no guarantees.
I'm trying to grab a window by the process name and focus it, then take a screenshot of it. It works perfectly unless I have Teamviewer open (not even while using teamviewer to screenshare, just when teamviewer is running)
When teamviewer is running the window isn't focused or brought to the foreground, and the rect it screenshots is very small (33x21) where normally it would be 1600x900.
Here is the code in question:
proc = Process.GetProcessesByName(procName)[0];
SetForegroundWindow(proc.MainWindowHandle);
ShowWindow(proc.MainWindowHandle, SW_RESTORE);
Rect rect = new Rect();
GetWindowRect(proc.MainWindowHandle, ref rect);
int width = rect.right - rect.left;
int height = rect.bottom - rect.top;
Bitmap bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb);
Graphics.FromImage(bmp).CopyFromScreen(rect.left, rect.top, 0, 0, new Size(width, height), CopyPixelOperation.SourceCopy);
Here is where I'm getting those functions:
[DllImport("user32.dll")]
private static extern IntPtr ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll")]
public static extern IntPtr GetWindowRect(IntPtr hWnd, ref Rect rect);
[DllImport("user32.dll")]
private static extern int SetForegroundWindow(IntPtr hWnd);
I too have found that teamViewer break UI Automation. Disabling the "Present this Application" function re-enables UI Automation to work.
I have encountered a similar problem. On two Windows 7 Pro computers I noticed that with the TeamViewer client running the following code stops working.
var wordProcess = Process.GetProcessesByName("winword")
.FirstOrDefault(process => process.MainWindowTitle.Contains(documentName));
Setting a breakpoint and inspecting single running WINWORD process reveals that Process.MainWindowTitle property is blank most of the times. While WinWord windows taskbar icon clearly shows the title.
Exiting TeamViewer restores the things back to normal: Process.MainWindowTitle every time becomes properly populated.
I have reported the issue to the TeamViewer team.
Tested with:
TeamViewer 9 ver. 9.0.27339, set for unattended access; MS Word 2007
It takes some time for my program to finish computation, so I would like to run it, read some web pages meanwhile, and when the screen flashes (notification of finished computation), I would get back to my program.
The only missing part is -- how to flash entire screen in C#? I use WPF if this matters.
Please note -- my program is not visible, the other program (web browser for example) takes entire screen (that is the point of the problem, because otherwise, I wouldn't need any notification at all).
Flash = blink.
my first approach would be: on completion of the computation have your program open a new topmost window with transparent background and set it to some color (white) for some brief intervals and close the window again. mind you, while the window is on top you'll not be able to interact with underlying windows during the flashing because the window will eat those events. Alternatively, you could do what most other windows applications (like outlook or messenger) do: display a brief notification box that is clickable to get you to the associated application (your program).
i think a more 'normal' practice would be to install the app as a sys tray icon - then you can change that upon any status change.
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern Int16 FlashWindowEx(ref FLASHWINFO pwfi);
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct FLASHWINFO {
public UInt32 cbSize;
public IntPtr hwnd;
public UInt32 dwFlags;
public UInt32 uCount;
public UInt32 dwTimeout;
}
public const UInt32 FLASHW_STOP = 0;
public const UInt32 FLASHW_CAPTION = 1;
public const UInt32 FLASHW_TRAY = 2;
public const UInt32 FLASHW_ALL = 3;
public void Flash() {
FLASHWINFO flashInfo = new FLASHWINFO();
flashInfo.cbSize = (uint)System.Runtime.InteropServices.Marshal.SizeOf(flashInfo);
flashInfo.hwnd = this.Handle; // get the window handle
flashInfo.dwFlags = FLASHW_TIMERNOFG | FLASHW_ALL;
flashInfo.uCount = UInt32.MaxValue;
flashInfo.dwTimeout = 0;
FlashWindowEx(ref flashInfo);
}
I don't think that you can technically flash your screen with WPF. Maybe with a Win32 function. But would it be a possibility to make a screenshot and show a Windows that shows a modified version of that screenshot? This window would have to be declared as TopMost and cover your screen and your image could be modified by increasing the alpha channel over the time.
Edit: OK, I think I misunderstood "flash". If you just want to show a flashing rectangle with one color have a look at the thread which Mamta Dalal posted.