┌───────────────┐
│ BOLDY.H       │
└───────────────┘

/**************************************************************************/
/* boldy.h - исходный текст программы Болван диалоГовый                   */
/*           v0.03                                                        */
/*========================================================================*/
/* (c) VicTor Smirnoff, 1998-2000                    sva@water.karelia.ru */
/**************************************************************************/

/**************************************************************************/
/* Идентификаторы дополнительных сообщений                                */
/**************************************************************************/
#define MY_QUERYSIZE WM_USER+1 // проверка размеров окна
#define MY_SETSIZE   WM_USER+2 // установка размеров окна

/**************************************************************************/
/* Идентификаторы наименований                                            */
/**************************************************************************/
#define IDS_APPTITLE       1   // название программы
                               // (заголовок главного окна)

/**************************************************************************/
/* Идентификаторы рабочих окон и ресурсов                                 */
/**************************************************************************/
#define ID_MSGBOX         11   // окно сообщений (WinMessageBox)

/**************************************************************************/
/* Идентификаторы сообщений об ошибке                                     */
/**************************************************************************/
#define IDS_CREATEMAIN  1001   // ошибка создания главного
                               // окна приложения

/**************************************************************************/
/* Идентификаторы основных окон и ресурсов                                */
/**************************************************************************/
#define ID_MAIN          101   // главное окно приложения

/**************************************************************************/
/* Далее следуют идентификаторы пользовательских ресурсов.                */
/* Вы можете создать свои собственные ресурсы (например, диалог с помощью */
/* DLGEDIT). Идентификаторы Ваших ресурсов должны следовать за данным     */
/* комментарием и не должны пересекаться с имеющимися ресурсами. Затем Вы */
/* можете просто заменить ресурсы программы (заново компилировать         */
/* программу не надо!) с помощью RC (см. RCboldy.CMD).                    */
/**************************************************************************/

//--- меню
#define ID_FILE          102
#define ID_OPEN          103
#define ID_SAVE          104
#define ID_SAVEAS        105
#define ID_EXIT          106   // кнопка Выход диалога
#define ID_HELP          107
#define ID_ABOUT         108

//--- окна диалога
#define ID_ICON          109
#define ID_TEXT          110

┌───────────────┐
│ BOLDY.CPP     │
└───────────────┘

/**************************************************************************/
/* boldy.cpp - исходный текст программы Болван диалоГовый                 */
/*           v0.03                                                        */
/*========================================================================*/
/* (c) VicTor Smirnoff, 1998-2000                    sva@water.karelia.ru */
/**************************************************************************/
#define INCL_PM
#define INCL_DOSPROCESS        // нужен для DosSleep()

#include <os2.h>
#include <stdlib.h>            // нужен для max()
#include <string.h>            // нужен для strncpy()
#include <stdio.h>             // нужен для sprintf()

#define Main main

#ifdef __HIGHC__
   #define min( a, b ) ( ((a) < (b)) ? (a) : (b) )
   #define max( a, b ) ( ((a) > (b)) ? (a) : (b) )
#endif

#include "boldy.h"

/**************************************************************************/
/* Прототипы функций                                                      */
/**************************************************************************/
MRESULT EXPENTRY WndDlgProc( HWND, ULONG, MPARAM, MPARAM );
VOID SetDlgItemPos( LONG, LONG );
VOID DisplayError( ULONG );
VOID BeepError( ULONG );

/**************************************************************************/
/* Константы                                                              */
/**************************************************************************/
#define RETURN_ERROR         1      // значение возврата при ошибке
#define BEEP_WARN_FREQ    3000      // тон сигнала об ошибке
#define BEEP_WARN_DUR      200      // длительность сигнала об ошибке
#define BEEP_WARN_PAUSE     40      // пауза между сигналами об ошибке
#define BEEP_WARN_INIT       2      // число сигналов об ошибке инициализации
#define BEEP_WARN_QUEUE      4      // число сигналов об ошибке создания очереди
#define MSG_WARN_SIZE       80      // длина сообщения об ошибке

/**************************************************************************/
/* Глобальные переменные                                                  */
/**************************************************************************/
HAB  hab;
HWND hwndMain;
HPOINTER hptrIcon = NULLHANDLE;

SWP swpDefault;                    // дефолтный размер Dialog
SWP swpMini;                       // размер Dialog перед минимизацией

CHAR szAppTitle[MAXNAMEL];

/**************************************************************************/
/* Головная функция приложения                                            */
/* Получает управление при запуске приложения                             */
/**************************************************************************/
Main ()
{
   HMQ    hmq;
   QMSG   qmsg;

/**************************************************************************/
/* Инициализация оконного интерфейса                                      */
/*                                                                        */
/* (***) несмотря на все уверения и примеры, WinMessageBox() не работает  */
/*       до тех пор, пока не получен hab и не создана очередь сообщений.  */
/*       Поэтому об ошибке здесь сообщаем серией сигналов.                */
/**************************************************************************/
   hab = WinInitialize( 0 );
   if ( hab == NULLHANDLE )
   {
      BeepError( BEEP_WARN_INIT );
      return RETURN_ERROR;
   }

/**************************************************************************/
/* Создание очереди сообщений                                             */
/**************************************************************************/
   hmq = WinCreateMsgQueue( hab, 0 );
   if ( hmq == NULLHANDLE )
   {
      BeepError( BEEP_WARN_QUEUE );
      return RETURN_ERROR;
   }

/**************************************************************************/
/* Получим строку с заголовком (названием) программы                      */
/*                                                                        */
/* (***) название программы (заголовок главного окна) хранится в ресурсах */
/*       исходя из тех соображений, что в локализованных версиях          */
/*       программы оно должно звучать на национальном языке.              */
/*       Помещение названия и любых других текстовых сообщений в ресурсы  */
/*       позволяет исключить повторную компиляцию программы при подготовке*/
/*       локализованных версий.                                           */
/*       В этом случае достаточно просто подготовить ресурсы на нужном    */
/*       языке и заменить ими ресурсы, существующие в EXE-файле, с помощью*/
/*       RC (см. RCboldy.CMD).                                            */
/**************************************************************************/
   WinLoadString( hab,
                  (HMODULE)0L,
                  IDS_APPTITLE,
                  MAXNAMEL,
                  (PSZ)szAppTitle );

   hptrIcon = WinLoadPointer( HWND_DESKTOP, 0L, ID_MAIN );

/**************************************************************************/
/* Создаём главное окно приложения (Dialog)                               */
/**************************************************************************/
   hwndMain = WinLoadDlg( HWND_DESKTOP, // где разместить
                          HWND_DESKTOP, // кто собственник
                          WndDlgProc,   // процедура обработки диалога
                          (HMODULE)0,   // 0 - в EXE, #N - в DLL
                          ID_MAIN,      // идентификатор диалога в ресурсе
                          NULL);        // данные для инициализации

   if ( hwndMain == NULLHANDLE )
   {
      DisplayError( IDS_CREATEMAIN );
      WinDestroyMsgQueue( hmq );
      WinTerminate( hab );
      return RETURN_ERROR;
   }

/**************************************************************************/
/* Цикл обработки сообщений                                               */
/**************************************************************************/
   while( WinGetMsg( hab, &qmsg, 0, 0, 0 ) ) 
   {
      WinDispatchMsg( hab, &qmsg );
   }

/**************************************************************************/
/* Закрытие приложения                                                    */
/**************************************************************************/
   if ( hptrIcon != NULLHANDLE ) WinDestroyPointer( hptrIcon );

   WinDestroyWindow( hwndMain );
   WinDestroyMsgQueue( hmq );
   WinTerminate( hab );

   return 0;
}

/**************************************************************************/
/* Функция главного окна (Dialog)                                         */
/**************************************************************************/
MRESULT EXPENTRY WndDlgProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
{
   switch ( msg )
   {
/**************************************************************************/
/* WM_INITDLG                                                             */
/*    запрос на инициализацию окна Dialog                                 */
/*    (но к этому моменту оно ещё не создано)                             */
/*                                                                        */
/* 1. запросим проверку размеров окна Dialog                              */
/*                                                                        */
/* (***) для правильного получения размеров дефолтного окна и установки   */
/*       новых размеров пришлось ввести два дополнительных сообщения:     */
/*       MY_QUERYSIZE и MY_SETSIZE.                                       */
/*       Возвращаем TRUE, чтобы система не пыталась установить фокус      */
/*       на окне диалога (около 10 лишних сообщений).                     */
/**************************************************************************/
      case WM_INITDLG:
         WinPostMsg( hwnd, MY_QUERYSIZE, NULL, NULL );
      return (MRESULT)TRUE;

/**************************************************************************/
/* MY_QUERYSIZE                                                           */
/*    поступает от обработчика (Dialog) сразу после WM_INITDLG            */
/*    (к этому времени уже создано окно Dialog дефолтного размера)        */
/*                                                                        */
/* 1. установим иконку и текст заголовка                                  */
/* 2. загрузим таблицу акселераторов                                      */
/* 3. создадим пользовательское меню                                      */
/* 4. добавим элемент в список окон                                       */
/* 5. определим дефолтные размеры и увеличим их на высоту меню;           */
/*    это будут минимально возможные размеры (если не менять размер,      */
/*    то пользовательское меню при первом запуске появляется только       */
/*    после любого изменения размеров окна).                              */
/* 6. восстановим параметры окна                                          */
/* 7. если параметры не восстановлены (например, отсутствуют),            */
/*    то запросим показ и активацию окна дефолтного размера               */
/**************************************************************************/
      case MY_QUERYSIZE:
      {
         SWP swp;
         SWCNTRL swctl;
         HSWITCH hswitch;
         HACCEL  hAccel;
         FRAMECDATA frame;

         WinSendMsg( hwndMain, WM_SETICON, (MPARAM)hptrIcon, (MPARAM)0L );
         WinSetWindowText( hwndMain, szAppTitle );

         hAccel = WinLoadAccelTable( hab, (HMODULE)NULLHANDLE, ID_MAIN );
         WinSetAccelTable( hab, hAccel, hwndMain );

         frame.cb = sizeof( FRAMECDATA );
         frame.flCreateFlags = FCF_MENU;
         frame.hmodResources = 0L;
         frame.idResources = ID_MAIN;

         WinCreateFrameControls( hwndMain, &frame, (PSZ)0L );

         swctl.hwnd = hwndMain;
         swctl.hwndIcon = hwndMain;
         swctl.hprog = NULLHANDLE;
         swctl.idProcess = 0;
         swctl.idSession = 0;
         swctl.uchVisibility = SWL_VISIBLE;
         swctl.fbJump = SWL_JUMPABLE;
         swctl.szSwtitle[0] = 0x00;
         swctl.szSwtitle[MAXNAMEL + 1] = 0x00;
         strncpy( swctl.szSwtitle, szAppTitle, MAXNAMEL );

         hswitch = WinAddSwitchEntry( &swctl );

         WinQueryWindowPos( hwnd, (PSWP)&swp );
         swp.cy += WinQuerySysValue( HWND_DESKTOP, SV_CYMENU );
         swpDefault = swp;
         swpMini = swp;
         WinSetWindowPos( hwnd, HWND_TOP, 
                          0, 0, swp.cx, swp.cy, 
                          SWP_SIZE | SWP_NOADJUST );

         WinPostMsg( hwnd, MY_SETSIZE, 
                     MPFROMLONG(swpDefault.cx), 
                     MPFROMLONG(swpDefault.cy) );
      }
      return (MRESULT)FALSE;

/**************************************************************************/
/* MY_SETSIZE                                                             */
/*    поступает от обработчика (Dialog) после MY_QUERYSIZE                */
/*    и WM_ADJUSTWINDOWPOS для выравнивания элементов диалога после       */
/*    изменения размеров окна диалога;                                    */
/*    в качестве параметров получает старые размеры окна Dialog           */
/*                                                                        */
/* 1. позиционируем элементы диалога в соответствии с новыми размерами,   */
/*    если окно не минимизировано                                         */
/*                                                                        */
/* (***) WinSetWindowPos(...,SWP_ACTIVATE) защищает от неадекватной       */
/*       реакции на максимизацию из минимизированного состояния           */
/*       (иначе WinQueryWindowPos возвращает размер окна равный размеру   */
/*       миниокна (40x40 для иконки 32x32), хотя на экране уже            */
/*       прорисовано окно новых размеров)                                 */
/*                                                                        */
/* (***) WinShowWindow(...,TRUE) необходим для показа диалога после его   */
/*       создания                                                         */
/**************************************************************************/
      case MY_SETSIZE:
      {
         SWP swp;
         LONG deltaX, deltaY;

         WinSetWindowPos( hwnd, HWND_TOP, 
                          0L, 0L, 0L, 0L, SWP_ACTIVATE );

         WinQueryWindowPos( hwnd, (PSWP)&swp );

         if ( !(swp.fl & SWP_MINIMIZE) )
         {
            deltaX = swp.cx - LONGFROMMP(mp1);
            deltaY = swp.cy - LONGFROMMP(mp2);

            if ( deltaX != 0 || deltaY != 0 )
               SetDlgItemPos( deltaX, deltaY );

            WinShowWindow( hwnd, TRUE );
         }
      }
      return (MRESULT)FALSE;

/**************************************************************************/
/* WM_ADJUSTWINDOWPOS                                                     */
/*    поступает перед изменением размеров диалога                         */
/**************************************************************************/
      case WM_ADJUSTWINDOWPOS:
      {
         SWP swp;

         WinQueryWindowPos( hwnd, (PSWP)&swp );

/**************************************************************************/
/* SWP_MINIMIZE                                                           */
/*    запрошена минимизация окна                                          */
/*                                                                        */
/* 1. сохраним текущие размеры окна для последующего восстановления       */
/**************************************************************************/
         if (((PSWP)mp1)->fl & SWP_MINIMIZE)
            WinQueryWindowPos( hwnd, (PSWP)&swpMini );

/**************************************************************************/
/* SWP_RESTORE || SWP_MAXIMIZE                                            */
/*    запрошено восстановление или максимизация окна                      */
/*                                                                        */
/* 1. если из минимизированного состояния, то сообщим размеры,            */
/*    сохранённые перед минимизацией;                                     */
/*    SWP_ACTIVATE отключаем из-за неадекватной реакции                   */
/* 2. иначе сообщим текущие размеры окна                                  */
/*                                                                        */
/* (***) проверка на размеры меньше дефолтных необходима для              */
/*       предотвращения изменения размеров максимизированного окна        */
/*       меньше дефолтных (т.е. когда юзер тянет мышью границу            */
/*       максимизированного окна уменьшая его)                            */
/**************************************************************************/
         else if ( (((PSWP)mp1)->fl & SWP_RESTORE) ||
                   (((PSWP)mp1)->fl & SWP_MAXIMIZE) )
         {
            if ( swp.fl & SWP_MINIMIZE )
            {
               ((PSWP)mp1)->fl = ((PSWP)mp1)->fl & ~SWP_ACTIVATE;

               WinPostMsg( hwnd, MY_SETSIZE,
                           MPFROMLONG(swpMini.cx), 
                           MPFROMLONG(swpMini.cy) );
            }
            else
            {
               if ( (((PSWP)mp1)->cx < swpDefault.cx) ||
                    (((PSWP)mp1)->cy < swpDefault.cy) )
               {
                  ((PSWP)mp1)->cx = max( swpDefault.cx, ((PSWP)mp1)->cx );
                  ((PSWP)mp1)->cy = max( swpDefault.cy, ((PSWP)mp1)->cy );
               }

               WinPostMsg( hwnd, MY_SETSIZE,
                           MPFROMLONG(swp.cx), 
                           MPFROMLONG(swp.cy) );
            }
         }

/**************************************************************************/
/* SWP_SIZE                                                               */
/*    запрошено изменение размеров окна                                   */
/*                                                                        */
/* 1. если новые размеры меньше дефолтных (минимально возможных),         */
/*    то изменим параметры для установки дефолтных размеров               */
/* 2. сообщим текущие размеры окна                                        */
/*                                                                        */
/* (***) для диалога SWP_SIZE всегда ходит в паре с SWP_MOVE              */
/**************************************************************************/
         else if (((PSWP)mp1)->fl & SWP_SIZE)
         {
            if ( (((PSWP)mp1)->cx < swpDefault.cx) ||
                 (((PSWP)mp1)->cy < swpDefault.cy) )
            {
               ((PSWP)mp1)->cx = max( swpDefault.cx, ((PSWP)mp1)->cx );
               ((PSWP)mp1)->cy = max( swpDefault.cy, ((PSWP)mp1)->cy );
            }

            WinPostMsg( hwnd, MY_SETSIZE,
                        MPFROMLONG(swp.cx), 
                        MPFROMLONG(swp.cy) );
         }
      }
      return WinDefDlgProc( hwnd, msg, mp1, mp2 );

/**************************************************************************/
/* WM_CLOSE                                                               */
/*    поступает после обработки WM_COMMAND=ID_EXIT (пользователь          */
/*    щёлкнул по кнопке ВЫХОД, нажал F3 или выбрал пункт меню             */
/*    ВЫХОД) или дважды щёлкнул по минизначку, щёлкнул по кнопке          */
/*    завершения в полосе заголовка, нажал Alt-F4 или выбрал пункт        */
/*    ЗАКРЫТЬ в системном меню или в меню соответствующего значка         */
/*    в папке ОБЗОР МИНИОКОН                                              */
/*                                                                        */
/* 1. запросим завершение приложения                                      */
/*                                                                        */
/* (***) WinDismissDlg не нужен, т.к. в обработчике не используется       */
/*       WinProcessDlg или WinDlgBox (диалог немодальный)                 */
/**************************************************************************/
      case WM_CLOSE:
         WinPostMsg( hwnd, WM_QUIT, NULL, NULL );
      return (MRESULT)FALSE;

/**************************************************************************/
/* WM_COMMAND                                                             */
/*    поступает, если пользователь воздействует на какой-либо элемент     */
/*    диалога                                                             */
/**************************************************************************/
      case WM_COMMAND:
         switch( SHORT1FROMMP( mp1 ) )
         {
/**************************************************************************/
/* пользователь щёлкнул по кнопке ВЫХОД, нажал F3 или выбрал пункт меню   */
/* ВЫХОД                                                                  */
/*                                                                        */
/* (***) отправляем WM_CLOSE, чтобы обработка выхода была одинакова       */
/*       в разных случаях                                                 */
/**************************************************************************/
            case ID_EXIT:
               WinPostMsg( hwnd, WM_CLOSE, NULL, NULL );
            break;

/**************************************************************************/
/* пользователь выбрал один из пунктов меню                               */
/*                                                                        */
/* (***) в настоящий момент эти пункты меню не обрабатываются.            */
/**************************************************************************/
            case ID_OPEN:
            case ID_SAVE:
            case ID_SAVEAS:
            case ID_ABOUT:
            break;

/**************************************************************************/
/* сюда Вы можете вставить обработку элементов своего диалога             */
/*                                                                        */
/* case:                                                                  */
/*    ...                                                                 */
/*    break;                                                              */
/**************************************************************************/

/**************************************************************************/
/* (***) диалог снимается (прячется окно), если выполнять WinDefDlgProc   */
/*       по умолчанию для необрабатываемых элементов диалога              */
/**************************************************************************/
            default:
            break;
         }
      return (MRESULT)FALSE;

/**************************************************************************/
/* WinDefDlgProc, по умолчанию                                            */
/**************************************************************************/
      default:
      return WinDefDlgProc( hwnd, msg, mp1, mp2 );
   }

   return (MRESULT)FALSE;
}

/**************************************************************************/
/* Позиционирование элементов диалога                                     */
/*                                                                        */
/* Позиционирует иконку и кнопку ВЫХОД.                                   */
/*                                                                        */
/* Параметры: dX - приращение размеров окна по оси X                      */
/*            dY - приращение размеров окна по оси Y                      */
/*                                                                        */
/* (***) Вы можете изменить эту функцию для позиционирования своих        */
/*       элементов диалога.                                               */
/**************************************************************************/
VOID SetDlgItemPos( LONG dX, LONG dY )
{
   HWND hwnd;
   SWP swp;

/**************************************************************************/
/* спрячем все элементы диалога                                           */
/* (перерисовка невидимых окон значительно быстрее)                       */
/**************************************************************************/
   WinShowWindow( WinWindowFromID( hwndMain, ID_TEXT ), FALSE );
   WinShowWindow( WinWindowFromID( hwndMain, ID_ICON ), FALSE );
   WinShowWindow( WinWindowFromID( hwndMain, ID_EXIT ), FALSE );

/**************************************************************************/
/* позиционируем иконку                                                   */
/**************************************************************************/
   hwnd = WinWindowFromID( hwndMain, ID_ICON);
   WinQueryWindowPos( hwnd, (PSWP)&swp );
   WinSetWindowPos( hwnd, HWND_TOP,
                    swp.x + dX, swp.y + dY, swp.cx, swp.cy,
                    SWP_MOVE );

/**************************************************************************/
/* позиционируем кнопку ВЫХОД                                             */
/**************************************************************************/
   hwnd = WinWindowFromID( hwndMain, ID_EXIT);
   WinQueryWindowPos( hwnd, (PSWP)&swp );
   WinSetWindowPos( hwnd, HWND_TOP,
                    swp.x + dX, swp.y, swp.cx, swp.cy,
                    SWP_MOVE );

/**************************************************************************/
/* изменяем размеры текстового поля                                       */
/**************************************************************************/
   hwnd = WinWindowFromID( hwndMain, ID_TEXT);
   WinQueryWindowPos( hwnd, (PSWP)&swp );
   WinSetWindowPos( hwnd, HWND_TOP,
                    swp.x, swp.y, swp.cx + dX, swp.cy + dY,
                    SWP_SIZE );

/**************************************************************************/
/* покажем все элементы диалога                                           */
/**************************************************************************/
   WinShowWindow( WinWindowFromID( hwndMain, ID_TEXT), TRUE );
   WinShowWindow( WinWindowFromID( hwndMain, ID_ICON), TRUE );
   WinShowWindow( WinWindowFromID( hwndMain, ID_EXIT), TRUE );
}

