Консультация № 146427
08.10.2008, 11:12
0.00 руб.
0 1 1
Здравствуйте, эксперты RUSFAQ.RU !

Возникла проблема следующего плана:
пытаюсь разобраться с кодом "Создание диалоговой панели" из книги Ганеева "Проектирование интерфейса пользователя средствами Win32 API".
Код в приложении. При запуске кода на выполнение (компилируется без ошибок) - главное окно работает, а панель диалога нет ...
Такой же вопрос я встречал на одном из сторонних форумов. Надеюсь, эксперту не составить труда найти ошибку.

Спасибо !

Приложение:
//exmpl.cpp

#include "Functions.h"

#define ID_STATIC 2000
#define ID_BUTTON1 2001
#define ID_BUTTON2 2002
#define ID_BUTTON3 2003
#define ID_HELP 2004

LRESULT CALLBACK WndProc(HWND,UINT, WPARAM,LPARAM);
LRESULT CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM);
int CreateDlg (HWND);
HINSTANCE hInstance;
char szClass[] = "AppClass";

INT WINAPI WinMain (HINSTANCE hlnstance, HINSTANCE, PSTR, INT nCmdShow)
{ MSG msg; HWND hwnd; ::hInstance=hInstance;

if (!RegClass(WndProc,szClass,COLOR_DESKTOP)) return FALSE;

int wScreen=GetSystemMetrics(SM_CXSCREEN);
int hScreen=GetSystemMetrics(SM_CYSCREEN);

hwnd = CreateWindow(szClass, "Создание диалоговой панели", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
0,0, wScreen/2, hScreen/2, 0,0, hInstance, NULL);

if (!hwnd) return FALSE;
while(GetMessage(&msg, NULL,0,0))
{ TranslateMessage(&msg); DispatchMessage(&msg);}
return (int)msg.wParam;
}

LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{ switch (msg)
{ case WM_CREATE:
{ CreateDlg(hwnd); return 0;}
case WM_DESTROY:
{ PostQuitMessage(0); return 0;}
} return DefWindowProc(hwnd, msg, wParam, lParam);
}

LRESULT CALLBACK DlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{ switch (msg)
{ case WM_COMMAND:
{ switch(LOWORD(wParam))
{ case IDOK:
case IDCANCEL:
{ return TRUE; }
} return FALSE;
}
} return FALSE;
}

