How can I save a shortcut's icon? - python

I am trying to write a program where I can open any program from a folder of shortcuts on my desktop. As part of the gui, I would like the shortcut's icon to be visible next to its name. Any idea how I can get a shortcuts icon from a directory, without manually finding and saving it?
I tried to find the shortcut's file properties to see where its icon was, but I couldn't find any code to help me see it.

Using pywin32 according to http://timgolden.me.uk/pywin32-docs/win32com.shell_and_Windows_Shell_Links.html
from win32com.shell import shell
import pythoncom
shortcut = pythoncom.CoCreateInstance(
shell.CLSID_ShellLink, None,
pythoncom.CLSCTX_INPROC_SERVER, shell.IID_IShellLink
)
shortcut.QueryInterface( pythoncom.IID_IPersistFile ).Load( filepath )
Get the Icon path and ID:
>>> print(shortcut.GetIconLocation())
('', 0)
If manually changed:
('%ProgramFiles%\\Blender Foundation\\Blender 3.4\\blender-launcher.exe', 0)
So we need to get the EXE path to resolve the Icon if the path is empty.
See docs for the ENUM supplied.
And I manually pretty printed the result.
>>> print(shortcut.GetPath(shell.SLGP_UNCPRIORITY ))
(
'C:\\Program Files\\Blender Foundation\\Blender 3.4\\blender-launcher.exe',
(
32,
pywintypes.datetime(2022, 12, 20, 2, 2, 52, tzinfo=TimeZoneInfo('GMT Standard Time', True)),
pywintypes.datetime(2023, 1, 16, 10, 30, 16, 724000, tzinfo=TimeZoneInfo('GMT Standard Time', True)),
pywintypes.datetime(2022, 12, 20, 2, 2, 52, tzinfo=TimeZoneInfo('GMT Standard Time', True)),
0,
1079520,
0,
0,
'blender-launcher.exe',
''
)
)
The extra data seems to be from the EXE, see MS Windows Docs: https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-win32_find_dataa

Related

GIMP script can find custom palette when run in terminal but cant when inside a program

I want to execute gimp -if --batch-interpreter python-fu-eval -b 'import sys;sys.path=["."]+sys.path;import colorindex;colorindex.python_colorindex("gimptemp.jpg")' -b 'pdb.gimp_quit(1)' (which works fine when run in the terminal) from inside a script like this colorindex = subprocess.run(["/usr/bin/gimp", "-if", "--batch-interpreter", "python-fu-eval", "-b", "import sys;sys.path=['.']+sys.path;import colorindex;colorindex.python_colorindex('gimptemp.jpg')", "-b", "pdb.gimp_quit(1)"]) (which errors bc a gimp function cant find a needed palette)
Error:
GIMP-Error: Calling error for procedure 'gimp-image-convert-indexed':
Palette 'E-Ink' not found
Traceback (most recent call last):
File "/usr/lib/gimp/2.0/python/gimpfu.py", line 827, in _run
return apply(func, params[1:])
File "/usr/lib/gimp/2.0/plug-ins/python-eval/python-eval.py", line 25, in code_eval
exec code in globals()
File "<string>", line 1, in <module>
File "./colorindex.py", line 7, in python_colorindex
pdb.gimp_image_convert_indexed(image, 1, 4, 3, FALSE, FALSE, "E-Ink")
RuntimeError: Palette 'E-Ink' not found
batch command experienced an execution error
/usr/bin/gimp: GEGL-WARNING: (gegl-tile-handler-cache.c:977):gegl_tile_cache_destroy: runtime check failed: (g_queue_is_empty (&cache_queue))
EEEEeEeek! 2 GeglBuffers leaked
I got the same issue in terminal when I accidentally left in the -d flag blocking brushes and things from loading, but obviously I took that out so idk what could be blocking the palette from loading this time, especially when it works in terminal. Using subprocess.Popen instead didn't change the error. The custom palette doesnt show up in the palette tray gui when I open gimp through the script, but it does show up in the gui when ran through terminal
Here's colorindex.py
import os
from gimpfu import *
def python_colorindex(file):
image = pdb.gimp_file_load(file, file, run_mode=RUN_NONINTERACTIVE)
drawable = pdb.gimp_image_get_active_layer(image)
pdb.gimp_image_convert_indexed(image, 1, 4, 3, FALSE, FALSE, "E-Ink")
pdb.file_png_save(image, drawable, file, file, 0, 0, 0, 0, 0, 0, 0)
pdb.gimp_image_delete(image)
print("Exit")
I can't replicate this as I'm a Windows user, but I assume that your E-Ink.gpl palette is saved in your personal palette directory, maybe running gimp as a subprocess from python isn't loading your personal files.
You might try forcing gimp to use your personal setup by using the --gimprc=filename option to point to your personal gimprc file.

