Лекція №3 lparam lparam

При изменении размеров родительского окна в дочернее поступает сообщение WM_PAINT, по которому в переменной R формируются размеры родительского окна и при помощи функции MoveWindow(hWndC, R.left, R.bottom-iHeight, R.right, R.bottom-iHeight, 1) дочернему окну выделяется нижняя часть родительского окна.

BOOL PostMessage(

Функция PostMessage помещает сообщение в очередь сообщений, связанную с потоком, который создал заданное окно и возвращает значение без ожидания потока, который обрабатывает сообщение.

HWND hWnd,

UINT Msg,

WPARAM wParam,

LPARAM lParam

);

Если вводимый символ не является символьным кодом виртуальной клавиши Enter и количество введённых символов меньше 21, то оконная функция ChldWndProc дочернего окна записывает символы в буфер Password при помощи указателя Str.

После этого выполняется функция InvalidateRect() для порождения сообщения WM_PAINT, которое придет в дочернее окно и обновит отображаемую в нем строку.

10) Основное окно получает сообщение WM_CОMMAND и по значению идентификатора в LОWОRD(wParam) определяет, что оно пришло не от меню, а от дочернего окна, и вызывает функцию обработки пароля OnChild(), передавая ей в качестве второго параметра код извещения. Соответствующий фрагмент кода приведен в листинге:

case WM_COMMAND:

wmId = LOWORD(wParam);

wmEvent = HIWORD(wParam);

// Parse the menu selections:

switch (wmId)

{

case IDM_EXIT:

DestroyWindow(hWnd);

break;

case NumC:

OnChld(hWnd,message,HIWORD(wParam),lParam); // Обработка пароля

break;

default:

return DefWindowProc(hWnd, message, wParam, lParam);

}

break;

11) Код функции обработки пароля приведён в листинге:

void OnChld(HWND hWnd,UINT message,int Length,LPARAM lParam)

{

if(strcmp(PassWord,TruePassWord)||Length)

MessageBox(hWnd, "Надо вспомнить правильный пароль","Скажи \"Пароль\"",0);

else MessageBox(hWnd, "Пароль принят","",0);

}

На основе сравнения строк и проверки длины введенного пароля функция принимает решение о приеме пароля и отображает соответствующее сообщение при помощи функции MessageBox().


15) Создание дочернего окна с дескриптором Chld оформлено отдельной функцией.

BOOL CreateChild(HWND hWnd)

{static WNDCLASS wc;

if(Chld) //Стандартный для WINDOWS прием - чтобы не думать, о

// действиях при попытке нового ввода до завершения предыдущего

DestroyWindow(Chld);

UnregisterClass("ReadStr",GetModuleHandle(NULL));

// Раз было окно, значит был и класс

// Если класс не убрать, получится ошибка при новой регистрации

}

wc.hInstance = GetModuleHandle(NULL);

wc.hbrBackground =(HBRUSH)(COLOR_BTNFACE+1);

wc.lpfnWndProc = ChldWndProc;

wc.lpszClassName = "ReadStr";

if (!RegisterClass(&wc)) return 0;

Chld=0;

Chld=CreateWindowEx (WS_EX_CLIENTEDGE, "ReadStr",

"Значения ", WS_CHILD|WS_VISIBLE, 30,30,60,60,

hWnd, HMENU(NumC),GetModuleHandle(NULL), NULL);

SetFocus(Chld);

return (int)Chld;

}

После первого щелчка в рабочей области родительского окна левой кнопкой мыши и до завершения ввода пароля дескриптор Chld не будет равен нулю. При повторном вызове функции CreateChild (то есть при повторной активизации левой кнопки мыши в клиентской области родительского окна) уничтожается дочернее окно и отменяется регистрация класса.


Пример №1: Создания главного окна с дочерним окном для ввода пароля.

#include "stdafx.h"

#include "resource.h"

#define MAX_LOADSTRING 100

// Global Variables:

HINSTANCE hInst; // current instance

TCHAR szTitle[MAX_LOADSTRING]; // The title bar text

TCHAR szWindowClass[MAX_LOADSTRING]; // The title bar text

static TCHAR PassWord[7]; //введенный пользователем пароль

static TCHAR TruePassWord[]=_T("Password"); //Правильный пароль

static HWND Chld;

static WORD i;

static TCHAR *Str=NULL;

static int sMax;

int wHeight=30; //Высота дочернего окна

static TCHAR Sym[80];

// Foward declarations of functions included in this code module:

ATOM MyRegisterClass(HINSTANCE hInstance);

BOOL InitInstance(HINSTANCE, int);

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

BOOL CreateChild(HWND hWnd);

void InitStr(HWND hWnd,TCHAR *s,int Max,TCHAR Sy);

void OnChld(HWND hWnd,UINT message,int Length,LPARAM lParam);

LRESULT APIENTRY ChldWndProc (HWND UkOkn,UINT message, WPARAM wParam,LPARAM lParam);

int APIENTRY WinMain(HINSTANCE hInstance,

HINSTANCE hPrevInstance,

LPSTR lpCmdLine,

int nCmdShow)

{

UNREFERENCED_PARAMETER(hPrevInstance);

UNREFERENCED_PARAMETER(lpCmdLine);

// TODO: Place code here.

MSG msg;

HACCEL hAccelTable;

// Initialize global strings

LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);

LoadString(hInstance, IDC_CHILD_WINDOW, szWindowClass, MAX_LOADSTRING);

MyRegisterClass(hInstance);

// Perform application initialization:

if (!InitInstance (hInstance, nCmdShow))

{

return FALSE;

}

hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_CHILD_WINDOW);

// Main message loop:

while (GetMessage(&msg, NULL, 0, 0))

{

if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

}

return msg.wParam;

}

LRESULT APIENTRY ChldWndProc(HWND hWndC,UINT message,WPARAM wParam,LPARAM lParam)

{ RECT R;

switch (message)

{

case WM_CHAR:

if (LOWORD(wParam)==VK_RETURN || i>=20)

{

Str[i]=0;

PostMessage(GetParent(hWndC),WM_COMMAND,MAKELONG(NumC, i-sMax),0);

i=0;

DestroyWindow(hWndC);

UnregisterClass(_T("ReadStr"),GetModuleHandle(NULL));

}

else

{

if(++i<=sMax)

Str[i-1]=(char)LOWORD(wParam);

InvalidateRect(hWndC,NULL,1);

}

break;

case WM_PAINT:

{PAINTSTRUCT ps;

GetClientRect(GetParent(hWndC),&R);

MoveWindow(hWndC,R.left,R.top,R.right,R.top+wHeight,1);

BeginPaint(hWndC,&ps);

SetBkMode(ps.hdc, TRANSPARENT);

TextOut(ps.hdc,0,0,_T("Введите пароль: "),14);

TextOut(ps.hdc,17*8,0,Sym,i);

EndPaint(hWndC,&ps);

}

return 0;

default:

return DefWindowProc(hWndC,message,wParam,lParam);

}

return 0;

}

ATOM MyRegisterClass(HINSTANCE hInstance)

{

WNDCLASSEX wcex;

wcex.cbSize = sizeof(WNDCLASSEX);

wcex.style = CS_HREDRAW | CS_VREDRAW;

wcex.lpfnWndProc = (WNDPROC)WndProc;

wcex.cbClsExtra = 0;

wcex.cbWndExtra = 0;

wcex.hInstance = hInstance;

wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_CHILD_WINDOW);

wcex.hCursor = LoadCursor(NULL, IDC_ARROW);

wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);

wcex.lpszMenuName = (LPCWSTR)IDC_CHILD_WINDOW;

wcex.lpszClassName = szWindowClass;

wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);

return RegisterClassEx(&wcex);

}

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)

{

HWND hWnd;

hInst = hInstance; // Store instance handle in our global variable

hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,

400, 300, 500, 500, NULL, NULL, hInstance, NULL);

if (!hWnd)

{

return FALSE;

}

ShowWindow(hWnd, nCmdShow);

UpdateWindow(hWnd);

return TRUE;

}

void OnChld(HWND hWnd,UINT message,int Length,LPARAM lParam)

{

if(_tcscmp(PassWord,TruePassWord)||Length)

MessageBox(hWnd, _T("Надо вспомнить правильный пароль"),_T("Скажи \"Пароль\""),0);

else MessageBox(hWnd, _T(" Пароль принят"),_T(""),0);

}

BOOL CreateChild(HWND hWnd)

{static WNDCLASS wc;

if(Chld) //Стандартный для WINDOWS прием - чтобы не думать, о действих при

{ //попытке нового ввода до завершения

DestroyWindow(Chld); // предыдущего.

UnregisterClass(_T("ReadStr"),GetModuleHandle(NULL));

// Раз было окно, значит,был и класс

// Если класс не убрать, получится ошибка при новой регистрации

}

wc.hInstance = GetModuleHandle(NULL);

wc.hbrBackground =(HBRUSH)(COLOR_BTNFACE+1);

wc.lpfnWndProc = ChldWndProc;

wc.lpszClassName = _T("ReadStr");

if (!RegisterClass(&wc)) return 0;

Chld=0;

Chld=CreateWindowEx

(WS_EX_CLIENTEDGE, _T("ReadStr"), _T(" Значения "),

WS_CHILD|WS_VISIBLE,

30,30,60,60,

hWnd, HMENU(NumC),GetModuleHandle(NULL), NULL);

SetFocus(Chld);

return (int)Chld;

}

void InitStr(HWND hWnd,TCHAR *s,int Max,TCHAR Sy)

{

Str=s;

sMax=Max;

int j;

for (j=0; j<21;j++)Sym[j]=Sy;

Sym[j]=0;

CreateChild(hWnd);

}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

int wmId, wmEvent;

TCHAR szHello[MAX_LOADSTRING];

LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);

switch (message)

{

case WM_COMMAND:

wmId = LOWORD(wParam);

wmEvent = HIWORD(wParam);

// Parse the menu selections:

switch (wmId)

{

case IDM_EXIT:

DestroyWindow(hWnd);

break;

case NumC:

OnChld(hWnd,message,HIWORD(wParam),lParam); // Обработка пароля

break;

default:

return DefWindowProc(hWnd, message, wParam, lParam);

}

break;

case WM_LBUTTONDOWN:

InitStr(hWnd,PassWord,8,_T('*'));

break;

case WM_DESTROY:

PostQuitMessage(0);

break;

default:

return DefWindowProc(hWnd, message, wParam, lParam);

}

return 0;

}


Пример 2: Окно приложения стиля временного окна с кнопкой минимизации и с фоном цвета рабочего стола Windows занимает весь экран. При попытке запустить второй экземпляр приложения на передний план перемещается окно первого экземпляра и завершается работа.

Шаг 1)

Для поиска приложения используется функция FindWindow:

HWND hwnd= FindWindow(szMainClass,szTitle);

Данная функция возвращает дескриптор окна класса szMainClass с заголовком szTitle. Если такого окна нет, то это первый экземпляр приложения и дескриптору hwnd присваивается NULL. Иначе возвращается дескриптор найденного окна.

Если работает экземпляр другого приложения с окном класса с таким же именем szMainClass и заголовком szTitle, то данная функция вернёт дескриптор окна другого приложения иначе переходим к шагу 5.

Шаг 2)

Если «предыдущий экземпляр приложения» обнаружен, то выводим сообщение:

MessageBox(hwnd,”Можно запускать только одну копию приложения!!!\n\n”

“Перемещаю на передний план первый экземпляр”,

szTitle,MB_OK);

Шаг 3)

До перемещения окна на передний план необходимо проверить состояние этого окна и, если оно свёрнуто, то восстанавливаем его предыдущее состояние:

If(IsIconic(hwnd)) ShowWindow(hwnd,SW_RESTORE);

SW_RESTORE - активизирует и отображает окно. Если окно минимизировано или развернуто, Windows восстанавливает его в первоначальном размере и позиции (то же самое, что и SW_SHOWNORMAL).


Шаг 4)

Перемещаем окно первого экземпляра на передний план:

SetForegroundWindow(hwnd);

Затем второй экземпляр приложения завершает работу.

Шаг 5)

В случае, если предыдущий экземпляр приложения не найден, то регистрируем класс окна:

if (!RegClass(WndProc,szMainClass,COLOR_DESKTOP))

return FALSE;

Шаг 6)

Для создания максимально распахнутого окна приложения необходимо определить ширину и высоту экрана в пикселях:

int w=GetSystemMetrics(SM_CXSCREEN);

int h=GetSystemMetrics(SM_CYSCREEN);

Шаг 7)

Создаём окно:

Hwnd=CreateWindow(szMainClass,szTitle,WS_POPUPWINDOW|WS_CAPTION|WS_MINIMIZEBOX|WS_VISIBLE,0,0,w,h,0,0,hInstance,NULL);

Стиль WS_POPUPWINDOW|WS_CAPTION|WS_MINIMIZEBOX|WS_VISIBLE указывает на временное окно с кнопкой минимизации и заголовком.

Шаг 8)

Далее создаём цикл обработки сообщений приложения:

while (GetMessage(&msg,0,0,0)) DispatchMessage(&msg);

Так как приложение не предусматривает обработки сообщений от клавиатуры, то в цикле отсутствует вызов функции трансляции клавиатурных сообщений.


Шаг 9)

Создаём оконную процедуру:

LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)

{switch(msg)

{

case WM_DESTROY:

{PostQuitMessage(0); return 0;}

}

return DefWindowProc(hwnd,msg,wParam,lParam);

}


______________________________________________________________

Листинг 1:

#include <windows.h>

#include<tchar.h> // for UNICODE charset

bool RegClass(WNDPROC,LPCTSTR,UINT);

LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);

HINSTANCE hInstance;

TCHAR szMainClass[]=_T("MainClass");

TCHAR szTitle[]=_T("Пример 1.1");

int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrevInst,

LPSTR lpszCmdLine, int nCmdShow)

{

MSG msg;

hInstance=hInst;

HWND hwnd=FindWindow(szMainClass,szTitle);

if (hwnd)

{

MessageBox(hwnd,_T("Можно запускать только один экземпляр приложения!\n")

_T("Перемещаю на передний план первый экземпляр"),

szTitle,MB_OK|MB_ICONSTOP);

if (IsIconic(hwnd))

ShowWindow(hwnd,SW_RESTORE);

SetForegroundWindow(hwnd);

return 0;

}

if (!RegClass(WndProc,szMainClass,COLOR_DESKTOP))

return FALSE;

int w=GetSystemMetrics(SM_CXSCREEN)-1;

int h=GetSystemMetrics(SM_CYSCREEN)-1;

hwnd=CreateWindow(szMainClass,szTitle,WS_POPUPWINDOW|WS_CAPTION|

WS_MINIMIZEBOX|WS_VISIBLE,

0,0,w,h,0,0,hInstance,NULL);

if (!hwnd) return FALSE;

while (GetMessage(&msg,0,0,0))

DispatchMessage(&msg);

return msg.wParam;

}

bool RegClass(WNDPROC Proc,LPCTSTR szName,UINT brBackground)

{

WNDCLASS wc;

wc.style=wc.cbClsExtra=wc.cbWndExtra=0;

wc.lpfnWndProc=Proc;

wc.hInstance=hInstance;

wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);

wc.hCursor=LoadCursor(NULL,IDC_ARROW);

wc.hbrBackground=(HBRUSH)(brBackground+1);

wc.lpszMenuName=(LPCTSTR)NULL;

wc.lpszClassName=szName;

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

}

LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)

{switch(msg)

{

case WM_DESTROY:

{PostQuitMessage(0); return 0;}

}

return DefWindowProc(hwnd,msg,wParam,lParam);

}

Самостоятельно на практике: Приведенный код перевести на ассемблер.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: