Segmentation fault of ImageMagick + Python ctypes - python

I am using ImageMagick library with Python ctypes. I wrote a following simple code, but it crashes with segmentation fault (KERN_INVALID_ADDRESS) in Mac:
from ctypes import *
from ctypes.util import find_library
lib = CDLL(find_library('MagickWand'))
lib.MagickWandGenesis()
wand = lib.NewMagickWand()
lib.MagickReadImage(wand, 'mona-lisa.jpg')
lib.DestroyMagickWand(wand)
lib.MagickWandTerminus()
It works well in Linux and Windows both, but craches only in Mac OS X Lion. I built ImageMagick in various ways (official binary package, Homebrew, traditional ./configure && make), but it crashed for every trial.
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x00000000009a7638
0x000000010149a8d1 in MagickReadImage ()
Not only for MagickReadImage() function, IsMagickWand() function also crashes. I only guess NewMagickWand() returns a wrong pointer, or ctypes in Mac handles pointers incorrectly, but I’m not sure.
What’s wrong in this situation?

I changed the following code:
lib.MagickReadImage(wand, 'mona-lisa.jpg')
to:
f2 = lib.MagickReadImage
f2.argtypes = [c_void_p, c_char_p]
f2(wand, 'mona-lisa.jpg')
So, it works well.

Most likely this is a 32/64 bit issue. Is the Mac version the only 64 bit process that you've tested? Or perhaps you got lucky in the Windows and Linux versions in that they happen to return pointers of the form 0x00000000xxxxxxxx.
wand = lib.NewMagickWand()
NewMagickWand returns a pointer but you have not told ctypes to expect a pointer. As it stands ctypes defaults to a 32 bit integer for the return value. Add this line before you call NewMagickWand.
lib.NewMagickWand.restype = c_void_p
This tells ctypes that NewMagickWand returns a pointer.

Related

Interacting with AURA_SDK.dll through python using ctypes

I'm trying to control my ASUS ROG Flare keyboard LED colors using python.
I downloaded the Aura Software Developer Kit from the ASUS website.
link here: https://www.asus.com/campaign/aura/us/SDK.php
inside the kit there is a menu guide and a dll file called AURA_SDK.dll. The guide says that with the mentioned dll the keyboard can be controlled.
I'm using the ctypes python package and succeeded in loading the package, but when I'm calling the first function to obtain control on the keyboard the program fails because I don't fully understand the argument the function needs to run.
Documentation from the guide:
Code I am trying:
import ctypes
path_dll = 'AURA_SDK.dll'
dll = ctypes.cdll.LoadLibrary(path_dll)
res = dll.CreateClaymoreKeyboard() # fails here
Any ideas on how to create this argument?
Thanks in advance.
This should do it. A good habit to get into is always define .argtypes and .restype for the functions you call. This will make sure parameters are converted correctly between Python and C types, and provide better error checking to help catch doing something incorrectly.
There are also many pre-defined Windows types in wintypes so you don't have to guess what ctype-type to use for a parameter.
Also note that WINAPI is defined as __stdcall calling convention and should use WinDLL instead of CDLL for loading the DLL. On 64-bit systems there is no difference between standard C calling convention (__cdecl) and __stdcall, but it will matter if you are using 32-bit Python or desire portability to 32-bit Python.
import ctypes as ct
from ctypes import wintypes as w
dll = ct.WinDLL('./AURA_SDK') # Use WinDLL for WINAPI calls.
dll.CreateClaymoreKeyboard.argtypes = ct.POINTER(ct.c_void_p), # tuple of arguments
dll.CreateClaymoreKeyboard.restype = w.DWORD
handle = ct.c_void_p() # Make an instance to pass by reference and receive the handle.
res = dll.CreateClaymoreKeyboard(ct.byref(handle))
# res is non-zero on success

PySide and VTK on Windows 32

I've got a PySide/VTK application, connected using the QVTKRenderWindowInteractor.
PySide 1.0.9 works ok on Unix based systems with a QT4.8/VTK 5.8. (all Python 2.7.3)
Then I port on a Microsoft Windows system (XP 32), with PySide win32 distribution (1.1.x) Qt4 and VTK 5.10, and I have a type error in QVTKRenderWindowInteractor while retrieving the self.winId() which is expected to be castable as int:
TypeError: int() argument must be a string or a number, not 'PyCObject'
The PySide API actually says the PySide.QtGui.QWidget.winId() returns a long...
I'm starting some more tests on both MS-Windows and Unix, but maybe some of you could give me a piece of advice?
What and where do I have to look for?
Could it be related to a bad cast of this long on a 32bits system, produced by the PySide interface generator to Qt?
see line 152
http://sourceforge.net/p/pycgns/code/ci/17b696c3b0ad2b387b7e0ddc5d9b195cbc6abf70/tree/NAVigater/CGNS/NAV/Q7VTKRenderWindowInteractor.py
Replace this row by:
WId = self.winId()
if type(WId).__name__ == 'PyCObject':
from ctypes import pythonapi, c_void_p, py_object
pythonapi.PyCObject_AsVoidPtr.restype = c_void_p
pythonapi.PyCObject_AsVoidPtr.argtypes = [py_object]
WId = pythonapi.PyCObject_AsVoidPtr(WId)
self._RenderWindow.SetWindowInfo(str(int(WId)))

Detect 64bit OS (windows) in Python

Does anyone know how I would go about detected what bit version Windows is under Python. I need to know this as a way of using the right folder for Program Files.
Many thanks
I think the best solution to the problem has been posted by Mark Ribau.
The best answer to the question for Python 2.7 and newer is:
def is_os_64bit():
return platform.machine().endswith('64')
On windows the cross-platform-function platform.machine() internally uses the environmental variables used in Matthew Scoutens answer.
I found the following values:
WinXP-32: x86
Vista-32: x86
Win7-64: AMD64
Debian-32: i686
Debian-64: x86_64
For Python 2.6 and older:
def is_windows_64bit():
if 'PROCESSOR_ARCHITEW6432' in os.environ:
return True
return os.environ['PROCESSOR_ARCHITECTURE'].endswith('64')
To find the Python interpreter bit version I use:
def is_python_64bit():
return (struct.calcsize("P") == 8)
I guess you should look in os.environ['PROGRAMFILES'] for the program files folder.
platform module -- Access to underlying platform’s identifying data
>>> import platform
>>> platform.architecture()
('32bit', 'WindowsPE')
On 64-bit Windows, 32-bit Python returns:
('32bit', 'WindowsPE')
And that means that this answer, even though it has been accepted, is incorrect. Please see some of the answers below for options that may work for different situations.
Came here searching for properly detecting if running on 64bit windows, compiling all the above into something more concise.
Below you will find a function to test if running on 64bit windows, a function to get the 32bit Program Files folder, and a function to get the 64bit Program Files folder; all regardless of running 32bit or 64bit python. When running 32bit python, most things report as if 32bit when running on 64bit, even os.environ['PROGRAMFILES'].
import os
def Is64Windows():
return 'PROGRAMFILES(X86)' in os.environ
def GetProgramFiles32():
if Is64Windows():
return os.environ['PROGRAMFILES(X86)']
else:
return os.environ['PROGRAMFILES']
def GetProgramFiles64():
if Is64Windows():
return os.environ['PROGRAMW6432']
else:
return None
Note: Yes, this is a bit hackish. All other methods that "should just work", do not work when running 32bit Python on 64bit Windows (at least for the various 2.x and 3.x versions I have tried).
Edits:
2011-09-07 - Added a note about why only this hackish method works properly.
def os_platform():
true_platform = os.environ['PROCESSOR_ARCHITECTURE']
try:
true_platform = os.environ["PROCESSOR_ARCHITEW6432"]
except KeyError:
pass
#true_platform not assigned to if this does not exist
return true_platform
http://blogs.msdn.com/b/david.wang/archive/2006/03/26/howto-detect-process-bitness.aspx
Many of these proposed solutions, such as platform.architecture(), fail because their results depend on whether you are running 32-bit or 64-bit Python.
The only reliable method I have found is to check for the existence of os.environ['PROGRAMFILES(X86)'], which is unfortunately hackish.
You should be using environment variables to access this. The program files directory is stored in the environment variable PROGRAMFILES on x86 Windows, the 32-bit program files is directory is stored in the PROGRAMFILES(X86) environment variable, these can be accessed by using os.environ('PROGRAMFILES').
Use sys.getwindowsversion() or the existence of PROGRAMFILES(X86) (if 'PROGRAMFILES(X86)' in os.environ) to determine what version of Windows you are using.
Following this documentation, try this code:
is_64bits = sys.maxsize > 2**32
Im aware that in comments of the question this method was already used.
This is the method the .net framework uses:
import ctypes
def is64_bit_os():
""" Returns wethever system is a 64bit operating system"""
is64bit = ctypes.c_bool()
handle = ctypes.windll.kernel32.GetCurrentProcess() # should be -1, because the current process is currently defined as (HANDLE) -1
success = ctypes.windll.kernel32.IsWow64Process(handle, ctypes.byref(is64bit)) #should return 1
return (success and is64bit).value
print(is64_bit_os())
I just found another way to do this, which may be useful in some situations.
import subprocess
import os
def os_arch():
os_arch = '32-bit'
if os.name == 'nt':
output = subprocess.check_output(['wmic', 'os', 'get', 'OSArchitecture'])
os_arch = output.split()[1]
else:
output = subprocess.check_output(['uname', '-m'])
if 'x86_64' in output:
os_arch = '64-bit'
else:
os_arch = '32-bit'
return os_arch
print 'os_arch=%s' % os_arch()
I tested this code in the following environments:
Ubuntu 16.04 + Python 2.7.12
Mac OS Sierra + Python 2.7.11
Windows 7 Pro 32-bit + Python 2.7.5 (32-bit)
Windows 10 Home 64-bit + Python 2.7.13 (32-bit)
The subject lines asks about detecting 64 or 32bit OS, while the body talks about determining the location of ProgramFiles. The latter has a couple of workable answers here. I'd like to add another solution generalized to handle StartMenu, Desktop, etc. as well as ProgramFiles: How to get path of Start Menu's Programs directory?
When you need to find out things about windows system, it is usually somewhere in the registry, according to MS documentation, you should look at (http://support.microsoft.com/kb/556009) this key value:
HKLM\HARDWARE\DESCRIPTION\System\CentralProcessor\0
and if it is:
0x00000020 (32 in decimal)
It is a 32 bit machine.
64-bit versions of Windows use something called registry redirection and reflection keys. There is a compatibility layer called WoW64 which enables compatibility of 32-bit applications. Starting from Windows 7 and Windows Server 2008 R2 WoW64 registry keys are not longer reflected but shared. You can read about it here:
registry-reflection: msdn.microsoft.com/en-us/library/aa384235(v=vs.85).aspx
affected-keys: msdn.microsoft.com/en-us/library/aa384253(v=vs.85).aspx
wikipedia: en.wikipedia.org/wiki/WoW64
All you need to do is detect existence of those keys. You can use _winreg for that. Use try: and try opening key, example:
try:
aReg = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,"SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Run")
import _winreg
def get_registry_value(key, subkey, value):
key = getattr(_winreg, key)
handle = _winreg.OpenKey(key, subkey )
(value, type) = _winreg.QueryValueEx(handle, value)
return value
windowsbit=cputype = get_registry_value(
"HKEY_LOCAL_MACHINE",
"SYSTEM\\CurrentControlSet\Control\\Session Manager\\Environment",
"PROCESSOR_ARCHITECTURE")
print windowsbit
just run this code
if you are working on 64 bit windows machine this will print AMD64
or if you are working on 32 bit it will print AMD32
i hope this code can help to solve this problem fully
This works for me in the Python versions I use: 2.7 and 2.5.4
import win32com.client
import _winreg
shell = win32com.client.Dispatch('WScript.Shell')
proc_arch = shell.ExpandEnvironmentStrings(r'%PROCESSOR_ARCHITECTURE%').lower()
if proc_arch == 'x86':
print "32 bit"
elif proc_arch == 'amd64':
print "64 bit"
else:
raise Exception("Unhandled arch: %s" % proc_arch)
Just to update this old thread - it looks like the platform module reports the correct architecture now (at least, in Python 2.7.8):
c:\python27\python.exe -c "import platform; print platform.architecture(), platform.python_version()"
('32bit', 'WindowsPE') 2.7.6
c:\home\python278-x64\python.exe -c "import platform; print platform.architecture(), platform.python_version()"
('64bit', 'WindowsPE') 2.7.8
(sorry I don't have the rep to comment on the first answer which still claims to be wrong :)
import platform
platform.architecture()[0]
It will return '32bit' or '64bit' depending on system architecture.
The solution posted by Alexander Brüsch is the correct solution, but it has a bug that only reveals itself on python3.x. He neglected to cast the returned value from GetCurrentProcess() to a HANDLE type. Passing a simple integer as the first parameter of IsWow64Process() returns 0 (which is an error flag from win32api). Also, Alexander incorrectly handles the return statement (success has no .value attribute).
For those who stumble on this thread, here is the corrected code:
import ctypes
def is64_bit_os():
"""Returns True if running 32-bit code on 64-bit operating system"""
is64bit = ctypes.c_bool()
handle = ctypes.wintypes.HANDLE(ctypes.windll.kernel32.GetCurrentProcess())
success = ctypes.windll.kernel32.IsWow64Process(handle, ctypes.byref(is64bit))
return success and is64bit.value
print(is64_bit_os())
There is a function named machine in platform module. I installed both Python3.8 32-bit and 64-bit versions on the same 64-bit machine with 64-bit Windows 10 and here is what I found:
And it looks like platform.machine returns machine architecture without bothering what type of python is installed. so here is my
final compilation
import platform
def is_64bit():
return platform.machine().endswith('64')
Most of the answers here are incorrect :/
Here is a simple translation of the well known method used in CMD and this is how microsoft do it too.
import os
_os_bit=64
if os.environ.get('PROCESSOR_ARCHITECTURE').lower() == 'x86' and os.environ.get('PROCESSOR_ARCHITEW6432') is None: _os_bit=32
print(_os_bit)
but remember: Windows 10 on ARM includes an x86-on-ARM64 emulation, so the possible values for PROCESSOR_ARCHITECTURE are: AMD64 or IA64 or ARM64 or x86
A solution, putting together the options from the links below and using os module:
import os
#next save the response from the command prompt saved to a file
window = os.system('PowerShell.exe "gwmi win32_operatingsystem | select osarchitecture" > prompt.txt')
#next read the file
f = open('prompt.txt','r')
windowsos = f.readlines()
f.close()
print(windowsos[3][:-1])
https://datatofish.com/command-prompt-python/
https://www.radishlogic.com/windows/how-to-check-if-your-windows-10-is-64-bit-or-32-bit/
https://www.tutorialspoint.com/how-to-run-a-powershell-script-from-the-command-prompt
import struct
def is64Windows():
return struct.calcsize('P') * 8 == 64
There should be a directory under Windows 64bit, a Folder called \Windows\WinSxS64 for 64 bit, under Windows 32bit, it's WinSxS.

calling Objective C functions from Python?

Is there a way to dynamically call an Objective C function from Python?
For example, On the mac I would like to call this Objective C function
[NSSpeechSynthesizer availableVoices]
without having to precompile any special Python wrapper module.
As others have mentioned, PyObjC is the way to go. But, for completeness' sake, here's how you can do it with ctypes, in case you need it to work on versions of OS X prior to 10.5 that do not have PyObjC installed:
import ctypes
import ctypes.util
# Need to do this to load the NSSpeechSynthesizer class, which is in AppKit.framework
appkit = ctypes.cdll.LoadLibrary(ctypes.util.find_library('AppKit'))
objc = ctypes.cdll.LoadLibrary(ctypes.util.find_library('objc'))
objc.objc_getClass.restype = ctypes.c_void_p
objc.sel_registerName.restype = ctypes.c_void_p
objc.objc_msgSend.restype = ctypes.c_void_p
objc.objc_msgSend.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
# Without this, it will still work, but it'll leak memory
NSAutoreleasePool = objc.objc_getClass('NSAutoreleasePool')
pool = objc.objc_msgSend(NSAutoreleasePool, objc.sel_registerName('alloc'))
pool = objc.objc_msgSend(pool, objc.sel_registerName('init'))
NSSpeechSynthesizer = objc.objc_getClass('NSSpeechSynthesizer')
availableVoices = objc.objc_msgSend(NSSpeechSynthesizer, objc.sel_registerName('availableVoices'))
count = objc.objc_msgSend(availableVoices, objc.sel_registerName('count'))
voiceNames = [
ctypes.string_at(
objc.objc_msgSend(
objc.objc_msgSend(availableVoices, objc.sel_registerName('objectAtIndex:'), i),
objc.sel_registerName('UTF8String')))
for i in range(count)]
print voiceNames
objc.objc_msgSend(pool, objc.sel_registerName('release'))
It ain't pretty, but it gets the job done. The final list of available names is stored in the voiceNames variable above.
2012-4-28 Update: Fixed to work in 64-bit Python builds by making sure all parameters and return types are passed as pointers instead of 32-bit integers.
Since OS X 10.5, OS X has shipped with the PyObjC bridge, a Python-Objective-C bridge. It uses the BridgeSupport framework to map Objective-C frameworks to Python. Unlike, MacRuby, PyObjC is a classical bridge--there is a proxy object on the python side for each ObjC object and visa versa. The bridge is pretty seamless, however, and its possible to write entire apps in PyObjC (Xcode has some basic PyObjC support, and you can download the app and file templates for Xcode from the PyObjC SVN at the above link). Many folks use it for utilities or for app-scripting/plugins. Apple's developer site also has an introduction to developing Cocoa applications with Python via PyObjC which is slightly out of date, but may be a good overview for you.
In your case, the following code will call [NSSpeechSynthesizer availableVoices]:
from AppKit import NSSpeechSynthesizer
NSSpeechSynthesizer.availableVoices()
which returns
(
"com.apple.speech.synthesis.voice.Agnes",
"com.apple.speech.synthesis.voice.Albert",
"com.apple.speech.synthesis.voice.Alex",
"com.apple.speech.synthesis.voice.BadNews",
"com.apple.speech.synthesis.voice.Bahh",
"com.apple.speech.synthesis.voice.Bells",
"com.apple.speech.synthesis.voice.Boing",
"com.apple.speech.synthesis.voice.Bruce",
"com.apple.speech.synthesis.voice.Bubbles",
"com.apple.speech.synthesis.voice.Cellos",
"com.apple.speech.synthesis.voice.Deranged",
"com.apple.speech.synthesis.voice.Fred",
"com.apple.speech.synthesis.voice.GoodNews",
"com.apple.speech.synthesis.voice.Hysterical",
"com.apple.speech.synthesis.voice.Junior",
"com.apple.speech.synthesis.voice.Kathy",
"com.apple.speech.synthesis.voice.Organ",
"com.apple.speech.synthesis.voice.Princess",
"com.apple.speech.synthesis.voice.Ralph",
"com.apple.speech.synthesis.voice.Trinoids",
"com.apple.speech.synthesis.voice.Vicki",
"com.apple.speech.synthesis.voice.Victoria",
"com.apple.speech.synthesis.voice.Whisper",
"com.apple.speech.synthesis.voice.Zarvox"
)
(a bridged NSCFArray) on my SL machine.
Mac OS X from 10.5 onward has shipped with Python and the objc module that will let you do what you want.
An example:
from Foundation import *
thing = NSKeyedUnarchiver.unarchiveObjectWithFile_(some_plist_file)
You can find more documentation here.
You probably want PyObjC. That said, I've never actually used it myself (I've only ever seen demos), so I'm not certain that it will do what you need.

Finding the Current Active Window in Mac OS X using Python

Is there a way to find the application name of the current active window at a given time on Mac OS X using Python?
This should work:
#!/usr/bin/python
from AppKit import NSWorkspace
activeAppName = NSWorkspace.sharedWorkspace().activeApplication()['NSApplicationName']
print activeAppName
Only works on Leopard, or on Tiger if you have PyObjC installed and happen to point at the right python binary in line one (not the case if you've installed universal MacPython, which you'd probably want to do on Tiger). But Peter's answer with the Carbon way of doing this will probably be quite a bit faster, since importing anything from AppKit in Python takes a while, or more accurately, importing something from AppKit for the first time in a Python process takes a while.
If you need this inside a PyObjC app, what I describe will work great and fast, since you only experience the lag of importing AppKit once. If you need this to work as a command-line tool, you'll notice the performance hit. If that's relevant to you, you're probably better off building a 10 line Foundation command line tool in Xcode using Peter's code as a starting point.
The method in the accepted answer was deprecated in OS X 10.7+. The current recommended version would be the following:
from AppKit import NSWorkspace
active_app_name = NSWorkspace.sharedWorkspace().frontmostApplication().localizedName()
print(active_app_name)
First off, do you want the window or the application name? This isn't Windows—an application process on Mac OS X can have multiple windows. (Furthermore, this has also been true of Windows for a few years now, although I have no idea what the API looks like for that.)
Second, Carbon or Cocoa?
To get the active window in Cocoa:
window = NSApp.mainWindow()
To get the name of your process in Cocoa:
appName = NSProcessInfo.processInfo().processName()
Edit: Oh, I think I know what you want. The name of the frontmost process, right?
I don't think there's a way to do it in Cocoa, but here's how to do it in Carbon in C:
ProcessSerialNumber psn = { 0L, 0L };
OSStatus err = GetFrontProcess(&psn);
/*error check*/
CFStringRef processName = NULL;
err = CopyProcessName(&psn, &processName);
/*error check*/
Remember to CFRelease(processName) when you're done with it.
I'm not sure what that will look like in Python, or if it's even possible. Python doesn't have pointers, which makes that tricky.
I know PyObjC would translate the latter argument to CopyProcessName into err, processName = CopyProcessName(…), but the Carbon bindings don't rely on PyObjC (they're part of core Python 2), and I'm not sure what you do about the PSN either way.
I needed the current frontmost application in a Python script that arranges the windows nicely on my screen (see move_window).
Of course, the complete credit goes to Peter! But here is the complete program:
#include <Carbon/Carbon.h>
int main(int, char) {
ProcessSerialNumber psn = { 0L, 0L };
OSStatus err = GetFrontProcess(&psn);
CFStringRef processName = NULL;
err = CopyProcessName(&psn, &processName);
printf("%s\n", CFStringGetCStringPtr(processName, NULL));
CFRelease(processName);
}
Build with gcc -framework Carbon filename.c

Categories