WindowsError:exception:使用winAPI写入0xC0000000的访问冲突

时间:2013-09-06 22:08:01

标签: python winapi ctypes

我正在尝试创建一个窗口,我可以在消息循环中显示图形但是我收到“WindowsError:exception:access violation writing 0xC0000000”错误。据我所知,这里提到的其他问题是由于该方法试图写错了地方。

代码是对here的匹配,但消息循环函数保持不变;我甚至尝试过使用PeekMessage和其他各种方法。

from ctypes import *
import win32con

_WNDPROC = WINFUNCTYPE(c_long, c_int, c_uint, c_int, c_int)

_NULL = c_int(win32con.NULL)
_user32 = windll.user32
_gdi32 = windll.gdi32

def _ErrorIfZero(handle):
    if handle == 0:
        raise WinError()
    else:
        return handle

CreateWindowEx = _user32.CreateWindowExW
CreateWindowEx.argtypes = [c_int,
                           c_wchar_p,
                           c_wchar_p,
                           c_int,
                           c_int,
                           c_int,
                           c_int,
                           c_int,
                           c_int,
                           c_int,
                           c_int,
                           c_int]
CreateWindowEx.restype = _ErrorIfZero

class _WNDCLASS(Structure):
    _fields_ = [('style', c_uint),
                ('lpfnWndProc', _WNDPROC),
                ('cbClsExtra', c_int),
                ('cbWndExtra', c_int),
                ('hInstance', c_int),
                ('hIcon', c_int),
                ('hCursor', c_int),
                ('hbrBackground', c_int),
                ('lpszMenuName', c_wchar_p),
                ('lpszClassName', c_wchar_p)]

    def __init__(self,
                 wndProc,
                 style=win32con.CS_HREDRAW | win32con.CS_VREDRAW,
                 clsExtra=0,
                 wndExtra=0,
                 menuName=None,
                 className=u"PythonWin32",
                 instance=None,
                 icon=None,
                 cursor=None,
                 background=None,
                 ):

        if not instance:
            instance = windll.kernel32.GetModuleHandleW(c_int(win32con.NULL))
        if not icon:
            icon = _user32.LoadIconW(c_int(win32con.NULL),
                                     c_int(win32con.IDI_APPLICATION))
        if not cursor:
            cursor = _user32.LoadCursorW(c_int(win32con.NULL),
                                         c_int(win32con.IDC_ARROW))
        if not background:
            background = windll.gdi32.GetStockObject(c_int(win32con.WHITE_BRUSH))

        self.lpfnWndProc=wndProc
        self.style=style
        self.cbClsExtra=clsExtra
        self.cbWndExtra=wndExtra
        self.hInstance=instance
        self.hIcon=icon
        self.hCursor=cursor
        self.hbrBackground=background
        self.lpszMenuName=menuName
        self.lpszClassName=className

class _RECT(Structure):
    _fields_ = [('left', c_long),
                ('top', c_long),
                ('right', c_long),
                ('bottom', c_long)]
    def __init__(self, left=0, top=0, right=0, bottom=0 ):
        self.left = left
        self.top = top
        self.right = right
        self.bottom = bottom

class _PAINTSTRUCT(Structure):
    _fields_ = [('hdc', c_int),
                ('fErase', c_int),
                ('rcPaint', _RECT),
                ('fRestore', c_int),
                ('fIncUpdate', c_int),
                ('rgbReserved', c_wchar * 32)]

class _POINT(Structure):
    _fields_ = [('x', c_long),
                ('y', c_long)]
    def __init__( self, x=0, y=0 ):
        self.x = x
        self.y = y

class _MSG(Structure):
    _fields_ = [('hwnd', c_int),
                ('message', c_uint),
                ('wParam', c_int),
                ('lParam', c_int),
                ('time', c_int),
                ('pt', _POINT)]

def RunMessageLoop():
    """Runs the loop to get messages from"""
    msg = _MSG()
    pMsg = pointer(msg)

    while _user32.GetMessageW(pMsg, _NULL, 0, 0):
        _user32.TranslateMessage(pMsg)
        _user32.DispatchMessageW(pMsg)

    return msg.wParam

## Lifted shamelessly from WCK (effbot)'s wckTkinter.bind
def EventHandler(message):
    """Decorator for event handlers"""
    def decorator(func):
        func.win32message = message
        return func
    return decorator

