Re[8]: Как организовать цикл обработки сообщений?
От: desco США http://v2matveev.blogspot.com
Дата: 14.10.06 13:46
Оценка: 6 (1)
Здравствуйте, OldDino, Вы писали:

OD>Здравствуйте, Pablo Cabaneiro, Вы писали:


PC>>А если бы Вы разъяснили, что есть EventTypes, было бы вообще супер =)



OD>
OD>    #region __Перечисление типов событий__
OD>    public enum EventTypes
OD>    {
OD>      DRIVE_CONNECTED = 0x02,
OD>      DRIVE_DISCONNECTED = 0x03
OD>    }
OD>    #endregion
OD>


OD>К сожалению, я не смог найти какого-либо описания типов сообщений, значения вычислил экспериментальным путём.


Win32_VolumeChangeEvent


EventType
Data type: uint16
Access type: Read-only

Type of event. This property is inherited from Win32_DeviceChangeEvent.

Value Meaning
1 Configuration Changed
2 Device Arrival
3 Device Removal

4 Docking

Re: Как организовать цикл обработки сообщений?
От: Nickolay Ch  
Дата: 11.10.06 13:46
Оценка: +1

Если его запускать в отдельном потоке, то ничего работать не будет (видимо, потому, что это не GUI-поток).

Это кто такое сказал? Вы проверяли?
Если у вас при этом летит исключение(забыл уже какое), то возможно, поможет вызов SetApartmentState(ApartmentState.STA); у треда, в котором вызываете Application.Run();
Как организовать цикл обработки сообщений?
От: Pablo Cabaneiro  
Дата: 11.10.06 13:38
Оценка:
Хочется сделать класс UsbInformer с двумя событиями — UsbFlashDriveInserted и UsbFlashDriveRemoved. Как отлавливать события, связанные с usb, я здесь уже нашел — это переопределение WndProc в форме и отсев нужных сообщений (можно еще через WMI, но но работает как-то криво, через раз). Фишка в том, что хотелось бы использовать этот класс в любых приложениях, в т.ч. службах и консоли. Для этого можно создать невидимую форму, в которой и переопределяется WndProc. Проблема в том, куда девать Application.Run(), т.е. как организовать цикл обработки сообщений. Ведь этот метод не возвращает управления до завершения приложения. Если его запускать в отдельном потоке, то ничего работать не будет (видимо, потому, что это не GUI-поток). Как быть? Может быть, есть какой-то способ создать второй GUI-поток со своим циклом обработки сообщений? Или, возможно, существует альтернативный способ отлова сообщений? Гуру говорят, что сообщения обычно посылаются окнам... заранее благодарен.

12.10.06 19:19: Перенесено модератором из '.NET' — IT
Re[2]: Как организовать цикл обработки сообщений?
От: Pablo Cabaneiro  
Дата: 11.10.06 14:04
Оценка:
Здравствуйте, Nickolay Ch, Вы писали:


NC>

NC>Если его запускать в отдельном потоке, то ничего работать не будет (видимо, потому, что это не GUI-поток).

NC>Это кто такое сказал? Вы проверяли?
NC>Если у вас при этом летит исключение(забыл уже какое), то возможно, поможет вызов SetApartmentState(ApartmentState.STA); у треда, в котором вызываете Application.Run();

Я пробовал. Рекомендованный Вами вызов, увы, не помог. На всякий случай приведу код, вдруг я совсем ерунду написал

class UsbInformer : Form
{
    const int WM_DEVICECHANGE = 0x0219;
    const int DBT_DEVICEARRIVAL = 0x8000;
    const int DBT_DEVICEREMOVECOMPLETE = 0x8004;

    public UsbInformer()
    {
         MethodInfo mi = GetType().GetMethod("CreateControl", BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] { typeof(bool) }, null);
         mi.Invoke(this, new object[] { true });
         Thread t = new Thread(new ThreadStart(Go));
         t.SetApartmentState(ApartmentState.STA);
         t.Start();
    }

    void Go()
    {
         Application.Run();
    }

    protected override void WndProc(ref Message m)
    {
         if (m.Msg == WM_DEVICECHANGE)
         {
              switch (m.WParam.ToInt32())
              {
                    case DBT_DEVICEARRIVAL:
                    {
                          Console.WriteLine("ARRIVAL");
                          break;
                    }
                    case DBT_DEVICEREMOVECOMPLETE:
                    {
                          Console.WriteLine("REMOVE");
                          break;
                    }
               }
          }
          base.WndProc(ref m);
     }
}

