IntPtr WndProc no suitable method found to override c# - c#

i was trying to override this WndProc in my win form application but got error IntPtr WndProc no suitable method found to override. my code as follows
protected override IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == NativeCalls.APIAttach && (uint)lParam == NativeCalls.SKYPECONTROLAPI_ATTACH_SUCCESS)
{
// Get the current handle to the Skype window
NativeCalls.HWND_BROADCAST = wParam;
handled = true;
return new IntPtr(1);
}
// Skype sends our program messages using WM_COPYDATA. the data is in lParam
if (msg == NativeCalls.WM_COPYDATA && wParam == NativeCalls.HWND_BROADCAST)
{
COPYDATASTRUCT data = (COPYDATASTRUCT)Marshal.PtrToStructure(lParam, typeof(COPYDATASTRUCT));
StatusTextBox.Items.Add(data.lpData + Environment.NewLine);
// Check for connection
//if (data.lpData.IndexOf("CONNSTATUS ONLINE") > -1)
// ConnectButton.IsEnabled = false;
// Check for calls
IsCallInProgress(data.lpData);
handled = true;
return new IntPtr(1);
}
return IntPtr.Zero;
}
anyone can guide me what i am missing. thanks

Your method signature is incorrect, Form.WndProc you are overriding returns void.
protected virtual void WndProc(ref Message m)
I don't know where you got that code, port from C++ maybe? but it won't work with a WinForms form.

Related

How can I listen a device's messages in a C# project

it's me again!
This question is quite hard, for I'll do my best explaining it: As I mentioned in a previous question, I'm working in a scanner management on C#, using a C++ dll sent by provider. According to the API's manual, there are certain messages sent under certain conditions. In example: After Starting up the scanner, it should send the message DEVICE_CONNECTED (with a value of 0), and then change it state.
Those messages values are defined in the .dll
My issue is trying to get those messages on my C# project
I been looking for information about messages transfering, and I found out there's a WndProc that processes Windows messages, for I tried following their example:
private const int DEVICE_CONNECTED = 0;
/*Some code*/
[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
protected override void WndProc(ref Message m)
{
if (m.Msg == DEVICE_CONNECTED)
listBox1.Items.Add("Connected");
base.WndProc(ref m);
}
Of course, that one failed.
Later, I been checking the API's manual, and I think I got a clue where I can get the messages from:
// This is how is defined at .dll (C++)
DWORD StartUp( HWND Handle, UINT SorterMessage )
Where "Handle" is the handle to the application's messages destination window.
So my C# import is as follows:
[DllImport(path, EntryPoint = "?StartUp##YGKPAUHWND__##I#Z")]
public static extern int StartUp(IntPtr HWMD, uint SorterMessage);
Now I got a pointer from where I could extract the messages. My question is: How?
I found this example in another forum:
[Serializable, StructLayout(LayoutKind.Sequential)]
public struct MSG
{
public IntPtr hwnd;
public int message;
public IntPtr wParam;
public IntPtr lParam;
public int time;
public int pt_x;
public int pt_y;
};
[DllImport("user32.dll", CharSet = CharSet.Ansi)]
public static extern bool GetMessage([In, Out] ref MSG msg, IntPtr hWnd, int uMsgFilterMin, int uMsgFilterMax);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr DispatchMessage([In] ref MSG msg);
MSG msg = new MSG();
while (GetMessage(ref msg, IntPtr.Zero, 0, 0))
DispatchMessage(ref msg);
I tried to use it, as follows:
// Added a constructor inside of the struct:
public MSG(IntPtr hwndPtr)
{
hwnd = hwndPtr;
message = -1;
wParam = new IntPtr();
lParam = new IntPtr();
time = 0;
pt_x = 0;
pt_y = 0;
}
// Left the dll imports like in their example (although I fixed the path)
// Calling the method in my main
int ID, st;
ID = Class1.StartUp(hwnd, 10); // Just used 10 like in the API's manual
Console.WriteLine("Turning on device");
MSG msg = new MSG(hwnd);
while(Class1.GetMessage(ref msg, IntPtr.Zero, 0, 0))
Class1.DispatchMessage(ref msg);
Console.WriteLine(msg.message);
do { Class1.GetState(ID, out st); }
while (st != (int) DevStates.chgParams);
Console.WriteLine("Device on");
What I expect? After printing "Turning on device" I shoud get the message (because during start up, and according to manual, it sends a message before change the state), and then the "Device on" string.
What do I get? Just after printing "Turning on device" program does nothing but blink the cursor (and of course, the "Device on" string never shows up). Looks like it's waiting for any message. Tried placing the messages call in different places and the behaviour is the same.
Any advices? Thanks in advance.
Solved it (finally)
This is how I did it:
Used windows forms, since it has the class "Message"
Imported the .dll I was working on to make stuff easier, placed
all methods in a "ScanMgr" class.
using ...
using APIcsharp;
class ScanMgr
{
int ID = 0;
public string startUp(IntPtr hwmd, uint wmApp)
{
int state;
ID = NativeAPI.StartUp(hwmd, wmApp);
if(ID != 0)
{
do { NativeAPI.GetState(ID, out state); }
while(state == (int)(DevStates.StartingUp)); // DevStates is a enum
return "Device on";
}
return "Error turning on";
}
/* Other stuff to do */
}
Then, defined an override method for the messages
public partial class Form1 : Form
{
const uint wm_channel = 0x8000 + 1;
ScanMgr scanner = new ScanMgr();
public Form1()
{ InitializeComponent(); }
private void StartBtn_Click(object sender, EventArgs e)
{ log.Items.Add(scanner.startUp(this.Handle, wm_channel)); }
/* Other stuff yadda yadda */
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if(m.Msg == wm_channel)
{ /* To do stuff with m.WParam and m.LParam */ }
}
}

How to use this WndProc in Windows Forms application?

Please guide me how to use this WndProc in Windows Forms application:
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == NativeCalls.APIAttach && (uint)lParam == NativeCalls.SKYPECONTROLAPI_ATTACH_SUCCESS)
{
// Get the current handle to the Skype window
NativeCalls.HWND_BROADCAST = wParam;
handled = true;
return new IntPtr(1);
}
// Skype sends our program messages using WM_COPYDATA. the data is in lParam
if (msg == NativeCalls.WM_COPYDATA && wParam == NativeCalls.HWND_BROADCAST)
{
COPYDATASTRUCT data = (COPYDATASTRUCT)Marshal.PtrToStructure(lParam, typeof(COPYDATASTRUCT));
StatusTextBox.AppendText(data.lpData + Environment.NewLine);
// Check for connection
if (data.lpData.IndexOf("CONNSTATUS ONLINE") > -1)
ConnectButton.IsEnabled = false;
// Check for calls
IsCallInProgress(data.lpData);
handled = true;
return new IntPtr(1);
}
return IntPtr.Zero;
}
I have seen people use the above code in this way in WPF like
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
// Attach WndProc
HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
source.AddHook(WndProc);
}
You can use Application.AddMessageFilter Method.
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public class TestMessageFilter : IMessageFilter
{
public bool PreFilterMessage(ref Message m)
{
// Blocks all the messages relating to the left mouse button.
if (m.Msg >= 513 && m.Msg <= 515)
{
Console.WriteLine("Processing the messages : " + m.Msg);
return true;
}
return false;
}
}
The prototype for WndProc in C# is:
protected virtual void WndProc(ref Message m)
So, you need to override this procedure in your class, assumed that it's derived from Control.
protected override void WndProc(ref Message m)
{
Boolean handled = false; m.Result = IntPtr.Zero;
if (m.Msg == NativeCalls.APIAttach && (uint)m.Param == NativeCalls.SKYPECONTROLAPI_ATTACH_SUCCESS)
{
// Get the current handle to the Skype window
NativeCalls.HWND_BROADCAST = m.WParam;
handled = true;
m.Result = new IntPtr(1);
}
// Skype sends our program messages using WM_COPYDATA. the data is in lParam
if (m.Msg == NativeCalls.WM_COPYDATA && m.WParam == NativeCalls.HWND_BROADCAST)
{
COPYDATASTRUCT data = (COPYDATASTRUCT)Marshal.PtrToStructure(m.LParam, typeof(COPYDATASTRUCT));
StatusTextBox.AppendText(data.lpData + Environment.NewLine);
// Check for connection
if (data.lpData.IndexOf("CONNSTATUS ONLINE") > -1)
ConnectButton.IsEnabled = false;
// Check for calls
IsCallInProgress(data.lpData);
handled = true;
m.Result = new IntPtr(1);
}
if (handled) DefWndProc(ref m); else base.WndProc(ref m);
}

WndProc to detect device unplug and plug

How can I know a devices is plug or unplug in WPF?
I am using the code below to detect device changes:
private void OnSourceInitialized(object sender, EventArgs e)
{
IntPtr windowHandle = (new WindowInteropHelper(this)).Handle;
HwndSource src = HwndSource.FromHwnd(windowHandle);
src.AddHook(new HwndSourceHook(WndProc));
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
// Handle WM_DEVICECHANGE...
if (msg == 0x219)
{
InitHead();
}
return IntPtr.Zero;
}
Thank you.
EDITED:
I did the below, still not working:
if (msg == 0x0219)
{
switch (wParam.ToInt32())
{
case 0x8000:
{
InitHead();
}
break;
}
}
To detect if a device has been plugged in, , we add the hook to our Window_Loaded method that looks like the following
HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
source.AddHook(new HwndSourceHook(this.WndProc));
The handler looks as follows:
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == 0x0219 && (int)wParam == 0x8000) // 0x8000 is DBT_DEVICEARRIVAL
{
ProcessConnected();
}
return IntPtr.Zero;
}
Unfortunately, none of the DBT_DEVICE constants are triggered when a device is unplugged, rather they are called when you try to eject the device from Windows.

