Обновить

Рэймонд Чен — ветеран компьютерной индустрии, который работает в Microsoft c 1992 года. Рэймонд участвовал в разработке OS/2, Windows 95, DirectX и оболочки Windows, а последние десятилетия отвечает за сохранение обратной совместимости системы. В своём блоге Old New Thing Чен регулярно делится забавными историями из разработки софта, но также показывает действительно полезные примеры.

На этот раз Чен показал, почему история буфера обмена не отражает быстрые изменения содержимого буфера. Рэймонд приводит следующий фрагмент кода от клиента. Этот код был написан для некой утилиты, вставляющей в историю буфера обмена объекты. В некотором роде историю прошлых изменений превращали в будущее — целью было предугадать, какие элементы пользователь хотел бы видеть в истории буфера обмена.

// В целях наглядности вся проверка ошибок опущена
#include <windows.h>

void SetClipboardText(HWND hwnd, PCWSTR text)
{
    OpenClipboard(hwnd);
    EmptyClipboard();
    auto size = sizeof(wchar_t) * (1 + wcslen(text));
    auto clipData = GlobalAlloc(GMEM_MOVEABLE, size);
    auto buffer = (LPWSTR)GlobalLock(clipData);
    strcpy_s(buffer, size, text);
    GlobalUnlock(clipData);
    SetClipboardData(CF_UNICODETEXT, clipData);
    CloseClipboard();
}

// Чтобы они были под рукой, разместим эти строки в истории буфера обмена
static constexpr PCWSTR messages[] = {
    L"314159", // номер бага, который мы хотим исправить
    L"e83c5163316f89bfbde7d9ab23ca2e25604af290", // коммит, к которому привязываем ошибку
    L"Widget polarity was set incorrectly.", // комментарий, который нужно добавить
};

int wmain([[maybe_unused]] int argc,
          [[maybe_unused]] wchar_t* argv[])
{
    auto tempWindow = CreateWindowExW(0, L"static", nullptr, WS_POPUPWINDOW,
            0, 0, 0, 0, nullptr, nullptr, nullptr, nullptr);

    for (auto message : messages)
    {
        SetClipboardText(tempWindow, message);
    }
    DestroyWindow(tempWindow);
    return 0;
}

Код записывает в буфер обмена последовательно три строковые переменные. Однако при запуске утилиты в истории буфера обмена оказывалась лишь одна — последняя. Куда делись две остальные?

Дело в том, что служба истории буфера обмена работает асинхронно через механизм Clipboard Format Listener, существующий с эпохи Windows Vista. В этом механизме через функцию Add­Clipboard­Format­Listener приложение добавляет себя в качестве листенера. После этого никаких дополнительных опросов буфера обмена проводить не нужно — система сама оповестит приложение, если буфер изменился.

При получении уведомления служба истории буфера обновляет собственно историю буфера обмена. Но из-за асинхронности событие может происходить с задержкой. Как объясняет Чен, из-за асинхронной природы обновлений при получении WM_CLIPBOARD­UPDATE от Clipboard Format Listener буфер может успеть обновиться ещё раз.

Как считает Рэймонд, это даже не баг, а фича. Так получается избегать приложений, которые быстро спамили бы в буфер обмена множество изменений. Если даже пользователь не успевает воспользоваться содержимым буфера, то сохранять это для истории смысла нет, указывает Чен.

В другом посте из своего блога Рэймонд объяснил механизмы утилит-просмотрщиков буфера обмена с синхронными обновлениями буфера. Здесь периодически выполняется опрос GetClipboardSequenceNumber. У данного подхода тоже есть проблемы: редкий опрос угрожает привести к пропуску изменения буфера, но слишком частые запросы создадут лишнюю нагрузку на систему.

Рэймонд обещает в следующий раз показать, как исправить код выше.

Теги:
Всего голосов 5: ↑4 и ↓1+6
Комментарии0

Зуд от укуса комара или мошки — лютый биохимический прикол

Предположим, вас укусил комар прямо в задницу.

Что там, вы не видите, но зудит, поэтому вы чешетесь. То есть прям берёте и начинаете водить ногтями по месту укуса. До тех пор, пока это отвратительное состояние зуда в моменте не пройдёт.

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

Есть ещё невероятный прикол с серотонином в этой же цепочке, но про него чуть позже.

Боль вообще-то — технология отрицательной обратной связи. Не делай, чтобы тебе не было больно. Не трогай горячее; не выгибай вот так руку; береги пораненную ногу; не бей организмом по кокосу, бей лучше камнем и так далее.

Зуд от укуса комара даёт положительную обратную связь. Чем больше зудит, тем больше зудит.

Часто бывает, что 90% итогового воспалительного процесса — это не комар и его токсины, это мы своими ногтями.

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

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

Зуд от укуса комара или мошки — лютый биохимический прикол

Публикации