Реферати

Учбова допомога: Обмін даними в Windows

Поняття і сутність страхування. Зміст. Уведення. Поняття про страхування. стр. 4 Істотні умови договору страхування. стр. 6 Учасники страхових відносин. стр. 8 3.1. Страховик.

Проблеми маркетингових систем розподілу в сучасних російських умовах. Уведення. Процеси, що протікають в економіці Росії, обумовлюють необхідність формування і розміщення виробничо-збутових систем, адекватних вимогам сучасного менеджменту. Тенденція така, що на ринку уцелеют лише ті суб'єкти господарювання, що зуміють створити системи розподілу своєї чи продукції приєднатися до вже існуючим.

Миколі Чаушеску. Президент Румунії з 1974 року, генеральний секретар Румунської компартії з 1965 року. У 1967-1974 роках голова Державної ради. З 1955 року - у керівництві компартії. Скинуть у ході народного повстання і розстріляний (1989).

У країні вічних канікул. У країні вічних канікул Автор: Олексин А. Г. Л. Лагину, автору знаменитого "Старого Хоттабича", присвячую ПОКИ ЩЕ НЕ ПОЧАЛАСЯ КАЗКА... Цю дорогу я знаю напам'ять, як улюблений вірш, що ніколи не заучував, але яке саме запам'яталося на все життя. Я міг би йти по ній замруживши, якби по тротуарах не поспішали пішоходи, а по м- товой не мчалися автомашини і тролейбуси...

Поняття убивство. Кваліфіковані склади убивства Республіки Казахстан. ВВЕДЕННЯ Імовірно, майже про кожне з107 відомих нині елементів написані наукові монографії. Не раз починалися спроби розповісти про всіх елементів

Буфер обміну (CLIPBOARD)

В Windows передбачений спеціальний механізм обміну даними між різними додатками, званий буфер обміну (clipboard). Буфер обміну являє собою буфер, в який можуть бути вміщені дані яким-небудь додатком. Всі інші додатки Windows можуть прочитати ці дані або розмістити в цьому буфері свої.

Для того, що б не виникало плутанини при використанні буфера обміну, Windows передбачає застосування певних форматів даних, що розміщуються в буфері.

У деяких випадках буває зручно переглянути дані, розміщені в буфері обміну - для цих цілей Windows містить спеціальну програму перегляду буфера обміну, що міститься, (Clipboard Viewer). Не треба змішувати між собою сам буфер обміну і програму його перегляду. Буфер обміну реалізований декількома функціями Windows і спеціальними даними.

При розгляді буфера обміну нам треба буде розглянути три питання:

1) як можна самим класти або читати дані з буфера обміну

2) як можна використати буфер обміну зі стандартним вікном-редактором

3) як написати власну програму перегляду буфера обміну, що міститься.

Заздалегідь ми розберемося з деякими основними поняттями, пов'язаними із застосуванням буфера обміну.

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

Кожному вживаному формату даних буфера обміну в Windows поставлений у відповідність певний номер. Windows визначає декілька стандартних форматів і надає для них певні символічні імена:

CF_TEXT відповідає ASCIIZ тексту

CF_BITMAP звичайний битмап

CF_DIB битмап, незалежний від пристрою

CF_PALETTE палітра (звичайно застосовується разом з CF_DIB)

CF_METAFILEPICT метафайл

При відображенні даних цих форматів в програмі перегляду буфера обміну не виникає ніяких проблем, оскільки Windows містить всі необхідні кошти для відображення цих даних. Однак Ви можете класти в буфер обміну дані у власному форматі. Якщо Ви хочете, що б їх відображала стандартна програма перегляду, то Ви повинні їх оголосити як

CF_OWNERDISPLAY дані, що відображаються користувачем

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

Декілька додаткових форматів, будучи звичайними форматами даних, мають відмінні від них номери. У символічних іменах таких даних присутня абревіатура ' DSP'

CF_DSPTEXT відповідає ASCIIZ тексту

CF_DSPBITMAP звичайний битмап

CF_DSPMETAFILEPICT метафайл

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

Крім розглянутих, Windows додатково визначає велику кількість інших стандартних форматів даних, однак вони використовуються порівняно рідко. У більшості випадків це специфічні формати даних різних популярних програм, які було вирішено включити в стандарт Windows.

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

UINT RegisterClipboardFormat(lpszFormatName);

для вже зареєстрованого формату Ви можете взнати його ім'я:

int GetClipboardFormatName(nFormat, lpsBuffer, nMaxCount);

Буфер обміну містить не більше за один блок даних кожного формату, причому всі дані, ті, що знаходяться в буфері повинні бути встановлені одним вікном. Оскільки дані, що передаються в буфер обміну, повинні бути доступні всім додаткам, то для їх передачі використовуються тільки блоки глобальної пам'яті.

Запис і читання даних з буфера обміну

Загальні правила роботи з буфером обміну зводяться до наступного:

1) Вся робота з буфером обміну повинна провестися за час обробки одного повідомлення. Під час роботи з буфером Ви не повинні викликати ніяких функцій, які можуть передати управління іншому додатку. Тобто Ви не повинні використати функцій типу: DialogBox, MessageBox, GetMessage, PeekMessage.

Дані повинні розміщуватися тільки в переміщуваному блоці глобальної пам'яті.

Коли буфер обміну отримує дані, він оголошує себе власником цих даних, так що додаток більше не повинен використати передані дані. Більш того ці дані не можна видаляти при завершенні роботи Вашого додатку - коли буде треба, буфер обміну сам видалить їх.

Коли Ви читаєте дані з буфера обміну, то Ви отримуєте хендл блоку даних. Оскільки ці дані закріплені за буфером, то Ви не повинні з ними працювати, Вам необхідно скопіювати їх до себе.

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

2) Перед початком обміну даними з буфером обміну Ви повинні його відкрити. Робиться це за допомогою функції

BOOL OpenClipboard(hWnd);

якщо Ви покладете які-небудь дані в буфер, то вікно, вказане Вами, буде вважатися власником всіх даних буфера обміну.

3) Потім Ви можете здійснити необхідні операції обміну даними. Якщо Ви маєте намір покласти дані в буфер обміну, то Ви повинні заздалегідь видалити все вже дані, що знаходяться в йому:

BOOL EmptyClipboard(void);

і тільки потім покласти потрібні дані, скориставшись функцією:

HGLOBAL SetClipboardData(nFormat, hGlobal);

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

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

Для цього випадку в Windows передбачений механізм передачі даних із затримкою. Викликаючи функцію SetClipboardData Ви вказуєте замість хендла блоку даних NULL. Це означає, що дані для буфер обміну у Вас є, але передавати Ви їх будете тільки на вимогу. Для такої передачі Вам треба буде обробляти три повідомлення:

WM_RENDERFORMAT nFormat 0L

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

SetClipboardData(nFormat, hGlobal);

передавши їй хендл реального блоку даних.

WM_RENDERALLFORMATS, 0, 0L

повідомлення посилається Вашому вікну коли воно знищується, а буфер обміну містить заримовані дані Вашого вікна. Ви повинні звичайним образом (тобто відкрити-очистити-покласти-закрити) передати всі дані в буфер обміну.

WM_DESTROYCLIPBOARD, 0, 0L

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

Якщо Ви маєте намір тільки читати дані з буфера обміну, то очищати його не треба, а отримати дані потрібного формату можна за допомогою функції

HGLOBAL GetClipboardData(nFormat);

Функція повертає хендл глобального блоку пам'яті, який Ви повинні скопіювати до себе.

4) Після завершення обміну з буфером обміну Ви повинні закрити його за допомогою функції

BOOL CloseClipboard(void);

На цьому закінчуються операції обміну даними з буфером обміну.

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

BOOL IsClipboardFormatAvailable(nFormat);

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

UINT EnumClipboardFormats(nFormat);

Ця функція перебирає присутні формати даних в буфері обміну і повертає номер наступного в списку або 0. Приклад застосування:

UINTnFormat= 0;

while ((nFormat= EnumClipboardFormats(nFormat)) != 0) { // перебір форматів }

Можна взнати кількість присутніх в буфері обміну форматів даних за допомогою функції

UINT CountClipboardFormats(void);

5) Зараз ми розглянемо правила застосування форматів даних CF_DSP... Ці дані призначені для використання тільки Вашим додатками.

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

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

HWND GetClipboardOwner(void);

яка поверне хендл вікна, що поклав дані. Якщо ви утрудняєтеся по хендлу визначити приналежність вікна до потрібного додатку, то Ви майже напевно знаєте, до якого класу воно повинно належати (оскільки і дані, і додаток, і клас вікон розроблені Вами). Тому Ви можете взнати ще і ім'я класу вікна:

intGetClassName(hWnd, lpsBuffer, nMaxCount);

Буфер обміну і стандартне вікно-редактор

Часто доводиться використати буфер обміну спільно із звичайним вікном редактора. Великих складностей тут немає, оскільки таке вікно автоматично підтримує операції обміну даними з буфером в форматі CF_TEXT. Єдине, що нам треба зробити - навчитися передавати редактору команди для здійснення цього обміну.

Це звичайно доводиться робити для того, що б додати меню, вмісне пункти Cut-Copy-Paste. Оскільки сам редактор, будучи дочірнім вікном, не має меню, то меню додається до нашого батьківського вікна. Тобто команди, отримані від меню, треба якось передати у вікно редактора.

При цьому заодно доводиться дозволяти/забороняти окремі пункти меню в залежності від наявності виділеного тексту в редакторі (Cut, Copy) і наявності потрібних даних в буфері обміну (Paste).

Для передачі звичайному редактору команд для обміну даними з буфером служать повідомлення

WM_PASTE 0 0L

вставити текст з Clipboard в поточну позицію каретки

WM_COPY 0 0L

скопіювати виділений текст з редактора в Clipboard

WM_CUT 0 0L

скопіювати виділений текст і видалити його з редактора

Ми повинні просто послати потрібне повідомлення редактору і він виконає все інше. Зверніть увагу на те, що ці повідомлення не є специфічними для редактора - вони мають префікс WM_ - тобто це повідомлення для звичайного вікна.

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

Для того, що б дозволяти або забороняти потрібні пункти меню можна скористатися функцією IsClipboardFormatAvailable для дозволу/заборони операції Paste і передачею повідомлення EM_GETSEL для з'ясування можливості операцій Cut і Copy.

Перегляд даних, що знаходяться в буфері обміну

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

WM_DRAWCLIPBOARD 0 0L

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

У якійсь мірі це схоже на обробку переривань DOS - система втримує хендл тільки першого вікна перегляду, той - хендл наступного і так далі.

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

HWND SetClipboardViewer(hWnd);

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

Далі, при оновленні даних в буфері обміну, Ваше вікно отримує повідомлення WM_DRAWCLIPBOARD. Обичнаяобработкаетогосообщенія:

case WM_DRAWCLIPBOARD: if (hWndNextViewer) PostMessage(hWndNextViewer, wMsg, wParam, lParam); InvalidateRect(hWnd, NULL, TRUE); return 0;

Внаслідок обробки цього повідомлення вікно програми перегляду перемальовується, і таке ж повідомлення отримує інша програма.

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

BOOL ChangeClipboardChain(hWndViewer, hWndNextViewer);

Що значить: замість вікна hWndViewer буде використовуватися вікно hWndNextViewer. Ця функція звичайно викликається при обробці повідомлення WM_DESTROY. Внаслідок виконання цієї функції перша програма перегляду в ланцюжку отримає повідомлення (WM_CHANGECBCHAIN, hWndRemoved, hWndNext). Це повідомлення обробляється так:

case WM_CHANGECBCHAIN: if (wParam == hWndNextViewer) { hWndNextViewer= LOWORD(lParam); } else if (hWndNextViewer) { PostMessage(hWndNextViewer, wMsg, wParam, lParam); } return 0;

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

Відображення даних програмою перегляду відбувається також, як і їх звичайне читання (відкрив-прочитав-закрив).

Динамічний обмін даними (DDE)

Поки що ми розглянули тільки один спосіб обмінюватися даними між різними додатками - буфер обміну. Однак цей спосіб не завжди ефективний. У більшості випадків він обмежений застосуванням в редакторах.

Однак необхідність обміну даними між різними додатками реально існує, тому Windows містить ще один засіб для такого обміну - DDE (Dynamic Data Exchange).

DDE заснований на використанні повідомлень для передачі даних між двома додатками. При цьому один з додатків (звичайно вмісне дані) називається сервером (server), а інше (що звичайно вимагає даних) - клієнтом (client). У більш загальному вигляді: клієнт виступає в ролі активного додатку, що вимагає, що б його запити були обслужені сервером. Сам процес обміну даними коштами DDE між клієнтом і сервером називається DDE-розмовою (DDE-conversation).

Звичайно протокол обміну даними між клієнтом і сервером виглядає приблизно таким чином:

- клієнт передає всім доступним додаткам повідомлення про те, що йому треба.

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

- клієнт посилає запит (и) серверу для виконання вимог.

- в деяких випадках сервер може інформувати клієнта про зміну або наявність тих або інакших даних. Для цього клієнт повинен підписатися (advise) на необхідні дані.

- обмін між клієнтом і сервером може продовжуватися доти, поки один з них не зажадає припинення.

У процесі DDE-розмови відбувається обмін сполученнями між двома додатками. Зрозуміло, що адресатами таких повідомлень є не самі додатки, а їх вікна. У більшості випадків для нормального ведіння DDE-розмови створюються спеціальні приховані (невидимі) вікна, які і здійснюють обмін сполученнями між собою. Звісно, в DDE можуть брати участь вікна одного додатку, не тільки різних, але треба врахувати, що DDE для обміну даними в межах одного додатку є неефективним. Оскільки процеси підготовки і прийому даних можуть займати значний час, то потрібно, щоб для обміну повідомленнями використовувалася функція PostMessage, а не SendMessage (крім встановлення DDE-розмови). Це, правда, створює додаткову складність - необхідність синхронізації дій різних вікон між собою.

У Windows міститься все необхідне для організації DDE, причому в двох примірниках. Крім старого способу, існуючого з перших версій Windows, в Windows версії 3.1 була додана спеціальна бібліотека DDEML (DDE Management Library), що є "надбудовою" над старим способом і призначена для формалізації протоколів обміну. Істотна різниця між цими способами пов'язана з тим, що для організації DDE старим способом ви повинні передбачити обробку спеціальних повідомлень необхідними Вам вікнами, а бібліотека DDEML сама створює необхідні приховані вікна і організує обмін повідомленнями; при цьому для взаємодії з Вашим додатком DDEML буде викликати спеціально розроблену Вами CALLBACK процедуру (що не виявляє віконною процедурою).

Вважається, що при використанні DDEML дещо спрощується написання додатків, оскільки вона бере на себе питання синхронізації обміну. Однак на практиці не було помічено реального спрощення роботи в зв'язку із застосуванням бібліотеки. Більш того початковий текст може виявитися навіть більше, ніж при використанні старого методу.

Тому ми будемо розглядати тільки старий спосіб організації DDE. Заздалегідь ми введемо декілька термінів, що використовуються в DDE. Коли клієнт починає DDE або вимагає дані, він посилає серверу специфікацію того, що він вимагає.

Ця специфікація складається з 3 пунктів:

- ім'я додатку - application (в DDEML називається сервіс (service)); оскільки в більшості випадків в документації застосовується термін service, то його ми і будемо використовувати далі. Хоч, треба відмітити, цей параметр звичайно задає умовне ім'я додатку-сервера.

- тему DDE-розмови - topic

- необхідні дані - item

Ім'я сервісу і тема DDE-розмови используютсяпри встановленні зв'язку. Внаслідок цього в системі повинне бути встановлений обмін даними між однією або декількома парами вікон, які підтримують дані сервіс і тему. Одне з вікон в кожній парі буде бути клієнтом, а інше - сервером. У процесі подальшої DDE-розмови може відбуватися обмін даними, ім'я яких задається окремо і є можливим ім'ям даних для даного сервісу і теми.

Ці три імена представлені у вигляді атомів (ATOM), тому нам треба розібратися з атомами і правилами їх застосування перед продовженням розмови об DDE.

Атоми

Атомами в Windows називаються нумеровані рядки тексту, що зберігаються в спеціальній таблиці. Максимальний розмір рядка 255 символів. При приміщенні рядка в таблицю їй привласнюється унікальний номер, який власне і використовується замість самого рядка. Часто атомом називають саме ці номери, а рядки - іменами атомів. Обидві платформи (Windows 3.x і Win32) використовують для завдання атомів 16-ти розрядні числа, звані ATOM, що дозволяє в одному двійчастому слові передавати до двох атомів.

Якщо додавати два однакових рядки в таблицю атомів, то вони отримають однаковий номер. На цьому заснований один з способів порівняння рядків - додати обидва рядки в таблицю і порівняти атоми (не забудьте після цього видалити доданий атом, навіть якщо це було треба тільки для перевірки).

Для кожного додатку доступні дві таблиці атомів - локальна і глобальна. Оскільки DDE підтримується між різними додатками те, очевидно, повинна застосовуватися тільки глобальна таблиця атомів.

Для роботи з глобальними атомами призначені наступні функції:

ATOM GlobalAddAtom(lpszName); UINT GlobalGetAtomName(aAtom, lpsBuffer, nMaxCount); ATOM GlobalFindAtom(lpszName); ATOM GlobalDeleteAtom(aAtom);

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

Для роботи з локальними атомами використовуються аналогічні функції, але не маючі на початку слова "Global". Крім цього для роботи з локальною таблицею атомів додана ще одна функція:

ATOM AddAtom(lpszName); UINT GetAtomName(aAtom, lpsBuffer, nMaxCount); ATOM FindAtom(lpszName); ATOM DeleteAtom(aAtom);

BOOL InitAtomTable(UINT cTableEntries);

Яка дозволяє указати максимальне число рядків, що вміщуються в локальну таблицю атомів. За умовчанням це число дорівнює 37 (розмір глобальної таблиці атомів змінити не можна). При роботі з локальною таблицею атомів видаляти атоми в кінці роботи додатку необов'язково - при завершенні роботи всього додатку таблиця буде автоматично видалена.

При обміні даними за допомогою DDE відбувається послідовна посилка повідомлень від одного додатку до іншого і навпаки. Одна DDE транзакція звичайно складається з двох - трьох послідовних повідомлень. У цих повідомленнях часто передаються необхідні імена, представлені у вигляді глобальних атомів. При цьому виникає необхідність так організувати обмін повідомленнями, що б забезпечити видалення всіх атомів, що знову додаються. Для цього прийняте таке рішення: додаток, що посилає атоми разом з повідомлення повинне ці атоми створити, а потім перевірити код завершення функції PostMessage - якщо посилка пройшла успішно, то атом повинен бути звільнений приймаючим додатком, а якщо при посилці виникла помилка, то атом повинно видалити посилющее додаток. У деяких випадках атом, отриманий додатком з повідомленням, може бути посланий разом з повідомленням у відповідь назад (крім повідомлення WM_DDE_INITIATE, про що див. нижче). У цьому випадку не обов'язково атом видаляти а потім створювати знов, можна використати отриманий; однак необхідно пересвідчитися, що він був посланий з повідомлення у відповідь і, якщо посилка не відбулася, його треба видалити.

Особливості завдання параметра lParam повідомлень DDE

Потрібно врахувати деякі відмінності в застосуванні параметра lParam повідомлень DDE на 16-ти і 32-х розрядних платформах (Windows 3.x і Win32). Справа в тому, що спочатку цей параметр використовувався для передачі двох значень, часто атома імені даних і хендла глобального блоку. У разі 32-х розрядної платформи хендл блоку сам займає двійчасте слово і розміститися в lParam спільно з атомом імені даних не може.

Для розв'язання цієї проблеми були введені спеціальні функції, що здійснюють "упаковку" двох вказаних значень (званих молодшим і старшим) в одне двійчасте слово. Фактично можна вважати, що виділяється спеціальна структура, вмісна пару полів, ідентифікатор якої використовується в якості lParam.

Оскільки різні повідомлення DDE використовують lParam різним образом, то і упаковка даних здійснюється не для кожного повідомлення, так що для кожного повідомлення треба перевіряти необхідність використання цього механізму, а для повідомлення WM_DDE_ACK треба ще перевірити, у відповідь на яке повідомлення він посланий. Для роботи з "упакованими" даними необхідно застосовувати спеціальні функції:

LONGPackDDElParam(UINTuMsg, UINTuLow, UINTuHigh); LONGUnpackDDElParam(UINTuMsg, LONGlParam, PUINTpuLow, PUINTpuHigh); LONGFreeDDElParam(UINTuMsg, LONGlParam); LONGReuseDDElParam(LONGlParam, UINTuMsgIn, UINTuMsgOut, UINTuLow, UINTuHigh);

Функція PackDDElParam упаковує вказані дані в проміжну структуру, хендл якої повертається у вигляді LONG; значення, що повертається може бути використане тільки для передачі даних за допомогою функції PostMessage і тільки для деяких повідомлень DDE. Функція UnpackDDElParam виконує зворотну операцію, але проміжна структура даних при цьому зберігається. Для того, що б її видалити необхідно використати FreeDDElParam. Остання функція ReuseDDElParam може застосовуватися для використання однієї структури при повторній передачі даних або відповіді на прийняте повідомлення. Як параметр lParam функції PostMessage необхідно вказувати те, що повертається, а не первинне значення.

У описі параметрів повідомлень ми зберігаємо колишній синтаксис, причому lParam може як і раніше задаватися у вигляді двох компонент старший & молодший. Єдина відмінність, що під старшим і молодшим компонентом не треба мати на увазі слова, а для отримання цих компонентом може бути потрібна функція UnpackDDElParam, про що в описі повідомлення буде зроблена спеціальна обмовка. У рідких випадках можуть даватися два описи параметрів, для Windows 3.x і для Win32. Для відмінності цих варіантів в описі параметрів повідомлення можуть бути додані спеціальні пояснення

(Packed Win32) - якщо параметр упаковується у разі платформи Win32

(Windows 3.x) - якщо опис застосовується тільки у випадку Windows 3.x

(Win32) - якщо опис застосовується тільки у випадку Win32

DDE, початок обміну і його завершення

Коли ми говорили про загальний вигляд протоколу DDE, ми відмітили, що він заснований на обміні повідомленнями. У більшості випадків повідомлення посилаються (post) а не передаються (send). При цьому додаток, те, що посилає повідомлення не має можливості дочекатися обробки цього повідомлення. Тому ті дані, які посилаються одним додатком, повинні бути знищені іншим, що б вони не залишалися в пам'яті. Єдине виключення з цього правила - повідомлення WM_DDE_INITIATE і відповідь на нього (WM_DDE_ACK) які завжди передаються, а не посилаються.

При початку DDE-розмови посилається повідомлення

WM_DDE_INITIATE hWnd aTopic & aService

це повідомлення використовується для початку DDE-розмови. Параметр wParam містить хендл вікна, що послало, а lParam в молодшому слові - атом aService, а в старшому - атом aTopic, задаючі, відповідно, сервіс і тему DDE-розмови. Нульові значення атомів вказують відповідно на будь-яку тему, що підтримується і будь-який сервіс. Передача: Коли клієнт викликає функцію SendMessage для встановлення DDE-розмови, він створює необхідні атоми, а після повернення з функції SendMessage він зобов'язаний ці атоми видалити. Отримання: сервер, що отримав це повідомлення, і підтримуючий вказані сервіс і тему відповідає повідомленням WM_DDE_ACK. При цьому він зобов'язаний створити наново необхідні атоми - використати атоми, отримані з повідомленням заборонено. Значення атомів aTopic і aService рівні 0 вказують, відповідно, на будь-яку тему, що підтримується сервером і сервіс. У цьому випадку сервер повинен відповісти стільки разів, скільки відповідних тим і сервісів він підтримує.

Це повідомлення передається всім додаткам (як хендла вікно-одержувач повідомлення використовується HWND_BROADCAST або -1). Той сервер, який підтримує дану тему і сервіс повинен відповісти на цей запит передачею повідомлення

WM_DDE_ACK hWnd aTopic & aService

повідомлення, підтверджуюче прийняте раніше повідомлення. Параметр wParam містить хендл вікна, що послало, а lParam використовується різними способами, в залежності від того, яке повідомлення викликало це підтвердження. У залежності від значень параметрів повідомлення розглядають позитивні і негативні підтвердження. При відповіді на WM_DDE_INITIATE молодше слово lParam містить атом сервісу, а старше - атом теми, при цьому WM_DDE_ACK не посилається, а передається за допомогою функції SendMessage, причому воно розглядається тільки як позитивне, оскільки як негативна відповідь використовується відсутність цього повідомлення. Якщо WM_DDE_ACK отримане у відповідь на WM_DDE_INITIATE, то для обох платформ - Windows 3.x і Win32 воно використовується однаково; а якщо воно отримане у відповідь на яке-небудь інакше повідомлення, то параметр lParam буде використаний для передачі "упакованого" значення. Отримання: додаток-клієнт, повідомлення, що отримало WM_DDE_ACK зобов'язано видалити все супроводжуючі його атоми. Передача: при відповіді на WM_DDE_INITIATE заборонено використати отримані атоми, сервер зобов'язаний створити необхідні для відповіді атоми і послати їх (оскільки на одне WM_DDE_INITIATE може відповісти декілька серверів, а при обробці WM_DDE_ACK клієнт зобов'язаний видаляти всі атоми).

Якщо WM_DDE_ACK передається у відповідь на повідомлення WM_DDE_INITIATE, то в lParam містяться такі-же дані, що і у повідомлення WM_DDE_INITIATE. Це вважається позитивним підтвердженням. Якщо відповідь негативна, то підтвердження при ініціалізації просто не видається.

У більшості випадків сервер, що відповідає на WM_DDE_INITIATE, створює спеціальне вікно для кожної DDE-розмови. Це пов'язано з тим, що при подальшому обміні даними сервіс і тема вказуватися не будуть, а сама DDE-розмова визначається фактично вікном-клієнтом і вікном-сервером. Одна така пара вікон обмінюється даними тільки в рамках вказаних при встановленні DDE-розмови теми і сервісу. Тільки самі прості DDE-сервери можуть обійтися одним вікном, але при цьому вони в даний момент часу можуть працювати тільки з одним клієнтом.

Увага! При встановленні зв'язку з яким-небудь сервером Ви можете отримати декілька повідомлень WM_DDE_ACK від різних серверів, підтримуючих вказані сервіс і тему. Якщо в повідомленні WM_DDE_INITIATE ви указали будь-яку тему, що підтримується і/або будь-який можливий сервіс, то практично завжди відповідають відразу декілька серверів. У цьому випадку Ви повинні створювати список всіх тим і сервісів, з якими встановлюється зв'язок даною операцією (не забудьте в кінці закрити всі початі DDE-розмови), а якщо ви маєте намір працювати тільки з одним з серверів, що відповіли, то з всіма іншими ви повинні завершити DDE-розмову посилкою WM_DDE_TERMINATE.

Зауваження. Згідно з документацією сервер, що отримав WM_DDE_INITIATE з вказівкою будь-якої теми, що підтримується або сервісу, зобов'язаний відправити у відповідь стільки повідомлень WM_DDE_ACK, скільки тим і сервісів він підтримує. Насправді багато які DDE сервери цього не роблять, як, наприклад, Microsoft Internet Explorer. Такі сервери відповідають тільки на точно вказані сервіс і тему. Це може бути виправдане, якщо сервер підтримує значне число тим або сервісів. При відповіді на WM_DDE_INITIATE вже устанавливаетя DDE-розмову, для якої сервер створює окреме вікно і, відповідно, витрачає ресурси. Якщо сервер відповідає на цілий список тим і/або сервісів, то створюється багато вікон, що, швидше усього, зайво. Суворо говорячи, вказувати будь-яку тему або сервіс треба тільки у разі реальної необхідності, оскільки одним таким запитом можуть бути встановлені декілька десятків DDE-розмов відразу (так, наприклад, один тільки Netscape Navigator відповідає приблизно 3 десятками що підтримуються ним тим).

Початок DDE-розмови - це єдиний випадок, коли повідомлення DDE передаються з допомогою SendMessage, а не PostMessage. Це необхідне для нормального початку обміну.

Зараз ми розглянемо невеликий приклад взаємодії двох додатків, клієнта і сервер при початку DDE-розмови.

У даному прикладі розглянутий самий простий випадок, коли зв'язок встановлюється тільки з одним сервером і для однієї теми. При цьому можна обійтися без створення списку сервісів і тим, з якими встановлюються з'єднання.

Вважається, що при ініціалізації DDE-розмови, клієнт повинен отримати відповідь (або пересвідчиться в його відсутності) негайно. Цього можна досягнути тільки використовуючи передачу, а не посилку повідомлень. У цьому випадку підтвердження приходить в той час, поки клієнт чекає завершення роботи процедури SendMessage. Для нормального продовження DDE клієнт повинен запам'ятати хендл сервера (а сервер - хендл клієнта).

Оскільки можливий випадок, що на запит клієнта відповідять два і більше за сервери, то треба передбачити або відмова від встановлення більш ніж одного з'єднання (як в приведеному прикладі), або організувати DDE відразу з декількома серверами.

Якщо клієнт отримав позитивну відповідь від сервера, то він може почати обмін даними. Цей обмін буде продовжуватися доти, поки обидва додатки не обміняються повідомленнями

WM_DDE_TERMINATE hWnd 0L

повідомлення закінчує DDE-розмову. Параметр hWnd є хендлом вікна, що послало. При цьому знищуються допоміжні структури і обнуляються змінні.

Послати WM_DDE_TERMINATE може як клієнт, так і сервер. Обидва вони повинні бути готові до прийому такого повідомлення від напарника.

Обмін даними між клієнтом і сервером

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

У DDE розрізнюють три способи отримання даних від сервера, званих видами зв'язку. Ці три вигляду зв'язку називаються холодна, тепла і гаряча. Коротко пояснимо відмінності цих видів зв'язку:

- холодний зв'язок - cold link

обмін даними відбувається тільки по запиту клієнта. Сервер посилає у відповідь дані або негативне підтвердження.

- гарячий зв'язок - hot link

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

- теплий зв'язок - warm link

клієнт, як і при гарячому зв'язку, підписується на отримання оновлених даних. Однак сервер передає не дані, а тільки повідомлення про те, що у нього є дані для клієнта. Клієнт може зажадати дані у сервера в будь-який зручний для нього момент.

Останні два вигляду зв'язку (тепла і гаряча) називаються іноді постійним (permanent) зв'язком.

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

Коли два додатки обмінюються даними один з одним, вони передають один одному хендли блоків даних і атоми. Для того, що б ці дані були доступні обом додаткам, вони повинні бути глобальними. Однак треба врахувати, що звичайно глобальні блоки даних пов'язані з тим додатком, який їх створив, тобто при завершенні додатку ці дані автоматично знищуються. Оскільки процес DDE-розмови є асинхронним, то необхідно забезпечувати збереження даних незалежно від існування їх додатку, що створив. Для цього глобальні блоки даних повинні бути такими, що розділяються - при їх виділенні треба вказувати прапор GMEM_DDESHARE (або GMEM_SHARE, який є синонімом).

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

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

"Холодний" зв'язок - cold link

При холодному зв'язку обмін даними активується клієнтом. Для цього клієнт посилає спеціальне повідомлення, у відповідь на яке сервер відправляє дані (якщо може), або повідомлення про помилку:

WM_DDE_REQUEST hWnd aItem & cfFormat

це повідомлення є вимогою передачі даних. Параметр wParam є хендлом вікна, що послало повідомлення, а lParam містить в молодшому слові номер формату даних (номери ті-же, що використовуються буфером обміну), а в старшому - атом імені даних. Платформи Win32 і Windows 3.x використовують це повідомлення однаково.

У відповідь на це повідомлення сервер може відповісти або повідомленням WM_DDE_DATA, якщо він має необхідні дані і може їх послати, або "негативним" повідомленням WM_DDE_ACK, вказуючим, що сервер не може послати необхідні дані.

WM_DDE_DATA hWnd aItem & hData (Packed Win32)

Це повідомлення передає дані клієнту. Молодший компонент lParam містить хендл глобального блоку, що розділяється даних hData. Цей параметр може бути рівний 0, що реально зустрічається тільки у разі "теплого" зв'язку (див. нижче). Блок даних, що Передається повинен починатися зі структури DDEDATA, прапор fAckReq якої вказує на необхідність відправки підтвердження про отримання даних. Передача: сервер не може скидати одночасно обидва біти fRelease і fAckReq в 0. Тобто коректними є тільки три можливих комбінації fRelease і fAckReq, при яких можна визначити, хто повинен звільняти блок даних - клієнт або сервер. Звільнення ресурсів: атом aItem повинен віддалятися, якщо тільки він не посилається з повідомлення у відповідь WM_DDE_ACK (якщо біт fAckReq заголовка даних рівний 1, тобто потрібно відповідь). Звільнення блоку даних залежить від установки бітів fRelease і fAckReq заголовка даних:

fRelease

fAckReq

0

1

блок даних завжди звільняється сервером при отриманні відповіді від клієнта (вважається, що до моменту отримання сервером підтвердження клієнт вже прочитав необхідні дані і їх йому більше не потрібні).

1

0

блок даних завжди звільняється клієнтом, сервер відповіді не отримує (так клієнт може деякий час зберігати отримані дані незалежно від течії DDE-розмови).

1

1

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

Структура DDEDATA містить наступні дані:

typedef struct tagDDEDATA { WORD unused:12, fResponse:1, // 1 у відповідь на WM_DDE_REQUEST, 0 - WM_DDE_ADVISE fRelease:1, // дані повинні бути видалені після отримання reserved:1, fAckReq:1; // 1 - необхідно послати підтвердження про прийом short cfFormat; // формат даних BYTE Value[1]; // самі дані } DDEDATA;

Увага! в документації по Windows 3.x SDK і Win32 SDK містилася помилка - там були переплутані пояснення до полів fResponse і fAckReq, так що опис структури DDEDATA суперечив опису повідомлення WM_DDE_DATA. У документації, супроводжуючій компілятор Microsoft Visual З++ v4.0 ця помилка була виправлена.

Помітьте, що сервер може зажадати підтвердження про прийом посланих даних. Для цього він встановлює біт fAckReq в заголовку переданих даних рівним 1. У такому випадку необхідно послати повідомлення у відповідь WM_DDE_ACK (позитивне або негативне, якщо виникла яка-небудь помилка).

Якщо сервер не має потрібних даних, то замість WM_DDE_DATA клієнт отримає WM_DDE_ACK (негативне)

WM_DDE_ACK hWnd aItem & wStatus (Packed Win32)

Молодший компонент lParam містить інформацію про підтвердження, що посилається. Молодший байт цього слова містить код, що повертається додатком, старший байт містить два що означають біти 0x80 і 0x40. Часто цей параметр представляється у вигляді структури DDEACK. Старше слово lParam являє собою атом, що ідентифікує дані. Згідно з документацією цей атом обов'язково повинен бути видалений при обробці цього повідомлення. У разі платформи Win32 параметр lParam використовується для передачі "упакованого" значення; при цьому треба пам'ятати, що якщо WM_DDE_ACK приходить у відповідь на WM_DDE_INITIATE, то параметр lParam містить звичайні, не упаковані дані.

Структура DDEACK містить наступні дані:

typedef struct tagDDEACK { WORD bAppReturnCode:8, // код, визначуваний додатком reserved:6, fBusy:1, // 1 - сервер зайнятий і не може обробити запит fAck:1; // 1 - повідомлення було отримане додатком } DDEACK;

У залежності від значень бітів fBusy і fAck розрізнюють наступні можливі види відповідей:

- fAck = 1 fBusy = 0 - позитивне підтвердження

- fAck = 0 fBusy = 0 - негативне підтвердження

- fAck = 0 fBusy = 1 - сервер зайнятий, або не може обробити запит в розумні терміни (що є "розумні" терміни - не пояснюється)

- Згідно з документацією установка обох прапорів fAck і fBusy одночасно повинна бути виключена.

Замість структури DDEACK часто використовують просто бітові шаблони - 0x8000 відповідає позитивному підтвердженню, 0 - негативному і 0x4000 - сервер зайнятий (взагалі говорячи, це також негативне підтвердження, хоч запит можна спробувати повторити).

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

// // wait for time out // static BOOL TimeOut(HWND hWnd, UINT wMsg, UINT uTimeOut) { DWORD dwTime; MSG msg;

// FALSE design normal termination // TRUE design time-out or negative WM_DDE_ACK dwTime= GetCurrentTime(); while (dwTime + uTimeOut > GetCurrentTime()) { if (PeekMessage(&msg, hWnd, NULL, NULL, PM_REMOVE)) { // обработатьполученноесообщение TranslateMessage(&msg); DispatchMessage(&msg); if (msg.message == WM_DDE_ACK) { // check for. fAck return LOWORD(msg.lParam) & 0x8000? FALSE: TRUE; } else if (msg.message == wMsg) return FALSE; } }

return TRUE; }

Звичайно процедура, що чекає потрібне повідомлення, виглядає трохи інакше. Це пов'язано з бажаним відображенням курсора очікування (у вигляді пісочних годин), а також з обробкою повідомлень, витягнутих з черги. У багатьох випадках нормальна обробка повідомлень не зводиться тільки до функцій TranslateMessage і DispatchMessage, але також включає підтримку акселераторів, немодальних діалогів і пр. Крім цього потрібно врахувати, що у разі платформи Windows 3.x розмір черги повідомлень додатку порівняно невеликий - так що при видобуванні повідомлень, направлених тільки конкретному вікну, черга може легко переповнитися.

Ще одне зауваження торкається часу очікування відповіді від сервера. Цей проміжок не треба призначати дуже великим, але в той же час він повинен вистачати, що б навіть на повільних машинах упевнено отримувати відповідь від сервера. При надлишково великому часі очікування відповіді може виникати враження "зависання" додатку, поки воно чекає відповіді. Звичайно людина чекає від комп'ютера майже миттєвої реакції або, в гіршому випадку, явно видимої роботи. Якщо програма зупиняється на термін більш 10-15 секунд, то вже виникає неспокій про її роботу.

Практично прийнятним є інтервал порядку 5-30 секунд, оскільки на середній машині відповідь може затримуватися до 5-10 секунд при нормальній роботі і, відповідно, на повільних машинах інтервал потрібно збільшити приблизно до тридцяти секунд. (Відмінність між швидкими і повільними машинами вельми відносна - із зростанням потужності комп'ютерів зростає навантаження на них, тому час виконання більш-менш значних операцій знижується порівняно повільно). Можливим рішенням є двухетапное очікування - перший етап до 3-6 секунд проходить як звичайно, а після закінчення цього інтервалу відображається вікно діалогу з кнопкою "Cancel", після чого очікування продовжується або до отримання відповіді, або до скасування очікування користувачем. Це дозволяє користувачу оцінити зайнятість системи і, при необхідності, продовжити очікування в розумних межах.

Задача визначення часу очікування відповіді від сервера є досить важливою через необхідність звільняти зайняті ресурси. Фактично, при обміні повідомленнями виникає наступна ситуація: при посилці яких небудь об'єктів, що розділяються від одного додатку до іншого (це можуть бути атоми або глобальні блоки даних) необхідно ці об'єкти видаляти після їх використання. Однак тут треба врахувати наступний нюанс:

- якщо функція PostMessage не може послати повідомлення, об'єкти можна видаляти відразу, оскільки другий додаток їх не отримає.

- якщо повідомлення послане, то момент знищення об'єктів вибирається відповідно до опису повідомлення в документації. Так, наприклад, атоми звичайно віддаляються по наступній схемі

- при отриманні посланого запиту перевіряється необхідність відповіді, якщо відповідь потрібна, то атом передається разом з відповіддю і знищується додатком, що послав запит

- якщо відповідь потрібна, але його послати не вдається, то атом знищується додатком, що отримав запит

- якщо відповідь не потрібна, то атом знову-же знищується додатком, що отримав запит

- послане повідомлення може "не дійти" до адресата (наприклад, якщо вікно-одержувач буде закрито вже після того, як до нього в чергу попаде це повідомлення, але до його обробки). При цьому відповіді не буде, а додаток-одержувач звільнити ресурси не зможе.

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

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

"Гарячий" зв'язок - hot link

Протокол при гарячому зв'язку. Після ініціація обміну клієнт посилає запит WM_DDE_ADVISE, вказуючи бажані дані. Сервер відповідає про можливість гарячого зв'язку, і, звичайно, відразу ж посилає перші дані, для ініціація клієнта. Таким чином осуществялется як-би "підписка" на отримання необхідних даних при їх зміні. Цей вигляд зв'язку зручний, якщо Вам необхідно взаємодіяти з якою-небудь базою даних, вміст якої може динамічно оновлюватися, як наприклад база даних "товари на складі" для великих магазинів - доступ до цієї бази одночасно можуть мати різні відділи магазина і список товарів, що є на сладе, постійно змінюється. Використання гарячого зв'язку в цьому випадку дозволить створити локальні списки на комп'ютерах різних відділів і автоматично оновлювати їх, як тільки здійснюється зміна загальної бази даних.

WM_DDE_ADVISE hWnd aItem & hOptions (Packed Win32)

Молодший компонент параметра lParam містить хендл глобального блоку, що розділяється, вмісного невелику структуру DDEADVISE, а старший компонент - атом, що описує дані на які здійснюється підписка. Структура DDEADVISE визначає тип зв'язку - гаряча або холодна, а також необхідність вимагати підтвердження про доставку даних від клієнта. У разі платформи Win32 параметр lParam використовується для передачі "упакованого" значення. Сервер, що отримав це повідомлення зобов'язаний відповісти на нього посилкою підтвердження WM_DDE_ACK, позитивного або негативного. Звільнення ресурсів: Клієнт, що послав запит, повинен дочекатися відповіді від сервера. Якщо відповідь позитивна, то блок даних повинен бути видалений сервером, а якщо негативний, то клієнт повинен сам його видалити.

Структура DDEADVISE містить наступні дані:

typedef struct { WORD reserved:14, fDeferUpd:1, // 1-"теплий" зв'язок, 0-"гарячий" fAckReq:1; // 1-необхідно вимагати підтвердження, 0-не треба short cfFormat; // бажаний формат даних } DDEADVISE;

При завданні біта fDeferUpd рівним 1 здійснюється так званий теплий зв'язок, при якому сервер тільки інформує про наявність у нього змінених даних, але не посилає їх клієнту безпосередньо. У разі гарячого зв'язку цей біт должет бути рівний 0. Біт fAckReq, рівний 1, вказує на необхідність вимагати від клієнта підтвердження про отримання даних. Пізніше, коли сервер почне посилати клієнту повідомлення WM_DDE_DATA він встановить в структурі DDEDATA біт fAckReq відповідним тому, який Ви указали в структурі DDEACK і, відповідно, клієнт повинен буде підтверджувати отримання ним даних від сервера (треба врахувати, що біт fAckReq впливає на стратегію звільнення даних, що посилаються - детальніше див. опис повідомлення WM_DDE_DATA).

Поле cfFormat вказує на формат даних, які клієнт чекає від сервера. Ви можете для одного вигляду даних в межах однієї DDE-розмови підписатися на отримання даних різного типу одночасно, посилаючи WM_DDE_ADVISE стільки разів, скільки форматів даних Ви хочете отримувати. Однак така можливість дозволена тільки для гарячого зв'язку. Згідно з документацією підписка на одні і ті-же дані в різних форматах для теплого зв'язку заборонена.

Сервер, при отриманні повідомлення WM_DDE_ADVISE, перевіряє можливість здійснити підписку на ці дані, створює необхідні йому структури даних і відповідає клієнту повідомленням WM_DDE_ACK - позитивним або негативним. Це повідомлення в цьому випадку використовується також, як і при відповіді на WM_DDE_DATA.

Якщо підписка здійснена успішно, то далі сервер починає сповіщати клієнта про оновлення даних, здійснюючи кожний раз пересилку цих даних клієнту за допомогою вже розглянутого повідомлення WM_DDE_DATA. Єдина відмінність від отримання даних у відповідь на WM_DDE_REQUEST полягає в тому, що біт fResponse структури DDEDATA рівний 0, тоді як при відправці даних по запиту він встановлюється в 1. Це дозволяє визначити причину отримання даних при обробці повідомлення.

Закінчується такий обмін посилкою WM_DDE_UNADVISE серверу. У цьому повідомленні вказується, від підписки на які дані клієнт відмовляється (оскільки теоретично один клієнт може підписатися відразу на декілька видів даних).

WM_DDE_UNADVISE hWnd aItem & cfFormat

Молодше слово параметра lParam описує формат даних, а старше слово - атом, що описує дані на які здійснюється підписка. У разі платформи Win32 параметр lParam використовується також, як і у випадку Windows 3.x. Якщо параметр cfFormat рівний 0, то відміняється підписка на вказані дані для всіх тих форматів, для яких була здійснена підписка. Якщо параметр aItem рівний NULL, то відміняється підписка на всі види даних в межах даної DDE-розмови. Сервер, обробивши це повідомлення, повинен послати у відповідь підтвердження WM_DDE_ACK, позитивне або негативне; при цьому якщо одна операція відміняє підписку на дані в різних форматах, то посилається тільки одне підтвердження.

Повідомлення WM_DDE_UNADVISE не еквивалентено WM_DDE_TERMINATE, після його обробки відміняється тільки підписка, а сама DDE-розмова продовжується, так що клієнт може встановити потім новий вигляд зв'язку з сервером. Сервер зобов'язаний відповісти на повідомлення WM_DDE_ADVISE позитивним або негативним підтвердженням.

"Теплий" зв'язок - warm link

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

Як і гарячий зв'язок, тепла встановлюється за допомогою повідомлення WM_DDE_ADVISE з єдиним виключенням - біт fDeferUpd структури DDEADVISE рівний 1, а не 0.

Далі сервер починає інформувати клієнта про оновлення (або наявності) у нього потрібних даних. Для цього використовується звичайне повідомлення WM_DDE_DATA, яке в цьому випадку не передає ніяких даних. Для цього параметр hData (молодше слово lParam або, у випадку Win32, молодша компонента, витягуваний з допомогою UnpackDDElParam) встановлюється рівним 0. Клієнт, отримуючи таке повідомлення без даних, може негайно запитати потрібні дані або просто запам'ятати, що дані змінилися і пізніше, при необхідності, отримати їх.

Помітьте, що у разі гарячого зв'язку ви можете підписатися відразу на отримання інформації про зміну одних і тих-же даних в різних форматах, а у разі теплого зв'язку це заборонене. Така заборона пояснюється тим, що при підтримці таких видів зв'язку для різних даних або одних і тих-же даних, але в різних форматах, клієнт повинен вести список даних і форматів на які здійснена підписка. При отриманні WM_DDE_DATA, що інформує про зміну даних ім'я даних задається параметром aItem (упакований в lParam), а формат даних - полем cfFormat структури DDEDATA. Однак у разі теплого зв'язку повідомлення WM_DDE_DATA не містить даних і, отже, інформація про формат даних недоступна, при цьому однозначно знайти запис в спике не представляється можливим, якщо тільки не накласти обмеження - при теплому зв'язку підписуватися можна на дані тільки в одному форматі, тоді запис списку буде однознано визначений ім'ям даних.

Для того, що б отримати потрібні дані, клієнт просто посилає окремий запит WM_DDE_REQUEST, як у разі холодного зв'язку. Таким чином теплий зв'язок є "гібридом" двох інших видів зв'язку - холодної і гарячої.

Скасування підписки у разі теплого зв'язку нічим не відрізняється від такого-же дії для гарячого зв'язку - клієнт посилає повідомлення WM_DDE_UNADVISE серверу, який відповідає на це підтвердженням.

Робота з DDE у разі теплого або гарячого зв'язку звичайно не викликає значних складностей; однак треба звернути увагу на можливість використання декількох видів зв'язку одночасно. Звичайно, при написанні додатків використовуються припущення типу "У відповідь на послане WM_DDE_REQUEST повинно прийти або WM_DDE_DATA, або WM_DDE_ACK". Однак в житті ситуація може виявитися істотно складнішою - якщо одне вікно використовує декілька з'єднань, то у відповідь на посланий WM_DDE_REQUEST спочатку може прийти повідомлення WM_DDE_DATA, що інформує про отримання даних (у разі теплого або гарячого зв'язку) і тільки потім справжня відповідь на WM_DDE_REQUEST. Для того, що б зменшити імовірність таких ситуацій, для кожної DDE-розмови створюють спеціальне приховане вікно, взаємодіюче з сервером (або клієнтом). Однак при розробці власних прикладних застосувань таку можливість все-одинаково треба враховувати, оскільки в процедурах обробки повідомлень доведеться перевіряти, в зв'язку з якою подією отримане те або інакше повідомлення; а при розробці DDE-клієнтів треба постаратися розділити різні види обміну даними або по різних DDE-розмовах, або за часом.

Передача даних від клієнта до сервера

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

WM_DDE_POKE hWnd aItem & hData (Packed Win32)

Повідомлення WM_DDE_POKE посилається клієнтом для передачі даних серверу. У разі платформи Windows 3.x молодший компонент параметра lParam містить хендл блоку даних, що передається, а старший - атом імені даних, що передаються. Блок даних, що Передається повинен бути глобальним і що розділяється і повинен починатися зі структури DDEPOKE. При посилці повідомлення WM_DDE_POKE використовується наступна стратегія звільнення блоку даних: він знищується додатком (клієнтом), що послав, якщо:

- в заголовку блоку біт fRelease рівний 0

- клієнт повернув негативну відповідь

- посилка даних не відбулася

додаток (сервер), що Отримав дані буде знищувати цей блок тільки якщо біт fRelease рівний 1 і сервер повертає позитивне підтвердження.

typedef struct { WORD unused:13, fRelease:1, // 1 - блок звільняється клієнтом fReserved:2; short cfFormat; // формат даних (див. формати буфера обміну) BYTE Value[1]; // дані } DDEPOKE, що передаються;

Сервер, той, що отримав це повідомлення повинен зберегти отримані дані і повідомити клієнту про результат виконання цієї операції посилкою повідомлення WM_DDE_ACK, позитивного або негативного. У цьому повідомленні може бути переданий отриманий атом імені даних, або отриманий може бути видалений, а для посилки підтвердження створений наново.

Виконання команд DDE

Крім механізму обміну даними між клієнтом і сервером DDE передбачає ще один спосіб взаємодії додатків - виконання сервером команд клієнта. Для того, що б указати серверу на необхідність виконання команди, клієнт повинен послати спеціальне повідомлення WM_DDE_EXECUTE, у відповідь на яке сервер намагається виконати команду і повідомляє клієнту про результат її виконання, посилаючи у відповідь повідомлення WM_DDE_ACK (позитивне або негативне).

WM_DDE_EXECUTE hWnd hCmd & 0 (Windows 3.x)

WM_DDE_EXECUTE hWnd hCmd (Win32)

Параметр lParam описує команду, що передається серверу. Для цього рядок, вмісний команду, вміщується в блок даних, що виділяється за допомогою функції GlobalAlloc з прапором GMEM_DDESHARE. У разі платформи Windows 3.x старше слово параметра lParam містить хендл цього блоку, а молодше - просто 0; А у разі платформи Win32 параметр lParam безпосередньо містить цей хендл. Звільнення ресурсів: блок даних, вмісний команду, повинен бути звільнений клієнтом при отриманні підтвердження від сервера. Разом з цим підтвердженням повертається хендл цього блоку, так що клієнт вільно може його звільнити.

У разі платформи Win32 рядок, вмісний команду може бути представлена UNICODE-рядком, але тільки в тому випадку, якщо обидва вікна, що беруть участь в DDE-розмові підтримують UNICODE, тобто обидва повертають TRUE при виклику функції IsWindowUnicode(hWnd).

У відповідь на повідомлення WM_DDE_EXECUTE сервер посилає повідомлення WM_DDE_ACK, що інформує про виконання команди (позитивне) або про невдачу (негативне). У цьому повідомленні повертається хендл блоку, вмісного команду, так що сервер може цей блок видалити, а також в параметрі wStatus - в молодшому байті - може бути повернений додатковий код, що уточнює результат або причину помилки (див. опис структури DDEACK, що представляє параметр wStatus в розділі, присвяченому холодному зв'язку).

WM_DDE_ACK hWnd hCmd & wStatus (Packed Win32)

Молодший компонент lParam містить інформацію про підтвердження, що посилається. Молодший байт цього слова містить код, що повертається додатком, старший байт містить два що означають біти 0x80 і 0x40. Часто цей параметр представляється у вигляді структури DDEACK. Старший компонент lParam являє собою хендл блоку, вмісного команду. Згідно з документацією цей блок обов'язково повинен бути звільнений при обробці цього повідомлення. У разі платформи Win32 параметр lParam використовується для передачі хендла "упакованих" даних.

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

Відповідно до документації Microsoft команда повинна являти собою рядок, що закінчується нульовим символом і вмісний одну або декілька команд. Кожна команда повинна бути взята в квадратні дужки [...]. Кожна команда складається з двох частин - імені команди і, можливо, списку параметрів. При цьому список параметрів береться в круглі дужки, а параметри в списку розділяються комами. Ім'я команди не може містити пропусків, дужок, ком і лапки; параметри можуть містити ці символи, але в такому випадку такий параметр повинен бути взятий в лапки, а символ лапки в тексті параметра представляється як лапки, що повторюється. У колишніх версіях DDE - для Windows 3.x - було потрібен, що б символи () [ ], ті, що зустрічаються в тексті параметра (в лапки) дублювалися; в той час як в Win32 це вже не потрібно. Проблема, однак, існує - в середовищі Win32 можуть бути запущені як 16-ти розрядні додатки, так і 32-х розрядні, при цьому можлива взаємодія таких додатків за допомогою DDE. У такій ситуації сервери повинні розпізнавати обидва варіанти представлення дужок - як що повторюються, так і не повторящиеся.

Приклади для Win32:

[команда] [команда1][команда2][команда_с_параметрами (параметр1, параметр2)][командаN] [команда (параметр1,'параметр2 з пропусками, дужками []() і "" лапки")]

У випадку Windows 3.x останній приклад буде виглядати так:

[команда (параметр1,'параметр2 з пропусками, дужками [[]](()) і "" лапки")]

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

Тема DDE-розмови "System"

Згідно з документацією Microsoft всім DDE-серверам, що знову розробляються рекомендується підтримувати в кожному сервісі спеціальну службову тему DDE-розмови "System". Ця тема призначена для отримання основної інформації про сервер. У межах цієї теми визначено декілька стандартних імен даних, до яких можна звернутися для отримання необхідної інформації.

На жаль самі розробники Microsoft не дуже суворо дотримують це правило. Так, наприклад, Microsoft Word і Microsoft Excel підтримують цю тему, а Program Manager, Explorer, Internet Explorer - не підтримують. Однак документація залишається документацією, тому при розробці власних DDE-серверів варто дотримуватися правил, що пропонуються.

При обміні даними з серверами, підтримуючими тему "System" треба дотримуватися наступних правил:

- для отримання даних використовується холодний зв'язок

- дані надаються тільки в форматі CF_TEXT

- за багатьма даними, що запитуються повертається список значень. Цей список представлений у вигляді рядка, що закінчується нульовим символом, окремі пункти якої відділяються символом табуляції (код - 9).

- При використанні DDEML ім'я теми "System" визначене в файлі DDEML.H як SZDDESYS_TOPIC.

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

При розробці власного сервера не обов'язково підтримувати всі приведені дані, одинаково як не обов'язково взагалі підтримувати тему "System" (хоч це бажане). Якщо Ви підтримуєте тільки деякі дані цієї теми, звернете увагу на дані "SysItems", які дозволяють клієнту взнати, які саме дані можна запитувати.

Назва теми для DDE Назва теми для DDEML

Опис

FormatsSZDDESYS_ITEM_FORMATS

Повертає список форматів, що підтримуються сервером даних. Звичайно назви співпадають з назвами форматів буфера обміну, але перші три символи "CF_" опущені. Тобто формат CF_BITMAP буде представлений як BITMAP. Рекомендується так упорядковувати назви форматів в списку, що б формати передаючі більше інформації були першими. Тобто, наприклад, формат DIB повинен бути розташований до формату BITMAP.

HelpSZDDESYS_ITEM_HELP

Пояснення до використання даного DDE сервера. Досить довільний текст, що бажано пояснює, які дані можуть бути отримані, які команди можуть бути виконані які дані можуть бути передані серверу і т. д.

ReturnMessageSZDDESYS_ITEM_RTNMSG

Інформація про останнє отправленом підтвердження WM_DDE_ACK. За допомогою цього типу даних можна передавати додаткові дані, що уточнюють результат виконання останньої транзакції.

StatusSZDDESYS_ITEM_STATUS

У відповідь на цей запит сервер повинен відправити рядок "Busy" або "Ready", що інформує про стан сервера. Помітьте, що цей рядок сервер повинен посилати, навіть якщо він зайнятий і не може обробляти інакші запити.

SysItemsSZDDESYS_ITEM_SYSITEMS

Повертає список імен даних, які представлені в темі "System". Цей список може використовуватися клієнтом, що б взнати, які дані він може запитувати в рамках теми "System".

TopicsSZDDESYS_ITEM_TOPICS

Повертає список тим, що підтримуються сервером в даний момент часу. У процесі роботи сервера цей список може змінюватися, так, наприклад, Microsoft Word відкриває окрему тему для роботи з кожним завантаженим документом.

TopicItemListSZDDE_ITEM_ITEMLIST

Аналогічне SysItems, повертає список даних, що підтримуються для даної теми. Цей запит може застосовуватися до тем, що не є темою "System". Цей список може змінюватися в процесі роботи сервера.

Program Manager як DDE-сервер

Program Manager є спеціалізованим DDE-сервером. Він дозволяє запущеним додаткам управляти конфігурацією груп додатків, змінювати їх атрибути і т. д. Звичайно програми установки додатків використовують DDE з Program Manager для створення необхідної групи і наповнення її елементами. У випадку Windows-94 або Windows NT v4.0 і вище за Program Manager звичайно не використовується, але працюючий при цьому Explorer підтримує ті-же самі сервіс, тему і команди, що і Program Manager. При цьому замість груп створюються підміню в меню Пуск¦Програма (Start¦Programs).

У принципі Windows може бути сконфигурирован так, що замість Program Manager використовується абсолютно інакша оболонка, яка може не підтримувати DDE, що описується. Можливим виходом з цієї ситуації є спроба запуску Program Manager (PROGMAN.EXE), якщо з першого разу не вдається встановити DDE-розмову.

Для взаємодії з Program Manager необхідно встановити DDE-розмову з сервером, підтримуючим сервіс і тему з однаковим ім'ям "PROGMAN", а потім можна передавати необхідні команди (повідомлення WM_DDE_EXECUTE). Команди, які підтримує Program Manager, дозволяють додатку створювати, відображати, видаляти і перезавантажувати групи, додавати, змінювати або видаляти елементи груп і завершувати роботу Program Manager. Для цього призначені наступні команди:

CreateGroup - створити групу програм

ShowGroup - показати групу у вказаному стані

Reload - перезавантажити групу з файла

DeleteGroup - видалити групу

AddItem - додати елемент

ReplaceItem - змінити елемент

DeleteItem - удалитьелемент

ExitProgman - вийтииз Program Manager

Program Manager обробляє команди в форматі, рекомендованому Microsoft. Тобто кожна команда береться в квадратні дужки, а якщо вона має додаткові параметри, то список параметрів береться в круглі дужки, причому параметри в списку розділені комами. У одному запиті до сервера можна указати декілька команд відразу, наприклад:

[ShowGroup( "Accessories", 1)][AddItem(myapp.exe,'My app", myapp.exe,5)]

Цей приклад додає елемент "My app" в групу "Accessories".

Крім виконання цих команд Program Manager може виконувати обмін даними з клієнтом, завдяки чому можливе отримання інформації про групи, що є і елементи цих груп. Для цього використовуються ті ж імена сервісу і теми "PROGMAN", що і для виконання команд, але при цьому серверу передаються запити на отримання даних по холодному зв'язку в форматі CF_TEXT.

Для того, що б отримати список груп, клієнт повинен прочитати дані з ім'ям "Group". У відповідь Program Manager поверне список груп, розділений символами переведення рядка.

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

Інформація про групу складається з:

- імені групи, взятого в лапки

- шляхи до файла групи (. grp)

- число елементів в групі

Інформація про елемент групи:

- команда, взята в лапки

- назва каталога

- шляхи до файла, вмісного піктограму

- індексу піктограми в файлі

- "гарячій клавіші" (в числовій формі)

- прапору мінімізованого стану при запуску додатку

Примітка: в документації затверджується, що на кількість елементів в групі накладене обмеження - не більше за 50 елементів на одну групу. Однак існує інакше, набагато більш жорстке обмеження - розмір grp-файла під Windows 3.x не може бути більше 64K. Цей розмір може бути легко перевищений, якщо використовуються відеорежим з великою кількістю кольорів (Hi-Color або TrueColor), наприклад 16, 24 або 32 біта на піксель. Справа в тому, що grp-файл містить в собі зображення всіх піктограм, розмір яких збільшується із збільшенням числа кольорів. При цьому граничний розмір grp-файла може бути досягнутий після десятка елементів (для TrueColor - приблизно 13 елементів).

Далі більш детально описуються команди, що обробляються Program Manager. При цьому ми будемо дотримуватися наступного синтаксису - опис самої команди в квадратні дужки не укладається, а необов'язкові параметри виділяються з їх допомогою. Для кращої читаемости параметри розділяються додатковим пропуском (при передачі команди цих пропусків бути не повинне).

Рекомендується додатково переглянути розділ "Виконання команд DDE" для отримання довідок про синтаксис запису команд і параметрів.

CreateGroup(GroupName [,CommonGroupFlag]) CreateGroup(GroupName [,GroupFile])

Команда CreateGroup створює вказану групу, або робить активною вже існуючу.

Параметри:

GroupName рядок, задаючий ім'я групи.

CommonGroupFlag параметр вказує, яка група створюється. Якщо він рівний 1, то створюється загальна група, а якщо 0, то персональна. Якщо працюючий користувач не має адміністративних привілеїв, то спроба створити загальну групу не вдасться. За умовчанням використовується 1 для користувачів, що мають в своєму розпорядженні привілеї адміністратора, і 0 для інших користувачів.

GroupFile в Windows 3.1 цей параметр задавав ім'я grp-файла. У старших версіях Windows як другий параметр розглядаються тільки 0 і 1, інакше цей параметр ігнорується.

ShowGroup(GroupName, ShowCommand [,CommonGroupFlag])

Команда ShowGroup дозволяє показати групу в нормальному, максимізованому або мінімізованому вигляді.

Параметри:

GroupName рядок, задаючий ім'я групи.

ShowCommand ціле число, вказуюче, в якому вигляді треба відобразити вікно групи.

1 - відобразити активним в нормальному стані

2 - відобразити активним в мінімізованому стані

3 - відобразити активним в максимізованому стані

4 - відобразити вікно групи в нормальному стані; активне вікно залишиться активним

5 - робить вікно групи активним, не змінюючи її розміру і положення

6 - мінімізує вікно групи

7 - мінімізує вікно групи; активне вікно залишиться активним

8 - відображає в поточному стані

CommonGroupFlag параметр вказує, яка група створюється. Якщо він рівний 1, то створюється загальна група, а якщо 0, то персональна. Якщо працюючий користувач не має адміністративних привілеїв, то спроба створити загальну групу не вдасться. За умовчанням використовується 1 для користувачів, що мають в своєму розпорядженні привілеї адміністратора, і 0 для інших користувачів.

Reload(GroupName [,CommonGroupFlag])

Ця команда примушує Program Manager видалити опис групи з пам'яті і завантажити grp-файл знов. Така можливість може застосовуватися, якщо програма модифікує безпосередньо grp-файл, а потім хоче відобразити зроблені зміни.

Параметри:

GroupName рядок, задаючий ім'я групи.

CommonGroupFlag параметр вказує, яка група створюється. Якщо він рівний 1, то створюється загальна група, а якщо 0, то персональна. Якщо працюючий користувач не має адміністративних привілеїв, то спроба створити загальну групу не вдасться. За умовчанням використовується 1 для користувачів, що мають в своєму розпорядженні привілеї адміністратора, і 0 для інших користувачів.

DeleteGroup(GroupName [,CommonGroupFlag]) DeleteGroup(GroupName [,GroupFile])

Команда DeleteGroup видаляє вказану групу.

Параметри:

GroupName рядок, задаючий ім'я групи.

CommonGroupFlag параметр вказує, яка група створюється. Якщо він рівний 1, то створюється загальна група, а якщо 0, то персональна. Якщо працюючий користувач не має адміністративних привілеїв, то спроба створити загальну групу не вдасться. За умовчанням використовується 1 для користувачів, що мають в своєму розпорядженні привілеї адміністратора, і 0 для інших користувачів.

GroupFile в Windows 3.1 цей параметр задавав ім'я grp-файла. У старших версіях Windows як другий параметр розглядаються тільки 0 і 1, інакше цей параметр ігнорується.

AddItem(CmdLine [Name [,IconPath [,IconIndex [,xPos, yPos [,DefDir [,HotKey [,fMinimize [fSeparateMemSpace] ] ] ] ] ] ])

Команда AddItem дозволяє додати в активну групу програмний елемент.

Параметри:

CmdLine рядок, задаючий команду, що здійснює запуск додатку. Цей рядок повинен містити ім'я додатку, а також може містити повний шлях до додатку і інші необхідні параметри.

Name задає ім'я елемента в групі. Якщо цей параметр опущений, то використовується ім'я додатку.

IconPath задає повне ім'я файла, вмісного ресурс піктограми, яка буде відображатися у вікні групи. Це може бути файл, що виконується Windows (. exe,.dll) або окрема піктограма (. ico). Якщо цей параметр опущений, то піктограма шукається в файлі додатку, причому, якщо вказаний файл не є приложеним, то використовується піктограма асоційованого з даним типом файлів додатку (асоціації задаються за допомогою реєстру Windows); а якщо і це не вдається, то використовується піктограма за умовчанням.

IconIndex задає індекс піктограми в файлі, визначеному параметром IconPath.

xPos, yPos задають положення піктограми у вікні групи. Ці параметри представлені цілими числами. Якщо позиція не задана, то Program Manager знаходить перше невживане місце.

DefDir задає ім'я робочого каталога додатку.

HotKey задає "гарячу" клавішу, що використовується для виклику додатку.

fMinimize вказує чи, треба- відображати вікно додатку при запуску у вигляді піктограми.

fSeparateMemSpace вказує чи, треба- запускати 16-ти розрядний додаток в самостійному адресному просторі (використовується на деяких платформах Win32).

ReplaceItem(ItemName)

Команда ReplaceItem використовується для заміни одного елемента іншим. При виконанні цієї команди вказаний елемент віддаляється, а його позиція запам'ятовується. Подальший виклик AddItem створить новий елемент в цьому місці.

Параметри:

ItemName рядок, задаючий ім'я елемента, що видаляється. На його місці буде розміщений наступний елемент, що створюється.

DeleteItem(ItemName)

Команда DeleteItem здійснює видалення вказаного програмного елемента.

Параметри:

ItemName рядок, задаючий ім'я елемента, що видаляється.

ExitProgman(bSaveGroups)

Ця команда завершує роботу Program Manager.

Параметри:

bSaveGroups величина, вказуюча треба чи ні зберігати поточний стан груп перед завершенням роботи Program Manager. При значенні 0 збереження груп не відбувається.