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)))
Related
I've been trying to create a simple window using win32api but in python using the ctypes lib.
Now the first thing i need is the programs console windows instance handle.
For getting that i need to get a handle to the console window which is doable by using Kernel.dll GetConsoleWindow() Function. Then i pass that to the GetWindowLongA() Function of the User32.dll library which should return the python equivalent of HINSTANCE in windows.h header of C which should be an int. but all i get is 0 which means it has failed.
The code i currently have is:
windows = windll.LoadLibrary("User32.dll")
kernel = windll.LoadLibrary("Kernel32.dll")
consoleHandle = kernel.GetConsoleWindow()
print(f"Console HWND : {consoleHandle}")
instanceHandle: ctypes.wintypes.HINSTANCE = windows.GetWindowLongA(consoleHandle, c_int(-6))
print(f"Console HINSTANCE : {instanceHandle}")
print(f"LAST FUNCTION ERROR : {kernel.GetLastError()}")
OUTPUT :
Console HWND : 198610
Console HINSTANCE : 0
LAST FUNCTION ERROR : 1413
now error 1413 is ERROR_INVALID_INDEX (based on System error codes) which is probably caused cause i passed c_int(-6) as the int nIndex argument which must represent the GWL_HINSTANCE macro defined in windows.h (based on this windows doc) but it doesnt work.
What should i do to fix it and why doesnt it work?
Console Windows are not the same as GUI Windows. GetActiveWindow() is what you want, and needs to be run for a GUI Python IDE, not a console window.
Assuming 64-bit Windows and Python, you also need GetWindowLongPtrA() (or W) to retrieve handles.
To ensure you retrieve the last error cause by a Windows API failure using ctypes, use the use_last_error=True parameter and call ctypes.get_last_error() to retrieve it. The error code is only valid after the specific Windows call that failed, ctypes will capture that with this method. Otherwise, you don't know what Windows APIs might be called by the Python implementation between the ctypes API call to the function that failed and the ctypes GetLastError() API call. I got 1400 (invalid window handle) when calling GetWindowLongPtrA() with a console handle.
It's also good practice to fully specify .argtypes and .restype, esp. for 64-bit Windows as the default return type is c_int (32-bit) and handles are 64-bit in that architecture.
Below works for a 64-bit Python IDE:
import ctypes as ct
from ctypes import wintypes as w
GWLP_HINSTANCE = -6
# LONG_PTR isn't defined by wintypes.
# LPARAM is long on 32-bit, longlong on 64-bit,
# which matches LONG_PTR type.
LONG_PTR = w.LPARAM
u32 = ct.WinDLL('user32', use_last_error=True)
GetWindowLongPtrA = u32.GetWindowLongPtrA
GetWindowLongPtrA.argtypes = w.HWND, ct.c_int
GetWindowLongPtrA.restype = LONG_PTR
GetActiveWindow = u32.GetActiveWindow
GetActiveWindow.argtypes = ()
GetActiveWindow.restype = w.HWND
hwnd = GetActiveWindow()
print(f'hwnd = {hwnd:#x}')
instanceHandle = GetWindowLongPtrA(hwnd, GWLP_HINSTANCE)
print(f'instanceHandle = {instanceHandle:#x}')
Output:
hwnd = 0xd044c
instanceHandle = 0x7ff700250000
I am studying the book "Python Grey Hat", this is one of my functions, I have been looking for this problem for a long time or not solved.
def func_resolve(self,dll,function):
GetModuleHandle = kernel32.GetModuleHandleA
GetModuleHandle.argtypes = [c_char_p]
GetModuleHandle.restype = c_void_p
handle = GetModuleHandle(dll)
print(handle)
GetProcAddress = kernel32.GetProcAddress
GetProcAddress.argtypes = [c_void_p,c_char_p]
GetProcAddress.restype = c_void_p
address = GetProcAddress(handle,function)
print(address)
My output handle value is 140707194077184, the address value is 140707194386736, I use OllyDbg to view the address of the wprintf function in msvcrt.dll is 0x73D178A0, but the value of address is converted to hexadecimal is also much larger than 0x73D178A0, hope Can someone help me, thank you
Nevermind the answer to my comment, I've found the cause. From OllyDbg (emphasis is mine):
OllyDbg is a 32-bit assembler level analysing debugger for Microsoft® Windows®.
That means that it can only load (work with) 32 bit processes (and / or .dlls) only. wprintf address confirms it (0x73D178A0 is 32 bit as it has (at most) 8 hex digits).
On the other hand, in Python, you get (much) larger values for pointers or addresses (e.g. handler = 140707194077184 (0x7FF8F256B930)) which don't fit in the 32 bit range, so it's 64 bit. For more details on how to get running Python architecture, check [SO]: How do I determine if my python shell is executing in 32bit or 64bit mode on OS X? (#CristiFati's answer) (even if the question is for OSX, Win is covered as well).
So, what's the catch? It's [MS.Docs]: File System Redirector that confused you regarding msvcr(t###).dll location:
Python (64 bit) loaded it from "%windir%\System32"
OllyDbg (32 bit) made you think that it loaded it from the same location (for backward compatibility reasons), when in fact it loaded it from "%windir%\SysWOW64"
Using a tool built for both 32 bit and 64 bit that you can launch in parallel (I use Dependency Walker), you can see the differences.
The return value is a Windows handle. The value is big because you are using 64-bit Python. The value doesn't matter as long as you've declared your ctypes properly. This code will work Python 2 or 3, 32- or 64-bit, and uses ctypes.wintypes for predefined Windows types:
from __future__ import print_function
import sys
from ctypes import *
from ctypes import wintypes as w
print(sys.version)
kernel32 = WinDLL('kernel32')
GetModuleHandle = kernel32.GetModuleHandleW
GetModuleHandle.argtypes = [w.LPCWSTR]
GetModuleHandle.restype = w.HMODULE
GetProcAddress = kernel32.GetProcAddress
GetProcAddress.argtypes = [w.HMODULE,w.LPCSTR]
GetProcAddress.restype = c_void_p # FARPROC isn't defined in wintypes, but a generic pointer works.
handle = GetModuleHandle(u'user32')
address = GetProcAddress(handle,b'MessageBeep')
print(hex(address))
MessageBeep = WINFUNCTYPE(w.BOOL,w.UINT)(address)
MessageBeep(0)
Output with two Pythons I have installed (beep is played each time):
C:\>py -2 test.py
2.7.14 (v2.7.14:84471935ed, Sep 16 2017, 20:19:30) [MSC v.1500 32 bit (Intel)]
0x756e56d0
C:\>py -3 test.py
3.7.0 (v3.7.0:1bf9cc5093, Jun 27 2018, 04:59:51) [MSC v.1914 64 bit (AMD64)]
0x7fff6ca29a40
When I call GetProcAddress() by win32api, I get the handle successfully but ctypes didn't.
The codes are:
from ctypes import windll
import win32api
KERNEL32 = windll.kernel32
h_kernel32 = KERNEL32.GetModuleHandleW('kernel32.dll')
print(hex(h_kernel32))
h_loadlib1=win32api.GetProcAddress(h_kernel32,'LoadLibraryW')
print(hex(h_loadlib1))
if not h_loadlib1:
print("NtCreateThreadEx Failed:",win32api.GetLastError())
h_loadlib2 = KERNEL32.GetProcAddress(h_kernel32,'LoadLibraryW')
print(hex(h_loadlib2))
if not h_loadlib2:
print("NtCreateThreadEx Failed:",win32api.GetLastError())
And the outputs:
0x77250000
0x77266f80
0x0
NtCreateThreadEx Failed: 127
SYSTEM INFO:
windows7 64, python 3.43
You need to use a char string rather than the default Unicode string provided by python 3.x, as hinted by the GetProcAddress documentation (the 2nd parameter is a LPCSTR, not LPCTSTR or LPCWSTR):
h_loadlib2 = KERNEL32.GetProcAddress(h_kernel32,'LoadLibraryW'.encode(encoding='ascii'))
Alternatively, you can pass a byte:
h_loadlib2 = KERNEL32.GetProcAddress(h_kernel32, b'LoadLibraryW')
Note: The above code won't work on a python 64-bit interpreter (the most significant 32-bit of the 64-bit module handle are zeroed). In this case you'll need to use argtypes and restype as explained in the tutorial (for example by defining a 64-bit HMODULE type).
I'd need help trying to figure out this thing.
Yesterday I installed the beta of Spyder 2.3 to work with Anaconda Python 3.3, on my Win7 64-bit laptop.
Opening an internal console window, I noticed an error that triggered every sec,
Traceback (most recent call last):
File "C:\Miniconda3\lib\site-packages\spyderlib\widgets\status.py", line 80, in update_label
self.label.setText('%d %%' % self.get_value())
File "C:\Miniconda3\lib\site-packages\spyderlib\widgets\status.py", line 93, in get_value
return memory_usage()
File "C:\Miniconda3\lib\site-packages\spyderlib\utils\system.py", line 20, in windows_memory_usage
class MemoryStatus(wintypes.Structure):
AttributeError: 'module' object has no attribute 'Structure'
This appears to come from the fact that system.py tries to use "wintype.Structure" when psutil is not installed, and I can see no such thing as a Structure class (or module) in wintypes.py... Even c_uint64 is not in wintypes.
I solved the issue the easy way - I just installed psutil and was done. But the fact is that several scripts appear to use wintypes.Structure (see Google). And I really don't see it... so what am I missing?
Thanks!
I'm editing my answer.
The problem here appears to be that the Python 2.7 version of wintypes.py (from the ctypes 1.1.0 package) starts with
from ctypes import *
while wintypes.py from the Python 3.3 ctypes 1.1.0 package uses:
import ctypes
So basically wintypes.Structure, .c_uint64, .sizeof and .byref are all from ctypes. They don't get altered in wintypes - at least not up to this 1.1.0 version. So this change to Spyder(2.3.0beta3)'s status.py should make it work with no errors both for Python 2.7 and Python 3.3:
def windows_memory_usage():
"""Return physical memory usage (float)
Works on Windows platforms only"""
from ctypes import windll, Structure, c_uint64, sizeof, byref
from ctypes.wintypes import DWORD
class MemoryStatus(Structure):
_fields_ = [('dwLength', DWORD),
('dwMemoryLoad',DWORD),
('ullTotalPhys', c_uint64),
('ullAvailPhys', c_uint64),
('ullTotalPageFile', c_uint64),
('ullAvailPageFile', c_uint64),
('ullTotalVirtual', c_uint64),
('ullAvailVirtual', c_uint64),
('ullAvailExtendedVirtual', c_uint64),]
memorystatus = MemoryStatus()
# MSDN documetation states that dwLength must be set to MemoryStatus
# size before calling GlobalMemoryStatusEx
# http://msdn.microsoft.com/en-us/library/aa366770(v=vs.85)
memorystatus.dwLength = sizeof(memorystatus)
windll.kernel32.GlobalMemoryStatusEx(byref(memorystatus))
return float(memorystatus.dwMemoryLoad)
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.