Тема: Створення власної 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:
Відкриваємо cpp-файл нашого проекту. Спочатку додаємо в нього заголовки LUA, причому перед їх включенням (це важливо!) Додаємо визначення двох змінних препроцесора: вони необхідні для випадку складання DLL, доступною з LUA. Якби ми збирали навпаки LUA-інтерпретатор, що запускає з себе LUA-скрипти, то необхідно було б зробити інші визначення.
Оскільки у нас C ++ файл, то підключення заголовних файлів LUA необхідно зробити під extern "C".
Замість визначення LUA_LIB і LUA_BUILD_AS_DLL через директиву #define, можна додати їх в рядок Preprocessor Definitions у властивостях проекту (зручно, якщо проект містить безліч файлів):
Ще одне міркування.
Щоб у вас не виникло проблем з перенесенням і використанням вашої бібліотеки на інших комп'ютерах (якщо така потреба є), то є сенс скомпілювати її зі статичним run-time, тобто весь код власне бібліотек C ++ буде повністю всередині вашої DLL. Це кілька збільшить її розмір, але кого зараз хвилює розмір файлу? Відповім: нікого. Зате вам не доведеться додатково до вашої бібліотеці тягати кілька системних DLL, або змушувати користувачів вашої встановлювати C ++ Redistributable Package, причому певної версії. Ви ж не хочете створювати собі і іншим зайві складнощі? і правильно, тому статичний run-time - це наш шлях.
Щоб його включити, необхідно зробити наступні настройки у властивостях проекту. Причому в залежності від конфігурації слід вибрати правильний тип run-time # 'а, інакше і debug буде не debug, і release не зрозумій що.
Для release-конфігурацій вибираємо:
Для debug-конфігурацій вибираємо:
Тепер власне код бібліотеки на 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 # виходить не потрібна.
А що стосується "розбігу",
Друзі! Безкоштовно я роблю те, що мені цікаво. Поимя вже совість.