Вызовите или BeginInvoke нельзя назвать на управлении, пока дескриптор окна не был создан

Всякий раз, когда вы захотите сделать что-то подобное, Google, использующий «WMI», вероятно, даст вам что-то полезное.

Например -

От: https://docs.microsoft.com/en-us/windows/desktop/cimwin32prov/stopservice-method-in-class-win32-service [112 ]

Set ServiceSet = GetObject("winmgmts:").ExecQuery( _
          "select * from Win32_Service where Name='ClipSrv'")

for each Service in ServiceSet
 RetVal = Service.StopService()
 if RetVal = 0 then 
  WScript.Echo "Service stopped" 
 elseif RetVal = 5 then 
  WScript.Echo "Service already stopped" 
 end if
next

Аналогичным образом: https://docs.microsoft.com/en-us/windows/desktop/cimwin32prov/startservice-method-in-class-win32-service [ 117]

Set ServiceSet = GetObject("winmgmts:").ExecQuery( _
           "select * from Win32_Service where Name='ClipSrv'")

for each Service in ServiceSet
 RetVal = Service.StartService()
 if RetVal = 0 then WScript.Echo "Service started"
 if RetVal = 10 then WScript.Echo "Service already running"
next

76
задан Community 23 May 2017 в 12:26
поделиться

3 ответа

Возможно, вы создаете свои элементы управления на не та нить. Рассмотрим следующую документацию из MSDN :

Это означает, что InvokeRequired может вернуть false, если Invoke не требуется (вызов происходит в том же потоке), или , если элемент управления был создан на другой поток, но контроль дескриптор еще не был создан.

В случае, когда дескриптор элемента управления еще не был создан, вы должны не просто вызывать свойства, методы, или события на контроле. Это может заставить ручку управления быть созданный в фоновом потоке, изолировать контроль на потоке без сообщения насосом и делая Приложение нестабильно.

Вы можете защитить от этого случая с помощью также проверяет значение IsHandleСоздано, когда InvokeRequired возвращает false в фоновом потоке. Если ручка управления еще не была создан, вы должны ждать, пока он не был создан до вызова Invoke или BeginInvoke. Как правило, это происходит только если создан фоновый поток в конструкторе первичной формы для приложения (как в Application.Run (новый MainForm ()), до того, как форма была показана или Application.Run был вызван.

Давайте посмотрим, что это значит для вас. (Об этом было бы легче подумать, если бы мы увидели вашу реализацию SafeInvoke).

Предполагая, что ваша реализация идентична ссылочной, за исключением проверки на IsHandleCreated , давайте следовать логике:

public static void SafeInvoke(this Control uiElement, Action updater, bool forceSynchronous)
{
    if (uiElement == null)
    {
        throw new ArgumentNullException("uiElement");
    }

    if (uiElement.InvokeRequired)
    {
        if (forceSynchronous)
        {
            uiElement.Invoke((Action)delegate { SafeInvoke(uiElement, updater, forceSynchronous); });
        }
        else
        {
            uiElement.BeginInvoke((Action)delegate { SafeInvoke(uiElement, updater, forceSynchronous); });
        }
    }
    else
    {    
        if (uiElement.IsDisposed)
        {
            throw new ObjectDisposedException("Control is already disposed.");
        }

        updater();
    }
}

Рассмотрим случай, когда мы вызываем SafeInvoke из потока не-gui для элемента управления, дескриптор которого не был создан.

uiElement не равен нулю, поэтому мы проверяем uiElement.InvokeRequired . Согласно документам MSDN (выделено жирным шрифтом) InvokeRequired вернет false , потому что, хотя он был создан в другом потоке, дескриптор не был создан! Это отправляет нас в условие else , где мы проверяем IsDisposed или сразу же продолжаем вызывать переданное действие ... из фонового потока !

В этом Точка, все ставки отменены: этот элемент управления, потому что его дескриптор был создан в потоке, который не имеет насос сообщений для него, как упоминалось во втором абзаце. Возможно, это тот случай, с которым вы столкнулись?

71
ответ дан 24 November 2019 в 11:18
поделиться

Метод в сообщении, на которое вы ссылаетесь, вызывает Invoke / BeginInvoke перед проверкой, обрабатывается ли дескриптор элемента управления был создан в случае, когда он вызывается из потока, который не создал элемент управления.

Таким образом, вы получите исключение, когда ваш метод вызывается из потока, отличного от того, который создал элемент управления. Это может произойти из-за удаленных событий или заданных в очередь рабочих элементов пользователя ...

РЕДАКТИРОВАТЬ

Если вы проверяете InvokeRequired и HandleCreated до вызова invoke, вы не должны получать это исключение.

5
ответ дан 24 November 2019 в 11:18
поделиться

Вот мой ответ к подобному вопрос :

я думаю (еще не совершенно уверенный) это это вызвано тем, что InvokeRequired будет всегда возвращать false, если управление имеет еще не загрузил/показал. Я сделал обходное решение, которое, кажется, работает на момент, который является к простому сослаться на дескриптор связанного управление в его создателе, как так:

 var x = это. Дескриптор; 

(См. http://ikriv.com/en/prog/info/dotnet/MysteriousHang.html )

20
ответ дан 24 November 2019 в 11:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: