Чем отличается pid от hinstance


Чем отличается pid от hinstance?

Что это за переменная такая? Можно ли ее использовать в проектах без форм? И как узнать имя файла моего проекта, если у меня есть его хендл?
Заранее благодарен.

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

Если не знаешь что такое хендл — поясню: Это дескриптор(указатель) приложения.

\\ Это дескриптор(указатель) приложения.

Не совсем так.
Скажем точнее. MS не очень-то хотело давать программистам доступ к «потрохам» Windows напрямую через указатели. На всякий случай. Вместо этого им дали «рукоятки»-хэндлы. Используются самыми различными функциями WinAPI. Можно рассматривать как некое значение которое Windows умеет преобразовать в указатель на нужный объект ядра. А уж приложение это, окно или другой объект это смотря что за хендл

Является ли HINSTANCE действительным для потоков?

В одном приложении .exe WinMain точка входа имеет параметр HINSTANCE , который должен быть псевдо-дескриптором (поскольку эквивалентен GetModuleHandle(NULL) , который возвращает псевдо-дескриптор, согласно MSDN). Я предполагаю, что это псевдо, потому что есть оба специальных значения (например, NULL для обозначения модуля точки входа) и константы, используемые для возврата ошибки (что-то меньшее, чем 32).

MSDN явно описывает его как указатель (в настоящее время эквивалентный HMODULE ) на базовый адрес модуля; мы знаем, что это может иметь совершенно иное значение для 16-битных приложений, но в 32/64 бит мира каждый процесс имеет свое собственное адресное пространство, тогда его точное значение бесполезно, вероятно, всегда одинаково для каждого экземпляра и абсолютно бессмысленно вне его процесса.

Все сказанное, это мой первый вопрос: можем ли мы (формально, несмотря на то, что MSDN кажется противоречивым), предположим, что HINSTANCE является указателем (даже если честно, я не вижу никакого использования для этого), или лучше предположить, что это (псевдо) дескриптор (где его значение непрозрачно)?

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

Мы можем думать, что дескриптор процесса действителен для каждого процесса, но несколько (угловых) случаев заставляют меня думать, что мы должны считать его действительным для каждой нити. Если эти угловые случаи существуют тогда (даже если они обычно работают как ожидаемые для каждого процесса), мы полагаемся на детали реализации, поведение undefined может быть изменено для разных архитектур, версий, сред.

Посмотрим на случай, когда я вижу проблему (код настолько тривиален, что я просто описываю сценарий): DLL обычно имеет разделяемый раздел кода, но они могут также иметь (даже если это довольно необычно) раздел разделенных данных (например, для обмена обширными данными по всем процессам или для реализации быстрого и грязного механизма МПК). Это может быть необычным, но возможным (и довольно легко реализовать, например, в VС++, с несколькими директивами #pragma data_seg и comment(linker) ). В этом случае мы знаем (внутри нашей DLL), что мы не можем сравнивать HINSTANCE (потому что они могут иметь одинаковое значение), но также IMO мы не можем доверять HINSTANCE , которые мы имели из потока A (в нашей DLL) сопоставим с HINSTANCE , мы имеем в потоке B. Короче: каждый раз, когда нам нужно HINSTANCE , мы должны вызвать GetModuleHandle(NULL) , чтобы получить актуальную актуальную для каждой нить.

Как бонус, я также понял бы, как это относится к HINSTANCE , мы получаем как параметр, когда он приходит от WinMain . Теоретически это для потока, но, например, CreateWindow() будет корректно разрешать его (поскольку scope — это текущий исполняемый процесс, конечно, предполагая, что вызывающий поток имеет свой собственный цикл сообщений)?

РЕДАКТИРОВАТЬ кажется, что я был совершенно не прав, я помню сходство потоков для HMODULE, но оно относится к Windows Mobile.

Если этот параметр равен NULL, GetModuleHandle возвращает псевдо-дескриптор текущего процесса. [. ] Псевдо-дескриптор — это специальная константа, которая интерпретируется как текущий дескриптор потока. Вызывающий поток может использовать этот дескриптор для указания самого себя, когда требуется описатель потока.

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

Renault Megane Горыныч › Бортжурнал › ДИАГНОСТИКА Часть2 TORQUE

Привет друзья ! Сегодня речь пойдет о программе TORQUE PRO на данный момент это последняя версия)))
Эта программа может работать как со стандартными наборами PID- ов так и спользовательскими.
Разберем на примере что такое PID?
PID это параметр автомобиля зашифрован условным кодом-идентификатором, например «PR071» —PID.
Так где же нам взять эти наборы специальных PID-ов для моего автомобиля спросите вы? Ответ: все они находятся в уже доступной базе Renault CLIP v1.60, с которой может работать программный комплекс PyRen.

ПИД-регуляторы – для чайников-практиков

Что мы делаем?

Итак, мы делаем регулятор холостого хода.
В данном случае однозначно просится к реализации система управления с обратной связью. В своей статье про «Датчики и АЦП» я рассказывал про систему управления с обратной связью, подробности ищите там. Также там была неплохая картинка на эту тему:

Что это будет в данном случае?
Мы хотим управлять оборотами двигателя в состоянии холостого хода. Для этого у нас есть шаговый двигатель, который открывает/закрывает заслонку для регулировки подачи воздуха. Также у нас есть таблица, которая указывает желаемую частоту двигателя в зависимости от текущей температуры. Управление объектом тут у нас выполняется шаговым двигателем. Состояние объекта определяется 1) оборотами двигателя и 2) текущей температурой.
Для данной картинки получаем следующее:


  • Объект — двигатель автомобиля;
  • Измерение производится для 1) оборотов двигателя (в нашем случае – промежуток времени между соседними импульсами тахометра, которых два на один оборот) и 2) температуры двигателя (сопротивление терморезистора);
  • Воздействие направлено на обороты двигателя, для чего регулируется заслонка воздуха. Регулируется она шаговым двигателем. Значит, мы задаем степень смещения для шагового двигателя;
  • Расчет — вычисление требуемого смещения в зависимости от 1) оборотов двигателя, 2) температуры двигателя, 3) текущего состояния шагового двигателя;
  • Общение в данном случае отсутствует (впрочем, я выведу наружу COM-порт для настройки/диагностики устройства).

