[C #] Send a message to a windowless process,
Note:This article applies to the. net2.0 + winform program.
A winform program, I hope it cannot be opened more, so when the user starts the second instance, as the second instance, there may be several practices:
Obviously, the 3rd practices are more authentic. The core problem for achieving this effect is: how to display the window of a specified process?
The first thing that comes to mind is to call APIs such as ShowWindow and SetForegroundWindow, which can be used together to display the front rows of blocked and minimized windows. This is also a method described in many web articles related to this case, the limitation of this method is that the main window of the target Process must exist. To be precise, a valid Main Window handle is required, which is manifested in accessing Process. main1_whandle can get a non-IntPtr. zero value, that is, a valid handle. You can use the spy tool to view at least one window in the process. You can also press alt + tab to switch the window.
What if the process has no window? Let's first explain under what circumstances the process will have no window. It's very easy to let Form. visible = false (or Form. hide (), equivalent) is enough. Now the form disappears, neither visible nor corresponding taskbar buttons. alt + tab cannot be cut out. When all the forms in the program are Hide, the main‑whandle accessing the process will get IntPtr. Zero, which is a windowless process. So what kind of programs will do this, too much. Well, all kinds of music players, soft killer or anything, allow [close/minimize to the system tray]. After you have made a fork or minimized, the form is hidden, leaving only one icon in the tray area. Because the maindomainwhandle of this process does not have a valid handle, the above APIs cannot be used. You can only find another method.
Go back to the question [How to display the window of the specified process]. If your program cannot close to the tray area, there will always be a window (as can be minimized ), you can use ShowWindow, SetForegroundWindow, and other APIs happily. However, if your program wants to allow users to hide the window like a player to kill the soft state, you have to continue to struggle. At this time, the problem becomes [How to display a window for a windowless process ], my idea is as follows: since the target process does not have a window, I cannot operate on its form purely by external means. However, because the program is written by myself, it cannot be integrated internally or externally, this is done. For example, if you send a specific message to it, it will display its window after receiving the message ~ Then the sorry will be included. This idea involves two main issues,How to sendAndHow to acceptAs for how to display the window in the front row after receiving it, small case.
How to send
SendMessage and PostMessage cannot be used because the two products are also based on the window. In fact, I once suspected that the message path is feasible, which involves a principle problem, that is, if a message must be sent only to a window, it is doomed that this cannot be done, and only other inter-process communication solutions can be considered. Fortunately, I learned about the PostThreadMessage API and solved my problem. This API is used to send messages to a specified Thread (the MSDN document is here). This also shows that in principle, messages can not only be sent to windows, but also to threads, I don't know if I can send anything else. Let's take a look at the sending statement:
Void Main (){... // send the message PostThreadMessage (Process. getprocpolicyid (pid ). threads [0]. id, 0x80F0, IntPtr. zero, IntPtr. zero );...} [return: financialas (UnmanagedType. bool)] [DllImport ("user32.dll", SetLastError = true)] public static extern bool PostThreadMessage (int threadId, uint msg, IntPtr wParam, IntPtr lParam );
The 1st parameters of the API are the ID of the target thread. Note: ① this ID is the global Thread ID of the system, not a "false" ID like Thread. ManagedThreadId; ② the target Thread must have a message loop. The main thread of winform is usually the UI thread, which naturally has a message loop, so you don't need to consider this issue. The first parameter is the ID of the message to be sent. Our purpose is to send and receive a message agreed by both parties. Therefore, this message must be special and cannot be used to hit the shirt with the system message. Therefore, it is best to range from 0x8001 ~ Between 0xBFFF, which is the message segment (WM_APP) left by the system for the application ). The following two parameters are useless. You can use them if you want to make the message more special or want to carry other information. If the return value is true or false, the sending is successful or failed.
In addition, the target Process may have multiple threads. Among them, which is the main thread that can receive messages? I have no scientific judgment method, and bold speculation is Process. the first item in the Threads set, which is a good guess so far. If you have scientific knowledge, please inform ~ Thank you.
How to accept
Because the message comes from a thread, don't worry about receiving it in the WndProc in the main window. Besides, when the message comes, it is a problem that the main window does not exist. The application-level message filter is used to receive messages. The filter is an implementation System. windows. forms. IMessageFilter Interface Class (MSDN), which only needs to implement a method: bool PreFilterMessage (ref Message m). The method logic is that if the received Message m is processed and eaten, true is returned, and false is returned for other messages. The entire filter is like this:
Class MsgFilter: IMessageFilter {public bool PreFilterMessage (ref Message m) {if (m. msg = 0x80F0) {DoSomething (); // display window or other things return true;} return false ;}}
In fact, after receiving the message, I did not directly do display window-related tasks, but triggered an event. The event was registered in the main form and the display window-related code was written in the event processing method. This is a design consideration and has nothing to do with the subject of this article.
After the filter is written, you have to add it to a place for it to work. When the filter is added, it is recommended to add it as soon as possible, for example, at the beginning of main. Like this:
void Main(){ Application.AddMessageFilter(new MsgFilter()); ...}
Now, the problem of sending and receiving is solved. This is essentially a problem of inter-process communication. In fact, any process communication method can be applied in this case. Taking the message is just one of the methods. Of course, if you have a better solution for this case, please kindly advise and thank you first.
-Wen Bi-