0

I will try explain as much as i can. Basically i'm using Global Hotkeys in my Formless System Tray Application. To do so i'm using this hotkey manager: Global hotkey in console application When calling the hotkeys i started receiving this exception:

Current thread must be set to single thread apartment (STA) mode before OLE calls can be made. Ensure that your Main function has STAThreadAttribute marked on it.

The way i 'fixed' the exception is: https://stackoverflow.com/a/6373700/6329242 My global hotkeys started working except one and I am getting the same exception for it. Couldn't really find a way to fix it.

Here's how i call them:

      static void HotKeyManager_HotKeyPressed(object sender, HotKeyEventArgs e)
    {
        switch (e.Key)
        {
            case Keys.D1:
                CaptureAreaOfScreenForm caos2 = new CaptureAreaOfScreenForm();
                var thread1 = new Thread(new ParameterizedThreadStart(param => { caos2.Show(); }));
                thread1.SetApartmentState(ApartmentState.STA);
                thread1.Start();
                break;
            case Keys.D2:
                CaptureWorkingArea cwa2 = new CaptureWorkingArea();
                var thread2 = new Thread(new ParameterizedThreadStart(param => { cwa2.CaptureTheWorkingArea(); }));
                thread2.SetApartmentState(ApartmentState.STA);
                thread2.Start();
                break;
            case Keys.D3:
                CaptureFullScreen cfs2 = new CaptureFullScreen();
                var thread3 = new Thread(new ParameterizedThreadStart(param => { cfs2.CaptureDesktop(); }));
                thread3.SetApartmentState(ApartmentState.STA);
                thread3.Start();
                break;
            case Keys.D4:
                CaptureAllScreens cas2 = new CaptureAllScreens();
                var thread4 = new Thread(new ParameterizedThreadStart(param => { cas2.CaptureScreens(); }));
                thread4.SetApartmentState(ApartmentState.STA);
                thread4.Start();
                break;
            case Keys.D5:
                UploadFromFile uff2 = new UploadFromFile();
                var thread5 = new Thread(new ParameterizedThreadStart(param => { uff2.UploadFile(); }));
                thread5.SetApartmentState(ApartmentState.STA);
                thread5.Start();
                break;
        }
        //collect the garbage
        GC.Collect();
    }

(case Keys.D1 is the problem). The difference between the problematic one and the others is i am calling a form class. (others are working fine)

P.S. I am new to programming if I can add something that would help solving it or anything more tell me to do so. Thanks.

Community
  • 1
  • 1
P. Krumov
  • 3
  • 2
  • Have you tried calling ShowDialog instead of Show? By the way, you should really include code in the body of the question rather than as an attachment. – wizzardmr42 May 13 '16 at 08:02
  • Yes i tried ShowDialog - it gives me the same exception plus i can't really use it because i am using the form to draw a rectangle and then close it (with ShowDialog it sticks on screen). – P. Krumov May 13 '16 at 08:08

1 Answers1

2

nb. This is pretty dodgy - Windows Forms is designed to run all Forms and Controls through a single thread, but that doesn't mean you won't get it to work. You do need to make sure that you create things in the same thread which they run in though, so try changing it so that you are creating the form inside the thread too...

  static void HotKeyManager_HotKeyPressed(object sender, HotKeyEventArgs e)
    {
        switch (e.Key)
        {
            case Keys.D1:

                var thread1 = new Thread(new ParameterizedThreadStart(param => { CaptureAreaOfScreenForm caos2 = new CaptureAreaOfScreenForm();caos2.Show(); }));
                thread1.SetApartmentState(ApartmentState.STA);
                thread1.Start();
                break;
            case Keys.D2:
                CaptureWorkingArea cwa2 = new CaptureWorkingArea();
                var thread2 = new Thread(new ParameterizedThreadStart(param => { cwa2.CaptureTheWorkingArea(); }));
                thread2.SetApartmentState(ApartmentState.STA);
                thread2.Start();
                break;
            case Keys.D3:
                CaptureFullScreen cfs2 = new CaptureFullScreen();
                var thread3 = new Thread(new ParameterizedThreadStart(param => { cfs2.CaptureDesktop(); }));
                thread3.SetApartmentState(ApartmentState.STA);
                thread3.Start();
                break;
            case Keys.D4:
                CaptureAllScreens cas2 = new CaptureAllScreens();
                var thread4 = new Thread(new ParameterizedThreadStart(param => { cas2.CaptureScreens(); }));
                thread4.SetApartmentState(ApartmentState.STA);
                thread4.Start();
                break;
            case Keys.D5:
                UploadFromFile uff2 = new UploadFromFile();
                var thread5 = new Thread(new ParameterizedThreadStart(param => { uff2.UploadFile(); }));
                thread5.SetApartmentState(ApartmentState.STA);
                thread5.Start();
                break;
        }
        //collect the garbage
        GC.Collect();
    }
wizzardmr42
  • 1,634
  • 12
  • 22
  • Fundamental Windows Threading 101: STA and all objects in the UI MUST be created on te UI Thread. – TomTom May 13 '16 at 08:16
  • @TomTom I haven't used WPF but I got the impression that is only true for Windows Forms? – wizzardmr42 May 13 '16 at 08:18
  • I had to change it to ShowDialog, because otherwise my form was just blinking when its created inside but it worked out wooooooooo! Thank you very much you made my day! Gotta make a few changes its gonna be a boom!. Ty ty. – P. Krumov May 13 '16 at 08:24
  • No, it is fundamental for EVERYTHING. First, it makes programming controls a LOT easier... second it is fundamental for WINDOWS... The whole UI core follows this paradigm. – TomTom May 13 '16 at 08:29
  • @wizzardmr42 It's a very useful approach. You can have multiple message loops per process (each in its own thread), but it's tricky. Multi-threading is very hard, and a multi-threaded UI is no different. You really want to only multi-thread when necessary, and making sure UI works properly from any thread is a lot of work that can be entirely avoided by just making sure the UI is only accessed from the UI thread. This is the same for Winforms as for WPF or HTML/JS. – Luaan May 13 '16 at 08:42