/**************************************************************************/
/* Вывод сообщения об ошибке                                              */
/*                                                                        */
/* Текст сообщения об ошибке подгружается из ресурсов и выводится в окне  */
/*                                                                        */
/* Параметры: idMsg - идентификатор сообщения в ресурсах                  */
/**************************************************************************/
VOID DisplayError( ULONG idMsg )
{
   CHAR cMsg[MSG_WARN_SIZE] = "";

   WinLoadString( hab, (HMODULE)0L,
                  idMsg, MSG_WARN_SIZE,
                  (PSZ)cMsg );

   if ( cMsg[0] != 0 )
   {
      WinMessageBox( HWND_DESKTOP, HWND_DESKTOP, (PCH)cMsg,
                     (PCH)szAppTitle, ID_MSGBOX,
                     MB_OK | MB_APPLMODAL | MB_MOVEABLE | MB_ERROR );
   }
}

/**************************************************************************/
/* Сообщение об ошибке                                                    */
/*                                                                        */
/* Выдаёт серию сигналов об ошибке                                        */
/*                                                                        */
/* Параметры: n - количество сигналов в серии                             */
/**************************************************************************/
VOID BeepError( ULONG n )
{
   INT i;

   for ( i = 0; i < n; i ++ )
   {
      DosBeep( BEEP_WARN_FREQ, BEEP_WARN_DUR );
      DosSleep( BEEP_WARN_PAUSE );
   }
}

┌───────────────┐
│ BOLDY.DEF     │
└───────────────┘

NAME BOLDY
WINDOWAPI

┌───────────────┐
│ BOLDY.RC      │
└───────────────┘

/**************************************************************************/
/* boldy.rc - исходный текст программы Болван диалоГовый                  */
/*            v0.03                                                       */
/*========================================================================*/
/* (c) VicTor Smirnoff, 1998-2000                    sva@water.karelia.ru */
/**************************************************************************/
#include <os2.h>
#include "boldy.h"

/**************************************************************************/
/* Собственный значок приложения                                          */
/*    В отличие от главного окна приложения, создаваемого функцией        */
/*    WinCreateStdWindow(), при создании фрейма диалога собственный       */
/*    значок приложения не используется (даже при включённом флаге        */
/*    FCF_ICON).                                                          */
/**************************************************************************/
ICON ID_MAIN boldy.ico

/**************************************************************************/
/* Таблица акселераторов                                                  */
/*    В отличие от главного окна приложения, создаваемого функцией        */
/*    WinCreateStdWindow(), при создании фрейма диалога таблица           */
/*    акселераторов не используется (даже при включённом флаге            */
/*    FCF_ACCELTABLE).                                                    */
/**************************************************************************/
ACCELTABLE ID_MAIN PRELOAD
BEGIN
    VK_F3, ID_EXIT, VIRTUALKEY
