Сообщение Проблема HCURSOR, или как делить свой ресурс с другими? от 08.03.2024 17:51
Изменено 08.03.2024 17:51 Marty
Проблема HCURSOR, или как делить не свой ресурс с другими?
Здравствуйте!
Что-то не очень понимаю, как разделять ресурс с операционной системой, ну и вообще, со сторонними сущностями, которыми не всегда я управляю.
Может, это вопрос скорее в "Архитектуру", но вопрос в тч и по плюсикам, по реализации.
Краткая справка, кто не знаком с WinAPI.
WinAPI предоставляет следующие функции:
Тут проблема с SetCursor — она передаёт владение над HCURSOR системе, и возвращает предыдущий установленный хэндл, прекращая владение над ним. Тут ещё возможно важный нюанс, что HCURSOR это глобальный системный ресурс, т.е. если я в приложении установлю свой HCURSOR, то он вероятно останется в системе даже после гибели приложения. Я не проверял, но, судя по тому, что там не требуется хэндл окна, то хэндлом курсора либо приложение владеет, либо сама система.
Простой кейс длительной блокирующей операции:
Тут всё нормально, нет никаких проблем.
Другой вариант — я хочу создать несколько курсоров заранее при создании окна, они грузятся из файлов и на каждый чих мне дорого их грузить, в процессе работы хочу произвольно их устанавливать, но когда окно разрушается и/или приложение завершается, я хочу установить тот курсор, который был до меня, и удалить то, что создал.
Тут для автоматического управления загруженными курсорами я начинаю управлять временем жизни HCURSOR, но проблема в том, что я уже не знаю, какой HCURSOR сейчас выбран.
Предположим, у меня есть объект курсора, и функция создания таких курсоров типа такого:
Я создаю такие курсоры, они у меня где-то лежат, по мере необходимости я устанавливаю нужный, или восстанавливаю дефолтный.
Дефолтный курсор — можно при старте приложения сделать так для его получения:
При завершении на OnClose просто восстановить дефолтный:
Я могу написать в доке, что курсоры надо хранить в какой-то переменной, но доки никто не читает, и могут сделать тупо так:
Т.е. тупо передать временный объект, и тогда, после установки курсора объект разрушится, и HCURSOR, которым он управлял, тоже будет уничтожен. Не уверен, что система у HCURSOR ведёт счетчик какой-то, и тогда окажется, что система владеет разрушенным HCURSOR. Не понятно, как быть в такой ситуации?
Ещё проблема в том, что описанный сценарий не позволяет восстановить не дефолтный курсор, а тот курсор, который был установлен ранее.
В общем, не очень понятно, как такую ситуацию разрулить?
Есть вариант, когда класс Cursor не владеет HCURSOR, а всеми созданными HCURSOR владеет фабрика, их создающая, и она разрушает при своём разрушении только те HCURSOR, которые создала сама.
Или, может, как-то ещё можно разрулить проблему?
Что-то не очень понимаю, как разделять ресурс с операционной системой, ну и вообще, со сторонними сущностями, которыми не всегда я управляю.
Может, это вопрос скорее в "Архитектуру", но вопрос в тч и по плюсикам, по реализации.
Краткая справка, кто не знаком с WinAPI.
WinAPI предоставляет следующие функции:
BOOL DestroyCursor(HCURSOR hCursor);
HCURSOR CreateCursor(...); // Создаёт курсор из битиков
HCURSOR LoadCursor(HINSTANCE hInstance, LPCSTR lpCursorName); // Загружает курсор из ресурсов, или из файла, или стоковый
HCURSOR SetCursor(HCURSOR hCursor); // Устанавливает текущий курсор и возвращает предыдущийТут проблема с SetCursor — она передаёт владение над HCURSOR системе, и возвращает предыдущий установленный хэндл, прекращая владение над ним. Тут ещё возможно важный нюанс, что HCURSOR это глобальный системный ресурс, т.е. если я в приложении установлю свой HCURSOR, то он вероятно останется в системе даже после гибели приложения. Я не проверял, но, судя по тому, что там не требуется хэндл окна, то хэндлом курсора либо приложение владеет, либо сама система.
Простой кейс длительной блокирующей операции:
struct ScopeCursor
{
HCURSOR hcurDestroy;
HCURSOR hcurRestore;
ScopeCursor(HCURSOR hcNew) : hcurDestroy(hcNew), hcurRestore(SetCursor(hcNew)) {}
~ScopeCursor() { SetCursor(hcurRestore); DestroyCursor(hcurDestroy); }
};
void longBlockingJob()
{
auto savedCursor = ScopeCursor(CreateStockCursor(IDC_WAIT));
// Долгая работа
// Тут курсор сам будет восстановлен
}Тут всё нормально, нет никаких проблем.
Другой вариант — я хочу создать несколько курсоров заранее при создании окна, они грузятся из файлов и на каждый чих мне дорого их грузить, в процессе работы хочу произвольно их устанавливать, но когда окно разрушается и/или приложение завершается, я хочу установить тот курсор, который был до меня, и удалить то, что создал.
Тут для автоматического управления загруженными курсорами я начинаю управлять временем жизни HCURSOR, но проблема в том, что я уже не знаю, какой HCURSOR сейчас выбран.
Предположим, у меня есть объект курсора, и функция создания таких курсоров типа такого:
class Cursor
{
HCURSOR hCursor;
Cursor(HCURSOR hc) : hCursor(hc) {}
// всякие copy/move ctor/op=
~Cursor()
{
::DestroyCursor(hCursor);
}
};
// Где-то в классе окна, или может, глобальная ф-я
Cursor createStockCursor(int id)
{
return Cursor(LoadCursor(0, id));
}
void setDefaultCursor(); // установка дефолтного, см ниже
void setCursor(Cursor c);Я создаю такие курсоры, они у меня где-то лежат, по мере необходимости я устанавливаю нужный, или восстанавливаю дефолтный.
Дефолтный курсор — можно при старте приложения сделать так для его получения:
class CMainWindow : // ...
{
HCURSOR hCursorDefault;
// ...
void OnCreate()
{
HCURSOR hTmpCursor = ::LoadCursor(NULL, IDC_WAIT);
hCursorDefault = ::SetCursor(hTmpCursor);
::SetCursor(hDefaultCursor); // Восстановили оригинальный курсор, но хэндл у нас уже есть
::DestroyCursor(hTmpCursor);
}
};При завершении на OnClose просто восстановить дефолтный:
void OnCreate()
{
setDefaultCursor(); // ::SetCursor(hDefaultCursor);
// Больше ничего не делаем, просто установили тот курсор, который был до нашего вмешательства, значит, все наши курсоры точно не заняты системой и их деструкторы отработают нормально
}Я могу написать в доке, что курсоры надо хранить в какой-то переменной, но доки никто не читает, и могут сделать тупо так:
setCursor(createStockCursor())Т.е. тупо передать временный объект, и тогда, после установки курсора объект разрушится, и HCURSOR, которым он управлял, тоже будет уничтожен. Не уверен, что система у HCURSOR ведёт счетчик какой-то, и тогда окажется, что система владеет разрушенным HCURSOR. Не понятно, как быть в такой ситуации?
Ещё проблема в том, что описанный сценарий не позволяет восстановить не дефолтный курсор, а тот курсор, который был установлен ранее.
В общем, не очень понятно, как такую ситуацию разрулить?
Есть вариант, когда класс Cursor не владеет HCURSOR, а всеми созданными HCURSOR владеет фабрика, их создающая, и она разрушает при своём разрушении только те HCURSOR, которые создала сама.
Или, может, как-то ещё можно разрулить проблему?
Проблема HCURSOR, или как делить свой ресурс с другими?
Здравствуйте!
Что-то не очень понимаю, как разделять ресурс с операционной системой, ну и вообще, со сторонними сущностями, которыми не всегда я управляю.
Может, это вопрос скорее в "Архитектуру", но вопрос в тч и по плюсикам, по реализации.
Краткая справка, кто не знаком с WinAPI.
WinAPI предоставляет следующие функции:
Тут проблема с SetCursor — она передаёт владение над HCURSOR системе, и возвращает предыдущий установленный хэндл, прекращая владение над ним. Тут ещё возможно важный нюанс, что HCURSOR это глобальный системный ресурс, т.е. если я в приложении установлю свой HCURSOR, то он вероятно останется в системе даже после гибели приложения. Я не проверял, но, судя по тому, что там не требуется хэндл окна, то хэндлом курсора либо приложение владеет, либо сама система.
Простой кейс длительной блокирующей операции:
Тут всё нормально, нет никаких проблем.
Другой вариант — я хочу создать несколько курсоров заранее при создании окна, они грузятся из файлов и на каждый чих мне дорого их грузить, в процессе работы хочу произвольно их устанавливать, но когда окно разрушается и/или приложение завершается, я хочу установить тот курсор, который был до меня, и удалить то, что создал.
Тут для автоматического управления загруженными курсорами я начинаю управлять временем жизни HCURSOR, но проблема в том, что я уже не знаю, какой HCURSOR сейчас выбран.
Предположим, у меня есть объект курсора, и функция создания таких курсоров типа такого:
Я создаю такие курсоры, они у меня где-то лежат, по мере необходимости я устанавливаю нужный, или восстанавливаю дефолтный.
Дефолтный курсор — можно при старте приложения сделать так для его получения:
При завершении на OnClose просто восстановить дефолтный:
Я могу написать в доке, что курсоры надо хранить в какой-то переменной, но доки никто не читает, и могут сделать тупо так:
Т.е. тупо передать временный объект, и тогда, после установки курсора объект разрушится, и HCURSOR, которым он управлял, тоже будет уничтожен. Не уверен, что система у HCURSOR ведёт счетчик какой-то, и тогда окажется, что система владеет разрушенным HCURSOR. Не понятно, как быть в такой ситуации?
Ещё проблема в том, что описанный сценарий не позволяет восстановить не дефолтный курсор, а тот курсор, который был установлен ранее.
В общем, не очень понятно, как такую ситуацию разрулить?
Есть вариант, когда класс Cursor не владеет HCURSOR, а всеми созданными HCURSOR владеет фабрика, их создающая, и она разрушает при своём разрушении только те HCURSOR, которые создала сама.
Или, может, как-то ещё можно разрулить проблему?
Что-то не очень понимаю, как разделять ресурс с операционной системой, ну и вообще, со сторонними сущностями, которыми не всегда я управляю.
Может, это вопрос скорее в "Архитектуру", но вопрос в тч и по плюсикам, по реализации.
Краткая справка, кто не знаком с WinAPI.
WinAPI предоставляет следующие функции:
BOOL DestroyCursor(HCURSOR hCursor);
HCURSOR CreateCursor(...); // Создаёт курсор из битиков
HCURSOR LoadCursor(HINSTANCE hInstance, LPCSTR lpCursorName); // Загружает курсор из ресурсов, или из файла, или стоковый
HCURSOR SetCursor(HCURSOR hCursor); // Устанавливает текущий курсор и возвращает предыдущийТут проблема с SetCursor — она передаёт владение над HCURSOR системе, и возвращает предыдущий установленный хэндл, прекращая владение над ним. Тут ещё возможно важный нюанс, что HCURSOR это глобальный системный ресурс, т.е. если я в приложении установлю свой HCURSOR, то он вероятно останется в системе даже после гибели приложения. Я не проверял, но, судя по тому, что там не требуется хэндл окна, то хэндлом курсора либо приложение владеет, либо сама система.
Простой кейс длительной блокирующей операции:
struct ScopeCursor
{
HCURSOR hcurDestroy;
HCURSOR hcurRestore;
ScopeCursor(HCURSOR hcNew) : hcurDestroy(hcNew), hcurRestore(SetCursor(hcNew)) {}
~ScopeCursor() { SetCursor(hcurRestore); DestroyCursor(hcurDestroy); }
};
void longBlockingJob()
{
auto savedCursor = ScopeCursor(CreateStockCursor(IDC_WAIT));
// Долгая работа
// Тут курсор сам будет восстановлен
}Тут всё нормально, нет никаких проблем.
Другой вариант — я хочу создать несколько курсоров заранее при создании окна, они грузятся из файлов и на каждый чих мне дорого их грузить, в процессе работы хочу произвольно их устанавливать, но когда окно разрушается и/или приложение завершается, я хочу установить тот курсор, который был до меня, и удалить то, что создал.
Тут для автоматического управления загруженными курсорами я начинаю управлять временем жизни HCURSOR, но проблема в том, что я уже не знаю, какой HCURSOR сейчас выбран.
Предположим, у меня есть объект курсора, и функция создания таких курсоров типа такого:
class Cursor
{
HCURSOR hCursor;
Cursor(HCURSOR hc) : hCursor(hc) {}
// всякие copy/move ctor/op=
~Cursor()
{
::DestroyCursor(hCursor);
}
};
// Где-то в классе окна, или может, глобальная ф-я
Cursor createStockCursor(int id)
{
return Cursor(LoadCursor(0, id));
}
void setDefaultCursor(); // установка дефолтного, см ниже
void setCursor(Cursor c);Я создаю такие курсоры, они у меня где-то лежат, по мере необходимости я устанавливаю нужный, или восстанавливаю дефолтный.
Дефолтный курсор — можно при старте приложения сделать так для его получения:
class CMainWindow : // ...
{
HCURSOR hCursorDefault;
// ...
void OnCreate()
{
HCURSOR hTmpCursor = ::LoadCursor(NULL, IDC_WAIT);
hCursorDefault = ::SetCursor(hTmpCursor);
::SetCursor(hDefaultCursor); // Восстановили оригинальный курсор, но хэндл у нас уже есть
::DestroyCursor(hTmpCursor);
}
};При завершении на OnClose просто восстановить дефолтный:
void OnCreate()
{
setDefaultCursor(); // ::SetCursor(hDefaultCursor);
// Больше ничего не делаем, просто установили тот курсор, который был до нашего вмешательства, значит, все наши курсоры точно не заняты системой и их деструкторы отработают нормально
}Я могу написать в доке, что курсоры надо хранить в какой-то переменной, но доки никто не читает, и могут сделать тупо так:
setCursor(createStockCursor())Т.е. тупо передать временный объект, и тогда, после установки курсора объект разрушится, и HCURSOR, которым он управлял, тоже будет уничтожен. Не уверен, что система у HCURSOR ведёт счетчик какой-то, и тогда окажется, что система владеет разрушенным HCURSOR. Не понятно, как быть в такой ситуации?
Ещё проблема в том, что описанный сценарий не позволяет восстановить не дефолтный курсор, а тот курсор, который был установлен ранее.
В общем, не очень понятно, как такую ситуацию разрулить?
Есть вариант, когда класс Cursor не владеет HCURSOR, а всеми созданными HCURSOR владеет фабрика, их создающая, и она разрушает при своём разрушении только те HCURSOR, которые создала сама.
Или, может, как-то ещё можно разрулить проблему?