cool hit counter [C#] Sending a message to a windowless process_Intefrankly

[C#] Sending a message to a windowless process

Notes. This article applies to .net2.0+ winform programs

A winform program, which I would like to not be able to multiopen (but how to prevent multiopen is not the point of this article), could probably be done in several ways when the user starts a second instance, as a second instance.

  1. A pop-up tells the user that [program is running] or something like that, and the user clicks on the pop-up and exits itself
  2. Doing nothing, silently withdrawing from itself
  3. Let the first instance that has been run display its form and exit itself when it's done

Obviously the 3rd approach is more authentic, and the core problem in achieving that effect is really: how to display the window of the specified process?

The first thing that comes to mind is to call ShowWindow, SetForegroundWindow and other APIs, with the use of which you can display the front row of the obscured, minimized window, which is the method introduced in many web articles involving such cases. The limitation of this method is that the main window of the target process must exist, to be precise, it must have a valid main window handle, as shown by accessing Process.MainWindowHandle to get a non-IntPtr.Zero value, i.e. a valid handle; or using the spy class tool to see that there is at least one window under the process; or pressing alt+tab to switch its window out.

What about if the process doesn't have a window? Let's start with what happens when the process will have no window, it's simple, just let Form.Visible=false (or Form.Hide(), equivalent), at which point the form disappears, neither visible nor corresponding taskbar buttons, and alt+tab doesn't cut out. When all the Forms in the program are Hide, accessing the MainWindowHandle of the process will give you IntPtr.Zero, which is the windowless process. So what kind of programs do this, too many well, various music players, antivirus and what not, all allow [close/minimize to system tray] and after you fork or minimize, the form is hidden, leaving only an icon in the tray area. Since the MainWindowHandle of such a process does not get a valid handle, those APIs above cannot be used, so we have to find another way.

Back to the question [how to show the window of the specified process], if your program does not allow closing to the tray area and the window is always present (it is also present when minimized), then you happily use the ShowWindow, SetForegroundWindow and other APIs without continuing. But if your program is going to allow the user to hide the window, like the player antivirus, then you still have to keep tossing, at this point the problem becomes [how to make a windowless process show a window], my thinking is this: since the target process does not have a window, I have no way to manipulate its form purely by external means, but because the program is written by myself, can we do this with an internal and external response. For example, send a specific message to it, and after it receives that message, it understands it by heart and displays its window ~ by the time the glory and wealth are enjoyed sorry into the scene. There are two main issues involved in this line of thinking. How to send harmony How to collect As for how to display the window in the front row after receiving it or something like that, small case.

How to send

SendMessage/PostMessage naturally does not mean, because these two goods are also based on the window, in fact, I once doubted whether it is feasible to take the message path, which involves a principle, that is, if the message must be sent only to the window, then it is doomed to this path is not possible, only to consider other inter-process communication solutions. Good to learn about the PostThreadMessage API, which solved my problem. This API is a way to send a message to a specified thread ( MSDN documentation is here ), it also shows that in principle, messages can be sent not just to windows, but also to threads, and it's not clear if they can be sent to anything else. Let's start with the sending statement.

void Main()
    // Send a message to the target process' main thread
    PostThreadMessage(Process.GetProcessById(pid).Threads[0].Id, 0x80F0, IntPtr.Zero, IntPtr.Zero);

[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = true)]
public static extern bool PostThreadMessage(int threadId, uint msg, IntPtr wParam, IntPtr lParam);

The 1st parameter of the API is the ID of the target thread. Note two things: (i) this ID is a global thread ID, not a "fake" ID like Thread. The main thread of winform is often the UI thread, and there is a natural message loop, so there is no need to consider this. The 2nd parameter is the ID of the message to be sent. Our purpose is to send a message that is agreed between the sending and receiving parties, so this message should be special enough not to clash with the system message, so the range should preferably be between 0x8001 and 0xBFFF, which is the message segment (WM_APP) that the system leaves for the application's own use. I don't use the last two parameters, you can use them if you want to make the message a bit more special or if you want to carry other information. method returns true/false for sending success/failure respectively.

Also, the target process may have multiple threads, of which I have no scientific way of determining which is the main thread that can receive messages, a wild guess would be item 1 in the Process.Threads collection, a guess that has worked well so far, regardless. If you have a scientific method of determining this, please let us know ~ thanks.

How to collect

Since the message is threaded over, don't think about collecting it in the main window's WndProc, and besides it's a question of whether the main window exists when the message comes over. To receive messages with an application-level message filter, the filter is a class that implements the System.Windows.Forms.IMessageFilter interface (MSDN ), the interface only needs to implement one method: bool PreFilterMessage(ref Message m), the logic of the method is to return true if the received message m is the one you want to process and eat, and return false for the rest of the messages to let go. The whole filter looks like this.

class MsgFilter : IMessageFilter
    public bool PreFilterMessage(ref Message m)
        if (m.Msg == 0x80F0)
DoSomething();  //Display windows or other things
            return true;
        return false;

In fact I don't do anything display window related directly after receiving the message, but raise an event, the main form registers the event, and then write the display window related code in the event handler method. This is a design consideration, not relevant to the main point of this article, and not much more.

Once the filter is written, you still have to add it to a place for it to work, and when you add it is when it starts to work, so it's best to add it early, for example at the beginning of main. Like this.

void Main()
    Application.AddMessageFilter(new MsgFilter());

At this point, the problem of sending and receiving is solved. This is essentially an inter-process communication problem, so really any means of process communication can be applied in the case of this article, and walking messages is just one means. Of course, if you have a better solution for this case, please let me know and thank you in advance. -Bunbi-

1、AI unblocked Algorithm regulates traffic light duration to really help smart travel
2、4800 million yuan large tender Songwon City cloud computing big data center construction project
3、Sun and Moon Functional World Cuts 2017 Materials Field Annual Roundup
4、What to do if NotificationName is so hard to use in Swift
5、The students at Tao Lin High School are awesome

    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送