47816 (597361), страница 12

Файл №597361 47816 (Ознакомление с приложениями Windows) 12 страница47816 (597361) страница 122016-07-30СтудИзба
Просмтор этого файла доступен только зарегистрированным пользователям. Но у нас супер быстрая регистрация: достаточно только электронной почты!

Текст из файла (страница 12)

virtual LRESULT dispatch( UINT, WPARAM, LPARAM );
virtual BOOL OnCreate( LPCREATESTRUCT );
virtual void OnDestroy( void ) = 0;
virtual void OnPaint( HDC hdc ) = 0;

public:
Win0( void );
~Win0( void );
BOOL create( char* );
void destroy( void );
void update( void ) { UpdateWindow( hwnd ); }
void show( int nCmdShow ) { ShowWindow( hwnd, nCmdShow ); }

friend LONG WINAPI _export Win0proc( HWND, UINT, WPARAM, LPARAM );
};

class App0 {
public:
static HINSTANCE hInstance;
static HINSTANCE hPrevInstance;
static LPSTR lpszCmdLine;
static int nCmdShow;

App0( HINSTANCE, HINSTANCE, LPSTR, int );
~App0( void );

BOOL init( void );
int run( void );
void release( void );
};

Файл 1c_cls.cpp

#include "1c.h"
HINSTANCE App0::hInstance;
HINSTANCE App0::hPrevInstance;
LPSTR App0::lpszCmdLine;
int App0::nCmdShow;

static char szWndClass[]= "test window class";
static Win0* on_create_ptr;

Win0::Win0( void )
{
hwnd = NULL;
}

Win0::~Win0( void )
{
destroy();
}

LRESULT WINAPI _export Win0proc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
Win0* pwin;

pwin = (Win0*)GetWindowLong( hWnd, 0 );
if ( !pwin ) {
SetWindowLong( hWnd, 0, (LONG)(Win0 FAR*)(pwin = on_create_ptr) );
pwin->hwnd = hWnd;
}
return pwin->dispatch( uMsg, wParam, lParam );
}

LRESULT Win0::dispatch( UINT uMsg, WPARAM wParam, LPARAM lParam )
{
PAINTSTRUCT ps;

switch ( uMsg ) {
case WM_CREATE: return OnCreate( (LPCREATESTRUCT)lParam ) ? 0L : -1L;
case WM_PAINT: OnPaint( BeginPaint( hwnd, &ps ) ); EndPaint( hwnd, &ps ); return 0L;
case WM_DESTROY: OnDestroy(); return 0L;
default: break;
}
return DefWindowProc( hwnd, uMsg, wParam, lParam );
}

void Win0::destroy( void )
{
if ( IsWindow( hwnd ) ) DestroyWindow( hwnd );
hwnd = (HWND)NULL;
}

BOOL Win0::create( char* title )
{
on_create_ptr = this;
CreateWindow(
szWndClass, // class name
title, // window name
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT,CW_USEDEFAULT, // window position
CW_USEDEFAULT,CW_USEDEFAULT, // window size
NULL, // parent window
NULL, // menu
hInstance, // current instance
NULL // user-defined parameters
);
on_create_ptr = (Win0*)NULL;
return IsWindow( hwnd );
}

BOOL Win0::OnCreate( LPCREATESTRUCT lpCreateStruct )
{
UNUSED_ARG( lpCreateStruct );

return TRUE;
}

App0::App0( HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpszCmd, int nShow )
{
hInstance = hInst;
hPrevInstance = hPrev;
lpszCmdLine = lpszCmd;
nCmdShow = nShow;
}

App0::~App0( void )
{
}

BOOL App0::init( void )
{
static BOOL done;
WNDCLASS wc;

if ( !done && !hPrevInstance ) {
wc.style = 0;
wc.lpfnWndProc = Win0proc;
wc.cbClsExtra = 0;
wc.cbWndExtra = sizeof(LONG);
wc.hInstance = hInstance;
wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = szWndClass;
done = RegisterClass( &wc ) ? TRUE : FALSE;
}

return done;
}

int App0::run( void )
{
MSG msg;

while ( GetMessage( &msg, NULL, NULL, NULL ) ) {
TranslateMessage( &msg );
DispatchMessage( &msg );
}

return msg.wParam;
}

void App0::release( void )
{
}

Файл 1c_main.cpp

#include "1c.h"

class MainWindow : public Win0 {
protected:
virtual void OnDestroy( void );
virtual void OnPaint( HDC hdc );

public:
MainWindow( void );
~MainWindow( void );
};

class MyApp : public App0 {
protected:
MainWindow wnd;

public:
MyApp( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpszCmdLine, int nCmdShow );
~MyApp( void );
BOOL init( void );
};

MainWindow::MainWindow( void ) : Win0()
{
}

MainWindow::~MainWindow( void )
{
}

void MainWindow::OnDestroy( void )
{
PostQuitMessage( 0 );
}

void MainWindow::OnPaint( HDC hdc )
{
TextOut( hdc, 0, 0, "Hello, world!", 13 );
}

MyApp::MyApp( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpszCmdLine, int nCmdShow )
: App0( hInst, hPrevInst, lpszCmdLine, nCmdShow )
{
}

MyApp::~MyApp( void )
{
}

BOOL MyApp::init( void )
{
if ( App0::init() ) {
if ( wnd.create( "window header" ) ) {
wnd.show( nCmdShow );
wnd.update();
return TRUE;
}
}
return FALSE;
}

int PASCAL WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpszCmdLine, int nCmdShow )
{
int a;
MyApp app( hInst, hPrevInst, lpszCmdLine, nCmdShow );

if ( app.init() ) {
a = app.run();
} else a = -1;
app.release();

return a;
}

Обзор примера 1C

Пример содержит два базовых класса: App0 — описывает приложение и Win0 — описывает окно.

Класс App0 содержит 4 члена–данных: hInstance, hPrevInstance, lpszCmdLine и nCmdShow, которые являются аргументами функции WinMain. Интереснее разобраться с методами, описанными в этом классе. Конструктор просто инициализирует члены–данные для использования в последующем; деструктор вообще ничего не делает. Пара методов init и release предназначена для переопределения в дальнейшем — метод init должен выполнять специфичную инициализацию приложения, а метод release — операции при завершении. В классе App0 метод init осуществляет регистрацию оконной процедуры (в терминологии Windows — класса), которая будет применяться данным приложением. Метод run выполняет цикл обработки сообщений.

Класс Win0 содержит только один член–данные hwnd — хендл окна. Конструктор устанавливает значение хендла окна равным NULL (окно не создано), деструктор проверяет существование окна и, при необходимости, закрывает его. Методы create, destroy, update и show соответствуют функциям API: CreateWindow, DestroyWindow, UpdateWindow и ShowWindow. Методы OnCreate, OnDestroy и OnPaint соответствуют обработчикам сообщений WM_CREATE, WM_DESTROY и WM_PAINT. Метод dispatch является диспетчером, который распределяет пришедшие сообщения по соответствующим методам–обработчикам.

В том–же классе декларирована дружественная функция Win0proc, которая является собственно оконной процедурой.

Коротко рассмотрим, как создается окно в этом примере. Для создания окна необходимо вызвать метод create, который, в свою очередь, вызовет функцию CreateWindow из Windows. Во время создания окна его оконная процедура начнет получать сообщения (в том числе и WM_CREATE, хотя, на самом деле, это будет не первое полученное сообщение). Эта процедура для нормальной работы требует, что бы в структуре описания окна в Windows был сохранен указатель на объект, описывающий окно в приложении. Но в момент первого вызова обработчика сообщений этот указатель там не находиться — все происходит еще только во время работы функции CreateWindow. Соответственно мы используем некоторую статическую переменную (on_create_ptr), которая перед вызовом CreateWindow инициализируется указателем на объект. Тогда обработчик сообщений может быть построен по следующей схеме:

LONG WINAPI _export Win0proc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
Win0* pwin;

pwin = (Win0*)GetWindowLong( hWnd, 0 ); // получаем указатель на объект
if ( !pwin ) { // указатель равен NULL — объект только создается
// инициализируем объект и указатель на него
SetWindowLong( hWnd, 0, (LONG)(Win0 FAR*)(pwin = on_create_ptr) );
pwin->hwnd = hWnd;
}
// вызываем виртуальную функцию-диспетчер
return pwin->dispatch( uMsg, wParam, lParam );
}

При нормальной работе первый вызов функции GetWindowLong вернет указатель на объект, так что следующий шаг — вызов функции–диспетчера. Таким образом дополнительные затраты ресурсов на реализацию ООП таким способом оказываются минимальными. В случае разработки классов–наследников от Win0 надо разработать собственную функцию–диспетчер, которая будет вместо процедуры DefWindowProc вызывать диспетчер класса–предка.

В примерах, сопровождающих компиляторы инициализация объекта и указателя на объект в структуре описания окна выполняется при обработке WM_CREATE. Это решение не является наилучшим — сообщение WM_CREATE далеко не самое первое из обрабатываемых сообщений, хотя, предусмотрев обработку сообщений с помощью DefWindowProc при неопределенном указателе, можно осуществлять инициализацию и при обработке WM_CREATE.

Конечно, этот пример крайне упрощен. Вообще, даже в простейших случаях, надо проводить контроль корректности данных, убедиться, что окно еще не существует перед вызовом CreateWindow в методе create, проверить on_create_ptr перед использованием и многое другое. Данный пример специально лишен всего этого, что бы в максимально открытом виде продемонстрировать простейшую схему.

Основы работы с памятью

Дополнительно надо разобраться с несколькими терминами Windows API, которые постоянно применяются, но очень плохо описаны в документации. Речь идет о хендлах копии приложения (HINSTANCE), модуля (HMODULE) и задачи (HTASK). Все эти хендлы используются разными функциями, причем разница между ними никак не поясняется. Помимо этого в Win32 API появилась пара дополнительных хендлов — хендл процесса и хендл потока, а также идентификаторы процесса и потока. При этом осталась все прежние понятия, часто изменившие смысл, но в документации по–прежнему не описанные (или описанные плохо).

Хендл задачи (HTASK), хендлы и идентификаторы процесса и потока 

В Windows 3.x под задачей подразумевается конкретный запущенный процесс, для которого определены командная строка, текущая выполняемая инструкция, указатель на стек, переменные окружения, PDB (эквивалент префикса задачи (PSP) в среде DOS) и пр. Хендл задачи можно получить с помощью функции

HTASK GetCurrentTask( void );

В Win32 хендл задачи не применяется, а вместо него надо пользоваться хендлами и/или идентификаторами процесса и потока. Их можно получить с помощью функций:

HANDLE GetCurrentProcess( void );
HANDLE OpenProcess( fdwAccess, fInherit, dwIDProccess );
DWORD GetCurrentProcessId( void );
HANDLE GetCurrentThread( void );
DWORD GetCurrentThreadId( void );

Функции GetCurrentProcess и GetCurrentThread возвращают так называемый псевдодескриптор19 процесса (потока). Псевдодескриптор — это некоторая величина, рассматриваемая в качестве дескриптора текущего процесса (потока). То есть эта величина, применяемая в контексте другого процесса (потока), будет описывать его, а не данный поток. Для получения “настоящего” хендла из псевдодескриптора надо воспользоваться функцией:

BOOL DuplicateHandle(
hSourceProcess, hSourceHandle, hTargetProcess, lphTargetHandle,
fdwAccess, fInherit, fdwOptions
);

Хендл копии приложения (HINSTANCE) 

В Windows 3.x этот хендл указывает на сегмент данных приложения, который содержит стек и локальную кучу. Для каждого запущенного приложения создается свой собственный сегмент данных, что позволяет однозначно определить конкретную копию приложения по его сегменту данных или организовать обмен данными между двумя копиями одного приложения. Так функция GetInstanceData позволяет скопировать данные, принадлежащие сегменту данных другой копии, в то–же самое место текущей копии.

int GetInstanceData( hInstance, pByte, cbData );

В функцию WinMain передается как хендл текущей копии приложения, так и хендл предыдущей копии, что позволяет организовать взаимодействие двух копий между собой, предотвратить запуск других копий, если это может привести к ошибке, или для выполнения действий, необходимых только в первой копии приложения.

В Win32 для каждого запущенного приложения (т.е. процесса) выделяется виртуальное адресное пространство в 4Г в едином сегменте. Поэтому данный хендл соответствует не сегменту данных (который описывает весь 4Г сегмент), а адресу в виртуальном пространстве, с которого был загружен данный модуль. В адресном пространстве одного процесса никаких других приложений не существует, поэтому этот хендл не может применяться для обнаружения других копий приложения и тем более для обмена данными между разными копиями приложений. В приложениях Win32 hPrevInstance всегда равен NULL, а хендл текущей копии приложения в большинстве случаев совпадает. При необходимости обнаружения других копий приложения надо использовать какие–либо иные методы, например функцию:

HWND FindWindow( lpszClassName, lpszWindowTitle );

Хендл окна в Win32 является уникальным и может идентифицировать конкретное окно в любом приложении.

Для обмена данными между приложениями (процессами) приходится передавать данные из адресного пространства одного процесса в адресное пространство другого. Для выполнения этих операций предусмотрено сообщение WM_COPYDATA. Когда Вы посылаете это сообщение окну, созданному другим процессом, указанные Вами данные копируются в адресное пространство другого процесса и могут быть прочитаны оконной процедурой окна–получателя. Этот механизм может применяться и для обмена данными между 16ти и 32х битовыми приложениями, однако для этого необходимо определить номер сообщения WM_COPYDATA и специальную структуру COPYDATASTRUCT для 16ти битовой платформы — так как файл windows.h не содержит этих определений:

Характеристики

Тип файла
Документ
Размер
2,36 Mb
Тип материала
Учебное заведение
Неизвестно

Список файлов книги

Свежие статьи
Популярно сейчас
Зачем заказывать выполнение своего задания, если оно уже было выполнено много много раз? Его можно просто купить или даже скачать бесплатно на СтудИзбе. Найдите нужный учебный материал у нас!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает - и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе "Студизба"
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Популярные преподаватели
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
7029
Авторов
на СтудИзбе
260
Средний доход
с одного платного файла
Обучение Подробнее