Итак, мы измерили все, что надо, и получили Обороты (t) — текущие обороты двигателя (текущего момента времени t), Температуру (t) — текущую температуру. Также у нас есть Шаг (t) — текущий шаг заслонки и Обороты (t+1) — новое значение оборотов двигателя, которое зависит от температуры. Получить нам в итоге надо Шаг (t+1) — новое положение заслонки.
Немного математики:

Что это за функция? Она выдает нам текущее значение шага, которое зависит от всего вышеперечисленного. Как она это делает?
Вся собака зарылась в том, что мы хотели на данный шаг получить одни обороты, а они в реальности совсем другие! Значит, нам нужно знать значение текущей ошибки (невязки), и она может быть вычислена как разность предполагаемых оборотов в будущем и текущих:

Ошибка (t) = Обороты (t+1)Обороты (t).

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

Теперь можно вынести значение предыдущего шага за скобки:

Все понятно? Мы на каждом шаге работы регулятора должны задавать текущее положение шагового двигателя. Он зависит, понятное дело, от предыдущего шага и от ошибки. Шаговый двигатель управляется смещениями, поэтому нам не так уж и важен текущий шаг (проигнорируем тему выхода за пределы допустимого количества шагов – моему другу электрику это знать не обязательно). В итоге можно перейти к такой записи:

ИзменениеШага (t+1) = Функция .

Во как все упростилось! В итоге мы пришли к загадочной функции, которая зависит от текущей ошибки. Что это за функция? Думаю, все уже догадались – это пропорционально-интегрально-дифференциальный регулятор.
Справедливости ради надо указать темы, которые мы проигнорировали (опять же – эти тонкости не для электриков!):

  • дискретностьtили размер шага. С какой частотой мы делаем воздействие? Я не знаю – я еще только разрабатываю сие чудо техники. Думаю, что шага в 50 мсек хватит за глаза. В моей программе это будет настраиваемый из EEPROM параметр. Впрочем, эту тему игнорировать нельзя и мы к ней еще вернемся;
  • управление шаговым двигателем. Там своя масса нюансов. Читайте Интернет, googl-ите – тема широко освещена;
  • связь функции с шагом и оборотами. Ошибку-то мы вычислили, ее размерность совпадает с размерностью оборотов двигателя (в моем случае это время, мсек). Как она преобразуется в размерность шага? Эту тему мы тоже оставим за бортом, т. к. это не имеет отношения к теме, собственно, ПИД-регуляторов. Для особо любопытных – я буду брать % от максимально возможной ошибки (задается максимально/минимально допустимыми оборотами) и пропорционально его превращать в % от максимально возможного одиночного изменения шага (задается полным диапазоном шагов двигателя).

Формула ПИД-регулятора

Как я и обещал, формул тут не будет… ну, почти не будет. И этот раздел – как раз и будет формулой. Обещаю – больше формул не будет! Так что потерпите!
Итак, формула ПИД-регулятора:

(навеяно Википедией)
Тут у нас следующие буковки (разъясним чуть ниже):

  • u (t) — наша Функция;
  • P — пропорциональная составляющая;
  • I — интегральная составляющая;
  • D — дифференциальная составляющая;
  • e (t) – текущая ошибка;
  • Kp — пропорциональный коэффициент;
  • Ki — интегральный коэффициент;
  • Kd — дифференциальный коэффициент;

Все, расслабились – больше эта формула нам в работе не понадобится, она для пояснения сути.
А суть тут такая.
У нас есть воздействие, наша Функция (u (t) ). Она состоит из трех составляющих – Пропорциональной, Интегральной и Дифференциальной (отсюда и ПИД-регулятор).
Формула в вышеприведенном виде хороша для изучения, но неудобна для расчетов (хотя бы потому, что в вычислительной технике надо переходить к численным методам). В программной реализации, если верить этой статье, переходят к дискретной реализации:

Вот это уже выглядит куда реальнее и понятнее! Мы вычисляем сумму трех составляющих. Каждая из них определяется своими коэффициентами. Если данный коэффициент нулевой, то составляющая в вычислении не участвует. С этой формулой мы и будем работать далее, ее я и реализую.
Впрочем, есть еще и другая, рекуррентная реализация:

Какая из них лучше/правильней? Математика, в общем-то, одинаковая. Коэффициенты тоже. Говорят, что есть разные подводные булыжники при реализации.
Обратите внимание! Коэффициенты тут – обязательно дробные числа! В языке программирования Си – как минимум float, а лучше бы и double.
Вся магия ПИД-регуляторов – именно в этих коэффициентах. Как их подбирать – посмотрим в конце. А сейчас переведем дух от математики и поедем к изучению поведения этой формулы.
Все расчеты и моделирование я проводил на модели в Excel. Он – файл – приложен внизу, с ним можно поиграться самостоятельно. Модель – сугубо для ознакомления с идеей! Т. е. не надо ее стараться привести к какому-то реальному процессу, искать в ней научный смысл и т. п. Там все цифры слегка «отфонарные». Но зато и файл простенький и несложный. И моделируется быстро. И дает возможность понять суть ПИД-регулятора. Пару слов по файлу я дам в конце.

Пропорциональная составляющая

Первый коэффициент – пропорциональный. Он самый очевидный и понятный (реально я когда-то давно сам вывел формулу ПИД-регулятора, кому-то показал, и он рассказал мне об этой теории; так вот, вывод я начал с пропорционального вида).
Рассмотрим его – пропорционального коэффициента — влияние на результат.

Илон Маск рекомендует:  area в HTML

«Ожидаемое» – это то, что мы хотим получить. Вначале оно равно какому-то низкому значению (в нашем примере – это те обороты двигателя, которые создает стартер). Далее, в момент времени 3, оно вдруг стало равно 2000 (завели мотор и, исходя из текущей температуры, мы должны получить 2000 оборотов в минуту).
(Небольшая ремарка – в автомобилях частоту измеряют в кол-во оборотов в минуту!)
Сделаем первый вариант: Kp = 2. Посмотрим на красную линию. Что мы видим? По ходу дела обороты начали расти – ошибка стала снижаться – значение коррекции постепенно растет — красная линия растет (обороты двигателя увеличиваются). В какой-то момент (почему-то 13-ый) обороты достигают требуемой величины. Класс? Супер! Да вот только медленно как-то…
Попробуем другой коэффициент: Kp = 5. Что видим? Зеленая линия. Достигла результата шустро – на 6-ом шаге. Класс! Да вот – ой! – перелет (по науке перерегулирование). Потом, правда, вернулись назад – порядок.
А что если коэффициент сделать еще больше? Kp = 20. Синяя линия – бух! За один шаг! Но – сразу перелет. Потом падаем вниз – ошибка стала отрицательной. Опять сильно вниз! Рывок вверх! Опять вниз! Что видим? Пошли колебания. Они, слава Богу, затухающие.
Если увеличивать коэффициент больше, то такие колебания могут стать незатухающими. Система начнет колебаться все больше и больше, пока не … ну-у, тут уже все зависит от конкретной системы.
Какова природа колебаний? Система, на которую воздействуют, всегда (в реальной жизни) инерционна. Обороты повышаются – коэффициент падает к нулю. И вот – достигли нужной точки. Коэффициент ошибки (и регулирования) достиг нуля. Но ведь процесс поднятия оборотов инерционен! Движёк раскочегарен, обороты продолжают по инерции расти. И тогда будем двигать заслону назад – опускать обороты. Опять достигли нуля – а обороты продолжают падать… И так, в общем-то, до бесконечности.
Особенно это очевидно в системах поддержания температуры. Нагрев надо выключать до нужной температуры – чтобы сам нагреватель перестал разогреваться и греть объект.
Для решения этой проблемы используется следующая –

Интегральная составляющая

Эта составляющая накапливает ошибку (как и любой интегратор). Т. е. постепенно накапливается эта самая ошибка, интегратор «наполняется» и его воздействие увеличивается. Эффект от такого накопления не мгновенен — ибо ошибка должна накопиться, на что уходит некоторое количество шагов алгоритма.
Рассмотрим случай, когда Kp = 5, а Ki будем менять:


Вариант 1 (красный) – Ki = 0.
Вариант 2 (зеленый) – Ki = 0.2.
Вариант 3 (синий) – Ki = -0.3.
Использование положительного коэффициента (зеленая линия) в данном случае, пожалуй, ничего нам не дало. А вот отрицательный коэффициент (синяя линия) очень даже неплохо помог! Но вот только линяя пошла вниз, и потом она приведет к раскачиванию системы… (но на практике раскачивания системы, как правило, не происходит, т. к. постоянно будут коррекции текущего состояния)
Итак, интегральная составляющая позволила нам сгладить резкий эффект пропорциональной составляющей. Это неплохо!
Но вы погодите – сейчас нам покажет всю свою мощь

Дифференциальная составляющая

Эта составляющая пропорциональна темпу изменений. Как подсказали в комментариях, она «придает ускорение».
Как и ранее, Kp = 5, а Kd будем менять:

Вариант 1 (красный) – Kd = 0.
Вариант 2 (зеленый) – Kd = 0.2.
Вариант 3 (синий) – Kd = -0.2.
Каково? И сглаживает, и не дает раскачиваться в будущем!

Реакция на помехи

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

Шумовое (случайное) воздействие – одинаковое для всех вариантов.
Вариант 1 (красный) – Kp = 10, Ki = 0, Kd = 10.
Вариант 2 (зеленый) – Kp = 10, Ki = 2, Kd = 0.
Вариант 3 (синий) – Kp = 10, Ki = 2, Kd = 6.
Как видно, с добавлением составляющих стабильность (немного) увеличивается.

Настройка

Я думаю, общее представление о формуле ПИД-регулирования вы получили. Программируется легко, эффект красивый. И следующий вопрос у вас будет – «а как получит коэффициенты»? И вот тут все становится кисло… Потому что, если до этих пор шла строгая математика, то дальше начинаются танцы с бубнами, шаманство и шайтанство. Нет, все-таки есть какие-то точные методы, но мне становится плохо при мысли, что я должен это проделать для своего двигателя в автомобиле!
В комментариях мой метод (и мое понимание) настройки разгромили, закопали и затоптали. И порекомендовали прочитать хорошую книгу «ТЕОРИЯ АВТОМАТИЧЕСКОГО УПРАВЛЕНИЯ ДЛЯ «ЧАЙНИКОВ»» К.Ю. Полякова (созвучное название, не находите?). Согласен, тема (настройки) сложная, для меня неоднозначная, поэтому соглашусь с комментирующими — надо прочитать эту книгу и глубже вникать в тему. Но… это уже будет не для уровня чайников, не так ли? В книге Полякова формул более чем достаточно, а это уже уровень электро-чайника! Так что позвольте мне изложить свой подход. Неидеальный, но достаточный для старта и более детального изучения темы.

Прежде всего, вы должны иметь четкое представление о своей системе регулирования – насколько она инерционна? какие шумы на нее могут воздействовать? какие воздействия (результаты функции ПИД-регулятора) для нее недопустимы?
Следующий вопрос – насколько вашу систему можно погонять туды-сюды? Все методы, что я нашел, базируются на тестовых воздействиях на систему и анализе результатов. Нужно пробовать, пробовать, считать, считать, считать (ну или по науке — строить модель)… А температура двигателя-то растет, и воздействие через полчаса работы уже будет совсем не таким, как при начале. А как вы в один и тот же день проверите работу при -30оС и +30оС.
Вот несколько полезных советов оттуда же:

  • увеличение пропорционального коэффициента увеличивает быстродействие и снижает запас устойчивости;
  • с уменьшением интегральной составляющей ошибка регулирования с течением времени уменьшается быстрее;
  • уменьшение постоянной интегрирования уменьшает запас устойчивости;
  • увеличение дифференциальной составляющей увеличивает запас устойчивости и быстродействие.

Впрочем, несколько обнадеживает информация из другой статьи: «ПИД-регуляторы замечательны тем, что для их хорошей настройки не требуется отличного понимания формальной теории управления системами. При этом они позволяют решить около 90% всех задач управления простыми системами замкнутого цикла.»
Там же описана процедура настройки. Рекомендую почитать — просто и со вкусом.
Мой же подход базируется на следующем.

Частота опроса/воздействия

Есть очень важный момент работы при разработке ПИД-регулятора: воздействие должно быть строго периодичным, т. е. производиться через равные промежутки времени! Аналогично, ошибка должна вычисляться также периодически.
Какой должен быть период измерений/воздействий? Для начала определите время стабилизации системы – за сколько должно быть достигнуто устойчивое состояние (в случае регулятора холостого хода хватит периода 0.5 секунды). Потом разделите это время на 10 … 100 – и вы получите длительность шага (в моем случае хватит и 10 мсек). А вообще – чем выше частота, тем лучше! Но надо помнить, что операции с дробными числами весьма медленны. Фактически, они и зададут вам период работы.
Посмотрим, как период опроса (и воздействия) влияет на качество результата:

Коэффициенты ПИД-регулятора: – Kp = 10, Ki = 0, Kd = 0.
Вариант 1 (красный) – период опроса 0.5 у.е.
Вариант 2 (зеленый) – период опроса 0.35 у.е.
Вариант 3 (синий) – период опроса 0.15 у.е.
Как видим, в первом случае есть мощные выбросы. Во втором случае (70% от первого периода) они стали слабее, а в третьем (30%) – преобразование вообще получилось гладким! Т. е. для первых двух вариантов нужны дополнительно интегральная или дифференциальная составляющие, а для последнего мы обошлись только пропорциональной. А это существенная разница в вычислениях!
Так что вопросу выбора периода надо уделить первостепенное внимание.
Итак, время выбрали, все коэффициенты сбросили в ноль. Начинаем управлять системой.
Идеально, если вы сможете собрать статистику – записывать воздействие/результат/сопутствующую информацию в текстовый файл. Потом его можно открыть в том же Excel и проанализировать.

Настройка пропорционального коэффициента Kp

Для начала я устанавливаю коэффициент Kp в 1 и смотрю, что будет. Растет слишком медленно – увеличиваю. В какой-то момент начнутся перелеты и колебания. Значит, многовато – уменьшаем. Исчезли – немного увеличиваем. Начались – немного уменьшаем. Исчезли — … И так далее, пока не надоест. В итоге получили достаточно устойчивый пропорциональный регулятор, который надо немного скорректировать (надо ли? Если все работает вполне качественно, то не морочим себе голову и считаем, что все настроено)

Настройка дифференциального коэффициента Kd

Понемногу наращиваю коэффициент Kd — 0.5, 1,… Колебания системы уменьшаются, все работает красивее… Пока не происходит обратное – начинаются мощные выбросы. Все, перерегулировали, уменьшаем.
Итак, имеем выбросы – уже меньше, но все равно имеем. Самое то сгладить, притормозить воздействие!

Настройка интегрально го коэффициента Ki

Шаманим дальше. Берем совсем немного – 0.1 для начала. Можно попробовать и небольшое отрицательное значение. Смотрим, пробуем, крутим…
Процесс этот – настройки – итерационный. Стоит пробовать разные варианты, начинать сначала. Для меня он по-прежнему туманен и шайтанен.

Дополнительные модули?


Построили, сделали — и увидели, что все равно есть какие-то биения, ненужные колебания. Ну-с, а что вы хотели. Серьезный подход изобилует формулами, сложными расчетами!
И Бог с ними — вот что я скажу! Можно вполне на выходе добавить усреднение нескольких последних тактов — дешево (в плане расчетов) и сердито (в плане стабильности воздействий). Можно поставить еще какие-нибудь фильтры.
Не будем догматичными! Кто сказал, что нужно ограничиться одним лишь ПИД-регулятором?

Информация по модели

А теперь – обещанная пара слов по Excel-файлу. В нем реализована модель, схожая с перемещением по линии. Не очень корректная, возможно, но вполне достаточная для старта (может, по результатам обсуждения сделаю более точную модель — возьму для примера модель электродвигателя из статьи Полякова). Есть предыдущее положение, скорость и ускорение. Скорость рассчитывается как разница предыдущих перемещений. Ускорение определяется как П-И-Д – воздействие, умноженное на коэффициент усиления (в верхней части таблицы).
В таблице представлены 3 варианта. Они настраиваются сверху:

  • Коэффициент усиления задает множитель для ускорения. Меньше единицы – воздействие будет «тормозить», больше – раскачивать систему;
  • Начальное значение — стартовое значение оборотов двигателя;
  • Шаг времени используется в формуле расчета новых значений. Его увеличение «ускоряет» моделирование (и исчезают все мелкие шаги);
  • Шум — диапазон изменения случайного числа. Ставите 0 – и его воздействие на моделирование исчезает;
  • Воздействие — три коэффициента для расчета. Меняете, смотрите;
  • Колонка желаемое — то значение, к которому стремится ПИД-регулятор. Его можно менять в любой клетке по высоте. Там сейчас заложено несколько ступенек

Результат моделирования – 2 графика. Первый – маленький – показывает несколько значений вначале. Второй показывает всю таблицу.
Попробуйте поменять в этом файле коэффициенты – результат будет сразу виден. По ходу дела вы сами заметите закономерности, о которых тут написано (и выведете свои новые).

В заключение – о реализации

С теорией вроде бы разобрались. Теперь – о реализации.
Сердце регулятора – формула. Она оперирует с дробными числами. Учтите, что такие операции и на 32-хбитным контроллерах выполняются не моментально, что тут говорить о 8-битках! Вычисление отдельных частей формулы – П-, И-, Д- — лучше написать не одной строкой на Cи, а разбить на части. И делать между ними что-нибудь полезное.
(ну… все не так трагично. У меня на ATMega в Cv AVR2 с 8 МГц кварцем формула просчиталась за 0.18мсек. Для моих нужд — с головой!)
И еще не забываем ограничивать воздействие допустимыми пределами! Иначе можно что-нибудь угробить!
И учитываем периодичность измерения/воздействия.
UPD: кстати, насчет «периодичности» и временнЫх режимов.
Если вы реализуете свой алгоритм с помощью операционной системы реального времени, то там разумное учесть следующее:

  • чтение текущего состояния (измерение ошибки) и воздействие должны быть вынесены в отдельный поток с максимально высоким приоритетом, т. к. весьма критична периодичность чтения/воздействия. Причем, эти потоки должны быть синхронны, но сдвинуты по фазе (другими словами, эти потоки должны вызываться с одинаковой периодичностью, но в разные моменты времени).
  • расчет воздействия должен вестись в потоке с относительно низким приоритетом. Нет, ну он вообще-то может быть и весьма высоким, но однозначно ниже приоритета обработчиков прерываний и функций, непосредственно с ними — обработчиками прерываниями — связанными.
  • также разумно поток вычисления воздействия сделать «спящим», а будить его должен поток измерения ошибки (после ее вычисления, конечно).
  • возможна ситуация, что время воздействия пришло, а воздействие еще не рассчитано (т. к. разные приоритеты). Поэтому переменная с воздействием должна изменяться атомарно, да и считываться тоже: 1) меняться только в конце вычисления, 2) считываться только в одном месте потока воздействия. На худой конец повторится старое воздействие. Немного подпортит картинку, конечно, но потом, я думаю, система восстановится. Ну и нельзя забывать, что это в Си действия с float атомарные, на Ассемблере отнюдь! Похоже, что не обойтись без средств синхронизации/блокировки.
