Пишу приложение для того чтобы выводить журналы Windows в нужном мне виде. Ради пробы написал консольную прогу, которая просто извлекает все записи из всех журналов. Вот ее код:
static void Main(string[] args)
{
var logs = EventLog.GetEventLogs();
foreach(var log in logs)
{
try
{
var collection = log.Entries;
foreach (EventLogEntry entry in collection)
{
Console.WriteLine("{0} - {1} - {2}", entry.TimeGenerated, entry.Source, entry.Message);
}
Console.WriteLine(log.LogDisplayName);
Console.WriteLine();
}
catch
{
}
}
Console.Read();
}
Все работает здорово, пока цикл не добирается до журнала "Безопасность". Вылетает исключение "Запрошенный доступ к реестру защищен". Решается это запуском с правами администратора. Проблема в том, что мне нельзя запускать приложение с правами администратора. Есть ли какое-то обходное решение?
В итоге нашел решение в связке Служба Windows-Приложение. Служба считывает по запросу события и передает их в приложение, используя NamedPipes
.
Приведу здесь некоторые методы, так сказать для будущего.
Класс взаимодействия для службы:
public class PipeFunctions
{
static bool[] clientsArray = new bool[] { false, false, false };
CancellationTokenSource CancellationTokenSource = new CancellationTokenSource();
public static void StartExchange()
{
for (int i = 0; i < clientsArray.Length; i++)
{
if (!clientsArray[i])
{
StartPipeServerAsync();
clientsArray[i] = true;
}
}
}
private static async void StartPipeServerAsync()
{
var ps = new PipeSecurity();
// себе разрешаем все
ps.AddAccessRule(
new PipeAccessRule(
WindowsIdentity.GetCurrent().Owner,
PipeAccessRights.FullControl, AccessControlType.Allow));
// остальным только чтение/запись в пайп
ps.AddAccessRule(
new PipeAccessRule(
new SecurityIdentifier(WellKnownSidType.WorldSid, null),
PipeAccessRights.ReadWrite, AccessControlType.Allow));
NamedPipeServerStream pipeServer =
new NamedPipeServerStream("EventServerPipe", PipeDirection.InOut, 3, PipeTransmissionMode.Message,
PipeOptions.None,0,0,ps);
// Ожидание подключения клиента
await pipeServer.WaitForConnectionAsync();
try
{
StreamString ss = new StreamString(pipeServer);
// Подтверждение
int counter = 0;
ss.WriteString("I am the one true server!");
while (true)
{
string dataString = ss.ReadString();
if (!string.IsNullOrEmpty(dataString))
{
if (dataString != "Client disconnected!")
{
// Непосредственно получение данных о системных событиях
// и формирование сообщения для передачи
var logs = EventLog.GetEventLogs();
foreach (var log in logs)
{
try
{
var collection = log.Entries;
foreach (EventLogEntry entry in collection)
{
ss.WriteString(string.Format("{0} - {1} - {2} - {3} - {4} - {5} - {6} - {7} - {8}",
log.LogDisplayName, entry.EntryType, entry.Index, entry.MachineName, entry.Message, entry.Source,
entry.TimeGenerated, entry.TimeWritten, entry.UserName));
counter++;
}
}
catch (Exception ex)
{
// Выводим ошибочку в файл не прерывая передачи
File.WriteAllLines(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonDocuments), "AdminServiceErrors.txt"), new string[] { ex.Message });
}
}
// Сообщаем о том, что закончили передачу
ss.WriteString("Finish");
// Выводим в файл количество переданных сообщений (исключительно для проверки)
File.WriteAllLines(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonDocuments), "AdminServiceResult.txt"), new string[] { string.Format("Отправлено {0} сообщений",counter) });
}
else
break;
}
else break;
}
}
// Catch the IOException that is raised if the pipe is broken
// or disconnected.
catch (IOException e)
{
Console.WriteLine("ERROR: {0}", e.Message);
}
pipeServer.Close();
for (int i = 0; i < clientsArray.Length; i++)
{
if (clientsArray[i])
{
clientsArray[i] = false;
break;
}
}
StartExchange();
}
}
Здесь служба постоянно ожидает подключения до трех клиентов и каждому из подключившихся выдает все сообщения из журналов Windows в специальном (нужном мне) формате.
В свою очередь клиент выглядит как-то так:
class Program
{
static int counter = 0;
static string data = "";
public static List<HMIEventGroup> HMIEventGroups { get; set; } = new List<HMIEventGroup>();
public static bool CollectionIsBusy { get; set; } = false;
static void Main(string[] args)
{
PipeClientConnectAsync();
Console.Read();
}
public static async void PipeClientConnectAsync()
{
try
{
NamedPipeClientStream pipeClient =
new NamedPipeClientStream(".", "EventServerPipe",
PipeDirection.InOut, PipeOptions.None, TokenImpersonationLevel.Anonymous);
await pipeClient.ConnectAsync();
StreamString ss = new StreamString(pipeClient);
if (ss.ReadString() == "I am the one true server!")
{
ss.WriteString("Connected");
string temp = "";
Console.WriteLine("Начали получать данные");
while(true)
{
temp = ss.ReadString();
if(temp!="Finish")
{
HMIEvent.ParseAsync(temp);
counter++;
}
else
{
break;
}
}
}
else
{
Console.WriteLine("Server could not be verified.");
}
pipeClient.Close();
Console.WriteLine("Получено {0} сообщений", counter);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
После получения каждого сообщения вызывается асинхронный метод HMIEvent.ParseAsync()
, который разбирает строку и превращает ее в экземпляр нужного мне класса.
На передачу ~32000 сообщений уходит ~10 секунд.
Зарегистрируйте свое приложение как службу от имени системы.
Виртуальный выделенный сервер (VDS) становится отличным выбором
Всем привет, недавно решил научиться делать программы в WinForms и вот такой вопрос назрел, как сохранить изменённую форму в файл, вот пример...
Знаю, что код ничего не должен знать о вьюМне надо создавать внутри StackPanel button, планирую их создавать по логике сколько строк в таблице БД столько...