Рубрики
Без рубрики

Как использовать объекты DLL / COM из Python или – Как отправить факс с Python

Используйте DLLs от Python. Отправьте факсы Python, не написав любым кодом, чтобы отправить факсы.

Автор оригинала: Spencer Phillip Young.

Как инженеры, мы знаем, что мы должны избегать наращивания колеса. Когда мы можем, мы хотим использовать библиотеки, написанные другими людьми, чтобы сделать некоторые тяжелые для нас. В этом посте я собираюсь поделиться с вами некоторыми вещами, которые я узнал о том, как использовать существующие библиотеки из DLL (или любых других файлов с информацией типа COM, такими как файлы TLB или OCX). В частности, я поделюсь некоторыми вещами, которые я узнал в моем путешествии, чтобы выяснить, как использовать Python, чтобы отправить факс. Поэтому мы в конечном итоге покажем, как вы можете использовать Windows DLL, которая находится за функциональными возможностями в Windows Факс и сканирование полезность.

DLL – это D ynamic- Л чернил Л Ibrary. Dlls – это Вид как исполняемые файлы. Они могут содержать код, данные и другие ресурсы. Есть много, что можно сказать о DLL, но для этого поста мы больше всего занимаются Код часть dlls.

Итак, все, что вам нужно знать прямо сейчас, так это то, что есть код (методы, которые можно назвать, свойства, которые можно прочитать и т. Д.), Это было написано другими инженерами, которые мы хотим повторно использовать в этих файлах DLL.

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

Есть несколько способов поступить об этом.

Используя ctypes.

CTYPES является частью стандартной библиотеки Python и, отчасти, она помогает нам использовать DLL.

В качестве краткого примера я покажу вам, как использовать Getsystemmetrics Метод, который существует в User32.dll который живет в Windows \ system32 \ user32.dll Отказ

Первый шаг – загрузить DLL. Это довольно просто.

import ctypes
User32 = ctypes.WinDLL('User32.dll')

Теперь мы можем начать назвать методы от этой DLL напрямую!

>>> User32.GetSystemMetrics(1) # Get the height of the primary monitor
1440

Довольно круто! Но вы можете спросить себя: как я узнал, чтобы получить доступ к способу под названием .Getsystemmretrics И как я узнал, чтобы пройти в 1 Как аргумент, чтобы получить высоту монитора?

Как мне знать, какие методы и свойства существуют?

Это сложная проблема. В мире DLL, обычно вы, как ожидается, узнают о методах заранее. Это обычно означает, что говорят или читают Документы Отказ Для приведенного выше примера мы можем прочитать в документах, которые Microsoft предоставляет этому Getsystemmetrics это метод, который принимает один параметр, целое число, представляющее индекс системной информации для получения:

int GetSystemMetrics(
  int nIndex
);

Документы также указывают, как целочисленные параметры отображаются на метрике системы. В таблице мы видим Sm_cyscreen Имеет индекс 1 И описывается как «высота экрана первичного монитора дисплея, в пикселях». На основании этой информации мы собрали вместе, чем мы можем позвонить User32.getsystemmetrics (1) Чтобы получить высоту основного монитора.

Что делать, если у нас нет документов?

Иногда нам недостаточно повезло, чтобы знать заранее или иметь доступные нам ссылки. Они также не очень удобны, даже когда у вас их есть. Вы заметите, что, в отличие от многих обычных классов Python, User32 Объект, который мы сделали ранее, не говорят нам, какие методы существуют в DLL. Вы можете попробовать позвонить dir (user32) Но это не даст вам никакой полезной информации.

Если вы пошли на рискнуть, как получить эту информацию без документов, вы, вероятно, будут сообщены использовать DLL Exporter или Com Browser. Введите Pywin32 Отказ

Используя pywin32.

Pywin32 – удивительная библиотека, которая позволяет вам взаимодействовать с API Windows через Python. Среди его много особенностей это win32com.client Компонент, который позволяет вам взаимодействовать с DLL. Одной из менее известных функций PYWIN32 является способность генерировать классы Python для всех методов DLL. Вы также можете использовать Pythoncom в качестве COM-браузера. Вы можете установить Pywin32, используя PIP Python -M PIP Установка Pywin32

Обзор библиотек COM в вашей системе:

python -m win32com.client.combrowse

Есть лучшие браузеры COM, но это аккуратно использовать это.

Но действительно интересная часть способна создавать классы Python для комбинаций COM-интерфейсов. Чтобы начать создание файла Python, вы можете запустить эту команду из оболочки

python -m win32com.client.makepy -i

Если вы не даете ему вход какую библиотеку, которую вы хотите создать, она предложит вам выбрать один. Я выбрал библиотеку Com Type Service Service Com (тот, кто позади Windows Факс и сканирование Инструмент) Вы увидите вывод что-то вроде этого:

Microsoft Fax Service Extended COM Type Library
 {2BF34C1A-8CAC-419F-8547-32FDF6505DB8}, lcid=0, major=1, minor=0
 >>> # Use these commands in Python code to auto generate .py support
 >>> from win32com.client import gencache
 >>> gencache.EnsureModule('{2BF34C1A-8CAC-419F-8547-32FDF6505DB8}', 0, 1, 0)

После этих инструкций мы можем сделать что-то вроде этого:

from win32com.client import gencache
faxcomex = gencache.EnsureModule('{2BF34C1A-8CAC-419F-8547-32FDF6505DB8}', 0, 1, 0)
print(dir(faxcomex)) # Unlike before, we can actually see some method names
print(repr(faxcomex)) # You'll notice the generated filename there, if you're curious to look.

Что интересно о созданном коде, состоит в том, что он поставляется в комплекте с Docstrings.

class IFaxServer(DispatchBaseClass):
  'IFaxServer Interface'
  CLSID = IID('{D73733C7-CC80-11D0-B225-00C04FB6C2F5}')
  coclass_clsid = IID('{D73733C8-CC80-11D0-B225-00C04FB6C2F5}')

  def Connect(self, ServerName=defaultNamedNotOptArg):
    'Makes a connection to a fax server'
    return self._oleobj_.InvokeTypes(1, LCID, 1, (24, 0), ((8, 0),),ServerName
      )

  def CreateDocument(self, FileName=defaultNamedNotOptArg):
    'Creates a fax document to send'
    return self._ApplyTypes_(4, 1, (12, 0), ((8, 0),), 'CreateDocument', None,FileName
      )

Так что вы могли бы даже делать такие вещи, как Помощь (faxcomex.ifaxserver.connect) в интерактивной оболочке. Довольно аккуратно! Если вы настолько склонны, вы можете даже скопировать этот сгенерированный код для чего-то вроде faxcomex.py и вместо faxcomex.ensuremodule ('{2BF34C1A-8CAC-419F-8547-32FDF6505DB8}', 0, 1, 0) Вы можете просто использовать Импорт факсcomex.

Исследуя генерированный код Python и чтение документов Microsoft для интерфейсов FAXCOMEX я придумаю следующую функцию.

from faxcomex import FaxDocument, FaxServer
def send_fax(number, subject, recipient_name='', servername='', body_doc='C:\\Path\\To\\SomeFile.tiff') 
    doc = FaxDocument()
    doc.Body = body_doc
    doc.Subject = subject
    doc.Recipients.Add(number, recipient_name)
    server = FaxServer()
    server.Connect(servername)
    doc.ConntectedSubmit(server)
    server.Disconnect()

Предполагая, что у вас есть факсимильный сервер, работающий на локальном и факсимильном модеме установкой, уже в инструменте факса Windows Fax и Scan ServerName = '' предполагает локальный сервер.

И это работает!

Сделать вещи немного приятнее и чувствовать Больше похоже на Python, мы можем скрыть некоторые артефакты COM-библиотеки путем подкласса сгенерированных классов Python.

from faxcomex import FaxServer, FaxDocument
class PyFaxServer(FaxServer):
    def __init__(self, servername=''):
        """get servername on object creation, so its not needed later"""
        super().__init__()
        self.__servername = servername
    def connect(self):
        """a python-naming-convention-compliant alias for `Connect`"""
        return self.Connect()
    def Connect(self):
        """override this so we can call connect without arguments"""
        return super().Connect(self.__servername)

    def _connection_manager(self):
        """manage connection and disconnection in a context manager"""
        try:
            yield self.connect()
        finally:
            self.Disconnect()

    def send(self, doc):
        """convenience method to connect to the server and send a document"""
        with self._connection_manager():
            doc.ConnectedSubmit(self)

class PyFaxDocument(FaxDocument):
    def __init__(self, *recipients, subject, body):
        super().__init__()
        for recipient_number, recipient_name in recipients:
            self.Recipients.Add(recipient_number, recipient_name)
        self.Subject = subject
        self.Body = body
    def submit(self, server):
        """Convenience method to submit document to a PyFaxServer object)"""
        server.send(self)

Теперь наш send_fax Функция выглядит и чувствует себя немного больше похоже на Python, хотя это MS DLL под капотом.

def send_fax(number, subject, body_doc, recipient_name='', servername=''):
    server = PyFaxServer(servername)
    recipient = (number, recipient_name)
    document = PyFaxDocument(recipient, subject=subject, body=body_doc)
    server.send(document)

Итак, мы реализовали Хороший Интерфейс FAX Server без написания практически любого собственного кода. Как круто!

Это все, что я получил сейчас.