C# How to Make a BalloonToolTip from a Non-Form Application - c#

Okay, So I'm attempting to make a Simple Screenshot program and I need the program to show a BalloonToolTip when a screenshot is taken and when the program is set to run on start up. The code below show my entire program, there is no form, nor is there a designer. Just a program that runs from Program.cs, and its not a console application.
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Windows;
using FullscreenShot.Properties;
using GlobalHotKey;
using System.Windows.Input;
using System.Timers;
using System.Threading.Tasks;
using Microsoft.Win32;
namespace FullscreenShot
{
class Program
{
private static NotifyIcon notifyIcon;
private static HotKeyManager hotKeyManager;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
System.Windows.Forms.Application.EnableVisualStyles();
System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(false);
// We need to dispose here, or the icon will not remove until the
// system tray is updated.
System.Windows.Forms.Application.ApplicationExit += delegate{ notifyIcon.Dispose(); };
CreateNotifyIcon();
System.Windows.Forms.Application.Run();
}
/// <summary>
/// Creates the icon that sits in the system tray.
/// </summary>
private static void CreateNotifyIcon()
{
notifyIcon = new NotifyIcon
{
Icon = Resources.AppIcon,
ContextMenu = GetContextMenu()
};
notifyIcon.Visible = true;
/*------------------------------------------------------------*/
hotKeyManager = new HotKeyManager();//Creates Hotkey manager from GlobalHotKey
var hotKey = hotKeyManager.Register(Key.F12, ModifierKeys.Control); // Sets Hotkey to Control + F12, ModifierKeys must be pressed first/
hotKeyManager.KeyPressed += HotKeyManagerPressed; //Creates void for "HotKeyManagerPressed"
void HotKeyManagerPressed(object sender, KeyPressedEventArgs e) //Checks to see if hotkey is pressed
{
if(e.HotKey.Key == Key.F12)
{
TakeFullScreenShotAsync();
BalloonTip();
// MessageBox.Show("Screenshot Taken");
}
}
}
/// <summary>
/// Creates BalloonTip to notify you that your Screenshot was taken.
/// </summary>
private static void BalloonTip()
{
notifyIcon.Visible = true;
notifyIcon.Icon = SystemIcons.Information;
notifyIcon.ShowBalloonTip(740, "Important From Screenshot", "Screenshot Taken", ToolTipIcon.Info);
}
private static void BalloonTip2()
{
notifyIcon.Visible = true;
notifyIcon.Icon = SystemIcons.Information;
notifyIcon.ShowBalloonTip(1, "Important From Screenshot", "Screenshot will now begin on startup", ToolTipIcon.Info);
}
///<summary>
///Creates the contextmenu for the Icon
///<summary>
private static ContextMenu GetContextMenu()
{
string myPath = System.AppDomain.CurrentDomain.BaseDirectory.ToString();
System.Diagnostics.Process prc = new System.Diagnostics.Process();
prc.StartInfo.FileName = myPath;
ContextMenu menu = new ContextMenu();
menu.MenuItems.Add("Take Screenshot (Ctrl+F12)", delegate { TakeFullScreenShotAsync(); });
menu.MenuItems.Add("Open Folder", delegate { prc.Start(); });
menu.MenuItems.Add("Exit", delegate { System.Windows.Forms.Application.Exit(); });
menu.MenuItems.Add("Run On Startup", delegate { RunOnStartup(); });
return menu;
}
/// <summary>
/// Simple function that finds Registry and adds the Application to the startup
/// </summary>
private static void RunOnStartup()
{
RegistryKey reg = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
reg.SetValue("MyApp", Application.ExecutablePath.ToString());
BalloonTip2();
MessageBox.Show("The Program will now start on startup");
}
/// <summary>
/// Gets points for the screen uses those points to build a bitmap of the screen and saves it.
/// </summary>
private static async void TakeFullScreenShotAsync()
{
await Task.Delay(750);//Allows task to be waited on for .75ths of a second. Time In ms.
int width = Screen.PrimaryScreen.Bounds.Width;
int height = Screen.PrimaryScreen.Bounds.Height;
using (Bitmap screenshot = new Bitmap(width, height, PixelFormat.Format32bppArgb))
{
using (Graphics graphics = Graphics.FromImage(screenshot))
{
System.Drawing.Point origin = new System.Drawing.Point(0, 0);
System.Drawing.Size screenSize = Screen.PrimaryScreen.Bounds.Size;
//Copy Entire screen to entire bitmap.
graphics.CopyFromScreen(origin, origin, screenSize);
}
//Check to see if the file exists, if it does, append.
int append = 1;
while (File.Exists($"Screenshot{append}.jpg"))
append++;
string fileName = $"Screenshot{append}.jpg";
screenshot.Save(fileName, ImageFormat.Jpeg);
}
}
}
}
Now you may not need all of that but I want to make sure i didn't mess anything up in the process, and yes my Resources are being found and the Icon is set, I'm just not understanding why this isn't working.

I just copied all your code there's a small problem, not sure it's you copy paste error You need to keep HotKeyManagerPressed outside. It worked for me with this, I see the notification for me it's windows 10 notification.
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Windows;
using GlobalHotKey;
using System.Windows.Input;
using System.Timers;
using System.Threading.Tasks;
using Microsoft.Win32;
using FullScreenShot.Properties;
namespace FullScreenShot
{
class Program
{
private static NotifyIcon notifyIcon;
private static HotKeyManager hotKeyManager;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
System.Windows.Forms.Application.EnableVisualStyles();
System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(false);
// We need to dispose here, or the icon will not remove until the
// system tray is updated.
System.Windows.Forms.Application.ApplicationExit += delegate { notifyIcon.Dispose(); };
CreateNotifyIcon();
System.Windows.Forms.Application.Run();
}
/// <summary>
/// Creates the icon that sits in the system tray.
/// </summary>
private static void CreateNotifyIcon()
{
notifyIcon = new NotifyIcon
{
Icon = Resources.AppIcon,
ContextMenu = GetContextMenu()
};
notifyIcon.Visible = true;
/*------------------------------------------------------------*/
hotKeyManager = new HotKeyManager();//Creates Hotkey manager from GlobalHotKey
var hotKey = hotKeyManager.Register(Key.F12, ModifierKeys.Control); // Sets Hotkey to Control + F12, ModifierKeys must be pressed first/
hotKeyManager.KeyPressed += HotKeyManagerPressed; //Creates void for "HotKeyManagerPressed"
}
private static void HotKeyManagerPressed(object sender, KeyPressedEventArgs e) //Checks to see if hotkey is pressed
{
if (e.HotKey.Key == Key.F12)
{
TakeFullScreenShotAsync();
BalloonTip();
// MessageBox.Show("Screenshot Taken");
}
}
/// <summary>
/// Creates BalloonTip to notify you that your Screenshot was taken.
/// </summary>
private static void BalloonTip()
{
notifyIcon.Visible = true;
notifyIcon.Icon = SystemIcons.Information;
notifyIcon.ShowBalloonTip(740, "Important From Screenshot", "Screenshot Taken", ToolTipIcon.Info);
}
private static void BalloonTip2()
{
notifyIcon.Visible = true;
notifyIcon.Icon = SystemIcons.Information;
notifyIcon.ShowBalloonTip(1, "Important From Screenshot", "Screenshot will now begin on startup", ToolTipIcon.Info);
}
///<summary>
///Creates the contextmenu for the Icon
///<summary>
private static ContextMenu GetContextMenu()
{
string myPath = System.AppDomain.CurrentDomain.BaseDirectory.ToString();
System.Diagnostics.Process prc = new System.Diagnostics.Process();
prc.StartInfo.FileName = myPath;
ContextMenu menu = new ContextMenu();
menu.MenuItems.Add("Take Screenshot (Ctrl+F12)", delegate { TakeFullScreenShotAsync(); });
menu.MenuItems.Add("Open Folder", delegate { prc.Start(); });
menu.MenuItems.Add("Exit", delegate { System.Windows.Forms.Application.Exit(); });
menu.MenuItems.Add("Run On Startup", delegate { RunOnStartup(); });
return menu;
}
/// <summary>
/// Simple function that finds Registry and adds the Application to the startup
/// </summary>
private static void RunOnStartup()
{
RegistryKey reg = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
reg.SetValue("MyApp", Application.ExecutablePath.ToString());
BalloonTip2();
MessageBox.Show("The Program will now start on startup");
}
/// <summary>
/// Gets points for the screen uses those points to build a bitmap of the screen and saves it.
/// </summary>
private static async void TakeFullScreenShotAsync()
{
await Task.Delay(750);//Allows task to be waited on for .75ths of a second. Time In ms.
int width = Screen.PrimaryScreen.Bounds.Width;
int height = Screen.PrimaryScreen.Bounds.Height;
using (Bitmap screenshot = new Bitmap(width, height, PixelFormat.Format32bppArgb))
{
using (Graphics graphics = Graphics.FromImage(screenshot))
{
System.Drawing.Point origin = new System.Drawing.Point(0, 0);
System.Drawing.Size screenSize = Screen.PrimaryScreen.Bounds.Size;
//Copy Entire screen to entire bitmap.
graphics.CopyFromScreen(origin, origin, screenSize);
}
//Check to see if the file exists, if it does, append.
int append = 1;
while (File.Exists($"Screenshot{append}.jpg"))
append++;
string fileName = $"Screenshot{append}.jpg";
screenshot.Save(fileName, ImageFormat.Jpeg);
}
}
}
}
Check the image

You haven't called the BalloonTip() method in your TakeFullScreenShotAsync() method.
private static async void TakeFullScreenShotAsync()
{
await Task.Delay(750);//Allows task to be waited on for .75ths of a second. Time In ms.
int width = Screen.PrimaryScreen.Bounds.Width;
int height = Screen.PrimaryScreen.Bounds.Height;
using (Bitmap screenshot = new Bitmap(width, height, PixelFormat.Format32bppArgb))
{
using (Graphics graphics = Graphics.FromImage(screenshot))
{
System.Drawing.Point origin = new System.Drawing.Point(0, 0);
System.Drawing.Size screenSize = Screen.PrimaryScreen.Bounds.Size;
//Copy Entire screen to entire bitmap.
graphics.CopyFromScreen(origin, origin, screenSize);
}
//Check to see if the file exists, if it does, append.
int append = 1;
while (File.Exists($"Screenshot{append}.jpg"))
append++;
string fileName = $"Screenshot{append}.jpg";
screenshot.Save(fileName, ImageFormat.Jpeg);
// Call the Show Tip Message Here...
BalloonTip();
}
}
Line: hotKeyManager.Register(...) threw an error since I have a hotkey already registered hence I change it to something else that worked for me.

Related

How to set a hotkey to a Non-Form Program

Okay so I'm making this simple screenshot program using bitmaps and such, but when i try to make a hotkey like f12, for instance, nothing happens, i coded it just to show a message box, but it doesn't even do that. So i set it back to do both message box and take a screenshot but still doesn't work.
private static NotifyIcon notifyIcon;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
System.Windows.Forms.Application.EnableVisualStyles();
System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(false);
// We need to dispose here, or the icon will not remove until the
// system tray is updated.
System.Windows.Forms.Application.ApplicationExit += delegate
{
notifyIcon.Dispose();
};
CreateNotifyIcon();
System.Windows.Forms.Application.Run();
}
/// <summary>
/// Creates the icon that sits in the system tray.
/// </summary>
///
static void Program_KeyDown(object sender, KeyEventArgs e)
{
if(e.KeyCode == Keys.F12)
{
MessageBox.Show("ScreenShot Taken");
TakeFullScreenShot();
}
else if(e.KeyCode == Keys.F11)
{
Application.Exit();
}
}
private static void CreateNotifyIcon()
{
notifyIcon = new NotifyIcon
{
Icon = Resources.AppIcon, ContextMenu = GetContextMenu()
};
notifyIcon.Visible = true;
}
private static ContextMenu GetContextMenu()
{
string myPath = System.AppDomain.CurrentDomain.BaseDirectory.ToString();
System.Diagnostics.Process prc = new System.Diagnostics.Process();
prc.StartInfo.FileName = myPath;
ContextMenu menu = new ContextMenu();
menu.MenuItems.Add("Take Screenshot (F12)", delegate { TakeFullScreenShot(); });
menu.MenuItems.Add("Open Folder", delegate { prc.Start(); });
menu.MenuItems.Add("Exit", delegate { System.Windows.Forms.Application.Exit(); });
return menu;
}
private static void TakeFullScreenShot()
{
int width = Screen.PrimaryScreen.Bounds.Width;
int height = Screen.PrimaryScreen.Bounds.Height;
using (Bitmap screenshot = new Bitmap(width, height, PixelFormat.Format32bppArgb))
{
using (Graphics graphics = Graphics.FromImage(screenshot))
{
Point origin = new Point(0, 0);
Size screenSize = Screen.PrimaryScreen.Bounds.Size;
//Copy Entire screen to entire bitmap.
graphics.CopyFromScreen(origin, origin, screenSize);
}
//Check to see if the file exists, if it does, append.
int append = 1;
while (File.Exists($"Screenshot{append}.jpg"))
append++;
string fileName = $"Screenshot{append}.jpg";
screenshot.Save(fileName, ImageFormat.Jpeg);
}
}
You may not need all of that but its just to make sure i didn't mess anything up when trying to build it. Also, this program has no form to it, its just a icon in your taskbar, if you right click on it and click Take Screenshot(F12) It will take the screenshot with out problem. Thank you!
The hotkey will not work unless the program has focus. The Key events are only sent to your application when it has focus.

Send feedback/effect to joystick from .net

Thanks to this answer https://stackoverflow.com/a/13734766/637142 I am able to know when a button is pressed or when the steering wheel is rotated. Now my question is how do I send an effect to the device? For example when I am playing a game if I crash the wheel will vibrate. How could I make the steering wheel vibrate?
I belive what I need to do is to Start() an effect (http://sharpdx.org/documentation/api/t-sharpdx-directinput-effect). The SharpDX.DirectInput.Joystick class does not seem to have a method to return me all the effects. There is a method called GetEffects but that method returns a collection of EffectInfo objects. How does a game sends commands to the joystick?
The source code is copy-pasted from here.
To use this source you need a "Force Effect file" (C:\MyEffectFile.ffe), to "play" it on the joystick.
According to this book to create the "force effect" file you need to use the "Force Editor" that came with DirectX SDK.
(the same book, alternatively, state that you can create the effect from scratch in the code... down in the answer I've found another piece of code that create and use an effect without loading it from a file :-))
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using Microsoft.DirectX;
using Microsoft.DirectX.DirectInput;
namespace JoystickProject
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Label label1;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
private Device device = null;
private bool running = true;
private ArrayList effectList = new ArrayList();
private bool button0pressed = false;
private string joyState = "";
public bool InitializeInput()
{
// Create our joystick device
foreach(DeviceInstance di in Manager.GetDevices(DeviceClass.GameControl,
EnumDevicesFlags.AttachedOnly | EnumDevicesFlags.ForceFeeback))
{
// Pick the first attached joystick we see
device = new Device(di.InstanceGuid);
break;
}
if (device == null) // We couldn't find a joystick
return false;
device.SetDataFormat(DeviceDataFormat.Joystick);
device.SetCooperativeLevel(this, CooperativeLevelFlags.Exclusive | CooperativeLevelFlags.Background);
device.Properties.AxisModeAbsolute = true;
device.Properties.AutoCenter = false;
device.Acquire();
// Enumerate any axes
foreach(DeviceObjectInstance doi in device.Objects)
{
if ((doi.ObjectId & (int)DeviceObjectTypeFlags.Axis) != 0)
{
// We found an axis, set the range to a max of 10,000
device.Properties.SetRange(ParameterHow.ById,
doi.ObjectId, new InputRange(-5000, 5000));
}
}
// Load our feedback file
EffectList effects = null;
effects = device.GetEffects(#"C:\MyEffectFile.ffe",
FileEffectsFlags.ModifyIfNeeded);
foreach(FileEffect fe in effects)
{
EffectObject myEffect = new EffectObject(fe.EffectGuid, fe.EffectStruct,
device);
myEffect.Download();
effectList.Add(myEffect);
}
while(running)
{
UpdateInputState();
Application.DoEvents();
}
return true;
}
private void PlayEffects()
{
// See if our effects are playing.
foreach(EffectObject myEffect in effectList)
{
//if (button0pressed == true)
//{
//MessageBox.Show("Button Pressed.");
// myEffect.Start(1, EffectStartFlags.NoDownload);
//}
if (!myEffect.EffectStatus.Playing)
{
// If not, play them
myEffect.Start(1, EffectStartFlags.NoDownload);
}
}
//button0pressed = true;
}
protected override void OnClosed(EventArgs e)
{
running = false;
}
private void UpdateInputState()
{
PlayEffects();
// Check the joystick state
JoystickState state = device.CurrentJoystickState;
device.Poll();
joyState = "Using JoystickState: \r\n";
joyState += device.Properties.ProductName;
joyState += "\n";
joyState += device.ForceFeedbackState;
joyState += "\n";
joyState += state.ToString();
byte[] buttons = state.GetButtons();
for(int i = 0; i < buttons.Length; i++)
joyState += string.Format("Button {0} {1}\r\n", i, buttons[i] != 0 ? "Pressed" : "Not Pressed");
label1.Text = joyState;
//if(buttons[0] != 0)
//button0pressed = true;
}
public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.label1 = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// label1
//
this.label1.BackColor = System.Drawing.SystemColors.ActiveCaptionText;
this.label1.Location = new System.Drawing.Point(8, 8);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(272, 488);
this.label1.TabIndex = 0;
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.BackColor = System.Drawing.SystemColors.ControlText;
this.ClientSize = new System.Drawing.Size(288, 502);
this.Controls.AddRange(new System.Windows.Forms.Control[] {
this.label1});
this.Name = "Form1";
this.Text = "Joystick Stuff";
this.ResumeLayout(false);
}
#endregion
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
using (Form1 frm = new Form1())
{
frm.Show();
if (!frm.InitializeInput())
MessageBox.Show("Couldn't find a joystick.");
}
}
}
}
I've just found here another piece of code that maybe useful.
This sample seem to create the effect from scratch, so you shouldn't need an "effect file".
DeviceList xDeviceList = Manager.GetDevices(DeviceClass.GameControl, EnumDevicesFlags.AttachedOnly);
DeviceInstance someDeviceInstance;
foreach (DeviceInstance deviceInstance in xDeviceList)
{
someDeviceInstance = deviceInstance;
break;
}
Device someDevice = new Device(someDeviceInstance.InstanceGuid);
someDevice.SetCooperativeLevel(this.Handle, CooperativeLevelFlags.Exclusive | CooperativeLevelFlags.Background);
int[] axis = new int[0];
foreach (DeviceObjectInstance doi in someDevice.Objects)
{
if((doi.Flags & (int)ObjectInstanceFlags.Actuator) != 0)
{
axis = new int[axis.Length + 1];
axis[axis.Length - 1] = doi.Offset;
}
}
someDevice.Acquire();
Effect effect = new Effect();
effect.SetDirection(new int[axis.Length]);
effect.SetAxes(new int[axis.Length]);
effect.ConditionStruct = new Condition[axis.Length];
effect.Flags = EffectFlags.Cartesian | EffectFlags.ObjectOffsets;
effect.Duration = int.MaxValue;
effect.SamplePeriod = 0;
effect.Gain = 10000;
effect.TriggerButton = (int)Microsoft.DirectX.DirectInput.Button.NoTrigger;
effect.TriggerRepeatInterval = 0;
effect.UsesEnvelope = false;
effect.EffectType = Microsoft.DirectX.DirectInput.EffectType.ConstantForce;
effect.StartDelay = 0;
effect.Constant = new Microsoft.DirectX.DirectInput.ConstantForce();
effect.Constant.Magnitude = -5000;
EffectObject effectObject = null;
foreach (EffectInformation ei in someDevice.GetEffects(EffectType.ConstantForce))
{
effectObject = new EffectObject(ei.EffectGuid, effect, someDevice);
}
effectObject.SetParameters(effect, EffectParameterFlags.Start );
And here is another link then may be useful Force feedback sample

InvalidateRec with User32.dll , trying to delete all other frames except last frame created

Im actually trying to paint an elipse around my cursor when i moove it, I dont want it to leave a trail like it does actually.
Can someone help with this, I believe it has something to do with the invalidaterec option
Any example son using invalidate rec?
Here is my code, besides the trail it has to work the same way it does now.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace MouseTest
{
public partial class Form1 : Form
{
[DllImport("user32.dll", EntryPoint = "GetDC")]
private static extern IntPtr GetDC(IntPtr hWnd);
[DllImport("user32.dll", EntryPoint = "ReleaseDC")]
private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
[System.Runtime.InteropServices.DllImport("Shell32.dll")]
private static extern int SHChangeNotify(int eventId, int flags, IntPtr item1, IntPtr item2);
System.Timers.Timer t1 = new System.Timers.Timer(100);
public Form1()
{
t1.Elapsed += new System.Timers.ElapsedEventHandler(t1_Elapsed);
t1.Start();
// System.Windows.Forms.Cursor.Current = System.Windows.Forms.Cursors.WaitCursor;
//Mouse.OverrideCursor = System.Windows.Input.Cursors.Hand;
InitializeComponent();
}
void t1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
t1.Stop();
//SolidBrush b = new SolidBrush(Color.Red);
IntPtr desktopDC = GetDC(IntPtr.Zero);
Graphics g = Graphics.FromHdc(desktopDC);
g.FillEllipse(new SolidBrush(Color.BlueViolet), Cursor.Position.X, Cursor.Position.Y, 25, 25);
g.Dispose();
ReleaseDC(IntPtr.Zero, desktopDC);
t1.Start();
}
}
}
Yes, keeping the previous coordinate and calling InvalidateRect on the previous enclosing rectangle before drawing the new new ellipse would probably work. I don't have any code lying around that calls InvalidateRect, but if this is exactly your goal:" to paint an elipse around my cursor when i moove it, I dont want it to leave a trail like it does actually." there are other, more straight forward ways.
One way is to draw the ellipse on a transparent form and then move that form around based on the cursor's movement:
Here, first is the form definition:
namespace MouseForm
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.shapeContainer1 = new Microsoft.VisualBasic.PowerPacks.ShapeContainer();
this.ovalShape1 = new Microsoft.VisualBasic.PowerPacks.OvalShape();
this.timer1 = new System.Windows.Forms.Timer(this.components);
this.SuspendLayout();
//
// shapeContainer1
//
this.shapeContainer1.Location = new System.Drawing.Point(0, 0);
this.shapeContainer1.Margin = new System.Windows.Forms.Padding(0);
this.shapeContainer1.Name = "shapeContainer1";
this.shapeContainer1.Shapes.AddRange(new Microsoft.VisualBasic.PowerPacks.Shape[] {
this.ovalShape1});
this.shapeContainer1.Size = new System.Drawing.Size(74, 74);
this.shapeContainer1.TabIndex = 0;
this.shapeContainer1.TabStop = false;
//
// ovalShape1
//
this.ovalShape1.BorderColor = System.Drawing.Color.Red;
this.ovalShape1.BorderWidth = 3;
this.ovalShape1.FillColor = System.Drawing.SystemColors.Control;
this.ovalShape1.FillStyle = Microsoft.VisualBasic.PowerPacks.FillStyle.Solid;
this.ovalShape1.Location = new System.Drawing.Point(2, 2);
this.ovalShape1.Name = "ovalShape1";
this.ovalShape1.Size = new System.Drawing.Size(70, 70);
//
// timer1
//
this.timer1.Enabled = true;
this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(74, 74);
this.ControlBox = false;
this.Controls.Add(this.shapeContainer1);
this.Enabled = false;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.Name = "Form1";
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.Text = "Form1";
this.TopMost = true;
this.TransparencyKey = System.Drawing.SystemColors.Control;
this.ResumeLayout(false);
}
#endregion
private Microsoft.VisualBasic.PowerPacks.ShapeContainer shapeContainer1;
private Microsoft.VisualBasic.PowerPacks.OvalShape ovalShape1;
private System.Windows.Forms.Timer timer1;
}
}
And here is the code:
using System;
using System.Windows.Forms;
namespace MouseForm
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void timer1_Tick(object sender, EventArgs e)
{
this.Left = Cursor.Position.X - this.Width / 2;
this.Top = Cursor.Position.Y - this.Height / 2;
}
}
}
I'll leave it as an exercise to the reader to implement a way to close the transparent form :)

