Skip to content

Instantly share code, notes, and snippets.

@Pagliacii
Last active February 25, 2024 20:40
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save Pagliacii/774ed5d3ea78a36cdb0754be6a25408d to your computer and use it in GitHub Desktop.
Save Pagliacii/774ed5d3ea78a36cdb0754be6a25408d to your computer and use it in GitHub Desktop.
Use ctypes to call WIndows API
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import ctypes
import os
from ctypes import windll, wintypes
from typing import Optional
NULL: int = 0
GENERIC_ALL: int = 28
GENERIC_EXECUTE: int = 29
GENERIC_WRITE: int = 30
GENERIC_READ: int = 31
FILE_SHARE_DISABLE: int = 0x00000000
FILE_SHARE_READ: int = 0x00000001
FILE_SHARE_WRITE: int = 0x00000002
FILE_SHARE_DELETE: int = 0x00000004
CREATE_NEW: int = 1
CREATE_ALWAYS: int = 2
OPEN_EXISTING: int = 3
OPEN_ALWAYS: int = 4
TRUNCATE_EXISTING: int = 5
FILE_ATTRIBUTE_READONLY: int = 0x1
FILE_ATTRIBUTE_HIDDEN: int = 0x2
FILE_ATTRIBUTE_SYSTEM: int = 0x4
FILE_ATTRIBUTE_DIRECTORY: int = 0x10
FILE_ATTRIBUTE_ARCHIVE: int = 0x20
FILE_ATTRIBUTE_DEVICE: int = 0x40
FILE_ATTRIBUTE_NORMAL: int = 0x80
FILE_ATTRIBUTE_TEMPORARY: int = 0x100
FILE_ATTRIBUTE_SPARSE_FILE: int = 0x200
FILE_ATTRIBUTE_REPARSE_POINT: int = 0x400
FILE_ATTRIBUTE_COMPRESSED: int = 0x800
FILE_ATTRIBUTE_OFFLINE: int = 0x1000
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED: int = 0x2000
FILE_ATTRIBUTE_ENCRYPTED: int = 0x4000
FILE_ATTRIBUTE_INTEGRITY_STREAM: int = 0x8000
FILE_ATTRIBUTE_VIRTUAL: int = 0x10000
FILE_ATTRIBUTE_NO_SCRUB_DATA: int = 0x20000
FILE_ATTRIBUTE_RECALL_ON_OPEN: int = 0x40000
FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS: int = 0x400000
FILE_FLAG_BACKUP_SEMANTICS: int = 0x02000000
FILE_FLAG_DELETE_ON_CLOSE: int = 0x04000000
FILE_FLAG_NO_BUFFERING: int = 0x20000000
FILE_FLAG_OPEN_NO_RECALL: int = 0x00100000
FILE_FLAG_OPEN_REPARSE_POINT: int = 0x00200000
FILE_FLAG_OVERLAPPED: int = 0x40000000
FILE_FLAG_POSIX_SEMANTICS: int = 0x0100000
FILE_FLAG_RANDOM_ACCESS: int = 0x10000000
FILE_FLAG_SESSION_AWARE: int = 0x00800000
FILE_FLAG_SEQUENTIAL_SCAN: int = 0x08000000
FILE_FLAG_WRITE_THROUGH: int = 0x80000000
# ref: https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/aa379560(v=vs.85)
class SECURITY_ATTRIBUTES(ctypes.Structure):
_fields_ = [
("nLength", wintypes.DWORD),
("lpSecurityDescriptor", wintypes.LPVOID),
("bInheritHandle", wintypes.BOOL)
]
# ref: https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-large_integer-r1
class LARGE_INTEGER(ctypes.Structure):
_fields_ = [
("QuadPart", ctypes.c_longlong)
]
# ref: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew
def create_file(
path: str,
access: int=GENERIC_READ,
share_mode: int=FILE_SHARE_DISABLE,
security_attrs: Optional[SECURITY_ATTRIBUTES]=None,
creation: int=OPEN_EXISTING,
flags: int=FILE_ATTRIBUTE_NORMAL,
template: Optional[wintypes.HANDLE]=None,
) -> wintypes.HANDLE:
CreateFileW = windll.kernel32.CreateFileW
CreateFileW.argtypes = (
wintypes.LPCWSTR, # LPCWSTR lpFileName
wintypes.DWORD, # DWORD dwDesiredAccess
wintypes.DWORD, # DWORD dwShareMode
wintypes.LPVOID, # LPSECURITY_ATTRIBUTES lpSecurityAttributes
wintypes.DWORD, # DWORD dwCreationDisposition
wintypes.DWORD, # DWORD dwFlagsAndAttributes
wintypes.HANDLE, # HANDLE hTemplateFile
)
CreateFileW.restype = wintypes.HANDLE
# these two arguments below have not been testing.
lpSecurityAttributes = ctypes.byref(security_attrs) if security_attrs else NULL
hTemplateFile = template if template else NULL
return CreateFileW(
path, access, share_mode, lpSecurityAttributes,
creation, flags, hTemplateFile
)
# ref: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfilesizeex
def get_file_size(path: str) -> int:
GetFileSizeEx = windll.kernel32.GetFileSizeEx
GetFileSizeEx.argtypes = (
wintypes.HANDLE, # HANDLE hFile
ctypes.POINTER(LARGE_INTEGER), # PLARGE_INTEGER lpFileSize
)
GetFileSizeEx.restype = wintypes.BOOL
size = LARGE_INTEGER(0)
handle = create_file(path)
result = GetFileSizeEx(handle, ctypes.byref(size))
close_handle(handle)
if not result:
raise ctypes.WinError()
return size.QuadPart
# ref: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppathw
def get_temp_path(max_size: Optional[int]=None) -> str:
GetTempPathW = windll.kernel32.GetTempPathW
GetTempPathW.argtypes = (
wintypes.DWORD, # DWORD nBufferLength
wintypes.LPWSTR, # LPWSTR lpBuffer
)
GetTempPathW.restype = wintypes.DWORD # zero for failure
if not max_size:
max_size = wintypes.MAX_PATH
buffer = ctypes.create_unicode_buffer(max_size)
lpBuffer = ctypes.cast(ctypes.byref(buffer), wintypes.LPWSTR)
result = GetTempPathW(max_size, lpBuffer)
if result == 0:
raise ctypes.WinError()
return buffer.value.rstrip()
# ref: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettempfilenamew
def get_temp_file_name(
parent_path: str=".",
prefix: Optional[str]=None,
unique: Optional[int]=0
) -> str:
GetTempFileNameW = windll.kernel32.GetTempFileNameW
GetTempFileNameW.argtypes = (
wintypes.LPCWSTR, # LPCWSTR lpPathName
wintypes.LPCWSTR, # LPCWSTR lpPrefixString
wintypes.UINT, # UINT uUnique
wintypes.LPWSTR, # LPWSTR lpTempFileName
)
GetTempFileNameW.restype = wintypes.UINT # zero for failure
buffer = ctypes.create_unicode_buffer(wintypes.MAX_PATH)
lpTempFileName = ctypes.cast(ctypes.byref(buffer), wintypes.LPWSTR)
result = GetTempFileNameW(parent_path, prefix, unique, lpTempFileName)
if result == 0:
raise ctypes.WinError()
return buffer.value.rstrip()
# ref: https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle
def close_handle(handle: wintypes.HANDLE) -> bool:
CloseHandle = windll.kernel32.CloseHandle
CloseHandle.argtypes = (wintypes.HANDLE,)
CloseHandle.restype = wintypes.BOOL
result = CloseHandle(handle)
if not result:
raise ctypes.WinError()
return True
def print_file_size(path: str) -> None:
print(f"The size of {path}:")
print(f"\tvia ctypes module: {get_file_size(path)}")
print(f"\tvia os module: {os.path.getsize(path)}")
print()
def main():
import tempfile
temp_dir: str = get_temp_path()
temp_file: str = get_temp_file_name(temp_dir, prefix="win")
path = os.path.abspath(temp_file)
with open(path, "wb") as f:
f.write(os.urandom(1024))
print("File generated by Win32 API.")
print_file_size(path)
temp_dir: str = tempfile.gettempdir()
file_descriptor: int
path: str
file_descriptor, path = tempfile.mkstemp(prefix="tempfile", dir=temp_dir)
with os.fdopen(file_descriptor, mode="wb") as f:
f.write(os.urandom(1024))
print("File generated by Python tempfile module.")
print_file_size(path)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment