(I am an novice/beginner when it comes to C# and Winform)
I have a Windows Forms application with 2 forms. The first form is transparent and is just there to show and hide the second form. The second form is an "Overlay" with some buttons. I have a hotkey to open the second form but I can't get it to close the second form with a hotkey. I have tried some different things and googled a lot. The purpose with this application is to open the overlay menu and from that menu you can switch between applications.
Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace WindowsFormsApp2
{
public partial class Form1 : Form
{
//Click thurgh
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr Hwnd, int nIndex, int dwNewLong);
[DllImport("user32.dll")]
static extern int GetWindowLong(IntPtr hWnd, int nIndex);
//
//Hotkey
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(String sClassName, String sAppName);
private IntPtr thisWindow;
private Hotkey hotkey;
//
FormOverlay frm = new FormOverlay();
public Form1()
{
InitializeComponent();
this.BackColor = Color.LimeGreen;
this.TransparencyKey = Color.LimeGreen;
this.TopMost = true;
this.FormBorderStyle = FormBorderStyle.None;
int initialStyle = GetWindowLong(this.Handle, -20);
SetWindowLong(this.Handle, -20, initialStyle | 0x80000 | 0x20);
}
private void Form1_Load(object sender, EventArgs e)
{
thisWindow = FindWindow(null, "Form1");
hotkey = new Hotkey(thisWindow);
hotkey.RegisterHotKeys();
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
hotkey.UnRegisterHotKeys();
}
protected override void WndProc(ref Message keyPressed)
{
Process[] pname = Process.GetProcessesByName("FormOverlay");
if (keyPressed.Msg == 0x0312)
{
if (pname.Length > 0) //my latest try
{
frm.Hide();
MessageBox.Show("1");
}
else
{
frm.Show();
}
}
base.WndProc(ref keyPressed);
}
}
}
Hotkey.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace WindowsFormsApp2
{
class Hotkey
{
public enum fsModifiers
{
Alt = 0x0001,
Control = 0x0002,
Shift = 0x0004,
Window = 0x0008,
}
private IntPtr _hWnd;
public Hotkey(IntPtr hWnd)
{
this._hWnd = hWnd;
}
public void RegisterHotKeys()
{
RegisterHotKey(_hWnd, 1, (uint)fsModifiers.Control, (uint)Keys.G);
}
public void UnRegisterHotKeys()
{
UnregisterHotKey(_hWnd, 1);
UnregisterHotKey(_hWnd, 2);
}
#region WindowsAPI
[DllImport("user32.dll")]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);
[DllImport("user32.dll")]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
#endregion
}
}
If you have any documentation, article, video or tutorial that contains your answer please post it, too, so I don't ask too many questions in the comments.
Related
I'm trying to make a program that opens a browser on each multi-display.
When I did it with a notepad, it worked. However, when it's a browser didn't work and showed the error "System.InvalidOperationException: Process must exit before requested information can be determined". I will appreciate your help with this situation.
This is my code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp5
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern int MoveWindow(IntPtr hwnd, int x, int y,
int nWidth, int nHeight, int bRepaint);
private void Form1_Load(object sender, EventArgs e)
{
foreach (Screen item in Screen.AllScreens)
{
//Open a web browser
System.Diagnostics.Process process1 = System.Diagnostics.Process.Start("C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe");
//System.Diagnostics.Process process2 = System.Diagnostics.Process.Start("notepad.exe");
process1.WaitForInputIdle();
//process2.WaitForInputIdle();
//Move the browser window
MoveWindow(process1.MainWindowHandle, item.Bounds.X, item.Bounds.Y, item.Bounds.Width, item.Bounds.Height, 1);
//MoveWindow(process2.MainWindowHandle, item.Bounds.X, item.Bounds.Y, item.Bounds.Width, item.Bounds.Height, 1);
}
}
}
}
It seems that msedge.exe use a host process to start different tabs, so we can't use the created process ID to handle it.
Compare created process ID with processes in the Task Manager, the
process 38756 is missing.
Another tool to browse edge relative processes is the built-in task manager of edge.
We can't find process 38756 as well.
So re-search the target edge process is necessary.
This repo https://github.com/alex-tomin/Tomin.Tools.KioskMode demostrate how to move chrome window into different monitors and set as full screen.
I tried to extract the necessary and modify your code like below, hope it helps:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace TestWinFormsApp
{
// Get full definition of SetWindowPosFlags here:
// https://www.pinvoke.net/default.aspx/Enums/SetWindowPosFlags.html
[Flags]
public enum SetWindowPosFlags : uint
{
SWP_NOREDRAW = 0x0008,
SWP_NOZORDER = 0x0004
}
// Get full definition of ShowWindowCommands here:
// https://www.pinvoke.net/default.aspx/Enums/ShowWindowCommand.html
public enum ShowWindowCommands
{
Maximize = 3,
Restore = 9,
}
public static class WinApi
{
[DllImport("user32.dll", SetLastError = true)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, SetWindowPosFlags uFlags);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ShowWindow(IntPtr hWnd, ShowWindowCommands nCmdShow);
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load_1(object sender, EventArgs e)
{
var ignoreHandles = new List<IntPtr>();
foreach (Screen item in Screen.AllScreens)
{
this.StartEdgeProcess();
var windowHandle = this.GetWindowHandle("msedge", ignoreHandles);
ignoreHandles.Add(windowHandle);
WinApi.ShowWindow(windowHandle, ShowWindowCommands.Restore);
WinApi.SetWindowPos(windowHandle, IntPtr.Zero, item.Bounds.Left, item.Bounds.Top, 800, 600, SetWindowPosFlags.SWP_NOZORDER | SetWindowPosFlags.SWP_NOREDRAW);
WinApi.ShowWindow(windowHandle, ShowWindowCommands.Maximize);
}
}
private void StartEdgeProcess()
{
var process = new Process();
process.StartInfo.FileName = "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe";
process.StartInfo.Arguments = "about:blank" + " --new-window -inprivate ";
process.Start();
process.WaitForInputIdle();
}
private IntPtr GetWindowHandle(string processName, List<IntPtr> ignoreHandlers)
{
IntPtr? windowHandle = null;
while (windowHandle == null)
{
windowHandle = Process.GetProcesses()
.FirstOrDefault(process => process.ProcessName == processName
&& process.MainWindowHandle != IntPtr.Zero
&& !string.IsNullOrWhiteSpace(process.MainWindowTitle)
&& !ignoreHandlers.Contains(process.MainWindowHandle))
?.MainWindowHandle;
}
return windowHandle.Value;
}
}
}
I have this Form5 and When i load it, is supposed to load google chrome into this window form if chrome is already running or not then is going to start a new process.
Then issue stands at when im closing the Form5 then chrome is not being unembedded from the window form and as you can see on Form5_FormClosed is the code that is supposed to restore the window back to task bar but nothing happens and sometimes after 1 of 100 is working. What im doing wrong?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace TrinityItemCreator
{
public partial class Form5 : Form
{
private string urlDestination;
private Process myprocess;
public Form5(string urlTarget)
{
InitializeComponent();
urlDestination = urlTarget;
}
[DllImport("user32.dll")]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
// HWND Constants
static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2);
static readonly IntPtr HWND_TOP = new IntPtr(0);
static readonly IntPtr HWND_BOTTOM = new IntPtr(1);
// P/Invoke
[DllImport("user32.dll")]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
private void Form5_Load(object sender, EventArgs e)
{
Process[] pname = Process.GetProcessesByName("chrome");
if (pname.Length != 0) // chrome is already opened
{
//Process.Start("chrome", urlDestination);
Process[] processlist = Process.GetProcesses();
foreach (Process theprocess in processlist)
{
if (theprocess.ProcessName == "chrome")
{
SetParent(theprocess.MainWindowHandle, panel2.Handle);
int left = 1;
int top = 1;
int width = 876;
int height = 656;
SetWindowPos(theprocess.MainWindowHandle, HWND_TOP, left, top, width, height, 0);
myprocess = theprocess;
}
}
}
else
{
myprocess = Process.Start("chrome", urlDestination);
Thread.Sleep(1000);
SetParent(myprocess.MainWindowHandle, panel2.Handle);
int left = 1;
int top = 1;
int width = 876;
int height = 656;
SetWindowPos(myprocess.MainWindowHandle, HWND_TOP, left, top, width, height, 0);
}
}
private void Form5_FormClosed(object sender, FormClosedEventArgs e)
{
SetParent(myprocess.MainWindowHandle, IntPtr.Zero);
ShowWindow(myprocess.MainWindowHandle, 3); // maximize back
ShowWindow(myprocess.MainWindowHandle, 2); // minimize to taskbar
Thread.Sleep(1500);
}
private void ButtonMyTemplates_Click(object sender, EventArgs e)
{
Close();
}
}
}
I am trying to make a Windows Forms Application be able to repeatedly show and then hide itself.
The idea is to create a small app that overlays an image on the screen every time a modifier key like Num Lock or Caps lock is pressed. I have the detection of the keyboard keys working flawlessly, but I am not having much luck with creating a form that I can show and then hide repeatedly.
The way I see it, (please correct me if I'm wrong) there are two possible ways to make the form behave like I want it to:
Start the form normally in Program.cs and then hold the logic for hiding and showing the form and displaying the image inside Form1.cs
The form would call this.Hide() and this.Show() to hide and show itself, but whenever I try to do this, I cannot get this.Hide() to hide the form; the form remains visible on top of all of the open windows.
Hold the logic for hiding and showing the form in Program.cs and then just hold the logic to display the image in Form1.cs
I've been toying around with the code from this guide to show and hide the from from Program.cs with a class wrapper for the form, but as it turns out, form.Showdialog() prevents any further code execution until the form is closed.
I've been playing around with the code myself, and neither of the above methods have worked. Am I thinking about this in the wrong way entierly? Can a WFA ever behave in the way I want it to?
The code for this is a bit messy, and I'm not sure what parts are the most relevant here, but I'll do my best to include it here:
Program.cs:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Threading;
using System.Windows.Forms;
namespace KeyboardIndicators {
// ApplicationContext wrapper
public abstract class TrayIconApplicationContext : ApplicationContext {
private NotifyIcon lockIcon;
private ContextMenu lockIconContext;
protected TrayIconApplicationContext() {
// Wire up the ApplicationExitHandler to ApplicationExit events
Application.ApplicationExit += this.ApplicationExitHandler;
lockIconContext = new ContextMenu {
};
// Create lockIcon tray icon and make it visible
lockIcon = new NotifyIcon {
ContextMenu = lockIconContext,
Text = Application.ProductName,
Icon = new Icon("icon.ico"),
Visible = true
};
}
protected NotifyIcon LockIcon { get { return lockIcon; } }
protected ContextMenu LockIconContext { get { return lockIconContext; } }
// ApplicationExit event handler
private void ApplicationExitHandler(object sender, EventArgs e) {
this.OnApplicationExit(e);
}
// Performs cleanup to end the application
protected virtual void OnApplicationExit(EventArgs e) {
// TODO(Neil): Add meaningful thread cleanup here soon
if (lockIcon != null) {
lockIcon.Visible = false;
lockIcon.Dispose();
}
if (lockIconContext != null)
LockIconContext.Dispose();
}
}
// TrayIconApplicationContext wrapper for Form1 to control the activation of the form window
class FormApplicationContext : TrayIconApplicationContext {
public FormApplicationContext() {
// Add Exit menu item
MenuItem exit = new MenuItem("E&xit");
this.LockIconContext.MenuItems.Add(exit);
exit.Click += this.ExitContextMenuClickHandler;
//KeyboardIndicators indicators = new KeyboardIndicators();
//indicators.RunListener();
{
using(Form form = new Form1("NumLock", true))
form.ShowDialog();
}
}
private void ExitContextMenuClickHandler(object sender, EventArgs eventArgs) {
this.ExitThread();
}
}
public class KeyboardIndicators {
class LockState {
// Is the numlock key on?
public bool Num;
// Is the capslock key on?
public bool Caps;
// Is the scroll lock key on?
public bool Scroll;
}
public void RunListener() {
try {
// Store the old keyboard lock state
LockState prevState = new LockState() {
Num = Control.IsKeyLocked(Keys.NumLock),
Caps = Control.IsKeyLocked(Keys.CapsLock),
Scroll = Control.IsKeyLocked(Keys.Scroll)
};
while (true) {
// Store the new keyboard lock state
LockState newState = new LockState() {
Num = Control.IsKeyLocked(Keys.NumLock),
Caps = Control.IsKeyLocked(Keys.CapsLock),
Scroll = Control.IsKeyLocked(Keys.Scroll)
};
//TODO(Neil): Handle simultaneous presses better, i.e. queue the balloon tips
if (newState.Num != prevState.Num) {
Form1 form = new Form1("NumLock", newState.Num);
} else if (newState.Caps != prevState.Caps) {
Form1 form = new Form1("CapsLock", newState.Caps);
} else if (newState.Scroll != prevState.Scroll) {
Form1 form = new Form1("ScrollLock", newState.Scroll);
}
// Set the previous lock state to the new one in prep for the next iteration
prevState = newState;
// Sleep for 500ms
Thread.Sleep(500);
}
} catch (ThreadAbortException) { /* No need to do anything, just catch the ThreadAbortException.*/ }
}
}
static class Program {
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//Application.Run(new Form1("NumLock", true));
Application.Run(new FormApplicationContext());
}
}
}
Form1.cs:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace KeyboardIndicators {
public partial class Form1 : Form {
public Form1(String activatedModifier, bool lockState) {
InitializeComponent();
ShowForm(activatedModifier);
//this.Show();
//this.Hide();
}
public void ShowForm(String activatedModifier) {
PictureBox pictureBox = new PictureBox();
Image myBitmap = Image.FromFile("cube.png");
Size bitmapSize = new Size(myBitmap.Width, myBitmap.Height);
switch (activatedModifier) {
case "NumLock":
break;
case "CapsLock":
break;
case "ScrollLock":
break;
}
this.Size = bitmapSize;
pictureBox.ClientSize = bitmapSize;
pictureBox.Image = myBitmap;
pictureBox.Dock = DockStyle.Fill;
this.Controls.Add(pictureBox);
this.FormBorderStyle = FormBorderStyle.None;
}
protected override CreateParams CreateParams {
get {
CreateParams createParams = base.CreateParams;
createParams.ExStyle |= 0x00000020; // WS_EX_TRANSPARENT
return createParams;
}
}
}
}
As an example I have created a Winforms Application which displays "NUM" and / or "CAPS" if any of those keys is pressed otherwise the form is hidden.
The detection of the keys is based on the C# Low Level Keyboard Hook.
Program.cs
using System;
using System.Windows.Forms;
namespace WinFormsKeyHook
{
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
Form1.cs
Note: Add a label named 'label1' to Form1 in Designer.
using System.Collections.Generic;
using System.Windows.Forms;
namespace WinFormsKeyHook
{
public partial class Form1 : Form
{
private static bool _caps;
private static bool _num;
public Form1()
{
InitializeComponent();
KeyboardHook kh = new KeyboardHook();
kh.KeysToObserve.AddRange(new List<Keys> { Keys.CapsLock, Keys.NumLock });
kh.InstallHook();
kh.KeyDown = key => ProcessKeyDown(key);
_caps = Control.IsKeyLocked(Keys.CapsLock);
_num = Control.IsKeyLocked(Keys.NumLock);
}
private void ProcessKeyDown(Keys key)
{
if (key == Keys.CapsLock)
{
_caps = !_caps;
}
if (key == Keys.NumLock)
{
_num = !_num;
}
this.ShowState(_num, _caps);
}
internal void ShowState(bool num, bool caps)
{
if (!num && !caps)
{
this.Hide();
return;
}
this.label1.Text = "";
this.label1.Text += num ? "NUM " : "";
this.label1.Text += caps ? "CAPS" : "";
if (!this.Visible)
{
this.Show();
}
}
}
}
KeyboardHook.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace WinFormsKeyHook
{
public class KeyboardHook
{
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private IntPtr _hookID = IntPtr.Zero;
public List<Keys> KeysToObserve { get; set; } = new List<Keys>();
public Action<Keys> KeyDown;
public void InstallHook()
{
_hookID = SetHook(HookCallback);
}
~KeyboardHook()
{
UnhookWindowsHookEx(_hookID);
}
public IntPtr SetHook(LowLevelKeyboardProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0);
}
}
public delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
public IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
var key = (Keys)vkCode;
Console.WriteLine(key);
KeyDown(key);
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
}
}
I tried this tutorial: https://www.youtube.com/watch?v=FL_y8GT1L7E
But after I register the hotkey, it is registered, but the callback just doesn't work.
When calling WndProc, the keyPressed.Msg doesn't equal to 0x0312 which means key press.
Any suggestions for creating a callback for a registered hotkey?
this is the class which registers and unregisters the hotkeys:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
class Hotkey
{
[DllImport("user32.dll")]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);
[DllImport("user32.dll")]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
private IntPtr _hWnd;
public Hotkey(IntPtr hWnd)
{
this._hWnd = hWnd;
}
public enum fsmodifiers
{
Alt = 0x0001,
Control = 0x0002,
Shift = 0x0004,
Window = 0x0008
}
public void RegisterHotkeys()
{
RegisterHotKey(IntPtr.Zero, 1, (uint)fsmodifiers.Control, (uint)Keys.B);
}
public void UnregisterHotkeys()
{
UnregisterHotKey(IntPtr.Zero, 1);
}
}
}
and the current callback is this:
protected override void WndProc(ref Message keyPressed)
{
if(keyPressed.Msg == 0x0312)
Console.WriteLine();
base.WndProc(ref keyPressed);
}
0x0312 is the value of key press in windows.
but I set a breakpoint where Console.WriteLine() but it never gets there.
This is a windows forms application.
When you call the native function RegisterHotKey(...) you miss the window handle (hWnd).
Try this:
class Hotkey
{
[DllImport("user32.dll")]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);
[DllImport("user32.dll")]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
private IntPtr _hWnd;
public Hotkey(IntPtr hWnd)
{
this._hWnd = hWnd;
}
public enum fsmodifiers
{
Alt = 0x0001,
Control = 0x0002,
Shift = 0x0004,
Window = 0x0008
}
public void RegisterHotkeys()
{
RegisterHotKey(this._hWnd, 1, (uint)fsmodifiers.Control, (uint)Keys.B);
}
public void UnregisterHotkeys()
{
UnregisterHotKey(this._hWnd, 1);
}
}
To get the handle of a windows form use:
this.Handle
I have the method DrawToBitmap but how do I get the handle of a process window ?
For example notepad.exe
What I want to do is when I start the program if the process(for example notepad.exe) not running yet then start it once it's running get it's window handle and save the window to image file.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Elgato.BaseClasses.UI;
using Elgato;
using Elgato.BaseClasses.Streaming;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
[DllImport("USER32.DLL")]
private static extern bool PrintWindow(HandleRef hwnd, IntPtr hdcBlt, int nFlags);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
}
public static Image DrawToBitmap(IntPtr handle)
{
RECT rect = new RECT();
GetWindowRect(handle, ref rect);
Bitmap image = new Bitmap(rect.Right - rect.Left, rect.Bottom - rect.Top);
using (Graphics graphics = Graphics.FromImage(image))
{
IntPtr hDC = graphics.GetHdc();
PrintWindow(new HandleRef(graphics, handle), hDC, 0);
graphics.ReleaseHdc(hDC);
}
return image;
}
}
}
To check whether a process exists and get the window handle if it exists, use the following code:
var processes = Process.GetProcessesByName("notepad");
if (processes.Length > 0)
{
var handle = processes[0].MainWindowHandle;
}
else
{
// Notepad is not started
}