Search code examples
c++winapipropertysheet

Can't use PropSheet to create a centered property sheet dialog


I am creating a modeless property sheet using the following settings:

   PROPSHEETHEADER pshdr = { 0 };

   pshdr.dwSize = sizeof(PROPSHEETHEADER);
   pshdr.dwFlags = PSH_NOAPPLYNOW | PSH_PROPSHEETPAGE |
                   PSH_MODELESS | PSH_USECALLBACK;
   pshdr.pfnCallback = PropSheetProc;
   pshdr.hwndParent = mGlobalState->trayWin;
   pshdr.pszCaption = L"My Settings";
   pshdr.nPages = mPages.size();
   pshdr.ppsp = mWinPages;

In PropSheetProc, I catch the PSCB_PRECREATE message and modify the dialog template so that it gets the DS_CENTER style:

static int CALLBACK
PropSheetProc(HWND hwndDlg,  // IN
              UINT uMsg,     // IN
              LPARAM lParam) // IN
{
   // Before the dialog is created, bless it with the DS_CENTER style.
   if (uMsg == PSCB_PRECREATE) {
      DLGTEMPLATE *dlgTemplate = (DLGTEMPLATE *)lParam;
      _ASSERT(dlgTemplate);

      dlgTemplate->style |= DS_CENTER;
   }

   return 0;
}

However this doesn't succeed in centering the dialog. I tried to catch PSCB_INITIALIZED instead and call a CenterWindow method on the hwnd passed to the PropSheetProc:

void
CenterWindow(HWND hwndWindow) // IN
{
   int nX, nY, nScreenWidth, nScreenHeight;
   RECT rectWindow;

   nScreenWidth = GetSystemMetrics(SM_CXSCREEN);
   nScreenHeight = GetSystemMetrics(SM_CYSCREEN);

   GetWindowRect(hwndWindow, &rectWindow);

   nX = (nScreenWidth - (rectWindow.right - rectWindow.left)) / 2;
   nY = (nScreenHeight - (rectWindow.bottom - rectWindow.top)) / 2;

   SetWindowPos(hwndWindow, 0, nX, nY, 0, 0,
                SWP_NOZORDER | SWP_NOSIZE);
}

But that doesn't work either!

Finally, I moved the CenterWindow call to directly after the PropSheet call:

   mHwnd = (HWND)PropertySheet(&pshdr);
   CenterWindow(mHwnd);
   return mHwnd != NULL;

And this DOES work, though on a heavily loaded system, the dialog flashes from its initial position over to its final position, which is suboptimal.

Using the PropSheetProc to modify the DLGTEMPLATE structure seems intuitive. Actually, I can apply other window styles. But DS_CENTER seems to have no effect. So what am I doing wrong? There's many ways I can work around this brokennness but why is it broken in the first place?


Solution

  • Overload the InitialUpdate() of the CPropertySheet, and place the CenterWindow() call there. This happens before the window is drawn on the screen, but after it is created, so it's hwnd will be valid. There is nothing broken. The dialog has to be Created to have a valid HWND. Alternatively, if your working with the resource editor you can set it's property to centered, and it will achieve the same result. Why are you overloading the WinProc for the propertysheet? The whole reason MFC uses message maps was to eliminate the need to even touch WinProc's.

    If your using raw win api in a SDK style application ::

    Handle WM_CREATE in the WinProc of the property sheet. The LPCREATE struct in the LPARAM will contain a valid HWND from the create call. Just make sure you pass the proper parameters back to WndProcDefault() otherwise window creation will fail.