C# WPF WndProc Message capture not working - c#

I am working with a Finger Print Sensor by ZkTeco. The below code in WFA works fine and the input from Finger Print Sensor is captured successfully.
protected override void DefWndProc(ref Message m)
{
switch (m.Msg)
{
case MESSAGE_CAPTURED_OK:
{
MemoryStream ms = new MemoryStream();
BitmapFormat.GetBitmap(FPBuffer, mfpWidth, mfpHeight, ref ms);
Bitmap bmp = new Bitmap(ms);
this.picFPImg.Image = bmp;
if (IsRegister)
{
// Logic here
}
}
}
default:
base.DefWndProc(ref m);
break;
}
But the alternative in WPF below code doesn't work.
HwndSource source;
protected override void OnSourceInitialized(EventArgs e)
{
var window = Application.Current.MainWindow;
base.OnSourceInitialized(e);
if (window != null)
{
HwndSource source = PresentationSource.FromVisual(window) as HwndSource;
source?.AddHook(WndProc);
}
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch (msg)
{
case MESSAGE_CAPTURED_OK:
{
MemoryStream ms = new MemoryStream();
BitmapFormat.GetBitmap(FPBuffer, mfpWidth, mfpHeight, ref ms);
}
}
}
While Debugging the function is being called but the Switch statement MESSAGE_CAPTURED_OK never becomes true. What could be the reason ?

Related

How to record while the window is not active?

I am making a recorder that records a specific window the user chooses. While I am recording, the program forces the window to be active all the time. It does not let me minimize it or even move it. It forced me to use alt + f4(that kills the active window) because I was not able to stop the recording. Is there a way to fix that?
Combobox code:
private void Handlebox_SelectedIndexChanged(object sender, EventArgs e)
{
if (Handlebox.SelectedIndex == 0)
{
handle_name = Handlebox.Items[0].ToString();
}
else if (Handlebox.SelectedIndex == 1)
{
handle_name = Handlebox.Items[1].ToString();
}
else if (Handlebox.SelectedIndex == 2)
{
handle_name = Handlebox.Items[2].ToString();
}
else if (Handlebox.SelectedIndex == 3)
{
handle_name = Handlebox.Items[3].ToString();
}
else if (Handlebox.SelectedIndex == 4)
{
handle_name = Handlebox.Items[4].ToString();
}
else if (Handlebox.SelectedIndex == 5)
{
handle_name = Handlebox.Items[5].ToString();
}
}
The way I add all the processes in the combobox:
foreach (Process process in processlist)
{
if (!String.IsNullOrEmpty(process.MainWindowTitle))
{
Handlebox.Items.Add(process.ProcessName);
}
}
The script that the whole recording takes place:
// Record video:
[StructLayout(LayoutKind.Sequential)]
public struct Rect
{
public int left;
public int top;
public int right;
public int bottom;
}
[DllImport("user32.dll")]
private static extern int SetForegroundWindow(IntPtr hWnd);
private const int SW_RESTORE = 9;
[DllImport("user32.dll")]
private static extern IntPtr ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll")]
public static extern IntPtr GetWindowRect(IntPtr hWnd, ref Rect rect);
public Bitmap CaptureApplication(string procName)
{
Process proc;
// Cater for cases when the process can't be located.
try
{
proc = Process.GetProcessesByName(procName)[0];
}
catch (IndexOutOfRangeException e)
{
return null;
}
// You need to focus on the application
SetForegroundWindow(proc.MainWindowHandle);
ShowWindow(proc.MainWindowHandle, SW_RESTORE);
// Delay
Thread.Sleep(1000);
Rect rect = new Rect();
IntPtr error = GetWindowRect(proc.MainWindowHandle, ref rect);
// sometimes it gives error.
while (error == (IntPtr)0)
{
error = GetWindowRect(proc.MainWindowHandle, ref rect);
}
int width = rect.right - rect.left;
int height = rect.bottom - rect.top;
Bitmap bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb);
Graphics.FromImage(bmp).CopyFromScreen(rect.left,rect.top,0,0,new Size(width, height),CopyPixelOperation.SourceCopy);
return bmp;
}
public void RecordVideo()
{
// Keep track of time:
watch.Start();
// Save screenshot:
string name = tempPath + "//screenshot-" + fileCount + ".png";
CaptureApplication(handle_name).Save(name, ImageFormat.Png);
inputImageSequence.Add(name);
fileCount++;
// Dispose of bitmap:
CaptureApplication(handle_name).Dispose();
}
Apologies for the brevity and style of this reply; I'm currently on mobile.
Could you express your combobox event handler as:
private void Handlebox_SelectedIndexChanged(object sender, EventArgs e)
{
if (Handlebox.SelectedIndex == -1) return;
handle_name = Handlebox.SelectedItem.ToString();
}
I'm not sure what exactly you want this application to do eventually, but If all you want is to gracefully exit, I would look into registering an event handler that watches for a key combination, and stops and saves the recording when it is pressed. I can't easily type out how to do that, but some concerted googling should help you.

How do I replace the icon on the title bar on a win 10 form

I am trying to replace the icon of a win form with a larger .png
Whether i try to draw a rectangle or load the image; i am not getting anything in the title bar.
I am using visual studio 2019 on a win 64 bit.
The code below is what i am using.
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace WindowsFormsApp8
{
public partial class Form1 : Form
{
public const uint WM_NCPAINT = 0x85;
[DllImport("user32.dll")]
private static extern IntPtr GetWindowDC(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
public Form1()
{
InitializeComponent();
this.ShowIcon = false;
this.Text = String.Empty;
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == WM_NCPAINT)
{
IntPtr dc = GetWindowDC(m.HWnd);
try
{
using (Graphics g = Graphics.FromHdc(dc))
{
//Rectangle rect = new Rectangle(0, 0, 30, 20);
//g.FillRectangle(Brushes.Blue, rect);
//g.Flush();
g.DrawImage(Bitmap.FromFile("C:\\Picture1.png"), new Point(0, 0));
}
}
finally
{
ReleaseDC(m.HWnd, dc);
}
}
}
}
}
This is what I want to achieve.1
Appreciate any help
Accordin the WM_NCPAINT:
Return value: An application returns zero if it processes this message.
If you have processed WM_NCPAINT, you cannot call the default WndProc
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_NCPAINT)
{
IntPtr dc = GetWindowDC(m.HWnd);
try
{
using (Graphics g = Graphics.FromHdc(dc))
{
//Rectangle rect = new Rectangle(0, 0, 30, 20);
//g.FillRectangle(Brushes.Blue, rect);
//g.Flush();
g.DrawImage(Bitmap.FromFile("C:\\head.png"), new Point(0, 0));
InvalidateRect(m.HWnd, IntPtr.Zero, 0);
}
}
finally
{
ReleaseDC(m.HWnd, dc);
}
}
else
base.WndProc(ref m);
}
But you need to draw other things yourself, such as system buttons.
As comments, you could create your custom window with the document.
Removing the Standard Frame with WM_NCCALCSIZE:
Starting with Windows Vista, removing the standard frame by simply
returning 0 when the wParam is TRUE
if (m.Msg == WM_NCPAINT)
{
...
}
else if (m.Msg == WM_NCCALCSIZE)
{
if(m.WParam == IntPtr.Zero)
base.WndProc(ref m);
}
else
base.WndProc(ref m);
This will remove the standard frame, and disable hitting, resizing and moving. The sample you can use HitTestNCA in the doc to enable them.
Finally, try to draw the title icon in PaintCustomCaption function.
Or you could try this Customized Form sample answer by #Aland Li.

Custom WndProc doesn't stop resizing

I made a form that handles WM_CREATE, WM_ACTIVATE, WM_NCCALCSIZE and WM_NCHITTEST. It also overrides the paint method.
The problem is when I resize the form it doesn't stop resizing. I tried to compare the messages with a working window but spy++ keeps crashing.
Here is my WndProc code:
protected override void WndProc(ref Message m)
{
IntPtr result = IntPtr.Zero;
bool callDWP = !Win32Interop.DwmDefWindowProc(m.HWnd, m.Msg, m.WParam, m.LParam, out result);
switch (m.Msg)
{
case Win32Messages.WM_CREATE:
{
int style = Win32Interop.GetWindowLong(m.HWnd, Win32Constants.GWL_STYLE);
int styleEx = Win32Interop.GetWindowLong(m.HWnd, Win32Constants.GWL_EXSTYLE);
Win32Interop.AdjustWindowRectEx(out RECT rc, style, false, styleEx);
}
break;
case Win32Messages.WM_ACTIVATE:
{
MARGINS margins = new MARGINS
{
cxLeftWidth = Math.Abs(BorderLeft),
cxRightWidth = Math.Abs(BorderRight),
cyBottomHeight = Math.Abs(BorderBottom),
cyTopHeight = Math.Abs(BorderTop)
};
int hr = Win32Interop.DwmExtendFrameIntoClientArea(m.HWnd, ref margins);
result = IntPtr.Zero;
}
break;
case Win32Messages.WM_NCCALCSIZE:
{
if (m.WParam != IntPtr.Zero)
{
result = IntPtr.Zero;
callDWP = false;
}
}
break;
case Win32Messages.WM_NCHITTEST:
{
{
int ht = DoHitTest(m);
Console.WriteLine(ht);
if (callDWP)
{
callDWP = (ht == Win32Constants.HTNOWHERE);
result = new IntPtr(ht);
}
}
break;
}
default:
{
base.WndProc(ref m);
break;
}
}
m.Result = result;
if (callDWP)
{
base.WndProc(ref m);
}
}
Don't call base.WndProc(ref m); in default

Embed Unity3D app inside WPF page causes process name to disappear after navigating to new page

I am using the code posted in this question with some minor changes:
Embed Unity3D app inside WPF *without* having it take up the whole window
This approach worked great, but when I am looking at my task manager processes. My main WPF executable name is removed from the process when I exit the page running the unity player and load another page. The application still works just fine. Task Manager just shows an icon with no process name next to it. This is only an issue because I have another background service that monitor my WPF application and starts and stops it remotely based on its name. Any suggestion?
Page Code Shown Below.
public System.Windows.Forms.Integration.WindowsFormsHost host = new System.Windows.Forms.Integration.WindowsFormsHost();
[DllImport("User32.dll")]
static extern bool MoveWindow(IntPtr handle, int x, int y, int width, int height, bool redraw);
internal delegate int WindowEnumProc(IntPtr hwnd, IntPtr lparam);
[DllImport("user32.dll")]
internal static extern bool EnumChildWindows(IntPtr hwnd, WindowEnumProc func, IntPtr lParam);
[DllImport("user32.dll")]
static extern int SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
private Process process;
private IntPtr unityHWND = IntPtr.Zero;
private const int WM_ACTIVATE = 0x0006;
private readonly IntPtr WA_ACTIVE = new IntPtr(1);
private readonly IntPtr WA_INACTIVE = new IntPtr(0);
System.Windows.Threading.DispatcherTimer dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
bool initialized = false;
public UnityPlayer()
{
InitializeComponent();
if (this.grid1.Children.Count == 0)
{
this.grid1.Children.Add(host);
}
dispatcherTimer.Tick += attemptInit;
dispatcherTimer.Interval = new TimeSpan(0, 0, 1);
dispatcherTimer.Start();
}
void attemptInit(object sender, EventArgs e)
{
if (process != null)
{
if (process.HasExited)
{
Thread.Sleep(1000);
FSC.GoHome();
}
}
if (initialized)
return;
HwndSource source = (HwndSource)HwndSource.FromVisual(host);
Console.WriteLine("attempting to get handle...");
if (source == null)
{
Console.WriteLine("Failed to get handle source");
return;
}
IntPtr hWnd = source.Handle;
try
{
process = new Process();
process.StartInfo.FileName = "Block Breaker.exe";
process.StartInfo.Arguments = "-parentHWND " + hWnd.ToInt32() + " " + Environment.CommandLine;
process.StartInfo.UseShellExecute = true;
process.StartInfo.CreateNoWindow = true;
process.Start();
process.WaitForInputIdle();
// Doesn't work for some reason ?!
//unityHWND = process.MainWindowHandle;
EnumChildWindows(host.Handle, WindowEnum, IntPtr.Zero);
//unityHWNDLabel.Text = "Unity HWND: 0x" + unityHWND.ToString("X8");
Console.WriteLine("Unity HWND: 0x" + unityHWND.ToString("X8"));
panel1_Resize(this, EventArgs.Empty);
initialized = true;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + ".\nCheck if Container.exe is placed next to UnityGame.exe.");
}
}
private void ActivateUnityWindow()
{
SendMessage(unityHWND, WM_ACTIVATE, WA_ACTIVE, IntPtr.Zero);
}
private void DeactivateUnityWindow()
{
SendMessage(unityHWND, WM_ACTIVATE, WA_INACTIVE, IntPtr.Zero);
}
private int WindowEnum(IntPtr hwnd, IntPtr lparam)
{
unityHWND = hwnd;
ActivateUnityWindow();
return 0;
}
private void panel1_Resize(object sender, EventArgs e)
{
MoveWindow(unityHWND, 0, 0, (int)host.Width, (int)host.Height, true);
Console.WriteLine("RESIZED UNITY WINDOW TO: " + (int)host.Width + "x" + (int)host.Height);
ActivateUnityWindow();
}
private void Page_Unloaded(object sender, RoutedEventArgs e)
{
dispatcherTimer.Stop();
dispatcherTimer = null;
host.Dispose();
}
Image Show Process Before the pages loads
Image show Process While the page is running
Image show Process After the pages exits and loads new page

WinApi - override GetMessage loop in WH_GETMESSAGE hook

I have implemented standard Win32 MDI window with following message loop:
MSG msg;
while (NativeMethods.GetMessage(out msg, this.handle, 0, 0) > 0)
{
if (!NativeMethods.TranslateMDISysAccel(this.mdiClientHandle, ref msg))
{
NativeMethods.TranslateMessage(ref msg);
NativeMethods.DispatchMessage(ref msg);
}
}
}
I am trying to override this message loop by using WH_GETMESSAGE hook. The hook is set correctly and works.
private static IntPtr MyGetMessageHook(int code, IntPtr wparam, IntPtr lparam)
{
if (code == 0)
{
MSG msg = (MSG)Marshal.PtrToStructure(lparam, typeof(MSG));
Debug.WriteLine(msg.message);
// Execute GetMessage loop logic.
if (!NativeMethods.TranslateMDISysAccel(MyMdiWindow.MdiClientHandle, ref msg))
{
NativeMethods.TranslateMessage(ref msg);
NativeMethods.DispatchMessage(ref msg);
}
// Set msg fields to 0.
msg.message = 0;
msg.hwnd = IntPtr.Zero;
msg.lParam = IntPtr.Zero;
msg.wParam = IntPtr.Zero;
Marshal.StructureToPtr(msg, lparam, true);
}
return new IntPtr(NativeMethods.CallNextHookEx(IntPtr.Zero, code, wparam, lparam));
}
The code in hook procedure executes, but I don't know why window doesn't respond. msg.message is being set to 0 after dispatching it. What happens with message after calling DispatchMessage?

Categories