python-2.7alertctypeswindows-7-x64

How to include image in Message Box using ctypes in python


I am making an message box in python 2.7 on windows 7 64 bit machine. It will rise to show error message to user in message box.

import ctypes

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

This shows the required message box. But in taskbar the default image of python appears which is annoying. So, how to include image in taskbar. Or just not to show default image of python in taskbar.

enter image description here

enter image description here


Solution

  • This is because you don't have a window, None, and then the system will assign a default icon.

    You can install a hook using SetWindowsHookEx and then alter MessageBox icon. For example let's use 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")
    

    Most the code is just functions prototype. Now you can call MyMessageBox as:

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

    result:

    enter image description here

    UPDATE: it will center the button now by enumerating through the message box window's chillers and looking for a button, then center it. I haven't test it much but it looks OK so far.