Showing posts with label Win32. Show all posts
Showing posts with label Win32. Show all posts

Monday, August 16, 2010

Windows Console progress bar

For pure nostalgic reasons I was looking into some old code. It is a console application, to tweak the UI (or lack of same) I wanted to provide a progress bar in the console window.



Client code for the screenshot above


using System;
using TMData.Console;
using System.Threading;

namespace ConsoleApplication
{
 /// <summary>
 /// Summary description for Class1.
 /// </summary>
 class Class1
 {
  /// <summary>
  /// The main entry point for the application.
  /// </summary>
  [STAThread]
  static void Main(string[] args)
  {
   // Where in the console should the progress bar be located
   ConsoleCoordinate consoleCoordinate = new ConsoleCoordinate(10,2);

   // Instantiate the progress bar
   ConsoleProgressBar consoleProgressBar = new ConsoleProgressBar(StandardHandle.Output, 0, 120, 50, consoleCoordinate);

   int x = 0;
   while (x < 120)
   {
    consoleProgressBar.ShowProgressInPercent(x);
    x++;
    Thread.Sleep(100);
   }
  }
 }
}

Helper classes and structs


using System;
using System.Runtime.InteropServices;

namespace TMData.Console
{
 /// <summary>
 /// Summary description for ConsoleCoordinate.
 /// </summary>
 [StructLayout(LayoutKind.Sequential)]
 public struct ConsoleCoordinate
 {
  private short _x;
  private short _y;

  public ConsoleCoordinate(short x, short y)
  {
   _x = x;
   _y = y;
  }
 }
}

using System;

namespace TMData.Console
{
 public enum StandardHandle
 {
  Input = -10,
  Output = -11,
  Error = -12
 }
}

And finally the main console progress class


using System;
using System.Runtime.InteropServices; 


namespace TMData.Console
{
 /// <summary>
 /// Summary description for ConsoleProgressBar.
 /// </summary>
 public class ConsoleProgressBar
 {
  private float minimumValue = 0;
  private float maximumValue = 0;
  private IntPtr handle;
  private ConsoleCoordinate consoleCoordinate;
  private int progressBarSize = 50;

  public ConsoleProgressBar(StandardHandle handle, int minimumValue, int maximumValue, int progressBarSize, ConsoleCoordinate consoleCoordinate)
  {
   this.handle = GetStdHandle((int)handle);;
   this.minimumValue = (float)minimumValue;
   this.maximumValue = (float)maximumValue;
   this.consoleCoordinate = consoleCoordinate;
  }
  
  public void ShowProgressInPercent (int currentValue)
  {
   int percentComplete =  Convert.ToInt32((currentValue / maximumValue) * 100);
   ShowProgress(percentComplete, percentComplete, "%", "100");
  }

  private void ShowProgress(int currentValue, int percentComplete, string unitIndicator, string maxDisplayValue)
  {
   // Calculations
   int incrementPercent = (int)100.0 / progressBarSize;
   int completeLength = Convert.ToInt32(percentComplete / incrementPercent);

   // Constructing the full string making up the progressbar
   string statusText = currentValue.ToString().PadLeft(maxDisplayValue.Length, ' ') + unitIndicator + " / " + maxDisplayValue + unitIndicator;
   int startPosOfStatusTextInProgressBar = (int)((float)progressBarSize / 2.0 - (int)(statusText.Length / 2.0 ));
   statusText = statusText.PadLeft(startPosOfStatusTextInProgressBar + statusText.Length, ' ');
   statusText = statusText.PadRight(progressBarSize,' ');
   
   // Preparing the completed/incomplete progressbar text string
   string completeText = statusText.Substring(0, completeLength);
   string incompleteText = statusText.Substring(completeText.Length, statusText.Length - completeText.Length);
   bool bResult = SetConsoleCursorPosition(handle, consoleCoordinate);

   // Printing to console and coloring
   SetConsoleTextAttribute(handle, 31);
   System.Console.Write(completeText);
   SetConsoleTextAttribute(handle, 127);
   System.Console.Write(incompleteText);
  }

  #region DllImports
  [DllImport("kernel32.dll")]
  public static extern IntPtr GetStdHandle(int intHandleType);

  [DllImport("kernel32.dll")]
  public static extern bool SetConsoleTextAttribute(IntPtr handle, int wAttributes);

  [DllImport("kernel32.dll", SetLastError=true)]
  public static extern bool SetConsoleCursorPosition(IntPtr handle, ConsoleCoordinate inCoordCharacterAttributes);
  #endregion
 }
}

Sunday, August 15, 2010

C# Round WinForms Helper

While figuring out what values were needed for the call to CreateRoundRectRgn for my tab in the previous post, C# Round WinForms Helper I made this small helper application. 


The source code can be downloaded here RoundedCorners.zip.

It allows you to use the levers to figure out the needed values of the different parameters based on what size the round form is.

Main.cs


using System;
using System.Drawing;
using System.Windows.Forms;

namespace TMData.RoundedCorners
{
 public partial class Main : Form
 {
  private RoundedCorners roundForm;
  public Main()
  {
   InitializeComponent();
  }

  private void timer1_Tick(object sender, EventArgs e)
  {
   formHeightTextBox.Text = roundForm.Height.ToString();
   formWidthTextBox.Text = roundForm.Width.ToString();

   label2.Text = trackBar2.Value.ToString();
   label3.Text = trackBar3.Value.ToString();
   label4.Text = trackBar4.Value.ToString();
   label5.Text = trackBar5.Value.ToString();
   label6.Text = trackBar6.Value.ToString();
   label7.Text = trackBar7.Value.ToString();

   roundForm.Region = Region.FromHrgn(Win32.CreateRoundRectRgn(trackBar2.Value, trackBar3.Value, trackBar4.Value, trackBar5.Value, trackBar6.Value, trackBar7.Value));
   generatedStatmentTextBox.Text = string.Format("CreateRoundRectRgn({0},{1},{2},{3},{4},{5})",trackBar2.Value, trackBar3.Value, trackBar4.Value, trackBar5.Value, trackBar6.Value, trackBar7.Value);
  }
  
  private void RoundedCorners_Load(object sender, EventArgs e)
  {
   roundForm = new RoundedCorners(this);
   roundForm.Show();
   roundForm.UpdateParentTrackBars();
   timer1.Start();
  }
 }
}


RoundedCorners.cs

using System;
using System.Windows.Forms;

namespace TMData.RoundedCorners
{
 public partial class RoundedCorners : Form
 {
  private Main parentForm;
  public RoundedCorners()
  {
   InitializeComponent();
  }

  public RoundedCorners(Main parentForm) : this()
  {
   this.parentForm = parentForm;
  }

  private void RoundedCorners_SizeChanged(object sender, EventArgs e)
  {
   UpdateParentTrackBars();
  }
  public void UpdateParentTrackBars()
  {
   parentForm.trackBar2.Maximum = Width;
   parentForm.trackBar4.Maximum = Width;
   parentForm.trackBar4.Value = Width;
   parentForm.trackBar3.Maximum = Height;
   parentForm.trackBar3.Value = Height;
   parentForm.trackBar5.Maximum = Height;
   parentForm.trackBar6.Maximum = Width;
   parentForm.trackBar7.Maximum = Height;
  }
 }
}


And Wins32.cs

using System;
using System.Runtime.InteropServices;

namespace TMData.RoundedCorners
{ 

 class Win32
 {
  /// <summary>
  /// Creates the round rect RGN.
  /// </summary>
  /// <param name="nLeftRect">The n left rect.</param>
  /// <param name="nTopRect">The n top rect.</param>
  /// <param name="nRightRect">The n right rect.</param>
  /// <param name="nBottomRect">The n bottom rect.</param>
  /// <param name="nWidthEllipse">The n width ellipse.</param>
  /// <param name="nHeightEllipse">The n height ellipse.</param>
  /// <returns></returns>
  [DllImport("Gdi32.dll", EntryPoint = "CreateRoundRectRgn")]
  public static extern IntPtr CreateRoundRectRgn
  (
   int nLeftRect,
   int nTopRect, // y-coordinate of upper-left corner
   int nRightRect, // x-coordinate of lower-right corner
   int nBottomRect, // y-coordinate of lower-right corner
   int nWidthEllipse, // height of ellipse
   int nHeightEllipse // width of ellipse
  );
 }
} 


Since each winform runs in a thread there should ideally be some syncronization rather than allowing the RoundedCorners form access to the Main form's controls, However since the point of this application was as to illustrate the use of CreateRoundRectRgn() I will leave it as is.

C# .NET Active Windows Size Helper

I have several times found myself with a need to easily get window size information in windows. And I wanted the information available in a nice rounded tab associated with the currently active window. As the astute reader will point out is that every thing about doing this is indeed really simple the only challenge is to get the rounded corners on a windows form.

This proved to be much easier than expected.

The final result looks like this. The source code can be downloaded here WindowsSize.zip.


Here below we can find the main relevant parts of the code.
private void Form1_Load(object sender, EventArgs e)
{
 timer1.Start();
 this.Region = Region.FromHrgn(Win32.CreateRoundRectRgn(0, 0, 80, 80, 80, 23));
 ShowInTaskbar = false;
 this.Width = 80;
 this.Height = 23;
}

private void timer1_Tick(object sender, EventArgs e)
{
 const int nChars = 256;
 WINDOWINFO info = new WINDOWINFO();
 StringBuilder buffer = new StringBuilder(nChars);

 info.cbSize = (uint)Marshal.SizeOf(info);

 IntPtr activeWindowHandle = Win32.GetForegroundWindow();
 Win32.GetWindowInfo(activeWindowHandle, ref info);

 // Move this windows to front
 this.BringWindowToFront();

 // We need to get the current window to make sure that we are not trying to set the position of
 // our own window based on out own size then the windows will be moving over the screen
 if (this.Handle != activeWindowHandle)
 {
  this.Top = info.rcWindow.Top - this.Height;
  this.Left = info.rcWindow.Left + 10;

  int width = info.rcWindow.Right - info.rcWindow.Left;
  int height = info.rcWindow.Bottom - info.rcWindow.Top;
  lblWindowSize.Text = string.Format(&quot;{0} x {1}&quot;, width.ToString(), height.ToString());
 }
}

/// &lt;summary&gt;
/// Brings the window to front.
/// &lt;/summary&gt;
private void BringWindowToFront()
{
 this.TopMost = true;
 this.Focus();
 this.BringToFront();
 this.TopMost = false;
}

And the relevant win32 api code
public struct RECT
{
 public int Left;       // Specifies the x-coordinate of the upper-left corner of the rectangle.
 public int Top;        // Specifies the y-coordinate of the upper-left corner of the rectangle.
 public int Right;      // Specifies the x-coordinate of the lower-right corner of the rectangle.
 public int Bottom;     // Specifies the y-coordinate of the lower-right corner of the rectangle.

}

[StructLayout(LayoutKind.Sequential)]
public struct WINDOWINFO
{
 public uint cbSize;
 public RECT rcWindow;
 public RECT rcClient;
 public uint dwStyle;
 public uint dwExStyle;
 public uint dwWindowStatus;
 public uint cxWindowBorders;
 public uint cyWindowBorders;
 public ushort atomWindowType;
 public ushort wCreatorVersion;

 public WINDOWINFO(Boolean? filler)
  : this()   // Allows automatic initialization of "cbSize" with "new WINDOWINFO(null/true/false)".
 {
  cbSize = (UInt32)(Marshal.SizeOf(typeof(WINDOWINFO)));
 }

}

class Win32
{
 /// <summary>
 /// Gets the foreground window.
 /// </summary>
 /// <returns></returns>
 [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
 public static extern IntPtr GetForegroundWindow();

 /// <summary>
 /// Gets the window info.
 /// </summary>
 /// <param name="hwnd">The HWND.</param>
 /// <param name="pwi">The pwi.</param>
 /// <returns></returns>
 [return: MarshalAs(UnmanagedType.Bool)]
 [DllImport("user32.dll", SetLastError = true)]
 public static extern bool GetWindowInfo(IntPtr hwnd, ref WINDOWINFO pwi);

 /// <summary>
 /// Gets the window text.
 /// </summary>
 /// <param name="hWnd">The h WND.</param>
 /// <param name="text">The text.</param>
 /// <param name="count">The count.</param>
 /// <returns></returns>
 [DllImport("user32.dll")]
 public static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);

 /// <summary>
 /// Creates the round rect RGN.
 /// </summary>
 /// <param name="nLeftRect">The n left rect.</param>
 /// <param name="nTopRect">The n top rect.</param>
 /// <param name="nRightRect">The n right rect.</param>
 /// <param name="nBottomRect">The n bottom rect.</param>
 /// <param name="nWidthEllipse">The n width ellipse.</param>
 /// <param name="nHeightEllipse">The n height ellipse.</param>
 /// <returns></returns>
 [DllImport("Gdi32.dll", EntryPoint = "CreateRoundRectRgn")]
 public static extern IntPtr CreateRoundRectRgn
 (
  int nLeftRect,
  int nTopRect, // y-coordinate of upper-left corner
  int nRightRect, // x-coordinate of lower-right corner
  int nBottomRect, // y-coordinate of lower-right corner
  int nWidthEllipse, // height of ellipse
  int nHeightEllipse // width of ellipse
 );
}