Python 2.7: Unable to read command output from terminal using StringIO() and Pandas

I am getting the following error when trying to read the output from a command from terminal using StringIO, this script is working fine in Python 3.x, however due to requirements in our environment I need to run this script in Python 2.7, any help to resolve this is appreciated:
Error
TypeError: initial_value must be unicode or None, not _io.StringIO
Script which is working fine in Python 3.x, but not working in 2.7
interface_status = connect.send_command('show ip int brief',expect_string=r'#')
old_stdout = sys.stdout
interface_result = StringIO()
sys.stdout = interface_result
sys.stdout = old_stdout
data_xe = pd.read_fwf(StringIO(interface_result), widths=[23, 16, 4, 7, 22, 8])
print(data_xe)
I have tried adding unicode before the variable, but it gives me blank data:
data_xe = pd.read_fwf(StringIO(unicode(interface_result)), widths=[23, 16, 4, 7, 22, 8])

Why Does My GIMP Python Plug-In Not Work on My Ubuntu Linux Box?

I am trying to write my own Python plug-in for the GNU Image Manipulation Plug-In. I was following this tutorial at this URL: http://gimpbook.com/scripting/slides/index.html. I changed some of the variable names and named the script something different but basically it is the same script.
The script works when calling it from the interactive GIMP Python shell. I access by doing this with the mouse: "Filters -> Python-Fu -> Console". Here the hello_world() function works.
However, when I put the plug-in in the .gimp2.8/plugins/ folder or the /usr/lib/gimp/2.0/plug-ins I am not able to see the plug-in in the Plug-In Browser after going to Help -> Plug-In Browser. Does anyone know what I am missing?
Regards,
My source-code for the Python GIMP plug-in is below...
#! /usr/bin/env python
from gimpfu import *
def hello_world(initstr, font, size, color):
img = gimp.Image(1, 1, RGB)
gimp.set_foreground(color)
layer = pdb.gimp_text_fontname(img, None, 0, 0, initstr, 10, True, size, PIXELS, font)
img.resize(layer.width, layer.height, 0, 0)
gimp.Display(img)
register(
"pythonic_easier_gimp",
"Hello Gimp Image", "Hello gimp image",
"My Name", "My Name", "2015",
"Easier gimp...",
"",
[
(PF_STRING, "string", "String", 'Hello, Gimp!'),
(PF_FONT, "font", "Font face", "Sans")
(PF_SPINNER, "size", "Font size", 50, (1, 3000, 1)),
(PF_COLOR, "color", "Text color", (1.0, 0.0, 0.0))
],
[],
easier_gimp, menu="<Image>/File/Create")
main()
If the script does not show on the menus it means the call to "register" and "main" above is not being run. One possibility is that you have not marked your Python file with the exectutable permission. (Check the file properties, or run chmod 777 myfile.py on it)
Another possibility is a Python syntax error - that could be difficult to spot giving the listing - to check for syntax errors, try just running the script as a normal Python program from the shell: $ python myfile.py - that should yield an ImportError. If you see a SyntaxError, fix that instead.
And finally, with the plug-in in place, start it from the terminal, instead of the menus - if GIMP found your plug-in but stumbled on an error on it, it should display a Wire read error on the terminal output: it also could indicate a Python syntax error, or incorrect call to register (too few or too many parameters). Since by this time you have ruled out syntax errors, double check your parameter count to register)
It should show up in the menus when you have fixed stuff thus far.
I found out a solution! I read a few tutorials online and switched to a different development environment, Eclipse using the PyDev plug-in. PyDev was able to point out syntax errors in the overly complex register() function.
#! /usr/bin/env python
from gimpfu import *
def wonka():
img = gimp.Image(1, 1, RGB)
gimp.set_foreground('purple')
layer = pdb.gimp_text_fontname(img, None, 0, 0, 'Willy Wonka!', 10, True, 90, PIXELS, 'comic sans')
img.resize(layer.width, layer.height, 0, 0)
gimp.Display(img)
register(
"wonka",
"Prints a message from Willy Wonka",
"Prints a message from Willy Wonka",
"User3870315",
"User3870315",
"2015",
"<Toolbox>/Tools/Wonka",
"",
[],
[],
wonka)
main()
This shows up in the Filters -> Python-Fu -> Console -> Browse. It also shows up in the toolbar under Tools.
These links helped:
http://gimpforums.com/thread-plugin-registration-problems
http://www.ibm.com/developerworks/library/os-autogimp/index.html
2 problems with the code stood out to me the function/call mismatched and a missing delimiting comma
(PF_FONT, "font", "Font face", "Sans") #<--missing comma
def hello_world(initstr, font, size, color): #<--Defined function hello_world()
easier_gimp, menu="<Image>/File/Create") #<--plugin calls easier_gimp()
So adding the comma and renaming hello_world to easier_gimp allow the plugin to work.
#! /usr/bin/env python
from gimpfu import *
def easier_gimp(initstr, font, size, color):
img = gimp.Image(1, 1, RGB)
gimp.set_foreground(color)
layer = pdb.gimp_text_fontname(img, None, 0, 0, initstr, 10, True, size, PIXELS, font)
img.resize(layer.width, layer.height, 0, 0)
gimp.Display(img)
register(
"pythonic_easier_gimp",
"Hello Gimp Image", "Hello gimp image",
"My Name", "My Name", "2015",
"Easier gimp...",
"",
[
(PF_STRING, "string", "String", 'Hello, Gimp!'),
(PF_FONT, "font", "Font face", "Sans"),
(PF_SPINNER, "size", "Font size", 50, (1, 3000, 1)),
(PF_COLOR, "color", "Text color", (1.0, 0.0, 0.0))
],
[],
easier_gimp, menu="<Image>/File/Create")
main()
Recently have been created Python based Hello World GIMP plugin examples in this github project

How to set shortcut working directory in cx_freeze msi bundle?

I was working on a Python program which deals with SQLite3 databases. I made it as an MSI setup file by using cx_Freeze.
Windows shortcuts produced by .msi set-up files generated by cx_Freeze do not provide the working directory property of the shortcut. Thus, when I run the executable using the shortcut created on the desktop, it's creating database files on the desktop itself.
This can be changed by providing a different working directory to the shortcut. How do I do that?
I was able to fix the problem by making a small change to cx_Freeze/windist.py. In add_config(), line 61, I changed:
msilib.add_data(self.db, "Shortcut",
[("S_APP_%s" % index, executable.shortcutDir,
executable.shortcutName, "TARGETDIR",
"[TARGETDIR]%s" % baseName, None, None, None,
None, None, None, None)])
to
msilib.add_data(self.db, "Shortcut",
[("S_APP_%s" % index, executable.shortcutDir,
executable.shortcutName, "TARGETDIR",
"[TARGETDIR]%s" % baseName, None, None, None,
None, None, None, "TARGETDIR")]) # <--- Working directory.
Thanks everyone.
Found the solution in the answer to another question.
Essentially, one needs to set up the shortcut table data. The last 'TARGETDIR' in the shortcut_table below sets up the working directory to be the installation directory.
---copied from above mentioned answer---
from cx_Freeze import *
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa371847(v=vs.85).aspx
shortcut_table = [
("DesktopShortcut", # Shortcut
"DesktopFolder", # Directory_
"DTI Playlist", # Name
"TARGETDIR", # Component_
"[TARGETDIR]playlist.exe",# Target
None, # Arguments
None, # Description
None, # Hotkey
None, # Icon
None, # IconIndex
None, # ShowCmd
'TARGETDIR' # WkDir
)
]
# Now create the table dictionary
msi_data = {"Shortcut": shortcut_table}
# Change some default MSI options and specify the use of the above defined tables
bdist_msi_options = {'data': msi_data}
setup(
options = {
"bdist_msi": bdist_msi_options,
},
executables = [
Executable(
"MyApp.py",
)
]
)

Python CreateFile Cannot Find PhysicalMemory

I am trying to access the Physical Memory of a Windows 2000 system (trying to do this without a memory dumping tool). My understanding is that I need to do this using the CreateFile function to create a handle. I have used an older version of win32dd to help me through this. Other documentation on the web points me to using either "\Device\PhysicalMemory" or "\\.\PhysicalMemory". Unfortunately, I get the same error for each.
Traceback (most recent call last):
File "testHandles.py", line 101, in (module)
File "testHandles.py", line 72, in createFileHandle
pywintypes.error: (3, 'CreateFile', 'The system cannot find the path specified.')
Actually, the error number returned is different for each run \\.\PhysicalMemory == 3 and \Device\PhysicalMemory == 2. Review of pywin32, win32file, createfile, pyhandle, and pywintypes did not produce information as to the different return values.
Here is my code. I am using py2exe to get this working on Windows 2000 (and yes it compiles successfully). I realize that I might also have a problem with DeviceIoControl but right now I am concentrating on CreateFile.
# testHandles.py
import ctypes
import socket
import struct
import sys
import win32file
import pywintypes
def createFileHandle():
outLoc = pywintypes.Unicode("C:\\Documents and Settings\\Administrator\\My Documents\\pymemdump_dotPM.dd")
handleLoc = pywintypes.Unicode("\\\\.\\PhysicalMemory")
#handleLoc = pywintypes.Unicode("\\Device\\PhysicalMemory")
placeHolder = 0
BytesReturned = 0
# Device = CreateFile(L"\\\\.\\win32dd", GENERIC_ALL, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
# CreateFile(fileName, desiredAccess , shareMode , attributes , creationDisposition , flagsAndAttributes , hTemplateFile )
#hMemHandle = win32file.CreateFile(handleLoc, GENERIC_ALL, SHARE_READ, None, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, None)
hMemHandle = win32file.CreateFile(handleLoc, win32file.GENERIC_READ, win32file.FILE_SHARE_READ, None, win32file.OPEN_EXISTING, win32file.FILE_ATTRIBUTE_NORMAL, None)
print "hMemHandle: %s" % hMemHandle
if (hMemHandle == NO_ERROR):
print "Could not build hMemHandle"
sys.exit()
# We send destination path to the driver.
#if (!DeviceIoControl(hMemHandle, 0x19880922, outLoc, (ULONG)(wcslen(outLoc) + 1) * sizeof(TCHAR), NULL, 0, &BytesReturned, NULL))
if (ctypes.windll.Kernel32.DeviceIoControl(hMemHandle, 0x19880922, outLoc, 5, NULL, 0, BytesReturned, NULL)):
print "Error: DeviceIoControl(), Cannot send IOCTL.\n"
else:
print "[win32dd] Physical memory dumped. You can now check %s.\n" % outLoc
# Dump memory
createFileHandle()
Thank you,
Cutaway
I don't believe it's possible to access the physical memory object from user mode land in Windows. As your win32dd link suggests, you will need to do it from kernel mode.

Categories