C # Служба Windows не может запустить exe [duplicate]

Что вы можете сделать по этому поводу?

Здесь есть много хороших ответов, объясняющих, что такое пустая ссылка и как ее отладить. Но очень мало о том, как предотвратить проблему или, по крайней мере, сделать ее легче поймать.

Проверить аргументы

Например, методы могут проверять разные аргументы, чтобы увидеть, null и выбросить ArgumentNullException, исключение, явно созданное для этой конкретной цели.

Конструктор для ArgumentNullException даже принимает имя параметра и сообщение как аргументы, чтобы вы могли точно сказать разработчику, что проблема.

public void DoSomething(MyObject obj) {
    if(obj == null) 
    {
        throw new ArgumentNullException("obj", "Need a reference to obj.");
    }
}

Использовать инструменты

Есть также несколько библиотек, которые могут помочь. Например, «Resharper» может предоставить вам предупреждения во время написания кода, особенно если вы используете их атрибут: NotNullAttribute

В разделе «Контракты кода Microsoft» вы используете синтаксис, например Contract.Requires(obj != null), который дает вам проверку выполнения и компиляцию: Представление кодовых контрактов .

Существует также «PostSharp», который позволит вам просто использовать такие атрибуты:

public void DoSometing([NotNull] obj)

Сделав это и сделав PostSharp частью вашего процесса сборки, obj будет проверяться на нуль во время выполнения. См. Ошибка проверки PostSharp

Решение для простого кода

Или вы всегда можете использовать свой собственный подход, используя простой старый код. Например, вот структура, которую вы можете использовать, чтобы поймать нулевые ссылки. Он моделируется после той же концепции, что и Nullable:

[System.Diagnostics.DebuggerNonUserCode]
public struct NotNull where T: class
{
    private T _value;

    public T Value
    {
        get
        {
            if (_value == null)
            {
                throw new Exception("null value not allowed");
            }

            return _value;
        }
        set
        {
            if (value == null)
            {
                throw new Exception("null value not allowed.");
            }

            _value = value;
        }
    }

    public static implicit operator T(NotNull notNullValue)
    {
        return notNullValue.Value;
    }

    public static implicit operator NotNull(T value)
    {
        return new NotNull { Value = value };
    }
}

. Вы использовали бы очень похоже на то, как вы бы использовали Nullable, за исключением того, что цель заключалась в том, чтобы сделать абсолютно противоположное - не разрешать null. Вот несколько примеров:

NotNull person = null; // throws exception
NotNull person = new Person(); // OK
NotNull person = GetPerson(); // throws exception if GetPerson() returns null

NotNull неявно отбрасывается в и из T, поэтому вы можете использовать его в любом месте, где это необходимо. Например, вы можете передать объект Person методу, который принимает значение NotNull:

Person person = new Person { Name = "John" };
WriteName(person);

public static void WriteName(NotNull person)
{
    Console.WriteLine(person.Value.Name);
}

Как вы можете видеть выше, как с помощью nullable, вы получите доступ к базовому значению через Value имущество. Кроме того, вы можете использовать явный или неявный листинг, вы можете увидеть пример с возвращаемым значением ниже:

Person person = GetPerson();

public static NotNull GetPerson()
{
    return new Person { Name = "John" };
}

Или вы даже можете использовать его, когда метод просто возвращает T (в этом случае Person), выполнив бросок. Например, следующий код будет похож на код выше:

Person person = (NotNull)GetPerson();

public static Person GetPerson()
{
    return new Person { Name = "John" };
}

Объединить с Extension

Объединить NotNull с методом расширения, и вы можете охватить еще больше ситуаций. Вот пример того, как может выглядеть метод расширения:

[System.Diagnostics.DebuggerNonUserCode]
public static class NotNullExtension
{
    public static T NotNull(this T @this) where T: class
    {
        if (@this == null)
        {
            throw new Exception("null value not allowed");
        }

        return @this;
    }
}

И вот пример того, как он может быть использован:

var person = GetPerson().NotNull();

GitHub

Для вашей справки я сделал код выше, доступный на GitHub, вы можете найти его по адресу:

https://github.com/luisperezphd/NotNull