int CreateDlg( HWND hwnd )
{ char const caption[ ]=" Изменение режима работы приложения";
char const stattxt[ ]="Сейчас следует:";
char const modeoff[ ]="завершить работу приложения";
char const modedat[ ]="перезагрузить данные";
char const modepsw[ ]="сменить имя пользователя";

//Выделяем блок памяти для записи шаблона
WORD *p, *pdlgtemplate;
pdlgtemplate=p=(PWORD)LocalAlloc(LPTR, 2000);
//Определяем среднюю ширину cxChar и высоту cyChar шрифта
int cxChar, cyChar;
{ TEXTMETRIC tm;
HDC hdc=GetDC(hwnd);
GetTextMetrics(hdc,&tm);
ReleaseDC(hwnd, hdc);
cxChar=tm.tmAveCharWidth+1;
cyChar=tm.tmHeight+tm.tmExternalLeading;
}

//Определяем диалоговые единицы ширины и высоты
DWORD dlgunit =GetDialogBaseUnits();
int dlgwunit=LOWORD(dlgunit), dlghunit=HIWORD(dlgunit);
//Пересчитываем габариты символов шрифта
cxChar=cxChar*4/dlgwunit;cyChar=cyChar*8/dlghunit;
int wDlg, hDlg, wItem, hItem, left, top;

//Записываем в шаблон данные панели
DWORD lStyle = DS_CENTER | DS_MODALFRAME | WS_POPUPWINDOW | WS_CAPTION;
wDlg=lstrlen(caption)*cxChar;
hDlg=cyChar*10;
DlgTemplate(p, lStyle, 7, 0, 0, wDlg, hDlg, (LPSTR)caption);

//Далее добавляем записи органов управления
//1
hItem=cyChar; top=left=hItem/2; hItem+=left; wItem=(wDlg-left-left);

lStyle = WS_CHILD | WS_VISIBLE | BS_GROUPBOX | WS_TABSTOP;
DlgItemTemplate(p, lStyle, left, top, wItem, 4*hItem+left, ID_STATIC,
(LPSTR)"button",(LPSTR)stattxt);

//2
wItem=lstrlen(modeoff)*cxChar+10; top+=hItem;
lStyle = BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP;
DlgItemTemplate(p, lStyle, hItem, top, wItem, hItem, ID_BUTTON1,
(LPSTR)"button", (LPSTR)modeoff);

//3
wItem=lstrlen(modedat)*cxChar+10; top+=hItem;
lStyle = BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE;
DlgItemTemplate(p, lStyle, hItem, top, wItem, hItem, ID_BUTTON2,
"button", (LPSTR)modedat);

//4
wItem=lstrlen(modepsw)*cxChar+10; top+=hItem;
lStyle = BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE;
DlgItemTemplate(p, lStyle, hItem, top, wItem, hItem, ID_BUTTON3,
(LPSTR)"button", (LPSTR)modepsw);

//5
wItem=(wDlg-left-left-hItem-hItem)/3; top+=hItem+hItem/2+left;
lStyle = BS_DEFPUSHBUTTON | WS_VISIBLE | WS_CHILD | WS_TABSTOP;
DlgItemTemplate(p, lStyle, left, top, wItem, hItem, IDOK,
(LPSTR)"button",(LPSTR)"Да");

//6
lStyle = BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD | WS_TABSTOP;
DlgItemTemplate(p, lStyle, left+wItem+hItem, top, wItem, hItem, IDCANCEL,
(LPSTR)"button",(LPSTR)"Oтмена");

//7
DlgItemTemplate(p, lStyle, left+wItem+hItem+wItem+hItem, top, wItem, hItem, ID_HELP,
(LPSTR)"button",(LPSTR)"Cправка");

//Создаем модальное диалоговое окно
DialogBoxIndirect(hInstance,(LPDLGTEMPLATE)pdlgtemplate, hwnd, (DLGPROC)DlgProc);
//Освобождаем занятый под шаблон блок памяти
LocalFree(LocalHandle(pdlgtemplate));
return 0;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Functions.cpp

#include "Functions.h"

BOOL RegClass (WNDPROC Proc, LPCTSTR szName, UINT brBackground)
{ WNDCLASS wc;
wc.style = 0;
wc.lpfnWndProc = Proc;
wc.cbClsExtra = wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
wc.hbrBackground =(HBRUSH)(COLOR_WINDOW +1);
wc.lpszMenuName =(LPCTSTR)NULL;
wc.lpszClass = szName;

return (RegisterClass (&wc) !=0);
}

LPWORD lpwAlign(LPWORD lpln)
{
ULONG ul=(ULONG)lpln;
ul+=3;
ul>>=2;
ul<<=2;
return (LPWORD)ul;
}


int nCopyAnsiToWideChar(LPWORD lpWCStr, LPSTR lpAnsiln)
{
int cchAnsi=lstrlen(lpAnsiln);
return MultiByteToWideChar(GetACP(), MB_PRECOMPOSED, lpAnsiln, cchAnsi, lpWCStr, cchAnsi) + 1;
}

void DlgTemplate(PWORD& p, DWORD lStyle, int items, int x, int y, int cx, int cy, LPSTR txt)
{
*p++=LOWORD(lStyle);
*p++=HIWORD(lStyle);
*p++=0;
*p++=0;
*p++=items;
*p++=x;
*p++=y;
*p++=cx;
*p++=cy;
*p++=0;
*p++=0;

int nchar=nCopyAnsiToWideChar(p,TEXT(txt));
*p++=nchar;
p=lpwAlign((LPWORD)p);
}

void DlgItemTemplate(PWORD& p, DWORD lStyle, int x, int y, int cx, int cy, WORD id, LPSTR classname, LPSTR txt)
{
*p++=LOWORD(lStyle);
*p++=HIWORD(lStyle);
*p++=0;
*p++=0;
*p++=x;
*p++=y;
*p++=cx;
*p++=cy;
*p++=id;

int nchar=nCopyAnsiToWideChar(p,TEXT(classname));

p+=nchar;

if(lstrlen(txt)>0)
nchar=nCopyAnsiToWideChar(p, TEXT(txt));
else nchar=nCopyAnsiToWideChar(p, TEXT(""));

p+=nchar;
p+=0;
p=lpwAlign((LPWORD)p);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Functions.cpp

#include <windows.h>
#include <stdlib.h>
#include <math.h>
#include <prsht.h>
#include <commctrl.h>
#pragma comment (lib, "comctl32.lib")

extern HINSTANCE hInstance;

BOOL RegClass (WNDPROC, LPCTSTR, UINT);

LPWORD lpwAlign(LPWORD);
int nCopyAnsiToWideChar(LPWORD, LPSTR);

void DlgTemplate(PWORD &, DWORD, int, int, int, int, int, LPSTR);
void DlgItemTemplate(PWORD &, DWORD, int, int, int, int, WORD, LPSTR, LPSTR);

Обсуждение

давно
Посетитель
7438
7205
08.10.2008, 14:38
общий
это ответ
Здравствуйте, Ustin7!
В приложении исправленная программа
Исправленные места помечены комментариями, начинающимися с //***liv***


Приложение:
//exmpl.cpp

#include "Functions.h"

#define ID_STATIC 2000
#define ID_BUTTON1 2001
#define ID_BUTTON2 2002
#define ID_BUTTON3 2003
#define ID_HELP 2004

LRESULT CALLBACK WndProc(HWND,UINT, WPARAM,LPARAM);
LRESULT CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM);
int CreateDlg (HWND);
HINSTANCE hInstance;
char szClass[] = "AppClass";

//***liv*** Буковка I в имени hInstance должна быть заглавной
INT WINAPI WinMain (HINSTANCE hInstance, HINSTANCE, PSTR, INT nCmdShow)
{ MSG msg; HWND hwnd; ::hInstance=hInstance;

if (!RegClass(WndProc,szClass,COLOR_DESKTOP)) return FALSE;

int wScreen=GetSystemMetrics(SM_CXSCREEN);
int hScreen=GetSystemMetrics(SM_CYSCREEN);

hwnd = CreateWindow(szClass, "Создание диалоговой панели", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
0,0, wScreen/2, hScreen/2, 0,0, hInstance, NULL);

if (!hwnd) return FALSE;
while(GetMessage(&msg, NULL,0,0))
{ TranslateMessage(&msg); DispatchMessage(&msg);}
return (int)msg.wParam;
}

LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{ switch (msg)
{ case WM_CREATE:
{ CreateDlg(hwnd); return 0;}
case WM_DESTROY:
{ PostQuitMessage(0); return 0;}
} return DefWindowProc(hwnd, msg, wParam, lParam);
}

LRESULT CALLBACK DlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{ switch (msg)
{ case WM_COMMAND:
{ switch(LOWORD(wParam))
{ case IDOK:
case IDCANCEL:
{ EndDialog(hwnd, 0); //***liv*** Модальный диалог надо завершать!
return TRUE; }
} return FALSE;
}
} return FALSE;
}

int CreateDlg( HWND hwnd )
{ char const caption[ ]=" Изменение режима работы приложения";
char const stattxt[ ]="Сейчас следует:";
char const modeoff[ ]="завершить работу приложения";
char const modedat[ ]="перезагрузить данные";
char const modepsw[ ]="сменить имя пользователя";

//Выделяем блок памяти для записи шаблона
WORD *p, *pdlgtemplate;
pdlgtemplate=p=(PWORD)LocalAlloc(LPTR, 2000);
//Определяем среднюю ширину cxChar и высоту cyChar шрифта
int cxChar, cyChar;
{ TEXTMETRIC tm;
HDC hdc=GetDC(hwnd);
GetTextMetrics(hdc,&tm);
ReleaseDC(hwnd, hdc);
cxChar=tm.tmAveCharWidth+1;
cyChar=tm.tmHeight+tm.tmExternalLeading;
}

//Определяем диалоговые единицы ширины и высоты
DWORD dlgunit =GetDialogBaseUnits();
int dlgwunit=LOWORD(dlgunit), dlghunit=HIWORD(dlgunit);
//Пересчитываем габариты символов шрифта
cxChar=cxChar*4/dlgwunit;cyChar=cyChar*8/dlghunit;
int wDlg, hDlg, wItem, hItem, left, top;

//Записываем в шаблон данные панели
DWORD lStyle = DS_CENTER | DS_MODALFRAME | WS_POPUPWINDOW | WS_CAPTION;
wDlg=lstrlen(caption)*cxChar;
hDlg=cyChar*10;
DlgTemplate(p, lStyle, 7, 0, 0, wDlg, hDlg, (LPSTR)caption);

//Далее добавляем записи органов управления
//1
hItem=cyChar; top=left=hItem/2; hItem+=left; wItem=(wDlg-left-left);

lStyle = WS_CHILD | WS_VISIBLE | BS_GROUPBOX | WS_TABSTOP;

//***liv*** Класс органа управления должен задаваться числом, а не адресом строки!
//***liv*** Описаны в h-ке
DlgItemTemplate(p, lStyle, left, top, wItem, 4*hItem+left, ID_STATIC,
S_BUTTON,(LPSTR)stattxt);


//2
wItem=lstrlen(modeoff)*cxChar+10; top+=hItem;
lStyle = BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP;
DlgItemTemplate(p, lStyle, hItem, top, wItem, hItem, ID_BUTTON1,
S_BUTTON, (LPSTR)modeoff);//***liv*** аналогично

//3
wItem=lstrlen(modedat)*cxChar+10; top+=hItem;
lStyle = BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE;
DlgItemTemplate(p, lStyle, hItem, top, wItem, hItem, ID_BUTTON2,
S_BUTTON, (LPSTR)modedat);//***liv*** аналогично

//4
wItem=lstrlen(modepsw)*cxChar+10; top+=hItem;
lStyle = BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE;
DlgItemTemplate(p, lStyle, hItem, top, wItem, hItem, ID_BUTTON3,
S_BUTTON, (LPSTR)modepsw);//***liv*** аналогично

//5
wItem=(wDlg-left-left-hItem-hItem)/3; top+=hItem+hItem/2+left;
lStyle = BS_DEFPUSHBUTTON | WS_VISIBLE | WS_CHILD | WS_TABSTOP;
DlgItemTemplate(p, lStyle, left, top, wItem, hItem, IDOK,
S_BUTTON,(LPSTR)"Да");//***liv*** аналогично

//6
lStyle = BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD | WS_TABSTOP;
DlgItemTemplate(p, lStyle, left+wItem+hItem, top, wItem, hItem, IDCANCEL,
S_BUTTON,(LPSTR)"Oтмена");//***liv*** аналогично

//7
DlgItemTemplate(p, lStyle, left+wItem+hItem+wItem+hItem, top, wItem, hItem, ID_HELP,
S_BUTTON,(LPSTR)"Cправка");//***liv*** аналогично

//Создаем модальное диалоговое окно
DialogBoxIndirect(hInstance,(LPDLGTEMPLATE)pdlgtemplate, hwnd, (DLGPROC)DlgProc);
//Освобождаем занятый под шаблон блок памяти
LocalFree(LocalHandle(pdlgtemplate));
return 0;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Functions.cpp

#include "Functions.h"

BOOL RegClass (WNDPROC Proc, LPCTSTR szName, UINT brBackground)
{ WNDCLASS wc;
wc.style = 0;
wc.lpfnWndProc = Proc;
wc.cbClsExtra = wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
wc.hbrBackground =(HBRUSH)(COLOR_WINDOW +1);
wc.lpszMenuName =(LPCTSTR)NULL;
wc.lpszClassName = szName;//***liv*** ошибочка в имени поля

return (RegisterClass (&wc) !=0);
}

LPWORD lpwAlign(LPWORD lpln)
{
ULONG ul=(ULONG)lpln;
ul+=3;
ul>>=2;
ul<<=2;
return (LPWORD)ul;
}


int nCopyAnsiToWideChar(LPWORD lpWCStr, LPSTR lpAnsiln)
{
int cchAnsi=lstrlen(lpAnsiln);
return MultiByteToWideChar(GetACP(), MB_PRECOMPOSED, lpAnsiln, cchAnsi, lpWCStr, cchAnsi) + 1;
}

void DlgTemplate(PWORD& p, DWORD lStyle, int items, int x, int y, int cx, int cy, LPSTR txt)
{
*p++=LOWORD(lStyle);
*p++=HIWORD(lStyle);
*p++=0;
*p++=0;
*p++=items;
*p++=x;
*p++=y;
*p++=cx;
*p++=cy;
*p++=0;
*p++=0;

p+=nCopyAnsiToWideChar(p,TEXT(txt)); //***liv*** Сократил немного (не ошибка)
}

//***liv*** Раз параметр "класс" не строка, а слово, то небольшое изменение в параметре
void DlgItemTemplate(PWORD& p, DWORD lStyle, int x, int y, int cx, int cy, WORD id, WORD wClass, LPSTR txt)
{
p=lpwAlign((LPWORD)p); //***liv*** Выравнивание лучше перемести в начало органа управления
*p++=LOWORD(lStyle);
*p++=HIWORD(lStyle);
*p++=0;
*p++=0;
*p++=x;
*p++=y;
*p++=cx;
*p++=cy;
*p++=id;
*p++=0xffff; //***liv*** Пропущеное поле!
*p++=wClass; //***liv*** Класс

p+=nCopyAnsiToWideChar(p, TEXT(txt)); //***liv*** Сократил немного (не ошибка)
//***liv*** Проверка на длину лишняя - получится автоматически и так
*p++=0; //***liv*** Пропущенное поле параметра
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Functions.h //***liv*** не CPP :)

#include <windows.h>
#include <stdlib.h>
#include <math.h>
#include <prsht.h>
#include <commctrl.h>
#pragma comment (lib, "comctl32.lib")

//***liv*** Классы стандартных органов управления
#define S_BUTTON 0x0080
#define S_EDIT 0x0081
#define S_STATIC 0x0082
#define S_LISTBOX 0x0083
#define S_SCROLLBAR 0x0084
#define S_COMBOBOX 0x0085

extern HINSTANCE hInstance;

BOOL RegClass (WNDPROC, LPCTSTR, UINT);

LPWORD lpwAlign(LPWORD);
int nCopyAnsiToWideChar(LPWORD, LPSTR);

void DlgTemplate(PWORD &, DWORD, int, int, int, int, int, LPSTR);
//***liv*** Тип параметра - не LPTR, а WORD
void DlgItemTemplate(PWORD &, DWORD, int, int, int, int, WORD, WORD, LPSTR);

Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Форма ответа