Python в Cygwin: WinAPI в отсутствии windll

от автора

Если верить обещаниям Microsoft, в скором времени Windows обзаведется возможностью запускать Linux приложения без каких-либо доработок напильником и сторонних сред окружения вроде Cygwin; одни восприняли эти обещания скептически, дескать, с поддержкой «андроид»-приложений ведь все сошло на нет, другие стали ерничать, мол, ожидайте в недалеком будущем Lindows, ну а третьи… Впрочем, найдутся и четвертые и пятые, — обещания — в будущем, а мы с вами живем здесь и сейчас, решаем задачи также здесь и сейчас, а следовательно какой резон толочь воду в ступе? Приятно, конечно, когда в системе уже предусмотрено нечто в разы упрощающее администрирование, но если этого нет, всегда найдется альтернативный вариант.

Cygwin для многих разработчиков стал своего рода стандартом де-факто: все что нужно для «быстрого старта» в одном инсталляторе, — кто-то под Cygwin даже создает отдельный раздел на диске; но вот что действительно непонятно, так это, например, для чего при развернутом в Cygwin Python устанавливать еще дистрибутив последнего с официального сайта, мотивируя это отсутствием windll в первом? Не знаю, может я не прав, но по-моему это — блажь, ибо Python суть вещь кроссплатформенная и хорошо документированная, а значит все, что написано с использованием windll заработает в окружении Cygwin. Чтобы было понятно о чем речь, приведу примеры вывода «виндового» Python:

>>> from ctypes import windll >>> 'windll' in globals() True >>> 

и того, что устанавливается в Cygwin:

>>> from ctypes import windll Traceback (most recent call last):   File "<stdin>", line 1, in <module> ImportError: cannot import name 'windll' >>> 

Так как же оно тогда заработает в Cygwin?! Все предельно просто, если обратиться к документации.

>>> from ctypes import cdll >>> cdll.kernel32.GetCurrentProcessId() 1592 >>> 

Дабы не переписывать в сценариях windll на cdll:

from os import name  if name is 'posix':  # name в Cygwin возвращает posix    from ctypes import cdll else:    from ctypes import windll  windll = cdll if 'cdll' in globals() else windll 

А чтобы головоломка сложилась, попробуем это применить на практике. Запускам bash (или mintty):

greg@greg:~$ cd /usr/local/bin/ greg@greg:/usr/local/bin$ vim uptime.py 

Конечно же код ниже только для примера.

#!/usr/bin/env python3  from os import name  if name is 'posix':    from ctypes import cdll else:    from ctypes import windll  windll = cdll if 'cdll' in globals() else windll  from ctypes import byref, c_void_p, c_wchar_p from struct import pack, unpack from sys    import exit  sti = pack('qqqLLQQ', 1, 2, 3, 4, 5, 6, 7) nts = windll.ntdll.NtQuerySystemInformation(3, sti, len(sti), 0) if nts != 0:    msg = c_void_p()    windll.kernel32.FormatMessageW(       0x00001100, None, windll.ntdll.RtlNtStatusToDosError(nts),       1024, byref(msg), 0, None    )    err = c_wchar_p(msg.value).value    windll.kernel32.LocalFree(msg)    print(err.strip() if err else 'Unknown error has been occured.')    exit(1) sti = unpack('qqqLLQQ', sti) sec = (sti[1] - sti[0]) / 1e7 print('%.u.%.2u:%.2u:%.2u' % (    sec / 86400, (sec / 3600) % 24, (sec % 3600) / 60, sec % 60 )) 

Сохраняем и выходим. Далее:

greg@greg:/usr/local/bin$ chmod 510 uptime.py greg@greg:/usr/local/bin$ ln -T uptime.py /bin/uptime greg@greg:/usr/local/bin$ cd greg@greg:~$ uptime 13.07:53:29 greg@greg:~$ exit 

Если путь до папки bin Cygwin прописан в переменной PATH командной строки Windows:

E:\src>sh -c uptime 13.07:53:59 

Как видим, все работает должным образом и из-под Cygwin.

ссылка на оригинал статьи https://habrahabr.ru/post/282720/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *