I am currently working on a windows touch application. Some winForm code remains. As you can see the height of the scroll/arrow buttons height is really too small for a touch button. Is there a way to increase the height to 35/40pixels?
The following link is a VS2012 c# example project download page.
download example here
Thank you.
This solution enumerates the child windows of the ContextMenuStrip. It might happen that there are two child windows (scroll buttons) or zero child windows.
The control used for the scroll buttons is a label, and the default uses a small 9x5 image. The image is updated to a larger image (using the Marlett font), and then AutoSize is set to true which causes the label to resize itself.
Edit: changed implementation to an extension method for better flexibility
using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace Opulos.Core.UI {
///<summary>Extension class to increase the size of the scroll up-down arrows on a drop down context menu or tool strip menu. The default up-down arrows are only 5 pixels high.</summary>
public static class ToolStripEx {
private static Hashtable htData = new Hashtable();
private class Data {
public bool needsUpdate = true;
public bool disposeLastImage = false;
public ToolStrip toolStrip = null;
public List<Image> currentImages = new List<Image>();
}
public static void BigButtons(this ToolStrip toolStrip) {
htData[toolStrip] = new Data() { toolStrip = toolStrip };
toolStrip.VisibleChanged += toolStrip_VisibleChanged;
toolStrip.ForeColorChanged += toolStrip_ForeColorChanged;
toolStrip.Disposed += toolStrip_Disposed;
}
static void toolStrip_Disposed(object sender, EventArgs e) {
Data d = (Data) htData[sender];
if (d != null && d.currentImages != null) {
foreach (var img in d.currentImages)
img.Dispose();
d.currentImages = null;
htData.Remove(sender);
}
}
static void toolStrip_ForeColorChanged(object sender, EventArgs e) {
Data d = (Data) htData[sender];
d.needsUpdate = true;
UpdateImages(d);
}
static void toolStrip_VisibleChanged(object sender, EventArgs e) {
Data d = (Data) htData[sender];
UpdateImages(d);
}
private static void UpdateImages(Data d) {
if (!d.needsUpdate)
return;
d.toolStrip.BeginInvoke((Action) delegate {
try {
var list = GetChildWindows(d.toolStrip.Handle);
if (list.Count == 0)
return;
List<Image> newImages = new List<Image>();
int k = 0;
foreach (var i in list) {
var c = Control.FromHandle(i) as Label;
if (c != null && d.needsUpdate) {
String glyph = (k == 0 ? "t" : "u");
using (Font f = new System.Drawing.Font("Marlett", 20f)) {
Size s = TextRenderer.MeasureText("t", f);
var oldImage = c.Image;
c.Image = new Bitmap(s.Width, s.Height);
newImages.Add(c.Image);
// avoid disposing the default image
// might cause problems, not sure
if (d.disposeLastImage)
oldImage.Dispose();
using (Graphics g = Graphics.FromImage(c.Image)) {
using (Brush b = new SolidBrush(d.toolStrip.ForeColor))
g.DrawString(glyph, f, b, 0, 0);
}
c.AutoSize = true;
}
k++;
}
}
if (newImages.Count > 0) {
d.needsUpdate = false;
d.disposeLastImage = true;
d.currentImages = newImages;
}
} catch {} // protect against crash (just in case)
});
}
private static List<IntPtr> GetChildWindows(IntPtr parent) {
List<IntPtr> result = new List<IntPtr>();
GCHandle listHandle = GCHandle.Alloc(result);
try {
EnumChildWindows(parent, enumProc, GCHandle.ToIntPtr(listHandle));
} finally {
if (listHandle.IsAllocated)
listHandle.Free();
}
return result;
}
private delegate bool EnumChildProc(IntPtr hWnd, IntPtr lParam);
private static EnumChildProc enumProc = new EnumChildProc(CallChildEnumProc);
private static bool CallChildEnumProc(IntPtr hWnd, IntPtr lParam) {
GCHandle gch = GCHandle.FromIntPtr(lParam);
List<IntPtr> list = gch.Target as List<IntPtr>;
if (list == null)
throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>");
list.Add(hWnd);
return true;
}
[DllImport("user32.dll")]
private static extern bool EnumChildWindows(IntPtr hWndParent, EnumChildProc lpEnumFunc, IntPtr lParam);
}
}
[STAThread]
static void Main() {
Application.EnableVisualStyles();
var cms = new ContextMenuStrip();
cms.BigButtons();
for (int i = 0; i < 20; i++)
cms.Items.Add(new ToolStripMenuItem("Item " + i));
cms.MaximumSize = new Size(200, 400);
Form f = new Form();
f.ContextMenuStrip = cms;
Application.Run(f);
}
Related
I need help getting my program to match the "stored" colour with the current one in the same location then click the mouse if it's the same. The grabbing of the colour works great so far in my code just unsure how to match a colour and a point, etc.
Also a start/stop button for the loop would be nice.
My code so far:
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Pixel_detection_test_3
{
public partial class PixelDetectionForm : Form
{
private const UInt32 MOUSEEVENTF_LEFTDOWN = 0x0002;
private const UInt32 MOUSEEVENTF_LEFTUP = 0x0004;
[DllImport("user32.dll")]
private static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData, uint dwExtraInf);
private int pixelY;
private int pixelX;
private Point pixelYX;
private static Color currentColour;
private static Color storedColour;
public PixelDetectionForm()
{
InitializeComponent();
}
static Color GetPixel(Point position)
{
using (var bitmap = new Bitmap(1, 1))
{
using (var graphics = Graphics.FromImage(bitmap))
{
graphics.CopyFromScreen(position, new Point(0, 0), new Size(1, 1));
}
return bitmap.GetPixel(0, 0);
}
}
private void PixelDetectionForm_KeyDown(object sender, KeyEventArgs e)
{
// Get Cursor Pixel Position
if (e.KeyCode == Keys.F1 || e.KeyCode == Keys.F2)
{
pixelY = Cursor.Position.Y;
pixelX = Cursor.Position.X;
pixelYX = Cursor.Position;
textBoxYPos.Text = pixelY.ToString();
textBoxXPos.Text = pixelX.ToString();
e.Handled = true;
}
// Get Cursor Pixel Colour
if (e.KeyCode == Keys.F1 || e.KeyCode == Keys.F3)
{
storedColour = GetPixel(Cursor.Position);
textBoxColour.Text = storedColour.ToString().Remove(0, 14).TrimEnd(']');
panelColourDisplay.BackColor = storedColour;
e.Handled = true;
}
}
// Not working, need help with this
private async void buttonStart_Click(object sender, EventArgs e)
{
while (true)
{
GetPixel(pixelYX);
// Should get position of 'pixelY' and 'pixelX'
panelColourDisplay2.BackColor = GetPixel(Cursor.Position);
if (pixelYX == storedColour)
{
MousePress();
}
// Need this to prevent not responding
await Task.Delay(3);
}
}
private void MousePress()
{
mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
}
private void PixelDetectionForm_Click(object sender, EventArgs e)
{
ActiveControl = null;
}
private void PixelDetectionForm_Activated(object sender, EventArgs e)
{
ActiveControl = null;
}
}
}
Thanks
Well, an alternative to the while..loop is using a Timer to achieve that.
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace Pixel_detection_test_3
{
public partial class PixelDetectionForm : Form
{
private readonly Timer Tmr;
private Point lastPoint;
//Assign this from your input code.
private Color targetColor;
public PixelDetectionForm()
{
Tmr = new Timer { Interval = 50 };
Tmr.Tick += (s, e) => FindMatches(Cursor.Position);
}
//...
In the timer's Tick event, the FindMatches(..) method is called to check the current Cursor.Position and add the distinct matches into a ListBox. You can replace the last part with what you really need to do when you find a match. Like calling the MousePress() method in your code:
//...
private void FindMatches(Point p)
{
//To avoid the redundant calls..
if (p.Equals(lastPoint)) return;
lastPoint = p;
using (var b = new Bitmap(1, 1))
using (var g = Graphics.FromImage(b))
{
g.CopyFromScreen(p, Point.Empty, b.Size);
var c = b.GetPixel(0, 0);
if (c.ToArgb().Equals(targetColor.ToArgb()) &&
!listBox1.Items.Cast<Point>().Contains(p))
{
listBox1.Items.Add(p);
listBox1.SelectedItem = p;
}
}
}
private void PixelDetectionForm_FormClosing(object sender, FormClosingEventArgs e)
{
Tmr.Dispose();
}
}
}
Start and stop the timer in the click events of the Start and Stop buttons.
Here's a demo:
Another alternative is to use the Global Mouse and Keyboard Hooks. Check this, this, and this for more details.
Edit 2/11/2020
If you just want to check whether a given color at a given point exists in a given image, then you can do:
private void buttonStart_Click(object sender, EventArgs e)
{
var targetColor = ...; //target color.
var targetPoint = ...; //target point.
var sz = Screen.PrimaryScreen.Bounds.Size;
using (var b = new Bitmap(sz.Width, sz.Height, PixelFormat.Format32bppArgb))
using (var g = Graphics.FromImage(b))
{
g.CopyFromScreen(Point.Empty, Point.Empty, b.Size, CopyPixelOperation.SourceCopy);
var bmpData = b.LockBits(new Rectangle(Point.Empty, sz), ImageLockMode.ReadOnly, b.PixelFormat);
var pixBuff = new byte[bmpData.Stride * bmpData.Height];
Marshal.Copy(bmpData.Scan0, pixBuff, 0, pixBuff.Length);
b.UnlockBits(bmpData);
for (var y = 0; y < b.Height; y++)
for(var x = 0; x < b.Width; x++)
{
var pos = (y * bmpData.Stride) + (x * 4);
var blue = pixBuff[pos];
var green = pixBuff[pos + 1];
var red = pixBuff[pos + 2];
var alpha = pixBuff[pos + 3];
if (Color.FromArgb(alpha, red, green, blue).ToArgb().Equals(targetColor.ToArgb()) &&
new Point(x, y).Equals(targetPoint))
{
//execute you code here..
MessageBox.Show("The given color exists at the given point.");
return;
}
}
}
MessageBox.Show("The given color doesn't exist at the given point.");
}
If you want to get a list of all the positions of a given color, then create a new List<Point>() and change the check condition to:
//...
var points = new List<Point>();
if (Color.FromArgb(alpha, red, green, blue).ToArgb().Equals(targetColor.ToArgb()))
{
points.Add(new Point(x, y));
}
I am creating a form inside another form. In the child form I have created taskbar button. I am overriding WndProc in the button.I am referring https://www.codeproject.com/Articles/10171/Adding-a-Minimize-to-tray-button-to-a-Form-s-caption bar. But whenever I am getting messages(mouse coordinates) , it is given with respect to the parent form. This makes trouble in calculations .I want those with respect to child form.How to achieve this?
This is the code for form1
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Form2 form2 = new Form2();
form2.TopLevel = false;
form2.AutoScroll = true;
form2.Anchor = AnchorStyles.Top;
form2.Dock = DockStyle.Fill;
this.splitContainer1.Panel2.Controls.Add(form2);
form2.Show();
}
}
this is form2.
public partial class Form2 : Form
{
TyronM.MinTrayBtn Pin_Button;
public Form2()
{
InitializeComponent();
Pin_Button = new TyronM.MinTrayBtn(this);
Pin_Button.MinTrayBtnClicked += new TyronM.MinTrayBtnClickedEventHandler(this.Pin_Button_Clicked);
}
public void Pin_Button_Clicked(object sender, EventArgs e)
{
MessageBox.Show("Pin button got Clicked");
}
protected override void WndProc(ref Message message)
{
const int WM_SYSCOMMAND = 0x0112;
const int SC_MOVE = 0xF010;
switch (message.Msg)
{
case WM_SYSCOMMAND:
int command = message.WParam.ToInt32() & 0xfff0;
if (command == SC_MOVE)
return;
break;
}
base.WndProc(ref message);
}
}
And this is for button.
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Diagnostics;
using System.Resources;
using System.Runtime.InteropServices;
namespace TyronM {
public delegate void MinTrayBtnClickedEventHandler(object sender, EventArgs e);
/// <summary>
/// Summary description for Class.
/// </summary>
public class MinTrayBtn : NativeWindow {
bool pinned = false;
bool pressed = false;
Size wnd_size = new Size();
public bool captured;
Form parent;
public event MinTrayBtnClickedEventHandler MinTrayBtnClicked;
#region Constants
const int WM_SIZE = 5;
const int WM_SYNCPAINT = 136;
const int WM_MOVE = 3;
const int WM_ACTIVATE = 6;
const int WM_LBUTTONDOWN =513;
const int WM_LBUTTONUP =514;
const int WM_LBUTTONDBLCLK =515;
const int WM_MOUSEMOVE = 512;
const int WM_PAINT = 15;
const int WM_GETTEXT = 13;
const int WM_NCCREATE =129;
const int WM_NCLBUTTONDOWN = 161;
const int WM_NCLBUTTONUP = 162;
const int WM_NCMOUSEMOVE = 160;
const int WM_NCACTIVATE =134;
const int WM_NCPAINT = 133;
const int WM_NCHITTEST = 132;
const int WM_NCLBUTTONDBLCLK = 163;
const int VK_LBUTTON = 1;
const int SM_CXSIZE = 30;
const int SM_CYSIZE = 31;
#endregion
#region Extra Constants
const int WM_MBUTTONUP = 0x0208;
#endregion
#region WinAPI Imports
[DllImport("user32")]
public static extern int GetWindowDC(int hwnd);
[DllImport("user32")]
public static extern short GetAsyncKeyState(int vKey);
[DllImport("user32")]
public static extern int SetCapture(int hwnd);
[DllImport("user32")]
public static extern bool ReleaseCapture();
[DllImport("user32")]
public static extern int GetSysColor(int nIndex);
[DllImport("user32")]
public static extern int GetSystemMetrics(int nIndex);
#endregion
#region Constructor and Handle-Handler ^^
public MinTrayBtn(Form parent) {
parent.HandleCreated += new EventHandler(this.OnHandleCreated);
parent.HandleDestroyed+= new EventHandler(this.OnHandleDestroyed);
parent.TextChanged+= new EventHandler(this.OnTextChanged);
this.parent = parent;
}
// Listen for the control's window creation and then hook into it.
internal void OnHandleCreated(object sender, EventArgs e){
// Window is now created, assign handle to NativeWindow.
AssignHandle(((Form)sender).Handle);
}
internal void OnHandleDestroyed(object sender, EventArgs e) {
// Window was destroyed, release hook.
ReleaseHandle();
}
// Changing the Text invalidates the Window, so we got to Draw the Button again
private void OnTextChanged(object sender, EventArgs e) {
DrawButton();
}
#endregion
#region WndProc
[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name="FullTrust")]
protected override void WndProc(ref Message m){
//label3.Text = "Button pressed: " + pressed;
//label4.Text = "Mouse captured: " + captured;
// Change the Pressed-State of the Button when the User pressed the
// left mouse button and moves the cursor over the button
if (m.Msg == WM_LBUTTONDBLCLK ||m.Msg == WM_LBUTTONDOWN || m.Msg == WM_LBUTTONUP
||m.Msg == WM_MBUTTONUP
)
MessageBox.Show("click happened");
if(m.Msg==WM_MOUSEMOVE) {
Point pnt2 = new Point((int)m.LParam);
Size rel_pos2 = new Size(parent.PointToClient(new Point(parent.Location.X, parent.Location.Y)));
// Not needed because SetCapture seems to convert the cordinates anyway
//pnt2 = PointToClient(pnt2);
pnt2-=rel_pos2;
//label2.Text = "Cursor #"+pnt2.X+"/"+pnt2.Y;
if(pressed) {
Point pnt = new Point((int)m.LParam);
Size rel_pos = new Size(parent.PointToClient(new Point(parent.Location.X, parent.Location.Y)));
//pnt = PointToClient(pnt);
pnt-=rel_pos;
if(!MouseinBtn(pnt)) {
pressed = false;
DrawButton();
}
} else {
if((GetAsyncKeyState(VK_LBUTTON)&(-32768))!=0) {
Point pnt = new Point((int)m.LParam);
Size rel_pos = new Size(parent.PointToClient(new Point(parent.Location.X, parent.Location.Y)));
//pnt = PointToClient(pnt);
pnt-=rel_pos;
if(MouseinBtn(pnt)) {
pressed = true;
DrawButton();
}
}
}
}
// Ignore Double-Clicks on the Traybutton
if(m.Msg==WM_NCLBUTTONDBLCLK) {
Point pnt = new Point((int)m.LParam);
Size rel_pos = new Size(parent.PointToClient(new Point(parent.Location.X, parent.Location.Y)));
pnt = parent.PointToClient(pnt);
pnt-=rel_pos;
if(MouseinBtn(pnt)) {
return;
}
}
#region NOT WORKING
// Button released and eventually clicked
if(m.Msg==WM_LBUTTONUP)
{
ReleaseCapture();
captured = false;
if(pressed) {
pressed = false;
DrawButton();
Point pnt = new Point((int)m.LParam);
Size rel_pos = new Size(parent.PointToClient(new Point(parent.Location.X, parent.Location.Y)));
pnt-=rel_pos;
if(MouseinBtn(pnt)) {
//TrayButton_clicked();
EventArgs e = new EventArgs();
if (MinTrayBtnClicked != null)
MinTrayBtnClicked(this, e);
return;
}
}
}
#endregion
// Clicking the Button - Capture the Mouse and await until the Uses relases the Button again
if(m.Msg==WM_NCLBUTTONDOWN) {
//MessageBox.Show("clicked");
Point pnt = new Point((int)m.LParam);
Size rel_pos = new Size(parent.PointToClient(new Point(parent.Location.X, parent.Location.Y)));
pnt = parent.PointToClient(pnt);
pnt-=rel_pos;
if(MouseinBtn(pnt)) {
MessageBox.Show("clicked");
pressed = true;
DrawButton();
SetCapture((int)parent.Handle);
captured = true;
return;
}
}
// Drawing the Button and getting the Real Size of the Window
if(m.Msg == WM_ACTIVATE || m.Msg==WM_SIZE || m.Msg==WM_SYNCPAINT || m.Msg==WM_NCACTIVATE || m.Msg==WM_NCCREATE || m.Msg==WM_NCPAINT || m.Msg==WM_NCACTIVATE || m.Msg==WM_NCHITTEST || m.Msg==WM_PAINT) {
if(m.Msg==WM_SIZE) wnd_size = new Size(new Point((int)m.LParam));
DrawButton();
}
base.WndProc(ref m);
}
#endregion
#region Button-Specific Functions
public bool MouseinBtn(Point click) {
int btn_width = GetSystemMetrics(SM_CXSIZE);
int btn_height = GetSystemMetrics(SM_CYSIZE);
Size btn_size = new Size(btn_width, btn_height);
Point pos = new Point(wnd_size.Width - 3 * btn_width - 12 - (btn_width - 18)+7, 6+4);
return click.X>=pos.X && click.X<=pos.X+btn_size.Width &&
click.Y>=pos.Y && click.Y<=pos.Y+btn_size.Height;
}
public void DrawButton() {
Graphics g = Graphics.FromHdc((IntPtr)GetWindowDC((int)parent.Handle)); //m.HWnd));
DrawButton(g, pressed);
}
public void DrawButton(Graphics g, bool pressed) {
int btn_width = GetSystemMetrics(SM_CXSIZE);
int btn_height = GetSystemMetrics(SM_CYSIZE);
//Point pos = new Point(wnd_size.Width-3*btn_width-12-(btn_width-18),6);
Point pos = new Point(wnd_size.Width - 3 * btn_width - 12 - (btn_width - 18)+7, 6+4);
// real button size
btn_width-=2;
btn_height-=4;
Color light = SystemColors.ControlLightLight;
Color icon = SystemColors.ControlText;
Color background = SystemColors.Control;
Color shadow1 = SystemColors.ControlDark;
Color shadow2 = SystemColors.ControlDarkDark;
Color tmp1, tmp2;
if(pressed) {
tmp1 = shadow2;
tmp2 = light;
} else {
tmp1 = light;
tmp2 = shadow2;
}
g.DrawLine(new Pen(tmp1),pos, new Point(pos.X+btn_width-1,pos.Y));
g.DrawLine(new Pen(tmp1),pos, new Point(pos.X,pos.Y+btn_height-1));
if(pressed) {
g.DrawLine(new Pen(shadow1),pos.X+1, pos.Y+1, pos.X+btn_width-2, pos.Y+1);
g.DrawLine(new Pen(shadow1),pos.X+1, pos.Y+1, pos.X+1, pos.Y+btn_height-2);
} else {
g.DrawLine(new Pen(shadow1),pos.X+btn_width-2, pos.Y+1, pos.X+btn_width-2, pos.Y+btn_height-2);
g.DrawLine(new Pen(shadow1),pos.X+1, pos.Y+btn_height-2, pos.X+btn_width-2, pos.Y+btn_height-2);
}
g.DrawLine(new Pen(tmp2),pos.X+btn_width-1, pos.Y+0, pos.X+btn_width-1, pos.Y+btn_height-1);
g.DrawLine(new Pen(tmp2),pos.X+0, pos.Y+btn_height-1, pos.X+btn_width-1, pos.Y+btn_height-1);
g.FillRectangle(new SolidBrush(background),pos.X+1+Convert.ToInt32(pressed), pos.Y+1+Convert.ToInt32(pressed), btn_width-3,btn_height-3);
#region Added Code
g.FillRectangle(new SolidBrush(icon),pos.X+(float)0.5625*btn_width+Convert.ToInt32(pressed),pos.Y+(float)0.6428*btn_height+Convert.ToInt32(pressed),btn_width*(float)0.1875,btn_height*(float)0.143);
g.DrawImage(Image.FromFile("red_Pushpin.jfif"),new Rectangle( pos,new Size(btn_width,btn_height)));
#endregion
}
#endregion
}
}
This is code for main
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());
}
}
This is the screenshot of the winform.
EDIT:
Upon investigation I found that WM_LBUTTONUP(Mouse left button up) is not triggered. Or it is not coming inside WndProc.
EDIT1:
It seems there was a problem in brackets.I changed the if conditions into switch case. This somewhat cleared the "Mouse left button up" problem. Now it is properly triggering. The remaining problem is mouse points based on parent form.
I am working on a c# console program on Windows to move a window, as part of this I am trying to create a transparent box at the target destination to give the user a visual confirmation of the new location. I am currently facing 2 main problems:
I want to place the form in screen coordinates
I want to be able to close the window after the user has confirmed their decision.
Currently I have code in a library that my console client is calling that does this:
public static void CreateBox(Rect rectangle)
{
Form f = new Form();
f.Name = BoxName;
f.BackColor = Color.Blue;
f.FormBorderStyle = FormBorderStyle.None;
f.Bounds = new System.Drawing.Rectangle(rectangle.Left, rectangle.Top, rectangle.Right - rectangle.Left, rectangle.Bottom - rectangle.Top);
f.TopMost = true;
f.Opacity = 0.5;
Application.EnableVisualStyles();
Task.Run(() => Application.Run(f));
}
And after searching some questions on here I have come up with this to attempt to close the form later:
public static void RemoveBox()
{
Form f = Application.OpenForms[BoxName];
if (f != null)
{
f.Close();
}
}
This is throwing an exception as its coming from a different thread, how can I close this window, and how can I place it in screen coordinates exactly where it should go?
EDIT:
I am now using this to attempt to find the box to move/close it unsuccessfully:
public static void CreateBox(Rect rectangle)
{
Form f = new Form();
f.Name = BoxName;
f.BackColor = Color.AliceBlue;
f.FormBorderStyle = FormBorderStyle.None;
f.TopMost = true;
f.Opacity = 0.3;
Application.EnableVisualStyles();
Task.Run(() =>
{
Application.Run(f);
});
MoveBox(rectangle);
}
public static void RemoveBox()
{
IntPtr hWnd = FindBox(new TimeSpan(0, 0, 1));
var proc = Process.GetProcesses().Where(p => p.Handle == hWnd).Single();
if (proc == null)
{
return;
}
proc.Kill();
}
public static void MoveBox(Rect rect)
{
IntPtr hWnd = FindBox(new TimeSpan(0, 0, 1));
MoveWindow(hWnd, rect);
}
private static IntPtr FindBox(TimeSpan timeout)
{
DateTime time = DateTime.Now;
IntPtr hWnd = IntPtr.Zero;
while(DateTime.Now < time.Add(timeout) || hWnd != IntPtr.Zero)
{
hWnd = FindWindowByCaption(IntPtr.Zero, BoxName);
}
return hWnd;
}
Issues with this:
I can't let the FindBox call take long at all because my goal is to make this box appear and snap windows to them as the user drags them and needs to move as they move it around the desktop.
the p.Handle == hWnd check in the RemoveBox function throws and access denied exception.
If you want do just get it working put:
Form.CheckForIllegalCrossThreadCalls = false;
Into your constructor, I do not recommend it however, since it will make the whole Form no longer be thread safe.
EDIT : Here is a quick test I've done using a WinForm. It should run fine on console as well.
public partial class Form1 : Form
{
//Globals
Form f;
Task t;
public Form1()
{
InitializeComponent();
f = new Form();
f.Name = "testForm";
f.BackColor = Color.Blue;
f.FormBorderStyle = FormBorderStyle.None;
f.Bounds = new System.Drawing.Rectangle(0, 0, 100, 100);
f.TopMost = true;
f.Opacity = 0.5;
Application.EnableVisualStyles();
//f.Show();
t = Task.Run(() => Application.Run(f));
}
private void btn_CloseForm_Click(object sender, EventArgs e)
{
if (f.InvokeRequired)
{
this.Invoke(new CloseForm_Delegate(CloseForm));
}
}
delegate void CloseForm_Delegate();
private void CloseForm()
{
f.Close();
}
private void btn_MoveForm_Click(object sender, EventArgs e)
{
if (f.InvokeRequired)
{
//set form position here
this.Invoke(new MoveForm_Delegate(MoveForm), new Point(0, 0));
}
}
delegate void MoveForm_Delegate(Point p);
private void MoveForm(Point p)
{
f.Location = p;
}
}
I added a new form to my project the new form contain in the designer webBrowser control. What i'm doing is parsing from html some links then navigate to each link then taking a screenshot and save to the hard disk each image i navigated to in the webBrowser.
In the end when all the links navigated and i have the images on the hard disk i display them on Form1 pictureBox with a hScrollBar.
But now instead waiting for it to finish in the new form and then to show all the images i want to show each saved image on the hard disk in the pictureBox in form1.
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.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.IO;
namespace WebBrowserScreenshots.cs
{
public partial class WebBrowserScreenshots : Form
{
private class MyComparer : IComparer<string>
{
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
private static extern int StrCmpLogicalW(string x, string y);
public int Compare(string x, string y)
{
return StrCmpLogicalW(x, y);
}
}
List<string> newHtmls = new List<string>();
string uri = "";
public bool htmlloaded = false;
int countlinks = 0;
public int numberoflinks = 0;
public int numberofimages = 0;
public List<string> imageList = new List<string>();
public WebBrowserScreenshots()
{
InitializeComponent();
webBrowser1.ScrollBarsEnabled = false;
webBrowser1.ScriptErrorsSuppressed = true;
NavigateToSites();
}
string test;
List<string> htmls;
private void GetLinks()
{
htmlloaded = true;
for (int i = 1; i < 304; i++)
{
if (newHtmls.Count == 1)
break;
backgroundWorker1.ReportProgress(i);
HtmlAgilityPack.HtmlWeb hw = new HtmlAgilityPack.HtmlWeb();
HtmlAgilityPack.HtmlDocument doc = hw.Load("http://test/page" + i);
htmls = new List<string>();
foreach (HtmlAgilityPack.HtmlNode link in doc.DocumentNode.SelectNodes("//a[#href]"))
{
string hrefValue = link.GetAttributeValue("href", string.Empty);
if (hrefValue.Contains("http") && hrefValue.Contains("attachment"))
htmls.Add(hrefValue);
}
if (htmls.Count > 0 && abovezero == false)
RealTimeHtmlList();
}
}
bool abovezero = false;
private void RealTimeHtmlList()
{
abovezero = true;
for (int x = 0; x < htmls.Count; x++)
{
test = htmls[x];
int index = test.IndexOf("amp");
string test1 = test.Substring(39, index - 25);
test = test.Remove(39, index - 35);
int index1 = test.IndexOf("amp");
if (index1 > 0)
test = test.Remove(index1, 4);
if (!newHtmls.Contains(test))
{
while (true)
{
if (htmlloaded == true)
{
newHtmls.Add(test);
RealTimeNavigate(test);
}
else
{
break;
}
}
}
}
}
private void RealTimeNavigate(string tests)
{
uri = test;
webBrowser1.Navigate(test);
htmlloaded = false;
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
GetLinks();
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
numberoflinks = e.ProgressPercentage;
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
numberofimages = newHtmls.Count;
htmlloaded = true;
}
private void NavigateToLinks()
{
if (countlinks != newHtmls.Count)
{
while (true)
{
if (htmlloaded == true)
{
uri = newHtmls[countlinks];
webBrowser1.Navigate(newHtmls[countlinks]);
countlinks++;
htmlloaded = false;
}
else
{
break;
}
}
}
}
int imagescount = 0;
public FileInfo[] filesinfo;
public bool savedall = false;
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (e.Url.ToString() == uri)
{
Bitmap bmp = new Bitmap(SaveImageFromWebBrowser(webBrowser1));
bmp = ImageTrim.ImagesTrim(bmp);
bmp.Save(#"e:\webbrowserimages\Image" + imagescount.ToString() + ".bmp",
System.Drawing.Imaging.ImageFormat.Bmp);
bmp.Dispose();
imagescount++;
htmlloaded = true;
RealTimeHtmlList();
}
}
private void NavigateToSites()
{
backgroundWorker1.RunWorkerAsync();
}
[DllImport("user32.dll")]
public static extern bool PrintWindow(IntPtr hwnd, IntPtr hdcBlt, uint nFlags);
private Bitmap SaveImageFromWebBrowser(Control ctl)
{
Bitmap bmp = new Bitmap(ctl.ClientRectangle.Width, ctl.ClientRectangle.Height);
using (Graphics graphics = Graphics.FromImage(bmp))
{
IntPtr hDC = graphics.GetHdc();
try { PrintWindow(ctl.Handle, hDC, (uint)0); }
finally { graphics.ReleaseHdc(hDC); }
}
return bmp;
}
}
}
And in form1 i did:
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.IO;
using System.Runtime.InteropServices;
namespace WebBrowserScreenshots.cs
{
public partial class Form1 : Form
{
private class MyComparer : IComparer<string>
{
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
private static extern int StrCmpLogicalW(string x, string y);
public int Compare(string x, string y)
{
return StrCmpLogicalW(x, y);
}
}
public List<string> imageList = new List<string>();
List<string> numbers = new List<string>();
WebBrowserScreenshots wbss;
public Form1()
{
InitializeComponent();
pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
this.imageList = Directory.GetFiles(#"e:\webbrowserimages\", "*.bmp").ToList();
this.imageList.Sort(new MyComparer());
if (this.imageList.Count > 0)
{
hScrollBar1.Minimum = 0;
hScrollBar1.Value = 0;
hScrollBar1.Maximum = this.imageList.Count - 1;
hScrollBar1.SmallChange = 1;
hScrollBar1.LargeChange = 1;
pictureBox1.Image = Image.FromFile(this.imageList[0]);
}
else
{
timer1.Start();
wbss = new WebBrowserScreenshots();
wbss.Show();
}
}
FileInfo[] myFile;
private void timer1_Tick(object sender, EventArgs e)
{
if (wbss.savedall == true)
{
timer1.Stop();
hScrollBar1.Enabled = true;
hScrollBar1.Minimum = 0;
hScrollBar1.Value = 0;
hScrollBar1.Maximum = wbss.imageList.Count - 1;
hScrollBar1.SmallChange = 1;
hScrollBar1.LargeChange = 1;
pictureBox1.Image = Image.FromFile(wbss.imageList[0]);
}
else
{
if (wbss.htmlloaded == true)
{
var directory = new DirectoryInfo(#"e:\webbrowserimages\");
myFile = directory.GetFiles("*.bmp");
if (myFile.Length > 0)
{
var myFiles = (from f in directory.GetFiles("*.bmp")
orderby f.LastWriteTime descending
select f).First();
hScrollBar1.Enabled = true;
hScrollBar1.Minimum = 0;
hScrollBar1.Value = 0;
hScrollBar1.Maximum = 1;
hScrollBar1.SmallChange = 1;
hScrollBar1.LargeChange = 1;
pictureBox1.Image = Image.FromFile(myFiles.Name);
}
}
}
}
private void hScrollBar1_Scroll(object sender, ScrollEventArgs e)
{
int index = (int)hScrollBar1.Value;
if (pictureBox1.Image != null) pictureBox1.Image.Dispose();
if (this.imageList.Count > 0)
{
pictureBox1.Image = Image.FromFile(this.imageList[index]);
label1.Text = "Displaying image " + index + " of " + (this.imageList.Count - 1);
}
else
{
pictureBox1.Image = Image.FromFile(wbss.imageList[index]);
label1.Text = "Displaying image " + index + " of " + (wbss.imageList.Count - 1);
}
}
}
}
In form1 i have two options situations could be done.
Once if i'm using in the new form the way that i'm waiting for the backgroundworker to complete and then to wait untill it will navigate to all links in the List newHtmls and then after all images saved on hard disk for example 2453 images then i browse them in form1 pictureBox and hScrollBar.
Or the second option i'm using now that once an image saved to the hard disk in the new form then i will show the image in the form1 pictureBox1.
Then another image saved so now there are two images on hard disk so now show the last saved image. And so on once image saved display it on form1 pictureBox.
Just to show it. So i will see every X seconds images changing in form1 pictureBox.
The problem i'm facing now is in Form1 in this part:
if (wbss.htmlloaded == true)
{
var directory = new DirectoryInfo(#"e:\webbrowserimages\");
myFile = directory.GetFiles("*.bmp");
if (myFile.Length > 0)
{
var myFiles = (from f in directory.GetFiles("*.bmp")
orderby f.LastWriteTime descending
select f).First();
hScrollBar1.Enabled = true;
hScrollBar1.Minimum = 0;
hScrollBar1.Value = 0;
hScrollBar1.Maximum = 1;
hScrollBar1.SmallChange = 1;
hScrollBar1.LargeChange = 1;
pictureBox1.Image = Image.FromFile(myFiles.Name);
}
}
On the line:
pictureBox1.Image = Image.FromFile(myFiles.Name);
FileNotFoundException: Image3.bmp
But on my hard disk i see Image3.bmp
I will try to narrow cut some code but it's all connected the new form with form1.
You need to use myFiles.FullName. myFiles.Name only has the path relative to the directory the file is in, which is not enough to find the file. FullName includes the directory, so it's the full absolute path to the file.
And for gasake, name your controls. Form1 isn't a good name. pictureBox1 isn't a good name. Even the variable names are misleading - myFile for a collection of files, and then myFiles for a single file? And why are you calling GetFiles again when you already have a list in myFile? And why even check for file length? Why not just do directory.GetFiles("*.bmp").OrderByDescending(i => i.LastWriteTime).Select(i => i.FullName).FirstOrDefault()?
I have an interop question about embedding WinForms controls into a WPF application and differences in the .Net framework versions.
The following should show a transparent wpf control (red box) over a WebBrowser control and works as expected when using .Net 3.5:
... but after compilation with .Net 4.5 the following occurs.
Everything works again when switching back to .Net 3.5
The following Code works for WPF with Win32 using .Net 3.0 up to .Net 3.5 but not with .Net 4.0/4.5:
Win32HostRenderer.xaml:
<UserControl x:Class="WPFInterop.Interop.Win32HostRenderer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Image Name="_interopRenderer" Stretch="None"/>
</Grid>
</UserControl>
Win32HostRenderer.xaml.cs:
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using Winforms = System.Windows.Forms;
using GDI = System.Drawing;
using System.Runtime;
using System.Runtime.InteropServices;
namespace WPFInterop.Interop
{
public partial class Win32HostRenderer : System.Windows.Controls.UserControl
{
[DllImport("user32.dll")]
private static extern bool PrintWindow(IntPtr hwnd, IntPtr hdcBlt, uint nFlags);
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
[DllImport("Kernel32.dll", EntryPoint = "RtlMoveMemory")]
private static extern void CopyMemory(IntPtr Destination, IntPtr Source, int Length);
private DispatcherTimer _rendererTimer;
private int _rendererInterval = 33;
private InteropForm _interopForm;
private Winforms.Control _winformControl;
private BitmapSource _bitmapSource;
private BitmapBuffer _bitmapSourceBuffer;
private GDI.Bitmap _gdiBitmap;
private GDI.Graphics _gdiBitmapGraphics;
private IntPtr _hGDIBitmap;
public Win32HostRenderer()
{
InitializeComponent();
}
private void InitializeInteropForm()
{
if (_winformControl == null) return;
if (_interopForm != null)
{
TearDownInteropForm();
}
_interopForm = new InteropForm();
_interopForm.Opacity = 0.01;
_interopForm.Controls.Add(_winformControl);
_interopForm.Width = _winformControl.Width;
_interopForm.Height = _winformControl.Height;
}
private void TearDownInteropForm()
{
if (_interopForm == null) return;
_interopForm.Hide();
_interopForm.Close();
_interopForm.Dispose();
_interopForm = null;
}
private void InitializeRendererTimer()
{
TearDownRenderTimer();
_rendererTimer = new DispatcherTimer();
_rendererTimer.Interval = new TimeSpan(0, 0, 0, 0, _rendererInterval);
_rendererTimer.Tick += new EventHandler(_rendererTimer_Tick);
_rendererTimer.Start();
}
void _rendererTimer_Tick(object sender, EventArgs e)
{
RenderWinformControl();
}
private void TearDownRenderTimer()
{
if (_rendererTimer == null) return;
_rendererTimer.IsEnabled = false;
}
private void RegisterEventHandlers()
{
Window currentWindow = Window.GetWindow(this);
currentWindow.LocationChanged += new EventHandler(delegate(object sender, EventArgs e)
{
PositionInteropFormOverRender();
});
currentWindow.SizeChanged += new SizeChangedEventHandler(delegate(object sender, SizeChangedEventArgs e)
{
PositionInteropFormOverRender();
});
currentWindow.Deactivated += new EventHandler(delegate(object sender, EventArgs e)
{
//_interopForm.Opacity = 0;
});
currentWindow.Activated += new EventHandler(delegate(object sender, EventArgs e)
{
// _interopForm.Opacity = 0.01;
});
currentWindow.StateChanged += new EventHandler(delegate(object sender, EventArgs e)
{
PositionInteropFormOverRender();
});
_interopRenderer.SizeChanged += new SizeChangedEventHandler(delegate(object sender, SizeChangedEventArgs e)
{
PositionInteropFormOverRender();
});
}
private void PositionInteropFormOverRender()
{
if (_interopForm == null) return;
Window currentWindow = Window.GetWindow(this);
Point interopRenderScreenPoint = _interopRenderer.PointToScreen(new Point());
_interopForm.Left = (int)interopRenderScreenPoint.X;
_interopForm.Top = (int)interopRenderScreenPoint.Y;
int width = 0;
if ((int)_interopRenderer.ActualWidth > (int)currentWindow.Width)
{
width = (int)currentWindow.Width;
}
else
{
width = (int)_interopRenderer.ActualWidth;
}
if ((int)currentWindow.Width < width)
width = (int)currentWindow.Width;
_interopForm.Width = width;
}
private void InitializeBitmap()
{
if (_bitmapSource == null)
{
TearDownBitmap();
}
int interopRenderWidth = _winformControl.Width;
int interopRenderHeight = _winformControl.Height;
int bytesPerPixel = 4;
int totalPixels = interopRenderWidth * interopRenderHeight * bytesPerPixel;
byte[] dummyPixels = new byte[totalPixels];
_bitmapSource = BitmapSource.Create(interopRenderWidth,
interopRenderHeight,
96,
96,
PixelFormats.Bgr32,
null,
dummyPixels,
interopRenderWidth * bytesPerPixel);
_interopRenderer.Source = _bitmapSource;
_bitmapSourceBuffer = new BitmapBuffer(_bitmapSource);
_gdiBitmap = new GDI.Bitmap(_winformControl.Width,
_winformControl.Height,
GDI.Imaging.PixelFormat.Format32bppRgb);
_hGDIBitmap = _gdiBitmap.GetHbitmap();
_gdiBitmapGraphics = GDI.Graphics.FromImage(_gdiBitmap);
}
private void TearDownBitmap()
{
_bitmapSource = null;
_bitmapSourceBuffer = null;
if (_gdiBitmap != null)
{
_gdiBitmap.Dispose();
}
if (_gdiBitmapGraphics != null)
{
_gdiBitmapGraphics.Dispose();
}
if (_hGDIBitmap != IntPtr.Zero)
{
DeleteObject(_hGDIBitmap);
}
}
private void InitializeWinformControl()
{
InitializeInteropForm();
InitializeBitmap();
RegisterEventHandlers();
PositionInteropFormOverRender();
_interopForm.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
_interopForm.Show();
InitializeRendererTimer();
}
public Winforms.Control Child
{
get { return _winformControl; }
set
{
_winformControl = value;
InitializeWinformControl();
}
}
private void RenderWinformControl()
{
PaintWinformControl(_gdiBitmapGraphics, _winformControl);
GDI.Rectangle lockRectangle = new GDI.Rectangle(0,
0,
_gdiBitmap.Width,
_gdiBitmap.Height);
GDI.Imaging.BitmapData bmpData = _gdiBitmap.LockBits(lockRectangle,
GDI.Imaging.ImageLockMode.ReadOnly,
GDI.Imaging.PixelFormat.Format32bppRgb);
System.IntPtr bmpScan0 = bmpData.Scan0;
CopyMemory(_bitmapSourceBuffer.BufferPointer,
bmpScan0,
(int)_bitmapSourceBuffer.BufferSize);
_gdiBitmap.UnlockBits(bmpData);
_interopRenderer.InvalidateVisual();
}
private void PaintWinformControl(GDI.Graphics graphics, Winforms.Control control)
{
IntPtr hWnd = control.Handle;
IntPtr hDC = graphics.GetHdc();
PrintWindow(hWnd, hDC, 0);
graphics.ReleaseHdc(hDC);
}
}
}
BitmapBuffer.cs:
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime;
using System.Runtime.InteropServices.ComTypes;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace WPFInterop
{
class BitmapBuffer
{
private BitmapSource _bitmapImage = null;
private object _wicImageHandle = null;
private object _wicImageLock = null;
private uint _bufferSize = 0;
private IntPtr _bufferPointer = IntPtr.Zero;
private uint _stride = 0;
private int _width;
private int _height;
public BitmapBuffer(BitmapSource Image)
{
//Keep reference to our bitmap image
_bitmapImage = Image;
//Get around the STA deal
_bitmapImage.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new System.Windows.Threading.DispatcherOperationCallback(delegate
{
//Cache our width and height
_width = _bitmapImage.PixelWidth;
_height = _bitmapImage.PixelHeight;
return null;
}), null);
//Retrieve and store our WIC handle to the bitmap
SetWICHandle();
//Set the buffer pointer
SetBufferInfo();
}
/// <summary>
/// The pointer to the BitmapImage's native buffer
/// </summary>
public IntPtr BufferPointer
{
get
{
//Set the buffer pointer
SetBufferInfo();
return _bufferPointer;
}
}
/// <summary>
/// The size of BitmapImage's native buffer
/// </summary>
public uint BufferSize
{
get { return _bufferSize; }
}
/// <summary>
/// The stride of BitmapImage's native buffer
/// </summary>
public uint Stride
{
get { return _stride; }
}
private void SetBufferInfo()
{
int hr = 0;
//Get the internal nested class that holds some of the native functions for WIC
Type wicBitmapNativeMethodsClass = Type.GetType("MS.Win32.PresentationCore.UnsafeNativeMethods+WICBitmap, PresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
//Get the methods of all the static methods in the class
MethodInfo[] info = wicBitmapNativeMethodsClass.GetMethods(BindingFlags.Static | BindingFlags.NonPublic);
//This method looks good
MethodInfo lockmethod = info[0];
//The rectangle of the buffer we are
//going to request
Int32Rect rect = new Int32Rect();
rect.Width = _width;
rect.Height = _height;
//Populate the arguments to pass to the function
object[] args = new object[] { _wicImageHandle, rect, 2, _wicImageHandle };
//Execute our static Lock() method
hr = (int)lockmethod.Invoke(null, args);
//argument[3] is our "out" pointer to the lock handle
//it is set by our last method invoke call
_wicImageLock = args[3];
//Get the internal nested class that holds some of the
//other native functions for WIC
Type wicLockMethodsClass = Type.GetType("MS.Win32.PresentationCore.UnsafeNativeMethods+WICBitmapLock, PresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
//Get all the native methods into our array
MethodInfo[] lockMethods = wicLockMethodsClass.GetMethods(BindingFlags.Static | BindingFlags.NonPublic);
//Our method to get the stride value of the image
MethodInfo getStrideMethod = lockMethods[0];
//Fill in our arguments
args = new object[] { _wicImageLock, _stride };
//Execute the stride method
getStrideMethod.Invoke(null, args);
//Grab out or byref value for the stride
_stride = (uint)args[1];
//This one looks perty...
//This function will return to us
//the buffer pointer and size
MethodInfo getBufferMethod = lockMethods[1];
//Fill in our arguments
args = new object[] { _wicImageLock, _bufferSize, _bufferPointer };
//Run our method
hr = (int)getBufferMethod.Invoke(null, args);
_bufferSize = (uint)args[1];
_bufferPointer = (IntPtr)args[2];
DisposeLockHandle();
}
private void DisposeLockHandle()
{
MethodInfo close = _wicImageLock.GetType().GetMethod("Close");
MethodInfo dispose = _wicImageLock.GetType().GetMethod("Dispose");
close.Invoke(_wicImageLock, null);
dispose.Invoke(_wicImageLock, null);
}
private void SetWICHandle()
{
//Get the type of bitmap image
Type bmpType = typeof(BitmapSource);
//Use reflection to get the private property WicSourceHandle
FieldInfo fInfo = bmpType.GetField("_wicSource",
BindingFlags.NonPublic | BindingFlags.Instance);
//Retrieve the WIC handle from our BitmapImage instance
_wicImageHandle = fInfo.GetValue(_bitmapImage);
}
}
}
The InteropForm is just a derived System.Windows.Forms.Form and has no special magic.
Integration into WPF-Page is simple:
<interop:Win32HostRenderer x:Name="_host" Grid.Row="0">
</interop:Win32HostRenderer>
And after window Loaded event:
System.Windows.Forms.WebBrowser browser = new System.Windows.Forms.WebBrowser();
browser.Navigate("http://www.youtube.com");
browser.Width = 700;
browser.Height = 500;
_host.Child = browser;
(code parts from Jeremiah Morrill, see this blog for more info)
Ok, your first problem is with this bit of code:
//Get the methods of all the static methods in the class
MethodInfo[] info = wicBitmapNativeMethodsClass.GetMethods(BindingFlags.Static | BindingFlags.NonPublic);
//This method looks good
MethodInfo lockmethod = info[0];
In .Net 4, the "Lock" method is at index 1 (probably because a new "static" method has been added)...so your reflection code is using the wrong one.
Instead you can just use this to get it by name (suggest altering your other GetMethods to GetMethod):
MethodInfo lockmethod = wicBitmapNativeMethodsClass.GetMethod("Lock", BindingFlags.Static | BindingFlags.NonPublic);
Here it is working (in .NET 4)...I made it fill the client space...as I didn't have your full source code...alter as necessary to do your visual reflection, etc:
The changes I made were:
MethodInfo lockmethod = wicBitmapNativeMethodsClass.GetMethod("Lock", BindingFlags.Static | BindingFlags.NonPublic);
private void PositionInteropFormOverRender()
{
if (_interopForm == null) return;
Window currentWindow = Window.GetWindow(this);
FrameworkElement firstchild = this.Content as FrameworkElement;
if (firstchild != null)
{
Point interopRenderScreenPoint = currentWindow.PointToScreen(new Point());
_interopForm.Left = (int)interopRenderScreenPoint.X;
_interopForm.Top = (int)interopRenderScreenPoint.Y;
_interopForm.Width = (int)firstchild.RenderSize.Width;
_interopForm.Height = (int)firstchild.RenderSize.Height;
}
}
private void _host_Loaded(object sender, RoutedEventArgs e)
{
System.Windows.Forms.WebBrowser browser = new System.Windows.Forms.WebBrowser();
browser.Navigate("http://www.youtube.com");
browser.Width = 700;
browser.Height = 500;
browser.Dock = System.Windows.Forms.DockStyle.Fill;
_host.Child = browser;
}
private void InitializeInteropForm()
{
if (_winformControl == null) return;
if (_interopForm != null)
{
TearDownInteropForm();
}
_interopForm = new InteropForm();
_interopForm.Opacity = 0.5;
_interopForm.Controls.Add(_winformControl);
_interopForm.Width = _winformControl.Width;
_interopForm.Height = _winformControl.Height;
}
There are other things you need to fix/do/be aware of i.e.:
when the screen DPI is not 96dpi, you will have to convert the RenderSize.Width/Height values accordingly (see: How do I convert a WPF size to physical pixels?)
your "browser" window is hidden in the z-order when you drag the main Window...you just need to bring it back to the front.