Skip to content

Instantly share code, notes, and snippets.

@polyvertex
Last active August 27, 2020 04:34
Show Gist options
  • Save polyvertex/a5e40122e1835d9efa9b to your computer and use it in GitHub Desktop.
Save polyvertex/a5e40122e1835d9efa9b to your computer and use it in GitHub Desktop.
A wrapper over ctypes for the Windows API
import ctypes as ct
from ctypes.wintypes import *
import uuid
def has_func(ctypes_dll, func_name):
if hasattr(ctypes_dll, func_name):
return func_name
if not func_name.endswith("W") and hasattr(ctypes_dll, func_name + "W"):
return func_name + "W"
return None
def declare_func(*args, **kwargs):
return declare_func2(*args, **kwargs)[0]
def declare_func2(ctypes_dll, func_name, ret=None, arg=[]):
# do not fail if the function is not supported by the os
func_name = has_func(ctypes_dll, func_name)
if not func_name:
return None, None
# encapsulated *arg* in a list if needed
if isinstance(arg, tuple):
arg = list(arg)
elif not isinstance(arg, list):
arg = [arg]
# declare function in ctypes' namespace
func = getattr(ctypes_dll, func_name)
func.argtypes = arg
if ret is not None:
func.restype = ret
return func, func_name
def declare_global_func(*args, **kwargs):
func, name = declare_func2(*args, **kwargs)
if func:
globals()[name] = func
return func
return None
def ZeroMemory(ctypes_obj):
ct.memset(ct.addressof(ctypes_obj), 0, ct.sizeof(ctypes_obj))
LRESULT = LPARAM
LONG_PTR = LPARAM
ULONG_PTR = WPARAM
PVOID = ct.c_void_p
class COPYDATASTRUCT(ct.Structure):
_fields_ = [("dwData", ULONG_PTR),
("cbData", DWORD),
("lpData", PVOID)]
class GUID(Structure):
_fields_ = [
("Data1", DWORD),
("Data2", WORD),
("Data3", WORD),
("Data4", BYTE * 8)]
def __init__(self, uuidstr):
super().__init__(self)
(self.Data1, self.Data2, self.Data3, self.Data4[0], self.Data4[1],
rest) = uuid.UUID(uuidstr).fields
for i in range(2, 8):
self.Data4[i] = rest >> (8 - i - 1) * 8 & 0xff
class WNDCLASSEXW(ct.Structure):
_fields_ = [("cbSize", UINT),
("style", UINT),
("lpfnWndProc", WNDPROCTYPE),
("cbClsExtra", ct.c_int),
("cbWndExtra", ct.c_int),
("hInstance", HINSTANCE),
("hIcon", HICON),
("hCursor", HANDLE),
("hBrush", HBRUSH),
("lpszMenuName", LPCWSTR),
("lpszClassName", LPCWSTR),
("hIconSm", HICON)]
WNDPROCTYPE = ct.WINFUNCTYPE(LRESULT, HWND, UINT, WPARAM, LPARAM)
WM_QUIT = 0x12
WM_COPYDATA = 0x4A
WM_COMMAND = 0x0111
WM_USER = 0x0400
WAIT_TIMEOUT = 258
GWLP_USERDATA = -21
FOLDERID_AccountPictures = "{008ca0b1-55b4-4c56-b8a8-4de4b299d3be}" # %APPDATA%\Microsoft\Windows\AccountPictures
FOLDERID_CommonStartMenu = "{a4115719-d62e-491d-aa7c-e74b8be3b067}" # %ALLUSERSPROFILE%\Microsoft\Windows\Start Menu
FOLDERID_CommonStartup = "{82a5ea35-d9cd-47c5-9629-e15d2f714e6e}" # %ALLUSERSPROFILE%\Microsoft\Windows\Start Menu\Programs\StartUp
FOLDERID_Desktop = "{b4bfcc3a-db2c-424c-b029-7fe99a87c641}" # %USERPROFILE%\Desktop
FOLDERID_Documents = "{fdd39ad0-238f-46af-adb4-6c85480369c7}" # %USERPROFILE%\Documents
FOLDERID_Downloads = "{374de290-123f-4565-9164-39c4925e467b}" # %USERPROFILE%\Downloads
FOLDERID_LocalAppData = "{f1b32785-6fba-4fcf-9d55-7b8e7f157091}" # %LOCALAPPDATA% (%USERPROFILE%\AppData\Local)
FOLDERID_LocalAppDataLow = "{A520A1A4-1780-4FF6-BD18-167343C5AF16}" # %USERPROFILE%\AppData\LocalLow
FOLDERID_Profile = "{5e6c858f-0e22-4760-9afe-ea3317b67173}" # %USERPROFILE% (%SystemDrive%\Users\%USERNAME%)
FOLDERID_ProgramFiles = "{905e63b6-c1bf-494e-b29c-65b732d3d21a}" # %ProgramFiles%
FOLDERID_ProgramFilesX64 = "{6d809377-6af0-444b-8957-a3773f02200e}" # %ProgramFiles%
FOLDERID_ProgramFilesX86 = "{7c5a40ef-a0fb-4bfc-874a-c0f2e0b9fa8e}" # %ProgramFiles(x86)%
FOLDERID_RoamingAppData = "{3eb685db-65f9-4cf6-a03a-e3ef65729f3d}" # %APPDATA% (%USERPROFILE%\AppData\Roaming)
FOLDERID_StartMenu = "{625b53c3-ab48-4ec1-ba1f-a1ef4146fc19}" # %APPDATA%\Microsoft\Windows\Start Menu
FOLDERID_Startup = "{b97d20bb-f46a-4c97-ba10-5e3608430854}" # %APPDATA%\Microsoft\Windows\Start Menu\Programs\StartUp
FOLDERID_UserProgramFiles = "{5cd7aee2-2219-4a67-b85d-6c9ce15660cb}" # %LOCALAPPDATA%\Programs
FOLDERID_Windows = "{f38bf404-1d43-42f2-9305-67de0b28fc23}" # %windir%
kernel32 = ct.windll.kernel32
user32 = ct.windll.user32
shell32 = ct.windll.shell32
declare_global_func(kernel32, "GetLastError", ret=DWORD)
declare_global_func(kernel32, "GetModuleHandleW", ret=HMODULE, arg=[LPCWSTR])
declare_global_func(kernel32, "SetLastError", arg=[DWORD])
declare_global_func(user32, "ChangeWindowMessageFilterEx", ret=BOOL,
arg=[HWND, UINT, DWORD, ct.c_void_p])
declare_global_func(user32, "CreateWindowExW", ret=HWND, arg=[
DWORD, LPCWSTR, LPCWSTR, DWORD, ct.c_int, ct.c_int, ct.c_int, ct.c_int,
HWND, HANDLE, HINSTANCE, LPVOID])
declare_global_func(user32, "DefWindowProcW", ret=LRESULT,
arg=[HWND, UINT, WPARAM, LPARAM])
declare_global_func(user32, "DestroyWindow", ret=BOOL, arg=[HWND])
declare_global_func(user32, "DispatchMessageW", ret=LRESULT, arg=[LPMSG])
declare_global_func(user32, "FindWindowW", ret=HWND, arg=[LPCWSTR, LPCWSTR])
declare_global_func(user32, "GetClassInfoExW", ret=BOOL,
arg=[HANDLE, LPCWSTR, ct.POINTER(WNDCLASSEXW)])
declare_global_func(user32, "GetWindowLongPtrW", ret=LONG_PTR,
arg=[HWND, ct.c_int])
declare_global_func(user32, "MsgWaitForMultipleObjects", ret=DWORD,
arg=[DWORD, ct.POINTER(HANDLE), BOOL, DWORD, DWORD])
declare_global_func(user32, "PeekMessageW", ret=BOOL,
arg=[LPMSG, HWND, UINT, UINT, UINT])
declare_global_func(user32, "RegisterClassExW", ret=ATOM,
arg=[ct.POINTER(WNDCLASSEXW)])
declare_global_func(user32, "SendMessageW", ret=LRESULT,
arg=[HWND, UINT, WPARAM, LPARAM])
declare_global_func(user32, "SetWindowLongPtrW", ret=LONG_PTR,
arg=[HWND, ct.c_int, LONG_PTR])
declare_global_func(user32, "TranslateMessage", ret=BOOL, arg=[LPMSG])
declare_global_func(shell32, "SHGetKnownFolderPath", ret=ct.HRESULT,
arg=[ct.POINTER(GUID), DWORD, HANDLE, PWSTR])
def get_known_folder_path(known_folder_guidstr):
guid = GUID(known_folder_guidstr)
path_ptr = ct.c_wchar_p()
res = SHGetKnownFolderPath(ct.byref(guid), 0, None, ct.byref(path_ptr))
if res:
raise OSError(0, "SHGetKnownFolderPath('{}') failed (code {})".format(known_folder_guidstr, res), None, res)
return path_ptr.value
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment