Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python3 ctype CreateWindowEx simple example

I have googled for some time but could not find simple example of python3 ctypes and Win32 API for creating and showing window. Please point me to good link or show code here.

Thanks in advance!

like image 500
Darius Kucinskas Avatar asked Mar 18 '11 15:03

Darius Kucinskas


3 Answers

This is most easy to do with the win32gui module and its friends, win32api and win32con. There's no need to write your own ctypes wrappers to the Windows API. The simplest Petzold style app comes out something like this:

import win32api, win32con, win32gui

class MyWindow:

    def __init__(self):
        win32gui.InitCommonControls()
        self.hinst = win32api.GetModuleHandle(None)
        className = 'MyWndClass'
        message_map = {
            win32con.WM_DESTROY: self.OnDestroy,
        }
        wc = win32gui.WNDCLASS()
        wc.style = win32con.CS_HREDRAW | win32con.CS_VREDRAW
        wc.lpfnWndProc = message_map
        wc.lpszClassName = className
        win32gui.RegisterClass(wc)
        style = win32con.WS_OVERLAPPEDWINDOW
        self.hwnd = win32gui.CreateWindow(
            className,
            'My win32api app',
            style,
            win32con.CW_USEDEFAULT,
            win32con.CW_USEDEFAULT,
            300,
            300,
            0,
            0,
            self.hinst,
            None
        )
        win32gui.UpdateWindow(self.hwnd)
        win32gui.ShowWindow(self.hwnd, win32con.SW_SHOW)

    def OnDestroy(self, hwnd, message, wparam, lparam):
        win32gui.PostQuitMessage(0)
        return True

w = MyWindow()
win32gui.PumpMessages()
like image 194
David Heffernan Avatar answered Nov 11 '22 05:11

David Heffernan


Found this nice little trinket and took the time to get it working on nothing but the standard library of vanilla python 3.4.0:
(for those who wish to use natives over PyWin32)
http://code.activestate.com/recipes/208699-calling-windows-api-using-ctypes-and-win32con/

import sys
from ctypes import *

kernel32 = windll.kernel32
user32 = windll.user32
gdi32 = windll.gdi32

NULL = 0
CW_USEDEFAULT = -2147483648
IDI_APPLICATION = 32512
WS_OVERLAPPEDWINDOW = 13565952

CS_HREDRAW = 2
CS_VREDRAW = 1

IDC_ARROW = 32512
WHITE_BRUSH = 0

SW_SHOWNORMAL = 1

WNDPROC = WINFUNCTYPE(c_long, c_int, c_uint, c_int, c_int)

class WNDCLASS(Structure):
    _fields_ = [('style', c_uint),
                ('lpfnWndProc', WNDPROC),
                ('cbClsExtra', c_int),
                ('cbWndExtra', c_int),
                ('hInstance', c_int),
                ('hIcon', c_int),
                ('hCursor', c_int),
                ('hbrBackground', c_int),
                ('lpszMenuName', c_char_p),
                ('lpszClassName', c_char_p)]

class RECT(Structure):
    _fields_ = [('left', c_long),
                ('top', c_long),
                ('right', c_long),
                ('bottom', c_long)]

class PAINTSTRUCT(Structure):
    _fields_ = [('hdc', c_int),
                ('fErase', c_int),
                ('rcPaint', RECT),
                ('fRestore', c_int),
                ('fIncUpdate', c_int),
                ('rgbReserved', c_char * 32)]

class POINT(Structure):
    _fields_ = [('x', c_long),
                ('y', c_long)]

class MSG(Structure):
    _fields_ = [('hwnd', c_int),
                ('message', c_uint),
                ('wParam', c_int),
                ('lParam', c_int),
                ('time', c_int),
                ('pt', POINT)]

def ErrorIfZero(handle):
    if handle == 0:
        raise WinError
    else:
        return handle

def MainWin():
    global NULL
    CreateWindowEx          = user32.CreateWindowExA
    CreateWindowEx.argtypes = [c_int, c_char_p, c_char_p, c_int, c_int, c_int, c_int, c_int, c_int, c_int, c_int, c_int]
    CreateWindowEx.restype  = ErrorIfZero

    # Define Window Class
    wndclass = WNDCLASS()
    wndclass.style          = CS_HREDRAW | CS_VREDRAW
    wndclass.lpfnWndProc    = WNDPROC(WndProc)
    wndclass.cbClsExtra = wndclass.cbWndExtra = 0
    wndclass.hInstance      = kernel32.GetModuleHandleA(c_int(NULL))
    wndclass.hIcon          = user32.LoadIconA(c_int(NULL), c_int(IDI_APPLICATION))
    wndclass.hCursor        = user32.LoadCursorA(c_int(NULL), c_int(IDC_ARROW))
    wndclass.hbrBackground  = gdi32.GetStockObject(c_int(WHITE_BRUSH))
    wndclass.lpszMenuName   = None
    wndclass.lpszClassName  = b"MainWin"
    # Register Window Class
    if not user32.RegisterClassA(byref(wndclass)):
        raise WinError()
    # Create Window
    hwnd = CreateWindowEx(0,
                          wndclass.lpszClassName,
                          b"Python Window",
                          WS_OVERLAPPEDWINDOW,
                          CW_USEDEFAULT,
                          CW_USEDEFAULT,
                          CW_USEDEFAULT,
                          CW_USEDEFAULT,
                          NULL,
                          NULL,
                          wndclass.hInstance,
                          NULL)
    # Show Window
    user32.ShowWindow(c_int(hwnd), c_int(SW_SHOWNORMAL))
    user32.UpdateWindow(c_int(hwnd))
    # Pump Messages
    msg = MSG()
    pMsg = pointer(msg)
    NULL = c_int(NULL)

    while user32.GetMessageA( pMsg, NULL, 0, 0) != 0:
        user32.TranslateMessage(pMsg)
        user32.DispatchMessageA(pMsg)

    return msg.wParam

WM_PAINT = 15
WM_DESTROY = 2

DT_SINGLELINE = 32
DT_CENTER = 1
DT_VCENTER = 4
def WndProc(hwnd, message, wParam, lParam):
    ps = PAINTSTRUCT()
    rect = RECT()

    if message == WM_PAINT:
        hdc = user32.BeginPaint(c_int(hwnd), byref(ps))
        user32.GetClientRect(c_int(hwnd), byref(rect))
        user32.DrawTextA(c_int(hdc),
                         b"Python Powered Windows" ,
                         c_int(-1), byref(rect), 
                         DT_SINGLELINE|DT_CENTER|DT_VCENTER)
        user32.EndPaint(c_int(hwnd), byref(ps))
        return 0
    elif message == WM_DESTROY:
        user32.PostQuitMessage(0)
        return 0

    return user32.DefWindowProcA(c_int(hwnd), c_int(message), c_int(wParam), c_int(lParam))

if __name__=='__main__':
    sys.exit(MainWin())


like image 21
Tcll Avatar answered Nov 11 '22 06:11

Tcll


Here's a pure ctypes version based on the @Tcll answer ported to "wide" APIs as well. The original version didn't handle 64-bit Python correctly (casting handles to c_int) and was using the ANSI APIs, which isn't recommended anymore. It also declares full argtypes/restype for everything to help catch coding errors.

As you can see, it's much easier to use pywin32 instead.

Tested on Python 2.7 32-bit, Python 3.6 64-bit and Python 3.8 32-bit.

#coding:utf8
from __future__ import unicode_literals

import sys
from ctypes import *
from ctypes import wintypes as w  # ctypes has many pre-defined Windows types

def errcheck(result,func,args):
    if result is None or result == 0:
        raise WinError(get_last_error())
    return result

# Missing from ctypes.wintypes...
LRESULT = c_int64
HCURSOR = c_void_p

WNDPROC = WINFUNCTYPE(LRESULT,w.HWND,w.UINT,w.WPARAM,w.LPARAM)

def MAKEINTRESOURCEW(x):
    return w.LPCWSTR(x)

class WNDCLASSW(Structure):
    _fields_ = [('style', w.UINT),
                ('lpfnWndProc', WNDPROC),
                ('cbClsExtra', c_int),
                ('cbWndExtra', c_int),
                ('hInstance', w.HINSTANCE),
                ('hIcon', w.HICON),
                ('hCursor', HCURSOR),
                ('hbrBackground', w.HBRUSH),
                ('lpszMenuName', w.LPCWSTR),
                ('lpszClassName', w.LPCWSTR)]

class PAINTSTRUCT(Structure):
    _fields_ = [('hdc', w.HDC),
                ('fErase', w.BOOL),
                ('rcPaint', w.RECT),
                ('fRestore', w.BOOL),
                ('fIncUpdate', w.BOOL),
                ('rgbReserved', w.BYTE * 32)]

kernel32 = WinDLL('kernel32',use_last_error=True)
kernel32.GetModuleHandleW.argtypes = w.LPCWSTR,
kernel32.GetModuleHandleW.restype = w.HMODULE
kernel32.GetModuleHandleW.errcheck = errcheck

user32 = WinDLL('user32',use_last_error=True)
user32.CreateWindowExW.argtypes = w.DWORD,w.LPCWSTR,w.LPCWSTR,w.DWORD,c_int,c_int,c_int,c_int,w.HWND,w.HMENU,w.HINSTANCE,w.LPVOID
user32.CreateWindowExW.restype = w.HWND
user32.CreateWindowExW.errcheck = errcheck
user32.LoadIconW.argtypes = w.HINSTANCE,w.LPCWSTR
user32.LoadIconW.restype = w.HICON
user32.LoadIconW.errcheck = errcheck
user32.LoadCursorW.argtypes = w.HINSTANCE,w.LPCWSTR
user32.LoadCursorW.restype = HCURSOR
user32.LoadCursorW.errcheck = errcheck
user32.RegisterClassW.argtypes = POINTER(WNDCLASSW),
user32.RegisterClassW.restype = w.ATOM
user32.RegisterClassW.errcheck = errcheck
user32.ShowWindow.argtypes = w.HWND,c_int
user32.ShowWindow.restype = w.BOOL
user32.UpdateWindow.argtypes = w.HWND,
user32.UpdateWindow.restype = w.BOOL
user32.UpdateWindow.errcheck = errcheck
user32.GetMessageW.argtypes = POINTER(w.MSG),w.HWND,w.UINT,w.UINT
user32.GetMessageW.restype = w.BOOL
user32.TranslateMessage.argtypes = POINTER(w.MSG),
user32.TranslateMessage.restype = w.BOOL
user32.DispatchMessageW.argtypes = POINTER(w.MSG),
user32.DispatchMessageW.restype = LRESULT
user32.BeginPaint.argtypes = w.HWND,POINTER(PAINTSTRUCT)
user32.BeginPaint.restype = w.HDC
user32.BeginPaint.errcheck = errcheck
user32.GetClientRect.argtypes = w.HWND,POINTER(w.RECT)
user32.GetClientRect.restype = w.BOOL
user32.GetClientRect.errcheck = errcheck
user32.DrawTextW.argtypes = w.HDC,w.LPCWSTR,c_int,POINTER(w.RECT),w.UINT
user32.DrawTextW.restype = c_int
user32.EndPaint.argtypes = w.HWND,POINTER(PAINTSTRUCT)
user32.EndPaint.restype = w.BOOL
user32.PostQuitMessage.argtypes = c_int,
user32.PostQuitMessage.restype = None
user32.DefWindowProcW.argtypes = w.HWND,w.UINT,w.WPARAM,w.LPARAM
user32.DefWindowProcW.restype = LRESULT

gdi32 = WinDLL('gdi32',use_last_error=True)
gdi32.GetStockObject.argtypes = c_int,
gdi32.GetStockObject.restype = w.HGDIOBJ

CW_USEDEFAULT = -2147483648
IDI_APPLICATION = MAKEINTRESOURCEW(32512)
WS_OVERLAPPEDWINDOW = 13565952

CS_HREDRAW = 2
CS_VREDRAW = 1

IDC_ARROW = MAKEINTRESOURCEW(32512)
WHITE_BRUSH = 0

SW_SHOWNORMAL = 1

WM_PAINT = 15
WM_DESTROY = 2
DT_SINGLELINE = 32
DT_CENTER = 1
DT_VCENTER = 4

def MainWin():
    # Define Window Class
    wndclass = WNDCLASSW()
    wndclass.style          = CS_HREDRAW | CS_VREDRAW
    wndclass.lpfnWndProc    = WNDPROC(WndProc)
    wndclass.cbClsExtra = wndclass.cbWndExtra = 0
    wndclass.hInstance      = kernel32.GetModuleHandleW(None)
    wndclass.hIcon          = user32.LoadIconW(None, IDI_APPLICATION)
    wndclass.hCursor        = user32.LoadCursorW(None, IDC_ARROW)
    wndclass.hbrBackground  = gdi32.GetStockObject(WHITE_BRUSH)
    wndclass.lpszMenuName   = None
    wndclass.lpszClassName  = 'MainWin'

    # Register Window Class
    user32.RegisterClassW(byref(wndclass))

    # Create Window
    hwnd = user32.CreateWindowExW(0,
                          wndclass.lpszClassName,
                          'Python Window',
                          WS_OVERLAPPEDWINDOW,
                          CW_USEDEFAULT,
                          CW_USEDEFAULT,
                          CW_USEDEFAULT,
                          CW_USEDEFAULT,
                          None,
                          None,
                          wndclass.hInstance,
                          None)
    # Show Window
    user32.ShowWindow(hwnd,SW_SHOWNORMAL)
    user32.UpdateWindow(hwnd)

    # Pump Messages
    msg = w.MSG()
    while user32.GetMessageW(byref(msg), None, 0, 0) != 0:
        user32.TranslateMessage(byref(msg))
        user32.DispatchMessageW(byref(msg))

    return msg.wParam

def WndProc(hwnd, message, wParam, lParam):
    ps = PAINTSTRUCT()
    rect = w.RECT()

    if message == WM_PAINT:
        hdc = user32.BeginPaint(hwnd,byref(ps))
        user32.GetClientRect(hwnd,byref(rect))
        user32.DrawTextW(hdc,
                         'Python Powered Windows 你好吗?',
                         -1, byref(rect), 
                         DT_SINGLELINE|DT_CENTER|DT_VCENTER)
        user32.EndPaint(hwnd,byref(ps))
        return 0
    elif message == WM_DESTROY:
        user32.PostQuitMessage(0)
        return 0

    return user32.DefWindowProcW(hwnd,message,wParam,lParam)

if __name__=='__main__':
    sys.exit(MainWin())

enter image description here

like image 4
Mark Tolonen Avatar answered Nov 11 '22 05:11

Mark Tolonen