How to take a screenshot with Mono C#?

I'm trying to use use code get a screenshot in Mono C# but I'm getting a System.NotImplementedException when I call CopyFromScreen. My code works with .NET, so is there an alternate way of getting a screenshot using Mono?
Bitmap bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
Graphics graphics = Graphics.FromImage(bitmap as Image);
graphics.CopyFromScreen(0, 0, 0, 0, bitmap.Size);
System.IO.MemoryStream memoryStream = new System.IO.MemoryStream();
bitmap.Save(memoryStream, imageFormat);
bitmap.Save(#"\tmp\screenshot.png", ImageFormat.Png);
I am using Mono JIT compiler version 2.4.2.3 (Debian 2.4.2.3+dfsg-2)
UPDATE: Mono cannot take screenshots. Sad. Lame.
I guess an alternative would be using gtk# to get a screenshot. You would need to create a mono project with GTK# support, after that following code should execute:
Gdk.Window window = Gdk.Global.DefaultRootWindow;
if (window!=null)
{
Gdk.Pixbuf pixBuf = new Gdk.Pixbuf(Gdk.Colorspace.Rgb, false, 8,
window.Screen.Width, window.Screen.Height);
pixBuf.GetFromDrawable(window, Gdk.Colormap.System, 0, 0, 0, 0,
window.Screen.Width, window.Screen.Height);
pixBuf.ScaleSimple(400, 300, Gdk.InterpType.Bilinear);
pixBuf.Save("screenshot0.jpeg", "jpeg");
}
you could also use P\Invoke and call GTK functions directly.
hope this helps, regards
We had the same problem when we needed to take screenshots with Mono on Linux and OS X in the same software.
Actually, you can use CopyFromScreen on Mono on Linux. However you need to install mono-complete package, which includes System.Drawing.
For OS X the most reliable way is to Process.Start the screencapture command line tool. It is present there by default.
For Linux, to make it reliable, one can use either import command line from ImageMagic (you'll need to make it a dependency in this case), or force dependency on mono-complete package which includes System.Drawing. Gtk# approach is unreliable according to our tests and may provide blank screens or fail with exception (and we take thousands of screenshots on various machines every day).
Another thing is that when you need to capture multiple displays in one screenshot, you have to properly align separate screenshots after taking those separately via CopyFromScreen.
So we have this solution so far:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Windows.Forms;
namespace Pranas
{
/// <summary>
/// ScreenshotCapture
/// </summary>
public static class ScreenshotCapture
{
#region Public static methods
/// <summary>
/// Capture screenshot to Image object
/// </summary>
/// <param name="onlyPrimaryScreen">Create screen only from primary screen</param>
/// <returns></returns>
public static Image TakeScreenshot(bool onlyPrimaryScreen = false)
{
try
{
return WindowsCapture(onlyPrimaryScreen);
}
catch (Exception)
{
return OsXCapture(onlyPrimaryScreen);
}
}
#endregion
#region Private static methods
//private static Image ImageMagicCapture(bool onlyPrimaryScreen)
//{
// return ExecuteCaptureProcess("import", "-window root ");
//}
private static Image OsXCapture(bool onlyPrimaryScreen)
{
var data = ExecuteCaptureProcess(
"screencapture",
string.Format("{0} -T0 -tpng -S -x", onlyPrimaryScreen ? "-m" : ""));
return data;
}
/// <summary>
/// Start execute process with parameters
/// </summary>
/// <param name="execModule">Application name</param>
/// <param name="parameters">Command line parameters</param>
/// <returns>Bytes for destination image</returns>
private static Image ExecuteCaptureProcess(string execModule, string parameters)
{
var imageFileName = Path.Combine(Path.GetTempPath(), string.Format("screenshot_{0}.jpg", Guid.NewGuid()));
var process = Process.Start(execModule, string.Format("{0} {1}", parameters, imageFileName));
if (process == null)
{
throw new InvalidOperationException(string.Format("Executable of '{0}' was not found", execModule));
}
process.WaitForExit();
if (!File.Exists(imageFileName))
{
throw new InvalidOperationException(string.Format("Failed to capture screenshot using {0}", execModule));
}
try
{
return Image.FromFile(imageFileName);
}
finally
{
File.Delete(imageFileName);
}
}
/// <summary>
/// Capture screenshot with .NET standard implementation
/// </summary>
/// <param name="onlyPrimaryScreen"></param>
/// <returns>Return bytes of screenshot image</returns>
private static Image WindowsCapture(bool onlyPrimaryScreen)
{
if (onlyPrimaryScreen) return ScreenCapture(Screen.PrimaryScreen);
var bitmaps = (Screen.AllScreens.OrderBy(s => s.Bounds.Left).Select(ScreenCapture)).ToArray();
return CombineBitmap(bitmaps);
}
/// <summary>
/// Create screenshot of single display
/// </summary>
/// <param name="screen"></param>
/// <returns></returns>
private static Bitmap ScreenCapture(Screen screen)
{
var bitmap = new Bitmap(screen.Bounds.Width, screen.Bounds.Height, PixelFormat.Format32bppArgb);
using (var graphics = Graphics.FromImage(bitmap))
{
graphics.CopyFromScreen(
screen.Bounds.X,
screen.Bounds.Y,
0,
0,
screen.Bounds.Size,
CopyPixelOperation.SourceCopy);
}
return bitmap;
}
/// <summary>
/// Combine images into one bitmap
/// </summary>
/// <param name="images"></param>
/// <returns>Combined image</returns>
private static Image CombineBitmap(ICollection<Image> images)
{
Image finalImage = null;
try
{
var width = 0;
var height = 0;
foreach (var image in images)
{
width += image.Width;
height = image.Height > height ? image.Height : height;
}
finalImage = new Bitmap(width, height);
using (var g = Graphics.FromImage(finalImage))
{
g.Clear(Color.Black);
var offset = 0;
foreach (var image in images)
{
g.DrawImage(image,
new Rectangle(offset, 0, image.Width, image.Height));
offset += image.Width;
}
}
}
catch (Exception ex)
{
if (finalImage != null)
finalImage.Dispose();
throw ex;
}
finally
{
//clean up memory
foreach (var image in images)
{
image.Dispose();
}
}
return finalImage;
}
#endregion
}
}
Or install it via NuGet (disclaimer: I'm the author):
PM> Install-Package Pranas.ScreenshotCapture
We use it heavily in our product on many setups, so we periodically improve the code and put notes into blog.
With Mono 2.4.4 you can get the whole screen without GTK#:
public static class MonoScreenShooter
{
public static void TakeScreenshot(string filePath)
{
using (Bitmap bmpScreenCapture = new Bitmap(Screen.PrimaryScreen.Bounds.Width,
Screen.PrimaryScreen.Bounds.Height))
{
using (Graphics g = Graphics.FromImage(bmpScreenCapture))
{
g.CopyFromScreen(Screen.PrimaryScreen.Bounds.X,
Screen.PrimaryScreen.Bounds.Y,
0, 0,
bmpScreenCapture.Size,
CopyPixelOperation.SourceCopy);
}
bmpScreenCapture.Save(filePath, System.Drawing.Imaging.ImageFormat.Jpeg);
}
}
}
}

What's the correct way to use controls in Owner drawn list box?

I am experimenting with owner drawn list box. I am adding a text box to a specific item within list box. However, when I start scrolling, the text box does not display in the right location. What is the right way to do this?
Here's the code I am using.
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.Windows.Forms;
using System.Diagnostics;
namespace ListBoxControlScrollIssue
{
public partial class Form1 : Form
{
private const Int32 cellHeight = 40;
private ListBox listBox1;
private Font displayFont = new Font(FontFamily.GenericSerif, 8, FontStyle.Regular);
private Brush displayBrush = Brushes.Black;
private Pen displayPen = Pens.Black;
private Button separateDebug;
private TextBox item3Text;
public Form1()
{
SetupListBox();
}
private void SetupListBox()
{
this.listBox1 = new System.Windows.Forms.ListBox();
this.SuspendLayout();
//
// listBox1
//
this.listBox1.FormattingEnabled = true;
this.listBox1.Location = new System.Drawing.Point(40, 40);
this.listBox1.Name = "listBox1";
this.listBox1.Size = new System.Drawing.Size(300, 100);
this.listBox1.TabIndex = 0;
this.listBox1.DrawMode = DrawMode.OwnerDrawVariable;
this.listBox1.MeasureItem += new MeasureItemEventHandler(listBox1_MeasureItem);
this.listBox1.DrawItem += new DrawItemEventHandler(listBox1_DrawItem);
//
// Add items to list box.
//
this.listBox1.Items.Add("Item0");
this.listBox1.Items.Add("Item1");
this.listBox1.Items.Add("Item2");
this.listBox1.Items.Add("Item3");
this.listBox1.Items.Add("Item4");
//
// Add button.
//
separateDebug = new Button();
separateDebug.Name = "SeperateDebug";
separateDebug.Text = "Seperator";
separateDebug.Location = new Point(400, 100);
separateDebug.Click += new EventHandler(separateDebug_Click);
//
// Create the text box. However, don't add it to anything.
//
item3Text = new TextBox();
item3Text.Name = "item3Text";
item3Text.Multiline = false;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(525, 421);
this.Controls.Add(this.listBox1);
this.Controls.Add(this.separateDebug);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
}
void separateDebug_Click(object sender, EventArgs e)
{
Debug.Print("\n=========================\n");
}
void listBox1_DrawItem(object sender, DrawItemEventArgs e)
{
PointF displayLocation = new PointF(20, e.Index * cellHeight + 3);
//
// Display text names of the items here.
//
//
Debug.Print("DrawItem:: Index = {0}, location = {1}", e.Index, displayLocation);
e.Graphics.DrawString(this.listBox1.Items[e.Index].ToString(), displayFont, displayBrush, e.Bounds);
//
// Draw rectangle around the border to show boundary of cell.
//
e.Graphics.DrawRectangle(displayPen, e.Bounds);
}
void listBox1_MeasureItem(object sender, MeasureItemEventArgs e)
{
e.ItemHeight = cellHeight;
e.ItemWidth = this.listBox1.Width;
if (e.Index == 3)
{
//
// Set the location of item3Text to the location of bounds.
//
item3Text.Location = new Point(21, e.Index * cellHeight + 21);
listBox1.Controls.Add(item3Text);
}
}
}
}
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace ListBoxControlScrollIssue
{
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());
}
}
}
Form.Designer.cs
namespace ListBoxControlScrollIssue
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
}
#endregion
}
}
Edit I re-wrote my answer in order to be clearer.
The ListBox below displays a TextBox with along its SelectedItem.
GetItemRectangle(int index)
is used to retrieve an item's current location in the ListBox. It seems to be the key method you're looking for.
public class ListBoxEx : ListBox
{
public ListBoxEx()
{
TextBox.Visible = false;
Controls.Add(TextBox);
}
private readonly Size TextBoxOffset = new Size(16, 16);
private const Int32 CellHeight = 40;
private readonly TextBox TextBox = new TextBox();
protected override void OnSelectedIndexChanged(EventArgs e)
{
base.OnSelectedIndexChanged(e);
TextBox.Visible = SelectedIndex != -1;
}
protected override void OnDrawItem(DrawItemEventArgs e)
{
base.OnDrawItem(e);
// Somehow necessary
e.Graphics.FillRectangle(new SolidBrush(BackColor), e.Bounds);
// Drawing the item's text
e.Graphics.DrawString(Items[e.Index].ToString(), Font, new SolidBrush(ForeColor), e.Bounds);
// Drawing the item's borders
e.Graphics.DrawRectangle(new Pen(ForeColor), e.Bounds);
// Drawing updating the TextBox location
if (SelectedIndex != -1)
TextBox.Location = Point.Add(GetItemRectangle(SelectedIndex).Location, TextBoxOffset);
// Because clicking the scrollbar sometimes cause the ListBox to hide the TextBox
TextBox.BringToFront();
// Making sure the TextBox is redrawn ASAP
TextBox.Invalidate();
}
protected override void OnMeasureItem(MeasureItemEventArgs e)
{
base.OnMeasureItem(e);
e.ItemHeight = CellHeight;
}
}

Categories