How to Position my WPF Window exactly on top of Notepad? - c#

I am trying to show a WPF form as pop up over a Notepad and the Pop window has to be at the same position and size of the Notepad. I am trying the below code and the code works fine if my Screen Resolution Scale is 100%.
If it is not equal to 100%, I am not getting the exact position, the window misaligns.
I have tried the below code, it works just fine if my screen resolution scale is 100%
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
About about = new About();
RECT r = new RECT();
Process [] notepads=Process.GetProcessesByName("notepad");
if(notepads.Length==0)return;
if (notepads[0] != null)
{
IntPtr child= FindWindowEx(notepads[0].MainWindowHandle, new IntPtr(0), "Edit", null);
if (GetWindowRect(child, ref r))
{
about.Top = r.Top;
about.Left = r.Left;
}
}
about.ShowDialog();

Related

An image who is sometimes rendered, sometimes not

I'm creating a console app game and I would like to display some images on the screen. So, I found some tricks on google and I created that script to display an image :
[DllImport("user32.dll")] public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll", SetLastError = true)] public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
[DllImport("kernel32.dll", EntryPoint = "GetConsoleWindow", SetLastError = true)] private static extern IntPtr GetConsoleHandle();
private static void ShowImage(string filePath, int posX, int posY)
{
Image img = Image.FromFile(filePath);
var form = new Form
{
FormBorderStyle = FormBorderStyle.None
};
var parent = GetConsoleHandle();
var child = form.Handle;
SetParent(child, parent);
MoveWindow(child, 50, 50, img.Width, img.Height, true);
form.Paint += delegate (object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
Rectangle rc = new Rectangle(new Point(0, 0), img.Size);
g.DrawImage(img, form.ClientRectangle, rc, GraphicsUnit.Pixel);
};
Application.Run(form);
}
My problem is that, sometimes, I don't know why, my image doesn't appear ! And it's random, not 1 time on 2 or something like that !
Note : I use this code to display a png image
So, if someone know were is the problem, I'm ready to take notes :)

How do i use SetWindowPos to center a window?

What I want to do is to bring the handle to the front and to the center of the screen. Bring it to the front I know how to do i'm using SetForegroundWindow(IntPtr hWnd); and it's working fine. But how do I use the SetWindowPos to force to be in the center of the screen ?
IntPtr handle = process.MainWindowHandle;
if (handle != IntPtr.Zero)
{
SetWindowPos(handle, 0, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW);
}
Then when I call in the constructor for example to SetWindowPos what should I give it ? handle is fine I know what it should be. But all the resr 0,0,0,0,0,0 and what should be the values fro SWP_NOZORDER and SWP_NOSIZE ?
Before you can center it, first you must know how big it is. This can be accomplished with the GetWindowRect() API. After that it's simply a matter of calculating the center position taking into account the size of the screen:
public partial class Form1 : Form
{
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left; // x position of upper-left corner
public int Top; // y position of upper-left corner
public int Right; // x position of lower-right corner
public int Bottom; // y position of lower-right corner
}
private const int SWP_NOSIZE = 0x0001;
private const int SWP_NOZORDER = 0x0004;
private const int SWP_SHOWWINDOW = 0x0040;
[DllImport("user32.dll", SetLastError=true)]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags);
Process process;
public Form1()
{
InitializeComponent();
process = Process.GetProcessesByName("calc").FirstOrDefault();
}
private void button1_Click(object sender, EventArgs e)
{
if (process == null)
return;
IntPtr handle = process.MainWindowHandle;
if (handle != IntPtr.Zero)
{
RECT rct;
GetWindowRect(handle, out rct);
Rectangle screen = Screen.FromHandle(handle).Bounds;
Point pt = new Point(screen.Left + screen.Width / 2 - (rct.Right - rct.Left) / 2, screen.Top + screen.Height / 2 - (rct.Bottom - rct.Top) / 2);
SetWindowPos(handle, IntPtr.Zero, pt.X, pt.Y, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW);
}
}
}

How to reserve a row for input in multi-threaded Console?

This question has bugged me for a while now, and I realize it's hard to describe what I am looking for. I want to be able to reserve a row for text input in a C# Console Application, while still allowing other information to be updated in the remaining rows. More specifically, I'd like to make a small mud game where the game is updated even while the user is busy making input. It's important that the input doesn't block the information flow.
I'd like to achieve the effect of the user writing input to the last visible row in the screen, while the other text append as usual, but not scrolling down my line of input, nor overwrite it.
If I would describe this in terms of Forms, I'd imagine the equivalent of having a multi-line textbox as the upper portion for the information, with a single-line textbox at the bottom for the input.
One option that you could try, is to directly manipulate the console buffer to render your game area and use the Console.SetCursorPosition to position the cursor to the input line where you use Console.ReadLine for example to take the user input.
Since the direct manipulation of the buffer does not affect the cursor position and is independent of the Console Read/Write functionality you can have a thread updating the Console buffer which covers the first 24 lines and the 25 line is waiting for input. If I get some time I will try put together a sample of what I mean, but in the meantime you can reference the other answers I have provided for a pointer to writing directly to the Console buffer.
How can I write fast colored output to Console?
Deleting previously written lines in Console
Of course you will want to write some nice wrapper functions to make this easy to work with, I always think about doing this, I just don't do enough work with the console so that I actually get down and do something.
Update: Added a small example of updating the console in a thread while still accepting user input. Just type 'quit' to stop it running. Note the the ConsoleBuffer class is not ideal, I am not closing the console handle, it was just a quick piece of code for the demo.
using System;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
using System.Threading;
namespace ConsoleDemo
{
class Program
{
static void Main(string[] args)
{
Thread t = new Thread(new ThreadStart(UpdateConsole));
t.IsBackground=true;
t.Start();
string input;
do
{
Console.SetCursorPosition(0, 23);
Console.Write("Command: ");
input = Console.ReadLine();
ConsoleBuffer.ClearArea(0, 21, 80, 3);
Console.SetCursorPosition(0, 22);
Console.Write(input);
} while (!string.Equals(input, "quit", StringComparison.OrdinalIgnoreCase));
}
static void UpdateConsole()
{
int i = 0;
Random rnd = new Random();
while (true)
{
string s = new string((char)(65 + (i % 26)),1);
for (short x = 0; x < 80; ++x)
{
for (short y = 0; y < 20; ++y)
{
ConsoleBuffer.WriteAt(x, y, s);
ConsoleBuffer.SetAttribute(x, y, (short)(rnd.Next(15)+1));
}
}
Thread.Sleep(500);
i++;
}
}
}
public class ConsoleBuffer
{
private static SafeFileHandle _hBuffer = null;
static ConsoleBuffer()
{
_hBuffer = CreateFile("CONOUT$", 0x40000000, 2, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero);
if (_hBuffer.IsInvalid)
{
throw new Exception("Failed to open console buffer");
}
}
public static void WriteAt(short x, short y, string value)
{
int n = 0;
WriteConsoleOutputCharacter(_hBuffer, value, value.Length, new Coord(x, y), ref n);
}
public static void SetAttribute(short x, short y, short attr)
{
SetAttribute( x, y, new short[] { attr });
}
public static void SetAttribute(short x, short y, short[] attrs)
{
int n = 0;
WriteConsoleOutputAttribute(_hBuffer, attrs, attrs.Length, new Coord(x, y), ref n);
}
public static void ClearArea(short left, short top, short width, short height, char ch = ' ')
{
ClearArea(left, top, width, height, new CharInfo() { Char = new CharUnion() { UnicodeChar = ch } });
}
public static void ClearArea(short left, short top, short width, short height)
{
ClearArea(left, top, width, height, new CharInfo() { Char = new CharUnion() { AsciiChar = 32 } });
}
private static void ClearArea(short left, short top, short width, short height, CharInfo charAttr)
{
CharInfo[] buf = new CharInfo[width * height];
for (int i = 0; i < buf.Length; ++i)
{
buf[i] = charAttr;
}
SmallRect rect = new SmallRect() { Left = left, Top = top, Right = (short)(left + width), Bottom = (short)(top + height) };
WriteConsoleOutput(_hBuffer, buf,
new Coord() { X = width, Y = height },
new Coord() { X = 0, Y = 0 },
ref rect);
}
[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)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool WriteConsoleOutput(
SafeFileHandle hConsoleOutput,
CharInfo[] lpBuffer,
Coord dwBufferSize,
Coord dwBufferCoord,
ref SmallRect lpWriteRegion);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool WriteConsoleOutputCharacter(
SafeFileHandle hConsoleOutput,
string lpCharacter,
int nLength,
Coord dwWriteCoord,
ref int lpumberOfCharsWritten);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool WriteConsoleOutputAttribute(
SafeFileHandle hConsoleOutput,
short[] lpAttributes,
int nLength,
Coord dwWriteCoord,
ref int lpumberOfAttrsWritten);
[StructLayout(LayoutKind.Sequential)]
struct Coord
{
public short X;
public short Y;
public Coord(short X, short Y)
{
this.X = X;
this.Y = Y;
}
};
[StructLayout(LayoutKind.Explicit)]
struct CharUnion
{
[FieldOffset(0)]
public char UnicodeChar;
[FieldOffset(0)]
public byte AsciiChar;
}
[StructLayout(LayoutKind.Explicit)]
struct CharInfo
{
[FieldOffset(0)]
public CharUnion Char;
[FieldOffset(2)]
public short Attributes;
}
[StructLayout(LayoutKind.Sequential)]
struct SmallRect
{
public short Left;
public short Top;
public short Right;
public short Bottom;
}
}
}
The dotNet Console supports SetCursorPosition() and you also use the old DOS trick of ending a line with \r instead of \n\r.
But multi-threading and Append doesn't sound like a good combination.
Look at these .NET bindings for curses
http://www.mono-project.com/Libraries#Curses
ncurses is obviously a UNIX invention, but the API's are said to be mostly cross-platform (I haven't tried the .NET bindings myself, but have had very good results working with ncurses in general).
This will absolutely contain the goods you need and more

Drawing Window to Image file

Anyone know why this keeps returning a blank image? I found this function here.
I pass in a handle to a notepad process/window.
public static Image DrawToBitmap(IntPtr handle)
{
Bitmap image = new Bitmap(500, 500, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
using (Graphics graphics = Graphics.FromImage(image))
{
IntPtr hDC = graphics.GetHdc();
SendMessage(new HandleRef(graphics, handle), WM_PRINT, hDC, PRF_CHILDREN);
graphics.ReleaseHdc(hDC);
}
return image;
}
I make use of the above like so:
Image myimage = DrawToBitmap(handle);
myimage.Save("C:\\here.png", ImageFormat.Png);
Thanks all for any help
Update
I think I have managed to get the error code from SendMessage using the below:
if (SendMessage(handle, WM_PRINT, hDC, PRF_CLIENT))
{
Console.WriteLine("Success!");
}
else
{
Console.WriteLine("Error: " + Marshal.GetLastWin32Error());
}
I get an error of 8 and I found it means not enough memory? I have over 500MB free! Maybe I am understanding this wrong?
Instead of SendMessage you could just use PrintWindow
Here is a sample
public static Image DrawToBitmap(IntPtr handle)
{
RECT rect = new RECT();
GetWindowRect(handle, ref rect);
Bitmap image = new Bitmap(rect.Right - rect.Left, rect.Bottom - rect.Top);
using (Graphics graphics = Graphics.FromImage(image))
{
IntPtr hDC = graphics.GetHdc();
PrintWindow(new HandleRef(graphics, handle), hDC, 0);
graphics.ReleaseHdc(hDC);
}
return image;
}
#region Interop
[DllImport("USER32.DLL")]
private static extern bool PrintWindow(HandleRef hwnd, IntPtr hdcBlt, int nFlags);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
#endregion
Try passing PRF_CLIENT or PRF_NONCLIENT to SendMessage in addition to PRF_CHILDREN.
Also, how are you deriving the handle that you are passing to the function?

Simulating mouse move in Math Input Panel (Windows 7)

I would like to compare my application for handwritten mathematical symbols recognition with the Math Input Panel (MIP) contained in Windows 7. I have a library of recorded mouse strokes representing different mathematical formulas and I need to send them to the MIP to measure its performance.
I tried to simulate mouse move but it's not working.
Here are constants and imported methods that I use:
const UInt32 MOUSEEVENTF_LEFTDOWN = 0x0002;
const UInt32 MOUSEEVENTF_LEFTUP = 0x0004;
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
static extern void mouse_event(UInt32 dwFlags, UInt32 dx, UInt32 dy, UInt32 dwData, UIntPtr dwExtraInfo);
And that's the code itself:
IntPtr windowHandle = FindWindow("MathInput_Window", "");
SetForegroundWindow(windowHandle);
Cursor.Position = new Point(600, 700);
mouse_event(MOUSEEVENTF_LEFTDOWN, 600, 700, 0, UIntPtr.Zero);
for (int x = 600; x <= 650; x++)
{
Cursor.Position = new Point(x, 700);
}
for (int y = 700; y <= 750; y++)
{
Cursor.Position = new Point(650, y);
}
mouse_event(MOUSEEVENTF_LEFTUP, 650, 750, 0, UIntPtr.Zero);
But the only thing i get is a single dot at the position [600,700]. The funny thing is that when I use MSPaint instead of MIP everything is working perfectly.
Does anyone have some idea how it could be solved?
I have already solved the problem using the following function:
[DllImport("user32.dll", SetLastError = true)]
static extern uint SendInput(uint nInputs, ref INPUT pInputs, int cbSize);
I call it to control both mouse button clicks and mouse moves and it works perfectly.

Categories