Что такое время жизни данных параметров указателя в определяемых приложениями функциях обратного вызова Windows API? Это сохраняется после возврата обратного вызова?

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

BOOL CALLBACK EnumWindowStationProc(
    _In_ LPTSTR lpszWindowStation,
    _In_ LPARAM lParam
);

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

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

Официальная документация не дает четкого представления о времени жизни строковых данных. В описании параметра есть только одна строка:

lpszWindowStation [in]

Название оконной станции.

И нигде на странице документации не говорится о времени жизни строковых данных. Также я не могу вспомнить, чтобы когда-либо находил страницу MSDN, которая отвечает на этот вопрос "раз и навсегда", то есть для всех видов использования функции обратного вызова в Windows API.

На данный момент меня больше всего интересует EnumWindowStations() / EnumWindowStationsProc() случай, но было бы лучше, если бы ответчики обращались к общему случаю, то есть к тому, что предполагать для всех функций обратного вызова Windows API.

2 ответа

Решение

Как правило, если память выделена системой, вы можете рассчитывать на то, что она действительна в течение всего периода обратного вызова и не более. Это случай для lpszWindowStation в вашем примере. Вам нужно будет получить доступ и скопировать строку внутри вашей функции обратного вызова и не должны ссылаться на предоставленные системой данные вне вашего обратного вызова.

Вы можете сделать это с помощью небольшого мысленного эксперимента. Если эта строка может быть доступна после возврата обратного вызова, когда она станет недействительной? Когда это будет освобождено? Вы должны сказать системе, что с ней покончено. Поскольку для этого не указано API, единственным выводом является то, что указано выше.

Вещи разные для lParam, Это значение было предоставлено вами, когда вы звонили EnumWindowStations и поэтому вы управляете временем жизни всего, на что оно указывает, если действительно используете его в качестве указателя.

В общем, указатели, передаваемые в функции обратного вызова посредством WINAPI, гарантированно будут действительными только в течение срока обратного вызова (если иное не указано в документации конкретного обратного вызова). Когда обратный вызов возвращается, указатель следует считать недействительным (он может быть освобожден или может указывать на временный буфер, который будет перезаписан в следующей итерации перечисления и т. Д.).

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

Другие вопросы по тегам