Текущий раздел:

Описания RDS

Руководство программиста

Глава 2. Создание моделей блоков

§2.12. Реакция блоков на действия пользователя

§2.12.7. Добавление пунктов в системное меню RDS

Полный исходный текст на языке C++ для библиотеки (DLL) с моделью блока, добавляющего в главное меню RDS пункт для открытия родительской подсистемы.

      // Добавление пунктов в системное меню
      #include <windows.h>
      #include <RdsDef.h>
      // Подготовка описаний сервисных функций
      #define RDS_SERV_FUNC_BODY GetInterfaceFunctions
      #include <RdsFunc.h>

      //========== Главная функция DLL ==========
      int WINAPI DllMain(HINSTANCE /*hinst*/,
                               unsigned long reason,
                               void* /*lpReserved*/)
      { if(reason==DLL_PROCESS_ATTACH) // Загрузка DLL
          { // Получение доступа к функциям RDS
            if(!GetInterfaceFunctions())
              RDS_SERV_ERROR_MSGW // Сообщение: старая версия RDS
          }
        return 1;
      }
      //========= Конец главной функции =========

      // Класс личной области данных блока
      class TOpenSysWinData
      { public:
          RDS_MENUITEM MenuItem; // Идентификатор созданного пункта меню
          // Настроечные параметры
          char *Caption;   // Название пункта
          int Key;         // Клавиша (или 0,если ее нет)
          DWORD KeyShifts; // Состояние Ctrl, Alt и Shift

          // Создание пункта меню с заданными параметрами или
          // изменение параметров уже созданного пункта
          void RegisterMenuItem(void);

          int Setup(void);    // Открыть окно настройки
          void SaveBin(void); // Сохранить параметры
          int LoadBin(void);  // Загрузить параметры

          // Конструктор класса
          TOpenSysWinData(void)
            { Caption=NULL;
              Key=0; KeyShifts=0;
              MenuItem=NULL;
            };
          // Деструктор класса
          ~TOpenSysWinData()
            { // Освободить память, занятую строкой Caption
              rdsFree(Caption);
              // Удалить пункт меню
              rdsUnregisterMenuItem(MenuItem);
            };
      };
      //=========================================

      // Создание или модификация пункта меню
      // ВАЖНО: Исходный текст программы должен быть записан в UTF8,
      //   в противном случае необходимо использовать версии функций
      //   с суффиксом "W" и символьные константы с префиксом "L"
      void TOpenSysWinData::RegisterMenuItem(void)
      { // Вспомогательная переменная для заголовка пункта меню:
        // если Caption==NULL, пункт получит заголовок "Открыть окно"
        const char *text=Caption?Caption:"Открыть окно";
        // Флаги пункта меню: если клавиша определена (Key!=0),
        // пункт будет иметь "горячую клавишу"
        DWORD options=Key?RDS_MENU_SHORTCUT:0;

        if(MenuItem) // Пункт уже есть - изменяем
          rdsChangeMenuItem(MenuItem,text,options,Key,KeyShifts,0,0);
        else // Пункта еще нет - создаем
          MenuItem=rdsRegisterMenuItem(text,options,Key,KeyShifts,0,0);
      }
      //=========================================

      // Запись параметров блока
      void TOpenSysWinData::SaveBin(void)
      { BYTE tag; // Переменная для байта тега
        int len=Caption?strlen(Caption):0; // Длина строки Caption

        tag=1; // Тег 1 – название пункта меню
        rdsWriteBlockData(&tag,sizeof(tag));
        rdsWriteBlockData(&len,sizeof(len)); // Длина строки
        if(len) // При ненулевой длине – запись самой строки
          rdsWriteBlockData(Caption,len);

        tag=2; // Тег 2 – "горячая клавиша"
        rdsWriteBlockData(&tag,sizeof(tag));
        rdsWriteBlockData(&Key,sizeof(Key));
        rdsWriteBlockData(&KeyShifts,sizeof(KeyShifts));

        tag=0; // Тег 0 – конец данных
        rdsWriteBlockData(&tag,sizeof(tag));
      }
      //=========================================

      // Загрузка параметров блока
      int TOpenSysWinData::LoadBin(void)
      { BYTE tag; // Переменная для байта тега
        int len;

        // Прежде всего, освобождаем память, которую занимало старое
        // название пункта меню – сейчас загрузится новое
        rdsFree(Caption);
        Caption=NULL;

        for(;;)
          { if(!rdsReadBlockData(&tag,sizeof(tag)))
              break; // Тег не считан – данные неожиданно кончились
            switch(tag)
              { case 0: // Конец данных
                  RegisterMenuItem(); // Создаем или изменяем пункт меню
                  return RDS_BFR_DONE;
                case 1: // Название пункта
                  rdsReadBlockData(&len,sizeof(len));	// Читаем длину
                  if(len) // Длина ненулевая – читаем len байтов строки
                    { // Отводим место с учетом нуля в конце строки
                      Caption=(char*)rdsAllocate(len+1);
                      rdsReadBlockData(Caption,len);	// Читаем строку
                      Caption[len]=0;	// Дописываем нулевой байт в конец
                    }
                  break;
                case 2: // Данные "горячей клавиши"
                  rdsReadBlockData(&Key,sizeof(Key));
                  rdsReadBlockData(&KeyShifts,sizeof(KeyShifts));
                  break;
                default: // Тег не опознан – ошибка
                  return RDS_BFR_ERROR;
              }
          }
        // Вышли из цикла из-за неожиданного конца данных блока - ошибка
        return RDS_BFR_ERROR;
      }
      //=========================================

      // Настройка параметров блока
      // ВАЖНО: Исходный текст программы должен быть записан в UTF8,
      //   в противном случае необходимо использовать версии функций
      //   с суффиксом "W" и символьные константы с префиксом "L"
      int TOpenSysWinData::Setup(void)
      { RDS_HOBJECT window; // Идентификатор объекта-окна
        BOOL ok; // Пользователь нажал "OK"
        // Создание окна
        window=rdsFORMCreate(FALSE,-1,-1,"Открытие окна");
        // Поле ввода для строки названия
        rdsFORMAddEdit(window,0,1,RDS_FORMCTRL_EDIT,
            "Текст пункта меню:",200);
        rdsSetObjectStr(window,1,RDS_FORMVAL_VALUE,Caption);
        // Поле ввода для "горячей клавиши"
        rdsFORMAddEdit(window,0,2,RDS_FORMCTRL_HOTKEY,
            "Клавиша:",150);
        rdsSetObjectInt(window,2,RDS_FORMVAL_VALUE,Key);
        rdsSetObjectInt(window,2,RDS_FORMVAL_HKSHIFTS,KeyShifts);
        // Открытие окна
        ok=rdsFORMShowModalEx(window,NULL);
        if(ok)
          { // Нажата кнопка OK – запись параметров в блок
            rdsFree(Caption); // Уничтожение старой строки
            // Создание динамической копии введенной строки
            Caption=rdsDynStrCopy(rdsGetObjectStr(window,1,
                RDS_FORMVAL_VALUE));
            // Чтение параметров клавиши
            Key=rdsGetObjectInt(window,2,RDS_FORMVAL_VALUE);
            KeyShifts=rdsGetObjectInt(window,2,RDS_FORMVAL_HKSHIFTS);
            // Создание пункта меню на основе изменившихся параметров
            RegisterMenuItem();
          }
        // Уничтожение окна
        rdsDeleteObject(window);
        // Возвращаемое значение
        return ok?RDS_BFR_MODIFIED:RDS_BFR_DONE;
      }
      //=========================================

      // Блок, открывающий окно родительской подсистемы
      extern "C" __declspec(dllexport)
        int RDSCALL OpenSysWin(int CallMode,
                          RDS_PBLOCKDATA BlockData,
                          LPVOID ExtParam)
      { // Указатель на личную область данных блока,приведенный к
        // правильному типу
        TOpenSysWinData *data=(TOpenSysWinData*)(BlockData->BlockData);
        switch(CallMode)
          { case RDS_BFM_INIT: // Инициализация
              BlockData->BlockData=data=new TOpenSysWinData();
              break;
            case RDS_BFM_CLEANUP: // Очистка
              delete data;
              break;
            case RDS_BFM_SETUP: // Настройка
              return data->Setup();
            case RDS_BFM_SAVEBIN: // Сохранение параметров
              data->SaveBin();
              break;
            case RDS_BFM_LOADBIN: // Загрузка параметров
              return data->LoadBin();
            case RDS_BFM_MENUFUNCTION:// Выбор пункта меню
              rdsOpenSystemWindow(BlockData->Parent);
              break;
          }
        return RDS_BFR_DONE;
      }
      //=========================================