Link to home
Start Free TrialLog in
Avatar of CodingCat
CodingCat

asked on

how to use hooks in a c# class?

hi all,

I'd like to enable a class listen to windows messages.  This class is already derived from another abstract class, so it cannot inherit from NativeWindow class, which provide an easy way to hook to the message dispatch.

Another way that might work is to use HwndSource class. It has an "AddHook" method that can hook my own hook procedure.  But I feel this class may be an overkill as it is used to present WPF in a win32 window. I'm not using WPF at all.

Is it possible to use SetWindowsHookEx() to install my hook procedure in C#? if so, how to do it? any sample code?  Thanks
Avatar of Mike Tomlinson
Mike Tomlinson
Flag of United States of America image

Are you trying to hook your own app?...or an external one?  Give more details...
Avatar of CodingCat
CodingCat

ASKER

trying to hook my own app.

what's the difference between my own app and an external one?
I am also confused about the globe hook.  how's it different from others in implementation?
Huge difference.  You can't hook an external app using straight C#.  For that you'd need a "helper" DLL written in another language such as C/C++.

Global hooks...that really depends on what type of global hook you're trying to implement as some can be done from C# while others cannot.

What message are you trying to capture in your app?  Most of the time you can simply override WndProc() and look for the message.  Some messages specifically require you to register and/or setup a callback.  It varies...

Give details.  =)
the message I want to capture is sent from a camera. It starts pumping message with a call like this (c#):

ucCam.EnableMessage(uc480.IS_FRAME, hwnd.ToInt32());

The message I want to get is this "uc480.IS_FRAME", so I can retrieve the image just captured by the camera.

the sample code come with the camera override WndProc() to do the job:
            [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)
                  {
                // uc480 Message
                        case uc480.IS_UC480_MESSAGE:
                              HandleUc480Message( m.WParam.ToInt32(), m.LParam.ToInt32() );
                              break;                
                  }
                  base.WndProc(ref m);
            }

        // ------------------------  HandleUc480Message  -------------------------------
            //
            void HandleUc480Message( int wParam, int lParam )
            {
                  switch (wParam)
                  {
                        case uc480.IS_FRAME:
                              if ( !m_bDrawing )
                                    DrawImage();
                              break;

                        case uc480.IS_DEVICE_REMOVAL:
                        case uc480.IS_NEW_DEVICE:
                              UpdateInfos();
                              break;
                  }
            }

But that requires a class derived from "From" or "NativeWindows".  My class derived from an abstract "Camera" class, which have no "WndProc()" defined.
In this line:

    ucCam.EnableMessage(uc480.IS_FRAME, hwnd.ToInt32());

Where is "hwnd" coming from?...or is that from the example to?
You can inherit from NativeWindow and then just pass the window handle to the function EnableMessage(); Here is some pseudo code example.
Public Class MyCameraWindow
Inherits NativeWindow

Public Sub New()
Me.CreateHandle(New CreateParams)
End Sub

Protected Overrides Sub WndProc(ByRef m As Message)
  If m.Msg = uc480.IS_FRAME Then
  '// TODO:
  End If
  MyBase.WndProc(m)
End Sub
End Class

Public Class Camera
Private cameraWindow as New MyCameraWindow
Public Sub New()
ucCam.EnableMessage(uc480.IS_FRAME, cameraWindow.handle);
End Sub
End Class

Open in new window

I'm trying to do something like this:

hwnd = System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle;

because to initialize 'ucCam', the constructor requires a handler to be passed in.

my class is derived from another abstract 'camera' class. I cannot make it derive from NativeWindow at the same time. So there is no 'WndProc' to override.  So even I initialized a ucCam object with a hwnd, it's not listening to the windows message.
ASKER CERTIFIED SOLUTION
Avatar of nffvrxqgrcfqvvc
nffvrxqgrcfqvvc

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Can you embed a class that Inherits from NativeWindow (as egl1044 suggests) inside your 'camera' class?  Then you can make it raise custom events that your main 'camera' class subscribes to.
<< because to initialize 'ucCam', the constructor requires a handler to be passed in. >>

Can you show use what the constructor looks like for ucCam? Look under the object browser I think it's F5 does the constructor require (Interface, Window handle). What must you first do to be able to use the EnableMessage() mehod of ucCam?
the constructor for ucCam does not requires a handler

ucCam = new uc480();

It needs some initialization be done before the camera can stream video.  embed a class inherit from NativeWindow might work.  I'll try that out tonight
hi guys,

I've implemented a class inherit from NativeWindow to capture messages.
Now, I have a form class which is the main UI,  a CameraA subclass derived from an abstract class "Camera".  CameraA contains a member of 'ucCamera' type, which inherit from NativeWindow with overrided WndPorc method.   the main UI create a CameraA object, which in turn creates a ucCamera object to retrieve images.

But there is an issue (in ucCamera class) to initialize the camera:

parentHandle = System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle;
....
ucCam.InitCamera(0, parentHandle.ToInt32());


The above code is executed when creating the ucCamera object. The 'parentHandle' returned from the first statement is 0.
I tried to create CameraA object in main UI's constructor and 'Load' event handler, neither worked.  Any ideas?
clarification:

the ucCam object in the sample code is of uc480 type, it is a member of ucCamera type.
You can use the .Handle member of the class instance your created that Inherhits NativeWindow... But because you have a MainUI then you can just Override WndProc() on the MainUI form and use Me.Handle member.


ucCam.InitCamera(0, Me.Handle); // if you use MainUI form override WndProc()

ucCam.InitCamera(0, nativeWindowClassName.Handle); // If you use NativeWindow class instance

Open in new window

didn't work.  I've attached the code.  That explains better.

the constructor with no parameter use the NativeWindow subclass's handle to initialize the camera.
the constructor with parameter pass the main UI handle to initialize the camera
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Emgu.CV;
using Emgu.CV.Structure;
using System.ComponentModel;
using System.Drawing;
using System.Timers;
using System.Runtime.InteropServices;
using System.Windows.Interop;
using System.Windows.Forms;
using Emgu.CV;
using Emgu.CV.Structure;


namespace YAETLibrary.Camera
{
    public sealed class ThorlabsCamera2 : Camera
    {

        private Rectangle aoi;
        private Bitmap bitmap;
        private String name;

        private Image<Gray, Byte> image;
        private int fps;

        private ucCamera _cam;

        public ThorlabsCamera2()
        {
            try
            {
                //_cam = ucCamera.Instance;
                //_cam.NewImage += new EventHandler<ImageEventsArgs>(_cam_NewImage);
                _cam = new ucCamera();
                _cam.NewImage+=new EventHandler<ImageEventsArgs>(_cam_NewImage);
            }
            catch
            {
                throw new Exception("Cannot create Thorlabs camera.");
            }
        }

        public ThorlabsCamera2(IntPtr handler)
        {
            try
            {
                _cam = new ucCamera(handler);
                _cam.NewImage +=new EventHandler<ImageEventsArgs>(_cam_NewImage);
            }
            catch
            {
            }
        }

        void _cam_NewImage(object sender, ImageEventsArgs e)
        {
            image = e.Image;
            bitmap = image.Bitmap;
            OnImageArrived(e);
        }
        
        //static readonly ThorlabsCamera2 instance = new ThorlabsCamera2();
        //public static ThorlabsCamera2 Instance
        //{ get { return instance; } }

        public override int FPS
        {
            get
            {
                return fps;
            }
            set
            {
                fps = value;
            }
        }

        public override System.Drawing.Rectangle AOI
        {
            get
            {
                return aoi;
            }
            set
            {
                aoi = value;
            }
        }

        public override string Name
        {
            get
            {
                return name;
            }
            set
            {
                name = value;
            }
        }

        public override System.Drawing.Size ImageSize
        {
            get { return ImageSize; }
        }

        public override System.Drawing.Bitmap Bitmap
        {
            get { return bitmap; }
        }

        public override bool Start()
        {
            if (_cam != null && !_cam.IsLive)
                _cam.Start();
            return true;
        }

        public override bool Stop()
        {
            if (_cam != null && _cam.IsLive)
                _cam.Stop();
            return true;
        }

        public override void Dispose()
        {
            _cam.Dispose();
        }

    }

    sealed class ucCamera : NativeWindow, IDisposable
    {
        public ucCamera() { InitializeCamera(); }
        public ucCamera(IntPtr handler)
        { InitializeCamera(handler); }

        //private static ucCamera instance = new ucCamera();
        //public static ucCamera Instance
        //{ get { return instance; } }

        uc480 ucCam;
        private int width, height, bits, pitch;

        // uc480 images
        private const int IMAGE_COUNT = 4;
        private struct UC480IMAGE
        {
            public IntPtr pMemory;
            public int MemID;
            public int nSeqNum;
        }

        private UC480IMAGE[] ucCamImages;
        private IntPtr pCurMem;
        private IntPtr parentHandle;
        private bool liveStrem = false;
        private Size imageSize;
        private Rectangle aoi;

        private Image<Gray, Byte> image;

        public event EventHandler<ImageEventsArgs> NewImage;

        void InitializeCamera(IntPtr handler)
        {
            try
            {
                // initialize uc480 object
                ucCam = new uc480();
                //parentHandle = System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle;
                // init image struct and alloc marshall pointers for the uc480 memory
                ucCamImages = new UC480IMAGE[IMAGE_COUNT];
                int nLoop = 0;
                for (; nLoop < IMAGE_COUNT; nLoop++)
                {
                    ucCamImages[nLoop].pMemory = Marshal.AllocCoTaskMem(4);
                    ucCamImages[nLoop].MemID = 0;
                    ucCamImages[nLoop].nSeqNum = 0;
                }

                if (!ucCam.IsOpen())
                    ucCam.InitCamera(0, handler.ToInt32());
                // initialize image size
                int x, y;
                x = ucCam.SetImageSize(uc480.IS_GET_IMAGE_SIZE_X, 0);
                y = ucCam.SetImageSize(uc480.IS_GET_IMAGE_SIZE_Y, 0);
                imageSize = new Size(x, y);
                ucCam.SetImageSize(x, y);

                // alloc images
                ucCam.ClearSequence();
                for (nLoop = 0; nLoop < IMAGE_COUNT; nLoop++)
                {
                    ucCam.AllocImageMem(x, y, 8, ref ucCamImages[nLoop].pMemory, ref ucCamImages[nLoop].MemID);
                    ucCam.AddToSequence(ucCamImages[nLoop].pMemory, ucCamImages[nLoop].MemID);
                    ucCamImages[nLoop].nSeqNum = nLoop + 1;
                }
                ucCam.SetColorMode(uc480.IS_SET_CM_Y8);

                // enable message
                ucCam.EnableMessage(uc480.IS_FRAME, handler.ToInt32());
            }
            catch
            {
            }
        }

        void InitializeCamera()
        {
            //parentHandle = System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle;
            InitializeCamera(this.Handle);
        }

        [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)
            {
                // uc480 Message
                case uc480.IS_UC480_MESSAGE:
                    HandleUc480Message(m.WParam.ToInt32(), m.LParam.ToInt32());
                    break;
            }
            base.WndProc(ref m);
        }

        void HandleUc480Message(int wParam, int lParam)
        {
            switch (wParam)
            {
                case uc480.IS_FRAME:
                    OnNewImage();
                    break;
                case uc480.IS_DEVICE_REMOVAL:
                    break;
                case uc480.IS_NEW_DEVICE:
                    break;
            }
        }

        void OnNewImage()
        {
            // retrieve the image from the Thorlabs camera
            int num = 0;
            IntPtr pMem = new IntPtr();
            IntPtr pLast = new IntPtr();
            ucCam.GetActSeqBuf(ref num, ref pMem, ref pLast);
            if (pLast.ToInt32() == 0) return;
            int nLastID = GetImageID(pLast);
            int nLastNum = GetImageNum(pLast);

            ucCam.LockSeqBuf(nLastNum, pLast);
            pCurMem = pLast;
            ucCam.InquireImageMem(pLast, nLastID, ref width, ref height, ref bits, ref pitch);
            ucCam.UnlockSeqBuf(nLastNum, pLast);
            image = new Image<Gray, byte>(width, height, pitch, pLast);
            // Raise the event
            if (image != null)
            {
                NewImage(this, new ImageEventsArgs(image));
            }
        }

        public void Start()
        {
            if(!liveStrem)
            {
                liveStrem = true;
                bool ret = ucCam.CaptureVideo(uc480.IS_DONT_WAIT)== uc480.IS_SUCCESS;
            }
        }

        public void Stop()
        {
            if (liveStrem)
            {
                liveStrem = false;
                ucCam.StopLiveVideo(0);
            }
        }

        public Size ImageSize
        {
            get { return imageSize; }
            set { imageSize = value; }
        }

        public Rectangle AOI
        {
            get { return aoi; }
            set { aoi = value; }
        }

        public bool IsLive
        { get { return liveStrem; } }

        int GetImageID(IntPtr pBuffer)
        {
            if (!ucCam.IsOpen())
                return 0;
            int i = 0;
            for (; i < IMAGE_COUNT; i++)
                if (ucCamImages[i].pMemory == pBuffer)
                    return ucCamImages[i].MemID;
            return 0;
        }

        int GetImageNum(IntPtr pBuffer)
        {
            if (ucCam.IsOpen())
                return 0;
            int i = 0;
            for (; i < IMAGE_COUNT; i++)
                if (ucCamImages[i].pMemory == pBuffer)
                    return ucCamImages[i].nSeqNum;
            return 0;
        }

        #region IDisposable Members

        public void Dispose()
        {
            if (ucCam.IsOpen())
            {
                if (liveStrem)
                    ucCam.StopLiveVideo(0);
                for (int nLoop = 0; nLoop < IMAGE_COUNT; nLoop++)
                    Marshal.FreeCoTaskMem(ucCamImages[nLoop].pMemory);
                ucCam.ExitCamera();
            }
        }

        #endregion
    }
}

Open in new window

code for main UI form
public partial class MainUI : Form
    {
        #region camera test
        Camera _camera;
        CameraFactory _cameraFactory;

        public MainUI()
        {
            InitializeComponent();
            try
            {
                //_cameraFactory = CameraFactory.Instance;
                //_camera = _cameraFactory.GetCamera(2);
                _camera = new ThorlabsCamera2();
                _camera.ImageArrived += new EventHandler<ImageEventsArgs>(_camera_ImageArrived);
            }
            catch (Exception except)
            {
                MessageBox.Show(except.Message);
            }
        }

        void _camera_ImageArrived(object sender, ImageEventsArgs e)
        {
            pictureBox1.Image = _camera.Bitmap;
        }

        private void btn_start_Click(object sender, EventArgs e)
        {
            _camera.Start();
        }

        private void btn_stop_Click(object sender, EventArgs e)
        {
            _camera.Stop();
        }

        #endregion camera test

        private void MainUI_FormClosing(object sender, FormClosingEventArgs e)
        {
            _camera.Dispose();
        }

        private void MainUI_Load(object sender, EventArgs e)
        {

        }

    }

Open in new window

I was able to pass the main UI's handle to initialize the camera and enable the message, start video streaming.  The problem seems that the IS_FRAME event is never captured by the ucCamera class.  the overriden WndProc is never executed.
If you Inherit from NativeWindow you must call this.CreateHandle() with CreateParams ... That assigns a window handle to your NativeWindow. In your constructor you only have InitializeCamera(). In any case you don't really need NativeWindow if your going to have a MainUI because you can override WndProc() in your MainUI. If you are able to start and enable the message there must be some other reason you don't receive the message. Do you receive the other messages such as IS_DEVICE_REMOVAL, IS_NEW_DEVICE ?
the reason to use NativeWindow is that I would like to enable the mainUI to use a generic camera type. Other camera types do not require a handler to initialize.  That's why I used an abstract class 'Camera', which will inform the main UI that a new image is captured. Then the mainUI can to process the new images with the same workflow.

I don't think any messages are captured, including IS_DEVICE_REMOVAL, IS_NEW_DEVICE

I'll try the CreateHandle() method, see if anything changes.
Finally I got it work by mimicking the sample code found in MSDN for NativeWindow class.  The only drawback is that I have to pass the MainUI as a parent form to the NativeWindow class, and hook up the NativeWindow class to the parent form by AssignHandle() method.  Wonder if there's a better way to do it.  I'll start another question.