The ShellExecute API call will spawn a new process, it won't elevate permissions for the current process running.

Let's analyze this code snippet:

if is_admin():
    main()
else:
    ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, " ".join(sys.argv), None, 1)

When you first run this Python script without privileges, this initial process will jump to the last line of the code because is_admin returns False. Once there, the UAC prompt is displayed.

  • If the UAC prompt is accepted, then a completely new process (with different process ID) is created and the code is executed again (from the beginning), but this time with admin privileges. Now is_admin should return True and main should be called.
  • If the UAC prompt is rejected, no new process is created.

Regardless of the UAC response, the initial process will get the return code back, but its privileges will remain unaltered.

If you want to try this yourself, add an input() at the end of the file and you should be able to see two different windows after accepting the UAC prompt.

To avoid having your code being executed twice be sure to keep everything inside the main function. If you want to take an action based on the return code, this only makes sense for failures (code <= 32). If the return code is successfull (> 32), then the process should end gracefully and let the new spawned process do its job.

Answer from Martín De la Fuente on Stack Overflow
🌐
ProgramCreek
programcreek.com › python › example › 68647 › ctypes.windll.shell32
Python Examples of ctypes.windll.shell32
# pylint: disable=no-name-in-module,F0401 from ctypes import byref, c_int, POINTER, windll, WINFUNCTYPE from ctypes.wintypes import LPCWSTR, LPWSTR # <http://msdn.microsoft.com/en-us/library/ms683156.aspx> GetCommandLineW = WINFUNCTYPE(LPWSTR)(('GetCommandLineW', windll.kernel32)) # <http://msdn.microsoft.com/en-us/library/bb776391.aspx> CommandLineToArgvW = WINFUNCTYPE(POINTER(LPWSTR), LPCWSTR, POINTER(c_int))( ('CommandLineToArgvW', windll.shell32)) argc = c_int(0) argv_unicode = CommandLineToArgvW(GetCommandLineW(), byref(argc)) argv = [ argv_unicode[i].encode(encoding, 'replace') for i in range(0, argc.value) ] if not hasattr(sys, 'frozen'): # If this is an executable produced by py2exe or bbfreeze, then it # will have been invoked directly.
Discussions

python - How do I run a script with elevated UAC permissions using ctypes? - Stack Overflow
I'm attempting to create a utility tool via Python 3.x for the Windows 10 command-line. Since it will better format general command-line commands into more user-friendly menus, I want it to require More on stackoverflow.com
🌐 stackoverflow.com
python ctypes, call user32 and kernel32 func with arguments - Stack Overflow
I need to know how many arguments to pass in user32 and kernel32 functions for example : windll.kernel32.GetConsoleTitle() I get Error : :ValueError: Procedure probably called with not enough More on stackoverflow.com
🌐 stackoverflow.com
Request UAC Elevation From Within Python Script With ctypes.windll.shell32.ShellExecuteW - Stack Overflow
Copyimport ctypes, sys from my_module import myClass def is_admin(): try: return ctypes.windll.shell32.IsUserAnAdmin() except: return False if is_admin(): myClass else: # Re-run the program with admin rights ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, "", None, 1) More on stackoverflow.com
🌐 stackoverflow.com
February 22, 2018
python - Importing ctypes.windll.shell32.IsUserAnAdmin gives ImportError - Stack Overflow
Really stupid question here, sorry - it's my first day in Python. I want to import the 'IsUserAnAdmin' function like so: from ctypes.windll.shell32 import IsUserAnAdmin I'm obviously doing someth... More on stackoverflow.com
🌐 stackoverflow.com
🌐
Python
docs.python.org › 3 › library › ctypes.html
ctypes — A foreign function library for Python
Class which loads shared libraries. dlltype should be one of the CDLL, PyDLL, WinDLL, or OleDLL types.
Top answer
1 of 2
1

The ShellExecute API call will spawn a new process, it won't elevate permissions for the current process running.

Let's analyze this code snippet:

if is_admin():
    main()
else:
    ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, " ".join(sys.argv), None, 1)

When you first run this Python script without privileges, this initial process will jump to the last line of the code because is_admin returns False. Once there, the UAC prompt is displayed.

  • If the UAC prompt is accepted, then a completely new process (with different process ID) is created and the code is executed again (from the beginning), but this time with admin privileges. Now is_admin should return True and main should be called.
  • If the UAC prompt is rejected, no new process is created.

Regardless of the UAC response, the initial process will get the return code back, but its privileges will remain unaltered.

If you want to try this yourself, add an input() at the end of the file and you should be able to see two different windows after accepting the UAC prompt.

To avoid having your code being executed twice be sure to keep everything inside the main function. If you want to take an action based on the return code, this only makes sense for failures (code <= 32). If the return code is successfull (> 32), then the process should end gracefully and let the new spawned process do its job.

2 of 2
0
import ctypes
import sys
import platform

def admin() -> "Admin Bool":
    """Requests UAC Admin on Windows with a prompt"""
    if platform.system() == "Windows":
        ctypes.windll.shell32.ShellExecuteW(
            None,
            'runas',
            sys.executable,
            ' '.join(sys.argv),
            None,
            None
        )
        
        try:
            return ctypes.windll.shell32.IsUserAnAdmin()
        
        except:
            return False
        
    else:
        raise OSError("admin() only works for windows.")

This will request admin with an admin prompt. If True is returned, then admin has been granted by the user. Else, False will be returned.

🌐
GitHub
gist.github.com › TotalLag › f85eaf831c29b3a411a69187d9eef317
Re-run the program with admin rights in Python · GitHub
Re-run the program with admin rights in Python. GitHub Gist: instantly share code, notes, and snippets.
🌐
Lonami
lonami.dev › blog › ctypes-and-windows
Python ctypes and Windows | Lonami's Blog
June 19, 2019 - KEYEVENTF_KEYUP = 0x0002 def press(vk, down): inputs = INPUT(type=INPUT_KEYBOARD, value=INPUTUNION(ki=KEYBDINPUT( wVk=vk, wScan=0, dwFlags=0 if down else KEYEVENTF_KEYUP, time=0, dwExtraInfo=None ))) ctypes.windll.user32.SendInput(1, ctypes.byref(inputs), ctypes.sizeof(inputs)) for char in 'HELLO': press(ord(char), down=True) press(ord(char), down=False)
Find elsewhere
🌐
Python
svn.python.org › projects › ctypes › trunk › ctypes › docs › manual › tutorial.html
ctypes tutorial
ValueError: Procedure probably ... >>> >>> windll.msvcrt.printf("spam") # doctest: +WINDOWS Traceback (most recent call last): File "<stdin>", line 1, in ? ValueError: Procedure probably called with too many arguments (4 bytes in excess) >>> To find out the correct calling convention you have to look into the C header file or the documentation for the function you want to call. On Windows, ctypes uses win32 ...
🌐
GitHub
gist.github.com › princox › 92ad572cde940604adeaedea51cf5848
python execution file · GitHub
python execution file. GitHub Gist: instantly share code, notes, and snippets.
Top answer
1 of 2
3

Sure, it's located in pythoncom and shell for constants, for example:

from win32com.shell import shell
import pythoncom

# create an instance of IFileOperation
fo = pythoncom.CoCreateInstance(shell.CLSID_FileOperation, None, pythoncom.CLSCTX_ALL, shell.IID_IFileOperation)

# here you can use SetOperationFlags, progress Sinks, etc.

# create an instance of IShellItem for the source item
item1 = shell.SHCreateItemFromParsingName("c:\\temp\\source.txt", None, shell.IID_IShellItem)

# create an instance of IShellItem for the target folder
folder = shell.SHCreateItemFromParsingName("c:\\another", None, shell.IID_IShellItem)

# queue the copy operation
fo.CopyItem(item1, folder, "new name.txt", None)

# commit
fo.PerformOperations()
2 of 2
1

This question put me on track, as it shows that COM loading Windows functionality is in fact avialable from ctypes, albeit it requires a bit more work.

The question uses comtypes.GUID as the only (non standard) dependency.

Looking at comtypes itself, it's pure python and uses ctypes (for CoCreateInstance and all else), and the paths to the windows functions needed to load and handle the COM object can be found, specifically -

import ctypes
ctypes.oledll.ole32.CoCreateInstance()

The CLSIDs need to be put explicitly, as in the referred question -

IID_IFileOperation  = '{947AAB5F-0A5C-4C13-B4D6-4BF7836FC9F8}'
CLSID_FileOperation = '{3AD05575-8857-4850-9277-11B85BDB8E09}'

All and all, comtypes, which is a small pure python library, seems quite enough for this task, if one doesn't want to tinker with ctypes, paste in GUID or else doesn't mind the dependency.

However, this is fully implementable in ctypes, as proven by comtypes itself, with the caveat of possibly having to add in GUID manually -

from ctypes import *

BYTE, WORD, DWORD = c_byte, c_ushort, c_ulong

_StringFromCLSID = oledll.ole32.StringFromCLSID
_ProgIDFromCLSID = oledll.ole32.ProgIDFromCLSID
_CLSIDFromString = oledll.ole32.CLSIDFromString
_CLSIDFromProgID = oledll.ole32.CLSIDFromProgID
_CoCreateGuid    = oledll.ole32.CoCreateGuid

_CoTaskMemFree   = windll.ole32.CoTaskMemFree