Илон Маск рекомендует:  Что такое код array_count_values

Я использую такой алгоритм:

Как видите – ничего революционного!
Прежде всего, все радости происходят в отдельной функции, которая вызывается периодически.
Первый вызов – инициализация из EEPROM или откуда-нибудь еще коэффициенты, обнуляем переменные для рекурсивных вызовов. Потом начинаем пошагово 1) измерять, 2) вычислять, 3) воздействовать, и так по кругу. Заодно производится привязка к реальному времени. Если текущее время меньше требуемого (функция TimeIsLower), то действие не производится.
В комментариях поинтересовались — зачем такие сложности с машиной состояний? С недетерминированным алгоритмом? Отвечаю: благодаря такому подходу я реализую простенький «параллелизм». Т. е. в промежутке между этапами вычислений я делаю какие-то другие действия (в моем случае общение по UART, которое может быть весьма напряженным — когда я использую сий девайс как логгер событий).
Вроде бы все… Что забыл, что перепутал – пишите. Как всегда, приветствуются комментарии о ляпах и ошибках!

P. S.Хочу поучаствовать в конкурсе, поэтому добавляю:

Что такое ПИД регулятор для чайников?

Дифференциальный пропорционально-интегральный регулятор – устройство, которое устанавливают в автоматизированных системах для поддержания заданного параметра, способного к изменениям.

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

Что такое ПИД регулятор?

ПИД регулятор – прибор, встроенный в управляющий контур, с обязательной обратной связью. Он предназначен для поддержания установленных уровней задаваемых величин, например, температуры воздуха.

Устройство подает управляющий или выходной сигнал на устройство регулирования, на основании полученных данных от датчиков или сенсоров. Контроллеры обладают высокими показателями точности переходных процессов и качеством выполнения поставленной задачи.

Три коэффициента ПИД регулятора и принцип работы

Работа ПИД-регулятора заключается в подаче выходного сигнала о силе мощности, необходимой для поддержания регулируемого параметра на заданном уровне. Для вычисления показателя используют сложную математическую формулу, в составе которой есть 3 коэффициента – пропорциональный, интегральный, дифференциальный.

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

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

Дальше вступает интегральная составляющая, которая предназначена для того, чтобы компенсировать воздействие окружающей среды или других возмущающих воздействий на поддержание нашей температуры на заданном уровне. Поскольку всегда присутствуют дополнительные факторы, влияющие на управляемые приборы, в момент поступления данных для вычисления пропорциональной составляющей, цифра уже меняется. И чем больше внешнее воздействие, тем сильнее происходят колебания показателя. Происходят скачки подаваемой мощности.

Интегральная составляющая пытается на основе прошлых значений температуры, вернуть её значение, если оно поменялось. Подробнее процесс описан в видео ниже.


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

Интеграл используется для исключения ошибок путем расчета статической погрешности. Главное в этом процессе – подобрать правильный коэффициент, иначе ошибка (рассогласование) будет влиять и на интегральную составляющую.

Третий компонент ПИД – дифференцирующий. Он предназначен для компенсации влияния задержек, возникающих между воздействием на систему и обратной реакцией. Пропорциональный регулятор подает мощность до тех пор, пока температура не достигнет нужной отметки, но при прохождении информации к прибору, особенно при больших значениях, ошибки всегда возникают. Это может привести к перегреву. Дифференциал прогнозирует отклонения, вызванные задержками или воздействием внешней среды, и снижает подаваемую мощность заранее.

Настройка ПИД регулятора

Настройка ПИД-регулятора осуществляется 2 методами:

  1. Синтез подразумевает вычисление параметров на основании модели системы. Такая настройка получается точной, но требует глубоких познаний теории автоматического управления. Она подвластна только инженерам и ученым. Так как необходимо снимать расходные характеристики и производить кучу расчетов.
  2. Ручной способ основывается на методе проб и ошибок. Для этого за основу берутся данные уже готовой системы, вносятся некоторые коррективы в один или несколько коэффициентов регулятора. После включения и наблюдений за конечным результатом проводится изменение параметров в нужном направлении. И так до тех пор, пока не будет достигнут нужный уровень работоспособности.

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

Современные автоматизированные процессы реализуются как специализированные модули под управлением программ для настройки коэффициентов регулятора.

Назначение ПИД регулятора

ПИД регулятор предназначен для поддержания на требуемом уровне некой величины – температуры, давления, уровня в резервуаре, расхода в трубопроводе, концентрации чего-либо и т.д., изменением управляющего воздействия на исполнительные механизмы, такие как автоматические регулирующие клапана, используя для этого пропорциональную, интегрирующую, дифференцирующую величины для своей настройки.

Целью использования является получение точного управляющего сигнала, который способен контролировать большие производства и даже реакторы электростанций.

Пример схемы регулирования температуры

Часто ПИД регуляторы используются при регулировке температуры, давайте на простом примере подогрева воды в ёмкости рассмотрим данный автоматический процесс.

В емкости налита жидкость, которую нужно подогреть до нужной температуры и поддерживать её на заданном уровне. Внутри бака установлен датчик измерения температуры – термопара или термометр сопротивления и напрямую связан с ПИД-регулятором.