Функция родственного языка

В C # 6.0 был введен «оператор с нулевым условием», который немного помогает в этом. С помощью этой функции вы можете ссылаться на вложенные объекты, и если какой-либо из них null, все выражение возвращает null.

Это уменьшает количество нулевых проверок, которые вы должны выполнять в некоторых случаях. Синтаксис заключается в том, чтобы поставить вопросительный знак перед каждой точкой. Возьмите следующий код, например:

var address = country?.State?.County?.City;

Представьте, что country является объектом типа Country, который имеет свойство, называемое State и т. Д. Если country, State, County или City - null, то address will be null . Therefore you only have to check whether адрес is null`.

Это отличная функция, но она дает вам меньше информации. Это не делает очевидным, какой из 4 является нулевым.

Встроенный как Nullable?

C # имеет красивую стенографию для Nullable, вы можете сделать что-то нулевое помещая знак вопроса после такого типа int?.

Было бы неплохо, если бы у C # было что-то вроде структуры NotNull выше и имела аналогичную стенографию, может быть, восклицательный знак (!), чтобы вы могли написать что-то вроде: public void WriteName(Person! person).

34
задан GEOCHET 25 June 2009 в 23:29
поделиться

6 ответов

Я только что прочитал этот комментарий в msdn ( http://msdn.microsoft.com/en-us/library/ms682431 (VS.85) .aspx ):

Не вызывайте пользовательские приложения с помощью этой функции! КристианВиммер | Редактировать | Показать историю Пожалуйста, подождите. Если вы собираетесь вызывать приложения режима пользователя, которые предлагают редактирование документов и подобные материалы (например, Word), все несохраненные данные будут потеряны. Это связано с тем, что обычная последовательность выключения не применяется к процессам, запущенным с помощью CreateProcessWithLogonW. Таким образом, запущенные приложения не получают WM_QUERYENDSESSION, WM_ENDSESSION и самое важное сообщение WM_QUIT. Поэтому они не просят сохранить данные или очистить их материал. Они просто уйдут без предупреждения. Эта функция не является удобной для пользователя и должна использоваться с осторожностью.

Это просто «плохой пользовательский опыт». Никто не ожидает этого.

Это может объяснить, что я наблюдал: работает в первый раз. Сбой происходит каждый последующий раз. Это подтверждает мою веру в то, что что-то не очищается должным образом внутри

22
ответ дан Matt Jacobsen 27 August 2018 в 10:36
поделиться
  • 1
    Работал и для меня. Благодаря! – Dirk Vollmar 17 April 2009 в 15:18
  • 2
    Не уверен, что безопасность является проблемой, но NULL-DACL, как правило, очень плохая идея, безопасная. Прочтите раздел примечаний SetSecurityDescriptorDacl: msdn.microsoft.com/en-us/library/windows/desktop/… – Andreas Magnusson 23 April 2012 в 09:34
  • 3
    Как я могу получить стандартный вывод и стандартную ошибку? – Kiquenet 5 July 2013 в 11:59
  • 4
    что относительно исходного кода, если приложение имеет аргументы? – Kiquenet 8 July 2013 в 08:14
  • 5
    Является промежуточным "Стартером" требуется процесс? Я не сразу понимаю, почему. – Mark 24 November 2016 в 20:01

Вы говорите, что «Служба Windows запущена с использованием учетных данных администратора»

Вы имеете в виду фактическую учетную запись «Администратор» или пользователь в группе «Администраторы»? Запуск службы как администратора решил для меня.

0
ответ дан Fiona 27 August 2018 в 10:36
поделиться
  • 1
    Вероятно, у вас есть проблема в том, что ваш администратор должен всегда войти в систему, да? – Matt Jacobsen 19 February 2009 в 09:50

У меня были подобные проблемы, когда я попытался запустить двоичный файл PhantomJS с помощью «runas» -verb в службе Windows. Теперь я решил проблему, выполнив следующую процедуру:

  • Олицетворить пользователя
  • Пуск процесса (без интерфейса)
  • Олицетворить назад

Вы можете использовать Impersonator-Class для олицетворения. Также важно установить следующие свойства в ProcessStartInfo, поэтому приложение не пытается получить доступ к пользовательскому интерфейсу Windows:

var processStartInfo = new ProcessStartInfo()
{
    FileName = $@"{assemblyFolder}\PhantomJS\phantomjs.exe",
    Arguments = $"--webdriver={port}",
    RedirectStandardOutput = true,
    RedirectStandardError = true,
    RedirectStandardInput = true,
    UseShellExecute = false,
    CreateNoWindow = true,
    ErrorDialog = false,
    WindowStyle = ProcessWindowStyle.Hidden
};
0
ответ дан Harry Berry 27 August 2018 в 10:36
поделиться

Просто угадайте - вы используете LoadUserProfile = true с информацией о запуске? CreateProcessWithLogonW не загружает куст реестра пользователей по умолчанию, если вы не сообщите об этом.

1
ответ дан liggett78 27 August 2018 в 10:36
поделиться
  • 1
    Я не думал, что мне нужен реестр или действительно профиль пользователя, но я только что попробовал ваше предложение, чтобы увидеть, было ли это положительным эффектом. К сожалению, не .. :( – Matt Jacobsen 12 December 2008 в 13:56
  • 2
    Это, конечно, имеет значение только в том случае, если запущенные приложения должны иметь доступ к улей пользователя. – liggett78 12 December 2008 в 14:15
  • 3
    Как указано выше в исходном сообщении: Целевой процесс выполняется успешно ОДИН. если он может выполнить один раз, то это означает, что он имеет доступ ко всем требуемым ресурсам. – Matt Jacobsen 12 December 2008 в 15:01

Вам не нужен дескриптор окна для использования CreateProcessWithLogonW, я не уверен, откуда была ваша информация.

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

0
ответ дан Stephen Martin 27 August 2018 в 10:36
поделиться
  • 1
    Это не проблема безопасности. Если бы это было так, я бы не смог успешно запустить целевой процесс. – Matt Jacobsen 12 December 2008 в 13:46
  • 2
    Запуск целевого процесса непосредственно из службы и предоставление учетных данных пользователя всегда приводит к «недействительному дескриптору». исключение. Запуск промежуточного процесса без попытки изменения учетных данных, а затем запуск целевого процесса из этого промежуточного процесса, выдает проблему. – Matt Jacobsen 12 December 2008 в 13:50
  • 3
    Какую учетную запись использует ваша служба? "вы не можете вызвать CreateProcessWithLogonW из процесса, который выполняется под учетной записью LocalSystem & quot; (См. Функцию CreateProcessWithLogonW в MSDN) – liggett78 12 December 2008 в 14:26
  • 4
    Если возникает проблема безопасности с Window Station или Desktop, процесс запустится, а затем прервется, когда он попытается выполнить инициализацию user32. Мне придется дважды проверять, когда возникают другие ошибки безопасности. – Stephen Martin 12 December 2008 в 14:50
  • 5
    @ liggett78 Как упоминалось в исходном сообщении: я запускаю службу как «администратор». на данный момент - не LocalSystem – Matt Jacobsen 12 December 2008 в 15:05

Я не буду предлагать ни psexec, ни планировщик задач. Но вы посмотрели на Sudowin ?

Это почти то, что вы хотите, за исключением того, что он запрашивает пароль перед выполнением процесса.

Также, будучи открытым исходным кодом и всеми, вы можете видеть, как он выполняет процессы из связанного времени службы и снова.

1
ответ дан Vinko Vrsalovic 27 August 2018 в 10:36
поделиться
  • 1
    Теперь я просматриваю репозиторий svn sudowin после вашего предложения. Кажется, они игнорируют Systme.Diagnostics.Process полностью и взаимодействуют с CreateProcessAsUser вместо CreateProcessWithLogonW. Может быть, это трюк ... – Matt Jacobsen 12 December 2008 в 12:26
  • 2
    Стоит попробовать, по крайней мере. – Vinko Vrsalovic 12 December 2008 в 23:23
  • 3
    любое окончательное решение с полным образцом исходного кода, работающим над этим? используя sudowin? – Kiquenet 5 July 2013 в 11:59
Другие вопросы по тегам:

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