Створення власної dll на c для lua (в quik) (сторінка 1) - написання зовнішніх бібліотек на c

Тема: Створення власної DLL на C ++ для LUA (в QUIK)

Написання власних .dll-бібліотек на С ++ для підключення їх до коду Lua (QLua) і виклик своїх функцій з цих бібліотек

Скажу відразу: тут не планується і не буде вичерпного опису взаємодії LUA і Сі. Просто тому, що такого матеріалу в інтернеті просто завались, нічого нового я не відкрию.
Однак хотілося б привести опис кроків, що дозволяють зробити «швидкий старт» в написанні своєї бібліотеки, попутно вказавши на деякі неочевидні нюанси настройки проекту.

Почну в якомусь сенсі «з кінця».
Щоб підключити зовнішню DLL бібліотеку до LUA, в скрипті необхідно необхідно вписати рядок:

Отже, власне переходимо до C ++.
Для його успішної збірки нам обов'язково знадобляться наступні файли з поставки LUA (повний зібраний дистрибутив доступний на lua.org)

Перші три файли містять опис типів і прототипи інтерфейсних функцій LUA, четвертий - бібліотека для статичний лінковки з зовнішньої бібліотекою інтерпретатора lua5.1.dll.

Відкриваємо MS Visual Studio, створюємо новий проект DLL.
У властивостях проекту для будь-яких змін, які ми будемо збирати (зазвичай це Release і Debug), необхідно додати бібліотеку lua5.1.lib в додаткові бібліотеки. У доданому прикладі вона лежить в папці contrib:

Створення власної dll на c для lua (в quik) (сторінка 1) - написання зовнішніх бібліотек на c

Відкриваємо cpp-файл нашого проекту. Спочатку додаємо в нього заголовки LUA, причому перед їх включенням (це важливо!) Додаємо визначення двох змінних препроцесора: вони необхідні для випадку складання DLL, доступною з LUA. Якби ми збирали навпаки LUA-інтерпретатор, що запускає з себе LUA-скрипти, то необхідно було б зробити інші визначення.

Оскільки у нас C ++ файл, то підключення заголовних файлів LUA необхідно зробити під extern "C".

Замість визначення LUA_LIB і LUA_BUILD_AS_DLL через директиву #define, можна додати їх в рядок Preprocessor Definitions у властивостях проекту (зручно, якщо проект містить безліч файлів):

Створення власної dll на c для lua (в quik) (сторінка 1) - написання зовнішніх бібліотек на c

Ще одне міркування.
Щоб у вас не виникло проблем з перенесенням і використанням вашої бібліотеки на інших комп'ютерах (якщо така потреба є), то є сенс скомпілювати її зі статичним run-time, тобто весь код власне бібліотек C ++ буде повністю всередині вашої DLL. Це кілька збільшить її розмір, але кого зараз хвилює розмір файлу? Відповім: нікого. Зате вам не доведеться додатково до вашої бібліотеці тягати кілька системних DLL, або змушувати користувачів вашої встановлювати C ++ Redistributable Package, причому певної версії. Ви ж не хочете створювати собі і іншим зайві складнощі? і правильно, тому статичний run-time - це наш шлях.
Щоб його включити, необхідно зробити наступні настройки у властивостях проекту. Причому в залежності від конфігурації слід вибрати правильний тип run-time # 'а, інакше і debug буде не debug, і release не зрозумій що.

Для release-конфігурацій вибираємо:

Створення власної dll на c для lua (в quik) (сторінка 1) - написання зовнішніх бібліотек на c

Для debug-конфігурацій вибираємо:

Створення власної dll на c для lua (в quik) (сторінка 1) - написання зовнішніх бібліотек на c

Тепер власне код бібліотеки на C ++

Оскільки бібліотеку ми назвали luacdll і имено це ім'я вказуємо в require. то при завантаженні нашої бібліотеки LUA-інтерпретатор буде шукати експортовану з неї функцію з певним ім'ям, в даному випадку luaopen_luacdll (). Тут luaopen_ це зумовлений префікс (див. Документацію), а luacdll власне ім'я нашої бібліотеки. Зрозуміло, тип і аргументи цієї функції теж зумовлені.

Власне все, що ми тут робимо - це реєструємо в LUA-інтерпретатор (шляхом виклику luaL_openlib) ті функції, які ми надаємо з нашої бібліотеки, що робить їх доступними для виклику з LUA-скриптів. Другим параметром функції передається namespace, в якому будуть доступні функції нашої бібліотеки при виклику; щоб не заплутатися, namespace збігається з ім'ям бібліотеки.

В нашій найпростішої бібліотеці будуть реалізовані 3 функції, доступні з LUA:

GetCurrentThreadId - отримати ID поточного потоку

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

MultAllNumbers - перемножує все числа, які зустрілися в аргументах

Сам список функцій (ім'я та покажчик на відповідну Сі-функцію) описаний в константностей масиві:

Власне реалізація, наприклад, функції, що повертає ID поточного потоку:

Її прототип зумовлений і єдиний для всіх інтерфейсних функцій: приймає єдиний параметр L - покажчик на стек LUA (див. Документацію).
В даному випадку функція не має на увазі ніяких аргументів і повертає єдине цілочисельне значення.

Після компіляції вийшов DLL-файл (як було сказано) копіюємо в той же каталог, де розташований термінал QUIK (обов'язково перепишіть туди ж файл lua5.1.dll!), І запускаємо в ньому наступний LUA-скрипт, попередньо збережемо його у вигляді файлу :

В результаті його виконання буде виведено 3 повідомлення: з ID основного потоку терміналу, число 12.152 і число 1.1.

Повністю подібні тексти і скомпільовану dll можна скачати у вигляді архіву.

Re: Створення власної DLL на C ++ для LUA (в QUIK)

Куди помістити файл з DLL-бібліотекою

Я настійно рекомендую створену бібліотеку DLL помістити в каталог з QUIK, тобто в ту ж папку, де лежить файл info.exe.
Так, в принципі можна гратися із зазначенням шляхів в скрипті і це навіть працює при належному навичці. Ось тільки навіщо? чи є хоч один здоровий аргумент? Естетика - це, можливо, і добре, але надійність - вона, на мій погляд, переважує будь-яку естетику на 3 порядки мінімум.
Так що без докорів сумління розміщуйте свої DLL-бібліотеки в каталог з QUIK - і все у вас буде працювати просто і надійно.

Re: Створення власної DLL на C ++ для LUA (в QUIK)

Тобто фактично для вирішення завдання цілком підійде окремий додаток на C #, яке буде взаємодіяти зі скриптом Lua, вірно? Як така dll на C # виходить не потрібна.

А що стосується "розбігу",
Друзі! Безкоштовно я роблю те, що мені цікаво. Поимя вже совість.

Схожі статті