Написание приложений Win32 с помощью одних классов C++ (часть 2) - Типы обертки

ОГЛАВЛЕНИЕ

Типы обертки

Функция WrpBase::Value изначально возвращает OH, но на самом деле она должна возвращать тип функции Access, унаследованный от типажей и делающий функцию Value бесполезной копией. По сути, Value должна возвращать значение так, как оно хранится, только для чтения, без преобразования. Следовательно, ее возвращаемый тип был изменен на const SH&.

Это не влияет на нормальные обертки (SH является H, а OH является const HANDLE&, так что это одно и то же) или указатели (SH является H*, а OH является H*, что значит - "копировать при возврате", следовательно, const SH& становится const H*&, точно так же присваиваемым H*), но важно в более сложных случаях, когда возвращаемые типы не идентичны значениям, хранящимся в обертке.

Ниже приведен реальный случай.

Чтение пользовательских ресурсов

Для чтения пользовательского ресурса windows API требует следующих шагов:
1.    Вызвать FindResource, передав HMODLULE и ID, чтобы получить HRSRC.
2.    Вызвать LoadResource, передав HRSRC, чтобы получить ложный HGLOBAL.
3.    Вызвать LockResource, чтобы получить LPVOID для надлежащего приведения типа.
4.    Теперь стоит использовать данные
5.    Затем вызвать UnlockResource, передав HGLOBAL, и затем ...
6.    Снова вызвать FreeResource с HGLOBAL.

В то время как шаг 1 не требует выделения памяти, шаги 5 и 6 обратны шагам 3 и 2 соответственно.
Следовательно, удобная обертка прикрепляется к HRSRC, загружая данные, делает их доступными путем разыменования и освобождает данные при отцеплении. Если с одним и тем же HRSRC связано несколько оберток, загрузка должна производиться первой, а освобождение - последней. Данные должны быть шаблонным параметром.

Обертка ресурса для ресурса панели инструментов может быть (кроме пространства имен) Wrp<SResourceData<XToolBarData> >. Если wrpTbrRes является переменной указанного типа, operator-> вернет XToolbarData*.

Затем SResourcedata порождается от WrpBase, замыкая наследование (передавая себя в качестве параметра "W") и имея держатель конкретных типажей и счетчиков ссылок.

Поскольку для загрузки ресурса нужен не только HRSRC, но и HMODULE, приходится сохранять HMODULE как "начальный параметр" в SResourceData, прописывая функцию инициализации (void SetHModule(HMODULE hMod)). Надо хранить HGLOBAL и указатель Data. Так как эти значения должны сохраняться, пока у заданного ресурса не появятся обертки, удобней хранить данные значения в разделяемом держателе счетчиков ссылок.

Итак:
•    был определен XRefCountRes<Data>, порожденный от XRefCount<SResourceData<Data> >, хранящий еще два дополнительных члена: HGLOBAL и Data*.
•    были определены типы для получения const HRSRC& (являющегося IH), хранения HRSRC(являющегося SH), доступа к Data*(OH) и разыменования Data& (как RH)
•    изменены Access и Dereference для доступа к _pRC (держатель счетчика ссылок) и возврата Data* или Data& соответственно. Эти функции определены как статические в типажах и унаследованы в WrpBase. Нельзя переделать типажи, потому что на этом уровне не определен ни один указатель на объект счетчика ссылок. Они переопределены SResourceData не как статические, а как постоянные функции-члены. Поскольку они всегда вызываются через pThis() (преобразующего в W*, если W - обертка: SResourceData, в данном случае), будут вызваны переопределения.
•    OnFirstAttach и OnLastDetach переопределены для выполнения тяжелой работы: Load и Lock – сначала, Unlock и Free – позже.

Например, следующий код считывает ресурс RT_TOOLBAR в XToolBarData:

    // Примечание: допустим, уже имеется
    //  HINSTANCE hInst; LPCTSTR lpszResourceName;
    //
    struct XToolBarData
    {
        WORD wVersion;
        WORD wWidth;
        WORD wHeight;
        WORD wItemCount;
        //WORD aItems[wItemCount]

        WORD* items()
            { return (WORD*)(this+1); }
    };
   
    typedef NWrp::Wrp<NWrp::SResourceData<XToolBarData> > TTbrData;
    TTbrData TbrData;
    TbrData.SetHModule((HMODULE)hInst);
    TbrData.Attach(FindResource(hInst, lpszResourceName, RT_TOOLBAR));

    XToolBarData* pData = &*TbrData;
    ASSERT(pData && pData->wVersion == 1);
    // использовать pData при необходимости.
    // ресурсы будут освобождены при уходе из области видимости