• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 538
  • Last Modified:

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
0
CodingCat
Asked:
CodingCat
  • 11
  • 5
  • 4
1 Solution
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
Are you trying to hook your own app?...or an external one?  Give more details...
0
 
CodingCatAuthor Commented:
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?
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
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.  =)
0
Microsoft Certification Exam 74-409

VeeamĀ® is happy to provide the Microsoft community with a study guide prepared by MVP and MCT, Orin Thomas. This guide will take you through each of the exam objectives, helping you to prepare for and pass the examination.

 
CodingCatAuthor Commented:
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.
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
In this line:

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

Where is "hwnd" coming from?...or is that from the example to?
0
 
nffvrxqgrcfqvvcCommented:
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

0
 
CodingCatAuthor Commented:
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.
0
 
nffvrxqgrcfqvvcCommented:
You can create a seperate class that inherits from NativeWindow and create an instance of that class in your Camera class and the message will be handles in the WndProc() of that class.

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

If you have windows form then you can override it in your form. The camera hardware will send the message to the window handle you pass into the EnableMessage() function. Does your application use a form? If not you use NativeWindow.
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
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.
0
 
nffvrxqgrcfqvvcCommented:
<< 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?
0
 
CodingCatAuthor Commented:
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
0
 
CodingCatAuthor Commented:
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?
0
 
CodingCatAuthor Commented:
clarification:

the ucCam object in the sample code is of uc480 type, it is a member of ucCamera type.
0
 
nffvrxqgrcfqvvcCommented:
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

0
 
CodingCatAuthor Commented:
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

0
 
CodingCatAuthor Commented:
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

0
 
CodingCatAuthor Commented:
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.
0
 
nffvrxqgrcfqvvcCommented:
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 ?
0
 
CodingCatAuthor Commented:
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.
0
 
CodingCatAuthor Commented:
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.
0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

  • 11
  • 5
  • 4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now