Retrieve color of windows 10 taskbar - c#

I found out, that there is a static property in the System.Windows.SystemParameters class that declares the color the user chose for his Windows overall.
But there is a second possibility for the user that enables him to enable or disable, whether the taskbar/windows bar should use that same color.
I was unable to find a key for that in the SystemParameters-class.

I believe there is a registry value to find the colour and it is probably inside:
HKEY_CURRENT_USER\Control Panel\Colors
However on my system I have colours on the taskbar disabled and that colour value doesn't seem to appear in this key.
A work around would be to combine the answers to the following two questions:
TaskBar Location
How to Read the Colour of a Screen Pixel
You need the following imports:
[DllImport("shell32.dll")]
private static extern IntPtr SHAppBarMessage(int msg, ref APPBARDATA data);
[DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
private static extern int BitBlt(IntPtr hDC, int x, int y, int nWidth, int nHeight, IntPtr hSrcDC, int xSrc, int ySrc, int dwRop);
The following structs:
private struct APPBARDATA
{
public int cbSize;
public IntPtr hWnd;
public int uCallbackMessage;
public int uEdge;
public RECT rc;
public IntPtr lParam;
}
private struct RECT
{
public int left, top, right, bottom;
}
And the following constant:
private const int ABM_GETTASKBARPOS = 5;
Then you can call the following two methods:
public static Rectangle GetTaskbarPosition()
{
APPBARDATA data = new APPBARDATA();
data.cbSize = Marshal.SizeOf(data);
IntPtr retval = SHAppBarMessage(ABM_GETTASKBARPOS, ref data);
if (retval == IntPtr.Zero)
{
throw new Win32Exception("Please re-install Windows");
}
return new Rectangle(data.rc.left, data.rc.top, data.rc.right - data.rc.left, data.rc.bottom - data.rc.top);
}
public static Color GetColourAt(Point location)
{
using (Bitmap screenPixel = new Bitmap(1, 1, PixelFormat.Format32bppArgb))
using (Graphics gdest = Graphics.FromImage(screenPixel))
{
using (Graphics gsrc = Graphics.FromHwnd(IntPtr.Zero))
{
IntPtr hSrcDC = gsrc.GetHdc();
IntPtr hDC = gdest.GetHdc();
int retval = BitBlt(hDC, 0, 0, 1, 1, hSrcDC, location.X, location.Y, (int)CopyPixelOperation.SourceCopy);
gdest.ReleaseHdc();
gsrc.ReleaseHdc();
}
return screenPixel.GetPixel(0, 0);
}
}
Like this:
Color taskBarColour = GetColourAt(GetTaskbarPosition().Location);

Related

How does one create text that can overlay all windows like the Windows Activation Watermark?

I would like to create a count down timer that displays in the lower right hand of the screen with slightly transparent text that can be seen no matter what you have on the screen. Think of something like the windows not activated watermark message that appears when your windows copy isn't activated. That displays in the lower right overlaying all windows and is "stuck" to the screen.
Is there a way to do this via a program? C# preferred.
In my research so far I only came across Deskbands which allow you to put something in the task bar but not outside of it.
Note: The following answer creates a normal semi-transparent topmost form with smooth edge. It's not exactly like windows activation text, for example it goes behind tooltip windows or goes behind menus, but it stays on top of other non-topmost windows.
You can create a Layered Window by setting WS_EX_LAYERED style, then you can assign a smooth-edge transparent region to the window. You can also set WS_EX_TRANSPARENT for the window, then it will ignore the mouse event. Then to make it always on top set its TopMost to true. And finally if you want to make it semi-transparent use suitable Opacity value.
Example
In the following example, I've created an overlay form which is always on top and shows time:
1 - Add the following class which contains required native methods to your project:
using System;
using System.Runtime.InteropServices;
public class NativeMethods
{
public const int WS_EX_LAYERED = 0x80000;
public const int HTCAPTION = 0x02;
public const int WM_NCHITTEST = 0x84;
public const int ULW_ALPHA = 0x02;
public const byte AC_SRC_OVER = 0x00;
public const byte AC_SRC_ALPHA = 0x01;
public const int WS_EX_TRANSPARENT = 0x20;
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int x;
public int y;
public POINT(int x, int y)
{ this.x = x; this.y = y; }
}
[StructLayout(LayoutKind.Sequential)]
public struct SIZE
{
public int cx;
public int cy;
public SIZE(int cx, int cy)
{ this.cx = cx; this.cy = cy; }
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct BLENDFUNCTION
{
public byte BlendOp;
public byte BlendFlags;
public byte SourceConstantAlpha;
public byte AlphaFormat;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst,
ref POINT pptDst, ref SIZE psize, IntPtr hdcSrc, ref POINT pprSrc,
int crKey, ref BLENDFUNCTION pblend, int dwFlags);
[DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CreateCompatibleDC(IntPtr hDC);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetDC(IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
[DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DeleteDC(IntPtr hdc);
[DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);
[DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DeleteObject(IntPtr hObject);
}
2 - Add the following class which is a base class for semi-transparent smooth-edge windows forms:
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Imaging;
using static NativeMethods;
public class PerPixelAlphaForm : Form
{
public PerPixelAlphaForm()
{
this.FormBorderStyle = FormBorderStyle.None;
this.ShowInTaskbar = false;
this.TopMost = true;
}
protected override CreateParams CreateParams
{
get
{
CreateParams createParams = base.CreateParams;
if (!DesignMode)
createParams.ExStyle |= WS_EX_LAYERED | WS_EX_TRANSPARENT;
return createParams;
}
}
public void SelectBitmap(Bitmap bitmap, int opacity = 255)
{
if (bitmap.PixelFormat != PixelFormat.Format32bppArgb)
{
throw new ApplicationException(
"The bitmap must be 32bpp with alpha-channel.");
}
IntPtr screenDc = GetDC(IntPtr.Zero);
IntPtr memDc = CreateCompatibleDC(screenDc);
IntPtr hBitmap = IntPtr.Zero;
IntPtr hOldBitmap = IntPtr.Zero;
try
{
hBitmap = bitmap.GetHbitmap(Color.FromArgb(0));
hOldBitmap = SelectObject(memDc, hBitmap);
SIZE newSize = new SIZE(bitmap.Width, bitmap.Height);
POINT sourceLocation = new POINT(0, 0);
POINT newLocation = new POINT(this.Left, this.Top);
BLENDFUNCTION blend = new BLENDFUNCTION();
blend.BlendOp = AC_SRC_OVER;
blend.BlendFlags = 0;
blend.SourceConstantAlpha = (byte)opacity;
blend.AlphaFormat = AC_SRC_ALPHA;
UpdateLayeredWindow(this.Handle, screenDc, ref newLocation,
ref newSize, memDc, ref sourceLocation, 0, ref blend, ULW_ALPHA);
}
finally
{
ReleaseDC(IntPtr.Zero, screenDc);
if (hBitmap != IntPtr.Zero)
{
SelectObject(memDc, hOldBitmap);
DeleteObject(hBitmap);
}
DeleteDC(memDc);
}
}
}
3 - Then add the following class which is a form, having a timer that shows time:
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Drawing.Text;
using System.Windows.Forms;
public partial class Form1 : PerPixelAlphaForm
{
private IContainer components = null;
private Timer timer1;
private Bitmap image;
public Form1()
{
this.components = new Container();
this.timer1 = new Timer(this.components);
this.timer1.Enabled = true;
this.timer1.Interval = 500;
this.timer1.Tick += new EventHandler(this.timer1_Tick);
this.StartPosition = FormStartPosition.Manual;
this.Location = new Point(300, 300);
this.Size = new Size(800, 500);
this.image = new Bitmap(Width, Height, PixelFormat.Format32bppArgb);
}
private void timer1_Tick(object sender, EventArgs e)
{
using (var g = Graphics.FromImage(image))
{
g.Clear(Color.Transparent);
g.SmoothingMode = SmoothingMode.AntiAlias;
g.TextRenderingHint = TextRenderingHint.AntiAlias;
g.DrawString(DateTime.Now.ToString("HH:mm:ss"),
new Font(this.Font.FontFamily, 60, FontStyle.Bold), Brushes.Black,
ClientRectangle, StringFormat.GenericDefault);
SelectBitmap(image, 150);
}
}
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
components.Dispose();
if (disposing && image != null)
image.Dispose();
base.Dispose(disposing);
}
}
You can find more information in the following posts:
Windows Forms: Pass clicks through a partially transparent always-on-top window
Transparent background image for Form - Smooth edge shape for the Form

Remove space left after console scrollbars in C#

I'm making a console game in C# in Visual Studio and I want to make the game to be in the full console window.
I resized the buffer and window to be the same size, but it looks like the space after the scrollbars remained, which will probably be really annoying to look at. I wonder if there's any way to remove that blank space in C#, or at least add grayed-out scrollbars. I saw a similar thread, but it was in C++.
Here's a reproducible example:
using Microsoft.Win32.SafeHandles;
using System;
using System.IO;
using System.Runtime.InteropServices;
namespace ConsoleTest1
{
class Program
{
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern SafeFileHandle CreateFile(
string fileName,
[MarshalAs(UnmanagedType.U4)] uint fileAccess,
[MarshalAs(UnmanagedType.U4)] uint fileShare,
IntPtr securityAttributes,
[MarshalAs(UnmanagedType.U4)] FileMode creationDisposition,
[MarshalAs(UnmanagedType.U4)] int flags,
IntPtr template);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool WriteConsoleOutput(
SafeFileHandle hConsoleOutput,
CharInfo[] lpBuffer,
Coord dwBufferSize,
Coord dwBufferCoord,
ref SmallRect lpWriteRegion);
[StructLayout(LayoutKind.Sequential)]
public struct Coord
{
public short X, Y;
public Coord(short x, short y)
{
X = x;
Y = y;
}
}
[StructLayout(LayoutKind.Explicit)]
public struct CharUnion
{
[FieldOffset(0)] public char UnicodeChar;
[FieldOffset(0)] public byte AsciiChar;
}
[StructLayout(LayoutKind.Explicit)]
public struct CharInfo
{
[FieldOffset(0)] public CharUnion Char;
[FieldOffset(2)] public short Attributes;
}
[StructLayout(LayoutKind.Sequential)]
public struct SmallRect
{
public short Left, Top, Right, Bottom;
public SmallRect(short width, short height)
{
Left = Top = 0;
Right = width;
Bottom = height;
}
}
[STAThread]
static void Main(string[] args)
{
short width = 50, height = 20;
SafeFileHandle handle = CreateFile("CONOUT$", 0x40000000, 2, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero);
CharInfo[] buffer = new CharInfo[width * height];
SmallRect writeRegion = new SmallRect(width, height);
Console.SetWindowSize(width, height);
Console.SetBufferSize(width, height);
for (int i = 0; i < buffer.Length; ++i)
{
buffer[i].Attributes = 0xb0;
buffer[i].Char.UnicodeChar = ' ';
}
WriteConsoleOutput(handle, buffer, new Coord(width, height), new Coord(0, 0), ref writeRegion);
Console.ReadKey();
}
}
}
I don't really know how to do this or even if it's possible to remove the black space in this language.
Finally, after a lot of head-scratching, I think I've solved this issue. Firstly, I had to add some additional WinAPI methods:
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr GetStdHandle(int nStdHandle);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool GetConsoleScreenBufferInfoEx(
IntPtr hConsoleOutput,
ref ConsoleScreenBufferInfoEx ConsoleScreenBufferInfo);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool SetConsoleScreenBufferInfoEx(
IntPtr hConsoleOutput,
ref ConsoleScreenBufferInfoEx ConsoleScreenBufferInfoEx);
and structs:
[StructLayout(LayoutKind.Sequential)]
private struct ConsoleScreenBufferInfoEx
{
public uint cbSize;
public Coord dwSize;
public Coord dwCursorPosition;
public short wAttributes;
public SmallRect srWindow;
public Coord dwMaximumWindowSize;
public ushort wPopupAttributes;
public bool bFullscreenSupported;
public Colorref black, darkBlue, darkGreen, darkCyan, darkRed, darkMagenta, darkYellow, gray, darkGray, blue, green, cyan, red, magenta, yellow, white;
}
[StructLayout(LayoutKind.Sequential)]
private struct Colorref
{
public uint ColorDWORD;
}
After that, it was time to modify the part where the buffer and window were resized:
Console.SetWindowSize(width - 2, height);
Console.SetBufferSize(width, height);
IntPtr stdHandle = GetStdHandle(-11);
ConsoleScreenBufferInfoEx bufferInfo = new ConsoleScreenBufferInfoEx();
bufferInfo.cbSize = (uint)Marshal.SizeOf(bufferInfo);
GetConsoleScreenBufferInfoEx(stdHandle, ref bufferInfo);
++bufferInfo.srWindow.Right;
++bufferInfo.srWindow.Bottom;
SetConsoleScreenBufferInfoEx(stdHandle, ref bufferInfo);
And that's it! No more ugly black space (at least on my computer, haven't tested it on other Windows versions).

DwmGetWindowAttribute doesn't get the correct Rect size for MediaPlayer if it's in full screen mode

I am trying to get application size using this code :
[DllImport(#"dwmapi.dll")]
private static extern int DwmGetWindowAttribute(IntPtr hwnd, int dwAttribute, out Rect pvAttribute, int cbAttribute);
[Serializable, StructLayout(LayoutKind.Sequential)]
private struct Rect
{
public int Left;
public int Top;
public int Right;
public int Bottom;
public Rectangle ToRectangle()
{
return Rectangle.FromLTRB(Left, Top, Right, Bottom);
}
}
private static bool DWMWA_EXTENDED_FRAME_BOUNDS(IntPtr handle, out Rectangle rectangle)
{
Rect rect;
var result = DwmGetWindowAttribute(handle, (int)Dwmwindowattribute.DwmwaExtendedFrameBounds,
out rect, Marshal.SizeOf(typeof(Rect)));
rectangle = rect.ToRectangle();
return result >= 0;
}
it's working fine for all running applications but if it's Media Player in fullscreen mode I didn't get the right Rect size.
Windows Media Player is weird in full screen mode such that the main window handle doesn't correspond to the full screen window displayed. The full screen window still has a handle but a little more work is needed to get to it.
First you'd need to declare some WinAPI functions and structs:
delegate bool EnumWindowsProc(IntPtr hwnd, IntPtr lParam);
[DllImport("User32.dll")]
static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
[DllImport("User32.dll")]
static extern bool GetMonitorInfo(IntPtr hMonitor, ref MonitorInfo lpmi);
[DllImport("User32.dll")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("User32.dll")]
static extern IntPtr MonitorFromWindow(IntPtr hwnd, uint dwFlags);
[StructLayout(LayoutKind.Sequential)]
struct MonitorInfo
{
public uint Size;
public Rect Monitor;
public Rect Work;
public uint Flags;
}
// You seem to have this one already
[StructLayout(LayoutKind.Sequential)]
struct Rect
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
From there, the method looks like this:
// Pass Windows Media Player's main window handle here.
static bool GetWmpFullScreenHandle(IntPtr mainHandle, out IntPtr fullScreenHandle)
{
IntPtr tempHandle = IntPtr.Zero;
// Getting WMP's PID from the main window handle.
GetWindowThreadProcessId(mainHandle, out uint wmpProcessId);
// Optionally, check if the PID resolves to a WMP process.
if (System.Diagnostics.Process.GetProcessById(wmpProcessId).ProcessName != "wmplayer")
{
fullScreenHandle = IntPtr.Zero;
return false;
}
// This iterates through all the open window handles on the machine
// and passes them to the callback below.
EnumWindows((hWnd, lParam) =>
{
// Getting the window handle's PID.
GetWindowThreadProcessId(hWnd, out uint windowProcessId);
// Checking if the window handle belongs to the WMP process.
if (windowProcessId == wmpProcessId)
{
var monitorInfo = new MonitorInfo
{
Size = Convert.ToUInt32(Marshal.SizeOf(typeof(MonitorInfo)))
};
// Getting the dimensions of the monitor the window is displayed on,
// as well as the window dimensions.
if (GetMonitorInfo(MonitorFromWindow(hWnd, 0), ref monitorInfo) &&
GetWindowRect(hWnd, out Rect windowRect))
{
Rect monitorRect = monitorInfo.Monitor;
// If the window dimensions are the same as its monitor's
// dimensions, then we found a hidden full-screen window!
if (windowRect.Left == monitorRect.Left &&
windowRect.Top == monitorRect.Top &&
windowRect.Right == monitorRect.Right &&
windowRect.Bottom == monitorRect.Bottom)
{
tempHandle = hWnd;
}
}
}
return true;
},
IntPtr.Zero);
fullScreenHandle = tempHandle;
// Returns true if the hidden full-screen handle was found, false otherwise.
return fullScreenHandle != IntPtr.Zero;
}
If found, you can then pass the resulting handle to DWMWA_EXTENDED_FRAME_BOUNDS to get the Rectangle.

WebBrowser.DrawToBitmap() or other methods?

I am trying to capture the content of the WebBrowser control. DrawToBitmap() would work perfectly, but it is not supported in documentation for the WebBrowser control. I have been trying to find another way to capture the contents of the WebBrowser control and save them to a local image file.
Does anyone have any workarounds or other methods to save the contents of the WebBrowser control to a local image file?
The Control.DrawToBitmap doesn't always work so I resorted to the following native API calls that provide more consistent results:
The Utilities class. Call Utilities.CaptureWindow(Control.Handle) to capture a specific control:
public static class Utilities
{
public static Image CaptureScreen()
{
return CaptureWindow(User32.GetDesktopWindow());
}
public static Image CaptureWindow(IntPtr handle)
{
IntPtr hdcSrc = User32.GetWindowDC(handle);
RECT windowRect = new RECT();
User32.GetWindowRect(handle, ref windowRect);
int width = windowRect.right - windowRect.left;
int height = windowRect.bottom - windowRect.top;
IntPtr hdcDest = Gdi32.CreateCompatibleDC(hdcSrc);
IntPtr hBitmap = Gdi32.CreateCompatibleBitmap(hdcSrc, width, height);
IntPtr hOld = Gdi32.SelectObject(hdcDest, hBitmap);
Gdi32.BitBlt(hdcDest, 0, 0, width, height, hdcSrc, 0, 0, ApiConstants.SRCCOPY);
Gdi32.SelectObject(hdcDest, hOld);
Gdi32.DeleteDC(hdcDest);
User32.ReleaseDC(handle, hdcSrc);
Image image = Image.FromHbitmap(hBitmap);
Gdi32.DeleteObject(hBitmap);
return image;
}
}
The Gdi32 class:
public class Gdi32
{
[DllImport("gdi32.dll")]
public static extern bool BitBlt(IntPtr hObject, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hObjectSource, int nXSrc, int nYSrc, int dwRop);
[DllImport("gdi32.dll")]
public static extern IntPtr CreateCompatibleBitmap(IntPtr hDC, int nWidth, int nHeight);
[DllImport("gdi32.dll")]
public static extern IntPtr CreateCompatibleDC(IntPtr hDC);
[DllImport("gdi32.dll")]
public static extern bool DeleteDC(IntPtr hDC);
[DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
[DllImport("gdi32.dll")]
public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);
}
The User32 class:
public static class User32
{
[DllImport("user32.dll")]
public static extern IntPtr GetDesktopWindow();
[DllImport("user32.dll")]
public static extern IntPtr GetWindowDC(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern IntPtr GetWindowRect(IntPtr hWnd, ref RECT rect);
[DllImport("user32.dll")]
public static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDC);
}
The constants used:
public const int SRCCOPY = 13369376;
The structs used:
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
A friendly Control extension method:
public static class ControlExtensions
{
public static Image DrawToImage(this Control control)
{
return Utilities.CaptureWindow(control.Handle);
}
}
This is a code snippet from my CC.Utilities project and I specifically wrote it to take screenshots from the WebBrowser control.
The following method can capture the entire window image even if the window is larger than the size of screen. Then it can capture the image of the contents of the page if the window be resized to the webBrowser.Document.OffsetRectangle.Size
class NativeMethods
{
[ComImport]
[Guid("0000010D-0000-0000-C000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IViewObject
{
void Draw([MarshalAs(UnmanagedType.U4)] uint dwAspect, int lindex, IntPtr pvAspect, [In] IntPtr ptd, IntPtr hdcTargetDev, IntPtr hdcDraw, [MarshalAs(UnmanagedType.Struct)] ref RECT lprcBounds, [In] IntPtr lprcWBounds, IntPtr pfnContinue, [MarshalAs(UnmanagedType.U4)] uint dwContinue);
}
[StructLayout(LayoutKind.Sequential, Pack = 4)]
struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
public static void GetImage(object obj, Image destination, Color backgroundColor)
{
using(Graphics graphics = Graphics.FromImage(destination))
{
IntPtr deviceContextHandle = IntPtr.Zero;
RECT rectangle = new RECT();
rectangle.Right = destination.Width;
rectangle.Bottom = destination.Height;
graphics.Clear(backgroundColor);
try
{
deviceContextHandle = graphics.GetHdc();
IViewObject viewObject = obj as IViewObject;
viewObject.Draw(1, -1, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, deviceContextHandle, ref rectangle, IntPtr.Zero, IntPtr.Zero, 0);
}
finally
{
if(deviceContextHandle != IntPtr.Zero)
{
graphics.ReleaseHdc(deviceContextHandle);
}
}
}
}
}
Usage :
Bitmap screenshot = new Bitmap(1024, 768);
NativeMethods.GetImage(webBrowser.ActiveXInstance, screenshot, Color.White);
I am using DrawToBitmap (Visual Studio 2008 C#) to capture big images (user signed invoices,content out of the screen). Basically it is working well but I am getting blank images. About 100 employees are using this software, about every 2 weeks I can see one blank image.
I have done a lot of testing and one funny thing I found is:
I created a button to generate the image from the webbrowser. Usually is OK but if I click the webbrowser first, then click the create-button, the blank image will appear.
I used OleDraw method as in this topic on SO, but integrated it in a class derived from WebBrowser. This allows to do normal Control.DrawToBitmap not only for the WebBrowser, but for a form with WebBrowser in it as well. This also works if the form is hidden (covered by another form, including MDI parent form) and should work when user has locked session with Win+L (I haven't tested it).
public class WebBrowserEx : WebBrowser
{
private const uint DVASPECT_CONTENT = 1;
[DllImport("ole32.dll", PreserveSig = false)]
private static extern void OleDraw([MarshalAs(UnmanagedType.IUnknown)] object pUnk,
uint dwAspect,
IntPtr hdcDraw,
[In] ref System.Drawing.Rectangle lprcBounds
);
protected override void WndProc(ref Message m)
{
const int WM_PRINT = 0x0317;
switch (m.Msg)
{
case WM_PRINT:
Rectangle browserRect = new Rectangle(0, 0, this.Width, this.Height);
// Don't know why, but drawing with OleDraw directly on HDC from m.WParam.
// results in badly scaled (stretched) image of the browser.
// So, drawing to an intermediate bitmap first.
using (Bitmap browserBitmap = new Bitmap(browserRect.Width, browserRect.Height))
{
using (var graphics = Graphics.FromImage(browserBitmap))
{
var hdc = graphics.GetHdc();
OleDraw(this.ActiveXInstance, DVASPECT_CONTENT, hdc, ref browserRect);
graphics.ReleaseHdc(hdc);
}
using (var graphics = Graphics.FromHdc(m.WParam))
{
graphics.DrawImage(browserBitmap, Point.Empty);
}
}
// ignore default WndProc
return;
}
base.WndProc(ref m);
}
}

Multiple webcam capture in one avi with c# (windows forms)

I need to find a way how to make one video file from 2 or more webcam in C# (windows app). I tried to use the google for finding some samples, but no success. I found a way how to record a video from the webcam (with directshowNet, directx I can save two avi with two webcam...)
more about directShowNet:
http: //directshownet.sourceforge.net/
Sample for capturing video:
http: //www.codeproject.com/KB/directx/directshownet.aspx
For a simple example I have 2 webcams. I need to get the frames during the record, paste one frame near the other (make one image, create one frame from the two), and insert these new frames into a new avi.
Any idea? Is it possible to get the frames in time, and create one new avi from the 2 captured?
The question is bit old(!) but just in case: I have successfully used AForge.NET library. In its 2.1.4 version it has a sample that displays video from two cameras.
All you have to do is instead of using default Video Player control use VideoCaptureDevice and in NewFrame events create your desired bitmap.
AForge.NET even have a AVIWriter that you can use for creating output videos.
here this code for merge 2 images
#region TakeSnap Class
IntPtr memDc;
[StructLayout(LayoutKind.Sequential)]
public struct Sizes
{
public Int32 cx;
public Int32 cy;
public Sizes(Int32 x, Int32 y)
{
cx = x;
cy = y;
}
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct BLENDFUNCTION
{
public byte BlendOp;
public byte BlendFlags;
public byte SourceConstantAlpha;
public byte AlphaFormat;
}
[StructLayout(LayoutKind.Sequential)]
public struct Points
{
public Int32 x;
public Int32 y;
public Points(Int32 x, Int32 y)
{
this.x = x;
this.y = y;
}
}
[DllImport("gdi32.dll",EntryPoint="DeleteDC")]
public static extern IntPtr DeleteDC(IntPtr hDc);
[DllImport("gdi32.dll",EntryPoint="DeleteObject")]
public static extern IntPtr DeleteObject(IntPtr hDc);
[DllImport("gdi32.dll",EntryPoint="BitBlt")]
public static extern bool BitBlt(IntPtr hdcDest,int xDest,
int yDest,int wDest,int hDest,IntPtr hdcSource,
int xSrc,int ySrc,int RasterOp);
[DllImport ("gdi32.dll",EntryPoint="CreateCompatibleBitmap")]
public static extern IntPtr CreateCompatibleBitmap(IntPtr hdc,
int nWidth, int nHeight);
[DllImport ("gdi32.dll",EntryPoint="CreateCompatibleDC")]
public static extern IntPtr CreateCompatibleDC(IntPtr hdc);
[DllImport ("gdi32.dll",EntryPoint="SelectObject")]
public static extern IntPtr SelectObject(IntPtr hdc,IntPtr bmp);
[DllImport("user32.dll", EntryPoint="GetDesktopWindow")]
public static extern IntPtr GetDesktopWindow();
[DllImport("user32.dll",EntryPoint="GetDC")]
public static extern IntPtr GetDC(IntPtr ptr);
[DllImport("user32.dll",EntryPoint="GetSystemMetrics")]
public static extern int GetSystemMetrics(int abc);
[DllImport("user32.dll",EntryPoint="GetWindowDC")]
public static extern IntPtr GetWindowDC(Int32 ptr);
[DllImport("user32.dll",EntryPoint="ReleaseDC")]
public static extern IntPtr ReleaseDC(IntPtr hWnd,IntPtr hDc);
protected static IntPtr m_HBitmap;
public const int SM_CXSCREEN=0;
public const int SM_CYSCREEN=1;
public const int SRCCOPY = 13369376;
#endregion
private IntPtr get_pointer(string path)
{
Bitmap bitmap=new Bitmap(path);
IntPtr oldBits = IntPtr.Zero;
IntPtr screenDC = GetDC(IntPtr.Zero);
IntPtr hBitmap = IntPtr.Zero;
memDc = CreateCompatibleDC(screenDC);
try
{
Point topLoc = new Point(Left, Top);
Sizes bitMapSize = new Sizes(bitmap.Width, bitmap.Height);
BLENDFUNCTION blendFunc = new BLENDFUNCTION();
Points srcLoc = new Points(0, 0);
hBitmap = bitmap.GetHbitmap(Color.FromArgb(0));
IntPtr pt= SelectObject(memDc, hBitmap);
ReleaseDC(IntPtr.Zero, screenDC);
return memDc;
}
catch(Exception ex)
{
return this.Handle;
}
}
public Bitmap GetDesktopImage()
{
try
{
Sizes size;
IntPtr hBitmap;
IntPtr hDC = get_pointer(#"C:\Documents and Settings\admin\Desktop\11_13_40_453.jpg");
IntPtr hMemDC = CreateCompatibleDC(hDC);
IntPtr hDC1 = get_pointer(#"C:\Documents and Settings\admin\Desktop\11_13_42_906.jpg");
size.cx = this.Width-2;
size.cy = this.Height-22;
hBitmap = CreateCompatibleBitmap(hDC, size.cx*2, size.cy);
if (hBitmap!=IntPtr.Zero)
{
IntPtr hOld = (IntPtr)SelectObject(hMemDC, hBitmap);
BitBlt(hMemDC, 0, 0,size.cx,size.cy, hDC,0, 0,SRCCOPY);
BitBlt(hMemDC, size.cx, 0,size.cx,size.cy, hDC1,0, 0,SRCCOPY);
SelectObject(hMemDC, hOld);
DeleteDC(hMemDC);
DeleteDC(memDc);
ReleaseDC(this.Handle, hDC);
ReleaseDC(this.Handle, hDC1);
Bitmap bmp = System.Drawing.Image.FromHbitmap(hBitmap);
DeleteObject(hBitmap);
GC.Collect();
return bmp;
}
return null;
}
catch(Exception ex)
{
return null;
}
}
private void Createimage()
{
try
{
Bitmap bm= GetDesktopImage();
bm.Save(Application.StartupPath+"\\temp\\"+DateTime.Now.ToString("hh-mm-ss ff")+".Jpeg",System.Drawing.Imaging.ImageFormat.Jpeg);
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}

Categories

Resources