1. Въведение в Windows



страница2/4
Дата21.07.2017
Размер0.77 Mb.
#26214
1   2   3   4

12. Дъщерни контроли

Прозорец, к. има специфика в обработването, предопределена от типа и е дъщерен към по общ. Най-често предава msg към родителя си. Най-честото съобщ. е WM_COMMAND, а най простият контрол е BUTTON.

определяне на родител:

hwndParent = GetParent(hwndChild);

съобщения към родител: SendMessage(hwndParent,message,wParam,lParam);

Бутони (pushbutton, check box, radio, group box)

WM_COMMAND

SendMessage(hwndButton, BM_SETSTATE,1,0); // симулира натиск.

Това е прозорец, който има някаква специфика при обработването и се явява дъщерен на един по общ прозорец, най-често съобщения към родителя и най-честото съобщение е window command.

Прихващане на функции (Windows subclassing)

1. lpfnScrollProc = MakeProcInstance ((FARPROC)ScrollProc, hInstance);

2. Чрез GetWindowLong() се извлича адреса на стандартната функция.

3. Чрез SetWindowLong() се установява новия адрес .

4. Връщане към стандартната Windows функция:

CallWindowProc (lpfnStandart, hwnd, message, wParam, lParam);

Контрол за редактиране (edit )

CreateWindow(“edit”, …);

бутонът изпраща WM_COMMAND с нотификационен код ( в lParam).

Контроли в 32 битови версии

над 20 типа. 6 са “класически”- от първите версии. Имат поддръжка на MFC:

CButton,CListBox;CEdit;

CComboBox; CScrollBar;

CStatic.

Създаване на бутон:

CButton m_wndPushButton;

m_wndPushButton.Create(_T(“Start”), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, rect, this, IDC_BUTTON);

CEdit

CEdit::SetMargins() // задава размерите на полетата вляво и дясно



CEdit::SetRect() // задава редакторската област в контрола

CEdit::SetLimitText() // задава макс. брой символи (подрзабират се 30000.

CEdit::SetWindowText()

CEdit::GetWindowText()

ф-иите са наследени от CWnd

::Clear()

::Cut() за селе-

::Copy() ктиран

::Paste() текст

Пример: edit контрол,

който приема само числови стойности:

class CNumEdit : public Cedit

{protected:

afx_msg void OnChar(UINT nChar,UINT nRepCnt, UINT nFlags);

DECLARE_MESSAGE_MAP(};

BEGIN_MESSAGE_MAP(CNumEdit, CEdit)

ON_WM_CHAR()

END_MESSAGE_MAP()

void CNumEdit::OnChar((UINT nChar, UINT nRepCnt, UINT nFlags)

{

if((( nChar >= _T(‘0’)) && (nChar <= _T(‘9’)))) CEdit::OnChar(nChar, nRepCnt, nFlags);



}

Искаме да добавим филтър, к. да да допуска само цифри. И искаме функционалност, подобна на edit контрол. Затова правим клас CNumEdit наследник на CEdit. Трябва да се добави проверка за цифра. Това се добавя в метода свързан с натискане на клавиш(OnChar)За целта се декларира собствена ф-я OnChar с параметри като на стандартна ф-я.

1. Прототип

2. Свързване на ф-ята със съобщението-се добавя записа в нашата карта чрез DECLARE_ MESSAGE_MAP

3. Реализация-трябва да се направи карта на съобщенията

Искаме да добавим само една ф-я. Затова към нашия контрол ще постъпват много съобщ., к. той няма да ги обработва, а ще ги препраща към родителския. Само когато се получи OnChar ще го прихване. Записваме ф-ята OnChar, проверяваме дали е цифра от 0 до 9, ако не е нищо. Ако е: филтър и се пренасочва към CEdit.



13 Общи контроли в Windows среда – те са 20 и MFC осигурява класове за тях.

Създаване:

#include

//съдържа декларациите на контролите

CProgressCtrl wndProgress;

wndProgress.Create( стил, размери в правоъгълник, this, IDC_…);

Пример с List box:

ClistBox m_wndList;

m_wndList.Create(WS_….| ….., rect, this, IDC, ……);

m_wndList.InsertString(….);

m_wndList.DeleteString(…);…………….

Списъци с изображения -Image List ( tree view, list view, combo box extended)

CImageList il;

il.Create(IDB_BITMAP, 18, …);…

il.Draw(pDC, индекс, нач.координати, ефекти при чертане);

1. Привързват се не към WM_COMMAND, а към друго съобщение

2. Много от контролите стават по богати и повече

Прогрес контрола се създава с Create по отношение на ListBox освен да се променят размери може да се добавят и картинки. Контроли, к. допускат и добвяне на картинки. ImageList – принципът им е следният – работата с картинките се поема от един клас CImageList, k. после се свързва с низовете от списъка. Могат да се различават различни ефекти като прозрачност. Необходимо е мн-во от bitmap object, к. са с фиксирани р-ри – о/о 18 пиксели.

Разширен контрол ComboBoxExtended ComboBoxEx: public CComboBox

CComboBoxEx::SetImageList( & обект CImageList)

CComboBox::InsertItem()

//добавя елемент към контрола с указан текст,

Ех разширява функционалността на ComboBox. В примера се използва да се добавят картинки.

Контроли на прогрес

CProgressCtrl ::SetRange();

//задава диапазон от.. до..

CProgressCtrl ::GetRange();

CProgressCtrl::SetPos();

//ако искаме да започнем от някъкво ниво нататък;

Пример:


m_wndProgress.SetRange(0, 100);

m_wndProgress.SetPos(0);

for( int I =0; I < 100; I++)

{m_wndProgress.SetPos(I); ::Sleep(25);

}

Контрол за анимация



CAnimateCtrl::Open()

// зарежда AVI файл

CAnimate::Play();

//стартира анимацията

Картинките трябва да са в AVI формат, за да могат да се прихващат; Open – зарежда, Play – страртира. Указват се параметри като начални

14. Езикови средства за създаване на усотйчив код. Въведение в SEH.

SEH(Structure Exception Handling) структурирана обр. на изключителни ситуации.

Това е вграден механизъм за обработка на софтуерни(прекъсвания) и хардуерни(деление на нула) изкл. ситуации.

Пример:


int ConcStr( TCHAR* pszDest, TCHAR* pszSrc, int cDest ){TCHAR* pResult = NULL;

if( pszDest && pszSrc )

{int nDest = lstrlen

( pszDest);

int nSrc = lstrlen( pszSrc);

if(( nDest + nSrc) < cDest){pResult = lstrcat( pszDest, pszSrc );}

if ( pResult )

{return lstrlen (pResult);}

else{

return 0;



}

}

Добре структуриран код: използващ предоставените от средата средства за спряване с изкл. ситуации. Няма толкова проверки, добре блокуван и се знае кое кога ще се изпълни.



int ConcStr( TCHAR* pszDest, TCHAR* pszSrc, int cDest )

{__try


{TCHAR* pResult = lstrcat ( pszDest, pszSrc );

return lstrlen( pResult );

}

__except(EXCEPTION_EXECUTE_HANDLER)



{return 0;}

}

Exception ще се генерира във вторият случай.



Блокът след exception handler ще се изпълни при наличие на exception в try. Блокът exception се изпълнява в обсега на try.

В 32 битова среда има следните възможности за прихващане и обработка на exception:

1.Може да се ползва SEH механизма на ОС.

2.Може да се ползва собствения за езика механизъм за обработка на exceptions.

3.Възможна е комбинация то 1 и 2.

При откриване на exception става:

1.Изпълняваната нишка се прекратява.

2.Управлението се предава от usermode в kernelmode (ядрото на ОС поема управлението).

3.Търси се начин за реакция чрез exception блок. Ако има то той се изпълнява, а ако няма диспечера генерира служебен exception handler. Ако има блок exception handler, то:

1. Да се изчисти паметта от излишни данни.

2. Да се възстановят операциите в БД (ако има).

3. Да се освободят заетите ресурси.

4. В LOG файл може да се запише информация.

5. Диалогов прозорец с полезна информация.

1.Терминираща обработка (__finally).

__finally представлява блок за който може да се гарантира че винаги ще се изпълни.

BOOL Myfunc()

{int* p = 0;

__try{ // използва се p }

__finally{delete p;}

return fReturn;}

finally предшества блок, к. винаги ще се изпълнии то преди края на ф-ята. Ако имаме и finally и exception, то finally се изпълнява след exception блока.

Finally се изпълнява в следните случаи:

1) след изход от try секция

2) след прекратяването на try блока чрез exception

3) при нормален изход

Return по възможност ! да е извън try и finally блоковете. Иначе return може да е в try, finally или извън 2та блока. Ако е в try блока връщаната ст-ст не се връща в този момент, т.е компилатора съхранява резултата от връщане в междинна памет и ще го вурне след като handlera се изпълни. Това означава, че ако след finally блока има още 1 return той няма да върне ст-ст.

Пример:


Long calcFactorial(int n)

{ long lResult;

__try { if (n<2)

{ for(lResult=1;n>1;__)

lResult*=n;}

else return(long)n;}

__finally{ return lResult;}

}

Винаги се изпънява Return от finally, к. е грешно



__leave – поставена в try води до преждевременно пренасочване към блок finally като нищо от това което е предвидено за изпълнение след leave в try няма значение, както и междинното съхранение

__try


{__;__leave;__} //нищо след като не оказва влияние

За да разберем дали във finally сме дошли след нормален изход или след exeption се използват различни неща:

int main()

{ __try { __leave; cout<<”never”<

__finally {: f(AbnormalTermination()!=FALSE)

cout<<”abnormaltermination”



<else cout<<”normaltermination”<

return 0; }

Единственият начин е да не се изпълни finally е да прекратим нишката(abroad прекъсване)


15. Филтър за обработка на изключителни състояния (__except).

Той се изчислява и стойността определя начина на реакция при случване на exception.

1)EXCEPTION_EXECUTE_HANDLER – term.handler – има стойност 1:

Ще се изпълни блокът след except и управлението ще се подаде след блока except.

2)EXCEPTION_CONTINUE_SEARCH (0) –dispatcher ще търси друг. Има стойност 0. Той показва на ОС да пренебрагне нашият exception блок и да търси обхващащ exception блок.

3)EXCEPTION_CONTINUE_EXECUTION –пренебрегва (-1) - има стойност –1:

Той пренебрагва exception блока т.е. той не се изпълнява, няма да се търси друг, а управлението ще се предаде на следващата конструкция.

ОС изработва множество идентификатори, които указват причината за exception-а.

__except ( GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION )

{

cout << “прихваната изкл. ситуация” <

}

// опит за четене/запис без инициал. на указател или без съответни права.

По-общ анализ:

__ except( ExceptionFilter( GetExceptionCode()))

където:

int ExceptionFilter( int nException )



{ int nReturn;

switch( nException )

{

case EXCEPTION_INT_DIVIDE_BY_ZERO:



nReturn= EXCEPTION_EXECUTE_HANDLER;

break;


………………….

default: nReturn = EXCEPTION_CONTINUE_SEARCH;

}

return nReturn;



}

16 Вграден в С++ механизъм за р-я на изключителни събития

C++Exception Handling

int Divide( int n1, int n2 )

{ int nReturn = 0;

try{if( !n2 ) throw

range_error();

nReturn = n1 / n2;}

catch ( range_error& e )

{cout << “опит за / на 0” << endl;}

return nReturn;}

В try блока се генерират изключителни ситуации. Може да се генерира дъщерна изключителна ситуация, а да се прихване родителска. Трябва try и catch да са в една функция. Ако няма catch, то се търси в обхващащата функция дали има catch, ако никъде няма то се извиква terminate. При генериране на изключителни ситуации с throw автоматично се изпълняват деструкторите на всички обекти създадени от началото на try блока.

Standart Exception Library

exeption

logic_error runtime_error

domain_error range_error

(вътр. грешка) overflow er. invalid_argument, length_error,out_of_range

- runtime error - групира всички проблеми, к. не могат да се групират при изпълнението

- logic error - групира всички проблеми, к. се пораждат при изпълн. на ф-ята.

SomeFunc()

{try{…throw range_error( “ невъзможност за заделяне достатъчно памет”);

……}

catch( runtime_error e)



{cout << e.what() << endl ;

// e.what() – стандартна (извиква съобщение).

}}

Интересен синтаксис е следният:



catch (…) // прихваща за обработка всички exceptions.

Важно е да се обхване чрез try. Конструкторът, не връща стойност т.е. не може да информира за успех или неуспех относно работата му.

{cout << “ ……sssdcg “ << endl;

throw; }}

Windows отделя нишка, к. се занимава с анимации.

Контрол календар

CMonthCalCtrl – този контрол позволява на потребители да въвеждат дати чрез избиране от календар, вместо да ги набират в edit контрол. Той може да поддържа единичен или множествен избор.

ето пример за задаване текущата дата:

m_wndCal.SetCurSel(CTime(2002, 3, 25, …);

Контрол за избор на дата и час CdateTimeCtrl – контролът прилича на edit, но вместо да показва обикновени текстови низове, показва дати и часове.

дата: 9/03/02 или Thursday, September 25,2001

Час: HH:MM:SS последван от AM/PM


17 Съвместяване на двата механизма.

Някои проблеми в SEH механизма:

1.Възможно е ако работим само със SEH механизма да пропуснем деструкцията на някои проблеми.

2.SEH механизма дава възможност за много точно детайлиране на причината на ниско ниво, но при положение че сме прихванали съответната причина при SEH.

3.Повечето стандартни С++ функции са написани така, че хвърлят С++ exception, а не SEH exception.

Възможно е рпеобразуването на обекти на SEH към С++ exception обекти. За целта в 32 битовите SEH механизми е преджидена _set_se_translator позволява дефинирането на потребителска функция и извършва транслация на SEH механизма към С++ exception механизма. В My_func се изпълнява транслацията и се хвърля (throw) С++ exception обект, който съдържа информация с exception.

class CWin32Except

{unsigned int m_nCode;

public: CWin32Except( unsigned int nCode) : m_nCode(nCode){};

unsigned int Code() const {return m_nCode;};}

използване:

void SEH_MyFunc( unsigned int nCode, EXCEPTION_POINTERS* pExp )

{throw CWin32Except( nCode );}

void DoAccessViolation()

{int* p =0;*p = 32;}

void main(void)

{_se_translator_function fn old;

fnold=set_se_translator( SEH_MyFunc );

try{DoAccessViolation();}

catch(CWin32Except& e)

{cout << “ изкл. с CWin32Except ” << endl; cout << “Exception is “ << e.Code() << endl;}

_set_se_translator(fnold);}


18 Обработка на изкл ситуации при подкрепата на MFC класовете.

MFC дефинира над 10 класа свързани с exceptions.

try

{ // Execute some code that might throw an exception. }



catch( CException* e )

{// Handle the exception;"e" contains information

e->Delete(); }

// Other normal program statements ...

фрагмент прихващащ различни обекти – exceptions:

try{//Execute code that might throw an exception.}

catch(MemoryException* e)

{// Handle the out-of-memory exception here.}

catch(CFileException*e)

{// Handle the file exceptions here.}

catch( CException* e )

{// Handle all other types of exceptions here.

}

Действията се извършват по следният начин:



1. Генерира се exception.

2. Намира се съответнияат catch блок.

3. Предава се обекта exception catch блока.

4. Автомат. деструкция на всички обекти създадени в try блока от началото до момента на ген. на exception в обратен ред.

5. Изпълнение на блока следващ catch.

Изчислителният процес продължава след последния catch.


19.Изключения и .NET

Изключението не е грешка. То е просто нарушаване на допусканията за даден програмен интерфейс.

Отказ от HRESULT:

Изключение не може да се игнорира

няколко десетки стандартни типа на изключения, всички наследили System.Exception

стек на повикванията за catch

ако липсва филтър – генерира се “необработено съобщение”

след откриване на подходящ catch – изпълняване на всички finally от облока – подал изкл. докато стигне ( и там спира ) блока с catch филтъра, поел го за обработка.. След това се изпълнява catch блока.

В края на catch блока: а) подаване същото изкл нагоре; б) подава се друго изкл. с по-богата инф. нагоре; с. нишката излиза от catch.

Трагични” съобщения: OutOfMemoryException; StackOverflowException; ExecutionEngineException

System.Exception съдържа полезни свойства: Message; Source; StackTrace; TargetSite; HRESULT.

обща йерархия в .NET Framework Class Library (FCL):

System.Exception

= System.ApplicationException

==System.SystemException

подавайте конкретен клас изключение ( който няма производни класове)

йерархиите exceptions да са широки , но плитки. Тези без производни - sealed

Дефиниране на собствено изключение:

да има 3 public конструктора:

а. без параметри (по подразбиране)

б. с параметър string – задаващ съобщение

в. с параметър String и инстанция на производен на Exception тип ( за генерирано вътрешно съобщение)

2. наследява Exception

3. може да има и други констуктори

4. винаги да е сериализуем за да може изкл. да се предава през граница на процес, машина или кл. приложение или в log. За целта:

- [Serializable] атрибут

- ако има дефинирани свои даннови членове: - да е наследил ISerializable

- да имплементира метода му GetObjectData()

- да има констр. с 2 парам. – SerializationInfo и StreamingContext

[Serializable]

sealed class MyPrivateException : Exception, ISerializable {

public MyPrivateException() : base() {}

public MyPrivateException(String message) : base(message) {}

public MyPrivateException(String message, Exception innerException)

; base (message,innerException) { }

// дефинира собствено поле private String name;

// дефиниране на свойство само за четене, което връща данната public String Name Ш get{return name; } } //предефиниране базовото свойство Message, така че да включва и новото поле public override String Message

{ get { String msag = base.Message;

msg + = “ The name is” + name;

return msag; }}

// тъй като имаме поле, дефинираме конструктор за десериализация.

// Той е private, защото класа е sealed, иначе – protected private MyPrivateException (SerializationInfo info, StreamingContext context): base( info, context)

{ /* десериализация на полетата на базовия конструктор */

// десериализация на всяко ново поле

name = info.GetString(“Name”);}

// тъй като има поне 1 метод или данна, предефинираме метода за сериализация

void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) {

// сериализация на всяко поле

info.AddValue(“Name”, name);

base.GetObjectData(info, context);}

// дефиниране допълнителни конструктори, задаващи стойност на полето

public MyPrivateException(String message, String name) : this (message)

{

this.name = name;}



public MyPrivateException( String message, String name, Exception innerException): this(message, innerException)

{ this.name = name; }



Правила за работа с изключения

Разработвате библиотека: ако прихванете всички изкл. , как разработващия приложение с библиотеката ще знае че нещо се е случило

Разработвате библиотека с типове – не винаги знаете кое е грешка, кое не.

Избягвайте код , прихващащ всичко: catch(System.Exception) {………}

След прихващане и обработка на изключение, често е добре да уведомите извикващия: подавате същото (само с throw) или друго изключение (това е начина за преобразуваме изключението от нещо специфично, към общоразбираемо за потребителя)

Внимание: CLR управлява изключенията така: първо намира catch филтър, който може да е доста нагоре в стека. След това “развива” стека на вложените изкл. като изпълнява всички Finally блокове , до и без този съответстващ на прихващащия филтър.Следва изпълнение на catch блока и след това неговия finally.



20 Вход/изход и сериализация

Работа без сериализация – базов клас CFile.

CFile myfile;

CFileException* e;

if ( file.Open( _T(“My.txt”), CFile::modeReadWrite, &e))

{// работим с файла}

else{………e.ReportError();}

същото може и така:

try{CFile file (_T(“MyFile.txt”), CFile::modeReadWrite);…..}

catch( CFileException& e)

{eReportError();

eDelete();}

CFile – капсулира всички AVI ф-ии. Има над 25 м-да-за всички възможни метода над файла.

- отваряне на файл – има предвид “е” клас. Декл. ме обект от CFile exception. Отваряне на файл в режим за четене и запис. Може с try и catch. При отваряне на файл се показва режима.

- затваряне:

А. file.Close();

В. CFile обект се затваря авт. при излизане извън обсег.

- четене/ запис

BYTE buff[0x4000];

CFile file(………………);

DWORD length = file.GetLenght();

while(length)

{ UINT nByteRead = file.Read(buff, sizeof(buff));

lenght -= nByteRead;

}

- file.Write(buff, nByteRead);

// записва определен брой байтове от буфера

- file.Seek( относит. отместване в байтове, спрямо какво)

- препоръчително е четенето да се обхване oт try catch

- изтриване (Remove())

- преименоване на файлове (Rename())



Производни на CFile класове:

Методите за работа с CFile класове могат да се използват и в др. случаи. Напр. MemFile и SharedFile, DataObject – пренасянето на данни м/у приложения, може да се стандартизира чрез него, а за програмата си е все същото. SocketFile – предоставя файл с подобен интерфейс. Stdio File – специален файл към текстови данни.

Internet File – все едно се работи с файл, но на практика се работи с протоколите от нета.

CMemFile, CSharedFile

COleDataObject::GetFileData

CSocketFile, стои между архивния обект и CSocket обекта.

CStdioFile , наследник на CFile.

Пример:


try {

CStdioFile

file(_T(“My.txt”), CFile::modeRead);…..}

catch( CfFileException* e){}

CInternetFile, CGopherFile и CHttpFile .

Изброяване на файлове и директории

:: FindFirstFile

:: FindNextFile()

:: FindClose()

Универсален подход на I/O – използване на архиви (базов клас CArchive)

Ето пример: искате в отоворен файл да запишете 2 променливи a,b:

file.Write( &a, sizeof(a));

file.Write( &b, sizeof (&b));

Ето другият подход:

CArchive ar( &file, CArchive::store);

ar << a << b;

Архива е един междинен обектмежду нас и запомнящата среда, скриващ спецификацията на запомнянето, а представящ на нас само стандартният диск. Едни и същи операции за вход/изход да бъдат използвани за данни с различен тип, независимо от средата. За да се осъществи това посредата ! да се постави нещо. Архива е винаги между нашето приложение и запомнящата среда. Функцията на междинният слой е като един транслатор. Най-често архива се асоцира с диск. Първо създаваме архива – обект, асоцираме го със запомнящата среда. Командите за вход/изход трябва да се предефинират за нашите данни и обекти. Всички примитивни типове имат предефинирани в MFC операции за << >> (BYTE, WORD, LONG, DWORD, float, double, intchar, char, unsigned int). Оперторите са предефинирани и за непримитивни типове, за които има стандартни MFC класове:

пример: Cstring string; ar<

също и за: Ctime, Crect, Csize, ColeDateTime, cole variant …, както и за структури SIZE, POINT, RECT.

Ако се създават собствени класове и ако искаме те да поддържат всички обекти от тези класове и ако направим класа наследник на Cobject тогава не е нужно да предефинираме командите за вход/изход.




Сподели с приятели:
1   2   3   4




©obuch.info 2024
отнасят до администрацията

    Начална страница