Что такое время жизни данных параметров указателя в определяемых приложениями функциях обратного вызова 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
если вам нужно использовать его после возврата обратного вызова. Конечно, вы также должны управлять временем жизни выделенного буфера (ов).