Для подогрева жидкости будем подавать пар, как показано ниже на рисунке, с клапаном автоматического регулирования. Сам клапан получает сигнал от регулятора. Оператор вводит значение температурной уставки в ПИД-регуляторе, которую необходимо поддерживать в ёмкости.

Если настройки коэффициентов регулятора неверны, будут происходить скачки температуры воды, при этом клапан будет то полностью открыт, то полностью закрыт. В этом случае необходимо рассчитать коэффициенты ПИД регулятора и ввести их заново. Если все сделано правильно, через небольшой промежуток времени система выровняет процесс и температура в ёмкости будет поддерживаться на заданной отметке, при этом степень открытия регулирующего клапана будет находиться в среднем положении.

Чем отличается pid от hinstance?

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

Отписаться от уведомлений вы всегда сможете в профиле автора.

Статья относится к принтерам:

В процессе настройки своего ультиштейна столкнулся с тем, что не получается откалибровать PID стола.


M303 E-1 S90 C10 — нагреватель экструдера калибруется.

Что не указывай в качестве параметра после ‘Е’ — экструдер.

Пришлось вспомнить старую пословицу ‘Если ничего не помогло, попробуйте прочитать инструкцию’.

X0 R — Autodetect pid values. Use P for heated bed. X0 saves result in EEPROM. R is number of cycles.

m303 p1 s90 x0 r5

И оно даже работает.

Подпишитесь на автора

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

Отписаться от уведомлений вы всегда сможете в профиле автора.

Является ли HINSTANCE действительным для потоков?

В одном приложении .exe WinMain точка входа имеет параметр HINSTANCE , который должен быть псевдо-дескриптором (поскольку эквивалентен GetModuleHandle(NULL) , который возвращает псевдо-дескриптор, согласно MSDN). Я предполагаю, что это псевдо, потому что есть оба специальных значения (например, NULL для обозначения модуля точки входа) и константы, используемые для возврата ошибки (что-то меньшее, чем 32).

MSDN явно описывает его как указатель (в настоящее время эквивалентный HMODULE ) на базовый адрес модуля; мы знаем, что это может иметь совершенно иное значение для 16-битных приложений, но в 32/64 бит мира каждый процесс имеет свое собственное адресное пространство, тогда его точное значение бесполезно, вероятно, всегда одинаково для каждого экземпляра и абсолютно бессмысленно вне его процесса.

Все сказанное, это мой первый вопрос: можем ли мы (формально, несмотря на то, что MSDN кажется противоречивым), предположим, что HINSTANCE является указателем (даже если честно, я не вижу никакого использования для этого), или лучше предположить, что это (псевдо) дескриптор (где его значение непрозрачно)?

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

Мы можем думать, что дескриптор процесса действителен для каждого процесса, но несколько (угловых) случаев заставляют меня думать, что мы должны считать его действительным для каждой нити. Если эти угловые случаи существуют тогда (даже если они обычно работают как ожидаемые для каждого процесса), мы полагаемся на детали реализации, поведение undefined может быть изменено для разных архитектур, версий, сред.

Посмотрим на случай, когда я вижу проблему (код настолько тривиален, что я просто описываю сценарий): DLL обычно имеет разделяемый раздел кода, но они могут также иметь (даже если это довольно необычно) раздел разделенных данных (например, для обмена обширными данными по всем процессам или для реализации быстрого и грязного механизма МПК). Это может быть необычным, но возможным (и довольно легко реализовать, например, в VС++, с несколькими директивами #pragma data_seg и comment(linker) ). В этом случае мы знаем (внутри нашей DLL), что мы не можем сравнивать HINSTANCE (потому что они могут иметь одинаковое значение), но также IMO мы не можем доверять HINSTANCE , которые мы имели из потока A (в нашей DLL) сопоставим с HINSTANCE , мы имеем в потоке B. Короче: каждый раз, когда нам нужно HINSTANCE , мы должны вызвать GetModuleHandle(NULL) , чтобы получить актуальную актуальную для каждой нить.

Как бонус, я также понял бы, как это относится к HINSTANCE , мы получаем как параметр, когда он приходит от WinMain . Теоретически это для потока, но, например, CreateWindow() будет корректно разрешать его (поскольку scope — это текущий исполняемый процесс, конечно, предполагая, что вызывающий поток имеет свой собственный цикл сообщений)?

РЕДАКТИРОВАТЬ кажется, что я был совершенно не прав, я помню сходство потоков для HMODULE, но оно относится к Windows Mobile.

Если этот параметр равен NULL, GetModuleHandle возвращает псевдо-дескриптор текущего процесса. [. ] Псевдо-дескриптор — это специальная константа, которая интерпретируется как текущий дескриптор потока. Вызывающий поток может использовать этот дескриптор для указания самого себя, когда требуется описатель потока.

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

Visual C++ / FAQ — 4

Как убрать кнопку с TaskBar′а?


С помощью Win32 API это можно сделать с помощью функции CreateWindowEx(), указав флаг WS_EX_TOOLWINDOW.

Как определить позицию курсора в консоли Win32? Как очистить экран в консоли Win32?

Можно использовать функцию ScrollConsoleScreenBuffer или следующий код: Как узнать количество элементов и размер корзины? Как очистить корзину?

Как получить список все запущенных процессов и потоков?

Для Windows 9x используйте CreateToolhelp32Snapsot/ Process32First(Process32Next)/ Thread32First(Thread32Next).
Для WinNT NTQuerySystemInformation. А можно так: получаете список окон в системе (каким угодно способом, если нужны только процессы — можно ограничиться top-level), далее — GetWindowTreadProcessID — получаете ID процесса (и нити). OpenProcess — дает handle процесса.

Илон Маск рекомендует:  Что такое код asp isclientconnected

Какие существуют функции для работы с COM-портом напрямую под Win9x?

Посмотрите функции: Как завесить Windows?

1. Сделать файл system.ini больше, чем 64К. Вешается при загрузке.
2. Вызвать код:
cli
jmp $

Как получить hInstance консольного приложения?

Чем отличается PID от hInstance?

PID — уникальный идентификатор объекта ядра — процесса
Inst — (упрощенно) указатель на область памяти, куда загружен экземпляр модуля (экзешника, dll-ки)

Как установить обои на Рабочий Стол?

Пишем на WinAPI с «нуля»

Автор: Яковлев Игорь Сергеевич
Источник: RSDN Magazine #4-2005

Опубликовано: 30.12.2005
Исправлено: 16.03.2006
Версия текста: 1.0

От редакции


ПРИМЕЧАНИЕ

Данная статья является введением в программирование на WinAPI. Важно понимать, что она носит скорее информационный характер, чем служит примером кода для реальных приложений. Дело в том, что WinAPI создавался для языка С, и имеет целый ряд недостатков в применении, как-то: невысокая безопасность, большой объем ручного кодирования для решения простейших задач, С-стиль, плохо выглядящий в C++-приложениях. Практически любое средство разработки на языке C++ для Windows включает те или иные высокоуровневые C++-библиотеки (MFC, ATL/WTL для Visual C++, VCL для C++ Builder), значительно упрощающие разработку Windows-приложений, и делающие ее более безопасной.

Предисловие

Эта статья посвящена описанию программирования приложений на «чистом» Win32 API. Она написана в основном для начинающих программистов, пишущих программы на Visual C++ 6 с использованием библиотеки MFC, но я надеюсь, может пригодиться и более опытным людям.

First Blood

После создания нового проекта Win32 Application, в зависимости от выбранных опций, мастер генерирует стартовый код. Из этого кода программисту впоследствии, и придется писать программу. Создавая новый проект Win32 Application, выберите в окне мастера опцию An empty project и добавьте в раздел Source Files новый файл с расширением .cpp.


В этом файле добавьте функцию WinMain вида:

Вот и готова первая программа на WinAPI. Она выводит сообщение, после чего завершает свою работу. Обратите внимание на параметры функции WinMain :

  • HINSTANCE hInstance – дескриптор экземпляра приложения. Этот дескриптор содержит адрес начала кода программы в ее адресном пространстве. Дескриптор hInstance чаще всего требуется функциям, работающим с ресурсами программы.
  • HINSTANCE hPrevInstance – дескриптор предыдущего экземпляра приложения. Этот дескриптор остался от старых версий Windows — скорее всего, вам он никогда не пригодится.
  • LPSTR lpCmdLine – указатель на начало командной строки, введенной при запуске программы.
  • int nCmdShow – это значение содержит желаемый вид окна (например, свернутый или развернутый)

Значение, которое возвращается функцией WinMain (тип int ) – код завершения программы. Принято, что если программа завершила свое выполнение без ошибок, возвращается 0.

Функция WinMain – первая функция, которая выполнятся в программе (ее еще называют «точка входа» или «entry point»). С нее все начинается, и ею (желательно) все должно закончиться.

ПРИМЕЧАНИЕ

Функция WinMain – это первая функция, которую вы можете увидеть и заполнить кодом. На самом деле до этой функции выполняется достаточно много кода из библиотеки C++

You have a Message!

Программисты, незнакомые с программированием на WinAPI, спросят: «Что с этим делать?!», — или: «Где создавать CDialog?». В данном случае ответ прост – нигде! В нашем проекте нет класса CDialog или, предположим, CButton – ведь эта статья посвящена тому, как обойтись без них.

В Windows при каждом событии, произошедшем в системе, отсылается «сообщение Windows» («windows message»). Эти сообщения уведомляют программу о событиях в системе, а программа в свою очередь, может на них реагировать. Сообщения может отсылать не только Windows, но и сами приложения. Это является одним из способов организации связи между процессами в системе. Конечно, программа может отсылать сообщения и самой себе.

СОВЕТ

Сообщение можно отослать функцией SendMessage или ее асинхронным аналогом PostMessage.

Для приема сообщений в программе должен находиться «цикл сообщений» («message loop») который обычно выглядит так:

Функция GetMessage принимает следующие параметры:

  • LPMSG lpMsg – указатель на структуру сообщения, в которую GetMessage вернет результат.
  • HWND hWnd – описатель окна, от которого GetMessage примет сообщение ( NULL означает, что GetMessage принимает сообщения от всех окон, принадлежащих потоку).
  • UINT wMsgFilterMin – наименьший идентификатор сообщения, которое примет GetMessage.
  • UINT wMsgFilterMax – наибольший идентификатор сообщения, которое примет GetMessage (если в значениях параметров wMsgFilterMin и wMsgFilterMax передать 0, функция будет принимать ВСЕ сообщения).

Функция GetMessage не отдает управление программе, пока не придет какое-либо сообщение. Если пришедшее сообщение – WM_QUIT , функция GetMessage вернет 0 . Тогда цикл прервется, и программа завершит свою работу. При любом другом сообщении функция GetMessage возвращает значение больше нуля, и начинатся выполнение тела цикла. При ошибке GetMessage возвращает -1.

СОВЕТ

Сообщение WM_QUIT лучше посылать с помощью специальной функции PostQuitMessage(int iExitCode). Эта функция отошлет сообщение WM_QUIT, а в параметре wParam передаст код завершения программы, указанный в iExitCode.

Функция DispatchMessage должна вызвать «функцию обработки сообщений». В простейшем варианте она выглядит так:

При вызове этой функции ей передаются следующие параметры:


  • HWND hWnd – описатель окна, от которого пришло сообщение.
  • UINT message – идентификатор сообщения.
  • WPARAM wParam и LPARAM lParam – параметры сообщения.

Функция обработки сообщений не обязательно должна иметь имя WndProc . Таких функций в программе может быть несколько, но их прототипы обязательно должны выглядеть так:

При вызове этой функции DispatchMessage передает в параметре message идентификатор сообщения. По этому идентификатору производится выборка и выполняется какое-либо действие ( «реакция на сообщение» ).

В Windows существует очень много сообщений! Писать обработчики для всех сообщений – нереальная задача. Чтобы Windows сама обработала бесполезное для вас сообщение, необходимо вызвать функцию DefWindowProc :

Желательно передавать все необработанные сообщения этой функции, а результат ее выполнения возвращать при выходе из WndProc . Это очень важно, так как от обработки некоторых сообщений Windows ждет возврата конкретных результатов или действий.

Одной функцией обработки сообщений могут пользоваться несколько окон, но для одного окна может существовать только одна функция обработки сообщений! Как же система определяет, какой именно функцией обработки сообщения пользоваться для конкретного окна и где она находится?! За это отвечает «класс окна» («window class»).

CLASSные окна

При создании нового окна ему присваивается «Класс окна» (window class). Класс окна задает оконную функцию, используемую по умолчанию. Кроме этого, класс окна задает другие параметры окна, такие, как стиль, меню окна, цвет рабочей области и т.д. Разные классы окон могут указывать на одну и ту же функцию обработки сообщений. Для создания класса его необходимо зарегистрировать.

Итак, регистрация! За нее отвечает функция RegisterClass . В ее параметре необходимо передать указатель на структуру WNDCLASS . Обычно для заполнения структуры и вызова RegisterClass создают отдельную функцию. Но это — дело вкуса.

Вот простейший пример такой функции:

  • WNDPROC lpfnWndProc – адрес функции обработки сообщений.
  • HINSTANCE hInstance – уже знакомая переменная, описывающая экземпляр.
  • LPCTSTR lpszClassName – имя нового класса.
  • HICON hCursor – описатель курсора мыши.
  • HBRUSH hbrBackground – цвет рабочей области окна.

Функция RegisterClass возвращает уникальный «описатель класса окна» типа ATOM . Если при регистрации класса произошла ошибка, это значение будет равно нулю. Чтобы узнать, что произошло, можно вызвать функцию GetLastError() .

Существует также функция RegisterClassEx. Это аналог функции RegisterClass с возможностью присвоения окнам маленькой иконки. При работе с этой функцией необходимо пользоваться структурой WNDCLASSEX.

ПРИМЕЧАНИЕ

Если вы решились работать с GUI Windows вручную, то пользоваться нужно именно RegisterClassEx, поскольку приложение, не имеющее маленькой иконки, сегодня выглядит в Windows как минимум странно. – прим.ред.


СОВЕТ

Следите, чтобы имя вашего класса не совпадало с именами системных классов (например: button или edit).

ПРИМЕЧАНИЕ

Я описал не всю структуру. Все незаполненные поля, которых нет в примере, сейчас равны нулю. Об их значениях можно узнать из MSDN.

Сообщения от окон, созданных на базе класса, зарегистрированного описанной выше функцией RegMyWindowClass, будут обрабатываться функцией с именем WndProc. Чтобы функция WndProc поняла, от какого именно окна пришло сообщение, ей передается уникальный описатель окна HWND .

Our Windows

На вашем месте у меня возникло бы желание увидеть те самые пресловутые окна, из-за которых столько шума. Окно в Windows создается функцией CreateWindow . Вот ее прототип:

Как видите, у функции множество параметров:

  • LPCTSTR lpClassName – имя класса для создаваемого окна (это имя использовалось при регистрации класса).
  • LPCTSTR lpWindowName – имя окна.
  • DWORD dwStyle – стиль окна.
  • int x – позиция по горизонтали верхнего левого угла окна.
  • int y – позиция по вертикали.
  • int nWidth – ширина окна.
  • int nHeight – высота окна.
  • HWND hWndParent – используется для создания «дочернего окна» («child window»). Сюда передается описатель «родительского окна» («parent window»).
  • HMENU hMenu – описатель меню (если hMenu равно нулю, используется меню класса, указанного в lpClassName ).
  • HINSTANCE hInstance – экземпляр приложения.
  • LPVOID lpParam – указатель на пользовательский параметр окна. Этот указатель со всеми остальными параметрами функции CreateWindow будет занесен в структуру CREATESTRUCT . В сообщениях WM_CREATE или WM_NCCREATE параметр lParam будет содержать указатель на эту структуру.

Функция CreateWindow возвращает уникальный описатель окна HWND . Если функция вернула ноль, значит, во время создания окна произошла ошибка. Какая именно, можно узнать, вызвав функцию GetLastError .

ПРИМЕЧАНИЕ

Существует также функция CreateWindowEx, в которой дополнительно присутствует параметр dwExStyle. С его помощью можно создать окно с дополнительными стилями.

План полета

Итак, сейчас я упрощенно расскажу, что же произойдет, если щелкнуть по окну левой кнопкой мыши.

  1. Пользователь нажимает левую кнопку мыши в то время когда курсор мыши находится над рабочей областью окна.
  2. Windows помещает сообщение WM_LBUTTONDOWN в очередь потока.
  3. Цикл обработки сообщения должен вынуть сообщение с помощью функции GetMessage и передать его на обработку функции DispatchMessage .
  4. Функция DispatchMessage находит окно, которому предназначено сообщение и помещает сообщение в его очередь.
  5. Функция окна обрабатывает сообщение WM_LBUTTONDOWN и возвращает результат.
  6. Тело цикла заканчивается, и управление снова передается функции GetMessage для ожидания новых сообщений.

Итого

WinMain, регистрация класса, цикл сообщений, функция обработки сообщений, создание окна. Как все это связать?! Вот код, который объединяет все написанное выше в одну программу:

Вот, в принципе, и все! Это полноценное приложение на WinAPI.

Программа регистрирует класс, создает окно этого класса и обслуживает сообщение WM_LBUTTONUP (оно приходит по событию отпускания левой кнопки мыши), показывает окно, и после обработки сообщения снова возвращается в цикл сообщений, находящийся в WinMain .

Признаю, что данная статья и программа опускает очень много деталей! Многие вещи были не раскрыты (например, остальные переменные структуры WNDCLASS ). Все это сделано для того, чтобы максимально упростить статью и уменьшить код программы.

В чем разница между P > Задать вопрос

В чем между ними разница и что можно сделать с процессом имея либо PID либо HANDLE?

1 ответ 1

PID — это Process ID (идентификатор процесса), он уникален в пределах системы, т.е. одновременно не существует двух процессов с одинаковыми PID. Используется для идентификации процесса извне.

HANDLE — условно, адрес, по которому хранится информация по процессу, например такая как: время запуска, имя файла, ассоциированного с процессом, и даже тот же самый PID. Будучи однажды получен, HANDLE требует закрытия через CloseHandle() . Используется внутри программы, нет особого смысла в передаче наружу. В общем случае, тип HANDLE может идентифицировать разные ресурсы, далеко не только процессы. В winnt.h описан как указатель на void (т.е. на любой тип):

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

Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL