Centring TaskDialog on Parent's client area.

Windows specific questions.
Post Reply
deltarho[1859]
Posts: 4292
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Centring TaskDialog on Parent's client area.

Post by deltarho[1859] »

I have included TaskDialog centring in my latest project so knocked out a snippet if anyone would like to use it.

I have used a simple rc - just ' 1 24 "Theme.xml" ' - I'll let you supply the xml.

I am also using José Roca's WinFBX - you may have your own way of GUI programming.

The code is multi-monitor intelligent. If you move the parent to another monitor the TaskDialog will go with it.

Here are a few screenshots. It is OK with 64 bit - after some minor tweaks like Casting 'wParam' as a Uinteger.
Image

Example usage.

Code: Select all

#define UNICODE
#Define _WIN32_WINNT &h0602
#INCLUDE ONCE "Afx/CWindow.inc"
USING Afx

Const IDC_Button = 1000

' **********************************************
' For TaskDialog
Dim shared hHookTaskDialog As HHOOK
Dim shared hTaskDialogParent As hWnd
' **********************************************

DECLARE FUNCTION WinMain (BYVAL hInstance AS HINSTANCE, _
                          BYVAL hPrevInstance AS HINSTANCE, _
                          BYVAL szCmdLine AS ZSTRING PTR, _
                          BYVAL nCmdShow AS LONG) AS LONG

END WinMain(GetModuleHandleW(NULL), NULL, COMMAND(), SW_NORMAL)

DECLARE FUNCTION WndProc (BYVAL hwnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT
Declare Function CentredTaskDialog_CB( As Long, As Long, As Long) As Long
Declare function CentredTaskDialog( As HWND, As HINSTANCE, As PCWSTR, As PCWSTR, As PCWSTR, As TASKDIALOG_COMMON_BUTTON_FLAGS, _
As PCWSTR, As Long Ptr) As HRESULT

FUNCTION WinMain (BYVAL hInstance AS HINSTANCE, _
                  BYVAL hPrevInstance AS HINSTANCE, _
                  BYVAL szCmdLine AS ZSTRING PTR, _
                  BYVAL nCmdShow AS LONG) AS LONG

   AfxSetProcessDPIAware

   DIM pWindow AS CWindow
   pWindow.Create(NULL, "Posher than messagebox", @WndProc)
   pWindow.SetClientSize(366, 150)
   pWindow.Center
   pWindow.AddControl("Button", , IDC_Button, "Message", 10, 10, 75, 23)
   FUNCTION = pWindow.DoEvents(nCmdShow)

END FUNCTION

FUNCTION WndProc (BYVAL hwnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT

  SELECT CASE uMsg

    CASE WM_COMMAND
      SELECT CASE GET_WM_COMMAND_ID(wParam, lParam)
        CASE IDCANCEL
          IF GET_WM_COMMAND_CMD(wParam, lParam) = BN_CLICKED THEN
            SendMessageW hwnd, WM_CLOSE, 0, 0
            EXIT FUNCTION
          END IF
        case IDC_Button
          Dim pnButton As Long
          CentredTaskDialog( Hwnd, 0, "Centred TaskDialog", "I am the centre of attention", _
          "... admittedly not for long <smile>", TDCBF_OK_BUTTON, TD_INFORMATION_ICON, @pnButton )
      END SELECT

    CASE WM_SIZE
      IF wParam <> SIZE_MINIMIZED THEN
        DIM pWindow AS CWindow PTR = AfxCWindowPtr(hwnd)
        IF pWindow THEN pWindow->MoveWindow GetDlgItem(hwnd, IDCANCEL), _
          pWindow->ClientWidth - 120, pWindow->ClientHeight - 50, 75, 23, CTRUE
      END IF

    CASE WM_DESTROY
      PostQuitMessage(0)
      EXIT FUNCTION

  END SELECT

  FUNCTION = DefWindowProcW(hwnd, uMsg, wParam, lParam)

END FUNCTION

Function CentredTaskDialog_CB(ByVal lMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Dim hMonitor As HMONITOR
Dim MonInfo As MONITORINFO
Dim as Long w, h, x, y, z
Dim As RECT rc1, rc2, rc3

  If lMsg = HCBT_ACTIVATE Then
 
    UnhookWindowsHookEx hHookTaskDialog
 
    If hTaskDialogParent <> HWND_Desktop Then
 
      GetWindowRect hTaskDialogParent, @rc1
      GetWindowRect cast( Hwnd, Cast( Uinteger, wParam ) ), @rc2
      GetClientRect hTaskDialogParent, @rc3
      hMonitor = MonitorFromWindow( hTaskDialogParent, MONITOR_DEFAULTTONEAREST )
      MonInfo.cbSize = SizeOf( MonInfo )
      GetMonitorInfo cast(hMonitor, hMonitor ), Cast( LPMONITORINFO, @MonInfo )
 
      If (MonInfo.rcWork.Left = MonInfo.rcMonitor.Left) And (MonInfo.rcWork.Right = MonInfo.rcMonitor.Right) Then
        w = (MonInfo.rcMonitor.Right - MonInfo.rcMonitor.Left)*IIf(rc2.Left > 0, 1, -1) - 2*rc2.Left
      Else
        w = MonInfo.rcWork.Right + MonInfo.rcWork.Left - 2*rc2.Left
      End If
 
      If (MonInfo.rcWork.Top = MonInfo.rcMonitor.Top) And (MonInfo.rcWork.Bottom = MonInfo.rcMonitor.Bottom) Then
        h = (MonInfo.rcMonitor.Bottom - MonInfo.rcMonitor.Top)*IIf(rc2.Top > 0, 1, -1) - 2*rc2.Top
      Else
        h = MonInfo.rcWork.Bottom + MonInfo.rcWork.Top - 2*rc2.Top
      End If
      
      z = rc1.Bottom - rc1.Top -( rc3.Bottom - rc3.Top )
      x = (rc1.Left + rc1.Right - w) / 2
      y = (rc1.Top + rc1.Bottom + 2*z - h) / 2
 
      SetWindowPos Cast( hWnd, Cast( Uinteger, wParam ) ), HWND_TOPMOST, x+4, y-1, 0, 0, SWP_NOSIZE
      
      Return 0
 
    End If
 
  End If
 
End Function

function CentredTaskDialog( hwndOwner as HWND, hInstance as HINSTANCE, pszWindowTitle as PCWSTR, _
pszMainInstruction as PCWSTR, pszContent as PCWSTR, dwCommonButtons as TASKDIALOG_COMMON_BUTTON_FLAGS, _
pszIcon as PCWSTR,  pnButton as Long Ptr) as HRESULT
 
  hTaskDialogParent = hwndOwner
  hHookTaskDialog = SetWindowsHookEx(WH_CBT, Cast( HOOKPROC, procptr(CentredTaskDialog_CB) ), GetModuleHandle(ByVal 0), GetCurrentThreadId)
 
  Function = TaskDialog(hWndOwner, hInstance, pszWindowTitle, pszMainInstruction, pszContent, dwCommonButtons, pszIcon, pnButton)
 
End Function
Post Reply