views:

263

answers:

3

The PropertySheet API lets you define a PropSheetProc that can (on Windows XP and above) receive messages when the OK or Apply button is pressed. This lets you do processing when one of these buttons is clicked.

However, this handler is called before the individual property pages receive the PSN_APPLY notification through their respective dialog procedures. I want to do my processing after these notifications have been processed, preferably without ugly hacks. How do I do this?

Background: I'm storing my configuration in a single struct, and the individual pages each modify parts of this struct when they are applied. Then, after these values have been written, I want to apply the settings from the struct all at once, instead of re-applying all of them from each property page.

A: 

couldn't you just intercept the WM_COMMAND's BL_CLICKED message for ids IDOK, IDAPPLY and IDCANCEL?

Are you using MFC? or ATL?

Though I can't think of a time I wouldn't be able to intercept the BM_CLICKED...

Edit: Hmm never used property pages through that function... Just had a read through it. Have you set the pfnCallback function and the PSH_USECALLBACK flag set?

Each page also has a dialog proc. Can you not intercept the ok, cancel and apply from there as well? I think the other plan seems to fit more, though.

Goz
I would have to do this in my main message loop, which is in a completely unrelated part of the application. And I'm not even sure that these messages flow through there, because `PropertySheet()` doesn't return until the property sheet dialog is closed.
Thomas
@Edit: I am using the `pfnCallback`, and it gets called just fine, but *before* any of the individual property sheets' dialog procedures. I want to do stuff *after* all of these have done their work.
Thomas
No MFC or ATL by the way.
Thomas
A: 

You don't NEED to apply the struct from inside any of the dialog handlers. So, if its a modal Property Sheet, you could do something simple like:

// Display the property sheet.
PropertySheet(&theSheet);
// The peroperty sheets PSN_APPLY notification sets this bool to true in the struct.
if(theStruct.fApply)
  ApplyTheStruct(&theStruct);


Alternatively, I don't understand why, given that the 'struct' is just collecting the information entered on the pages, you dont change the struct as the user interacts with the page. Ignore the per-page PSN_APPLY messages and apply the struct when PropSheetProc is called. OR discard it totally if the notification is PSN_CANCEL.

Chris Becke
That ain't working. If the user clicks Apply, stuff needs to be applied, but the `PropertySheet` function does not yet return.
Thomas
The PropertySheet function will first send the PSN_APPLY message PRopSheetProc, then to each page, then it will return. The struct will now be set up and you can apply it? Is it really important to 'apply' the struct before the Property sheet is visibly closed?
Chris Becke
A: 

I ended up using the PropSheetProc callback to capture the property sheet's window handle, then hook up a subclass window procedure, like this:

// This is not officially defined, but the whole world uses it.
#define ID_APPLY_NOW 0x3021

WNDPROC origWinProc;

LRESULT CALLBACK MyWinProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) {
  // Call the original window procedure.
  LRESULT retVal = CallWindowProc(origWinProc, hwndDlg, msg, wParam, lParam);
  // Now, and only now, do our own stuff.
  switch (msg) {
    case WM_COMMAND:
      switch (LOWORD(wParam)) {
        case IDOK:
        case ID_APPLY_NOW:
          applyConfig();
          saveConfig();
          break;
      }
      break;
  }
  // Return the original winproc's result.
  return retVal;
}

int CALLBACK myPropSheetProc(HWND hwndDlg, UINT msg, LPARAM lParam) {
  switch (msg) {
    case PSCB_INITIALIZED:
      // Override the property sheet's window procedure with our own.
      origWinProc = (WNDPROC)SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)&MyWinProc);
      break;
  }
  return 0;
}

(Yes, I use switch statements even if there is only one case to consider. I'm strange like that.)

Thomas