How can I change another program's -- let's say Skype's -- window's size, from my C# program?
You can use MoveWindow (Where hWnd is the window you want 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).
You need to get the window handle of the other program, use Process.MainWindowHandle or FindWindow.
Having this, you can PInvoke SetWindowPos() to move, resize, change the Z-order or the min/max/restore state of the window.
I would use the Windows Api SetWindowPos
check this one out: Using SetWindowPos in C# to move windows around
of course first you should know the handle of the window you want to resize, this can be done in many ways like getting the process by name then the MainWindow of that process or with EnumWindow or FindWindow APIs
Related
I have a screen capturing utility on which I can rubber band an area on the desktop. I've done this is a fairly easy manner, I have a form which is the same size as the screen on which I draw a screenshot of the desktop transformed into grayscale. When the user holds down the left mouse button he/she can select an area on the form. The rectangle which the user draws is filled with TransparentColor. Once the users lifts up his/her mouse the transparent rectangle is left in place and the actual desktop is visible. Here comes my problem:
On my dev PC I can actually click through this transparent rectangle and navigate around etc. while on my other PC the form responds on mouse clicks on the actual transparent rectangle.
I'm using .NET 4.0 in C#, any ideas on how I can make it actually click through to the desktop on all cases??
Thank you and much appreciated :)
I managed to find a proper solution for this problem after looking very deeply into this. It turns out with the proper Win32 API calls it is possible to set a form "Invisible" to mouse clicks. This can be achieved by:
public const int GWL_EXSTYLE = -20;
public const uint WS_EX_LAYERED = 0x00080000;
public const uint WS_EX_TRANSPARENT = 0x00000020;
[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);
[DllImport("user32.dll")]
static extern bool SetLayeredWindowAttributes(IntPtr hwnd, uint crKey, byte bAlpha, uint dwFlags);
public void SetFormTransparent(IntPtr Handle) {
oldWindowLong = GetWindowLong(Handle, GWL_EXSTYLE);
SetWindowLong(Handle, GWL_EXSTYLE, Convert.ToInt32(oldWindowLong | WS_EX_LAYERED | WS_EX_TRANSPARENT));
}
public void SetFormNormal(IntPtr Handle) {
SetWindowLong(Handle, GWL_EXSTYLE, Convert.ToInt32(oldWindowLong | WS_EX_LAYERED));
}
But there is a trick to everything. You need to be careful that all clicks made on the forum will fall through the form and be sent to anything below the form. To ensure that if I click on my form e.g. on a button and I want the button clicked I did a simple trick. I have a timer in the background running every N milliseconds and analyzing the position of the Cursor. If it's above the area I want it to be, it'll set the Form to Normal via SetFormNormal() otherwise it'll be transparent.
Hope this code bit helps and people will use it.
I have both dark and light versions of my application icon; the dark version works best on gray surfaces such as Windows XP taskbar, where the light version works best as an icon in the titlebar.
Is there a way I can set the icon in the taskbar to a different icon than the one used in my form in C# (P/Invoke is fine)?
Send the WM_SETICON message to your form with different icon handles for the ICON_SMALL and the ICON_BIG parameter:
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, int wParam, IntPtr lParam);
private const uint WM_SETICON = 0x80u;
private const int ICON_SMALL = 0;
private const int ICON_BIG = 1;
public MyForm()
{
InitializeComponent();
SendMessage(this.Handle, WM_SETICON, ICON_SMALL, Properties.Resources.IconSmall.Handle);
SendMessage(this.Handle, WM_SETICON, ICON_BIG, Properties.Resources.IconBig.Handle);
}
I know this is an old question but I came across it when trying to achieve the same thing, and well yes you can do this, on Windows 7/8 at least.
It turns out an ICO file doesn't just contain one image, it contains 9 different images at 9 different resolutions:
16x16
24x24
32x32
48x48
64x64
72x72
80x80
96x96
128x128
On Windows 7 and 8, the 64x64 image is used on the taskbar, and the 16x16 image is used on the icon which is placed on the top left hand corner of your form.
You can use a tool like Greenfish Icon Editor Pro (I don't work for them or anything, this isn't a plug!) to have these as two seperate images, and then add this *.ico file as normal to your Windows Form/WPF form in Visual Studio.
The end result is shown below:
As you can see my WPF application has two seperate icons, one in the taskbar and another on the form.
So, I thought this would be simple and, well, I was wrong. Here is a simplified description of the problem:
I am writing a small application for our manufacturing folks that will grab a screenshot of the entire desktop as well as the foreground window when they click the application's icon in the system tray. Currently, I am using the Win32 method "GetforegroundWindow" in the MouseMove event of the NotifyIcon to save the foreground window handle and take the screenshot in the Click event.
This does work sometimes, but if I click the icon very quickly I actually capture the task bar instead of the foreground window. I am not sure why this is happening (I do understand that the task bar is a window, I don't understand why sometimes it seems to have focus in MouseMove before I have clicked), and I have had little luck using the EnumWindows method as well, likely because I do not completely understand how it works.
It would seem that, if I were able to get the z position of each window using only the window handle, this would be an easy problem to solve using EnumWindows. I have not found a method to do that however.
So, I ask you guys; how would you write a method to locate the foreground window reliably, given that it may not have focus at the time? Either my google-fu is failing me or the information on this is sparse. Thanks in advance.
The taskbar is as valid a foreground window as any. When you click it, it will temporarily be the foreground window. And if you click Start and press Escape for example, it will be the foreground window until you click off of it.
You can probably use GetWindow with HWND_NEXT passing in the window handle of the taskbar.
Nevermind, since the taskbar is a topmost window, GetWindow (or GetNextWindow, etc) will operate differently. I would suggest revisiting the EnumWindows solution which is probably your best bet.
If the form you want the snapshot of is the same as the form linked to the task bar, you really do not need to use GetforegroundWindow. Just use the Form.hWnd and pass that into the function getting the snapshot. You may need to make it the top window by calling
[DllImport( "user32.dll" )]
public static extern IntPtr SetForegroundWindow( IntPtr hWnd );
or
[DllImport( "user32.dll" )]
public static extern bool BringWindowToTop( HandleRef hWnd );
If you want the whole desktop, then you probably just need to put in a Thread.Sleep to make sure the foreground window has had enough to come to the top before getting the desktop snapshot.
putting the src from my comment here for better printing
[DllImport( "user32.dll" )]
public static extern IntPtr GetForegroundWindow();
[DllImport( "user32.dll" )]
public static extern IntPtr GetActiveWindow();
// this or the next line not both
IntPtr curWindow = GetActiveWindow();
IntPtr curWindow = GetForegroundWindow();
BringWindowToTop( window );
System.Threading.Thread.Sleep( 500 );
Where the thread spleep gives the window enough time to come to the top of the Z order.
I am interested in writing an application that overlays a small heads up display (HUD) over another application, in VB.NET. What is an example of this?
I will need to enumerate all open windows to find the window that I want, and then overlay some text in a specific position on the window. If the user moves that window, my text will need to follow. (I will probably be painting the text in a loop over and over).
Edit: nobody answered my original query - I added C# to the keywords to see if any of gurus in that language might have an answer.
You can use WinApi to enumerate windows.
You can start googling with
[DllImport("user32.dll")]
public static extern int EnumWindows(EnumWindowsProc ewp, int lParam);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetWindowRect(IntPtr hWnd, ref WapiRect lpRect);
When you have found your window and has its handle, there is no problem to plot on it with something like
Graphics g = Graphics.FromHwnd(win.Handle);
g.FillRectangle(new SolidBrush(Color.White), 0, 0, 1000, 1000);
But to overlay... One possible solution is to create own border less form(it can be made even transparent) and place your text on it. Then just place this special form on top of another application.
I know how to simulate mouse and keyboard events, but they act as if the user did them, so they will affect the window that is active. What I need is to simulate one of those inputs, but in a Window that is not active.
I'm not saying that it is minimized, imagine for example, you have msPaint, and notepad. Notepad is in front of paint. And you want to simulate mouse clicks in certain coordinates of the paint window, but without setting it active, making it possible for the user to keep using notepad which is in fron of paint.
Is this possible at all? Thanks!
I've tried this:
const int WM_KEYDOWN = 0x100;
Thread.Sleep(5000);
Process x = Process.Start(#"C:\WINDOWS\NOTEPAD.EXE");
PInvokes.PlatformInvokeUSER32.SendMessage(x.MainWindowHandle, WM_KEYDOWN, ((int)Keys.W), 0);
but it doesn't work =( Doesn't do anything :(
You can try the UI automation API. It supports also legacy applications.
Maybe try the PostMessage function instead:
[DllImport("user32.dll", CharSet=CharSet.Auto)]
private static extern int PostMessage(
int hWnd, int msg, int wParam, IntPtr lParam);
Depending on the target app, there could be lots of issues. Some apps trigger on WM_KEYDOWN or WM_KEYUP instead of WM_CHAR. Also, the key might already be down and is being ignored. For targets like webbrowsers, you need to get the right window handle. Winspector can get that for you.
Your code wont work because SendMessage requires that the window you're sending to be active.
Try PostMessage.