1

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

1 Answer 1

4

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.

Sign up to request clarification or add additional context in comments.

6 Comments

thanks for the answer. I doubt, how to use this code as a function, so that many time it is callable with different text messages.
@winterfall OK, I modified the code and wrapped these functions inside a single MyMessageBox function.
thanks a lot, I really appreciate your help. Can this ok button be moved to center. I added the screenshot of alert box where ok button comes at end. Can it moved to center
@winterfall There is no direct way to do this (it depends on the system and the theme I guess). I modified the code so it centers the button, it works well on Windows 7 but I haven't test it on other versions.
@winterfall Yes I use 32bit Windows 7.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.