class Program
{
     UsbInformer ui = new UsbInformer();
     Console.ReadLine();
}
Re[3]: Как организовать цикл обработки сообщений?
От: _FRED_ Черногория
Дата: 11.10.06 14:23
Оценка:
Здравствуйте, Pablo Cabaneiro, Вы писали:

PC>Я пробовал. Рекомендованный Вами вызов, увы, не помог. На всякий случай приведу код, вдруг я совсем ерунду написал


Попробуй как-то так:
namespace ConsoleApplication1
{
  #region Using's

  using System;
  using System.Threading;
  using System.Windows.Forms;
  using System.Diagnostics;

  #endregion Using's

  class Program
  {
    static void Main(string[] args) {
      using(MyController controller = new MyController()) {
        controller.Start();
        Console.WriteLine("Controller started.");
        Console.ReadLine();
        Console.WriteLine("Application shutdown.");
      }//using
    }
  }

  class MyController : IDisposable
  {
    #region Fields

    private readonly Thread worker;

    #endregion Fields

    #region Constructors\Destructor

    public MyController() {
      worker = new Thread(ThreadProc);
      worker.SetApartmentState(ApartmentState.STA);
    }

    #endregion Constructors\Destructor

    #region Properties

    private Thread WorkerThread {
      get { return worker; }
    }

    #endregion Properties

    #region Methods

    public void Start() {
      WorkerThread.Start();
    }

    private class ListenerForm : Form
    {
      protected override void WndProc(ref Message m) {
        Debug.WriteLine(m);
        base.WndProc(ref m);
      }
    }

    [STAThread]
    private static void ThreadProc() {
      try {
        using(ListenerForm listener = new ListenerForm()) {
          Application.Run(listener);
        }//using
        Debug.Print("Listener thread shutdowned");
      } catch(ThreadAbortException) {
        throw;
      } catch(Exception ex) {
        Debug.Print("Listener thread exception: {0}.", ex);
      }//try
    }

    #endregion Methods

    #region IDisposable Members

    public void Dispose() {
      if(WorkerThread.ThreadState != System.Threading.ThreadState.Suspended) {
        WorkerThread.Abort();
      }//if
    }

    #endregion IDisposable Members
  }
}

Рекомендую переделать MyController.Dispose() через объект синхронизации ну и так далее…
... << RSDN@Home 1.2.0 alpha rev. 652>>
Now playing: «Тихо в лесу…»
Help will always be given at Hogwarts to those who ask for it.
Re[4]: Как организовать цикл обработки сообщений?
От: Pablo Cabaneiro  
Дата: 12.10.06 08:42
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Рекомендую переделать MyController.Dispose() через объект синхронизации ну и так далее…


О, работает! Огромное спасибо! Не будет ли слишком нагло с моей стороны спросить, как переделать Dispose()? Везде пишут, что использовать Thread.Abort() некошерно, к тому же ThreadAbortException перехватывается почему-то спустя весьма заметное время после вызова Thread.Abort(). Я бы как обычно использовал какой-нить EventWaitHandle, но не могу понять, где ждать сигнала, т.к. Application.Run(), повторюсь, не возвращает управление. Пока получилось сделать следующим образом — я в Вашем коде вместо перехвата ThreadAbort просто вызываю listener.Close() (правда, предварительно переключившись в GUI-поток), что приводит к прекращению цикла обработки сообщений и незамедлительному завершению потока. Вроде работает =) Хотя, возможно, это бред =)
Re[5]: Как организовать цикл обработки сообщений?
От: _FRED_ Черногория
Дата: 12.10.06 09:12
Оценка:
Здравствуйте, Pablo Cabaneiro, Вы писали:

PC>О, работает! Огромное спасибо! Не будет ли слишком нагло с моей стороны спросить, как переделать Dispose()? Везде пишут, что использовать Thread.Abort() некошерно, к тому же ThreadAbortException перехватывается почему-то спустя весьма заметное время после вызова Thread.Abort().


Правильно.

PC>Я бы как обычно использовал какой-нить EventWaitHandle,


Правильно.

PC>но не могу понять, где ждать сигнала, т.к. Application.Run(), повторюсь, не возвращает управление.


Мы крутимся в WndProc и проверять событие можно в ней.

PC>Пока получилось сделать следующим образом — я в Вашем коде вместо перехвата ThreadAbort просто вызываю listener.Close() (правда, предварительно переключившись в GUI-поток), что приводит к прекращению цикла обработки сообщений и незамедлительному завершению потока. Вроде работает =) Хотя, возможно, это бред =)


Похоже на правду. ThreadProc и listener сделали члемами MyController? Переключаетесь в GUI-поток через Control.Invoke(…)? Должно работать. на самом деле вариантов реализации может быть полно и это, скорее, уже дело вкуса :о)
... << RSDN@Home 1.2.0 alpha rev. 652>>
Now playing: «Тихо в лесу…»
Help will always be given at Hogwarts to those who ask for it.
Re[6]: Как организовать цикл обработки сообщений?
От: Pablo Cabaneiro  
Дата: 12.10.06 09:39
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Похоже на правду. ThreadProc и listener сделали члемами MyController? Переключаетесь в GUI-поток через Control.Invoke(…)? Должно работать. на самом деле вариантов реализации может быть полно и это, скорее, уже дело вкуса :о)


Дада, именно так я и сделал. Еще раз огромное спасибо.
Re: Как организовать цикл обработки сообщений?
От: OldDino Россия  
Дата: 12.10.06 10:03
Оценка:
Здравствуйте, Pablo Cabaneiro, Вы писали:

PC>можно еще через WMI, но но работает как-то криво, через раз


Пару недель назад решал задачу с "отловом" сообщений о вставке и удалении в том числе и флэшек. А посему позвольте не согласиться с процитированным выше заявлением. У меня всё работает "прямо" и отрабатывает нормально каждый раз, а не через раз. Обрабатываются сообщения VolumeChange.
Если нужно, могу привести код.

С уважением,

OldDino
Re[2]: Как организовать цикл обработки сообщений?
От: Pablo Cabaneiro  
Дата: 12.10.06 10:08
Оценка:
Здравствуйте, OldDino, Вы писали:

OD>Пару недель назад решал задачу с "отловом" сообщений о вставке и удалении в том числе и флэшек. А посему позвольте не согласиться с процитированным выше заявлением. У меня всё работает "прямо" и отрабатывает нормально каждый раз, а не через раз. Обрабатываются сообщения VolumeChange.

OD>Если нужно, могу привести код.

Если не сложно, приведите. Спасибо.
Re[3]: Как организовать цикл обработки сообщений?
От: OldDino Россия  
Дата: 12.10.06 10:27
Оценка:
Здравствуйте, Pablo Cabaneiro, Вы писали:

PC>Если не сложно, приведите. Спасибо.


Не сложно. Привожу.

#region __Подготовка к началу обработки событий об изменении состояния устройств__
WqlEventQuery volumeChangeEventQuery = new WqlEventQuery( "SELECT * FROM Win32_VolumeChangeEvent" );
volumeChangeEventWatcher = new ManagementEventWatcher( volumeChangeEventQuery );
volumeChangeEventArrivedEventHandler = new EventArrivedEventHandler( VolumeChangeEventWatcher_EventArrived );
volumeChangeEventWatcher.EventArrived += volumeChangeEventArrivedEventHandler;
volumeChangeEventWatcher.Start();
#endregion

#region __Обработчик события VolumeChangeEventWatcher_EventArrived__
private void VolumeChangeEventWatcher_EventArrived( object sender, EventArrivedEventArgs eaea )
{
ManagementBaseObject eventObject = eaea.NewEvent;
UInt16 eventType = ( UInt16 ) eventObject.Properties[ "EventType" ].Value;
if( ( UInt16 ) EventTypes.DRIVE_CONNECTED == eventType )
{
#region __Подключение устройства__

#endregion
}
else
{
#region __Отключение устройства__

#endregion
}
}
#endregion

Ну, и где-нибудь при завершении:

volumeChangeEventWatcher.Stop();
volumeChangeEventWatcher.EventArrived -= volumeChangeEventArrivedEventHandler;


Вот, собственно, и всё. Работает всегла и везде. Проверялось на флэшках и картах. Единственное, что можно добавить, так это проверку на тип (REMOVABLE или FIXED) и интерфейс (USB или нет) устройства.

С уважением,

OldDino
Re[4]: Как организовать цикл обработки сообщений?
От: _FRED_ Черногория
Дата: 12.10.06 10:33
Оценка:
Здравствуйте, OldDino, Вы писали:

OD>Не сложно. Привожу.


Вот бы ещё тегами ([c#]…[/c#]) выделить не забыл!

OD>      #region __Подготовка к началу обработки событий об изменении состояния устройств__

OD>      WqlEventQuery volumeChangeEventQuery = new WqlEventQuery( "SELECT * FROM Win32_VolumeChangeEvent" );
OD>      volumeChangeEventWatcher = new ManagementEventWatcher( volumeChangeEventQuery );
OD>      volumeChangeEventArrivedEventHandler = new EventArrivedEventHandler( VolumeChangeEventWatcher_EventArrived );
OD>      volumeChangeEventWatcher.EventArrived += volumeChangeEventArrivedEventHandler;
OD>      volumeChangeEventWatcher.Start();

OD>      #endregion

OD>    #region __Обработчик события VolumeChangeEventWatcher_EventArrived__

OD>    private void VolumeChangeEventWatcher_EventArrived( object sender, EventArrivedEventArgs eaea )
OD>    {
OD>      ManagementBaseObject eventObject = eaea.NewEvent;
OD>      UInt16 eventType = ( UInt16 ) eventObject.Properties[ "EventType" ].Value;
OD>      if( ( UInt16 ) EventTypes.DRIVE_CONNECTED == eventType )
OD>      {
OD>        #region __Подключение устройства__
      
OD>        #endregion
OD>      }
OD>      else
OD>      {
OD>        #region __Отключение устройства__

OD>        #endregion
OD>      }
OD>    }

OD>    #endregion

OD>Ну, и где-нибудь при завершении:
OD>      volumeChangeEventWatcher.Stop();
OD>      volumeChangeEventWatcher.EventArrived -= volumeChangeEventArrivedEventHandler;
... << RSDN@Home 1.2.0 alpha rev. 652>>
Now playing: «Тихо в лесу…»
Help will always be given at Hogwarts to those who ask for it.
Re[5]: Как организовать цикл обработки сообщений?
От: OldDino Россия  
Дата: 12.10.06 10:36
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Здравствуйте, OldDino, Вы писали:


OD>>Не сложно. Привожу.


_FR>Вот бы ещё тегами ([c#]…[/c#]) выделить не забыл!


Принято. Критику считаю конструктивной. Благодарю.

С уважением,

OldDino
Re[6]: Как организовать цикл обработки сообщений?
От: Pablo Cabaneiro  
Дата: 12.10.06 10:52
Оценка:
Здравствуйте, OldDino, Вы писали:

OD>Принято. Критику считаю конструктивной. Благодарю.


А если бы Вы разъяснили, что есть EventTypes, было бы вообще супер =)
Re[7]: Как организовать цикл обработки сообщений?
От: OldDino Россия  
Дата: 12.10.06 11:00
Оценка:
Здравствуйте, Pablo Cabaneiro, Вы писали:

PC>А если бы Вы разъяснили, что есть EventTypes, было бы вообще супер =)



    #region __Перечисление типов событий__
    public enum EventTypes
    {
      DRIVE_CONNECTED = 0x02,
      DRIVE_DISCONNECTED = 0x03
    }
    #endregion


К сожалению, я не смог найти какого-либо описания типов сообщений, значения вычислил экспериментальным путём. .

С уважением,

OldDino
Re[9]: Как организовать цикл обработки сообщений?
От: OldDino Россия  
Дата: 16.10.06 04:24
Оценка:
Здравствуйте, desco, Вы писали:

D>Type of event. This property is inherited from Win32_DeviceChangeEvent.


Именно это я и не смог найти. Благодарю за помощь.

С уважением,

OldDino
Re[4]: Как организовать цикл обработки сообщений?
От: Vlad37  
Дата: 15.11.06 21:16
Оценка:
Здравствуйте, OldDino, Вы писали:

OD>      WqlEventQuery volumeChangeEventQuery = new WqlEventQuery( "SELECT * FROM Win32_VolumeChangeEvent" );
OD>      volumeChangeEventWatcher = new ManagementEventWatcher( volumeChangeEventQuery );
OD>      volumeChangeEventArrivedEventHandler = new EventArrivedEventHandler( VolumeChangeEventWatcher_EventArrived );
OD>      volumeChangeEventWatcher.EventArrived += volumeChangeEventArrivedEventHandler;
OD>      volumeChangeEventWatcher.Start();


Мне, таким образом, получить сообщение о вставке/удалении флешки не удалось.

Функция volumeChangeEventQuery, почему-то, не выполнилась ни разу ни при каких условиях.

____________Почему!?!?!?

У кого-нибудь ещё была такая проблема? Буду благодарен любым рассуждениям.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Re: Как организовать цикл обработки сообщений?
От: Аноним  
Дата: 16.12.06 18:12
Оценка:
OldDino, Вы писали:
Пару недель назад решал задачу с "отловом" сообщений о вставке и удалении в том числе и флэшек

Прошу пример кода или исходник Вашей программы.


данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Re[4]: Как организовать цикл обработки сообщений?
От: Аноним  
Дата: 16.12.06 19:31
Оценка:
У меня такая же проблема — функция volumeChangeEventQuery не работает.


данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Re[5]: Как организовать цикл обработки сообщений?
От: Аноним  
Дата: 17.12.06 16:24
Оценка:
Здравствуйте, Vlad37, Вы писали:

V>Здравствуйте, OldDino, Вы писали:


V>
OD>>      WqlEventQuery volumeChangeEventQuery = new WqlEventQuery( "SELECT * FROM Win32_VolumeChangeEvent" );
OD>>      volumeChangeEventWatcher = new ManagementEventWatcher( volumeChangeEventQuery );
OD>>      volumeChangeEventArrivedEventHandler = new EventArrivedEventHandler( VolumeChangeEventWatcher_EventArrived );
OD>>      volumeChangeEventWatcher.EventArrived += volumeChangeEventArrivedEventHandler;
OD>>      volumeChangeEventWatcher.Start();
V>


V> Мне, таким образом, получить сообщение о вставке/удалении флешки не удалось.


V> Функция volumeChangeEventQuery, почему-то, не выполнилась ни разу ни при каких условиях.


V>____________Почему!?!?!?


V> У кого-нибудь ещё была такая проблема? Буду благодарен любым рассуждениям.



Проблема решилась просто
Чтобы отследить подключение/отключение флэшки, в запросе надо указывать Win32_DeviceChangeEvent вместо
Win32_VolumeChangeEvent
Re[3]: Как организовать цикл обработки сообщений?
От: vhonest  
Дата: 18.12.06 11:04
Оценка:
Здравствуйте, Pablo Cabaneiro, Вы писали:

PC>
PC>         MethodInfo mi = GetType().GetMethod("CreateControl", BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] { typeof(bool) }, null);
PC>         mi.Invoke(this, new object[] { true });
PC>


Про визибильность формы.
У меня на висте не заработало почему-то. Да и не слишком ли это хитро, а то смахивает на хакерство. Может лучше что-нибудь навроде SetVisibilityCore?
Re[3]: Как организовать цикл обработки сообщений?
От: Аноним  
Дата: 04.03.08 09:56
Оценка:
OD>>Пару недель назад решал задачу с "отловом" сообщений о вставке и удалении в том числе и флэшек. А посему позвольте не согласиться с процитированным выше заявлением. У меня всё работает "прямо" и отрабатывает нормально каждый раз, а не через раз. Обрабатываются сообщения VolumeChange.

А как насчет того, что если взять флешку и быстро переткнуть ее из одного порта USB в другой, то на медленных машинах событие отключения диска от первого порта приходит позже, чем событие подключения в другой порт? В результате, в какой-то момент имеем два логических диска с одинаковыми буквами тома!!!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.