Указатель NULL
- это тот, который указывает на никуда. Когда вы разыскиваете указатель p
, вы говорите «дайте мне данные в месте, хранящемся в« p ». Когда p
является нулевым указателем, местоположение, хранящееся в p
, является nowhere
, вы говорите «Дайте мне данные в месте« нигде ». Очевидно, он не может этого сделать, поэтому он выбрасывает NULL pointer exception
.
В общем, это потому, что что-то не было правильно инициализировано.
Лучшая рекомендация - не использовать проект установки в Visual Studio. Это имеет очень серьезные ограничения. У меня были очень хорошие результаты с WiX
Добавление пустого ключа реестра в HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ services \ eventlog \ Application \ MY_CUSTOM_SOURCE_NAME_HERE, кажется, работает нормально.
Следуя предложению Хельба , я решил эту проблему. Уничтожение установщика журнала событий по умолчанию в точке, указанной в его примере, не позволило установщику автоматически зарегистрировать мою службу Windows в журнале событий приложений.
Слишком много времени было потеряно, пытаясь решить эту неприятную причуду. Спасибо за миллион!
FWIW, я не мог изменить код в своем сгенерированном дизайнером классе ProjectInstaller, не заставляя VS беспокоиться о модах. Я удалил сгенерированный дизайнером код и вручную вошел в класс.
Я столкнулся с некоторым странным поведением, потому что пытался зарегистрировать источник событий с тем же именем, что и служба, которую я запускал.
Я заметил, что для DisplayName также установлено то же имя, что и для вашего источника событий.
При запуске службы мы обнаружили, что Windows зарегистрировала запись «Служба успешно запущена» в журнале приложений с источником в качестве DisplayName. Похоже, это привело к регистрации имени приложения в журнале приложений.
В моем классе журнала событий я позже попытался зарегистрировать Имя приложения как источник с другим журналом событий, но когда дело дошло до добавления новых записей журнала событий, они всегда добавлялись в Приложение. войти.
Я также несколько раз получал сообщение «Описание для идентификатора события (0) в источнике».
В качестве обходного пути я просто зарегистрировал источник сообщения с немного другим именем для DisplayName, и с тех пор он работает. Стоит попробовать это, если вы еще этого не сделали.
Проблема возникает из-за installutil, который по умолчанию регистрирует источник событий с именем ваших сервисов в EventLog «Приложение». Я все еще ищу способ остановить это, делая это дерьмо. Было бы здорово, если бы кто-то мог повлиять на поведение installutil: (
Я также следовал предложению helb , за исключением того, что я в основном использовал классы, сгенерированные стандартным конструктором (объекты по умолчанию "ServiceProcessInstaller1" и "ServiceInstaller1"). Я решил опубликовать это, так как это немного более простая версия; а также потому, что я работаю в VB, и людям иногда нравится видеть VB-путь.
Как сказал tartheode , вам не следует изменять сгенерированный дизайнером класс ProjectInstaller в файле ProjectInstaller.Designer.vb , но вы можете изменить код в файле ProjectInstaller.vb . После создания обычного ProjectInstaller (с использованием стандартного механизма «Add Installer») единственное изменение, которое я сделал, было в New () класса ProjectInstaller. После обычного вызова InitializeComponent () я вставил этот код:
' remove the default event log installer
Me.ServiceInstaller1.Installers.Clear()
' Create an EventLogInstaller, and set the Event Source and Event Log
Dim logInstaller As New EventLogInstaller
logInstaller.Source = "MyServiceName"
logInstaller.Log = "MyCustomEventLogName"
' Add the event log installer
Me.ServiceInstaller1.Installers.Add(logInstaller)
Это сработало, как и ожидалось, в том, что установщик не создал источник событий в журнале приложений, а скорее созданный в новом пользовательском файле журнала.
Тем не менее, я облажался настолько, что у меня была небольшая путаница на одном сервере. Проблема с пользовательскими журналами заключается в том, что если существует имя источника события, связанное с неправильным файлом журнала (например, журнал «Приложение» вместо вашего нового пользовательского журнала), то сначала необходимо удалить имя источника; затем машина перезагрузилась; тогда источник может быть создан с привязкой к правильному журналу. Справка Microsoft четко заявляет (в описании класса EventLogInstaller ):
Метод Install генерирует исключение, если свойство Source соответствует имени источника, зарегистрированному для другого журнала событий. на компьютере.
Следовательно, у меня также есть эта функция в моей службе, которая вызывается при запуске службы:
Private Function EventLogSourceNameExists() As Boolean
'ensures that the EventSource name exists, and that it is associated to the correct Log
Dim EventLog_SourceName As String = Utility.RetrieveAppSetting("EventLog_SourceName")
Dim EventLog_LogName As String = Utility.RetrieveAppSetting("EventLog_LogName")
Dim SourceExists As Boolean = EventLog.SourceExists(EventLog_SourceName)
If Not SourceExists Then
' Create the source, if it does not already exist.
' An event log source should not be created and immediately used.
' There is a latency time to enable the source, it should be created
' prior to executing the application that uses the source.
'So pass back a False to cause the service to terminate. User will have
'to re-start the application to make it work. This ought to happen only once on the
'machine on which the service is newly installed
EventLog.CreateEventSource(EventLog_SourceName, EventLog_LogName) 'create as a source for the SMRT event log
Else
'make sure the source is associated with the log file that we want
Dim el As New EventLog
el.Source = EventLog_SourceName
If el.Log <> EventLog_LogName Then
el.WriteEntry(String.Format("About to delete this source '{0}' from this log '{1}'. You may have to kill the service using Task Manageer. Then please reboot the computer; then restart the service two times more to ensure that this event source is created in the log {2}.", _
EventLog_SourceName, el.Log, EventLog_LogName))
EventLog.DeleteEventSource(EventLog_SourceName)
SourceExists = False 'force a close of service
End If
End If
Return SourceExists
End Function
Если функция возвращает False, код запуска службы просто останавливает службу. Эта функция в значительной степени гарантирует, что вы в конечном итоге получите правильное имя источника события, связанное с правильным файлом журнала событий. Возможно, вам придется перезагрузить машину один раз; и вам, возможно, придется попробовать запустить службу более одного раза.
Я должен согласиться со stephbu о «странных состояниях», в которые попадает журнал событий, я сталкивался с этим раньше. Если бы я догадался, некоторые из ваших трудностей лежат там.
Однако лучший из известных мне способов ведения журнала событий в приложении - это использование TraceListener. Вы можете настроить их через app.config службы:
http://msdn.microsoft.com/en-us/library/system.diagnostics.eventlogtracelistener.aspx
В середине этой страницы есть раздел, в котором описано, как использовать свойство EventLog для указания EventLog, в который вы хотите записать.
Надеюсь, что это помогает.
Несколько вещей здесь
Создание журналов событий и источников на лету довольно неодобрительно. в первую очередь из-за прав, необходимых для выполнения действия - вы действительно не хотите благословлять свои приложения этой силой.
Более того, если вы удаляете журнал событий или источник, запись только действительно удаляется при перезагрузке сервера, поэтому вы можете войти в странное состояние, если удаляете и воссоздаете записи, не подпрыгивая. Существует также множество неписаных правил о конфликтах имен из-за способа хранения метаданных в реестре.
Рекомендуемый путь - это скрипт установщика и installutil или подпрограмма установки Windows.
Класс ServiceInstaller
автоматически создает EventLogInstaller
и помещает его в собственную коллекцию установщиков.
Попробуйте этот код:
ServiceProcessInstaller serviceProcessInstaller = new ServiceProcessInstaller();
serviceProcessInstaller.Password = null;
serviceProcessInstaller.Username = null;
serviceProcessInstaller.Account = ServiceAccount.LocalSystem;
// serviceInstaller
ServiceInstaller serviceInstaller = new ServiceInstaller();
serviceInstaller.ServiceName = "MyService";
serviceInstaller.DisplayName = "My Service";
serviceInstaller.StartType = ServiceStartMode.Automatic;
serviceInstaller.Description = "My Service Description";
// kill the default event log installer
serviceInstaller.Installers.Clear();
// Create Event Source and Event Log
EventLogInstaller logInstaller = new EventLogInstaller();
logInstaller.Source = "MyService"; // use same as ServiceName
logInstaller.Log = "MyLog";
// Add all installers
this.Installers.AddRange(new Installer[] {
serviceProcessInstaller, serviceInstaller, logInstaller
});
У меня такие же проблемы. В моем случае кажется, что установщик Windows автоматически добавляет источник события, имя которого совпадает с именем моей службы, и это может вызвать проблемы. Вы используете одно и то же имя для службы Windows и для источника журнала? Попробуйте изменить его так, чтобы ваш источник журнала событий назывался не так, как имя службы.