Как написать dll на python

Время на прочтение
11 мин

Количество просмотров 46K

DLL & Python

image

Недавно меня заинтересовала тема использования DLL из Python. Кроме того было интересно разобраться в их структуре, на тот случай, если придется менять исходники библиотек. После изучения различных ресурсов и примеров на эту тему, стало понятно, что применение динамических библиотек может сильно расширить возможности Python. Собственные цели были достигнуты, а чтобы опыт не был забыт, я решил подвести итог в виде статьи — структурировать свой знания и полезные источники, а заодно ещё лучше разобраться в данной теме.

Под катом вас ожидает статья с различными примерами, исходниками и пояснениями к ним.

Содержание

  • Структура DLL
  • DLL & Python
    • Подключение DLL
    • Типы данных в С и Python
    • Аргументы функция и возвращаемые значения
    • Своя DLL и ее использование
  • Полезные ссылки:

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

Структура DLL

DLL — Dynamic Link Library — динамическая подключаемая библиотека в операционной системе (ОС) Windows. Динамические библиотеки позволяют сделать архитектуру более модульной, уменьшить количество используемых ресурсов и упрощают модификацию системы. Основное отличие от .EXE файлов — функции, содержащиеся в DLL можно использовать по одной.

Учитывая, что статья не о самих библиотеках, лучше просто оставить здесь ссылку на довольно информативную статью от Microsoft: Что такое DLL?.


Для того, чтобы понять, как использовать динамические библиотеки, нужно вникнуть в их структуру.

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

Рисунок 1 — Пустой template, предлагаемый Code Blocks для проекта DLL.

На рисунке 1 приведен шаблон, который предлагает Code Blocks, при выборе проекта типа DLL. В представленном шаблоне есть две функции:

#define DLL_EXPORT __declspec(dllexport) // обязательно определять функции, 
                                         // которые могут быть экспортированы из                                                 // библиотеки
void DLL_EXPORT SomeFunction(const LPCSTR sometext); // просто функция для примера, она вызывает вывод сообщения в окно

extern "C" DLL_EXPORT BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) //функция точки входа

Для начала стоит подробнее рассмотреть функциюDllMain. Через нее ОС может уведомлять библиотеку о нескольких событиях (fdwReason):

  • DLL_PROCESS_ATTACH – подключение DLL. Процесс проецирования DLL на адресное пространство процесса. С этим значением DllMain вызывается всякий раз, когда какой-то процесс загружает библиотеку с явной или неявной компоновкой.

  • DLL_PROCESS_DETACH – отключение DLL от адресного пространства процесса. С этим значением DllMain вызывается при отключении библиотеки.

  • DLL_THREAD_ATTACH – создание процессом, подключившим DLL, нового потока. Зачем DLL знать о каких-то там потоках? А вот зачем, далеко не каждая динамическая библиотека может работать в многопоточной среде.

  • DLL_THREAD_DETACH – завершение потока, созданного процессом, подключившим DLL. Если динамическая библиотека создает для каждого потока свои «персональные» ресурсы (локальные переменные и буфера), то это уведомление позволяет их своевременно освобождать.

Опять же, в тему структуры DLL можно углубляться до бесконечности, там есть много различных нюансов, о которых немного изложено в этой статье.


У DllMain не так много аргументов, самый важный fdwReason уже рассмотрен выше, теперь о двух других:

  • Аргумент lpvReserved указывает на способ подключения DLL:
    • 0 — библиотека загружена с явной компоновкой.
    • 1 — библиотека загружена с неявной компоновкой.
  • Аргумент hinstDLL содержит описатель экземпляра DLL. Любому EXE- или DLL-модулю, загружаемому в адресное пространство процесса, присваивается уникальный описатель экземпляра.

О явной и неявной компоновке можно прочесть подробно в статье: Связывание исполняемого файла с библиотекой DLL.


В предложенном на рисунке 1 шаблоне есть функция SomeFunction, которая может быть экспортирована из динамической библиотеки. Для того, чтобы это показать, при объявлении функции указывается __declspec(dllexport). Например, так:

#define DLL_EXPORT __declspec(dllexport) 
void DLL_EXPORT SomeFunction(const LPCSTR sometext);

Функции, не объявленные таким образом, нельзя будет вызывать снаружи.

DLL & Python

Первым делом, расскажу, как подключать уже собранные DLL, затем, как вызывать из них функции и передавать аргументы, а уже после этого, постепенно доделаю шаблон из Code Blocks и приведу примеры работы с собственной DLL.

Подключение DLL

Основной библиотекой в Python для работы с типами данных, совместимыми с типами языка С является ctypes. В документации на ctypes представлено много примеров, которым стоит уделить внимание.

Чтобы начать работать с DLL, необходимо подключить библиотеку к программе на Python. Сделать это можно тремя способами:

  • cdll — загружает динамическую библиотеку и возвращает объект, а для использования функций DLL нужно будет просто обращаться к атрибутам этого объекта. Использует соглашение вызовов cdecl.
  • windll — использует соглашение вызовов stdcall. В остальном идентична cdll.
  • oledll — использует соглашение вызовов stdcall и предполагается, что функции возвращают код ошибки Windows HRESULT. Код ошибки используется для автоматического вызова исключения WindowsError.

Про соглашения о вызове функций.

Для первого примера будем использовать стандартную Windows DLL библиотеку, которая содержит всем известную функцию языка С — printf(). Библиотека msvcrt.dll находится в папке C:WINDOWSSystem32.

Код Python:

from ctypes import *

lib = cdll.msvcrt   # подключаем библиотеку msvcrt.dll
lib.printf(b"From dll with love!n") # вывод строки через стандартную printf

var_a = 31
lib.printf(b"Print int_a = %dn", var_a) # вывод переменной int 
                                # printf("Print int_a = %dn", var_a); // аналог в С

Результат:

From dll with love!
Print int_a = 31

Можно использовать подключение библиотеки с помощью метода windll либо oledll, для данного кода разницы не будет, вывод не изменится.

Если речь не идет о стандартной библиотеке, то конечно следует использовать вызов с указанием пути на dll. В ctypes для загрузки библиотек предусмотрен метод LoadLibrary. Но есть еще более эффективный конструктор CDLL, он заменяет конструкцию cdll.LoadLibrary. В общем, ниже показано два примера вызова одной и той же библиотеки msvcrt.dll.

Код Python:

from ctypes import *

lib = cdll.LoadLibrary(r"C:WindowsSystem32msvcrt.dll")   
lib.printf(b"From dll with love!n")    # вывод строки через стандартную printf

lib_2 = CDLL(r"C:WindowsSystem32msvcrt.dll") # подключаем библиотеку msvcrt.dll

var_a = 31
lib_2.printf(b"Print int_a = %dn", var_a)  # вывод переменной int

Иногда случается, что необходимо получить доступ к функции или атрибуту DLL, имя которого Python не «примет»… ну бывает. На этот случай имеется функции getattr(lib, attr_name). Данная функция принимает два аргумента: объект библиотеки и имя атрибута, а возвращает объект атрибута.

Код Python:

from ctypes import *

lib = cdll.LoadLibrary(r"C:WindowsSystem32msvcrt.dll")   

var_c = 51
print_from_C = getattr(lib, "printf")  # да, тут можно вписать даже "??2@YAPAXI@Z"
print_from_C(b"Print int_c = %dn", var_c)

Результат:

Print int_c = 51

Теперь становится понятно, как подключить библиотеку и использовать функции. Однако, не всегда в DLL нужно передавать простые строки или цифры. Бывают случаи, когда требуется передавать указатели на строки, переменные или структуры. Кроме того, функции могут и возвращать структуры, указатели и много другое.

Типы данных в С и Python

Модуль ctypes предоставляет возможность использовать типы данных совместимые с типами в языке С. Ниже приведена таблица соответствия типов данных.

Таблица 1 — Соответствие типов данных языка Python и языка C, которое предоставляет модуль ctypes.

Первое, что стоит попробовать — это использовать указатели, куда без них? Давайте напишем программу, где создадим строку и указатель на неё, а потом вызовем printf() для них:

Код:

from ctypes import *

lib = CDLL(r"C:WindowsSystem32msvcrt.dll")
printf = lib.printf # объект функции printf()

int_var = c_int(17) # переменная типа int из C
printf(b"int_var = %dn", int_var)

str_ = b"Hello, Worldn" # строка в Python
str_pt = c_char_p(str_)  # указатель на строку
printf(str_pt)           

print(str_pt)            
print(str_pt.value) # str_pt - указатель на строку, значение можно получить с использованием атрибута value

Результат:

int_var = 17
Hello, World
c_char_p(2814054827168)
b'Hello, Worldn'

Если вы создали указатель, то разыменовать (получить доступ к значению, на которое он указывает) можно с использованием атрибута value, пример выше.

Аргументы функций и возвращаемые значения

По умолчанию предполагается, что любая экспортируемая функция из динамической библиотеки возвращает тип int. Другие возвращаемые типы можно указать при помощи атрибута restype. При этом, чтобы указать типы аргументов функции можно воспользоваться атрибутом argtypes.

Например, стандартная функция strcat принимает два указателя на строки и возвращает один указатель на новую строку. Давайте попробуем ей воспользоваться.

char *strcat (char *destination, const char *append); // C функция для конкатонации (склеивания) строк 

Код Python:

from ctypes import *

libc = CDLL(r"C:WindowsSystem32msvcrt.dll")

strcat = libc.strcat        # получаем объект функции strcat
strcat.restype = c_char_p   # показываем, что функция будет возвращать указатель на                                 # строку
strcat.argtypes = [c_char_p, c_char_p] # показывает типы аргументов функции

str_1 = b"Hello,"
str_2 = b" Habr!"
str_pt = strcat(str_1, str_2) # вызываем стандартную функцию

print(str_pt)

Результат:

b'Hello, Habr!'

На этом закончим с примерами использования готовых DLL. Давайте попробуем применить знания о структуре DLL и модуле ctypes для того, чтобы собрать и начать использовать собственную библиотеку.

Своя DLL и ее использование

Пример 1

Шаблон DLL уже был рассмотрен выше, а сейчас, когда дело дошло до написания своей DLL и работы с ней, выскочили первые и очевидные грабли — несовместимость разрядности DLL и Python. У меня на ПК установлен Python x64, оказалось, что как бы ни были DLL универсальны, разрядность DLL должна соответствовать разрядности Python. То есть, либо ставить компилятор x64 и Python x64, либо и то и то x32. Хорошо, что это не сложно сделать.

Ниже привожу код шаблона DLL, в который добавил вывод строки при подключении библиотеки, а также небольшой разбор и вывод аргументов, с которыми вызвалась DllMain. В примере можно понаблюдать, какие участки кода библиотеки вызываются и когда это происходит.

Код DLL на С:

// a sample exported function
void __declspec(dllexport) SomeFunction(const LPCSTR sometext)
{
    MessageBoxA(0, sometext, "DLL Message", MB_OK | MB_ICONINFORMATION);
}

extern "C" DLL_EXPORT BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    switch (fdwReason)
    {
        case DLL_PROCESS_ATTACH:
            printf("Load DLL in Pythonn");

            printf("HINSTANCE = %pn",hinstDLL); // Вывод описателя экземпляра DLL

            if (lpvReserved)                     // Определение способа загрузки
              printf("DLL loaded with implicit layoutn"); 
            else
              printf("DLL loaded with explicit layoutn");          
            return 1;                            // Успешная инициализация

        case DLL_PROCESS_DETACH:
            printf("DETACH DLLn");
            break;

        case DLL_THREAD_ATTACH:
            break;

        case DLL_THREAD_DETACH:
            break;
    }
    return TRUE; // succesful
}

Код Python:

from ctypes import *

lib_dll = cdll.LoadLibrary("DLL_example.dll")   # подключаю свою DLL
str_ = b'Hello, Habr!'
p_str = c_char_p(str_)                          # получаю указатель на строку str_
lib_dll.SomeFunction(p_str)                     # вызываю SomeFunction из DLL

Функция SomeFunction получает указатель на строку и выводит её в окно. На рисунке ниже показана работа программы.

Рисунок 2 — Демонстрация работы шаблона библиотеки из Code Blocks.

Все действия происходящие в кейсе DLL_PROCESS_ATTACH, код которого приведен ниже, вызываются лишь одной строкой в Python коде:

lib_dll = cdll.LoadLibrary("DLL_example.dll")   # подключение библиотеки

Рисунок 3 — Действия происходящие при подключении DLL.

Пример 2

Чтобы подвести итог по использованию DLL библиотек из Python, приведу пример, в котором есть начальная инициализация параметров и передача новых через указатели на строки и структуры данных. Этот код дает понять, как написать аналог структуры С в Python. Ниже привожу код main.c, man.h и main.py.

Код DLL на С:

main.h

#ifndef __MAIN_H__
#define __MAIN_H__

#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <malloc.h>

#define DLL_EXPORT __declspec(dllexport) // обязательно определять функции, 
                                         // которые могут быть экспортированы из                                                 // библиотеки
#ifdef __cplusplus
extern "C"
{
#endif

struct Passport{
    char*  name;
    char*  surname;
    int var;
};

void DLL_EXPORT SetName(char* new_name);
void DLL_EXPORT SetSurname(char* new_surname);
void DLL_EXPORT SetPassport(Passport* new_passport);
void DLL_EXPORT GetPassport(void);

#ifdef __cplusplus
}
#endif
#endif // __MAIN_H__

В коде main.h определена структура Passport с тремя полями: два указателя и целочисленная переменная. Кроме того, четыре функции объявлены, как экспортируемые.

Код DLL на С:

main.c

#include "main.h"

#define SIZE_BUF 20

struct Passport passport; // объявляем переменную passport типа Passport

// Функция установки имени
void DLL_EXPORT SetName(char* new_name)
{
    printf("SetNamen");
    strcpy(passport.name, new_name);
}

// Функция установки фамилии
void DLL_EXPORT SetSurname(char* new_surname)
{
    printf("SetSurnamen");
    strcpy(passport.surname, new_surname);
}

// Функция установки полей структуры.
// На вход принимает указатель на структуру
void DLL_EXPORT SetPassport(Passport* new_passport)
{
    printf("SetPassportn");
    strcpy(passport.name, new_passport->name);
    strcpy(passport.surname, new_passport->surname);
    passport.var = new_passport->var;
}

// Вывести в консоль данные структуры
void DLL_EXPORT GetPassport(void)
{
    printf("GetPassport: %s | %s | %dn", passport.name, passport.surname, passport.var);
}

extern "C" DLL_EXPORT BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    switch (fdwReason)
    {
        case DLL_PROCESS_ATTACH:
            printf("Load DLL in Pythonn");

            passport.name = (char*)malloc(SIZE_BUF * sizeof(char)); // выделение памяти
            passport.surname = (char*)malloc(SIZE_BUF * sizeof(char)); // выделение памяти

            passport.var = 17; // начальная инициализация переменной
            SetName("Default"); // начальная инициализация буфера имени
            SetSurname("Passport"); // начальная инициализация буфера фамилии
            return 1;

        case DLL_PROCESS_DETACH:
            free (passport.name); // Освобождение памяти
            free (passport.surname); // Освобождение памяти
            printf("DETACH DLLn");
            break;

        case DLL_THREAD_ATTACH:
            break;

        case DLL_THREAD_DETACH:
            break;
    }
    return TRUE; // succesful
}

Внутри кейса DLL_PROCESS_ATTACH происходит выделение памяти под строки и начальная инициализация полей структуры. Выше DllMain определены функции:

  • GetPassport — вывод полей структуры passport в консоль.

  • *SetName(char new_name)** — установка поля name структуры passport.

  • *SetSurname(char new_surname)** — установка поля surname структуры passport.

  • *SetPassport(Passport new_passport)** — установка всех полей структуры passport. Принимает в качестве аргумента указатель на структуру с новыми полями.

Теперь можно подключить библиотеку в Python.

Код на Python

from ctypes import *

class Passport(Structure):              # класс, который соответствует структуре Passport 
    _fields_ = [("name", c_char_p),    # из файла main.h
                ("surname", c_char_p),
                ("var", c_int)]

lib_dll = cdll.LoadLibrary("DLL_example.dll")   # подключаю свою DLL
lib_dll.SetPassport.argtypes  = [POINTER(Passport)] # указываем, тип аргумента функции

lib_dll.GetPassport()          # вывод в консоль структуры

lib_dll.SetName(c_char_p(b"Yury"))
lib_dll.SetSurname(c_char_p(b"Orlov"))

lib_dll.GetPassport()         # вывод в консоль структуры

name = str.encode(("Vasiliy"))  # первый вариант получения указателя на байтовую строку
surname = c_char_p((b'Pupkin')) # второй вариант получения указателя на байтовую строку