class GUID(Structure):
    _fields_ = [("Data1", DWORD),
                ("Data2", WORD),
                ("Data3", WORD),
                ("Data4", BYTE * 8)]

    def __init__(self, name=None):
        if name is not None:
            _CLSIDFromString(unicode(name), byref(self))

    def __repr__(self):
        return u'GUID("%s")' % unicode(self)

    def __unicode__(self):
        p = c_wchar_p()
        _StringFromCLSID(byref(self), byref(p))
        result = p.value
        _CoTaskMemFree(p)
        return result
    __str__ = __unicode__

    def __cmp__(self, other):
        if isinstance(other, GUID):
            return cmp(bytes(self), bytes(other))
        return -1

    def __nonzero__(self):
        return self != GUID_null

    def __eq__(self, other):
        return isinstance(other, GUID) and \
               bytes(self) == bytes(other)

    def __hash__(self):
        # We make GUID instances hashable, although they are mutable.
        return hash(bytes(self))

    def copy(self):
        return GUID(unicode(self))

    def from_progid(cls, progid):
        """Get guid from progid, ...
        """
        if hasattr(progid, "_reg_clsid_"):
            progid = progid._reg_clsid_
        if isinstance(progid, cls):
            return progid
        elif isinstance(progid, basestring):
            if progid.startswith("{"):
                return cls(progid)
            inst = cls()
            _CLSIDFromProgID(unicode(progid), byref(inst))
            return inst
        else:
            raise TypeError("Cannot construct guid from %r" % progid)
    from_progid = classmethod(from_progid)

    def as_progid(self):
        "Convert a GUID into a progid"
        progid = c_wchar_p()
        _ProgIDFromCLSID(byref(self), byref(progid))
        result = progid.value
        _CoTaskMemFree(progid)
        return result

    def create_new(cls):
        "Create a brand new guid"
        guid = cls()
        _CoCreateGuid(byref(guid))
        return guid
    create_new = classmethod(create_new)
🌐
GitHub
github.com › python › typeshed › issues › 2099
ctypes windows only elements should be typechecked on linux · Issue #2099 · python/typeshed
May 6, 2018 - We have an program that can be run on linux and windows. But we use ctypes.WinDLL('shell32.dll') in a function, that is only run on windows. After you added the sub-file for ctypes, mypy (o...
Author: python
🌐
BestDivision
bestdivision.com › spread your knowledge - bestdivision › questions - bestdivision › python questions - categories - bestdivision › what is the ctypes.windll module in python? - bestdivision
What is the ctypes.windll module in Python? | BestDivision
July 14, 2023 - Discover the ctypes.windll module in Python, which enables access to Windows dynamic link libraries (DLLs). Learn how to load DLLs and call their functions for Windows API integration, complete with practical examples.
🌐
Wordpress
sjohannes.wordpress.com › 2010 › 06 › 19 › win32-python-getting-users-display-name-using-ctypes
Win32 Python: getting user’s display name using ctypes | Johannes Sasongko's old blog
February 14, 2021 - import ctypes def get_display_name(): GetUserNameEx = ctypes.windll.secur32.GetUserNameExW NameDisplay = 3 size = ctypes.pointer(ctypes.c_ulong(0)) GetUserNameEx(NameDisplay, None, size) nameBuffer = ctypes.create_unicode_buffer(size.contents.value) GetUserNameEx(NameDisplay, nameBuffer, size) return nameBuffer.value
🌐
0x00sec
archive.0x00sec.org › t › python-and-malware-writing-a-simple-wiper-malware › 31652
0x00sec - The Home of the Hacker
October 11, 2022 - The Home of the Hacker - Malware, Reverse Engineering, and Computer Science.
🌐
Reddit
reddit.com › r/learnpython › working with ctypes.windll is so annoying.
r/learnpython on Reddit: Working with ctypes.windll is so annoying.
June 30, 2024 -

Hello! I recently started on a function that creates some specified amount of text windows and spreads them around the screen.

The problem is that ctypes.windll.user32.MoveWindows and ctypes.windll.user32.SetWindowPos both not work for some reason.

I also found that the creation of the message box blocks the normal flow of the code, so then I put that creation of the box in a thread, but then you cannot specify the hwnd (handle for the window) for the move functions. I tried just putting it normally, but then it blocks the flow and does not let the move function do their thing.

It currently just stacks the windows diagonally like the old windows glitch, which is also cool, but not the wanted effect.

import time
import ctypes
import random
import threading

def message_box(title, message, count):
    try:
        values = 0 | 0x10 | 0x40000
        def show_box():
            screen_width = ctypes.windll.user32.GetSystemMetrics(0)
            screen_height = ctypes.windll.user32.GetSystemMetrics(1)

            x = random.randint(0, (screen_width - 200))
            y = random.randint(0, (screen_height - 100))
            print(f"X: {x}, Y: {y}")

            hwnd = ctypes.windll.user32.MessageBoxW(0, message, title, values)

            ctypes.windll.user32.MoveWindow(hwnd, x, y, 150, 50)
            ctypes.windll.user32.SetWindowPos(hwnd, -1, x, y, 0, 0, 0x0001)

        for i in range(count):
            threading.Thread(target=show_box).start()
            time.sleep(0.5)

    except Exception as e:
        print(f"Error displaying message box: {e}")

if __name__ == '__main__':
    message_box("Hello", "This is a test message", 5)

Here is my code so far if it is any help:

Is this actually even possible?