Python pywinauto search windows with partial title - python

Is there any way to make pywinauto find a window just with a part of the title?
This is my code:
import pywinauto
pwa_app = pywinauto.application.Application()
w_handle = pywinauto.findwindows.find_windows(title=u'Minitab Professional 5.1 64bit - 3333348.temp.project',
class_name='Window')[0]
The problem is that the number before temp.project changes every time I open the software and because of that I cannot get pywinauto to find the right window.

By skimming the source code on google code, I see you can feed a regex for the title :
#=========================================================================
def find_windows(class_name = None,
class_name_re = None,
parent = None,
process = None,
title = None,
title_re = None,
top_level_only = True,
visible_only = True,
enabled_only = False,
best_match = None,
handle = None,
ctrl_index = None,
predicate_func = None,
active_only = False,
control_id = None,
):
"""Find windows based on criteria passed in
Possible values are:
* **class_name** Windows with this window class
* **class_name_re** Windows whose class match this regular expression
* **parent** Windows that are children of this
* **process** Windows running in this process
* **title** Windows with this Text
* **title_re** Windows whose Text match this regular expression
* **top_level_only** Top level windows only (default=True)
* **visible_only** Visible windows only (default=True)
* **enabled_only** Enabled windows only (default=True)
* **best_match** Windows with a title similar to this
* **handle** The handle of the window to return
* **ctrl_index** The index of the child window to return
* **active_only** Active windows only (default=False)
* **control_id** Windows with this control id
"""
According to me pywinauto.findwindows.find_windows(title_re = r'Minitab Professional 5.1 64bit*', class_name='Window')[0] should work.

Use best_match, no need for regex:
handle = pywinauto.findwindows.find_window(best_match='Minitab')
app = pywinauto.application.Application().connect(handle=handle)
or shorter:
app = pywinauto.application.Application().connect(best_match='Minitab')

title_re works as Python regular expression. In your case it should be like title_re=u'Minitab Professional 5\.1 64bit - \d+\.temp\.project'.
\. means dot symbol, . means any symbol.
For fully functional dialog wrapper (instead of handle) the following thing is simpler:
dlg = pwa_app.Window_(title_re=u'Minitab Professional 5\.1 64bit - \d+\.temp\.project', class_name='Window')
It calls find_window with proper process param (this is pid), so you will not be confused by many similar windows from several app instances.
BTW, for 64-bit application you need 64-bit compatible clone of pywinauto (official 0.4.2 supports only 32-bit Python and apps because of different WinAPI structures alignment).

In this case it's better to connect to App by path, like:
app = application.Application(backend="uia")
app.connect(path = r"C:/Program Files/iTunes/iTunes.exe")

Here is another solution with pyautogui:
we will find a window by partial title then close it.
import pyautogui
win = [w for w in pyautogui.getAllWindows() if 'your window partial title' in w.title]
if len(win)>0:
win[0].close()

Related

Python get Desktop Path directly on Windows

Ive seen answers that finds the user's path, and then concatenating it with desktop, Such as:
desktop = os.path.expanduser("~/Desktop")
and
desktop = os.path.join(os.path.join(os.environ['USERPROFILE']), 'Desktop')
However it doesn't work when the device has non-default extensions:
C:\\Users\\NAME\\OneDrive\\Desktop
or non-english extension:
C:\\Users\\NAME\\OneDrive\\桌面
I ended up doing this as an emergency response:
possible_desktop_ext = ['Desktop', 'OneDrive\\Desktop', 'OneDrive\\桌面']
I can definitely see the list expanding exponentially in the future, and I don't really like the feeling of doing this every time I find a new extension.
So what is the most reliable way of retrieving the desktop's path?
This is adapted from https://stackoverflow.com/a/626927/5987, I urge you to go to it and give it the recognition it deserves.
import ctypes
from ctypes import wintypes, windll
CSIDL_DESKTOP = 0
_SHGetFolderPath = windll.shell32.SHGetFolderPathW
_SHGetFolderPath.argtypes = [wintypes.HWND,
ctypes.c_int,
wintypes.HANDLE,
wintypes.DWORD, wintypes.LPCWSTR]
path_buf = ctypes.create_unicode_buffer(wintypes.MAX_PATH)
result = _SHGetFolderPath(0, CSIDL_DESKTOP, 0, 0, path_buf)
print(path_buf.value)

Getting icon from external applications

I am trying to prepare an application similar to 'Windows Start Menu Search'.
That's why I need each applications own icon.
From the C:\ProgramData\Start Menu\Programs\ file path, I add existing applications to a list (QListWidget) with their names and path.
And I get the icons like this:
https://forum.qt.io/topic/62866/getting-icon-from-external-applications
provider = QFileIconProvider()
info = QFileInfo("program_path")
icon = QIcon(provider.icon(info))
And naturally the result is this:
But I don't want this "shortcut icon" to appear.
Then, I am thinking and I came to this conclusion:
shell = win32com.client.Dispatch("WScript.Shell")
provider = QFileIconProvider()
shortcut = shell.CreateShortCut(programPath)
info = QFileInfo(shortcut.targetPath)
icon = QIcon(provider.icon(info))
This solution worked. But, It has created issue for some applications.
So I am looking for an alternative solution.
You were almost there.
Browsing the menu directory tree is actually the right path, but you also have to ensure that the icon of the link is actually the same of the target, as it might not.
The shortcut.iconlocation is a string representing a "tuple" (sort of) including the icon path and the index (as icon resources might contain more than one icon).
>>> shortcut = shell.createShortCut(linkPath)
>>> print(shortcut.iconlocation)
# most links will return this:
> ",0"
# some might return this:
> ",4"
# or this:
> "C:\SomePath\SomeProgram\SomeExe.exe,5"
As long as the icon index is 0, you can get the icon using QFileIconProvider with the targetPath or iconLocation (if there's something before the comma).
The problem comes when there's a value different from 0 for the icon index, as Qt doesn't handle that.
I've put together a simple function (based on some research here on StackOverflow).
def getIcon(self, shortcut):
iconPath, iconId = shortcut.iconLocation.split(',')
iconId = int(iconId)
if not iconPath:
iconPath = shortcut.targetPath
iconPath = os.path.expandvars(iconPath)
if not iconId:
return QICon(self.iconProvider.icon(QFileInfo(iconPath)))
iconRes = win32gui.ExtractIconEx(iconPath, iconId)
hdc = win32ui.CreateDCFromHandle(win32gui.GetDC(0))
hbmp = win32ui.CreateBitmap()
# I think there's a way to find available icon sizes, I'll leave it up to you
hbmp.CreateCompatibleBitmap(hdc, 32, 32)
hdc = hdc.CreateCompatibleDC()
hdc.SelectObject(hbmp)
hdc.DrawIcon((0, 0), iconRes[0][0])
hdc.DeleteDC()
# the original QtGui.QPixmap.fromWinHBITMAP is now part of the
# QtWin sub-module
return QtGui.QIcon(QtWin.fromWinHBITMAP(hbmp.GetHandle(), 2))

get selected files on desktop in Windows (7)

Can someone tell me how I can get all the selected files on Windowsd desktop in Python? I've been searching for a way to do it and I can't find anyone. The only one I found is for C#, but I don't code in C#, so I don't even know if it works: Get list of selected files from Windows Desktop (if someone understands it and could explain/convert it, that'd be appreciated too). I've found something very near of this, but I can only make it get the number of seleted files, not their path, as I'd like:
import ctypes
from commctrl import LVM_GETITEMCOUNT,LVM_GETSELECTEDCOUNT
#The LVM_GETITEMCOUNT came with the script, I got the other one from Microsoft documentation about SendMessage(), and both are near, but none returns the paths, only numbers
import pywintypes
import win32gui
GetShellWindow = ctypes.windll.user32.GetShellWindow
def get_desktop():
"""Get the window of the icons, the desktop window contains this window"""
shell_window = GetShellWindow()
shell_dll_defview = win32gui.FindWindowEx(shell_window, 0, "SHELLDLL_DefView", "")
if shell_dll_defview == 0:
sys_listview_container = []
try:
win32gui.EnumWindows(_callback, sys_listview_container)
except pywintypes.error as e:
if e.winerror != 0:
raise
sys_listview = sys_listview_container[0]
else:
sys_listview = win32gui.FindWindowEx(shell_dll_defview, 0, "SysListView32", "FolderView")
return sys_listview
def _callback(hwnd, extra):
class_name = win32gui.GetClassName(hwnd)
if class_name == "WorkerW":
child = win32gui.FindWindowEx(hwnd, 0, "SHELLDLL_DefView", "")
if child != 0:
sys_listview = win32gui.FindWindowEx(child, 0, "SysListView32", "FolderView")
extra.append(sys_listview)
return False
return True
def get_item_count(window):
return win32gui.SendMessage(window, LVM_GETSELECTEDCOUNT)
desktop = get_desktop()
print(get_item_count(desktop))
I've searched on the commands that can be sent to a window, but I didn't find anyone to get the path of the selected items (maybe I missed one?).
A way I found of getting the selected files from Windows Explorer windows, but now from the desktop: https://stackoverflow.com/a/21250927/8228163.
Any help (with any Windows, preferably 7) is much appreciated. Thanks in advance!

Pulling QGIS plugin logic into stand alone Application

I'm new to QT, Python, and QGIS. I installed the "Plugin Builder" plugin and generated a Dockwidget. I am able to change the widget using qtcreator and am learning how to implement the signals and slots to work with my own plugin.
Now, to my question. Is there and easy way I can remove the QGIS iface and use my plugin's logic outside of QGIS? I'm not actually using any of the PyQGIS libraries at the moment, but I want to keep my QT interface and Python code/structure generated by the "Plugin Builder". Is there a way to do that?
Thanks.
Yes, there is a way to do it. But so far what I have found is that we need to copy entire Qgis library to the final software package. It is very important to set the correct path for qgis application inside the code as follows:
QgsApplication.setPrefixPath(r"C:\OSGeo4W\apps\qgis", True)
QgsApplication.initQgis()
QgsProject.instance().setFileName(strProjectName)
Also we need to write the file and close it at the end
QgsProject.instance().write()
QgsApplication.exitQgis()
Here's snapshot of the stand alone package I have created. The code needs some modification for some variables to work.
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from qgis.core import *
from qgis.gui import *
import os, datetime
class CreateQgs():
def initQgsFile(self, outputFolder, stopRadius):
strProjectName = str(outputFolder) + "\\" + "PhotoLocationMap.qgs"
QgsApplication.setPrefixPath(r"C:\OSGeo4W\apps\qgis", True)
QgsApplication.initQgis()
QgsProject.instance().setFileName(strProjectName)
highwayShapeFilePath = "C:/Shapefiles/Highway.shp"
arterialShapeFilePath = "C:/Shapefiles/StreetsMajor.shp"
highwayLayer = QgsVectorLayer(self.highwayShapeFilePath, 'HighwayDB' , 'ogr')
arterialLayer = QgsVectorLayer(self.arterialShapeFilePath, 'ArterialDB', 'ogr')
symbols = highwayLayer.rendererV2().symbols()
sym = symbols[0]
sym.setColor(QColor.fromRgb(255,94,94))
highwayLayer.triggerRepaint()
symbols = arterialLayer.rendererV2().symbols()
sym = symbols[0]
sym.setColor(QColor.fromRgb(76,138,245))
arterialLayer.triggerRepaint()
mapInstance = QgsMapLayerRegistry.instance()
mapInstance.instance().addMapLayer(arterialLayer)
mapInstance.instance().addMapLayer(highwayLayer)
QgsProject.instance().write()
QgsApplication.exitQgis()
def unitTest():
app = QgsApplication(sys.argv, True)
photoFolderPath = 'C:\Test\QGis\TestPics'
CreateQgsFile = CreateQgs()
CreateQgsFile.initQgsFile(photoFolderPath, 128)
if __name__ == "__main__":
unitTest()

What replaces the now-deprecated Carbon.File.FSResolveAliasFile in Python on OSX?

In Python 2, I can use the following code to resolve either a MacOS alias or a symbolic link:
from Carbon import File
File.FSResolveAliasFile(alias_fp, True)[0].as_pathname()
where alias_fp is the path to the file I'm curious about, stored as a string (source).
However, the documentation cheerfully tells me that the whole Carbon family of modules is deprecated. What should I be using instead?
EDIT: I believe the code below is a step in the right direction for the PyObjC approach. It doesn't resolve aliases, but it seems to detect them.
from AppKit import NSWorkspace
def is_alias (path):
uti, err = NSWorkspace.sharedWorkspace().typeOfFile_error_(
os.path.realpath(path), None)
if err:
raise Exception(unicode(err))
else:
return "com.apple.alias-file" == uti
(source)
Unfortunately I'm not able to get #Milliways's solution working (knowing nothing about Cocoa) and stuff I find elsewhere on the internet looks far more complicated (perhaps it's handling all kinds of edge cases?).
The PyObjC bridge lets you access NSURL's bookmark handling, which is the modern (backwards compatible) replacement for aliases:
import os.path
from Foundation import *
def target_of_alias(path):
url = NSURL.fileURLWithPath_(path)
bookmarkData, error = NSURL.bookmarkDataWithContentsOfURL_error_(url, None)
if bookmarkData is None:
return None
opts = NSURLBookmarkResolutionWithoutUI | NSURLBookmarkResolutionWithoutMounting
resolved, stale, error = NSURL.URLByResolvingBookmarkData_options_relativeToURL_bookmarkDataIsStale_error_(bookmarkData, opts, None, None, None)
return resolved.path()
def resolve_links_and_aliases(path):
while True:
alias_target = target_of_alias(path)
if alias_target:
path = alias_target
continue
if os.path.islink(path):
path = os.path.realpath(path)
continue
return path
The following Cocoa code will resolve alias.
NSURL *targetOfAlias(NSURL *url) {
CFErrorRef *errorRef = NULL;
CFDataRef bookmark = CFURLCreateBookmarkDataFromFile (NULL, (__bridge CFURLRef)url, errorRef);
if (bookmark == nil) return nil;
CFURLRef resolvedUrl = CFURLCreateByResolvingBookmarkData (NULL, bookmark, kCFBookmarkResolutionWithoutUIMask, NULL, NULL, false, errorRef);
CFRelease(bookmark);
return CFBridgingRelease(resolvedUrl);
}
I don't know how to invoke Cocoa framework from Python, but I am sure someone has done it
The following link shows code to resolve aslias or symlink https://stackoverflow.com/a/21151368/838253
The APIs those modules use are deprecated by Apple, it appears. You should use POSIX APIs instead.
os.path.realpath(FILE_OBJECT.name)

Categories