END

/**************************************************************************/
/* Пользовательское меню                                                  */
/*    В отличие от главного окна приложения, создаваемого функцией        */
/*    WinCreateStdWindow(), при создании фрейма диалога пользовательское  */
/*    меню не создаётся (даже при включённом флаге FCF_MENU).             */
/**************************************************************************/
MENU    ID_MAIN PRELOAD
BEGIN
    SUBMENU "Файл", ID_FILE
    BEGIN
        MENUITEM "Открыть",              ID_OPEN,    MIS_TEXT
        MENUITEM "Сохранить",            ID_SAVE,    MIS_TEXT
        MENUITEM "Сохранить как ...",    ID_SAVEAS,  MIS_TEXT
        MENUITEM SEPARATOR
        MENUITEM "Выход \t F3",          ID_EXIT,    MIS_TEXT
    END
    SUBMENU "Справка", ID_HELP
    BEGIN
        MENUITEM "О программе...",       ID_ABOUT,   MIS_TEXT
    END
END

/**************************************************************************/
/* Таблица строк (идентификаторы и строки с сообщениями)                  */
/**************************************************************************/
STRINGTABLE PRELOAD
BEGIN
    IDS_CREATEMAIN,  "Ошибка создания главного окна диалога"
    IDS_APPTITLE,    "Болван диалоГовый"
END

/**************************************************************************/
/* Диалог приложения                                                      */
/**************************************************************************/
;;
rcinclude boldy.dlg
;

┌───────────────┐
│ BOLDY.DLG     │
└───────────────┘

/**************************************************************************/
/* boldy.dlg - исходный текст программы Болван диалоГовый                 */
/*             v0.03                                                      */
/*========================================================================*/
/* (c) VicTor Smirnoff, 1998-2000                    sva@water.karelia.ru */
/**************************************************************************/
DLGINCLUDE 1 "boldy.h"

DLGTEMPLATE ID_MAIN LOADONCALL MOVEABLE DISCARDABLE
BEGIN
    DIALOG  "", ID_MAIN, 0, 0, 156, 43, NOT FS_DLGBORDER | FS_SIZEBORDER |
            NOT WS_SAVEBITS, FCF_SYSMENU | FCF_TITLEBAR | FCF_MINBUTTON |
            FCF_MAXBUTTON
    BEGIN
        DEFPUSHBUTTON   "Выход", ID_EXIT, 98, 0, 58, 14
        ICON            ID_MAIN, ID_ICON, 117, 20, 20, 16, WS_GROUP
        LTEXT           "Этот простой пример демонстрирует возможность созда"
                        "ния диалоговых окон с изменяемыми размерами и обычн"
                        "о отсутствующими атрибутами фрейма: (1)собственный "
                        "значок приложения, (2)пользовательское меню, (3)кла"
                        "виши-акселераторы.",
                        ID_TEXT, 1, 0, 90, 41, DT_WORDBREAK
                        PRESPARAMS PP_BACKGROUNDCOLOR, 0x00FFFFDCL
                        PRESPARAMS PP_FONTNAMESIZE, "8.Helv"
    END
END

┌───────────────┐
│ MAKEALL.CMD   │
└───────────────┘

/* Вызов компилятора */
'@echo off'

Icon_is_present = Stream( 'boldy.ico', 'C', 'Query Exists' )

If Icon_is_present \= '' then do
 Address CMD 'icc boldy.cpp boldy.def'
 Address CMD 'rc boldy.rc boldy.exe'
 Address CMD 'del /F boldy.obj >nul 2>nul'
 Address CMD 'del /F boldy.res >nul 2>nul'
End
Else do
 Say 'Not found: boldy.ico'
End

┌───────────────┐
│ RCBOLDY.CMD   │
└───────────────┘

/* Замена ресурсов boldy.exe */
'@echo off'

Address CMD 'rc boldy.rc'