`

c# - A study on the NativeWindow - encapsulate window handle and procedure

    博客分类:
  • C#
c# 
阅读更多

NativeWindow gives you a way to way to intercept the window messages (are you familiar with the Windows Message Pump?) 

Aslo, this class have provided with some default impl on manipulating handles and create child handle/control.s

 

NativeWindow for Message Intercepting and Handle Manipulation

 

We will first start from the basic example of the NativeWindow. This is an example that is taken from the MSDN NativeWindow Class page. 

 

The code is as below.

    // NativeWindow class
    // please check 
    //   http://msdn.microsoft.com/en-us/library/system.windows.forms.nativewindow.aspx
    // Summary description for Form1.
    [System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
    public class Form1 : System.Windows.Forms.Form
    {
        private MyNativeWindowListener nwl;
        private MyNativeWindow nw;

        internal void ApplicationActivated(bool ApplicationActivated)
        {
            // The application has been activated or deactivated
            System.Diagnostics.Debug.WriteLine("Application Active = " + ApplicationActivated.ToString());
        }

        private Form1()
        {
            this.Size = new System.Drawing.Size(300, 300);
            this.Text = "Form1";

            nwl = new MyNativeWindowListener(this);
            nw = new MyNativeWindow(this);

        }

        // The main entry point for the application.
        [STAThread]
        static void Main()
        {
            Application.Run(new Form1());
        }

    }


    [System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
    internal class MyNativeWindowListener : NativeWindow
    {

        // Constant value was found in the "windows.h" header file.
        private const int WM_ACTIVATEAPP = 0x001C;

        private Form1 parent;

        public MyNativeWindowListener(Form1 parent)
        {

            parent.HandleCreated += new EventHandler(this.OnHandleCreated);
            parent.HandleDestroyed += new EventHandler(this.OnHandleDestroyed);
            this.parent = parent;
        }

        internal void OnHandleCreated(object sender, EventArgs e)
        {
            // Window is now created, assign handle to NativeWindow.
            AssignHandle(((Form1)sender).Handle);
        }

        internal void OnHandleDestroyed(object sender, EventArgs e)
        {
            // Window was destroyed, release hook.
            ReleaseHandle();
        }

        [System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
        protected override void WndProc(ref Message m)
        {
            // Listen for operating system messages 
            switch (m.Msg)
            {
                case WM_ACTIVATEAPP:
                // Notify the form that this message was received. 
                // Application is activated or deactivated,  
                // based upon the WParam parameter.
                parent.ApplicationActivated(((int)m.WParam != 0));
                break;
            }
            base.WndProc(ref m);
        }

    }

     // MyNativeWindow class to create a window given a class name.
    [System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
    internal class MyNativeWindow : NativeWindow
    {
        // Constant values were found in the "windows.h" header file.
        private const int WS_CHILD = 0x40000000,
                          WS_VISIBLE = 0x10000000,
                          WM_ACTIVATEAPP = 0x001C;

        private int windowHandle;

        public MyNativeWindow(Form parent)
        {
            CreateParams cp = new CreateParams();

            // Fill in the CreateParams details.
            cp.Caption = "Click here";
            cp.ClassName = "Button"; // the classname has some predefined enumerations so that it knows what type of Control/handle to create.

            // Set the position on the form
            cp.X = 100;
            cp.Y = 100;
            cp.Height = 100;
            cp.Width = 100;

            // Specify the form as the parent.
            cp.Parent = parent.Handle;

            // Create as a child of the specified parent 
            cp.Style = WS_CHILD | WS_VISIBLE;

            this.CreateHandle(cp);
        }
        
        // Listen to when the handle changes to keep the variable in sync
        [System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
        protected override void OnHandleChange()
        {
            windowHandle = (int)this.Handle;
        }

        [System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case WM_ACTIVATEAPP:
                    // DO someting here in response to messages
                    break;
            }
            base.WndProc(ref m);
        }

    }

 the first derived class to MyNativeWindowListener class intercept the calls to Form's. It assign/destroy the handle (the handle of the main form is assigned) so that the interceptin is done. it will listen to the WM_ACTIVATE call and active the main form.)

the second class MyNativeWindow, what it does is to cretae a child handle based on the main handled passed in, the main handle is the handle of the form's. and this shows how you can leverage the NativeWindow to manipulate the handles/Controls.
If you run this code, you will see the following as a result.


 
NativeWindow to provide message pump


There is a post - Message Pump in .Net windows Service where a method of using the NativeWindow to simulate the Messgae Pump is discussed. and here is the detailed code.

    public class MessgePumpManager
    {
        private readonly Thread messagePump;

        private AutoResetEvent messagePumpRunning = new AutoResetEvent(false);

        public MessgePumpManager()
        {
            // start message pump in its own thread
            messagePump = new Thread(RunMessagePump) { Name = "ManualMessagePump" };
            messagePump.Start();
            messagePumpRunning.WaitOne();
        }

        // the message pump thread
        private void RunMessagePump()
        {
            // Create control to handle windows messages 
            MessageHandler messageHandler = new MessageHandler();

            // Do something
            // like initialize a thirdparty library
            //DLL.Init(messageHandler.Handle);

            Console.WriteLine("Message Pump thrad Started");
            messagePumpRunning.WaitOne();
            Application.Run();
        }
    }

    internal class MessageHandler : NativeWindow
    {
        public event EventHandler<MessageData> MessageReceived;

        public MessageHandler()
        {
            CreateHandle(new CreateParams());
        }

        protected override void WndProc(ref Message msg)
        {            
            // filter message here for your purposes
            EventHandler<MessageData> handler = MessageReceived;
            MessageData msgData = new MessageData(msg);
            if (handler != null) handler(this, msgData);

            base.WndProc(ref msg);
        }
    }

    // Struct cannot be inherited.
    class MessageData : EventArgs
    {
        private Message _message;
        public MessageData(Message message)
        {
            _message = message;
        }
    }

 as you can see some third party or some component may rquires a windows message pump to work, what has shown above is that the message pump handle (denoted by the MessageHandler class - inherits from the NativeWindow class ) is passed to the Third party componet, which could be in native code and be able to consume the handle and reconstruct his own message pump out of it.
The current thread (the thread which enters MessagePumpManager will block until the third party component has done with the handle - a typical way of implementing the message pump). 


 

References

NativeWindow Class

Message Pump in .Net windows Service

  • 大小: 4.4 KB
分享到:
评论

相关推荐

    C# - CSharp 12 in a Nutshell The Definitive Reference

    This comprehensive overview covers the key points discussed in the preface and introduction of "C# 12 in a Nutshell." The book delves deeper into each of these topics, providing detailed explanations,...

    c# http post get

    The provided code snippet and description detail a custom `WebClient` implementation in C#. This class is designed to handle HTTP requests and responses, specifically focusing on GET and POST methods....

    vm安装macos补丁_unlock-all-v111

    carry out additional actions which the scripts encapsulate for you especially on ESXi. If you want to run the unlocker directly the parameters are: Usage: ./Unlocker.Linux64 [-h] [-u] [target_...

    CSharp 3.0 With the .NET Framework 3.5 Unleashed(english)

    Based on the provided information from the book "C# 3.0 With the .NET Framework 3.5 Unleashed," we can extract several key points and concepts that are essential for understanding the fundamentals of ...

    vmware8 mac补丁

    carry out additional actions which the scripts encapsulate for you especially on ESXi. If you want to run the unlocker directly the parameters are: Usage: ./Unlocker.Linux64 [-h] [-u] [target_...

    VMware Unlocker for OS X 1.1.0

    carry out additional actions which the scripts encapsulate for you especially on ESXi. If you want to run the unlocker directly the parameters are: Usage: ./Unlocker.Linux64 [-h] [-u] [target_...

    matlab教程 - ME160指南

    The two appendices provide additional resources and a commentary on the guide itself, enhancing the learning experience and encouraging exploration beyond the textbook. In conclusion, the "MATLAB ...

    Killtest 分享ST0-10X 题库

    You are monitoring a filesystem on a Solaris operating system using Veritas Volume Manager when the following kernel message appears: WARNING: msgcntx: mesg069: V-2-69: memory usage specified by the ...

    Agile Web Development with Rails Final

    - Models represent the data layer and encapsulate the application’s logic. They interact with the database through the Active Record pattern, handling data retrieval and storage operations. 2. **...

    Javascript.Object.Oriented.Programming.pdf

    It will also act as a reference guide with useful examples on resolving problems with object-oriented code in Python, JavaScript, and C#. Table of Contents Chapter 1: Javascript Primer Chapter 2: ...

    Forger Windows API tutorial 中英文+源代码 [评价可免费]

    More advanced topics include programming with Threads with a practical example of a Folder Watcher--a program that watches directories for changes. Modern Windows programming requires some knowledge ...

    Packt.Learn.Selenium.rar

    mobile devices, and platforms.You'll strategize and handle a rich web UI using the advanced WebDriver API and learn techniques to handle real-time challenges in WebDriver. You'll perform different ...

    计算机网络英文题库(附答案)chapter5.pdf

    Chapter 5 of the "计算机网络英文题库(附答案)chapter5.pdf" focuses on the Link Layer and Local Area Networks (LANs). Here, we will delve into the key concepts and知识点 related to this chapter. 1. A ...

    Learning Angular - Fourth Edition A no-nonsense guide to building web applications with Angular 15 (Aristeidis Bampakos, Pablo Deeleman) (Z-Library).pdf

    Aristeidis has a strong background in various programming languages and technologies, with a focus on front-end development. He is passionate about sharing his knowledge and has contributed to ...

    《ACE程序员指南》

    Written in C++, with the help of 30 core developers and 1,700 contributors, this portable middleware has evolved to encapsulate and augment a wide range of native OS capabilities essential to support...

Global site tag (gtag.js) - Google Analytics