Лабораторні роботи WinApi

Site: Державний університет "Житомирська політехніка" - Освітній портал
Course: Системне програмування
Book: Лабораторні роботи WinApi
Printed by: Guest user
Date: Wednesday, 20 January 2021, 1:15 PM

Лабораторна робота №1

 Копіювання файлів

Завдання:

  1. Розібрати роботу програм copy1.c, copy2.c ( архів c_text.zip).
  2. Написати власну програму копіювання файлів використовуючи функції WinApi:
    CreateFile();
    ReadFile();
    WriteFile();
    CloseHandle();
  3. Обов'язково обробити можливість виникнення помилок при виклику системних функцій. Виводити код отриманої помилки використовуючи функцію GetLastError();
  4. Ім'я вхідного файлу, вихідного файлу мають задаватися в командному рядку.
  5. Визначити оптимальний розмір буферу пам'яті, який використовується в програмі для копіювання.
  6. Перевірити працездатність програми при копіюванні великих файлів.
  7. Програма має виводити під час копіювання відсотки виконаної роботи.
  8. Програма має після копіювання вивести інформацію про скопійований файл (ім'я, дату створення, дату модифікації, розмір, тощо).
  9. Програма має вивести кількість часу, витраченого на копіювання.
  10. Порівняти час копіювання з часом копіювання вбудованою консольною командою COPY. Пояснити отриманий результат.

Додаткове, необов'язкове завдання.

Додати можливість копіювати папки. Копіюватися мають усі вкладені папки та файли. Атрибути файлів та папок мають зберігатися. Доцільно використати рекурсивний прохід по деревоподібній структурі.

Лабораторна робота №2

Шифрування файлу

Технічне завдання:

     Модифікувати програму копіювання файлу, написану у лабораторній роботі №1, таким чином, аби вона шифрувала файл. Програма копіювання, має відповідати усім вимогам, описаним у лабораторній роботі №1.

Вимоги до програми шифрування:

1.  Назва програми: Encode.
2. Iнтерфейс - командний рядок, в який вводяться режим роботи програми, пароль, а також імена вхідного та вихідного файлів.
encrypt </e | /d> <File_to_code> [distination_file] [/p=password]
Наприклад:
 
encrypt /e myfile.txt myfile.cod /p=mypassword,   де 
/e або /d - ключ який визначає шифрування або дешифрування;
myfile.txt - специфікація файлу який має бути зашифрований;
myfile.cod - специфікація файлу в який має бути записано зашифровану послідовність;
/p=mypassword - пароль для шифрування.

3. Режим шифрування - ключ /e, режим дешифрування - ключ /d.

4. При неправильному завданні параметрів програма повинна виводити інформацію про вірне завдання параметрів.

Наприклад: 
encrypt </e | /d> <File_to_code> <distination_file> [/p=password]

5. Зашифрований файл повинен містити  заголовок і кодовані дані.  Заголовок доцільно записувати у файл при шифруванні двічі. Перший раз без порахованої контрольної суми, для того щоб відступити місце у файлі, перед записом вже зашифрованих даних. Вдруге заголовок записувати вже з порахованою контрольною сумою, після шифрування даних. Для цього відповідно треба перемістити покажчик запису-читання файлу на початок файлу, а після повторного запису заголовку поверх записаного, покажчик запису-читання необхідно повернути знов в кінець файлу, для уникнення відсікання вмісту файлу при його закритті, по поточній позиції покажчика запису-читання.

6. Заголовок повинен містити:
         сигнатуру виду файлу;
         номер версії програми;
         рядок Copyright, із якого зрозуміло, якою програмою файл був зашифрований;
         контрольну суму, яка надасть можливість пперевірити правильність розшифрування даних;
         імя вихідного файлу для його відновлення при дешифруванні
         іншу інформацію на розсуд розробника.

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

struct Header {
  char signat[3];
  int version;
  char CopyRight[30];
  unsigned long CRC;
  char filename[13];
  ... 

7. Необхідно рахувати контрольну суму, яка буде контролювати правильність дешифрування. Найпростішій метод підрахунку контрольної суми - це додавання усіх байтів файлу.

Наприклад:
unsigned long CRC = 0;
...
   CRC +=buffer[i];

...

Контрольна сума має рахуватися одночасно, під час шифрування, для уникнення подвійного проходу по файлу. Контрольна сума рахується над незашифрованими даними. Під час шифрування, контрольна сума накопичується, та потім записується у заголовок файлу. Під час дешифрування контрольна сума читається з файлу (читається увесь записаний заголовок файлу), та порівнюється з порахованою контрольною сумою над розшифрованими даними. Якщо суми співпадають, то це доказує правильність розшифрування файлу.




8. Для вшифрування даних можна використати будь який алгоритм. Найпростішим може бути алгоритм гамування. Базується він на бітовій операції XOR. В мові Сі операція визначена символом ' ^ '. Ця операція є зворотньою. Тобто:


a xor b = c
c xor b = a
c xor a = b

Використовуючи це правило, в програмі можна записати це так:

   int j = 0;
   for( int i = 0; i < BytesRead; i++ ) {
      if( j == strlen( password ) ) j = 0;  

      buffer[ i ] ^= password[ j++ ];
   }

Результат буде будуватись по наступній схемі:

Вхідна послідовність
b1
b2
b3
b4
b5
b6
b7
b8
b9
b10
...
bn
Символи паролю "vasya"
v
a
s
y
a
v
a
s
y
a
...
...
Вихідна послідовність
c1=b1^'v'
c2=b2^'a'
c3=b3^'s'
c4
c5
c6
c7
c8
c9
c10
...
cn
Процес дешифрування проходить по тій же схемі.

Додаткові, необов'язкові завдання:

1. Вдосконалити алгоритм шифрування.

2. Реалізувати шифрування папки зі всім вкладеним вмістом, записуючи усі в один вихідний файл. При дешифруванні відновити усі структуру папок та вкладених файлів.

 

Лабораторна робота №3

 "HelloWin"

Завдання:

1. Розібрати текст програми hellowin.c та вивчити матеріал викладений у файлі допомоги (архів lab3.zip)


Приклад програми

2. Створити аналогічну програму, яка друкує у вікно:

  • Змінні середовища програми. Порівняти з результатами роботи консольної команди SET.
  • Ім'я програми.
  • Шлях - звідки була запушена на виконання програма.
  • Аргументи командного рядка, які були задані при запуску програми.
  • Поточний шлях визначений для програми.
  • Пріоритет процесу та пріоритет первинного потоку.
Усі дані мають бути отримані за допомогою відповідних функцій WinApi.

Додаткове, необов'язкове завдання:

  1. Додати прокрутку (scroll) у вікно, з відповідною обробкою повідомлень.
  2. Додати меню до головного вікна програми, реалізувавши пункт "записати у файл". Має бути записана, уся інформація що була виведена у вікно.

Контрольні питання:

  1. Чим відрізняється програма для Windows від програми для DOS?
  2.  Яка функція є точкою входу в програму?
  3. Що таке клас вікна?
  4. Що таке віконна функція? Віконна процедура?
  5. Навіщо виконувати реєстрацію класу вікна?
  6. Як пов'язана віконна функція з вікном?
  7. Що таке цикл обробки повідомлень? Які його функції?
  8. Що таке повідомлення? Хто надсилає повідомлення?
  9. Хто отримує повідомлення для вікна?
  10. Які повідомлення ви вже знаєте? Що значить кожне з них?
  11. Що таке контекст пристрою? Яким чином виконується виведення у вікно програми?

Лабораторна робота №4

 "KeyLock"

Завдання:

1. Вивчити матеріал викладений у файлі допомоги (Опис роботи з клавіатурою, архів lab4.zip)

2. Створити програму, яка друкує в вікно інформацію про натискання клавіш на клавіатурі в подібну таблицю:

Massege Key Char Repeat Scan Ext Alt Prev Tran

За основу (скелет програми) можна використати програму з лабораторної роботи №3. 

Приклад роботи програми показано нижче на малюнку. Приклад готової програми в архіві матеріалу до лабораторної роботи (Програма keylock.exe).

Приклад програми до лаб. роботи №5

Контрольні питання:

  1. Які повідомлення від клавіатури ви знаєте?
  2. Що таке scancode клавіші?
  3. Як реєструються натискання комбінацій клавіш?
  4. Що таке системні клавіші?
  5. Як визначити факт утримування клавіші? Факт відпускання клавіші?

Лабораторна робота №5

Лабораторна робота №5 "Миша"

Програма обробки повідомлень від миші.
Підрахунок відстані та швидкості руху миші.

Завдання:

1. Вивести координати миші у вікні.
2. Знайти відстань між двома точками у вікні.
3. Знайти швидкість руху миші на проміжку.

Для виконання цієї лабораторної роботи, необхідно вивчити теоретичний матеріал.

1.       Виведення координат миші у вікні.

Для того щоб визначити координати миші, необхідно обробити повідомлення WM_MOUSEMOVE, яке приходить кожний раз, коли виконується рух миші при активному вікні, в камках вікна. Параметрами цього повідомлення є координати миші.

Обробляючи це повідомлення, ви формуєте текстовий рядок наприклад наступним чином:

X = LOWORD(lParam);
Y = HIWORD(lParam);
wsprintf(str, “ X = %d    Y = %d “, x,y );

2. Відстань між двома точками у вікні.

Необхідно зафіксувати дві точки. Нехай це будуть точки в яких користувач натисне ліву а потім праву кнопку миші.

Коли виконується натискання лівої або правої кнопки миші, ми отримуємо повідомлення:

WM_LBUTTONDOWN або WM_RBUTTONDOWN

Разом з цими повідомленнями передаються координати миші.

X = LOWORD(lParam);
Y = HIWORD(lParam);

Це координати в яких було виконане натискання.

Нехай ліва кнопка миші була натиснута в координатах (X1,Y1) а права в координатах (X2,Y2). Відстань між двома точками можна отримати за виразом:

S = sqrt( ( X2 - X1 ) * ( X2 - X1 ) + ( Y2 - Y1 ) * ( Y2 - Y1 ) );

Для визначення швидкості руху миші нам потрібно знати час руху на промішку.

Для визначення часу, потрібно зафіксувати час при натисканні лівої кнопки миші, а потім час при натисканні правої кнопки миші.

T1 = clock(); // цей рядок пишемо в обробник повідомлення WM_LBUTTONDOWN

T2 = clock();// цей рядок пишемо в обробник WM_RBUTTONDOWN

DT = T2 – T1;
Speed = S / DT

Тепер залишається тільки вивести значення в вікно.

Для виведення отриманих текстових рядків можна використати функцію TextOut(). Вона вигідна тим, що дозволяє виводити в визначені координати вікна.

Виведення отриманих рядків необхідно робити тільки в обробці повідомлення WM_PAINT. Нагадую, воно приходить тоді, коти операційна система вважає, що інформація в нашому вікні застаріла.

Якщо, нам потрібно згенерувати повідомлення WM_PAINT, то викликаємо функцію InvalidateRect(), яка повідомляє ОС про те що якась частина нашого вікна (або все вікно) застаріло. Виклик цієї функції ми робимо кожний раз, коли необхідно перемалювати вікно.

 

Додаткове (ускладнене завдання).

Знайти миттєву швидкість руху миші.
Підказка. Використовуєте програмований таймер, для отримання фіксованих проміжків часу, на яких визначайте відстань пройдену мишею, вона й буде швидкістю руху.

Лабораторна робота №6

 "Таймер"

Програмування таймеру.
Робота з системною датою та часом. 
Створення декількох таймерів, та обробка повідомлень від таймеру.

 

В данной лабораторной работе вам необходимо изучить работу «таймера».

 

Таймер – это объект ядра ОС Windows, который может быть проинициализирован, после чего в очередь сообщений для вашего приложения будет приходить сообщениеWM_TIMER каждый раз по истечении заданного промежутка времени.

 

Для установки таймера используется функция WinApi: SetTimer().

Для уничтожения таймера используют KillTimer();

 

Для написания 7 лаб. работы необходимо взять за основу, 4 лаб.работу. В ней создается окно, в которое необходимо вывести следующее:

  1. Системную дату.

Для этого вам необходимо ее получить. Это можно сделать, вызвав функцию:

GetDateFormat();

Вызов данной функции лучше выполнить в обработке сообщения WM_CREATE, то есть при создании окна. Результатом работы функции будет заполненная текстовая строка с текущей датой, которую вы и выведете при обработке сообщения WM_PAINT.

  1. Системное время с точностью до секунд.

Так как время будет меняться каждую секунду, то его и обновлять необходимо будет каждую секунду.

Поэтому необходимо использовать таймер. Например, его можно создать таким вызовом:

SetTimer(hwnd, 6, 1000, NULL);

где

hwnd – дескриптор окна;

6 (второй параметр) – идентификатор таймера, почему я задал ему номер 6 а не 1 поймете ниже. Но это просто его номер.

1000 (третий параметр) – промежуток времени, задается в млсек. 1000 млсек = 1 сек.

NULL (четвертый параметр) – указатель на функцию, которая будет вызвана, для обработки сообщения WM_TIMER, если задан NULL, то вызывается ваша оконная функция.

 

Вызов этой функции лучше выполнить при обработке сообщения WM_CREATE.

Тут же , не забудьте вставить обратный вызов, то есть уничтожение таймера.

KillTimer(hwnd, 6);

Где второй параметр это идентификатор удаляемого таймера.

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

 

Установив таймер, вы будете получать сообщение WM_TIMER, каждую секунду.

В обработчике этого сообщения вставьте вызов функции

GetTimeFormat(), которая вам вернет системное время. Результат будет в текстовой строке, вывод которой вставьте в обработке WM_PAINT.

 

  1. Программирование пяти таймеров на разное время.

Выведите в окно пять строк следующего содержания:

 

Timer number 1 ( 5s. ) - OFF

 

Timer number 2 ( 10s. ) – OFF

 

Timer number 3 ( 15s. ) – OFF

 

Timer number 4 ( 20s. ) – OFF

 

Timer number 5 ( 25s. ) - OFF

 

Если пользователь выполнить щелчок левой кнопки мыши по какой то из пяти строк, то фраза OFF, должна измениться на фразу ON, и после чего, через соответствующий промежуток времени (5, 10, 15, 20 или 25 сек.) соответствующая строка будет выглядеть например так:

 

Timer number 4 ( 20s. ) – ON     ( BEEP! )

 

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

Если пользователь выполнит повторный щелчок левой кнопкой мыши по тому же таймеру, то он должен выключиться (ON -> OFF), и после чего сигнал BEEP, не должен возле него появляться.

Пользователь может включить любое количество таймеров (он 1 до 5 одновременно), и все они должны «делать» BEEP, по истечении своего промежутка времени.

 

Для выполнения последнего (третьего) задания, сделайте следующее:

 

Вставьте обработку сообщения WM_LBUTTONDOWN, которое приходит, при нажатии левой кнопки и мыши. Проверьте координаты Миши, в которых выполнено нажатие, есть координаты совпадают с одной из строк 5 таймеров, то выполните действия по установке данного таймера.

Например для первого SetTimer(hwnd, 1, 5000, NULL);

Или для второго - SetTimer(hwnd, 2, 10000, NULL);

Перерисуйте OFF на ON.

 

Если таймер был включен, то выключите его

KillTimer(hwnd, 1);

Перерисуйте ON на OFF.

 

Как только вы установите очередной таймер, то он тоже станет присылать WM_TIMER. Для того чтоб различить от какого таймера пришло сообщение, тоесть какой промежуток времени прошел, для этого воспользуйтесь номером таймера который вы получаете вместе с сообщением WM_TIMER в параметре lParam.

Таким образом в обработчике WM_TIMER: можно выполнить следующее:

 

switch(lParam) {

case 1: // обработка таймера на 5 сек

break;

case 2: // обработка таймера на 10 сек

break;

case 3: // обработка таймера на 15 сек

break;

case 4: // обработка таймера на 20 сек

break;

case 6: // обработка таймера на 1 сек формирование строки системного времени

break;

}

 

Данная лаб.раб. рассчитана на одно лабораторное занятие.

Лабораторна робота №7

Лабораторна робота №7 "Процеси та потоки"

Взаємодія між процесами. 
Розподіл даних між процесами. 
Робота з файлами які відображаються у пам'ять.

 

Необходимо написать две программы, которые будут иметь общие данные.

Существует несколько механизмов реализации общего доступа к данным разных процессов.

Воспользуемся одним из них, наиболее удобным – проецированием файла в память.

Одна программа будет сортировать данные в файле, а другая отображать содержимое этого файла. Работать оба процесса будут одновременно.

 

Создайте файл data.dat. В нем записаны числа, сгенерированные случайным образом. Количество чисел – 20-30 штук. Диапазон значений:от 10 до 100. (Это именно числа, а не символьные строки хранящие ASCII коды цифр!!!)

 

Программа №1. «Сортировка данных»

  1. Берем за основу программу лаб.раб №4.
  2. Включаем обработку события нажатия клавиши, и отслеживаем в нем нажатие пробела. Если пользователь нажал пробел, значит начинаем сортировку данных.
  3. Выполняем проецирование файла в память. Используем для этого созданный файл data.dat. В результате получим доступ к данным как к обычному одномерному массиву.
  4. Выполняем сортировку массива, любым из методов сортировки. Вставьте 1-но секундную задержку для каждой итерации сортировки массива, это позволит потом наглядней увидеть процесс сортировки.
  5. По окончанию сортировки, программа выводит в окно, строку «Работа завершена».

 

Программа №1. «Вывод файла данных в окно»

  1. Берем за основу программу лаб.раб №4.
  2. Выполняем проецирование файла в память. Используем для этого созданный файл data.dat. В результате получим доступ к данным как к обычному одномерному массиву. Этот же файл проецирует в память предыдущая программа.
  3. Создаем таймер на 0.5 секунды. При получении сообщения от таймера, выполняем вывод всего массива в окно. Предусмотрите корректный перевывод данных в окно, без наложений. В окно выводим не числа из массива, а строки одного и того же символа, например «*», в количестве равном числу из массива.

 

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

 

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

 

Задание рассчитано на 2 лабораторных занятия. (4 недели).

 

Теория по проецированию файлов в методичке (часть 3).

Лабораторна робота №8

Лабораторна робота №8 "Виняткові ситуації"

Критичні секції коду програми. 
Виняткові ситуаціїї.
Виключення при взаємодії процесів.

Завдання:

Додати до програм, реалізованих за завданням попередньої лабораторної роботи №7, обробку критичних секцій коду та реалізувати блоки фіналізації, для забезпечення гарантованого звільнення синхронизуючого об'єкту.