CreateParams in the Compact Framework - c#

I'm using the .NET Compact Framework and would like to subclass a PictureBox control (in this case to remove the CS_DBLCLKS style from specific instances of the PictureBox control). The code below works on .NET standard, but not the Compact Framework:
using System;
using System.Windows.Forms;
namespace NoDblClick
{
public partial class NoDblClickPicControl : PictureBox
{
private const int CS_DBLCLKS = 0x008;
public NoDblClickPicControl()
{
}
protected override CreateParams CreateParams
{
get
{
// No compile, missing directive or assembly directive
CreateParams cp = base.CreateParams;
cp.ClassStyle &= ~CS_DBLCLKS;
return cp;
}
}
}
}
How do I get this to work on the Compact Framework? Perhaps I can PInvoke the functionality (from coredll.dll say)?

These styles are applied when the window class is created, and to my knowledge cannot be changed on the compact framework. Besides CreateParams, the full framework allows a window handle to be recreated, which also is not possible on the compact framework.
You could manually filter the messages sent to the control, and convert the double click message back to a mouse down message:
public partial class NoDblClickPicControl : PictureBox
{
private const int WM_LBUTTONDBLCLK = 0x0203;
private const int WM_LBUTTONDOWN = 0x0201;
private const int GWL_WNDPROC = -4;
[DllImport("coredll.dll", SetLastError = true)]
private static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, IntPtr newWndProc);
[DllImport("coredll.dll", SetLastError = true)]
private static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
private delegate IntPtr WndProcDelegate(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
private IntPtr prevWndProc;
private WndProcDelegate #delegate;
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
#delegate = new WndProcDelegate(MyWndProc);
prevWndProc = SetWindowLong(Handle, GWL_WNDPROC, Marshal.GetFunctionPointerForDelegate(#delegate));
}
protected override void OnHandleDestroyed(EventArgs e)
{
base.OnHandleDestroyed(e);
SetWindowLong(Handle, GWL_WNDPROC, prevWndProc);
}
private IntPtr MyWndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
{
if (msg == WM_LBUTTONDBLCLK)
{
msg = WM_LBUTTONDOWN;
}
return CallWindowProc(prevWndProc, hWnd, msg, wParam, lParam);
}
}

Related

What do I put for the MouseDevice parameter in a MouseButtonEventArgs Constructor?

I'm creating an app in WPF c# that needs to be able to detect mouse click up and click down events separately. In order to do this, I use code for a Global Mouse Hook that I found online. the only problem with the code was that it used EventArgs as the EventHandler so it passed the same function everytime I sent MouseUp and MouseDown in. To fix this, I used the MouseButtonEventArgs constructor. The rpoblem I'm having now is that the constructor needs 3 parameters: MouseDevice, timestamp, and MouseButton for the constructor to actually work. I have figured out timestamp and MouseButton, but I don't know what to put for MouseDevice. What do I put here to make the constructor work? Here is my low level mousehook class code.
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Input;
namespace KeystrokeDisplay
{
public static class MouseHook
{
public static event MouseEventHandler MouseAction = delegate { };
public static void Start()
{
_hookID = SetHook(_proc);
}
public static void stop()
{
UnhookWindowsHookEx(_hookID);
}
private static LowLevelMouseProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
private static IntPtr SetHook(LowLevelMouseProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_MOUSE_LL, proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam)
{
MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
MouseAction(null, new MouseButtonEventArgs(mouse: ????????, timestamp: 0, button: MouseButton.Left));
}
if (nCode >= 0 && MouseMessages.WM_LBUTTONUP == (MouseMessages)wParam)
{
MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
MouseAction(null, new MouseButtonEventArgs(mouse: ????????, timestamp: 0, button: MouseButton.Left));
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
public const int WH_MOUSE_LL = 14;
public enum MouseMessages
{
WM_LBUTTONDOWN = 0x0201,
WM_LBUTTONUP = 0x0202,
WM_RBUTTONDOWN = 0x0204,
WM_RBUTTONUP = 0x0205
}
[StructLayout(LayoutKind.Sequential)]
private struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
private struct MSLLHOOKSTRUCT
{
public POINT pt;
public uint mouseData;
public uint flags;
public uint time;
public IntPtr dwExtraInfo;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
}
}
How do I fix this? Also, I'm fairly new to c# so I might need some extra help understanding your answer.
I don't see any reason to use MouseEventHandler.
You want to detect mouse click up and click down events separately, so you can create two delegates for mouse click up and click down and pass own event arguments. You are only interested in which mouse button was pressed.
public delegate void MouseUpEventHandler(object sender, MyMouseEventArgs e);
public delegate void MouseDownEventHandler(object sender, MyMouseEventArgs e);
public class MyMouseEventArgs : EventArgs
{
public MouseButton MouseButton { get; }
public MyMouseEventArgs(MouseButton mouseButton)
{
MouseButton = mouseButton;
}
}
Then replace
public static event MouseEventHandler MouseAction = delegate { };
with
public static event MouseUpEventHandler MouseUpAction = delegate { };
public static event MouseDownEventHandler MouseDownAction = delegate { };
In HookCallback invoke MouseDownAction or MouseUpAction.
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam)
{
MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
MouseDownAction(null, new MyMouseEventArgs(MouseButton.Left));
}
if (nCode >= 0 && MouseMessages.WM_LBUTTONUP == (MouseMessages)wParam)
{
MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
MouseUpAction(null, new MyMouseEventArgs(MouseButton.Left));
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}

Trying to be able to click through transparency

I have a filled image on my form in front of everything but most of it is transparant so i'm trying to click through it. I have this:
public class clickThrough
{
[DllImport("user32.dll", EntryPoint = "SetWindowLongW")]
private static extern IntPtr SetWindowLongPtr32(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
[DllImport("user32.dll", EntryPoint = "SetWindowLongPtrW")]
private static extern IntPtr SetWindowLongPtr64(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
private delegate IntPtr WndProcDelegate(IntPtr hWnd, int message, IntPtr wParam, IntPtr lParam);
private static WndProcDelegate SetWindowProc(IntPtr hWnd, WndProcDelegate newWndProc)
{
IntPtr newWndProcPtr = Marshal.GetFunctionPointerForDelegate(newWndProc);
IntPtr oldWndProcPtr;
if (IntPtr.Size == 4)
oldWndProcPtr = SetWindowLongPtr32(hWnd, -4, newWndProcPtr);
else
oldWndProcPtr = SetWindowLongPtr64(hWnd, -4, newWndProcPtr);
return (WndProcDelegate)Marshal.GetDelegateForFunctionPointer(oldWndProcPtr, typeof(WndProcDelegate));
}
}
private void guna2PictureBox1_Click(object sender, EventArgs e)
{
int initialStyle = SetWindowLongPtrW(this.Handle, -20);
SetWindowLongPtrW(this.Handle, -20, initialStyle | 0x80000 | 0x20);
}
I get this error: The name 'SetWindowLongPtrW' does not exist in the current context

WinForms equivalent of WPF WindowInteropHelper, HwndSource, HwndSourceHook

I have a block of code like:
IntPtr hWnd = new WindowInteropHelper(this).Handle;
HwndSource source = HwndSource.FromHwnd(hWnd);
source.AddHook(new HwndSourceHook(WndProc));
NativeMethods.PostMessage((IntPtr)NativeMethods.HWND_BROADCAST, NativeMethods.WM_CALL, IntPtr.Zero, IntPtr.Zero);
This was originally in a WPF application. However, I need to replicate the functionality in a WinForms application. Also, NativeMethods.PostMessage just maps to user32.dll PostMessage:
[DllImport("user32")]
public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
Are there a 1 to 1 equivalents of WindowInteropHelper/HwndSource/HwndSourceHook that I can use in my WinForms applications?
The basic point is: you don't need anything except AddHook from your source. Each WinForm has a method GetHandle() which will give you the handle of the Window/Form (and you found PostMessage already by yourself).
Too translate AddHook you either write your own class implementing IMessageFilter (1) or you override WndProc() (2).
(1) will receive messages application-wide, regardless to which form you send them while (2) only receives messages for the specific form overriding the method.
I could'nt find anything regarding WM_CALL, as you have to specify the window message as an integer (usually in hex), so this is up to you.
(1):
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
public partial class Form1 : Form
{
[DllImport("user32")]
public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
//private const int WM_xxx = 0x0;
//you have to know for which event you wanna register
public Form1()
{
InitializeComponent();
IntPtr hWnd = this.Handle;
Application.AddMessageFilter(new MyMessageFilter());
PostMessage(hWnd, WM_xxx, IntPtr.Zero, IntPtr.Zero);
}
}
class MyMessageFilter : IMessageFilter
{
//private const int WM_xxx = 0x0;
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == WM_xxx)
{
//code to handle the message
}
return false;
}
}
(2):
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
public partial class Form 1 {
[DllImport("user32")]
public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
//private const int WM_xxx = 0x0;
//you have to know for which event you wanna register
public Form1()
{
InitializeComponent();
IntPtr hWnd = this.Handle;
PostMessage(hWnd, WM_xxx, IntPtr.Zero, IntPtr.Zero);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == WMK_xxx)
{
//code to handle the message
}
}
}
Am not more of WPF background. but for me it sounds like you're looking for NativeWindow.

The instructions at 0xXXXXXXXX referenced memory at 0xXXXXXXXX, The memory could not be written

I get this error when trying to implement a windows hook using SetWindowsHookEx and CallWndProc. I'm wondering if i implemented the hook correctly. Here is the code: This code will work as a keyboard hook if its replaced with LowLevelKeyboardProc
[DllImport("user32.dll")]
static extern IntPtr SetWindowsHookEx(int idHook, CallWndProc callback, IntPtr hInstance, uint threadId);
[DllImport("user32.dll")]
static extern bool UnhookWindowsHookEx(IntPtr hInstance);
[DllImport("user32.dll")]
static extern IntPtr CallNextHookEx(IntPtr idHook, int nCode, int wParam, IntPtr lParam);
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string lpFileName);
private delegate IntPtr CallWndProc(int nCode, IntPtr wParam, IntPtr lParam);
const int WH_CALLWNDPROC = 4;
const int WM_PASTE = 0x302;
private CallWndProc _proc = hookProc;
private static IntPtr hhook = IntPtr.Zero;
public void SetHook()
{
IntPtr hInstance = LoadLibrary("User32");
hhook = SetWindowsHookEx(WH_CALLWNDPROC, _proc, hInstance, 0);
}
public static void UnHook()
{
UnhookWindowsHookEx(hhook);
}
public static IntPtr hookProc(int code, IntPtr wParam, IntPtr lParam)
{
if (code >= 0 && wParam == (IntPtr)WM_PASTE)
{
MessageBox.Show("Paste");
return (IntPtr)1;
}
else
return CallNextHookEx(hhook, code, (int)wParam, lParam);
}
private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
UnHook();
}
private void Form1_Load(object sender, EventArgs e)
{
SetHook();
}
The module handle passed to SetWindowsHookEx should be the handle for your dll, not "user32".

Subclassing a external window in C# .NET

I'm trying to subclass an external window in C#.
I have used something similar before in VB6 without any problem BUT the below code just won't work. Can anybody help me out?
//API
[DllImport("user32")]
private static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, IntPtr newProc);
[DllImport("user32")]
private static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, WinProc newProc);
[DllImport("user32.dll")]
private static extern IntPtr DefWindowProc(IntPtr hWnd, int uMsg, int wParam, int lParam);
[DllImport("user32")]
private static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, int Msg, int wParam, int lParam);
private delegate IntPtr WinProc(IntPtr hWnd, int Msg, int wParam, int lParam);
private const int GWL_WNDPROC = -4;
private enum winMessage : int
{
WM_GETMINMAXINFO = 0x024,
WM_ENTERSIZEMOVE = 0x231,
WM_EXITSIZEMOVE = 0x232
}
private WinProc newWndProc = null;
private IntPtr oldWndProc = IntPtr.Zero;
private IntPtr winHook = IntPtr.Zero;
//Implementation
public void hookWindow(IntPtr winHandle)
{
if (winHandle != IntPtr.Zero)
{
winHook = winHandle;
newWndProc = new WinProc(newWindowProc);
oldWndProc = SetWindowLong(winHook, GWL_WNDPROC,newWndProc);
}
}
public void unHookWindow()
{
if (winHook != IntPtr.Zero)
{
SetWindowLong(winHook, GWL_WNDPROC, oldWndProc);
winHook = IntPtr.Zero;
}
}
private IntPtr newWindowProc(IntPtr hWnd, int Msg, int wParam, int lParam)
{
switch (Msg)
{
case (int)winMessage.WM_GETMINMAXINFO:
MessageBox.Show("Moving");
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
ok im done with the coding, but in your solution you have to have your form solution and a dll solution and it can work, if you want that code let me know. but you cannot subclass within a same exe. so it can all be done in c# but you do need that dll, when i got down to converting my c++ project
all because of
BOOL WINAPI DllMain(HANDLE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )
{
switch(fdwReason)
{
case DLL_PROCESS_ATTACH:
{
hInstance=(HINSTANCE)hinstDLL;
}
break;
case DLL_PROCESS_DETACH:
{
if((int)hndll>1)
{
SetWindowLong(hndll,GWL_WNDPROC,OldWndHndl); //Set back the old window procedure
return 1;
}
}
}
}
It's impossible with C#. Only unmanaged C/C++ can do it..
oldWndProc = SetWindowLong(winHook, GWL_WNDPROC,newWndProc); will always return 0(which means failed) if winHook is from another process.
Reference: https://social.msdn.microsoft.com/Forums/vstudio/en-US/8dd657b5-647b-443b-822d-ebe03ca4033c/change-wndproc-of-another-process-in-c

Categories

Resources