passport = Passport(name, surname, 34) # создаем объект структуры Passport

lib_dll.SetPassport(pointer(passport)) # передача структуры в функцию в DLL

lib_dll.GetPassport()         # вывод в консоль структуры

В коде выше многое уже знакомо, кроме создания структуры аналогичной той, которая объявлена в DLL и передачи указателя на эту структуру из Python в DLL.

Результат:

Load DLL in Python
SetName
SetSurname
GetPassport: Default | Passport | 17
SetName
SetSurname
GetPassport: Yury | Orlov | 17
SetPassport
GetPassport: Vasiliy | Pupkin | 34
DETACH DLL

P.S: Думаю, что примеры и объяснения из статьи помогут вам быстро начать использовать DLL библиотеки из Python. Ну а если вы не смогли найти ответы на свои вопросы то может помогут ссылки ниже. Если у кого-то будут вопросы — постараюсь ответить, если будут замечания — постараюсь исправить. Спасибо, что дочитали!

Полезные ссылки:

  • Документации ctypes — много примеров
  • Что такое DLL? — много и полно о dll.
  • [C/C++ из Python (ctypes)](C/C++ из Python (ctypes)) — хорошая статья.
  • Передача двумерных списков из python в DLL
  • Связывание исполняемого файла с библиотекой DLL
  • Github с dll «Hello-world» и её кодом — можно воспользоваться для тестирования.
  • Что такое TCHAR, WCHAR, LPSTR, LPWSTR,LPCTSTR — о типах данных.
  • Динамические библиотеки для гурманов — статья с большим количеством интересных нюансов.

To expand on the answer by Nick ODell

You must be on Windows for DLLs to work, they are not portable.

However the code below is cross platform and all platforms support run-times so this can be re-compiled for each platform you need it to work on.

Python does not (yet) provide an easy tool to create a dll, however you can do it in C/C++


First you will need a compiler (Windows does not have one by default) notably Cygwin, MinGW or Visual Studio.

A basic knowledge of C is also necessary (since we will be coding mainly in C).

You will also need to include the necessary headers, I will skip this so it does not become horribly long, and will assume everything is set up correctly.


For this demonstration I will print a traditional hello world:

Python code we will be converting to a DLL:

def foo(): print("hello world")

C code:

#include "Python.h" // Includes everything to use the Python-C API

int foo(void); // Declare foo

int foo(void) { // Name of our function in our DLL

    Py_Initialize(); // Initialise Python

    PyRun_SimpleString("print('hello world')"); // Run the Python commands

    return 0; // Finish execution
}

Here is the tutorial for embedding Python. There are a few extra things that should be added here, but for brevity I have left those out.

Compile it and you should have a DLL. :)


That is not all. You will need to distribute whatever dependencies are needed, that will mean the python36.dll run-time and some other components to run the Python script.

My C coding is not perfect, so if anyone can spot any improvements please comment and I will do my best to fix the it.


It might also be possible in C# from this answer How do I call a specific Method from a Python Script in C#?, since C# can create DLLs, and you can call Python functions from C#.

To expand on the answer by Nick ODell

You must be on Windows for DLLs to work, they are not portable.

However the code below is cross platform and all platforms support run-times so this can be re-compiled for each platform you need it to work on.

Python does not (yet) provide an easy tool to create a dll, however you can do it in C/C++


First you will need a compiler (Windows does not have one by default) notably Cygwin, MinGW or Visual Studio.

A basic knowledge of C is also necessary (since we will be coding mainly in C).

You will also need to include the necessary headers, I will skip this so it does not become horribly long, and will assume everything is set up correctly.


For this demonstration I will print a traditional hello world:

Python code we will be converting to a DLL:

def foo(): print("hello world")

C code:

#include "Python.h" // Includes everything to use the Python-C API

int foo(void); // Declare foo

int foo(void) { // Name of our function in our DLL

    Py_Initialize(); // Initialise Python

    PyRun_SimpleString("print('hello world')"); // Run the Python commands

    return 0; // Finish execution
}

Here is the tutorial for embedding Python. There are a few extra things that should be added here, but for brevity I have left those out.

Compile it and you should have a DLL. :)


That is not all. You will need to distribute whatever dependencies are needed, that will mean the python36.dll run-time and some other components to run the Python script.

My C coding is not perfect, so if anyone can spot any improvements please comment and I will do my best to fix the it.


It might also be possible in C# from this answer How do I call a specific Method from a Python Script in C#?, since C# can create DLLs, and you can call Python functions from C#.

To expand on the answer by Nick ODell

You must be on Windows for DLLs to work, they are not portable.

However the code below is cross platform and all platforms support run-times so this can be re-compiled for each platform you need it to work on.

Python does not (yet) provide an easy tool to create a dll, however you can do it in C/C++


First you will need a compiler (Windows does not have one by default) notably Cygwin, MinGW or Visual Studio.

A basic knowledge of C is also necessary (since we will be coding mainly in C).

You will also need to include the necessary headers, I will skip this so it does not become horribly long, and will assume everything is set up correctly.


For this demonstration I will print a traditional hello world:

Python code we will be converting to a DLL:

def foo(): print("hello world")

C code:

#include "Python.h" // Includes everything to use the Python-C API

int foo(void); // Declare foo

int foo(void) { // Name of our function in our DLL

    Py_Initialize(); // Initialise Python

    PyRun_SimpleString("print('hello world')"); // Run the Python commands

    return 0; // Finish execution
}

Here is the tutorial for embedding Python. There are a few extra things that should be added here, but for brevity I have left those out.

Compile it and you should have a DLL. :)


That is not all. You will need to distribute whatever dependencies are needed, that will mean the python36.dll run-time and some other components to run the Python script.

My C coding is not perfect, so if anyone can spot any improvements please comment and I will do my best to fix the it.


It might also be possible in C# from this answer How do I call a specific Method from a Python Script in C#?, since C# can create DLLs, and you can call Python functions from C#.

142 / 26 / 4

Регистрация: 06.05.2019

Сообщений: 1,680

Записей в блоге: 4

1

25.02.2020, 01:13. Показов 5944. Ответов 23


Если возможно что можно почитать и изучить, дайте информацию на такие ресурсы?



0



Programming

Эксперт

94731 / 64177 / 26122

Регистрация: 12.04.2006

Сообщений: 116,782

25.02.2020, 01:13

23

Эксперт Python

4606 / 2027 / 359

Регистрация: 17.03.2012

Сообщений: 10,084

Записей в блоге: 6

25.02.2020, 13:20

2

Не знаю, что такое mql.
Для С++ можно, но на сишной стороне надо будет использовать Python.h, т. е. специально адаптировать сишную часть. Но вообще неправильный подход, питон не для длл-ок. Для длл-ок следует использовать С++ и прочий натив.

Добавлено через 21 секунду
Гуглить Python/C API.



1



142 / 26 / 4

Регистрация: 06.05.2019

Сообщений: 1,680

Записей в блоге: 4

25.02.2020, 15:29

 [ТС]

3

Цитата
Сообщение от dondublon
Посмотреть сообщение

Для длл-ок следует использовать С++

Есть нужда в обработке имён функций и создании массивов, С++ не обладает такими гибкими возможностями, спасибо за советы.



0



Эксперт Python

4606 / 2027 / 359

Регистрация: 17.03.2012

Сообщений: 10,084

Записей в блоге: 6

25.02.2020, 17:16

4

Nexi99, не понял, что за обработка имён функций имеется в виду, но всё равно это не отменяет моего замечания.

Если у вас большое приложение на плюсах и надо небольшой кусочек вынести в питон, то используется Python embedding. Вот это уже да, штатная операция.



0



142 / 26 / 4

Регистрация: 06.05.2019

Сообщений: 1,680

Записей в блоге: 4

25.02.2020, 19:01

 [ТС]

5

Цитата
Сообщение от dondublon
Посмотреть сообщение

Python embedding

Спасибо за информацию, если доживу то буду это всё использовать.



0



142 / 26 / 4

Регистрация: 06.05.2019

Сообщений: 1,680

Записей в блоге: 4

14.04.2020, 19:07

 [ТС]

6

Цитата
Сообщение от dondublon
Посмотреть сообщение

Для С++ можно, но на сишной стороне надо будет использовать Python.h, т. е. специально адаптировать сишную часть.

Если адаптировать Python.h на сишной стороне, то этот код откомпилируется и будет работать напрямую с процессором как стандартный сишный код или он так и останется текстом и будет происходить постоянная трансляция между Python и с++?



0



Эксперт Python

4606 / 2027 / 359

Регистрация: 17.03.2012

Сообщений: 10,084

Записей в блоге: 6

15.04.2020, 10:50

7

Адаптировать Python.h не надо, он поставляется разработчиками питона. Адаптировать надо вашу сишную часть, чтобы она использовала Python.h.
Внутри ваш сишный код, конечно, будет работать как стандартный сишный код — он же сишный код. Насчёт трансляции не понял.



1



142 / 26 / 4

Регистрация: 06.05.2019

Сообщений: 1,680

Записей в блоге: 4

15.04.2020, 11:47

 [ТС]

8

Цитата
Сообщение от dondublon
Посмотреть сообщение

Адаптировать надо вашу сишную часть, чтобы она использовала Python.h.
Внутри ваш сишный код, конечно, будет работать как стандартный сишный код — он же сишный код.

Всё понятно спасибо.
Насчёт трансляции — я имел ввиду что будет происходить постоянное чтение скрипта/текста преобразование его в с++, а если вы пишите что этот код становится одним единым с сишным когда подключаешь Python.h к с++ то это в корне меняет дело.



0



Эксперт Python

4606 / 2027 / 359

Регистрация: 17.03.2012

Сообщений: 10,084

Записей в блоге: 6

15.04.2020, 13:22

9

Nexi99, питоновский код «транслируется» в штатном порядке, как питоновский. (На самом деле он не транслируется, но для простоты скажем так.)
Насчет «становится единым» — не совсем. Просто питоновский код сможет вызывать ваш сишный. Точно также, как он вызывает другой, «свой» сишный — например, внутренности списков.



0



Просто Лис

Эксперт Python

4862 / 3180 / 997

Регистрация: 17.05.2012

Сообщений: 9,288

Записей в блоге: 9

15.04.2020, 14:21

10

Цитата
Сообщение от dondublon
Посмотреть сообщение

mql.

mySQL же

Цитата
Сообщение от dondublon
Посмотреть сообщение

Просто питоновский код сможет вызывать ваш сишный.

Человеку наоборот надо из С++ вызывать питон.

ТС, там по факту вшивается интерпретатор питона. Пример: На сколько сложно перевести код Python на Си?



0



Garry Galler

Эксперт Python

5403 / 3827 / 1214

Регистрация: 28.10.2013

Сообщений: 9,554

Записей в блоге: 1

15.04.2020, 14:25

11

Цитата
Сообщение от Рыжий Лис
Посмотреть сообщение

mySQL же

Не а. Это трейдерский язык программирования a-la Си, только проще.

C
1
2
3
4
5
6
7
8
9
10
11
12
void OnStart() 
{
  //--- double three=3.0; 
  double x,y,z; 
  x=1/three; 
  y=4/three; 
  z=5/three; 
  if(x+y==z) 
    Print("1/3 + 4/3 == 5/3"); 
  else Print("1/3 + 4/3 != 5/3"); 
  // Результат: 1/3 + 4/3 != 5/3 
}

Цитата
Сообщение от Рыжий Лис
Посмотреть сообщение

Человеку наоборот надо из С++ вызывать питон.

Вот только ТС этого не понимает. Он думает что можно написать на Python скрипт, превратить его в обычную dll (не Python pyd) и потом пользоваться в С++.



0



Просто Лис

Эксперт Python

4862 / 3180 / 997

Регистрация: 17.05.2012

Сообщений: 9,288

Записей в блоге: 9

15.04.2020, 14:30

12

Наверное, можно и dll-ку скомпилить. Только она будет работать со скоростью питона, то есть никак.



0



142 / 26 / 4

Регистрация: 06.05.2019

Сообщений: 1,680

Записей в блоге: 4

15.04.2020, 17:57

 [ТС]

13

Цитата
Сообщение от Garry Galler
Посмотреть сообщение

Вот только ТС этого не понимает. Он думает что можно написать на Python скрипт, превратить его в обычную dll (не Python pyd) и потом пользоваться в С++.

Я уже разобрался благодаря вам конечно, что скомпилировать Пион не получиться.

Добавлено через 7 минут

Цитата
Сообщение от Рыжий Лис
Посмотреть сообщение

mql.
mySQL же

WinAPI

Добавлено через 2 часа 11 минут

Цитата
Сообщение от dondublon
Посмотреть сообщение

Для длл-ок следует использовать С++ и прочий натив

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



0



Просто Лис

Эксперт Python

4862 / 3180 / 997

Регистрация: 17.05.2012

Сообщений: 9,288

Записей в блоге: 9

15.04.2020, 18:04

14

Цитата
Сообщение от Nexi99
Посмотреть сообщение

как читаются dll библиотеки(например сишные),

Библиотека — она есть библиотека. Есть заголовки функций, в dll — сама скомпилированная функция. И при вызове функции можно уронить программу.



0



Эксперт Python

4606 / 2027 / 359

Регистрация: 17.03.2012

Сообщений: 10,084

Записей в блоге: 6

15.04.2020, 19:03

15

Цитата
Сообщение от Nexi99
Посмотреть сообщение

Скажите а как читаются dll библиотеки(например сишные), подключенные к основной программе как бинарные файлы или как скрипты

Что из себя представляет «основная программа»? Бинарные файлы и скрипты — это большая разница.



0



1550 / 875 / 179

Регистрация: 05.12.2015

Сообщений: 2,555

15.04.2020, 19:41

16

Nexi99, У меня к вам пара вопросов.
На этот форум регулярно приходят люди с вопросами, типа, как что-то прикрутить к mql, как что-то в этом mql-е сделать итд. Вот, соответственно, первый вопрос: Вы можете написать компилятор, или хотя бы транслятор своего языка по типу этого mql?
То есть люди написали этот mql. Написали кучу гайдов, как создать своего торгового бота и получать стопицот милиардов баксов в день ничего не делая, сами написание этого бота ниасилили? Если асилили, то почему они не молчат об этом, тупо гребя свое бабло? Почему они с вами решили поделиться? Почему вы считаете что они намного тупее вас, учитывая, что они таки написали этот mql?
И самый главный вопрос: как вы, блжад, на это ведетесь?



0



142 / 26 / 4

Регистрация: 06.05.2019

Сообщений: 1,680

Записей в блоге: 4

15.04.2020, 20:37

 [ТС]

17

Цитата
Сообщение от avgoor
Посмотреть сообщение

Вы можете написать компилятор, или хотя бы транслятор своего языка по типу этого mql?
То есть люди написали этот mql. Написали кучу гайдов, как создать своего торгового бота и получать стопицот милиардов баксов в день ничего не делая, сами написание этого бота ниасилили? Если асилили, то почему они не молчат об этом, тупо гребя свое бабло? Почему они с вами решили поделиться? Почему вы считаете что они намного тупее вас, учитывая, что они таки написали этот mql?
И самый главный вопрос: как вы, блжад, на это ведетесь?

Могу писать но у меня жизни не хватит на это эти оболочки и весь функционал долго строится. Но почему-то исходного кода от mql4 нет, как же мне модифицировать его, только писать свой компилятор или библиотеки. Кто неасилил написание бота я? Это дело большого времени, печи да и всё в чём проблема. Об этом умалчивают и очень хорошо. Кто со мной чем поделился, если бы поделился меня бы здесь не было. Я писал что они тупее, может и писал может и тупее что изменилось. Я пишу своего робота влаживая(очень большую) частицу себя. Возникает вопрос а языки программирования тоже ведь для маркетинга придумали правильно.



0



1550 / 875 / 179

Регистрация: 05.12.2015

Сообщений: 2,555

15.04.2020, 21:21

18

Цитата
Сообщение от Nexi99
Посмотреть сообщение

Могу писать но у меня жизни не хватит на это эти оболочки и весь функционал долго строится.

Ну и? Они, тупые, писали это чтоб ты обогатился? Сами-то они без тебя, конечно, грамотного робота не напишут. Вот на то, на что у тебя жизни не хватит у них времени хватило, а на робота… ну тупые они, без тебя никак.

Цитата
Сообщение от Nexi99
Посмотреть сообщение

Об этом умалчивают и очень хорошо

Да, это тайна за семью замками. Никто не знает. Только ты. Всех остальных в гугле забанили. Поэтому ты пришел на форум с тривиальным вопросом. Вот бы мне нагуглить как создать торгового робота и обогатиться за три секунды. Но, видишь ли, я, наверное, тупой. Вот, написать любой другой софт, где нужна определенная квалификация, я могу. А торгового робота… ну куда мне. Это только ты можешь.



0



142 / 26 / 4

Регистрация: 06.05.2019

Сообщений: 1,680

Записей в блоге: 4

15.04.2020, 22:14

 [ТС]

19

Цитата
Сообщение от avgoor
Посмотреть сообщение

Поэтому ты пришел на форум с тривиальным вопросом. Вот бы мне нагуглить как создать торгового робота и обогатиться за три секунды.

По поводу тупой не тупой скажу что я идейный человек.
Где я писал о том что можно написать робота за 3 с., а также о том как его написать, всему учился сам. Ни в одной из моих тем не было упоминания о подобном. Уже 3 года я топчусь и ушёл не очень далеко. И вообще если хотите писать подобные сообщения пишите мне в личку а не здесь, это не совсем корректно.



0



1550 / 875 / 179

Регистрация: 05.12.2015

Сообщений: 2,555

15.04.2020, 23:00

20

Цитата
Сообщение от Nexi99
Посмотреть сообщение

Где я писал о том что можно написать робота за 3 с., а также о том как его написать, всему учился сам. Ни в одной из моих тем не было упоминания о подобном.

Это очень простой софт. Придумать что-то проще сложно.

Цитата
Сообщение от Nexi99
Посмотреть сообщение

Уже 3 года я топчусь и ушёл не очень далеко.

Да. Потому что идти некуда. Это тупик. Проще «заработать» играя в казино.

Цитата
Сообщение от Nexi99
Посмотреть сообщение

И вообще если хотите писать подобные сообщения пишите мне в личку а не здесь, это не совсем корректно.

Это вполне корректно. Я писал о явлении торговых роботов как таковом. Может быть мои посты спасут кого-нибудь, в чью голову придет такая идея, но кто еще способен здраво ее осмыслить.



0



IT_Exp

Эксперт

87844 / 49110 / 22898

Регистрация: 17.06.2006

Сообщений: 92,604

15.04.2020, 23:00

20

Рука учит вас упаковать программу Python в DLL

Тип данных Python и Тип данных C выглядит как отношение «однонаправления« однонаправленно », кроме того, из-за Python он реализован языком C, поскольку Python реализуется языком C, поэтому функция между типом данных Python Операция также необходима для соответствия языку C. Итак, есть ли возможным «автоматическим» для замены, поверните код Python непосредственно в C-код? Ответ да, это главная проблема Cython.

В этом руководстве представит, как сделать Python Code в DLL для программ C / C ++ для программ C / C ++ с Cython.

Компилятор окружающей среды

  • Python 3 или Python 2
  • Visual Studio
  • JetBrains PyCharm

Установите Cython

Cython — это язык, который сочетает в себе грамматику Python и C, который можно просто дать Python со статическим типом синтаксиса.

Если Cython был установлен, вы можете пропустить этот шаг. Установка Cython Использовать easy_install, Python 2.7.9 или более поставлена ​​с Easy_install. Завершение в командной строке Visual Studio (обратите внимание, что версия Python использует 32 бита или 64-разрядную командную строку Visual Studio, можно запустить с привилегиями администратора):

easy_install -U cython

Компиляция с Цифоном

В новом проекте в Pycharm создайте файл PY: Great_module.py, введите следующее:

def str_add(str1, str2):
  return int(str1) + int(str2)

Это функция, которая преобразует строку для суммирования INT. Чтобы сделать эту функцию можно скомпилировать Cython, вам нужно создать новый файл run.pyx и добавить следующее:

cdef public int str_add(const char* str1,const char* str2):
  return int(str1) + int(str2)

CDEF и публикация — это все ключевые слова Cython, которые могут помочь функциям, которые могут быть вызваны внешними вызовами. Затем используйте следующую команду в Pycharm, чтобы генерировать два файла в Run.h и run.c.

cython run.pxy

Cython — это функция динамического типа, которая поддерживает Python. Если последующие шаги используют VS Command Line Compilation, также могут генерировать DLL, но я не знаю, почему я не могу извлечь функциональные адреса в DLL, поэтому равномерный тип, все параметры , и значения возврата используют ключевые слова статического типа Cython, чтобы указать типы данных.

Компилируйте динамическую библиотеку ссылок по VS

После получения .c и .h файл нам нужно создать проект VS DLL для него. Откройте VS-программное обеспечение, создайте новый проект Win32, в котором DLL выбора типа приложения и дополнительные параметры выбирают пустой проект. Скопируйте файл просто .c и .h к папке кода хранения проекта и добавьте его в проект. Добавьте пустую DLLMain.cpp в проекте и добавьте следующий код:

#include <Python.h>
#include <Windows.h>
#include "run.h"
extern "C"
{
  __declspec(dllexport) int __stdcall _str_add(const char * a, const char * b)
  {
    return str_add(a, b);
  }
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) 
{
  switch (fdwReason) 
  {
    case DLL_PROCESS_ATTACH:
      Py_Initialize();
      // DLL вызывается, когда она инициализирована, что является методом записи Python3, и Python2 изменяется, initrun (). Смотрите сгенерированный run.h
      PyInit_run();
      break;
    case DLL_PROCESS_DETACH:
      Py_Finalize();
      break;
  }
  return TRUE;
}

Щелкните правой кнопкой мыши на элементах, атрибутах, введите вкладку каталога VC ++. Добавить Python, включая «C: Programpfiles python36 включать». Добавьте Python’s Lib в библиотеку, такую ​​как «C: Program Files python36 libs». Обратите внимание, что выбрана сборная версия, а платформа X64 или платформа X32 выбирается в соответствии с версией Python. Файлы DLL могут быть получены после компиляции.

Динамический звонок DLL

Установите другой проект для проверки только что сгенерированной DLL. Откройте VS New Win32 Console Console и добавьте следующий код:

#include "stdafx.h"
#include <Windows.h>
#include <iostream>
using namespace std;
int main()
{
  // вызовите тест DLL
  typedef int(*pAdd)(const char * a, const char * b);
  HINSTANCE hDLL = LoadLibrary(_T("MyDLL.dll"));
  cout << "hDLL:" << hDLL << endl;
  if (hDLL)
  {
    / / Получить адрес функции, которая должна быть вызвана в DLL
    pAdd pFun = (pAdd)GetProcAddress(hDLL, "_str_add");
    cout << "pFun:" << pFun << endl;
    const char* stra= "12";
    const char* strb = "22";
    if (pFun)
    {
      int i = pFun(stra, strb);
      cout << "i = " << i << endl;
    }
  }
  system("pause");
  return 0;
}

Согласно выделению DLL Platform X86 или X64, выходной результат «I = 34» может быть получен после компиляции выпуска.

Добавить

  • После получения файлов .H и .C через Cython он может быть скомпилирован командой VS команда CL. Этот метод поддерживает динамический тип данных Python. Вам необходимо обратить внимание на выбора платформы X86 / X64 и привилегии администратора при компиляции. Но я не могу назвать правильно после успешной компиляции, и я до сих пор не знаю конкретных причин.
  • Компиляция под Linux будет более удобным, поскольку Linux Native поддерживает Python и имеет компилятор C / C ++, конфигурация окружающей среды будет легче.

Reference

  • C / C ++ и Python смешанное программирование
  • C ++ Регулирует ошибку приглашения скрипта Python Script LNK2001: невозможно разрешить внешний символ __imp_Py_initialize и другие ошибки
  • C ++ DLL Динамический вызов (явный)

Cover image for How to create a dynamic link library (DLL) and use it in .Net and Python

What is a DLL file?

A library is a collection of non-volatile resources that are used for software development. In this tutorial, we are going to create our own dynamic link library(DLL) using c#. A DLL is a library used on Microsoft platforms that contains code and data that can be used by more than one program at the same time. If you open the program information of most applications installed on Microsoft Windows you will notice DLL files. These DLL files store different functionalities for the application. Some of the advantages of DLL files are:

  1. Code reuse
  2. Efficient memory usage
  3. Reduced disk space
  4. Fast loading of applications

Making a DLL file

In this tutorial, we are going to make a simple calculator library that does addition, subtraction, multiplication, and division using C# in Visual Studio.

Create the project (library) in Visual Studio as follows

  1. Create new project
  2. Select C# Class Library (.Net Standard)
  3. Project name -> MyCalculator

The code for your library

Add the following code:

using System;

namespace MyCalculator
{
    public class Calculator
    {
        //Our addition function
        public double add(double num_one, double num_two)
        {
            return num_one + num_two;
        }
        //Our subtraction function
        public double subtract(double num_one, double num_two)
        {
            return num_one - num_two;
        }
        //Our multiplication function
        public double multiply(double num_one, double num_two)
        {
            return num_one * num_two;
        }
        //Our division function
        public double divide(double num_one, double num_two)
        {
            return num_one / num_two;         
        }
    }
}

Enter fullscreen mode

Exit fullscreen mode

Building your library project

Click on: Build -> Build Solution

Locating your Calculator Library

Your MyCalculator.dll is located in:

Your project folder -> MyCalculator -> MyCalculator -> bin -> debug

Using the DLL file in .Net

We are going to use our Calculator library MyCalculator.dll in a simple C# application.

Create a c# console application in Visual Studio as follows:

  1. File -> New -> Project
  2. Select: C# Console App
  3. Project name: MyProject

Importing our calculator library

  1. Copy MyCalculator.dll from: Your library project folder -> MyCalculator -> MyCalculator -> bin -> debug
  2. Paste MyCalculator.dll to Your project folder -> MyProject -> MyProject -> bin -> debug
  3. Add reference to your dll file:
    In solution explorer: Under MyProject -> Right click MyProject
    -> add -> Project reference
  4. Browse: Go to (Your project folder -> MyCalculator -> MyCalculator -> bin -> debug -> MyCalculator.dll
  5. Click add

The code for your project (MyProject)

Edit your code as follows:

using System;
using MyCalculator; // importing our calculator library

namespace MyProject
{
    class Program
    {
        static void Main(string[] args)
        {
            Calculator calc = new Calculator(); //Our Acalculator class object

            Console.WriteLine("Addition: "+calc.add(3, 2));
            Console.WriteLine("Subtraction: " + calc.subtract(3, 2));
            Console.WriteLine("Multiplication: " + calc.multiply(3, 2));
            Console.WriteLine("Division: " + calc.divide(3, 2));
        }
    }
}

Enter fullscreen mode

Exit fullscreen mode

Using the DLL file in Python

Install pythonnet

pip install pythonnet

Enter fullscreen mode

Exit fullscreen mode

Python code

import clr #import clr from pythonnet

#load our dll file(mine is in my C:\ folder)
clr.AddReference("C:\MyCalculator.dll")

#import our calculator class from Our C# namespace MyCalculator
from MyCalculator import Calculator

calc = Calculator() #create our Calculator object

#calling our methoths and printing
print("Addition: "+str(calc.add(3, 2)))
print("Subtraction: "+str(calc.subtract(3, 2)))
print("Multiplication: "+str(calc.multiply(3, 2)))
print("Division: "+str(calc.divide(3, 2)))

Enter fullscreen mode

Exit fullscreen mode

Понравилась статья? Поделить с друзьями:
  • Как написать ddos на python
  • Как написать daw
  • Как написать curl
  • Как написать csv файл
  • Как написать css селектор