GitHub Viewer
#include
#include
#include
#include
#include "helpers.h"
extern "C" {
PyObject *coinitialize(PyObject *, PyObject *args, PyObject *kwargs) {
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if (FAILED(hr)) {
PyErr_SetFromWindowsErr(hr);
return NULL;
}
Py_RETURN_NONE;
}
static void _invalid_parameter(
const wchar_t * expression,
const wchar_t * function,
const wchar_t * file,
unsigned int line,
uintptr_t pReserved
) { }
PyObject *fd_supports_vt100(PyObject *, PyObject *args, PyObject *kwargs) {
static const char * keywords[] = {"fd", NULL};
int fd;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i:fd_supports_vt100", keywords, &fd)) {
return NULL;
}
PyObject *r = NULL;
HANDLE h;
DWORD mode;
const DWORD expect_flags = ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING;
auto handler = _set_thread_local_invalid_parameter_handler(_invalid_parameter);
h = (HANDLE)_get_osfhandle(fd);
_set_thread_local_invalid_parameter_handler(handler);
if (GetConsoleMode(h, &mode)) {
if ((mode & expect_flags) == expect_flags) {
r = Py_GetConstant(Py_CONSTANT_TRUE);
} else {
r = Py_GetConstant(Py_CONSTANT_FALSE);
}
} else {
PyErr_SetFromWindowsErr(0);
}
return r;
}
PyObject *date_as_str(PyObject *, PyObject *, PyObject *) {
wchar_t buffer[256];
DWORD cch = GetDateFormatEx(
LOCALE_NAME_INVARIANT,
0,
NULL,
L"yyyyMMdd",
buffer,
sizeof(buffer) / sizeof(buffer[0]),
NULL
);
if (!cch) {
PyErr_SetFromWindowsErr(0);
return NULL;
}
return PyUnicode_FromWideChar(buffer, cch - 1);
}
PyObject *datetime_as_str(PyObject *, PyObject *, PyObject *) {
wchar_t buffer[256];
DWORD cch = GetDateFormatEx(
LOCALE_NAME_INVARIANT,
0,
NULL,
L"yyyyMMdd",
buffer,
sizeof(buffer) / sizeof(buffer[0]),
NULL
);
if (!cch) {
PyErr_SetFromWindowsErr(0);
return NULL;
}
cch -= 1;
cch += GetTimeFormatEx(
LOCALE_NAME_INVARIANT,
0,
NULL,
L"HHmmss",
&buffer[cch],
sizeof(buffer) / sizeof(buffer[0]) - cch
);
return PyUnicode_FromWideChar(buffer, cch - 1);
}
PyObject *reg_rename_key(PyObject *, PyObject *args, PyObject *kwargs) {
static const char * keywords[] = {"handle", "name1", "name2", NULL};
PyObject *handle_obj;
wchar_t *name1 = NULL;
wchar_t *name2 = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO&O&:reg_rename_key", keywords,
&handle_obj, as_utf16, &name1, as_utf16, &name2)) {
return NULL;
}
PyObject *r = NULL;
HKEY h;
if (PyLong_AsNativeBytes(handle_obj, &h, sizeof(h), -1) >= 0) {
int err = (int)RegRenameKey(h, name1, name2);
if (!err) {
r = Py_GetConstant(Py_CONSTANT_NONE);
} else {
PyErr_SetFromWindowsErr(err);
}
}
PyMem_Free(name1);
PyMem_Free(name2);
return r;
}
PyObject *get_current_package(PyObject *, PyObject *, PyObject *) {
wchar_t package_name[256];
UINT32 cch = sizeof(package_name) / sizeof(package_name[0]);
int err = GetCurrentPackageFamilyName(&cch, package_name);
switch (err) {
case ERROR_SUCCESS:
return PyUnicode_FromWideChar(package_name, cch ? cch - 1 : 0);
case APPMODEL_ERROR_NO_PACKAGE:
return Py_GetConstant(Py_CONSTANT_NONE);
default:
PyErr_SetFromWindowsErr(err);
return NULL;
}
}
PyObject *read_alias_package(PyObject *, PyObject *args, PyObject *kwargs) {
static const char * keywords[] = {"path", NULL};
wchar_t *path = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&:read_alias_package", keywords,
as_utf16, &path)) {
return NULL;
}
HANDLE h = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL);
PyMem_Free(path);
if (h == INVALID_HANDLE_VALUE) {
PyErr_SetFromWindowsErr(0);
return NULL;
}
struct {
DWORD tag;
DWORD _reserved1;
DWORD _reserved2;
wchar_t package_name[256];
wchar_t nul;
} buffer;
DWORD nread;
if (!DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0,
&buffer, sizeof(buffer), &nread, NULL)
// we expect our buffer to be too small, but we only want the package
&& GetLastError() != ERROR_MORE_DATA) {
PyErr_SetFromWindowsErr(0);
CloseHandle(h);
return NULL;
}
CloseHandle(h);
if (buffer.tag != IO_REPARSE_TAG_APPEXECLINK) {
return Py_GetConstant(Py_CONSTANT_NONE);
}
buffer.nul = 0;
return PyUnicode_FromWideChar(buffer.package_name, -1);
}
typedef LRESULT (*PSendMessageTimeoutW)(
HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam,
UINT fuFlags,
UINT uTimeout,
PDWORD_PTR lpdwResult
);
PyObject *broadcast_settings_change(PyObject *, PyObject *, PyObject *) {
// Avoid depending on user32 because it's so slow
HMODULE user32 = LoadLibraryExW(L"user32.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
if (!user32) {
PyErr_SetFromWindowsErr(0);
return NULL;
}
PSendMessageTimeoutW sm = (PSendMessageTimeoutW)GetProcAddress(user32, "SendMessageTimeoutW");
if (!sm) {
PyErr_SetFromWindowsErr(0);
FreeLibrary(user32);
return NULL;
}
// SendMessageTimeout needs special error handling
SetLastError(0);
LPARAM lParam = (LPARAM)L"Environment";
if (!(*sm)(
HWND_BROADCAST,
WM_SETTINGCHANGE,
NULL,
lParam,
SMTO_ABORTIFHUNG,
50,
NULL
)) {
int err = GetLastError();
if (!err) {
PyErr_SetString(PyExc_OSError, "Unspecified error");
} else {
PyErr_SetFromWindowsErr(err);
}
FreeLibrary(user32);
return NULL;
}
FreeLibrary(user32);
return Py_GetConstant(Py_CONSTANT_NONE);
}
// We load IsWow64Process2 dynamically to avoid breaking on earlier OS than we
// officially support. If the API doesn't exist, then we assume -64.
typedef BOOL (*PIsWow64Process2)(HANDLE, USHORT*, USHORT*);
PyObject *get_processor_architecture(PyObject *, PyObject *, PyObject *) {
USHORT dummy, machine = IMAGE_FILE_MACHINE_AMD64;
HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll");
if (kernel32) {
PIsWow64Process2 isWow64Process2 = (PIsWow64Process2)GetProcAddress(kernel32, "IsWow64Process2");
if (!isWow64Process2 || !isWow64Process2(0, &dummy, &machine)) {
machine = IMAGE_FILE_MACHINE_AMD64;
}
}
switch (machine) {
case IMAGE_FILE_MACHINE_I386: return PyUnicode_FromString("-32");
case IMAGE_FILE_MACHINE_ARM64: return PyUnicode_FromString("-arm64");
}
return PyUnicode_FromString("-64");
}
PyObject *get_environment_block(PyObject *, PyObject *, PyObject *) {
HANDLE token = NULL;
wchar_t *env = NULL;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_DUPLICATE, &token)
|| !CreateEnvironmentBlock((LPVOID *)&env, token, FALSE)) {
PyErr_SetFromWindowsErr(0);
if (token) CloseHandle(token);
return NULL;
}
// env is double null terminated, so read each string's length until we find
// the zero-length one. Our caller can do the split.
wchar_t *p = env;
size_t cch = wcslen(p);
while (p && cch) {
p += cch + 1;
cch = wcslen(p);
}
PyObject *r = PyUnicode_FromWideChar(env, p - env);
DestroyEnvironmentBlock(env);
CloseHandle(token);
return r;
}
}