How can I get a specific message on a specific method?
I've seen some examples and people use "ref" ,but I dont understand it.
In delphi,for example,my function(method) must be declared in the Main Form class and next to the declaration I have to put the message
type
TForm1 = class(TForm)
...
protected
procedure MessageHandler(var Msg:Tmessage);Message WM_WINSOCK_ASYNC_MSG;
end;
I need this in C# so I can use WSAAsyncSelect in my application
Check >my other Question< with bounty 550 reputation to understand what I mean
You can override the WndProc method on a control (e.g. form).
WndProc takes a reference to a message object. A ref parameter in C# is akin to a var parameter in Delphi. The message object has a Msg property that contains the message type, e.g (from MSDN):
protected override void WndProc(ref Message m)
{
// Listen for operating system messages.
switch (m.Msg)
{
// The WM_ACTIVATEAPP message occurs when the application
// becomes the active application or becomes inactive.
case WM_ACTIVATEAPP:
// The WParam value identifies what is occurring.
appActive = (((int)m.WParam != 0));
// Invalidate to get new text painted.
this.Invalidate();
break;
}
base.WndProc(ref m);
}
In .NET winforms, all messages go to WndProc, so you can override that:
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_WINSOCK_ASYNC_MSG)
{
// invoke your method
}
else
{
base.WndProc(ref m);
}
}
If I have misunderstood, please say - but I think you would do well to avoid this low-level approach, and describe what you want to achieve - i.e. it might be that .Invoke/.BeginInvoke are more appropriate.
Related
My goal is to disable all DoubleClick() events in my application. Just simply unsubscribing from those events is not possbile, because those are external custom controls. So I am aiming for disabling either the DoubleClick() for those controls or my whole application, it doesn't really matter.
What I am trying to do is to intervene once the window gets a WindowsMessage WM and the ID number Message.Msg is the code of e.g. a Button.Click() event.
private const int WM_COMMAND = // ???
if (m.Msg == WM_COMMAND)
...
But no matter which WindowsMessage notification code I use, I don't get the correct one which gets fired once a control gets clicked. But I was abel to intervene on a DoubeClick() on the Form.
private const int WM_NCLBUTTONDBLCLK = 0x00A3;
private const int WM_LBUTTONDBLCLK = 0x0203;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_NCLBUTTONDBLCLK || m.Msg == WM_LBUTTONDBLCLK)
{
m.Result = IntPtr.Zero;
return;
}
base.WndProc(ref m);
}
This works totally fine and disabels a DoubleClick on the client area and non client area of the Form. But in which area do I locate when I am hovering a control? Because those WindowsMessages referred to either the client area and non client area dont' get fired when I am on a control.
Sent when the user clicks a button.
The parent window of the button receives this notification code through the WM_COMMAND message.
MSDN doc about a button click notifaction message
The WM_COMMAND message has this notfication code:
private const int WM_COMMAND = 0x0111;
So when I try to react to this message being sent I can't, because this message doesn't get fired.
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_COMMAND)
MessageBox.Show("foo"); // nothing happens
base.WndProc(ref m);
}
What do I miss or missunderstand about this WindowsMessage?
Since no one posted an answer yet and I found a well working solution here is my attempt to disable all DoubleClick()s or just for one/a few desired Control/s.
The problem is that WndProc() doesn't filter or respond to all WMs that are being sent. Therefore the WM for a default doubleClick on the non client area 0x0203 can't get detected. So I went deeper to already filter the WMs before they reach WndProc(). One way is to use a MessageFilter that is being assigned to my Application.
private MessageFilter msgFilter = new MessageFilter();
Application.AddMessageFilter(msgFilter);
The method Param is an object of my own class MessageFilter, which needs to implement the IMessageFilter Interface in order to use it's PreFilterMessage(). This method gets invoked for each single WM that gets send to your application.
class MessageFilter : IMessageFilter
{
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == 0x0203)
{
m.Result = IntPtr.Zero;
return true;
}
else
return false;
}
}
So basically once there is a WM with the desired Message.Msg ID, I set the Result to zero so the DoubleClick() is completely disabled for the whole application.
Later on it turned out it would be better to disable the DoubleClick() only from one Control. Since every Control in Windows has a unique Handle HWnd, which is part of the Message, I can use it to scan if the certain Message aims to my specific single Control.
When you create your Control either subscribe in the .Designer.cs to the event:
this.yourControl.HandleCreated += new System.EventHandler(this.yourControl_HandleCreated);
Or if it's a custom Control subscribe to the event after it's creation. In the event you assign the value of the created Handle to any instance your MessageFilter has access to, like a Property in this class.
private void yourControl_HandleCreated(object sender, EventArgs e)
{
msgFilter.OwnHandle = yourControl.Handle;
}
After that simply add a second condition to the if statement:
if (m.Msg == 0x0203 && OwnHandle == m.HWnd)
...
(BTW this is C# .NET 4.5)
I have some unmanaged DLL that talks to some hardware. I wrap a bunch of code and get something simple, as a class object, that I can create in a WinForm.
private AvaSpec AS = new AvaSpec();
public AvaSpec_Form()
{
InitializeComponent();
AS.SpectrumMeasuredEvent += (se, ev) => { SpectrumMeasured(ev); };
AS.Init(this.Handle);
AS.Activate();
// configure as desired
// AS.l_PrepareMeasData.m_IntegrationDelay = 0;
if (AS.DeviceList.Count > 0)
{
AS.Start();
}
}
However, the DLL relies on receiving messages through WndProc. The best way I could figure out to do this is to overload the WndProc method on the Form:
protected override void WndProc(ref Message m)
{
// catch WndProc messages that AvaSpec defines as its own
if (m.Msg == AvaSpec.WM_MEAS_READY ||
m.Msg == AvaSpec.WM_APP ||
m.Msg == AvaSpec.WM_DBG_INFOAs ||
m.Msg == AvaSpec.WM_DEVICE_RESET )
{
AS.WndProcMessageReceived(ref m);
}
// else pass message on to default message handler
base.WndProc(ref m);
}
How can I hide this overload somehow in the class definition so that the overload method does not need to be added to the Form itself? There is some talk of the IMessageFilter interface, but it still looks to require some code in the form to add the filter. Any ideas on how to make this more elegant?
Ok I figured it out based on Colin Smith's hints.
You derive your class from NativeWindow:
https://msdn.microsoft.com/en-us/library/system.windows.forms.nativewindow(v=vs.110).aspx
Then assign the parent (form) Handle (that you pass by some initialization) to the Handle that NativeWindow provides to the class object. Then, you can overload the WndProc method directly in the object.
// object definition
public class AvaSpec : NativeWindow
{
protected override void WndProc(ref Message m)
{
// catch WndProc messages that AvaSpec defines as its own
if (m.Msg == AvaSpec.WM_MEAS_READY ||
m.Msg == AvaSpec.WM_APP ||
m.Msg == AvaSpec.WM_DBG_INFOAs ||
m.Msg == AvaSpec.WM_DEVICE_RESET)
{
WndProcMessageReceived(ref m);
}
// Call base WndProc for default handling
base.WndProc(ref m);
}
...(snip)
public void Init(IntPtr parentHandle)
{
this.AssignHandle(parentHandle);
...(snip)
and use it (pass handle pointer via some init) like so:
// WinForm definition
public partial class AvaSpec_X : Form
{
private AvaSpec AS = new AvaSpec();
public AvaSpec_X()
{
InitializeComponent();
AS.SpectrumMeasuredEvent += (se, ev) => { SpectrumMeasured(ev); };
AS.Init(this.Handle);
AS.Activate();
// configure as desired
//AS.l_PrepareMeasData.m_IntegrationDelay = 0;
if (AS.DeviceList.Count > 0)
{
AS.Start();
}
}
...(snip)
You could create a hidden modeless "form"/window and then use its .Handle in the call to 'AS.Init'.
By using a separate "window" rather than piggy-backing onto the main application window, it offers a bit better encapsulation.
For example, if in the future you needed to support the handling of multiple devices at the same time...then the "separate" windows would enable good separation of messages for different devices.
Your hardware/device handling code might use wParam or lParam to identify the "device id"...but it's more likely to be using them for something else, and relying on the "window destination" as the distinguisher.
Then let the main apps UI thread message pump...automatically dispatch messages to the windows you have created.
In your message handling code for that "window", you would handle messages, which would include the special privately registered messages such as WM_DBG_INFOAs, etc...which you then forward back to the AvaSpec via WndProcMessageReceived.
If that AvaSpec class is relying on you processing those messages in a timely fashion, then you might need to then explore creating multiple UI threads.
This might be needed if your main apps UI thread was getting overloaded, or was "busy" processing other messages e.g when resizing, moving window, etc.
By having a separate UI thread that is pumping the messages for your hidden "device" window, then it might provide a better response for your "device".
Note: multiple UI threads is an advanced topic, and there are some gotchas, but basically it involves creating a thread, telling it to use the STA (single-threaded apartment), creating your window form, and then usually use Application.Run with that form to cause message pumping.
i have been developing an application and i want to detect usb devices(MASS STORAGE) now that i have done but what i need to do is to capture that message and dont pass it to the windows. i want to ask a password and if that's ok then i want to pass the message to the windows otherwise discard it,,,how can i accomplish that,,,>
protected override void WndProc(ref Message m)
{
switch(m.Msg)
{
case Win32.WM_DEVICECHANGE: OnDeviceChange(ref m); break;
}
base.WndProc (ref m);
}
void OnDeviceChange(ref Message msg)
{
int wParam = (int)msg.WParam;
if (wParam == Win32.DBT_DEVICEARRIVAL)
{
label1.Text = "Arrival";
//MessageBox.Show("" + wParam);
//msg = Message.Create(new IntPtr(),1,new IntPtr(),new IntPtr());
}
else if (wParam == Win32.DBT_DEVICEREMOVECOMPLETE) label1.Text =
"Remove";
}
You can't prevent windows to detect the hardware, unless your software is running under the ring 0 (or 1, can't remember) protection level as a low level application.
This can only be achieved with a low level programming (C, ASM), not C#. The IL language will never be capable of doing things like you want to do.
Anyway, the thing you are doing is nothing but skipping the message to the base class of the Form, not more. The system will continue anyway to send messages like this to other applications no matter if you want it or not.
I have two assemblies that I'm trying to link together.
One is a sort of background process that is built with WinForms and will be designed to run as a Windows Service.
I have a second project that will act as a UI for the background process whenever a user launches it.
I've never tried attempting something like this with managed code before, so I've started trying to use windows messages to communicate between the two processes. I'm struggling when it comes to passing more than just IntPtrs back and forth, however.
Here's the code from a control in my UI project that registers itself with the background process:
public void Init()
{
IntPtr hwnd = IntPtr.Zero;
Process[] ps = Process.GetProcessesByName("BGServiceApp");
Process mainProcess = null;
if(ps == null || ps.GetLength(0) == 0)
{
mainProcess = LaunchApp();
}
else
{
mainProcess = ps[0];
}
SendMessage(mainProcess.MainWindowHandle, INIT_CONNECTION, this.Handle, IntPtr.Zero);
}
protected override void WndProc(ref Message m)
{
if(m.Msg == INIT_CONFIRMED && InitComplete != null)
{
string message = Marshal.PtrToStringAuto(m.WParam);
Marshal.FreeHGlobal(m.WParam);
InitComplete(message, EventArgs.Empty);
}
base.WndProc(ref m);
}
This is the code from the background process that's supposed to receive a request from the UI process to register for status updates and send a confirmation message.
protected override void WndProc(ref Message m)
{
if(m.Msg == INIT_CONNECTION)
{
RegisterUIDispatcher(m.WParam);
Respond(m.WParam);
}
if(m.Msg == UNINIT_CONNECTION)
{
UnregisterUIDispatcher(m.WParam);
if(m_RegisteredDispatchers.Count == 0)
{
this.Close();
}
}
base.WndProc(ref m);
}
private void Respond(IntPtr caller)
{
string test = "Registration confirmed!";
IntPtr ptr = Marshal.StringToHGlobalAuto(test);
SendMessage(caller, INIT_CONFIRMED, ptr, IntPtr.Zero);
}
The UI process receives the INIT_CONFIRMED message from my background process, but when I try to marshal the IntPtr back into a string, I get an empty string. Is the area of heap I am using out of scope to the other process or am I missing some security attribute maybe? Is there a better and cleaner way to go about something like this using an event driven model?
Not sure if you want to go this route, but you might have an easier time using WCF as the IPC layer, rather than low-level Windows IPC stuff. You'll need to build and expose interfaces for the service, then connect to them using your UI appklication.
There are a lot of good WCF tutorials out there, if you want to give it a shot.
I have a textview and when something is pasted into it from the clipboard I need to intercept that text and do some preprocessing on it before it ends up in the textview.
I've tried listening to the "PasteClipboard" event which doesn't give me a way to modify the incoming text. and the "textview.Buffer.Changed" event which fires after the pasted text makes it into the textview.
Thanks in advance.
AFAIK your best option is to postprocess the text after it's been inserted - the InsertText event on the TextBuffer has arguments that tell you the position and size of the inserted text, so you can remove, process and re-insert it. You would of course want to avoid catching 1-char insertions (keystrokes) and your own re-insertions, but that's trivial.
The only other option I can think of is to re-implement paste support, by catching the paste key command, middle-click, etc. - but note that the command keys can be overridden in users' gtkrc files, so implementing this correctly could get hairy.
It might also be worth asking in the #gtk+ IRC channel on irc.gnome.org.
Doing some short googling, I found the following documentation on Gtk.TextBuffer and GTK alternative to .net WndProc in Mono. It appears that you might want to add the [GLib.ConnectBefore] attribute to your code to access GTK's WndProc method. Beaner's code above would probably work with slight modification for the GTK framework.
This may not be a help to you, but I am catching the WM_PASTE message in a custom control that implements TextBox. I get the GetText from the clipboard into a string variable and if it matches what I am looking for I make my changes to the variable and set the .Text to my variable and swallow the event so the textbox neer gets it. If it is not what I am looking for, but is allowed I just pass the event on with base.WndProc(ref m).
Sample:
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_PASTE)
{
string clipboardVin = Clipboard.GetText();
string newVin = "";
if (SelectionLength > 0)
{
newVin = Text.Replace(SelectedText, "");
}
else
{
newVin = Text;
}
newVin = newVin.Insert(SelectionStart, clipboardVin);
if (!vinRegEx.IsMatch(newVin))
{
m.Result = new IntPtr(Convert.ToInt32(true));
MessageBox.Show("The resulting text is not a valid VIN.", "Can Not Paste", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
base.WndProc(ref m);
}
}
else
{
base.WndProc(ref m);
}
}