Здравствуйте, Fortnum, Вы писали:
F>А как предусмотреть? Не вызывать EndInvoke, а ждать Callback
а что делать, если Callback никогда не придет? получается у нас один поток будет висеть. а чтоб Callback пришел, надо чтоб функция когда-то закончила выполнение. у него в коде на пинг стоит таймаут 500 мс, так что все будет ок.
Топикстартеру:
твой код не поддается переделке под BackgroundWorker. И вообще я не уверен, что он заработает в несколько потоков. Выводить в richTextBox1 напрямую нельзя как уже говорили раньше. через BeginInvoke тоже не получится, потому что есть вероятность непоследовательного вывода. в конечном итоге получишь мусор, а не результат.
на вскидку:
я бы сделал класс РС со свойствами ip и info. создал коллекцию эти классов. сбор инфы тоже надо вынести в отдельный класс, например InfoCollector. и в конце (у тебя 4 framework):
List<PC> listOfAvailablePCs = //пингуем комп и добавляем в список если он доступен
BackgroundWorker bw = new BackgroundWorker();
bw.RunWorkerCompleted += ....
bw.ProgressChanged += ...
int pcFinishedCount = 0;
bw.DoWork += (sender, args) =>
listOfAvailablePCs.AsParallel().ForAll( (pc)=>
{
//may ping here
InfoCollector.CollectInfo(pc);
Interlocked.Increment(ref pcFinishedCount);
bw.ReportProgress(pcFinishedCount);
};
bw.RunWorkerAsync();
здесь можно пинговать внутри Actoin, но пинг при этом должен быть синхронным, а в класс PC нужно добавить свойство Boolean Available. получиться как-то так:
Здравствуйте, motormanyak, Вы писали:
M>твой код не поддается переделке под BackgroundWorker. И вообще я не уверен, что он заработает в несколько потоков. Выводить в richTextBox1 напрямую нельзя как уже говорили раньше. через BeginInvoke тоже не получится, потому что есть вероятность непоследовательного вывода. в конечном итоге получишь мусор, а не результат.
Я знал что мой код кривой, но не думал что он безнадёжен... Эх.. Не одну неделю гугли, читал, писал, а в итоге всё равно видать придётся в 3-ий раз переписывать проект с 0...
Извиняюсь за наглость, но не могли бы Вы прокомментировать кусочки приведённого вами кода, с небольшими пояснениями на местах многоточий, а то как Вы уже успели заметить у меня со своим то кодом беда, а чужой для меня это как информативные, но непонятные иероглифы)
M>здесь можно пинговать внутри Actoin, но пинг при этом должен быть синхронным, а в класс PC нужно добавить свойство Boolean Available. получиться как-то
Извините за глупые вопросы, не очень понял внутри какого Action? И использование синхронного пинга, разве не увеличит время выполнения программы? (не исключаю, что эти глупые вопросы, из-за не совсем точного понимания приведённых Вами кусочков кода)
Здравствуйте, nettro, Вы писали:
N>Здравствуйте, motormanyak, Вы писали:
M>>твой код не поддается переделке под BackgroundWorker. И вообще я не уверен, что он заработает в несколько потоков. Выводить в richTextBox1 напрямую нельзя как уже говорили раньше. через BeginInvoke тоже не получится, потому что есть вероятность непоследовательного вывода. в конечном итоге получишь мусор, а не результат.
N>Я знал что мой код кривой, но не думал что он безнадёжен... Эх.. Не одну неделю гугли, читал, писал, а в итоге всё равно видать придётся в 3-ий раз переписывать проект с 0...
N>Извиняюсь за наглость, но не могли бы Вы прокомментировать кусочки приведённого вами кода, с небольшими пояснениями на местах многоточий, а то как Вы уже успели заметить у меня со своим то кодом беда, а чужой для меня это как информативные, но непонятные иероглифы)
ща попробую.
List<PC> listOfAvailablePCs = //пингуем комп и добавляем в список если он доступен
BackgroundWorker bw = new BackgroundWorker();
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);int pcFinishedCount = 0;
bw.DoWork += (sender, args) =>
listOfAvailablePCs.AsParallel().ForAll( (pc)=>
{
//may ping here
InfoCollector.CollectInfo(pc);
Interlocked.Increment(ref pcFinishedCount);
bw.ReportProgress(pcFinishedCount);
});
bw.RunWorkerAsync();
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//в этом месте процесс опроса завершен. можем вывести какое-нибудь сообщение, типа
MessageBox.Show("Yahoooo!!!!");
//но лучше сделать как предлагает [url=http://msdn.microsoft.com/ru-ru/library/system.componentmodel.backgroundworker.runworkercompleted.aspx]msdn[/url]
//не забываем, что этот метод выполняется в основном потоке, поэтому можем смело вызывать элементы управления если нужно
}
void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
//этот метод тоже выполняется потоке UIthis.progressBar1.Value = Math.Round(e.ProgressPercentage / hostsCount * 100);
//hostsCount - общее количество пингуемых серверов
//Math.Round(e.ProgressPercentage / hostsCount * 100) - считаем процент обработанных серверов
}
N>Извините за глупые вопросы, не очень понял внутри какого Action? И использование синхронного пинга, разве не увеличит время выполнения программы? (не исключаю, что эти глупые вопросы, из-за не совсем точного понимания приведённых Вами кусочков кода)
метод ForAll() принимает Action<T> action как параметр. значит все что находится в скобках этого метода и есть Action. Теперь, так как стоит AsParallel(), значит все Action'ы будут выполнятся в разных потоках (не совсем так, но для первого знакомства сойдет). а так как каждый Action выполняется в отдельном потоке, то и синхронный пинг тормозить нас не будет. во втором куске кода показано все тоже самое, что и выше (точки поставил, чтоб не копировать повторяющийся код). изменяется только Action, а список listOfAvailablePCs должен содержать не доступные компы, а все возможные. в этом случае метод bw_RunWorkerCompleted можно изменить так:
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
MessageBox.Show(e.Error.Message);
}
else if (e.Cancelled)
{
richTextBox1.Text = "Canceled";
}
else
{
foreach (PC pc in listOfAvailablePCs)
{
if (pc.Available)
richTextBox1.Text += pc.Info + "\r\n";
else
richTextBox1.Text += pc.Ip + " is not available\r\n";
}
}
}
P.S. все функции Win32_lalala (которые теперь находятся в отдельном классе) должны писать результат в pc.Info, а не в richTextBox1.
P.S.S. catch метода WmiInfo тоже не должен ничего делать с richTextBox1. информацию об ошибке лучше хранить в объекте pc. (например добавить ему еще одно свойство типа Exception)
Здравствуйте, motormanyak, Вы писали:
M>Здесь BackgroundWorker не совсем подходит. В него можно вынести цикл опроса, что разлочит главное окно, но не ускорит процесс выполнения. Чтобы ускорить процесс выполнения, каждую итерацию следует вынести в отдельный поток (класс Thread).
А как же Parallel LINQ, Task Parallel Library, async/await наконец? Мы не ищем лёгких путей, да?
Здравствуйте, motormanyak, Вы писали:
M>ща попробую.
M>
M>List<PC> listOfAvailablePCs = //пингуем комп и добавляем в список если он доступен
M>BackgroundWorker bw = new BackgroundWorker();
M>bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
M>bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
M>int pcFinishedCount = 0;
M>bw.DoWork += (sender, args) =>
M>listOfAvailablePCs.AsParallel().ForAll( (pc)=>
M>{
M>//may ping here
M>InfoCollector.CollectInfo(pc);
M>Interlocked.Increment(ref pcFinishedCount);
M>bw.ReportProgress(pcFinishedCount);
M>});
M>bw.RunWorkerAsync();
M> void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
M> {
M>//в этом месте процесс опроса завершен. можем вывести какое-нибудь сообщение, типа
M>MessageBox.Show("Yahoooo!!!!");
M>//но лучше сделать как предлагает [url=http://msdn.microsoft.com/ru-ru/library/system.componentmodel.backgroundworker.runworkercompleted.aspx]msdn[/url]
M>//не забываем, что этот метод выполняется в основном потоке, поэтому можем смело вызывать элементы управления если нужно
M> }
M> void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
M> {
M> //этот метод тоже выполняется потоке UI
M>this.progressBar1.Value = Math.Round(e.ProgressPercentage / hostsCount * 100);
M>//hostsCount - общее количество пингуемых серверов
M>//Math.Round(e.ProgressPercentage / hostsCount * 100) - считаем процент обработанных серверов
M> }
M>
N>>Извините за глупые вопросы, не очень понял внутри какого Action? И использование синхронного пинга, разве не увеличит время выполнения программы? (не исключаю, что эти глупые вопросы, из-за не совсем точного понимания приведённых Вами кусочков кода)
M>метод ForAll() принимает Action<T> action как параметр. значит все что находится в скобках этого метода и есть Action. Теперь, так как стоит AsParallel(), значит все Action'ы будут выполнятся в разных потоках (не совсем так, но для первого знакомства сойдет). а так как каждый Action выполняется в отдельном потоке, то и синхронный пинг тормозить нас не будет. во втором куске кода показано все тоже самое, что и выше (точки поставил, чтоб не копировать повторяющийся код). изменяется только Action, а список listOfAvailablePCs должен содержать не доступные компы, а все возможные. в этом случае метод bw_RunWorkerCompleted можно изменить так:
M>
M>P.S. все функции Win32_lalala (которые теперь находятся в отдельном классе) должны писать результат в pc.Info, а не в richTextBox1. M>P.S.S. catch метода WmiInfo тоже не должен ничего делать с richTextBox1. информацию об ошибке лучше хранить в объекте pc. (например добавить ему еще одно свойство типа Exception)
Огромное Вам спасибо за пояснения!! И отдельное спасибо за ответ на возможно глупый вопрос и объяснение Action, а не отсылание на ресурсы msdn из которых для меня пока понятны не все вещи.
Здравствуйте, Vladek, Вы писали:
V>А как же Parallel LINQ, Task Parallel Library, async/await наконец? Мы не ищем лёгких путей, да?
Извините, но к сожаления я вообще не понимаю, о чём Вы написали, т.к. знаком с c# и программирование в частности, если Вы могли заметить по теме достаточно условно...
Я теперь даже не знаю с какой стороны подходить для полного переписывания проекта, и собственно как его переписывать, с моими ограниченными знаниями... А то что Вы упомянули, уверен ещё страшнее уже имеющегося
Здравствуйте, nettro, Вы писали: N>p.s. Если кто то откликнется на тему и поможет на конкретном примере привязать BackgroundWorker и ProgressBar к проге, а то сколько не пытаюсь по статьям с msdn, как то пока не получается... По необходимости могу прислать проект с кодом.
Автор, изучай Parallel LINQ, Task Parallel Library и async/await — это позволит писать тебе очень лаконичный код, особо не заморачиваясь низкоуровневыми деталями. И уж точно не придётся вникать в допотопные BackgroundWorker-ы. Под катом отрефакторенная версия твоего кода, мои дополнительные комментарии начинаются с //NOTE:.
ProgressBar тут попробуй привязать сам, через Invoke.
Скрытый текст
using System;
using System.Linq;
using System.Management;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace test
{
public partial class infoNetworkForm : Form
{
public infoNetworkForm()
{
InitializeComponent();
пароль_textBox.UseSystemPasswordChar = true;
}
private void сканироватьСеть_button_Click(object sender, EventArgs e)
{
//NOTE: Запускаем код асинхронно, не блокируя UI-поток своей работой
//NOTE: но загодя блокируем кнопку сканирования, чтобы пользователь снова её не нажал и не запустил процесс ещё раз
сканироватьСеть_button.Enabled = false;
Task.Factory.StartNew(delegate
{
// Получаем имя хоста текущей машиныvar localHostName = Dns.GetHostName();
// Получаем IP машины по имени хоста,
//NOTE: при этом ищем IPv4, так как сеть может поддерживать и IPv6var localHostIP = Dns.GetHostEntry(localHostName).AddressList.FirstOrDefault(address => address.AddressFamily == AddressFamily.InterNetwork);
// создаем список для адресов удаленных машин типа string
//NOTE: не используем примитивные типы без лишней необходимости! Формируем список из объектов IPAddress.var remoteHostIPAddresses = Enumerable
// повторяем ip-адрес 255 раз
.Repeat(localHostIP.GetAddressBytes(), 255)
// и преобразуем в обект IPAddress, заменяя последний байт адреса на порядковый номер в последовательности
.Select((address, index) =>
{
address[3] = (byte)(index + 1);
return new IPAddress(address);
})
// формируем из последовательности обыкновенный массив
.ToArray();
//NOTE: запускаем параллельный цикл опроса адресов, тем не менее этот вызов возвратит управление обратно,
// когда все адреса будут обработаны, то есть дождётся завершения всех итераций.
Parallel.ForEach(remoteHostIPAddresses, remoteHostIPAddress =>
{
//NOTE: Избавляемся от асинхронных вызовов внутри asinhroPing, так как опрос каждого хоста и так будет совершаться в фоновом потоке
asinhroPing(remoteHostIPAddress);
});
}, TaskCreationOptions.LongRunning) //NOTE: указываем, что задача может занять длительное время - тогда TPL оптимальнее будет использовать свои ресурсы
//NOTE: после выполнения задачи - проверим статус выполнения
.ContinueWith(scanTask =>
{
this.Invoke(new Action(delegate
{
//NOTE: разблокируем кнопку
сканироватьСеть_button.Enabled = true;
}));
//NOTE: если задача сканирования почему-то дала сбойif (scanTask.IsFaulted)
{
//NOTE: выводим информацию об ошибке, не забывая сделать это в контексте UI-потокаthis.Invoke(new Action(delegate
{
richTextBox1.AppendText("Ошибка! (в функции сканироватьСеть_button_Click)\r\n");
richTextBox1.AppendText(
"Source: " + scanTask.Exception.Source + "\r\n" +
"Message: " + scanTask.Exception.Message + "\r\n" +
"HelpLink" + scanTask.Exception.HelpLink);
}));
}
});
}
private void asinhroPing(IPAddress ipAddress)
{
try
{
// создаём класс управления событиями в потоке
AutoResetEvent waiter = new AutoResetEvent(false);
// записываем в массив байт сконвертированную в байтовый массив строку для отправки в пинг запросеbyte[] buffer = Encoding.ASCII.GetBytes("test asyncPing");
//создаем класс пинг
Ping ping = new Ping();
//указываем на метод, который будет выполняться в результате получения ответа на асинхронный запрос пинга
//NOTE: больше не требуется, смотри комментарии выше
//ping.PingCompleted += new PingCompletedEventHandler(funkPingCompleted);
//выставляем опции для пинга (непринципиально)
PingOptions options = new PingOptions(64, true);
int timeout = 500;
//посылаем асинхронный пинг на адрес с таймаутом 500мс, в нем передаем массив байт сконвертированных их строки в начале кода, используем при передаче указанные опции, после обращаемся к классу управления событиямиvar pingReply = ping.Send(ipAddress, timeout, buffer, options);
if (pingReply.Status == IPStatus.Success)
{
this.Invoke(new Action(delegate
{
// если ip адрес пингуеться, выводим ip в richTextBox1
richTextBox1.Text += pingReply.Address.ToString() + "\r\n";
// если ip адрес пингуеться, передаём этот ip в функция WmiInfo
//NOTE: по идее этот метод не должен напрямую обращаться к контролам, чтобы не блокировать UI работой к нему не относящийся,
// а просто собрать всю нужную информацию и уже затем передать её в UI-поток для вывода.
WmiInfo(pingReply.Address.ToString());
}));
}
}
catch (Exception ex)
{
this.Invoke(new Action(delegate
{
richTextBox1.AppendText("Ошибка! (в функции asinhroPing)\r\n");
richTextBox1.AppendText("Source: " + ex.Source + "\r\n" + "Message: " + ex.Message + "\r\n" + "HelpLink" + ex.HelpLink);
}));
}
}
private void WmiInfo(string a)
{
try
{
// Опции, если компьютер не в домене или у Вас нету прав Администратора
ConnectionOptions options = new ConnectionOptions();
ManagementScope scope;
//если на элементе checkBox чтоит галочка, записываем в свойства options значения логина и пароля их textBox-овif (авторизацияСПравамиАдминистратора_checkBox.Checked == true)
{
options.Username = имяПользователя_textBox.Text;
options.Password = пароль_textBox.Text;
//ManagementScope scope = new ManagementScope("\\\\" + a + "\\root\\cimv2", options);
scope = new ManagementScope("\\\\" + a + "\\root\\cimv2", options);
}
else
{
//ManagementScope scope = new ManagementScope("\\\\" + a + "\\root\\cimv2");
scope = new ManagementScope("\\\\" + a + "\\root\\cimv2");
}
//ManagementScope scope = new ManagementScope("\\\\" + a + "\\root\\cimv2", options);
scope.Connect();
richTextBox1.Text += "=============== Информация о процессоре ===============\r\n";
Win32_Processor(scope);
richTextBox1.Text += "=============== Информация о ОЗУ ===============\r\n";
Win32_PhysicalMemory(scope);
richTextBox1.Text += "=============== Информация о жёстких дисках ===============\r\n";
Win32_DiskDrive(scope);
richTextBox1.Text += "=============== Информация о видеоадаптере ===============\r\n";
Win32_VideoController(scope);
}
catch (Exception ex)
{
richTextBox1.Text += "Ошибка в функции WmiInfo! на ip: " + a + "\r\n";
richTextBox1.Text += "Source: " + ex.Source + "\r\n" + "Message: " + ex.Message + "\r\n" + "HelpLink" + ex.HelpLink;
}
}
// Класс Win32_Processor предоставляет сведения о процессоре.public void Win32_Processor(ManagementScope tmpAddress)
{
ObjectQuery query_Win32_Processor = new ObjectQuery("SELECT * FROM Win32_Processor");
ManagementObjectSearcher searcher_Win32_Processor = new ManagementObjectSearcher(tmpAddress, query_Win32_Processor);
ManagementObjectCollection queryCollection_Win32_Processor = searcher_Win32_Processor.Get();
foreach (ManagementObject info_Win32_Processor in queryCollection_Win32_Processor)
{
richTextBox1.Text += "------------------------------\r\n";
richTextBox1.Text += "ID устройства:\t\t" + info_Win32_Processor["DeviceID"] + "\r\n";
richTextBox1.Text += "Имя:\t\t\t" + info_Win32_Processor["Name"] + "\r\n";
richTextBox1.Text += "Производитель:\t\t" + info_Win32_Processor["Manufacturer"] + "\r\n";
richTextBox1.Text += "Описание:\t\t" + info_Win32_Processor["Description"] + "\r\n";
richTextBox1.Text += "Тип сокета:\t\t" + info_Win32_Processor["SocketDesignation"] + "\r\n";
richTextBox1.Text += "Текущая частота (MHz):\t" + info_Win32_Processor["CurrentClockSpeed"] + "\r\n";
richTextBox1.Text += "Версия:\t\t\t" + info_Win32_Processor["Version"] + "\r\n";
richTextBox1.Text += "Размер L2 кэша (Kb):\t" + info_Win32_Processor["L2CacheSize"] + "\r\n";
richTextBox1.Text += "Скорость L2 кэша (MHz):\t" + info_Win32_Processor["L2CacheSpeed"] + "\r\n";
//richTextBox1.Text += "Архитектура:\t\t" + info_Win32_Processor["Architecture"] + "\r\n";
// в переменную типа строка architecture записываем значение из коллекцииstring architecture = info_Win32_Processor["Architecture"].ToString();
// преобразуем строку в число и в зависимости от числа будет выведен рузельтатswitch (System.Int32.Parse(architecture))
{
case 0: richTextBox1.Text += "Архитектура:\t\t" + "x86" + "\r\n";
break;
case 1: richTextBox1.Text += "Архитектура:\t\t" + "MIPS" + "\r\n";
break;
case 2: richTextBox1.Text += "Архитектура:\t\t" + "Alpha" + "\r\n";
break;
case 3: richTextBox1.Text += "Архитектура:\t\t" + "PowerPC" + "\r\n";
break;
case 6: richTextBox1.Text += "Архитектура:\t\t" + "ia64" + "\r\n";
break;
}
//richTextBox1.Text += "Состояние:\t\t" + info_Win32_Processor["Availability"] + "\r\n";
// в переменную типа строка availability записываем значение из коллекцииstring availability = info_Win32_Processor["Availability"].ToString();
// преобразуем строку в число и в зависимости от числа будет выведен рузельтатswitch (System.Int32.Parse(availability))
{
case 3: richTextBox1.Text += "Состояние:\t\t" + "Running/Full Power" + "\r\n";
break;
case 4: richTextBox1.Text += "Состояние:\t\t" + "Warning" + "\r\n";
break;
case 5: richTextBox1.Text += "Состояние:\t\t" + "Testing" + "\r\n";
break;
case 10: richTextBox1.Text += "Состояние:\t\t" + "Degradation" + "\r\n";
break;
case 13: richTextBox1.Text += "Состояние:\t\t" + "Power Save - Unknow" + "\r\n";
break;
case 14: richTextBox1.Text += "Состояние:\t\t" + "Power Save - Low Power Mode" + "\r\n";
break;
case 15: richTextBox1.Text += "Состояние:\t\t" + "Power Save - Standby" + "\r\n";
break;
case 17: richTextBox1.Text += "Состояние:\t\t" + "Power Save - Warning" + "\r\n";
break;
}
richTextBox1.Text += "Процент загрузки (%):\t" + info_Win32_Processor["LoadPercentage"] + "\r\n";
richTextBox1.Text += "Статус:\t\t\t" + info_Win32_Processor["Status"] + "\r\n";
richTextBox1.Text += "------------------------------\r\n";
}
}
// Класс Win32_PhysicalMemory предоставляет сведения о физической памяти.public void Win32_PhysicalMemory(ManagementScope tmpAddress)
{
ObjectQuery query_Win32_PhysicalMemory = new ObjectQuery("SELECT * FROM Win32_PhysicalMemory");
ManagementObjectSearcher searcher_Win32_PhysicalMemory = new ManagementObjectSearcher(tmpAddress, query_Win32_PhysicalMemory);
ManagementObjectCollection queryCollection_Win32_PhysicalMemory = searcher_Win32_PhysicalMemory.Get();
foreach (ManagementObject info_Win32_PhysicalMemory in queryCollection_Win32_PhysicalMemory)
{
richTextBox1.Text += "Наименование устройства:\t" + info_Win32_PhysicalMemory["Name"] + "\r\n";
richTextBox1.Text += "Слот размещения:\t\t" + info_Win32_PhysicalMemory["DeviceLocator"] + "\r\n";
// т.к. Capacity показывает общий объем физической памяти в байтахlong size_in_MB = Int64.Parse(info_Win32_PhysicalMemory["Capacity"].ToString());
// переводим число из байт в мегабайты
size_in_MB = size_in_MB / (1024 * 1024);
richTextBox1.Text += "Объём памяти (Mb):\t" + size_in_MB + "\r\n";
richTextBox1.Text += "Быстродейсвтие (ns):\t" + info_Win32_PhysicalMemory["Speed"] + "\r\n";
}
}
public void Win32_DiskDrive(ManagementScope tmpAddress)
{
ObjectQuery query_Win32_DiskDrive = new ObjectQuery("SELECT * FROM Win32_DiskDrive");
ManagementObjectSearcher searcher_Win32_DiskDrive = new ManagementObjectSearcher(tmpAddress, query_Win32_DiskDrive);
ManagementObjectCollection queryCollection_Win32_DiskDrive = searcher_Win32_DiskDrive.Get();
foreach (ManagementObject info_Win32_DiskDrive in queryCollection_Win32_DiskDrive)
{
richTextBox1.Text += "Описание:\t\t" + info_Win32_DiskDrive["Description"] + "\r\n";
richTextBox1.Text += "Производитель:\t\t" + info_Win32_DiskDrive["Manufacturer"] + "\r\n";
richTextBox1.Text += "Модель:\t\t\t" + info_Win32_DiskDrive["Model"] + "\r\n";
richTextBox1.Text += "Идентификатор диска:\t" + info_Win32_DiskDrive["DeviceID"] + "\r\n";
richTextBox1.Text += "Тип интерфеса:\t\t" + info_Win32_DiskDrive["InterfaceType"] + "\r\n";
richTextBox1.Text += "Тип носителя:\t\t" + info_Win32_DiskDrive["MediaType"] + "\r\n";
richTextBox1.Text += "Колличество разделов:\t" + info_Win32_DiskDrive["Partitions"] + "\r\n";
}
}
public void Win32_VideoController(ManagementScope tmpAddress)
{
ObjectQuery query_Win32_VideoController = new ObjectQuery("SELECT * FROM Win32_VideoController");
ManagementObjectSearcher searcher_Win32_VideoController = new ManagementObjectSearcher(tmpAddress, query_Win32_VideoController);
ManagementObjectCollection queryCollection_Win32_VideoController = searcher_Win32_VideoController.Get();
foreach (ManagementObject info_Win32_VideoController in queryCollection_Win32_VideoController)
{
richTextBox1.Text += "Описание:\t\t" + info_Win32_VideoController["Description"] + "\r\n";
richTextBox1.Text += "Видеопроцессор:\t\t" + info_Win32_VideoController["VideoProcessor"] + "\r\n";
// т.к. AdapterRAM показывает общий объем графической памяти в байтах, конвертируем строку в инт и присваевыем переменнойlong size_AdapterRAM_in_MB = Int64.Parse(info_Win32_VideoController["AdapterRAM"].ToString());
// переводим число из байт в мегабайты
size_AdapterRAM_in_MB = size_AdapterRAM_in_MB / (1024 * 1024);
richTextBox1.Text += "Объём памяти (Mb):\t" + size_AdapterRAM_in_MB + "\r\n";
richTextBox1.Text += "Версия драйвера:\t\t" + info_Win32_VideoController["DriverVersion"] + "\r\n";
richTextBox1.Text += "Вендор:\t\t\t" + info_Win32_VideoController["PNPDeviceID"] + "\r\n";
// в переменную типа строка videoArchitecture записываем значение из коллекцииstring videoArchitecture = info_Win32_VideoController["VideoArchitecture"].ToString();
// преобразуем строку в число и в зависимости от числа будет выведен рузельтатswitch (System.Int32.Parse(videoArchitecture))
{
case 1: richTextBox1.Text += "Архитектура:\t\t" + "Other" + "\r\n";
break;
case 2: richTextBox1.Text += "Архитектура:\t\t" + "Unknown" + "\r\n";
break;
case 3: richTextBox1.Text += "Архитектура:\t\t" + "CGA" + "\r\n";
break;
case 4: richTextBox1.Text += "Архитектура:\t\t" + "EGA" + "\r\n";
break;
case 5: richTextBox1.Text += "Архитектура:\t\t" + "VGA" + "\r\n";
break;
case 6: richTextBox1.Text += "Архитектура:\t\t" + "SVGA" + "\r\n";
break;
case 7: richTextBox1.Text += "Архитектура:\t\t" + "MDA" + "\r\n";
break;
case 8: richTextBox1.Text += "Архитектура:\t\t" + "HGC" + "\r\n";
break;
case 9: richTextBox1.Text += "Архитектура:\t\t" + "MCGA" + "\r\n";
break;
case 10: richTextBox1.Text += "Архитектура:\t\t" + "8514A" + "\r\n";
break;
case 11: richTextBox1.Text += "Архитектура:\t\t" + "XGA" + "\r\n";
break;
case 12: richTextBox1.Text += "Архитектура:\t\t" + "Linear Frame Buffer" + "\r\n";
break;
case 160: richTextBox1.Text += "Архитектура:\t\t" + "PC-98" + "\r\n";
break;
}
}
}
private void авторизацияСПравамиАдминистратора_checkBox_CheckedChanged(object sender, EventArgs e)
{
if (авторизацияСПравамиАдминистратора_checkBox.Checked == true)
{
имяПользователя_textBox.ReadOnly = false;
пароль_textBox.ReadOnly = false;
}
else
{
имяПользователя_textBox.ReadOnly = true;
имяПользователя_textBox.ReadOnly = true;
}
}
}
}
Здравствуйте, nettro, Вы писали:
N>Извините, но к сожаления я вообще не понимаю, о чём Вы написали, т.к. знаком с c# и программирование в частности, если Вы могли заметить по теме достаточно условно... N>Я теперь даже не знаю с какой стороны подходить для полного переписывания проекта, и собственно как его переписывать, с моими ограниченными знаниями... А то что Вы упомянули, уверен ещё страшнее уже имеющегося
Наоборот, оно проще и лаконичнее. Там пониже, я слегка отрефакторил ваш код — заметьте, почти не трогая ваш код, а лишь обрамляя его в новые конструкции. В этом вся мощь и прелесть TPL и PLINQ.
Как тут правильно заметили, да я и сам там в комментариях к коду упомянул — надо отделить друг от друга две части программы: часть, собирающую информацию, и часть, выводящую её пользователю или записывающую её в БД. Тогда первую часть можно будет распараллелить по-полной, окончательно избавившись от тормозов.
Здравствуйте, Vladek, Вы писали:
V>Здравствуйте, nettro, Вы писали:
N>>Извините, но к сожаления я вообще не понимаю, о чём Вы написали, т.к. знаком с c# и программирование в частности, если Вы могли заметить по теме достаточно условно... N>>Я теперь даже не знаю с какой стороны подходить для полного переписывания проекта, и собственно как его переписывать, с моими ограниченными знаниями... А то что Вы упомянули, уверен ещё страшнее уже имеющегося
V>Наоборот, оно проще и лаконичнее. Там пониже, я слегка отрефакторил ваш код — заметьте, почти не трогая ваш код, а лишь обрамляя его в новые конструкции. В этом вся мощь и прелесть TPL и PLINQ.
V>Как тут правильно заметили, да я и сам там в комментариях к коду упомянул — надо отделить друг от друга две части программы: часть, собирающую информацию, и часть, выводящую её пользователю или записывающую её в БД. Тогда первую часть можно будет распараллелить по-полной, окончательно избавившись от тормозов.
Огромное спасибо Вам за полностью приведённый, отредактированный код с Вашими пояснениями почти к каждой строке кода, для меня просто неоценима подобного рода информативность.
Сейчас проверил на домашней сети, работа проекта колосально изменилась в лучшую сторону. Завтра буду тестить на работе.
По поводу разделения программы на 2 части, честно говоря для меня это всё одна большая часть, но как уже писали добрые люди в постах ранее, необходимо отделить функции типа public void Win32_ххх от программы и вынести это так сказать за пределы данной формы, как советовали опять таки выше — в отдельный класс. Так вот тут у меня и возникает может не очень корректный вопрос:
обязательно в этом новом классе использовать свойства get и put а само описание Win32_xxx должно находиться ещё где то или ниже, или можно в новом классе описать прям такими функциями какие они есть?
Здравствуйте, Vladek, Вы писали:
V>Автор, изучай Parallel LINQ, Task Parallel Library и async/await — это позволит писать тебе очень лаконичный код, особо не заморачиваясь низкоуровневыми деталями. И уж точно не придётся вникать в допотопные BackgroundWorker-ы. Под катом отрефакторенная версия твоего кода, мои дополнительные комментарии начинаются с //NOTE:. V>ProgressBar тут попробуй привязать сам, через Invoke.
Здравствуйте, Vladek, Вы писали:
V>А как же Parallel LINQ, Task Parallel Library, async/await наконец? Мы не ищем лёгких путей, да?
прежде чем трогать PLINQ, TPL и тем более async/await надо сначала разобраться что такое делегаты, потоки, пул потоков и как с этим всем работать, потом можно переходить к LINQ, и только потом к PLINQ и всему остальному. сначала люди пишут велосипеды, а потом используют модные библиотеки. и никак не наоборот
Здравствуйте, nettro, Вы писали:
N>Добрый день! А в чём состоит засада и есть ли у неё пути решения?
Ну так WmiInfo как выполнялось, так и продолжает выполняться в UI-потоке. Рабочий поток после вызова this.Invoke ставит в очередь и ждет, пока UI-поток формы выполнит WmiInfo. Если IP-адрес пингуется, но не поддерживает WMI (это может быть не компьютер, или компьютер под управлением не-Windows), или происходит ошибка аутентификации (на том компьютере не настроен DCOM), то форма будет висеть. Что и происходит у меня. С точки зрения ping'а у вас, было оно сделано допотопно или современно — не важно, все и так было сделано правильно — использование TPL не дало ничего нового. Но изучать его, конечно же, надо. Только я не уверен, что на изучение BackgroundWorker надо забить. Мне кажется, сперва надо научиться пользоваться BackgroundWorker'ом и ThreadPool'ом.
Здравствуйте, Fortnum, Вы писали:
F>Если IP-адрес пингуется, но не поддерживает WMI (это может быть не компьютер, или компьютер под управлением не-Windows), или происходит ошибка аутентификации (на том компьютере не настроен DCOM), то форма будет висеть. Что и происходит у меня.
К моему огромнейшему сожалению, это происходит и у меня...((
F>использование TPL не дало ничего нового. Но изучать его, конечно же, надо.
Да изучать по хорошему надо всё с чем работаешь или приходиться работать, но сами понимаете что с этим возникают некие проблемы когда есть какое то ограничение по времени...
Не сочтите за наглость, но если Вы при написании кусочков кода касаемых BackgroundWorker и ThreadPool, писали это в проекте и у Вас получилось избавиться от зависания формы, не могли бы Вы выложить этот проект, а то я смотрю мнения разделились, от чего я запутался ещё больше...
Спасибо.
Здравствуйте, nettro, Вы писали:
N>Здравствуйте, Fortnum, Вы писали:
F>>Если IP-адрес пингуется, но не поддерживает WMI (это может быть не компьютер, или компьютер под управлением не-Windows), или происходит ошибка аутентификации (на том компьютере не настроен DCOM), то форма будет висеть. Что и происходит у меня.
N>К моему огромнейшему сожалению, это происходит и у меня...((
F>>использование TPL не дало ничего нового. Но изучать его, конечно же, надо.
N>Да изучать по хорошему надо всё с чем работаешь или приходиться работать, но сами понимаете что с этим возникают некие проблемы когда есть какое то ограничение по времени...
N>Не сочтите за наглость, но если Вы при написании кусочков кода касаемых BackgroundWorker и ThreadPool, писали это в проекте и у Вас получилось избавиться от зависания формы, не могли бы Вы выложить этот проект, а то я смотрю мнения разделились, от чего я запутался ещё больше... N>Спасибо.
Если ещё кто то отзовётся на тему, этот вопрос не оставьте без внимания
N>По поводу разделения программы на 2 части, честно говоря для меня это всё одна большая часть, но как уже писали добрые люди в постах ранее, необходимо отделить функции типа public void Win32_ххх от программы и вынести это так сказать за пределы данной формы, как советовали опять таки выше — в отдельный класс. Так вот тут у меня и возникает может не очень корректный вопрос:
обязательно в этом новом классе использовать свойства get и put а само описание Win32_xxx должно находиться ещё где то или ниже, или можно в новом классе описать прям такими функциями какие они есть?
F>Не понял, каким образом этот факт влияет на выбор между использованием BackgroundWorker'а и запуском отдельного Thread'а?
Ну не нужна автору кнопка Stop pinging, а Abort треда, который выполняет пинг не приводит нарушению целостности. Зачем ему тратить время и вникать в BackgroundWorker? Я думаю это некая админская тулза для внутреннего использования, я бы сделал простой отдельный тред на каждый пинг.
Здравствуйте, igor-booch, Вы писали:
F>>Не понял, каким образом этот факт влияет на выбор между использованием BackgroundWorker'а и запуском отдельного Thread'а?
IB>Ну не нужна автору кнопка Stop pinging, а Abort треда, который выполняет пинг не приводит нарушению целостности. Зачем ему тратить время и вникать в BackgroundWorker? Я думаю это некая админская тулза для внутреннего использования, я бы сделал простой отдельный тред на каждый пинг.
Все же 254 рабочих потока — это жестоко. Но для того, чтобы въехать в суть происходящего сойдет. Т.к. автору нужно для начала понять, как в richTextBox выводить результаты работы этих потоков, чтобы они не путались между собой.
Здравствуйте, nettro, Вы писали:
N>>Не сочтите за наглость, но если Вы при написании кусочков кода касаемых BackgroundWorker и ThreadPool, писали это в проекте и у Вас получилось избавиться от зависания формы, не могли бы Вы выложить этот проект, а то я смотрю мнения разделились, от чего я запутался ещё больше... N>>Спасибо.
N>Если ещё кто то отзовётся на тему, этот вопрос не оставьте без внимания
Немного не понял, а что конкретно нужно? по-моему уже довольно много кода выложили, чтоб избавиться от зависания.
N>>По поводу разделения программы на 2 части, честно говоря для меня это всё одна большая часть, но как уже писали добрые люди в постах ранее, необходимо отделить функции типа public void Win32_ххх от программы и вынести это так сказать за пределы данной формы, как советовали опять таки выше — в отдельный класс. Так вот тут у меня и возникает может не очень корректный вопрос: N>обязательно в этом новом классе использовать свойства get и put а само описание Win32_xxx должно находиться ещё где то или ниже, или можно в новом классе описать прям такими функциями какие они есть?
а что за свойства такие get и put? может имелось в виду getter/setter?
можно сделать класс вообще с одним публичным методом возвращающим строку (в зависимости от конкретной задачи).
/*static*/class GatherInfo
{
public/*static*/ String GetInfo()
{
String result = Win32_Processor();
result += Win32_xxx();
result += Win32_yyy();
//etcreturn result;
}
private/*static*/ String Win32_Processor()
{
return [Some info about processor]
}
private/*static*/ String Win32_xxx()
{
return [another info]
}
}
может и не самый лучший способ, но самый простой и почти не требует доработок
Здравствуйте, motormanyak, Вы писали:
M>Немного не понял, а что конкретно нужно? по-моему уже довольно много кода выложили, чтоб избавиться от зависания.
я имел ввиду, если приведённые куски кода Вы писали в проекте, с дальнейшей компиляцией и просмотром работоспособности, а не сразу на форум, то был бы очень Вам благодарен, если бы этот проект был выложен, для просмотра как у Вас это всё дело реализовано
N>>>По поводу разделения программы на 2 части, честно говоря для меня это всё одна большая часть, но как уже писали добрые люди в постах ранее, необходимо отделить функции типа public void Win32_ххх от программы и вынести это так сказать за пределы данной формы, как советовали опять таки выше — в отдельный класс. Так вот тут у меня и возникает может не очень корректный вопрос: N>>обязательно в этом новом классе использовать свойства get и put а само описание Win32_xxx должно находиться ещё где то или ниже, или можно в новом классе описать прям такими функциями какие они есть?
M>а что за свойства такие get и put? может имелось в виду getter/setter? M>можно сделать класс вообще с одним публичным методом возвращающим строку (в зависимости от конкретной задачи).
/*static*/class GatherInfo
{
public/*static*/ String GetInfo()
{
String result = Win32_Processor();
result += Win32_xxx();
result += Win32_yyy();
//etcreturn result;
}
private/*static*/ String Win32_Processor()
{
return [Some info about processor]
}
private/*static*/ String Win32_xxx()
{
return [another info]
}
}
M>может и не самый лучший способ, но самый простой и почти не требует доработок
Извиняюсь, в прошлом сообщении не правильно написал, не свойства get и put, а get и set, что то на подобие этого (взято с wiki):
class MyClass
{
private int p_field;
public int Field
{
get
{
return p_field;
}
private set
{
p_field = value;
}
}
}
Здравствуйте, Fortnum, Вы писали:
F>А вообще, я бы порекомендовал отделить функционал по сбору информации с компьютеров от UI, выделив этот функционал в отдельный класс. Если интересно, чуть позже напишу как именно.
Здравствуйте, nettro, Вы писали:
N>p.s. Если кто то откликнется на тему и поможет на конкретном примере привязать BackgroundWorker и ProgressBar к проге, а то сколько не пытаюсь по статьям с msdn, как то пока не получается... По необходимости могу прислать проект с кодом.
Вот здесь обновленная версия программы с ProgressBar и без лишних тормозов от частых обращений к UI. Все данные по каждому хосту накапливаются в объекте класса StringBuilder, и только потом его содержимое добавляется в текстовое поле.
Здравствуйте, Vladek, Вы писали:
V>Здравствуйте, nettro, Вы писали:
N>>p.s. Если кто то откликнется на тему и поможет на конкретном примере привязать BackgroundWorker и ProgressBar к проге, а то сколько не пытаюсь по статьям с msdn, как то пока не получается... По необходимости могу прислать проект с кодом.
V>Вот здесь обновленная версия программы с ProgressBar и без лишних тормозов от частых обращений к UI. Все данные по каждому хосту накапливаются в объекте класса StringBuilder, и только потом его содержимое добавляется в текстовое поле.
АААААА!!! Огромнейшее Вам спасибо!! Вы 2ой раз меня выручаете, за что вам большое спасибо!
К сожалению сегодня уже не успею протестировать , дома почитаю код и постараюсь понять, а завтра уже протестирую работу, и отпишусь по поводу работы и кода, не закрывайте пожалуйста пока тему.