class Window(object):
    """The application window"""

    def __init__(self, title, updateHandler):

        #Store update function
        self.updateHandler = updateHandler

        #Register event handlers
        self._event_handlers = {}
        for key in dir(self):
            method = getattr(self, key)
            if hasattr(method, "win32message") and callable(method):
                self._event_handlers[method.win32message] = method

        #Register window class
        wndclass = _WNDCLASS(_WNDPROC(self.WndProc))
        wndclass.lpszClassName = u"HelloWindow"

        if not _user32.RegisterClassW(byref(wndclass)):
            raise WinError()

        #Now create the _Window

        self.Create( className=wndclass.lpszClassName,
                instance=wndclass.hInstance,
                windowName=title)

        #Show Window
        self.Show(win32con.SW_SHOWNORMAL)
        self.Update()

    def GetSize(self):
        rect = _RECT()
        _user32.GetClientRect(self.hwnd, byref(rect))
        return rect.width, rect.height

    def Create(self,
            exStyle=0 ,        #  DWORD dwExStyle
            className=u"WndClass",
            windowName=u"Window",
            style=win32con.WS_OVERLAPPEDWINDOW,
            x=win32con.CW_USEDEFAULT,
            y=win32con.CW_USEDEFAULT,
            width=win32con.CW_USEDEFAULT,
            height=win32con.CW_USEDEFAULT,
            parent=_NULL,
            menu=_NULL,
            instance=_NULL,
            lparam=_NULL,
            ):

        self.hwnd = CreateWindowEx(exStyle,
                              className,
                              windowName,
                              style,
                              x,
                              y,
                              width,
                              height,
                              parent,
                              menu,
                              instance,
                              lparam)
        return self.hwnd

    def Show(self, flag):
        return _user32.ShowWindow(self.hwnd, flag)

    def Update(self):
        if not _user32.UpdateWindow(self.hwnd):
            raise WinError()

    def WndProc(self, hwnd, message, wParam, lParam):

        event_handler = self._event_handlers.get(message, None)
        if event_handler:
            return event_handler(message, wParam, lParam)
        return _user32.DefWindowProcW(c_int(hwnd),
                                      c_int(message),
                                      c_int(wParam),
                                      c_int(lParam))


    """Yipee Events :'( """

    @EventHandler(win32con.WM_PAINT)
    def OnPaint(self, message, wParam, lParam):
        """Window is updating so update graphics inside"""
        ps = _PAINTSTRUCT()
        hdc = _user32.BeginPaint(c_int(self.hwnd), byref(ps))

        self.updateHandler(hdc)

        _user32.EndPaint(c_int(self.hwnd), byref(ps))
        return 0

    @EventHandler(win32con.WM_DESTROY)
    def OnDestroy(self, message, wParam, lParam):
        """Quit app when window is destroyed"""
        _user32.PostQuitMessage(0)
        return 0

class DrawMethods:
    @staticmethod
    def DrawLine(handle, x1, y1, x2, y2):
        """Draw a line between points"""
        _gdi32.MoveToEx(c_int(handle),
                        x1,
                        y1,
                        NULL)
        _gdi32.LineTo(c_int(hdc),
                      x2,
                      y2)

    @staticmethod
    def DrawRect(handle, x, y, width, height):
        """Draw a rect at x and y of width and height"""
        _gdi32.Rectangle(c_int(handle),
                         x,
                         y,
                         x+width,
                         y+height)

    #@staticmethod
    #def DrawCircle(x, y, radius):

    @staticmethod
    def DrawText(handle, x, y, width, height, text):
        """Draw text at the specified coordinates"""                                    # UPDATE!!!!
        rect = _RECT(x, y, width, height)
        flags = win32con.DT_SINGLELINE|win32con.DT_CENTER|win32con.DT_VCENTER
        _user32.DrawTextW(c_int(handle),
                          text,
                          c_int(-1),
                          byref(rect),
                          flags)


class Test:
    """Create window and start message loop"""

    def __init__(self):
        #So create a window (yes this is multi window compatible I think) titled "TestWindow!" that calls the Update method to draw everything
        self.window = Window("Test Window!", self.Update)

    def Update(self, handle):
        """This is called when the window updates and you can then use the drawing functions available in Renderer.DrawMethods"""
        #Renderer omitted as in the same file
        DrawMethods.DrawText( handle, 0, 0, 500, 500, u"Helllloooo!!! Testy testy test test :D" )

t= Test()
RunMessageLoop()

我希望有人可以帮助我,代码设计适用于任何Windows机器,所以你应该能够运行它(已经说过win32con导入可能是pywin32包的一部分......)

谢谢,

杰米:)

1 个答案:

答案 0 :(得分:0)

嗯,我让它工作......似乎对RunMessageLoop()的调用需要在Window类中(在init例程的底部)。