Implementing a Win32 message loop and creating a Window object with P/Invoke

My main goal is to implement a proper message loop purely with P/Invoke calls that is able to handle USB HID events. Definitely its functionality should be identical with the following code that works well in Windows Forms. This NativeWindow descendant receives the events:
public class Win32EventHandler : NativeWindow
{
public const int WM_DEVICECHANGE = 0x0219;
public Win32EventHandler()
{
this.CreateHandle(new CreateParams());
}
protected override void OnHandleChange()
{
base.OnHandleChange();
IntPtr handle = UsbHelper.RegisterForUsbEvents(this.Handle);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_DEVICECHANGE)
{
// Handle event
}
base.WndProc(ref m);
}
}
... powered by this event loop:
Win32EventHandler handler = new Win32EventHandler();
var context = new ApplicationContext();
Application.Run(context);
// Other thread calls:
// context.ExitThread()
I found out that implementing the event loop is rather easy:
while (true)
{
res = Win32.GetMessage(out msg, IntPtr.Zero, 0, 0);
if (res == 0)
{
break;
}
Win32.TranslateMessage(ref msg);
Win32.DispatchMessage(ref msg);
if (msg.message == WM_DEVICECHANGE)
{
// Handle event
}
}
But I have no idea how the underlying Window object should be created. The implementation of the NativeWindow class seems too complex for me.
This is my solution at the moment:
public void CustomLoop()
{
string clsName = "Class";
string wndName = "Window";
Win32.WNDCLASSEX wndClassEx = new Win32.WNDCLASSEX();
wndClassEx.cbSize = (uint)Marshal.SizeOf(wndClassEx);
wndClassEx.lpszClassName = clsName;
wndClassEx.lpfnWndProc = WndProc;
Win32.RegisterClassEx(ref wndClassEx);
IntPtr windowHandle = Win32.CreateWindowEx(0, clsName, wndName, 0, 0, 0, 0, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
IntPtr usbEventHandle = UsbHelper.RegisterForUsbEvents(windowHandle);
Win32.MSG msg;
sbyte res = 0;
while (true)
{
res = Win32.GetMessage(out msg, IntPtr.Zero, 0, 0);
if (res == 0)
{
break;
}
if (msg.message == WM.DEVICECHANGE)
{
// Handle event (does not fire)
}
else
{
Win32.TranslateMessage(ref msg);
Win32.DispatchMessage(ref msg);
}
}
Win32.DestroyWindow(windowHandle);
Win32.UnregisterClass(clsName, IntPtr.Zero);
}
[AllowReversePInvokeCalls]
private IntPtr WndProc(IntPtr hWnd, WM msg, IntPtr wParam, IntPtr lParam)
{
switch (msg)
{
case WM.DEVICECHANGE:
// Handle event (fires)
break;
default:
return Win32.DefWindowProc(hWnd, msg, wParam, lParam);
}
return IntPtr.Zero;
}
That's an very under-powered event loop. Consider using something like MsgWaitForMultipleObjectsEx instead of GetMessage.
Anyway, creating a window requires you to first register a window class (RegisterClassEx) and then create the window (CreateWindow). Neither one is particularly difficult. And instead of using base.WndProc(), you'll need to call DefWindowProc.
Trying to handle all messages directly inside the message loop is going to be overly difficult, that's why window procedures were created. And don't call TranslateMessage or DispatchMessage for any message you choose to process directly.
You may want to check out how this guy detect USB devices: A USB Library to Detect USB Devices

WPF stop mouse down event gaining Application focus

In WinForms I used the following block of code to stop the application gaining focus by being clicked on:
private const int WM_MOUSEACTIVATE = 0x0021;
private const int MA_NOACTIVATEANDEAT = 0x0004;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_MOUSEACTIVATE)
{
m.Result = (IntPtr)MA_NOACTIVATEANDEAT;
return;
}
base.WndProc(ref m);
}
Is there any alternative to this in a WPF application? Can I use a HwndSource? Here is what I have so far (WM_MOUSEACTIVATE alone does not work as required and the application still gets focus):
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
source.AddHook(WndProc);
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
// Handle messages...
int WM_MOUSEACTIVATE = 0x0021;
int WM_LBUTTONDOWN = 0x0201; //513
int WM_LBUTTONUP = 0x0202; //514
int WM_LBUTTONDBLCLK = 0x0203; //515
if (msg == WM_MOUSEACTIVATE || msg == MA_NOACTIVATEANDEAT || msg == WM_LBUTTONDOWN || msg == WM_LBUTTONUP || msg == WM_LBUTTONDBLCLK)
{
handled = true;
}
return IntPtr.Zero;
}
How can I get the Message Result?
Resolved by using:
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
// Handle messages...
int WM_MOUSEACTIVATE = 0x0021;
if (msg == WM_MOUSEACTIVATE )
{
handled = true;
return new IntPtr(MA_NOACTIVATEANDEAT);
}
return IntPtr.Zero;
}

Categories

Resources