Наслідування інтерфейсів delphi. Особливості роботи з інтерфейсами в Delphi

У мене проблема з використанням класу Delphi із коду C++. delphi dll demo, яка експортує функцію, що повертає об'єкт.
мій код Delphi Dll виглядає так:

Library DelphiTest; // uses part.... type IMyObject = interface procedure DoThis(n: Integer); функція DoThat: PWideChar; end; TMyObject = class(TInterfacedObject,IMyObject) procedure DoThis(n: Integer); функція DoThat: PChar; end; // TMyObject implementation go here ... procedure TMyObject.DoThis(n: Integer); починають showmessage("Ви знайдете DoThis метод з "+intToStr(n) +"Parameter"); end; function TMyObject.DoThat: PChar; begin showmessage("Ви знайдете функцію DoThat"); Result:= Pchar("Hello im Dothat"); end;

// Експорт функції DLL:

Function CreateMyObject: IMyObject; stdcall;export; var txt: TextFile; begin AssignFile(txt,"C:\log.log"); Reset(txt); Writeln(txt, "hello"); Result:= TMyObject.Create; end; exports CreateMyObject;

у моєму проекті C ++ я оголосив інтерфейс IMyObject наступним чином:

Class IMyObject ( public: IMyObject(); virtual ~IMyObject(); virtual void DoThis(int n) = 0; virtual char* DoThat() = 0; );

і моя основна функція так:

Typedef IMyObject* (__stdcall *CreateFn)(); int main() ( HMODULE hLib; hLib = LoadLibrary(L"DelphiTest.dll"); assert(hLib != NULL); // pass !! CreateFn pfnCreate; pfnCreate = (CreateFn)GetProcAddress((HINSTANCE)hM "); if (pfnCreate == NULL) ( DWORD errc = GetLastError(); printf("%u\n", errc); // it gets error 127 ) else( printf("success load\n"); ) IMyObject* objptr = pfnCreate(); objptr->DoThis(5); FreeLibrary(hLib); int in;

у цьому прикладі я отримав помилку під час виконання, коли я намагаюся отримати доступ до експортованої функції. помилки у рядку:
IMyObject* objptr = pfnCreate();

Ви можете сказати мені, що не так з моїм прикладом.
і, якщо можливо, будь-який робочий приклад для доступу до класу Delphi (DLL) з коду C++.

Рішення

Перша проблема – виклик угоди методів. Інтерфейс Delphi використовує register, який є специфічною угодою про виклики Delphi. Використання stdcall Наприклад, для методів інтерфейсу.

Наступна проблема в C++. Ваш інтерфейс C++ повинен бути похідним від IUnknown, крім того, він не повинен оголошувати конструктора або деструктора.

Крім того, ваш код Delphi експортується PWideChar, який не відображається на char* , він відображається на wchar_t* ,

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

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

Я чекаю, що є інші помилки, але це все, що я знайшов і досі.

Стаття написана за результатами розбору програм, написаних молодими розробниками нашої групи.

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

Багато користувачів, особливо ті, хто раніше працював у ДОС, мають звичку перемикатися між полями введення не мишкою, а за допомогою клавіатури клавіш Tab. До того ж це набагато швидше, ніж виділяти кожне поле мишею. Тому порядок перемикання компонентів має бути виставлений правильно. Це стосується як компонентів усередині всіх компонентів-контейнерів (панелей, GroupBox-ів та подібних до них), так і самих компонентів-контейнерів, якщо їх на формі кілька.

Порядок перемикання компонентів усередині контейнера визначається властивістю TabOrder. Першим стає активним компонент, у якого TabOrder дорівнює 0, другим з 1 і т.д., доки не будуть перебрані всі компоненти. Крім цього, компонент має властивість TabStop, яке показує, чи буде компонент отримувати фокус при перемиканні клавіш Tab. Якщо потрібно заборонити перемикання на будь-який компонент, поставте TabStop = false. У цьому випадку перейти на цей компонент можна буде лише за допомогою миші.

Бувають випадки, коли користувачі, які звикли перемикатися певною кнопкою в одній програмі, за звичкою продовжують користуватися нею і в інших. Часто це відбувається з користувачами 1С, де для переходу полями введення може використовуватися клавіша Enter. Що ж, дамо їм таку можливість у наших програмах, якщо вони про це просять. Встановлюємо у форми властивість KeyPreview у true та пишемо обробник події OnKeyPress:

Procedure TForm1.FormKeyPress (Sender: TObject; var Key: Char);
begin
if ord(key)=vk_Return then
Form1.SelectNext(PriemForm.ActiveControl, true, true);
end;

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

Кнопки за замовчуванням

Всі ті ж користувачі досить швидко звикають, що в діалогових вікнах програм, як правило, клавішею Enter можна підтвердити свій вибір, а клавішею Esc – скасувати. Давайте не розчаровуватимемо їх у наших програмах, тим більше що зробити це дуже просто. Для кнопки, що реагує на Enter, встановлюємо властивість Default у true. Для кнопки, що реагує на Esc, встановлюємо властивість Cancel у true. І все.

Так чи ні

Усі діалогові вікна, що запитують дії користувача, повинні мати принаймні дві кнопки: підтвердження дії та відмови від дії (Так/Ні, Зберегти/Скасувати тощо). Відмова від дії може здійснюватися закриттям вікна кнопкою [X] у заголовку вікна. Неприпустимо, якщо є лише одна кнопка для підтвердження дії, а відмовиться закривати вікно кнопкою [X] в заголовку, або можливість відмови взагалі відсутня. Це плутає користувача, викликаючи логічне запитання: а як відмовитись?

Також не забуваємо про те, що було сказано вище у пункті "Кнопки за замовчуванням".

Усі діалогові вікна повинні відкриватися у центрі екрана

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

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

Розміри вікон не повинні перевищувати розмірів екрану

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

Коректна зміна розмірів віконних елементів

Віконні елементи повинні коректно змінювати свої розміри або переміщатися при зміні розмірів вікна, при максимізації вікна та відновлення вікна після максимізації.

Все завжди видно

Зменшення розмірів вікна не повинно призводити до зникнення віконних елементів і бажано не повинно призводити до появи смуг прокручування (scroller-ів) самого вікна. Можна обмежувати мінімальні розміри вікна таким чином, щоб усі елементи були видні та доступні. Якщо немає можливості розмістити компоненти таким чином, щоб усі були видні у вікні, можна використовувати закладки (типу PageControl) для розбиття компонентів на групи. Відмовки щодо дозволу екрана теж не пропускаємо.

Хінти скрізь, хінти завжди

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

Кольорова гамма

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

Висновок

Є дуже хороший метод, який дозволяє знайти недоліки програми взагалі та зокрема інтерфейсу. Він простий: уявіть себе на місці користувача і протягом півгодини спробуйте працювати так, як він працює. Ще краще, якщо ваш користувач у межах досяжності (наприклад, працює у тій самій організації). У такому разі сядьте поруч із ним, а краще замість нього, і спробуйте зробити його роботу. Вносити дані, змінювати їх, виводити звіти тощо. Якщо ви не знаєте, як зробити правильно, запитайте свого користувача. Зробіть не одну-дві однотипні операції, як у режимі налагодження, а 20-30, а то й більш різних операцій, в різному порядку. Забудьте щось ввести або введіть неправильно та подивіться, як програма на це відреагує. Ви досить швидко побачите слабкі місця вашої програми.

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

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

Це стаття з мотивів питань на форумах: "Як мені повернути рядок з DLL?", "Як передати та повернути масив записів?", "Як передати в DLL форму?".

Щоб вам не витрачати половину життя на розібратися - у цій статті я принесу все на блюдечку.

Теми цієї статті різною мірою вже не раз торкалися цього блогу, але в цій статті вони зібрані в купу, наведені обґрунтування. Коротше, посилання на цю статтю можна кидатися в тих, хто розробляє DLL.

Важлива примітка: статтю потрібно читати послідовно. Приклади коду наводяться лише як приклади, на кожному кроці (пункті) статті код прикладів додається новими подробицями. Наприклад, на самому початку статті немає обробки помилок, вказуються "класичні" способи (типу, використання GetLastError, угоди sdtcall і т.д.), які під час статті замінюються більш адекватними. Зроблено так тому, щоб "нові" ("незвичайні") конструкції не викликали питань. Інакше довелося б до кожного прикладу вставляти примітку виду: "ось це обговорюється в тому пункті нижче, а ось те - в цьому ось". У кожному разі наприкінці статті є посилання вже готовий код, написаний з урахуванням всього сказаного у статті. Можете просто його брати та використати. А стаття пояснює навіщо та чому. Якщо вам не цікаво "навіщо і чому" - гортайте в кінець до висновку та посилання на завантаження прикладу.

тільки за результат

жорстке дотримання термінів

Прозорість

виконання проекту

техпідтримки у подарунок

Програмування, доопрацювання консультації з 1С

Як ми працюємо

1. Обговорюємо проблему телефоном. За наявності віддаленого доступу – показуєте на екрані вашого комп'ютера.

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

3. Ми виконуємо роботу.

4. Ви приймаєте роботу у вашій програмі, якщо є недоліки, ми їх виправляємо.

5. Ми виставляємо рахунок, ви сплачуєте.

Вартість робіт

1. Усі роботи діляться на 3 категорії: консультація, оновлення типової конфігурації, розробка або програмування нового звіту, обробки, кнопки тощо.

3. На роботи понад 10 годин попередньо складається технічне завдання з описом та вартістю робіт. Роботи розпочинаються після погодження ТЗ із Вами.

Технічна підтримка

1. Якщо ви виявляєте якісь помилки, у раніше прийнятих роботах, протягом 3-х місяців, ми виправляємо їх безкоштовно.

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

Програми для керування вашим бізнесом.

Купити 1С:Підприємство

Ми є офіційним дилером фірми 1С, ви можете придбати у нас різноманітні програмні продукти та ліцензії. Окрім покупки "коробки" ми допоможемо вам налаштувати програму, проконсультуємо та зробимо базові налаштування.

  • Бухгалтерський облік
  • Автоматизація магазину
  • Оптові продажі
  • Допомога в установці та початковому налаштуванні включена до пакету!
  • Тонка настройка конфігурацій під потреби замовника, розробка нових модулів за відсутності необхідних функцій стандартної конфігурації.
1с Бухгалтерія 1С:Управління торгівлею 1С:Роздріб 1С:Зарплата та Управління Персоналом
Від 3300 руб. Від 6700 руб. Від 3300 руб. Від 7400 руб.

Надання сервера.

Моментальне налаштування сервера + 1С.

Нема сервера? Не біда, підберемо і швидко налаштуємо сервер у "хмарі". За невелику платню ви отримуєте дуже надійне рішення.

  • Доступність 24\7
  • Немає необхідності тримати власного системного адміністратора (економія покриє витрати на сервер).
  • Швидке налаштування та встановлення 1С на сервер, через 3 дні у вас вже буде повністю робоча система.
  • Будь-якої миті можна переїхати на локальний сервер, якщо рішення не влаштує.

SMS із вашої 1С

Бажаєте щоб клієнти під час дізнавалися про акції, знижки? Клієнти не вертаються? Налаштуйте надсилання SMS прямо з 1С!

Наша компанія зможе в короткий термін налаштувати відправку SMS Вашим клієнтам безпосередньо з 1С. Приклади подій, які можна автоматизувати:

  • Подяка за покупку та нарахування бонусів відразу після чергової покупки.
  • Нарахування бонусів на картку в подарунок на день народження\до іншого знаменного або святкового дня.
  • Повідомлення про надходження товару на склад.
  • Закінчення терміну подарункових бонусів.
  • Повідомлення про надходження передоплати та резервування товару.
  • Адреса з уточненнями проїзду до магазину, номери телефонів.
  • І т.п.

Налаштування в 1С можна зробити силами наших спеціалістів чи своїх працівників. Ознайомитись з тарифами можна на сторінці SMS-тарифів.

  • Гарантія доставки SMS, гроші знімаються лише за доставлені SMS.
  • Окрема тарифікація кожного SMS.
  • Поповнення балансу у різний спосіб.
  • Перегляд історії всіх надісланих SMS у будь-який момент.
  • Ім'я відправника замість цифрового номера телефону одержувача повідомлення.

Об'єктно-орієнтоване програмування (ООП) крім поняття класу передбачає також фундаментальне поняття інтерфейсу.

Що ж таке інтерфейс та які особливості роботи з ним у мові програмування Delphi?

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

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

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

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

Для оголошення інтерфейсу Delphi служить ключове слово interface. Це теж ключове слово, що визначає секцію модуля, до якої можна звернутися з поза (між ключовими словами interface і implementation). Однак при оголошенні інтерфейсу застосовується інший синтаксис, схожий на оголошення класів.

Delphi/Pascal

IMyNewInterface = interface procedure InterfaceProc; end;

IMyNewInterface =interface

procedure InterfaceProc;

end;

Таким чином, сам синтаксис оголошення інтерфейсу немає принципових відмінностей з інших мов програмування (особливості синтаксису заснованого на Pascal поза рахунок). У той же час, реалізація інтерфейсів має низку характерних рис.

Справа в тому, що Delphi інтерфейси спочатку були введені для підтримки технології COM. Тому інтерфейс IInterface, який у Delphi є предком для всіх інших інтерфейсів (своєрідний аналог TObject), вже містить у собі три базові методи роботи з цією технологією: QueryInterface, _AddRef, _Release. Як результат, якщо клас реалізує будь-який інтерфейс, він повинен обов'язково реалізувати й ці методи. Навіть якщо цей клас не призначений для роботи COM.

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

Існує бібліотечний клас TInterfaceObject, який вже містить реалізацію цих методів і при наслідуванні від нього необхідність реалізовувати їх самостійно відпадає. Але так як Delphi не підтримує множинне успадкування класів, його застосування часто викликає додаткові складності в проектуванні та реалізації вже необхідного функціоналу.

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

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

Тому, багато програмістів Delphi до цих пір, по факту, позбавлені потужного і гнучкого інструменту для розробки архітектури додатків.

Поділитися