在另一个线程中调用函数 C#

发布于 2024-11-16 12:54:01 字数 4544 浏览 3 评论 0原文

我不知道该怎么说,但我会尽力。

我有一个 Windows 窗体应用程序,它使用网络摄像头为用户拍照,效果很好,我正在使用此处找到的 directshownet 库 http://directshownet.sourceforge.net/ 并使用 DxSnap 示例来拍摄照片。

应用程序的下一部分使用 RFID 标签读取器,一旦扫描标签,它就会调用拍照方法。这就是问题所在,因为 RFID 监听方法是在 GUI 线程的单独线程中运行的,因为它是一个无限 while 循环。

用于拍照的类将图片框控件的实例作为其构造函数的参数,该构造函数是在主线程中创建的,我认为这就是问题所在。

应用程序的每个部分都可以单独工作,但是当我尝试调用该方法从侦听器线程中获取照片时,一切都会崩溃并且应用程序崩溃。

有谁知道我如何从侦听器线程调用在主线程(拍摄照片)中初始化的对象的方法?

我尝试过委托和调用,但无法弄清楚,因为我不想直接操作控件,而是让对象在主线程中执行此操作。

这是一些代码:

    private Capture cam;
    private int portIndex = -1;
    private ArrayList AlreadyOpenPortList = new ArrayList();
    private byte readerAddr = 0;
    private Thread listenThread;
    IntPtr m_ip = IntPtr.Zero;

    public podiumForm()
    {
        InitializeComponent();

        // scanner and camera startup
        startCam();
        openComs();
        openRF();
        startListening();
    }


 private void startListening()
    {
        listenThread = new Thread(new ThreadStart(this.Listen));
        listenThread.Start();
    }

    /// <summary>
    /// Method of retrieving code tag details from reader
    /// </summary>
    private void Listen()        
    {
        int fCmdRet = 0x30;
        byte state = 1;
        byte AFI = 00;
        byte[] DSFIDAndUID = new byte[9];
        byte cardNumber = 0;
        string strDSFIDAndUID = "";
        byte outputSet;

        if (!GetCurrentUsePort())
        {
            MessageBox.Show("Open ComPort, Please");
            return;
        }


        while (true)
        {
            fCmdRet = StaticClassReaderA.Inventory(ref readerAddr, ref state, ref AFI, DSFIDAndUID, ref cardNumber, portIndex);
            if (fCmdRet == 0)
            {
                outputSet = 0;
                fCmdRet = StaticClassReaderA.SetGeneralOutput(ref readerAddr, ref outputSet, portIndex);
                strDSFIDAndUID = ByteArrayToHexString(DSFIDAndUID).Replace(" ", "");
                outputSet = 3;
                fCmdRet = StaticClassReaderA.SetGeneralOutput(ref readerAddr, ref outputSet, portIndex);
                SavePic(strDSFIDAndUID.Substring(2, 16));
                //MessageBox.Show(strDSFIDAndUID.Substring(2, 16));

                //ShutDown();
            }
        }
    }

private void SavePic(string text)
    {
        Cursor.Current = Cursors.WaitCursor;

        // Release any previous buffer
        if (m_ip != IntPtr.Zero)
        {
            Marshal.FreeCoTaskMem(m_ip);
            m_ip = IntPtr.Zero;
        }

        // here's where it crashes
        // capture image
        m_ip = cam.Click();
        Bitmap b = new Bitmap(cam.Width, cam.Height, cam.Stride, PixelFormat.Format24bppRgb, m_ip);
        cam.Dispose();

        // If the image is upsidedown
        b.RotateFlip(RotateFlipType.RotateNoneFlipY);
        pbPic.Image = b;

        Cursor.Current = Cursors.Default;
        MessageBox.Show("Here " + text);
    }


private void startCam()
    {
        const int VIDEODEVICE = 0; // zero based index of video capture device to use
        const int VIDEOWIDTH = 640; // Depends on video device caps
        const int VIDEOHEIGHT = 480; // Depends on video device caps
        const int VIDEOBITSPERPIXEL = 24; // BitsPerPixel values determined by device

        cam = new Capture(VIDEODEVICE, VIDEOWIDTH, VIDEOHEIGHT, VIDEOBITSPERPIXEL, pbPic);
    }


// method in capture class
 public IntPtr Click()
    {
        int hr;

        // get ready to wait for new image
        m_PictureReady.Reset();
        m_ipBuffer = Marshal.AllocCoTaskMem(Math.Abs(m_stride) * m_videoHeight);

        try
        {
            m_WantOne = true;

            // If we are using a still pin, ask for a picture
            if (m_VidControl != null)
            {
                // CRASHES HERE with : System.InvalidCastException was unhandled
                // Tell the camera to send an image
                hr = m_VidControl.SetMode(m_pinStill, VideoControlFlags.Trigger);
                DsError.ThrowExceptionForHR(hr);
            }

            // Start waiting
            if (!m_PictureReady.WaitOne(9000, false))
            {
                throw new Exception("Timeout waiting to get picture");
            }
        }
        catch
        {
            Marshal.FreeCoTaskMem(m_ipBuffer);
            m_ipBuffer = IntPtr.Zero;
            throw;
        }

        // Got one
        return m_ipBuffer;
    }

I don't know how to put this but I'll try my best.

I have a Windows form application which uses a webcam to take a photo of a user which works fine, I'm using the directshownet library found here http://directshownet.sourceforge.net/ and have used the DxSnap sample to take the photo.

The next part of the application uses an RFID tag reader that once a tag is scanned, it calls the take photo method. And this is where the problem is coming in, because the RFID listen method is run in a separate thread to the GUI thread, because it is an infinite while loop.

The class that is used to take the picture takes an instance of a picturebox control as a parameter for it's constructor, which is created in the main thread, and i think this is where the problem is.

Each part of the application works fine separately but when i try to call the method to take the photo from the listener thread all hell breaks loose and the app crashes.

Does anybody know how I could call a method of the object that is initialized in the main thread (that takes the photo) from the listener thread?

I've tried delegate and invoke, but can't figure it out as i don't want to manipulate the control directly, but rather let the object do it in the main thread.

Here's some code:

    private Capture cam;
    private int portIndex = -1;
    private ArrayList AlreadyOpenPortList = new ArrayList();
    private byte readerAddr = 0;
    private Thread listenThread;
    IntPtr m_ip = IntPtr.Zero;

    public podiumForm()
    {
        InitializeComponent();

        // scanner and camera startup
        startCam();
        openComs();
        openRF();
        startListening();
    }


 private void startListening()
    {
        listenThread = new Thread(new ThreadStart(this.Listen));
        listenThread.Start();
    }

    /// <summary>
    /// Method of retrieving code tag details from reader
    /// </summary>
    private void Listen()        
    {
        int fCmdRet = 0x30;
        byte state = 1;
        byte AFI = 00;
        byte[] DSFIDAndUID = new byte[9];
        byte cardNumber = 0;
        string strDSFIDAndUID = "";
        byte outputSet;

        if (!GetCurrentUsePort())
        {
            MessageBox.Show("Open ComPort, Please");
            return;
        }


        while (true)
        {
            fCmdRet = StaticClassReaderA.Inventory(ref readerAddr, ref state, ref AFI, DSFIDAndUID, ref cardNumber, portIndex);
            if (fCmdRet == 0)
            {
                outputSet = 0;
                fCmdRet = StaticClassReaderA.SetGeneralOutput(ref readerAddr, ref outputSet, portIndex);
                strDSFIDAndUID = ByteArrayToHexString(DSFIDAndUID).Replace(" ", "");
                outputSet = 3;
                fCmdRet = StaticClassReaderA.SetGeneralOutput(ref readerAddr, ref outputSet, portIndex);
                SavePic(strDSFIDAndUID.Substring(2, 16));
                //MessageBox.Show(strDSFIDAndUID.Substring(2, 16));

                //ShutDown();
            }
        }
    }

private void SavePic(string text)
    {
        Cursor.Current = Cursors.WaitCursor;

        // Release any previous buffer
        if (m_ip != IntPtr.Zero)
        {
            Marshal.FreeCoTaskMem(m_ip);
            m_ip = IntPtr.Zero;
        }

        // here's where it crashes
        // capture image
        m_ip = cam.Click();
        Bitmap b = new Bitmap(cam.Width, cam.Height, cam.Stride, PixelFormat.Format24bppRgb, m_ip);
        cam.Dispose();

        // If the image is upsidedown
        b.RotateFlip(RotateFlipType.RotateNoneFlipY);
        pbPic.Image = b;

        Cursor.Current = Cursors.Default;
        MessageBox.Show("Here " + text);
    }


private void startCam()
    {
        const int VIDEODEVICE = 0; // zero based index of video capture device to use
        const int VIDEOWIDTH = 640; // Depends on video device caps
        const int VIDEOHEIGHT = 480; // Depends on video device caps
        const int VIDEOBITSPERPIXEL = 24; // BitsPerPixel values determined by device

        cam = new Capture(VIDEODEVICE, VIDEOWIDTH, VIDEOHEIGHT, VIDEOBITSPERPIXEL, pbPic);
    }


// method in capture class
 public IntPtr Click()
    {
        int hr;

        // get ready to wait for new image
        m_PictureReady.Reset();
        m_ipBuffer = Marshal.AllocCoTaskMem(Math.Abs(m_stride) * m_videoHeight);

        try
        {
            m_WantOne = true;

            // If we are using a still pin, ask for a picture
            if (m_VidControl != null)
            {
                // CRASHES HERE with : System.InvalidCastException was unhandled
                // Tell the camera to send an image
                hr = m_VidControl.SetMode(m_pinStill, VideoControlFlags.Trigger);
                DsError.ThrowExceptionForHR(hr);
            }

            // Start waiting
            if (!m_PictureReady.WaitOne(9000, false))
            {
                throw new Exception("Timeout waiting to get picture");
            }
        }
        catch
        {
            Marshal.FreeCoTaskMem(m_ipBuffer);
            m_ipBuffer = IntPtr.Zero;
            throw;
        }

        // Got one
        return m_ipBuffer;
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

一瞬间的火花 2024-11-23 12:54:01

Take a look at the SynchronizationContext class; it allows you to dispatch work back on the main (UI) thread in a manner that is agnostic of how that mechanism actually works (and therefore works with WinForms and WPF). Therefore you don't need to have a reference to a Control to call Invoke on.

It is what BackgroundWorker uses behind the scenes (you may also be able to use BackgroundWorker, depending on what you're trying to do, which is slightly easier to work with).

红衣飘飘貌似仙 2024-11-23 12:54:01
 Image image = (Image)pictureBox.Invoke ((Func<Image>) delegate { return pictureBox.Image; });
 Image image = (Image)pictureBox.Invoke ((Func<Image>) delegate { return pictureBox.Image; });
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文