I would like to write a general method for all operating systems (Win, MacOS, Unix, ...) that changes a folder's icon.
I would like to extend the following implementation
import os
import warnings
import ctypes
from ctypes import POINTER, Structure, c_wchar, c_int, sizeof, byref
from ctypes.wintypes import BYTE, WORD, DWORD, LPWSTR, LPSTR
import win32api
class SetFolderIcon(object):
def __init__(self, folderPath, iconPath, reset=False):
assert os.path.isdir(folderPath), "folderPath '%s' is not a valid folder"%folderPath
self.__folderPath = unicode(os.path.abspath(folderPath), 'mbcs')
assert os.path.isfile(iconPath), "iconPath '%s' does not exist"%iconPath
self.__iconPath = unicode(os.path.abspath(iconPath), 'mbcs')
assert isinstance(reset, bool), "reset must be boolean"
self.__reset = reset
# set icon if system is windows
if os.name == 'nt':
try:
self.__set_icon_on_windows()
except Exception as e:
warnings.warn("Unable to set folder icon (%s)"%e)
elif os.name == 'posix':
raise Exception('posix system not implemented yet')
elif os.name == 'mac':
raise Exception('mac system not implemented yet')
elif os.name == 'os2':
raise Exception('os2 system not implemented yet')
elif os.name == 'ce':
raise Exception('ce system not implemented yet')
elif os.name == 'java':
raise Exception('java system not implemented yet')
elif os.name == 'riscos':
raise Exception('riscos system not implemented yet')
def __set_icon_on_windows(self):
HICON = c_int
LPTSTR = LPWSTR
TCHAR = c_wchar
MAX_PATH = 260
FCSM_ICONFILE = 0x00000010
FCS_FORCEWRITE = 0x00000002
SHGFI_ICONLOCATION = 0x000001000
class GUID(Structure):
_fields_ = [ ('Data1', DWORD),
('Data2', WORD),
('Data3', WORD),
('Data4', BYTE * 8) ]
class SHFOLDERCUSTOMSETTINGS(Structure):
_fields_ = [ ('dwSize', DWORD),
('dwMask', DWORD),
('pvid', POINTER(GUID)),
('pszWebViewTemplate', LPTSTR),
('cchWebViewTemplate', DWORD),
('pszWebViewTemplateVersion', LPTSTR),
('pszInfoTip', LPTSTR),
('cchInfoTip', DWORD),
('pclsid', POINTER(GUID)),
('dwFlags', DWORD),
('pszIconFile', LPTSTR),
('cchIconFile', DWORD),
('iIconIndex', c_int),
('pszLogo', LPTSTR),
('cchLogo', DWORD) ]
class SHFILEINFO(Structure):
_fields_ = [ ('hIcon', HICON),
('iIcon', c_int),
('dwAttributes', DWORD),
('szDisplayName', TCHAR * MAX_PATH),
('szTypeName', TCHAR * 80) ]
shell32 = ctypes.windll.shell32
fcs = SHFOLDERCUSTOMSETTINGS()
fcs.dwSize = sizeof(fcs)
fcs.dwMask = FCSM_ICONFILE
fcs.pszIconFile = self.__iconPath
fcs.cchIconFile = 0
fcs.iIconIndex = self.__reset
hr = shell32.SHGetSetFolderCustomSettings(byref(fcs), self.__folderPath, FCS_FORCEWRITE)
if hr:
raise WindowsError(win32api.FormatMessage(hr))
sfi = SHFILEINFO()
hr = shell32.SHGetFileInfoW(self.__folderPath, 0, byref(sfi), sizeof(sfi), SHGFI_ICONLOCATION)
#if hr == 0:
# raise WindowsError(win32api.FormatMessage(hr))
index = shell32.Shell_GetCachedImageIndexW(sfi.szDisplayName, sfi.iIcon, 0)
shell32.SHUpdateImageW(sfi.szDisplayName, sfi.iIcon, 0, index)
iconPath = 'C:\\Users\\myself\\Desktop\\icon.ico'
#iconPath = "C:\\Windows\\system32\\SHELL32.dll"
SetFolderIcon('C:\\Users\\myself\\Desktop\\Newfolder',iconPath, reset=False)
# reset icon
SetFolderIcon('C:\\Users\\myself\\Desktop\\Newfolder',iconPath, reset=True)
As you can see I only implemented the windows version using __set_icon_on_windows method. similar methods such as __set_icon_on_mac ... must be implemented
Thanks
Related
I am trying to follow this answer and i have reached the point where a should call
GetGUIThreadInfo()
but i cannot find that in the pywin32 docomentation i am using.
What i have done so far is
import win32api
import win32gui
import win32process
test1 = win32gui.FindWindowEx(0, 0, 0, "notepad")
(test1tid, test1pid) = win32process.GetWindowThreadProcessId(test1)
test1hwndFocus = win32process.GetGUIThreadInfo(test1tid)
but the last line is compleatly made up as i cannot find the right way to call the function.
Update1:
Think i made some progress but now my struct just returns 0 when i expect some hwnd... so maybe my struct is not writen to, i think this could be because of the types in my struct, but how do i find the right types?
import win32api
import win32gui
import win32process
import ctypes
class RECT(ctypes.Structure):
_fields_ = [
("left", ctypes.c_ulong),
("top", ctypes.c_ulong),
("right", ctypes.c_ulong),
("bottom", ctypes.c_ulong)
]
class GUITHREADINFO(ctypes.Structure):
_fields_ = [
("cbSize", ctypes.c_ulong),
("flags", ctypes.c_ulong),
("hwndActive", ctypes.c_ulong),
("hwndFocus", ctypes.c_ulong),
("hwndCapture", ctypes.c_ulong),
("hwndMenuOwner", ctypes.c_ulong),
("hwndMoveSize", ctypes.c_ulong),
("hwndCaret", ctypes.c_ulong),
("rcCaret", RECT)
]
guiThreadInfoStruct = GUITHREADINFO()
ctypes.sizeof(gtitest)
test1 = win32gui.FindWindowEx(0, 0, 0, "notepad")
(test1tid, test1pid) = win32process.GetWindowThreadProcessId(test1)
ctypes.windll.user32.GetGUIThreadInfo(test1tid, guiThreadInfoStruct)
print (guiThreadInfoStruct.hwndFocus)
Update2:
I found the types here
update3:
If anyone wanna see what i used this for go look here
Apparently, [MS.Docs]: GetGUIThreadInfo function is not wrapped by PyWin32, so alternative ways must be used. One of them is calling it via [Python 3.Docs]: ctypes - A foreign function library for Python (involves writing a lot of extra code).
code00.py:
#!/usr/bin/env python
import sys
import win32gui as wgui
import win32process as wproc
import win32con as wcon
import ctypes as ct
from ctypes import wintypes as wt
class GUITHREADINFO(ct.Structure):
_fields_ = [
("cbSize", wt.DWORD),
("flags", wt.DWORD),
("hwndActive", wt.HWND),
("hwndFocus", wt.HWND),
("hwndCapture", wt.HWND),
("hwndMenuOwner", wt.HWND),
("hwndMoveSize", wt.HWND),
("hwndCaret", wt.HWND),
("rcCaret", wt.RECT),
]
def __str__(self):
ret = "\n" + self.__repr__()
start_format = "\n {0:s}: "
for field_name, _ in self. _fields_[:-1]:
field_value = getattr(self, field_name)
field_format = start_format + ("0x{1:016X}" if field_value else "{1:}")
ret += field_format.format(field_name, field_value)
rc_caret = getattr(self, self. _fields_[-1][0])
ret += (start_format + "({1:d}, {2:d}, {3:d}, {4:d})").format(self. _fields_[-1][0], rc_caret.top, rc_caret.left, rc_caret.right, rc_caret.bottom)
return ret
def main(*argv):
window_name = "Untitled - Notepad"
hwnd = wgui.FindWindowEx(wcon.NULL, 0, wcon.NULL, window_name)
print("'{0:s}' window handle: 0x{1:016X}".format(window_name, hwnd))
tid, pid = wproc.GetWindowThreadProcessId(hwnd)
print("PId: {0:d}, TId: {1:d}".format(pid, tid))
user32_dll = ct.WinDLL("user32.dll")
GetGUIThreadInfo = getattr(user32_dll, "GetGUIThreadInfo")
GetGUIThreadInfo.argtypes = [wt.DWORD, ct.POINTER(GUITHREADINFO)]
GetGUIThreadInfo.restype = wt.BOOL
gti = GUITHREADINFO()
gti.cbSize = ct.sizeof(GUITHREADINFO)
res = GetGUIThreadInfo(tid, ct.byref(gti))
print("{0:s} returned: {1:d}".format(GetGUIThreadInfo.__name__, res))
if res:
print(gti)
if __name__ == "__main__":
print("Python {0:s} {1:d}bit on {2:s}\n".format(" ".join(item.strip() for item in sys.version.split("\n")), 64 if sys.maxsize > 0x100000000 else 32, sys.platform))
main(*sys.argv[1:])
print("\nDone.")
Output:
e:\Work\Dev\StackOverflow\q059884688>"e:\Work\Dev\VEnvs\py_pc064_03.07.06_test0\Scripts\python.exe" code00.py
Python 3.7.6 (tags/v3.7.6:43364a7ae0, Dec 19 2019, 00:42:30) [MSC v.1916 64 bit (AMD64)] 64bit on win32
'Untitled - Notepad' window handle: 0x00000000042B20D8
PId: 37192, TId: 53072
GetGUIThreadInfo returned: 1
<__main__.GUITHREADINFO object at 0x0000022649436648>
cbSize: 0x0000000000000048
flags: 0
hwndActive: None
hwndFocus: None
hwndCapture: None
hwndMenuOwner: None
hwndMoveSize: None
hwndCaret: None
rcCaret: (0, 0, 0, 0)
Done.
Notes:
print data that you are working with, as it might be different what you'd expect. For example, the Notepad window title is not "notepad" like your code expects it to be, and in that case win32gui.FindWindowEx would return NULL (0).
I also use [ActiveState.Docs]: PyWin32 Documentation (it's old and outdated, but in most cases it's extremely helpful)
I have below files
my_test.py
import my_debugger
debugger =my_debugger.debugger()
debugger.load("C:\\windows\\system32\\calc.exe")
my_debugger.py
from ctypes import *
from my_debugger_defines import *
kernel32 = windll.kernel32
class debugger():
def __init__(self):
pass
def load(self, path_to_exe):
creation_flags = DEBUG_PROCESS
startupinfo = STARTUPINFO()
process_information = PROCESS_INFORMATION
startupinfo.dwflags =0x1
startupinfo.wShowWindow = 0x0
startupinfo.cb = sizeof(startupinfo)
if kernel32.CreateProcessA(path_to_exe, None, None, None, None, byref(startupinfo),byref(process_information)):
print( "[*] we have succedfully lanunched the prcoess")
print ("[*] PID: %d" % process_information.dwProcessId)
else:
print("[*} error: 0x%08x." % kernel32.GetLastError())
my_debugger_defines.py
from ctypes import *
# mirosoft types to ctypes
WORD = c_ushort
DWORD =c_ulong
LPBYTE = POINTER(c_ubyte)
LPTSTR = POINTER(c_char)
HANDLE = c_void_p
#constants
DEBUG_PROCESS = 0X00000001
CREATE_NEW_CONSOLE = 0X00000010
#structures for createpressa() fuction
class STARTUPINFO(Structure):
_fields_ = [
("cb", DWORD),
("lpReserved", LPTSTR),
("lpDesktop", LPTSTR),
("lpTitle", LPTSTR),
("dwX", DWORD),
("dwY", DWORD),
("dwXSize", DWORD),
("dwYsize", DWORD),
("dsXCountChars", DWORD),
("dwYCountChars", DWORD),
("dwFillAttribute", DWORD),
("dwFlags", DWORD),
("wShowWindow", WORD),
("cbReserved2", WORD),
("lpReserved2", LPBYTE),
("hStdInput", HANDLE),
("hStdOutput", HANDLE),
("hStdError", HANDLE),
]
class PROCESS_INFORMATION(Structure):
_fields_ = [
("hProcess", HANDLE),
("HtHREAD", HANDLE),
("dwProcessId", DWORD),
("dwThreadId", DWORD),
]
when I run my_test.py I got below error
C:\download\New folder (6) (1)\Programowanie>python my_test.py
Traceback (most recent call last):
File "my_test.py", line 3, in
debugger.load("C:\windows\system32\calc.exe")
File "C:\download\New folder (6) (1)\Programowanie\my_debugger.py", line 19, in load
if kernel32.CreateProcessA(path_to_exe, None, None, None, None, byref(startupinfo),byref(process_information)):
TypeError: byref() argument must be a ctypes instance, not '_ctypes.PyCStructType'
C:\download\New folder (6) (1)\Programowanie>
do you know how to fix error?
I'm trying to find the base address of render.dll used in the process process.exe. I have modified the code in this question, and I'm able to get a result for the base address of render.dll.
from ctypes import *
from ctypes.wintypes import *
import psutil
class MODULEENTRY32(Structure):
_fields_ = [( 'dwSize', DWORD),
( 'th32ModuleID', DWORD),
( 'th32ProcessID', DWORD),
( 'GlblcntUsage', DWORD),
( 'ProccntUsage', DWORD),
( 'modBaseAddr', POINTER(BYTE)),
( 'modBaseSize', DWORD),
( 'hModule', HMODULE),
( 'szModule', c_char * 256),
( 'szExePath', c_char * 260)]
CreateToolhelp32Snapshot = windll.kernel32.CreateToolhelp32Snapshot
Module32First = windll.kernel32.Module32First
Module32Next = windll.kernel32.Module32Next
CloseHandle = windll.kernel32.CloseHandle
TH32CS_SNAPMODULE = 0x00000008
TH32CS_SNAPMODULE32 = 0x00000010
def getpid(processname):
for proc in psutil.process_iter():
if str(processname) in str(proc.name):
return proc.pid
def GetModuleByName(name):
snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE32 | TH32CS_SNAPMODULE, getpid('process.exe'))
entry = MODULEENTRY32()
entry.dwSize = sizeof(MODULEENTRY32)
if Module32First(snapshot, pointer(entry)):
while Module32Next(snapshot, entry):
if entry.szModule == name:
CloseHandle(snapshot)
return entry.modBaseAddr
CloseHandle(snapshot)
return None
baseAddr = GetModuleByName('render.dll')
print baseAddr
Which results in <__main__.LP_c_byte object at 0x00000000023C9348>. I know this is to do with the result being a POINTER(BYTE) type, but I am not sure how to get from this type to a normal hex memory address that I can use to read the process memory at this location.
I found an answer here. Turns out I had the same misunderstanding as the other poster and that using ctypes.addressof(baseAddr.contents) returns the correct memory address for the .dll.
I followed the Grey Hat Python and made a debugger, but it can't work well.
I ran the calc.exe and find the PID. However, the debugger can't attach to the process. I copied the code from the book and also downloaded the code from the Internet. Both of them gave me the same result.Here is my code:
from ctypes import *
from my_debugger_defines import *
kernel32 = windll.kernel32
class debugger():
def __init__(self):
self.h_process = None
self.pid = None
self.debugger_active = False
def load(self, path_to_exe):
#dwCreation flag determines how to create the process
#set creation_flags = CREATE_NEW_CONSOLE if you want
#to see the calculator GUI
creation_flags = DEBUG_PROCESS
#instantiate the structs
startupinfo = STARTUPINFO()
process_information = PROCESS_INFORMATION()
#The following two options allow the started process
#to be shown as a separate window. This also illustrates
#how different settings in the STARTUPINFO struct can affect
#the debugger.
startupinfo.dwFlags =0x1
startupinfo.wShowWindow =0x0
#We then initialize the cb variable in the STARTUPINFO struct
#which is just the size of the struct itself
startupinfo.cb = sizeof(startupinfo)
if kernel32.CreateProcessA(path_to_exe,
None,
None,
None,
None,
creation_flags,
None,
None,
byref(startupinfo),
byref(process_information)):
print "[*] We have successfully launched the process!"
print "[*] PID: %d" % process_information.dwProcessId
#Obtain a valid handle to the newly created process
#and store it for future access
self.h_process = self.open_process(process_information.dwProcessId)
else:
print "[*] Error:0x%08x."%kernel32.GetLastError()
def open_process(self, pid):
h_process = kernel32.OpenProcess(PROCESS_ALL_ACCESS, False, pid)
return h_process
def attach(self, pid):
self.h_process = self.open_process(pid)
#We attempt to attach to the process
#if this fails we exit the callable
if kernel32.DebugActiveProcess(pid):
self.debugger_active = True
self.pid = int(pid)
self.run()
else:
print "[*] Unable to attach to the process."
def run(self):
#Now we have to poll the debugger for debugging events
while self.debugger_active == True:
self.get_debug_event()
def get_debug_event(self):
debug_event = DEBUG_EVENT()
continue_status = DBG_CONTINUE
if kernel32.WaitForDebugEvent(byref(debug_event), INFINITE):
#We aren't going to build any event handlers just yet.
#Let's just resume the process for now.
raw_input("press a key to continue...")
self.debugger_active = False
kernel32.ContinueDebugEvent(\
debug_event.dwProcessId, \
debug_event.dwThreadId, \
continue_status )
def detach(self):
if kernel32.DebugActiveProcessStop(self.pid):
print "[*] Finished debugging. Exiting..."
return True
else:
print "There was an error"
return False
Everytime I run the program, it print "[*]Unable to attach to the process." and "There was an error".
Here is my test.py.
import my_debugger
debugger = my_debugger.debugger()
pid = raw_input("Enter the PID of the process to attach to: ")
debugger.attach(int(pid))
debugger.detach()
Why? Is it my computer system's problem? Can win8.1 use kernel32? How to fix it?
This code from the book works only on a 32-bit platform, so you can't attach to 64-bit process calc.exe.
Look at the answers to the question Python WaitForDebugEvent & ContinueDebugEvent (Gray Hat Python). May be they'll help you.
The content of "my_debugger_defines.py" file should be as follows ...
And It works on a 64-bit platform
from ctypes import *
BYTE = c_ubyte
WORD = c_ushort
DWORD = c_ulong
LPBYTE = POINTER(c_ubyte)
LPTSTR = POINTER(c_char)
HANDLE = c_void_p
PVOID = c_void_p
LPVOID = c_void_p
UINT_PTR = c_ulong
DEBUG_PROCESS = 0x00000001
PROCESS_ALL_ACCESS = 0x001F0FFF
INFINITE = 0xFFFFFFFF
DBG_CONTINUE = 0x00010002
class STARTUPINFO(Structure):
_fields_ = [
("cb", DWORD),
("lpReserved", LPTSTR),
("lpDesktop", LPTSTR),
("lpTitle", LPTSTR),
("dwX", DWORD),
("dwY", DWORD),
("dwXSize", DWORD),
("dwYSize", DWORD),
("dwXCountChars", DWORD),
("dwYCountChars", DWORD),
("dwFillAttribute",DWORD),
("dwFlags", DWORD),
("wShowWindow", WORD),
("cbReserved2", WORD),
("lpReserved2", LPBYTE),
("hStdInput", HANDLE),
("hStdOutput", HANDLE),
("hStdError", HANDLE),
]
class PROCESS_INFORMATION(Structure):
_fields_ = [
("hProcess", HANDLE),
("hThread", HANDLE),
("dwProcessId", DWORD),
("dwThreadId", DWORD),
]
class EXCEPTION_RECORD(Structure):
pass
EXCEPTION_RECORD._fields_ = [
("ExceptionCode", DWORD),
("ExceptionFlags", DWORD),
("ExceptionRecord", POINTER(EXCEPTION_RECORD)),
("ExceptionAddress", PVOID),
("NumberParameters", DWORD),
("ExceptionInformation", UINT_PTR * 15),
]
class _EXCEPTION_RECORD(Structure):
_fields_ = [
("ExceptionCode", DWORD),
("ExceptionFlags", DWORD),
("ExceptionRecord", POINTER(EXCEPTION_RECORD)),
("ExceptionAddress", PVOID),
("NumberParameters", DWORD),
("ExceptionInformation", UINT_PTR * 15),
]
class EXCEPTION_DEBUG_INFO(Structure):
_fields_ = [
("ExceptionRecord", EXCEPTION_RECORD),
("dwFirstChance", DWORD),
]
class CREATE_PROCESS_DEBUG_INFO(Structure):
_fields_ = [
("hFile", HANDLE),
("hProcess", HANDLE),
("hThread", HANDLE),
("lpBaseOfImage", LPVOID),
("dwDebugInfoFileOffset",DWORD),
("nDebugInfoSize", DWORD),
("lpThreadLocalBase", LPVOID),
("lpStartAddress", HANDLE),
("lpImageName", LPVOID),
("fUnicode", WORD)
]
class CREATE_THREAD_DEBUG_INFO(Structure):
_fields_ = [
("hThread", HANDLE),
("lpThreadLocalBase", LPVOID),
("lpStartAddress", HANDLE)
]
class EXIT_THREAD_DEBUG_INFO(Structure):
_fields_ = [
("dwExitCode", DWORD)
]
class EXIT_PROCESS_DEBUG_INFO(Structure):
_fields_ = [
("dwExitCode", DWORD)
]
class LOAD_DLL_DEBUG_INFO(Structure):
_fields_ = [
("hFile", HANDLE),
("lpBaseOfDll", LPVOID),
("dwDebugInfoFileOffset", DWORD),
("nDebugInfoSize", DWORD),
("lpImageName", LPVOID),
("fUnicode", WORD)
]
class UNLOAD_DLL_DEBUG_INFO(Structure):
_fields_ = [
("lpBaseOfDll", LPVOID)
]
class OUTPUT_DEBUG_STRING_INFO(Structure):
_fields_ = [
("lpDebugStringData", LPTSTR),
("fUnicode", WORD),
("nDebugStringLength", WORD)
]
class RIP_INFO(Structure):
_fields_ = [
("dwError", DWORD),
("dwType", DWORD)
]
class DEBUG_EVENT_UNION(Union):
_fields_ = [
("Exception", EXCEPTION_DEBUG_INFO),
("CreateThread", CREATE_THREAD_DEBUG_INFO),
("CreateProcessInfo", CREATE_PROCESS_DEBUG_INFO),
("ExitThread", EXIT_THREAD_DEBUG_INFO),
("ExitProcess", EXIT_PROCESS_DEBUG_INFO),
("LoadDll", LOAD_DLL_DEBUG_INFO),
("UnloadDll", UNLOAD_DLL_DEBUG_INFO),
("DebugString", OUTPUT_DEBUG_STRING_INFO),
("RipInfo", RIP_INFO),
]
class DEBUG_EVENT(Structure):
_fields_ = [
("dwDebugEventCode", DWORD),
("dwProcessId", DWORD),
("dwThreadId", DWORD),
("u", DEBUG_EVENT_UNION),
]
several month ago,I wrote https://github.com/325862401/goagent/blob/master/local/ieproxysetting.cpp. that program can set internet proxy automatically.
Now I want to use ctypes.windll.Wininet to do the same thing.
But I donot know how to pass the argument to InternetQueryOptionW.
and I also don't find the class refer to the INTERNET_PER_CONN_OPTION_LIST structure.
is there any demo for the usage of InternetQueryOptionW or InternetSetOptionW in python.
this https://bitbucket.org/canassa/switch-proxy/src/685ac447783a7cb3ead6ce8369b66483790c26be/proxy.py?at=default maybe be helpful.
but I donot want to modify Registry.
just use the api.
Thanks a lot.
sorry for poor English.
Here is Python equivalent to your cpp code, pretty much straight forward conversation (I didn't test it that much):
#-*- coding: utf-8 -*-
#!python
from ctypes import *
from ctypes.wintypes import *
# stick to unicode version
LPWSTR = POINTER(WCHAR)
HINTERNET = LPVOID
INTERNET_PER_CONN_FLAGS = 1
INTERNET_PER_CONN_AUTOCONFIG_URL = 4
INTERNET_PER_CONN_AUTODISCOVERY_FLAGS = 5
INTERNET_OPTION_REFRESH = 37
INTERNET_OPTION_SETTINGS_CHANGED = 39
INTERNET_OPTION_PER_CONNECTION_OPTION = 75
PROXY_TYPE_AUTO_PROXY_URL = 4
class INTERNET_PER_CONN_OPTION(Structure):
class Value(Union):
_fields_ = [
('dwValue', DWORD),
('pszValue', LPWSTR),
('ftValue', FILETIME),
]
_fields_ = [
('dwOption', DWORD),
('Value', Value),
]
class INTERNET_PER_CONN_OPTION_LIST(Structure):
_fields_ = [
('dwSize', DWORD),
('pszConnection', LPWSTR),
('dwOptionCount', DWORD),
('dwOptionError', DWORD),
('pOptions', POINTER(INTERNET_PER_CONN_OPTION)),
]
InternetSetOption = windll.wininet.InternetSetOptionW
InternetSetOption.argtypes = [HINTERNET, DWORD, LPVOID, DWORD]
InternetSetOption.restype = BOOL
if __name__ == '__main__':
proxy = create_unicode_buffer('http://127.0.0.1:8086/proxy.pac')
List = INTERNET_PER_CONN_OPTION_LIST()
Option = (INTERNET_PER_CONN_OPTION * 2)()
nSize = c_ulong(sizeof(INTERNET_PER_CONN_OPTION_LIST))
Option[0].dwOption = INTERNET_PER_CONN_AUTOCONFIG_URL
Option[0].Value.pszValue = proxy
Option[1].dwOption = INTERNET_PER_CONN_FLAGS
Option[1].Value.dwValue = PROXY_TYPE_AUTO_PROXY_URL
List.dwSize = sizeof(INTERNET_PER_CONN_OPTION_LIST)
List.pszConnection = None
List.dwOptionCount = 2
List.dwOptionError = 0
List.pOptions = Option
assert InternetSetOption(None, INTERNET_OPTION_PER_CONNECTION_OPTION, byref(List), nSize) == True
assert InternetSetOption(None, INTERNET_OPTION_SETTINGS_CHANGED, None, 0) == True
assert InternetSetOption(None, INTERNET_OPTION_REFRESH, None, 0) == True
You don't need MultiByteToWideChar, create_unicode_buffer and the unicode version of InternetSetOption should do the job.