【问题标题】:How to include image in Message Box using ctypes in python如何在 python 中使用 ctypes 在消息框中包含图像
【发布时间】:2014-01-08 12:00:18
【问题描述】:

我正在 windows 7 64 位机器上的 python 2.7 中制作一个消息框。它将在消息框中向用户显示错误消息。

import ctypes

msgbox = ctypes.windll.user32.MessageBoxA
ret = msgbox(None, 'message', 'title', 0)
print ret

这会显示所需的消息框。但是在任务栏中会出现python的默认图像,这很烦人。那么,如何在任务栏中包含图像。或者只是不在任务栏中显示 python 的默认图像

【问题讨论】:

    标签: python-2.7 alert ctypes windows-7-x64


    【解决方案1】:

    这是因为你没有窗口,None,然后系统会分配一个默认图标。

    您可以使用SetWindowsHookEx 安装挂钩,然后更改MessageBox 图标。例如让我们使用StackOverflow icon

    #-*- coding: utf-8 -*-
    #!python
    
    
    from ctypes import *
    from ctypes.wintypes import *
    #recommended
    #from ctypes import windll, c_int, c_int64, c_long, WINFUNCTYPE, POINTER, cast, c_wchar, byref
    #from ctypes.wintypes import HMODULE, LPCWSTR, HANDLE, HINSTANCE, UINT, HWND, WPARAM, LPARAM, HHOOK, DWORD, BOOL, RECT, POINT
    from os import path
    import platform
    
    #################################################################
    
    RelPath = lambda file : path.join(path.dirname(path.abspath(__file__)), file)
    
    #################################################################
    
    GetModuleHandle = windll.kernel32.GetModuleHandleW
    GetModuleHandle.restype = HMODULE
    GetModuleHandle.argtypes = [LPCWSTR]
    
    #################################################################
    
    IMAGE_ICON = 1
    LR_LOADFROMFILE = 0x00000010
    LR_CREATEDIBSECTION = 0x00002000
    
    LoadImage = windll.user32.LoadImageW
    LoadImage.restype = HANDLE
    LoadImage.argtypes = [HINSTANCE, LPCWSTR, UINT, c_int, c_int, UINT]
    
    #################################################################
    
    LRESULT = c_int64 if platform.architecture()[0] == "64bit" else c_long
    
    SendMessage = windll.user32.SendMessageW
    SendMessage.restype = LRESULT
    SendMessage.argtypes = [HWND, UINT, WPARAM, LPARAM]
    
    #################################################################
    
    MB_OK = 0x00000000L 
    
    MessageBox = windll.user32.MessageBoxW
    MessageBox.restype  = c_int
    MessageBox.argtypes = [HWND, LPCWSTR, LPCWSTR, UINT]
    
    #################################################################
    
    WH_CBT = 5
    HCBT_ACTIVATE = 5
    HOOKPROC = WINFUNCTYPE(LRESULT, c_int, WPARAM, LPARAM)
    
    SetWindowsHookEx = windll.user32.SetWindowsHookExW
    SetWindowsHookEx.restype = HHOOK
    SetWindowsHookEx.argtypes = [c_int, HOOKPROC, HINSTANCE, DWORD]
    
    #################################################################
    
    CallNextHookEx = windll.user32.CallNextHookEx
    CallNextHookEx.restype = LRESULT
    CallNextHookEx.argtypes = [HHOOK, c_int, WPARAM, LPARAM]
    
    #################################################################
    
    GetCurrentThreadId = windll.kernel32.GetCurrentThreadId
    GetCurrentThreadId.restype = DWORD
    GetCurrentThreadId.argtypes = None
    
    #################################################################
    
    UnhookWindowsHookEx = windll.user32.UnhookWindowsHookEx
    UnhookWindowsHookEx.restype = BOOL
    UnhookWindowsHookEx.argtypes = [HHOOK]
    
    #################################################################
    # code starts here
    
    def MyMessageBox(hWnd, lpText, lpCaption, uType, lpIcon):
      hHook = HHOOK(None)
    
      #**********************************************************#
        # center button code
      def EnumChildProc(hwnd, lParam):
        ClassName = (c_wchar * 7)()
        if GetClassName(hwnd, ClassName, 7) > 0:
          if ClassName.value.lower() == "button":
            wrect = RECT()
            GetClientRect(lParam, byref(wrect))
            brect = RECT()
            GetClientRect(hwnd, byref(brect))
            bpoint = RECT()
            MapWindowPoints(hwnd, lParam, cast(byref(bpoint), POINTER(POINT)), 2)
            MoveWindow(hwnd,
                      ((wrect.right - wrect.left) - (brect.right - brect.left)) // 2,
                      bpoint.top,
                      brect.right - brect.left,
                      brect.bottom - brect.top,
                      True)
            return False
        return True
        
      WNDENUMPROC = WINFUNCTYPE(BOOL, HWND, LPARAM)
    
      EnumChildWindows = windll.user32.EnumChildWindows
      EnumChildWindows.restype = BOOL
      EnumChildWindows.argtypes = [HWND, WNDENUMPROC, LPARAM]
    
      GetClassName = windll.user32.GetClassNameW
      GetClassName.restype = HWND
      GetClassName.argtypes = [HWND, LPCWSTR, c_int]
    
      GetClientRect = windll.user32.GetClientRect 
      GetClientRect.restype = BOOL
      GetClientRect.argtypes = [HWND, POINTER(RECT)]
      
      MoveWindow = windll.user32.MoveWindow
      MoveWindow.restype = BOOL
      MoveWindow.argtypes = [HWND, c_int, c_int, c_int, c_int, BOOL]
      
      MapWindowPoints = windll.user32.MapWindowPoints
      MapWindowPoints.restype = c_int
      MapWindowPoints.argtypes = [HWND, HWND, POINTER(POINT), UINT]
        
      #**********************************************************#
    
      def AlterIcon(_hWnd, lpszIcon):
    
        WM_SETICON = 0x0080
        ICON_BIG = 1
    
        hModel = GetModuleHandle(None)
        hIcon = LoadImage(hModel,
                          RelPath(lpszIcon),
                          IMAGE_ICON,
                          0, 0,
                          LR_LOADFROMFILE | LR_CREATEDIBSECTION)
    
    
        SendMessage(_hWnd, WM_SETICON, ICON_BIG, hIcon)
    
      def CBTProc(nCode, wParam, lParam):
        if nCode == HCBT_ACTIVATE:
          _hWnd = cast(wParam, HWND)
          AlterIcon(_hWnd, lpIcon)
          #**********************************************************#
          pEnumChildProc = WNDENUMPROC(EnumChildProc)
          EnumChildWindows(_hWnd, pEnumChildProc, _hWnd.value)
          #**********************************************************#
    
        CallNextHookEx(hHook, nCode, wParam, lParam)
        return 0
    
      # WARNING: don't pass HOOKPROC(CBTProc) directly to SetWindowsHookEx
      pCBTProc = HOOKPROC(CBTProc)
    
      hHook = SetWindowsHookEx(WH_CBT, pCBTProc, None, GetCurrentThreadId())
    
      MessageBox(hWnd, lpText, lpCaption, uType)
    
      UnhookWindowsHookEx(hHook)
    
    # example of usage
    MyMessageBox(None, "Hello world!", "Title", MB_OK, "favicon.ico")
    

    大部分代码只是函数原型。现在您可以拨打MyMessageBox 为:

    MyMessageBox(None, "Hello world!", "Title", MB_OK, "favicon.ico")
    

    结果:

    更新:它现在将通过枚举消息框窗口的冷却器并寻找一个按钮,然后将其居中来居中按钮。我没有对其进行太多测试,但到目前为止看起来还不错。

    【讨论】:

    • 感谢您的回答。我怀疑,如何将此代码用作函数,以便多次使用不同的文本消息调用它。
    • @winterfall 好的,我修改了代码并将这些函数包装在一个 MyMessageBox 函数中。
    • 非常感谢,非常感谢您的帮助。这个确定按钮可以移到中心吗?我添加了警报框的屏幕截图,其中确定按钮位于末尾。它可以移动到中心
    • @winterfall 没有直接的方法可以做到这一点(这取决于系统和我猜的主题)。我修改了代码,使按钮居中,它在 Windows 7 上运行良好,但我还没有在其他版本上测试过。
    • @winterfall 是的,我使用的是 32 位 Windows 7。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-08
    • 2020-05-12
    • 2016-11-01
    • 1970-01-01
    • 2013-07-19
    • 2017-06-03
    • 1970-01-01
    相关资源
    最近更新 更多