I have made a script that can send keys to any app in the background, but it does not work on DirectX.
I am trying to make my character jump in a game called "roblox".
This is the script
import time
import psutil
import win32con
from win32 import win32gui
from win32 import win32api
from win32 import win32process
keyDict = {" ": 0x20}
for i in range(0x41, 0x5A+1):
keyDict[chr(i)] = i
def CloseExe(exeName):
ID2Handle={}
def get_all_hwnd(hwnd,mouse):
if win32gui.IsWindow(hwnd) and win32gui.IsWindowEnabled(hwnd) and win32gui.IsWindowVisible(hwnd):
nID=win32process.GetWindowThreadProcessId(hwnd)
del nID[0]
for abc in nID:
try:
pro=psutil.Process(abc).name()
except psutil.NoSuchProcess:
pass
else:
if pro == exeName:
win32gui.PostMessage(hwnd,win32con.WM_CLOSE,0,0)
win32gui.EnumWindows(get_all_hwnd, 0)
def SendKeysSensitive(exeName, keysToSend):
mID2Handle={}
def get_all_hwnd(hwnd,mouse):
hwndTwo = win32gui.GetWindow(hwnd, win32con.GW_CHILD)
if win32gui.IsWindow(hwnd) and win32gui.IsWindowEnabled(hwnd) and win32gui.IsWindowVisible(hwnd):
nID=win32process.GetWindowThreadProcessId(hwnd)
del nID[0]
for abc in nID:
try:
pro=psutil.Process(abc).name()
except psutil.NoSuchProcess:
pass
else:
if pro == exeName:
for key in keysToSend:
win32gui.PostMessage(hwndTwo, win32con.WM_CHAR, key, 0)
def SendKeys(exeName, keysToSend):
mID2Handle={}
def get_all_hwnd(hwnd,mouse):
hwndTwo = hwnd
if win32gui.IsWindow(hwnd) and win32gui.IsWindowEnabled(hwnd) and win32gui.IsWindowVisible(hwnd):
nID=win32process.GetWindowThreadProcessId(hwnd)
del nID[0]
for abc in nID:
try:
pro=psutil.Process(abc).name()
except psutil.NoSuchProcess:
pass
else:
if pro == exeName:
for key in keysToSend:
win32gui.PostMessage(hwndTwo, win32con.WM_CHAR, key, 0)
win32gui.EnumWindows(get_all_hwnd, 0)
def TranslateKeys(text):
outKeys = []
for char in text:
outKeys.append(keyDict.get(char.upper()))
return outKeys
def ExE(name):
return name
if __name__ == '__main__':
prog = ExE("RobloxPlayerBeta.exe")
jump = TranslateKeys(" ")
SendKeys(prog, jump)
It does not work due to "RobloxPlayerBeta.exe" being DirectX.
I can not open the app, it 100% needs to be in the background.
Is this possible?
Well I had a problem similar to this and I found a solution. I'm not sure if this is what you're looking for, but there is a library for sending input to DirectX applications
It's called PyDirectInput. It's essentially PyAutoGui but works with DirectX
pip install pydirectinput
As far as roblox, I have used this before and can say it does work.
source code
I have made a python script which creates a MacOS Status bar item which displays youtube statistics.
I want to add dividers to the drop down menu when you click the text but I am unable to do this. (Image of what I mean under the text). I have found many examples but all of them only work with an __init__ function in the class. If I try adding an __init__ function to the class I get an error saying AttributeError: 'Sub_Counter' object has no attribute '_menu'. Why is this happening and how can it be fixed?
Code I added to the __init_ function
self.menu = [
"About",
"No Icon",
None,
"Detailed Statistics:",
None,
"Quit",
]
Normal Code without the __init__ function
import rumps
import time
import sys
import os
from sty import fg
from googleapiclient.discovery import build
key = open(os.path.join(sys.path[0], './key.txt')).read().strip()
service = build('youtube', 'v3', developerKey=key)
subs = service.channels().list(
part='statistics',
id='UCERizKQbgpBXOck0R6t_--Q'
).execute()['items'][0]['statistics']['subscriberCount']
timers = ["1 secs","5 secs","10 secs","15 secs","20 secs","25 secs","30 secs","35 secs","45 secs","50 secs","1 Min"]
EXEC_TIMER = 60
class Sub_Counter(rumps.App):
#rumps.timer(EXEC_TIMER)
def pull_data(self, _):
self.sub_menu = timers
subs = service.channels().list(
part='statistics',
id='UCERizKQbgpBXOck0R6t_--Q'
).execute()['items'][0]['statistics']['subscriberCount']
a = (str(subs))
self.icon = "logo.png"
self.title = "Subscribers: " + str(a)
self.notification = str(a) + " Subscribers"
#rumps.clicked("About")
def about(self, _=):
rumps.notification("Youtube Subscriber Count", "Made by Roxiun using Python & rumps", "Shows Youtube Subscriber counts")
#rumps.clicked("No Icon")
def noicon(self, sender):
sender.state = not sender.state
self.icon = None
#rumps.clicked("Detailed Statistics")
def Detailed_Statistics(self, _):
rumps.notification("You have:", self.notification , "Veiws Comming Soon")
if __name__ == "__main__":
Sub_Counter("Loading...").run() #debug=True
Image of what I want to do [circled in red - (Yes it is the line)]
Thanks in advance!
Fixed by doing
app = Sub_Counter("Loading...")
app.menu[
"About",
"No Icon",
None,
"Detailed Statistics:",
None,
"Quit",
]
app.run()
You can add a separator by doing:
self.menu.add(rumps.separator)
Link to source code.
I am trying to do this in Python 2.7. I have found an answer for it in C# here, but I am having trouble recreating it in Python. The answer suggested here does explain the concept which I understand, but I have no idea how to get it going.
Basically I just want to mark a file, press Winkey+C and have its path copied. I know how to do the hotkey part (pyhk, win32 [RegisterHotKey]), but my trouble is working around with the filepath.
Thanks in advance!
it takes a lot of hacking around, but a rough solution is below:
#!python3
import win32gui, time
from win32con import PAGE_READWRITE, MEM_COMMIT, MEM_RESERVE, MEM_RELEASE, PROCESS_ALL_ACCESS, WM_GETTEXTLENGTH, WM_GETTEXT
from commctrl import LVM_GETITEMTEXT, LVM_GETITEMCOUNT, LVM_GETNEXTITEM, LVNI_SELECTED
import os
import struct
import ctypes
import win32api
GetWindowThreadProcessId = ctypes.windll.user32.GetWindowThreadProcessId
VirtualAllocEx = ctypes.windll.kernel32.VirtualAllocEx
VirtualFreeEx = ctypes.windll.kernel32.VirtualFreeEx
OpenProcess = ctypes.windll.kernel32.OpenProcess
WriteProcessMemory = ctypes.windll.kernel32.WriteProcessMemory
ReadProcessMemory = ctypes.windll.kernel32.ReadProcessMemory
memcpy = ctypes.cdll.msvcrt.memcpy
def readListViewItems(hwnd, column_index=0):
# Allocate virtual memory inside target process
pid = ctypes.create_string_buffer(4)
p_pid = ctypes.addressof(pid)
GetWindowThreadProcessId(hwnd, p_pid) # process owning the given hwnd
hProcHnd = OpenProcess(PROCESS_ALL_ACCESS, False, struct.unpack("i",pid)[0])
pLVI = VirtualAllocEx(hProcHnd, 0, 4096, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE)
pBuffer = VirtualAllocEx(hProcHnd, 0, 4096, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE)
# Prepare an LVITEM record and write it to target process memory
lvitem_str = struct.pack('iiiiiiiii', *[0,0,column_index,0,0,pBuffer,4096,0,0])
lvitem_buffer = ctypes.create_string_buffer(lvitem_str)
copied = ctypes.create_string_buffer(4)
p_copied = ctypes.addressof(copied)
WriteProcessMemory(hProcHnd, pLVI, ctypes.addressof(lvitem_buffer), ctypes.sizeof(lvitem_buffer), p_copied)
# iterate items in the SysListView32 control
num_items = win32gui.SendMessage(hwnd, LVM_GETITEMCOUNT)
item_texts = []
for item_index in range(num_items):
win32gui.SendMessage(hwnd, LVM_GETITEMTEXT, item_index, pLVI)
target_buff = ctypes.create_string_buffer(4096)
ReadProcessMemory(hProcHnd, pBuffer, ctypes.addressof(target_buff), 4096, p_copied)
item_texts.append(target_buff.value)
VirtualFreeEx(hProcHnd, pBuffer, 0, MEM_RELEASE)
VirtualFreeEx(hProcHnd, pLVI, 0, MEM_RELEASE)
win32api.CloseHandle(hProcHnd)
return item_texts
def getSelectedListViewItem(hwnd):
return win32gui.SendMessage(hwnd, LVM_GETNEXTITEM, -1, LVNI_SELECTED)
def getSelectedListViewItems(hwnd):
items = []
item = -1
while True:
item = win32gui.SendMessage(hwnd, LVM_GETNEXTITEM, item, LVNI_SELECTED)
if item == -1:
break
items.append(item)
return items
def getEditText(hwnd):
# api returns 16 bit characters so buffer needs 1 more char for null and twice the num of chars
buf_size = (win32gui.SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0) +1 ) * 2
target_buff = ctypes.create_string_buffer(buf_size)
win32gui.SendMessage(hwnd, WM_GETTEXT, buf_size, ctypes.addressof(target_buff))
return target_buff.raw.decode('utf16')[:-1]# remove the null char on the end
def _normaliseText(controlText):
'''Remove '&' characters, and lower case.
Useful for matching control text.'''
return controlText.lower().replace('&', '')
def _windowEnumerationHandler(hwnd, resultList):
'''Pass to win32gui.EnumWindows() to generate list of window handle,
window text, window class tuples.'''
resultList.append((hwnd, win32gui.GetWindowText(hwnd), win32gui.GetClassName(hwnd)))
def searchChildWindows(currentHwnd,
wantedText=None,
wantedClass=None,
selectionFunction=None):
results = []
childWindows = []
try:
win32gui.EnumChildWindows(currentHwnd,
_windowEnumerationHandler,
childWindows)
except win32gui.error:
# This seems to mean that the control *cannot* have child windows,
# i.e. not a container.
return
for childHwnd, windowText, windowClass in childWindows:
descendentMatchingHwnds = searchChildWindows(childHwnd)
if descendentMatchingHwnds:
results += descendentMatchingHwnds
if wantedText and \
not _normaliseText(wantedText) in _normaliseText(windowText):
continue
if wantedClass and \
not windowClass == wantedClass:
continue
if selectionFunction and \
not selectionFunction(childHwnd):
continue
results.append(childHwnd)
return results
w=win32gui
while True:
time.sleep(5)
window = w.GetForegroundWindow()
print("window: %s" % window)
if (window != 0):
if (w.GetClassName(window) == 'CabinetWClass'): # the main explorer window
print("class: %s" % w.GetClassName(window))
print("text: %s " %w.GetWindowText(window))
children = list(set(searchChildWindows(window)))
addr_edit = None
file_view = None
for child in children:
if (w.GetClassName(child) == 'ComboBoxEx32'): # the address bar
addr_children = list(set(searchChildWindows(child)))
for addr_child in addr_children:
if (w.GetClassName(addr_child) == 'Edit'):
addr_edit = addr_child
pass
elif (w.GetClassName(child) == 'SysListView32'): # the list control within the window that shows the files
file_view = child
if addr_edit:
path = getEditText(addr_edit)
else:
print('something went wrong - no address bar found')
path = ''
if file_view:
files = [item.decode('utf8') for item in readListViewItems(file_view)]
indexes = getSelectedListViewItems(file_view)
print('path: %s' % path)
print('files: %s' % files)
print('selected files:')
for index in indexes:
print("\t%s - %s" % (files[index], os.path.join(path, files[index])))
else:
print('something went wrong - no file view found')
so what this does is keep checking if the active window is of the class the explorer window uses, then iterates through the children widgets to find the address bar and the file list view. Then it extracts the list of files from the listview and requests the selected indexes. it also gets and decodes the text from the address bar.
at the bottom the info is then combined to give you the complete path, the folder path, the file name or any combination thereof.
I have tested this on windows xp with python3.4, but you will need to install the win32gui and win32 conn packages.
# Import Statement.
import subprocess
# Trigger subprocess.
subprocess.popen(r'explorer /select,"C:\path\of\folder\file"'
I'm very new to python and I'm trying to print the url of an open websitein Chrome. Here is what I could gather from this page and googeling a bit:
import win32gui, win32con
def getWindowText(hwnd):
buf_size = 1 + win32gui.SendMessage(hwnd, win32con.WM_GETTEXTLENGTH, 0, 0)
buf = win32gui.PyMakeBuffer(buf_size)
win32gui.SendMessage(hwnd, win32con.WM_GETTEXT, buf_size, buf)
return str(buf)
hwnd = win32gui.FindWindow(None, "Chrome_WidgetWin_1" )
omniboxHwnd = win32gui.FindWindowEx(hwnd, 0, 'Chrome_OmniboxView', None)
print(getWindowText(hwnd))
I get this as a result:
<memory at 0x00CA37A0>
I don't really know what goes wrong, whether he gets into the window and the way I try to print it is wrong or whether he just doesn't get into the window at all.
Thanks for the help
Only through win32 can only get the information of the top-level application. If you want to get the information of each component located in the application, you can use UI Automation.
Python has a wrapper package Python-UIAutomation-for-Windows, and then you can get the browser's address bar url through the following code:
import uiautomation as auto
def get_browser_tab_url(browser: str):
"""
Get browser tab url, browser must already open
:param browser: Support 'Edge' 'Google Chrome' and other Chromium engine browsers
:return: Current tab url
"""
if browser.lower() == 'edge':
addr_bar = auto.EditControl(AutomationId='addressEditBox')
else:
win = auto.PaneControl(Depth=1, ClassName='Chrome_WidgetWin_1', SubName=browser)
temp = win.PaneControl(Depth=1, Name=browser).GetChildren()[1].GetChildren()[0]
for bar in temp.GetChildren():
last = bar.GetLastChildControl()
if last and last.Name != '':
break
addr_bar = bar.GroupControl(Depth=1, Name='').EditControl()
url = addr_bar.GetValuePattern().Value
return url
print(get_browser_tab_url('Edge'))
print(get_browser_tab_url('Google Chrome'))
print(get_browser_tab_url('Cent Browser'))
This should work:
import uiautomation as auto
control = auto.GetFocusedControl()
controlList = []
while control:
controlList.insert(0, control)
control = control.GetParentControl()
control = controlList[0 if len(controlList) == 1 else 1]
address_control = auto.FindControl(control, lambda c, d:
isinstance(c, auto.EditControl))
print('Current URL:')
print(address_control.GetValuePattern().Value)
I'm trying add some shell extensions using python with icons and a sub menu but I'm struggling to get much further than the demo in pywin32. I can't seem to come up with anything by searching google, either.
I believe I need to register a com server to be able to change the options in submenu depending on where the right clicked file/folder is and the type of file etc.
# A sample context menu handler.
# Adds a 'Hello from Python' menu entry to .py files. When clicked, a
# simple message box is displayed.
#
# To demostrate:
# * Execute this script to register the context menu.
# * Open Windows Explorer, and browse to a directory with a .py file.
# * Right-Click on a .py file - locate and click on 'Hello from Python' on
# the context menu.
import pythoncom
from win32com.shell import shell, shellcon
import win32gui
import win32con
class ShellExtension:
_reg_progid_ = "Python.ShellExtension.ContextMenu"
_reg_desc_ = "Python Sample Shell Extension (context menu)"
_reg_clsid_ = "{CED0336C-C9EE-4a7f-8D7F-C660393C381F}"
_com_interfaces_ = [shell.IID_IShellExtInit, shell.IID_IContextMenu]
_public_methods_ = shellcon.IContextMenu_Methods + shellcon.IShellExtInit_Methods
def Initialize(self, folder, dataobj, hkey):
print "Init", folder, dataobj, hkey
self.dataobj = dataobj
def QueryContextMenu(self, hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags):
print "QCM", hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags
# Query the items clicked on
format_etc = win32con.CF_HDROP, None, 1, -1, pythoncom.TYMED_HGLOBAL
sm = self.dataobj.GetData(format_etc)
num_files = shell.DragQueryFile(sm.data_handle, -1)
if num_files>1:
msg = "&Hello from Python (with %d files selected)" % num_files
else:
fname = shell.DragQueryFile(sm.data_handle, 0)
msg = "&Hello from Python (with '%s' selected)" % fname
idCmd = idCmdFirst
items = ['First Python content menu item!']
if (uFlags & 0x000F) == shellcon.CMF_NORMAL: # Check == here, since CMF_NORMAL=0
print "CMF_NORMAL..."
items.append(msg)
elif uFlags & shellcon.CMF_VERBSONLY:
print "CMF_VERBSONLY..."
items.append(msg + " - shortcut")
elif uFlags & shellcon.CMF_EXPLORE:
print "CMF_EXPLORE..."
items.append(msg + " - normal file, right-click in Explorer")
elif uFlags & CMF_DEFAULTONLY:
print "CMF_DEFAULTONLY...\r\n"
else:
print "** unknown flags", uFlags
win32gui.InsertMenu(hMenu, indexMenu,
win32con.MF_SEPARATOR|win32con.MF_BYPOSITION,
0, None)
indexMenu += 1
for item in items:
win32gui.InsertMenu(hMenu, indexMenu,
win32con.MF_STRING|win32con.MF_BYPOSITION,
idCmd, item)
indexMenu += 1
idCmd += 1
win32gui.InsertMenu(hMenu, indexMenu,
win32con.MF_SEPARATOR|win32con.MF_BYPOSITION,
0, None)
indexMenu += 1
return idCmd-idCmdFirst # Must return number of menu items we added.
def InvokeCommand(self, ci):
mask, hwnd, verb, params, dir, nShow, hotkey, hicon = ci
win32gui.MessageBox(hwnd, "Hello", "Wow", win32con.MB_OK)
def GetCommandString(self, cmd, typ):
# If GetCommandString returns the same string for all items then
# the shell seems to ignore all but one. This is even true in
# Win7 etc where there is no status bar (and hence this string seems
# ignored)
return "Hello from Python (cmd=%d)!!" % (cmd,)
def DllRegisterServer():
import _winreg
folder_key = _winreg.CreateKey(_winreg.HKEY_CLASSES_ROOT,
"Folder\\shellex")
folder_subkey = _winreg.CreateKey(folder_key, "ContextMenuHandlers")
folder_subkey2 = _winreg.CreateKey(folder_subkey, "PythonSample")
_winreg.SetValueEx(folder_subkey2, None, 0, _winreg.REG_SZ,
ShellExtension._reg_clsid_)
file_key = _winreg.CreateKey(_winreg.HKEY_CLASSES_ROOT,
"*\\shellex")
file_subkey = _winreg.CreateKey(file_key, "ContextMenuHandlers")
file_subkey2 = _winreg.CreateKey(file_subkey, "PythonSample")
_winreg.SetValueEx(file_subkey2, None, 0, _winreg.REG_SZ,
ShellExtension._reg_clsid_)
print ShellExtension._reg_desc_, "registration complete."
def DllUnregisterServer():
import _winreg
try:
folder_key = _winreg.DeleteKey(_winreg.HKEY_CLASSES_ROOT,
"Folder\\shellex\\ContextMenuHandlers\\PythonSample")
file_key = _winreg.DeleteKey(_winreg.HKEY_CLASSES_ROOT,
"*\\shellex\\ContextMenuHandlers\\PythonSample ")
except WindowsError, details:
import errno
if details.errno != errno.ENOENT:
raise
print ShellExtension._reg_desc_, "unregistration complete."
if __name__=='__main__':
from win32com.server import register
register.UseCommandLine(ShellExtension,
finalize_register = DllRegisterServer,
finalize_unregister = DllUnregisterServer)
I found out how to do this after a lot of trial and error and googling.
The example below shows a menu with a submenu and icons.
# A sample context menu handler.
# Adds a menu item with sub menu to all files and folders, different options inside specified folder.
# When clicked a list of selected items is displayed.
#
# To demostrate:
# * Execute this script to register the context menu. `python context_menu.py --register`
# * Restart explorer.exe- in the task manager end process on explorer.exe. Then file > new task, then type explorer.exe
# * Open Windows Explorer, and browse to a file/directory.
# * Right-Click file/folder - locate and click on an option under 'Menu options'.
import os
import pythoncom
from win32com.shell import shell, shellcon
import win32gui
import win32con
import win32api
class ShellExtension:
_reg_progid_ = "Python.ShellExtension.ContextMenu"
_reg_desc_ = "Python Sample Shell Extension (context menu)"
_reg_clsid_ = "{CED0336C-C9EE-4a7f-8D7F-C660393C381F}"
_com_interfaces_ = [shell.IID_IShellExtInit, shell.IID_IContextMenu]
_public_methods_ = shellcon.IContextMenu_Methods + shellcon.IShellExtInit_Methods
def Initialize(self, folder, dataobj, hkey):
print "Init", folder, dataobj, hkey
win32gui.InitCommonControls()
self.brand= "Menu options"
self.folder= "C:\\Users\\Paul\\"
self.dataobj = dataobj
self.hicon= self.prep_menu_icon(r"C:\path\to\icon.ico")
def QueryContextMenu(self, hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags):
print "QCM", hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags
# Query the items clicked on
files= self.getFilesSelected()
fname = files[0]
idCmd = idCmdFirst
isdir= os.path.isdir(fname)
in_folder= all([f_path.startswith(self.folder) for f_path in files])
win32gui.InsertMenu(hMenu, indexMenu,
win32con.MF_SEPARATOR|win32con.MF_BYPOSITION,
0, None)
indexMenu += 1
menu= win32gui.CreatePopupMenu()
win32gui.InsertMenu(hMenu,indexMenu,win32con.MF_STRING|win32con.MF_BYPOSITION|win32con.MF_POPUP,menu,self.brand)
win32gui.SetMenuItemBitmaps(hMenu,menu,0,self.hicon,self.hicon)
# idCmd+=1
indexMenu+=1
if in_folder:
if len(files) == 1:
if isdir:
win32gui.InsertMenu(menu,0,win32con.MF_STRING,idCmd,"Item 1"); idCmd+=1
else:
win32gui.InsertMenu(menu,0,win32con.MF_STRING,idCmd,"Item 2")
win32gui.SetMenuItemBitmaps(menu,idCmd,0,self.hicon,self.hicon)
idCmd+=1
else:
win32gui.InsertMenu(menu,0,win32con.MF_STRING,idCmd,"Item 3")
win32gui.SetMenuItemBitmaps(menu,idCmd,0,self.hicon,self.hicon)
idCmd+=1
if idCmd > idCmdFirst:
win32gui.InsertMenu(menu,1,win32con.MF_SEPARATOR,0,None)
win32gui.InsertMenu(menu,2,win32con.MF_STRING,idCmd,"Item 4")
win32gui.SetMenuItemBitmaps(menu,idCmd,0,self.hicon,self.hicon)
idCmd+=1
win32gui.InsertMenu(menu,3,win32con.MF_STRING,idCmd,"Item 5")
win32gui.SetMenuItemBitmaps(menu,idCmd,0,self.hicon,self.hicon)
idCmd+=1
win32gui.InsertMenu(menu,4,win32con.MF_SEPARATOR,0,None)
win32gui.InsertMenu(menu,5,win32con.MF_STRING|win32con.MF_DISABLED,idCmd,"Item 6")
win32gui.SetMenuItemBitmaps(menu,idCmd,0,self.hicon,self.hicon)
idCmd+=1
win32gui.InsertMenu(hMenu, indexMenu,
win32con.MF_SEPARATOR|win32con.MF_BYPOSITION,
0, None)
indexMenu += 1
return idCmd-idCmdFirst # Must return number of menu items we added.
def getFilesSelected(self):
format_etc = win32con.CF_HDROP, None, 1, -1, pythoncom.TYMED_HGLOBAL
sm = self.dataobj.GetData(format_etc)
num_files = shell.DragQueryFile(sm.data_handle, -1)
files= []
for i in xrange(num_files):
fpath= shell.DragQueryFile(sm.data_handle,i)
files.append(fpath)
return files
def prep_menu_icon(self, icon): #Couldn't get this to work with pngs, only ico
# First load the icon.
ico_x = win32api.GetSystemMetrics(win32con.SM_CXSMICON)
ico_y = win32api.GetSystemMetrics(win32con.SM_CYSMICON)
hicon = win32gui.LoadImage(0, icon, win32con.IMAGE_ICON, ico_x, ico_y, win32con.LR_LOADFROMFILE)
hdcBitmap = win32gui.CreateCompatibleDC(0)
hdcScreen = win32gui.GetDC(0)
hbm = win32gui.CreateCompatibleBitmap(hdcScreen, ico_x, ico_y)
hbmOld = win32gui.SelectObject(hdcBitmap, hbm)
# Fill the background.
brush = win32gui.GetSysColorBrush(win32con.COLOR_MENU)
win32gui.FillRect(hdcBitmap, (0, 0, 16, 16), brush)
# unclear if brush needs to be feed. Best clue I can find is:
# "GetSysColorBrush returns a cached brush instead of allocating a new
# one." - implies no DeleteObject
# draw the icon
win32gui.DrawIconEx(hdcBitmap, 0, 0, hicon, ico_x, ico_y, 0, 0, win32con.DI_NORMAL)
win32gui.SelectObject(hdcBitmap, hbmOld)
win32gui.DeleteDC(hdcBitmap)
return hbm
def InvokeCommand(self, ci):
mask, hwnd, verb, params, dir, nShow, hotkey, hicon = ci
win32gui.MessageBox(hwnd, str(self.getFilesSelected()), "Wow", win32con.MB_OK)
def GetCommandString(self, cmd, typ):
# If GetCommandString returns the same string for all items then
# the shell seems to ignore all but one. This is even true in
# Win7 etc where there is no status bar (and hence this string seems
# ignored)
return "Hello from Python (cmd=%d)!!" % (cmd,)
def DllRegisterServer():
import _winreg
folder_key = _winreg.CreateKey(_winreg.HKEY_CLASSES_ROOT,
"Folder\\shellex")
folder_subkey = _winreg.CreateKey(folder_key, "ContextMenuHandlers")
folder_subkey2 = _winreg.CreateKey(folder_subkey, "PythonSample")
_winreg.SetValueEx(folder_subkey2, None, 0, _winreg.REG_SZ,
ShellExtension._reg_clsid_)
file_key = _winreg.CreateKey(_winreg.HKEY_CLASSES_ROOT,
"*\\shellex")
file_subkey = _winreg.CreateKey(file_key, "ContextMenuHandlers")
file_subkey2 = _winreg.CreateKey(file_subkey, "PythonSample")
_winreg.SetValueEx(file_subkey2, None, 0, _winreg.REG_SZ,
ShellExtension._reg_clsid_)
print ShellExtension._reg_desc_, "registration complete."
def DllUnregisterServer():
import _winreg
try:
folder_key = _winreg.DeleteKey(_winreg.HKEY_CLASSES_ROOT,
"Folder\\shellex\\ContextMenuHandlers\\PythonSample")
file_key = _winreg.DeleteKey(_winreg.HKEY_CLASSES_ROOT,
"*\\shellex\\ContextMenuHandlers\\PythonSample")
except WindowsError, details:
import errno
if details.errno != errno.ENOENT:
raise
print ShellExtension._reg_desc_, "unregistration complete."
if __name__=='__main__':
from win32com.server import register
register.UseCommandLine(ShellExtension,
finalize_register = DllRegisterServer,
finalize_unregister = DllUnregisterServer)