//
//  Internal data structures for property sheet support.
//

//
//  Sigh.  Wiz97 underwent a redesign between IE4 and IE5
//  so we have to treat them as two unrelated wizard styles that happen to
//  have frighteningly similar names.  So prsht.h contains both
//  PSH_WIZARD97IE4 and PSH_WIZARD97IE5, and defines PSH_WIZARD97 to be
//  the one appropriate to the version of the header file being included.
//
//  We redefine PSH_WIZARD97 to mean "Any form of Wizard97",
//
#undef  PSH_WIZARD97
#define PSH_WIZARD97        (PSH_WIZARD97IE4 | PSH_WIZARD97IE5)

//
//  The history of PROPSHEETHEADER
//
//  PROPSHEETHEADERSIZE_BETA
//
//      This is the property sheet header that shipped in an early
//      Win95 beta (sometime between Sep 1993 and Sep 1994, maybe M5).
//
//      It is just like the shipping Win95 property sheet header,
//      except that it lacks the PFNPROPSHEETCALLBACK at the end.
//      We grudgingly accept it but don't publicize the fact.
//
//      For some reason, we have always supported this wacky
//      ancient unreleased PROPSHEETHEADER, so there's no point
//      in dropping support for it now...  If you think it's not
//      worth retaining support for this ancient structure,
//      feel free to nuke it.  But you become responsible for the
//      potential app compat bugs from Norton Utilities for
//      Windows 95 v1.0.
//
//  PROPSHEETHEADERSIZE_V1
//
//      This is the property sheet header that shipped in Win95,
//      NT4, and IE3.  It is documented and lots of people use it.
//
//  PROPSHEETHEADERSIZE_V1a
//
//      This is an interim property sheet header that never shipped.
//      Support for it has been broken for a long time, so I dropped
//      the support altogether for IE5.
//
//  PROPSHEETHEADERSIZE_V2
//
//      This is the property sheet header that shipped in IE4.
//
#define PROPSHEETHEADERSIZE_BETA    CCSIZEOF_STRUCT(PROPSHEETHEADER, H_ppsp)
#define PROPSHEETHEADERSIZE_V1      CCSIZEOF_STRUCT(PROPSHEETHEADER, pfnCallback)
#define PROPSHEETHEADERSIZE_V2      CCSIZEOF_STRUCT(PROPSHEETHEADER, H_pszbmHeader)

#define IsValidPROPSHEETHEADERSIZE(dwSize) \
       ((dwSize) == PROPSHEETHEADERSIZE_BETA || \
        (dwSize) == PROPSHEETHEADERSIZE_V1   || \
        (dwSize) == PROPSHEETHEADERSIZE_V2)

// PropertySheetPage structure sizes:

#define MINPROPSHEETPAGESIZEA PROPSHEETPAGEA_V1_SIZE
#define MINPROPSHEETPAGESIZEW PROPSHEETPAGEW_V1_SIZE
#define MINPROPSHEETPAGESIZE  PROPSHEETPAGE_V1_SIZE

//  - COMPATIBILITY CONSTRAINT -
//
//  Shell32 prior to IE5 knows the internal structure of the HPROPSHEETPAGE,
//  so we have to give it what it wants.  (shell32\bitbuck.c, docfind2.c)
//
//  Win95 Golden - Shell32 expects the HPROPSHEETPAGE to be equal to
//  the lParam that is passed to the dialog proc's WM_INITDIALOG.
//  No special flags are passed in the PROPSHEETPAGE to indicate
//  that this assumption is being made.
//
//  Win95 IE4 Integrated - Same as Win95 Golden, except that
//  the shell sets the PSP_SHPAGE bit in the PROPSHEETPAGE.dwFlags
//  to indicate that it wants this wacky behavior.
//
//  WinNT Golden - Shell32 expects the HPROPSHEETPAGE to be equal
//  to a pointer to the internal PSP structure used by WinNT golden.
//  The internal PSP structure looked like a PROPSHEETPAGE, except
//  that it had two fields stuck in front.  (One DWORD and one pointer.)
//  The NT shell passes the PSP_SHPAGE flag.
//
//  WinNT IE4 Integrated - Same as WinNT Golden.
//
//  Furthermore, all versions of Shell32 prior to IE5 call the internal
//  CreatePage function (shell32\docfind2.c)
//
//  - Summary -
//
//                passes       expected      expects
//              PSP_SHPAGE       PSP         CLASSICPREFIX
//              ---------      -------       -------------
//  95 Gold                      ANSI
//  95/IE4          *            ANSI
//  NT Gold         *            UNI           *
//  NT/IE4          *            UNI           *
//
//  Note that Win95 Gold does not set the PSP_SHPAGE flag, so we have
//  to assume that any ANSI caller might be a Win95 Gold shell32.
//
//  WinNT is easier.  We return the WinNT Golden UNICODE version of
//  the PSP if (and only if) the PSP_SHPAGE flag is set.
//
//  The PSP_SHPAGE flag has been removed from the header file so nobody
//  can pass it ever again.
//
//  So our structures look like this.  The bracketed section is the
//  the memory block passed by the app to CreatePropertySheetPage
//  and whose layout cannot be altered.
//
//  ANSI Comctl32, ANSI application:
//
//            +---------------+
//            | PAGEPREFIX    |
//  hpage95->/+---------------+
//          / | PROPSHEETPAGE |
//          | |  (ANSI)       |
//          | |               |
//          | +---------------+
//          | |               |
//          | | app goo       |
//          \ |               |
//           \+---------------+
//
//  UNICODE Comctl32, ANSI application.
//
//
//          The authoritative page      The shadow page
//
//            +---------------+         + - - - - - - - +
//            | PAGEPREFIX    |         | PAGEPREFIX    |
//            +---------------+         +---------------+ <- hpageNT
//            | CLASSICPREFIX |<-\/-----| CLASSICPREFIX |
//            +---------------+<-/\---->+---------------+\<- hpage95
//            | PROPSHEETPAGE |         | PROPSHEETPAGE | \
//            |  (UNICODE)    |         |  (ANSI)       | |
//            |               |         |               | |
//            +---------------+         +---------------+ |
//                                      |               | |
//                                      | app goo       | |
//                                      |               | /
//                                      +---------------+/
//
//                                  (The dotted line around PAGEPREFIX
//                                   means that it is allocated but unused.)
//
//
//  UNICODE Comctl32, UNICODE application.
//
//            +---------------+
//            | PAGEPREFIX    |
//  hpageNT-> +---------------+
//            | CLASSICPREFIX |
//  hpage95->/+---------------+
//          / | PROPSHEETPAGE |
//          | |  (UNICODE)    |
//          | |               |
//          | +---------------+
//          | |               |
//          | | app goo       |
//          \ |               |
//           \+---------------+
//
//  Are we confused yet?  Let's try to explain.
//
//  REQUIREMENT
//
//      The app goo must be kept in the structure
//      corresponding to the character set of the application.
//
//      Notice that if the application is ANSI, then the app goo
//      is kept with the ANSI version of PROPSHEETPAGE.  If the
//      application is UNICODE, then the app goo is kept with the
//      UNICODE version of the PROPSHEETPAGE.
//
//      It doesn't hurt to "accidentally" put a copy of the app goo
//      on the version the app doesn't use; that just wastes memory.
//
//  REQUIREMENT
//
//      If a UNICODE app passed PSP_SHPAGE, then the hpage must
//      point to the CLASSICPREFIX structure.
//
//      To simplify matters (like HPROPSHEETPAGE validation), we
//      apply this rule even if the app didn't pass PSP_SHPAGE.
//
//  DESIGN
//
//      If the app is ANSI and we support UNICODE, then we create
//      a UNICODE copy of the ANSI property sheet structure,
//      and the ANSI PROPSHEETPAGE becomes a "shadow".
//      The UNICODE copy does not need to carry the app goo
//      since it will never be seen by the app.
//
//  REQUIREMENT
//
//      If an ANSI app creates a property sheet page, then the hpage
//      must point to the ANSI version of the PROPSHEETPAGE.
//      (Because the app might be shell32.)
//
//  >> CAUTION <<
//
//      The requirements on hpages rule means that any time an hpage
//      comes in from the outside world, we need to sniff it and decide
//      if it's the UNICODE version or the ANSI version; if it's
//      the ANSI version, then we switch the pointer to point to
//      the UNICODE version instead.
//
//  REMARK
//
//      Internally, we use only the UNICODE version of the PROPSHEETPAGE.
//      (Unless we're building Win95 ANSI-only, duh.)  The ANSI version
//      (the "shadow") is just for show to keep the app happy.  It is
//      the UNICODE version that is authoritative.
//
//      Only the authoritative PROPSHEETPAGE needs to have the PAGEPREFIX,
//      but we put one on both sides to simplify memory management,
//      because it means that all PROPSHEETPAGEs look the same (both
//      authoritative and shadow).

#define PSP_SHPAGE                 0x00000200  // Ewww; see above

//
//  CLASSICPREFIX
//
//  This structure is allocated ahead of the PROPSHEETPAGE when we
//  create an HPROPSHEETPAGE.  See the diagrams above.  Sometimes
//  the HPROPSHEETPAGE points to this structure, sometimes it doesn't.
//  See the diagrams above.
//
//  This structure can never change, due to backwards compatibility
//  constraints described above.  (Okay, you can change it once you
//  decide to drop support for versions of NT less than 5, like that'll
//  ever happen.)

//
//  pispMain
//
//      Points to the main copy of the HPROPSHEETPAGE.
//
//  pispShadow
//
//      Points to that shadow copy of the HPROPSHEETPAGE, or NULL if
//      there is no shadow copy.

typedef struct CLASSICPREFIX 
{
    union ISP *pispMain;
    union ISP *pispShadow;
} CLASSICPREFIX, *PCLASSICPREFIX;

//
//  PAGEPREFIX
//
//  Stuff that we track which isn't part of the CLASSICPREFIX.
//
//  hpage is the HPROPSHEETPAGE that we give out to applications.
//

typedef struct PAGEPREFIX 
{
    HPROPSHEETPAGE hpage;
    DWORD dwInternalFlags;
    SIZE siz;                           // Page ideal size
} PAGEPREFIX, *PPAGEPREFIX;

//
//  Flag values for dwInternalFlags
//

#define PSPI_WX86               1
#define PSPI_FETCHEDICON        2       // For debugging (GetPageInfoEx)
#define PSPI_SIZEMASK           0xFFFF0000

//
//  _PSP
//
//  This is the structure than the compiler thinks an HPROPSHEETPAGE
//  points to.  To make sure all our code goes through
//  InternalizeHPROPSHEETPAGE on the way in and
//  ExternalizeHPROPSHEETPAGE on the way out, we intentionally leave
//  it undefined.

typedef struct _PSP PSP, *PPSP;

//
//  ISP - Internal Sheet Page
//
//  Our internal structure for tracking property sheet pages.  This
//  is also what a native-character set HPROPSHEETPAGE points to.
//
//  Note the "union with an array of one element that we index with
//  the value -1 in order to access it at negative offsets" trick.
//
//  Note also that the CLASSICPREFIX goes above the HPROPSHEETPAGE
//  on Win95, but below it on WinNT.  See discussion at the top of this
//  file.
//
//  To save all the typing of union names and [-1]'s, access to fields
//  of an IPSP are encapsulated inside the _psp, _cpfx, and _pfx macros.

typedef union ISP 
{
    struct 
    {
        PAGEPREFIX pfx;             // lives above the HPROPSHEETPAGE
    } above[1];
    struct 
    {
        CLASSICPREFIX cpfx;         // lives below the HPROPSHEETPAGE
        PROPSHEETPAGE psp;          // lives below the HPROPSHEETPAGE
    } below;
} ISP, *PISP;

#define _pfx    above[-1].pfx
#define _psp    below.psp
#define _cpfx   below.cpfx

#define GETORIGINALSIZE(psp) (((psp)->_pfx.dwInternalFlags & PSPI_SIZEMASK) >> 16)
#define SETORIGINALSIZE(psp, iSize) ((psp)->_pfx.dwInternalFlags |= (iSize << 16))

#define PropSheetBase(pisp)     ((LPBYTE)(pisp) - sizeof((PISP)pisp)->above)

//
//  Converting an HPROPSHEETPAGE into a PSP means sniffing at the
//  _cpfx.dwFlags and seeing if it's an ANSI page or a UNICODE page.
//

__inline
PISP
InternalizeHPROPSHEETPAGE(HPROPSHEETPAGE hpage)
{
    PISP pisp = (PISP)hpage;
    return pisp->_cpfx.pispMain;
}

#define ExternalizeHPROPSHEETPAGE(pisp) ((pisp)->_pfx.hpage)

//
// Used for GetPageInfo(), prpage.c
//
typedef struct {
    short     PointSize;
    WCHAR     szFace[LF_FACESIZE];
    BOOL      bItalic;
    int       iCharset;
} PAGEFONTDATA, * PPAGEFONTDATA;

//
//  PROPDATA
//
//  The state of a property sheet.
//

typedef struct
{
    HWND hDlg;          // the dialog for this instance data
    PROPSHEETHEADER psh;

    HWND hwndCurPage;   // current page hwnd
    HWND hwndTabs;      // tab control window
    int nCurItem;       // index of current item in tab control
    int idDefaultFallback; // the default id to set as DEFID if page doesn't have one

    int nReturn;
    UINT nRestart;

    int xSubDlg, ySubDlg;       // dimensions of sub dialog
    int cxSubDlg, cySubDlg;

    BOOL fFlags;
    BOOL fFlipped;      // Property sheet not mirrored but with flipped buttons

    // Wizard97 IE4 vs. IE5 discrepancy:
    //
    //  Wizard 97 IE4 - "watermark" refers to the bitmap that is used to
    //                  paint the background of the dialog.
    //  Wizard 97 IE5 - "watermark" refers to the bitmap that goes on
    //                  on the left-hand side of Welcome/Finish screens.
    //
  
    HBITMAP hbmWatermark;
    HBRUSH  hbrWatermark;
    HPALETTE hplWatermark;

    int cyHeaderHeight;
    HFONT hFontBold;
    HBITMAP hbmHeader;
    HBRUSH  hbrHeader;
    int ySubTitle;      // The subtitle's starting Y position
    BOOL fAllowApply;

    // These fields are used by MLUI
    LANGID wFrameLang;      // langid of propsheet frame
    int iFrameCharset;      // charset of propsheet frame

    // These fields cache font metric information
    PAGEFONTDATA    pfdCache;           // Cached font descriptor
    SIZE            sizCache;           // Cached height and width go here
    SIZE            sizMin;             // Smallest we allow pages to get

    HPROPSHEETPAGE rghpage[MAXPROPPAGES];

    HANDLE hActCtxInit;
} PROPDATA, *LPPROPDATA;
// defines for fFlags
#define PD_NOERASE       0x0001
#define PD_CANCELTOCLOSE 0x0002
#define PD_DESTROY       0x0004
#define PD_WX86          0x0008
#define PD_FREETITLE     0x0010
#define PD_SHELLFONT     0x0020         // Is the frame using SHELLFONT?
#define PD_NEEDSHADOW    0x0040

//
//  Helper macros
//
//  UNIX does not support dummy unions, so we have to say
//  DUMMYUNION<n>_MEMBER all over the place.  Sigh.
//  So all these underscore macros do the grunky work for us.
//
//  H_blah means "the field in the PROPSHEETHEADER named blah".
//  P_blah means "the field in the PROPSHEETPAGE   named blah".
//
//
#define H_hIcon             DUMMYUNION_MEMBER(hIcon)
#define H_pszIcon           DUMMYUNION_MEMBER(pszIcon)
#define H_nStartPage        DUMMYUNION2_MEMBER(nStartPage)
#define H_pStartPage        DUMMYUNION2_MEMBER(pStartPage)
#define H_phpage            DUMMYUNION3_MEMBER(phpage)
#define H_ppsp              DUMMYUNION3_MEMBER(ppsp)
#define H_hbmWatermark      DUMMYUNION4_MEMBER(hbmWatermark)
#define H_pszbmWatermark    DUMMYUNION4_MEMBER(pszbmWatermark)
#define H_hbmHeader         DUMMYUNION5_MEMBER(hbmHeader)
#define H_pszbmHeader       DUMMYUNION5_MEMBER(pszbmHeader)

#define P_pszTemplate       DUMMYUNION_MEMBER(pszTemplate)
#define P_pResource         DUMMYUNION_MEMBER(pResource)
#define P_hIcon             DUMMYUNION2_MEMBER(hIcon)
#define P_pszIcon           DUMMYUNION2_MEMBER(pszIcon)

//
//  HASCALLBACK - We should call the callback for this page.
//

#define HASCALLBACK(pisp) \
       (((pisp)->_psp.dwFlags & PSP_USECALLBACK) && \
         (pisp)->_psp.pfnCallback)

//
//  HASREFPARENT - We should adjust the pcRefParent for this page.
//

#define HASREFPARENT(pisp) \
       (((pisp)->_psp.dwFlags & PSP_USEREFPARENT) && \
         (pisp)->_psp.pcRefParent)

//
//  HASHEADERTITLE - We should display a header title for this page.
//

#define HASHEADERTITLE(pisp) \
       (((pisp)->_psp.dwFlags & PSP_USEHEADERTITLE) && \
         (pisp)->_psp.pszHeaderTitle)

//
//  HASHEADERSUBTITLE - We should display a header subtitle for this page.
//

#define HASHEADERSUBTITLE(pisp) \
       (((pisp)->_psp.dwFlags & PSP_USEHEADERSUBTITLE) && \
         (pisp)->_psp.pszHeaderSubTitle)

//
//  GETPISP - Obtain the PISP for this page.  Once they have been
//            placed into the H_phpage, all the HPROPSHEETPAGEs are
//            already internalized, so we can just cast them over.
//

#define GETPISP(ppd, i) ((PISP)(ppd)->psh.H_phpage[i])

//
//  SETPISP - Change the PISP for this page.
//

#define SETPISP(ppd, i, v) ((ppd)->psh.H_phpage[i] = (HPROPSHEETPAGE)(v))

//
//  GETHPAGE - Obtain the external HPROPSHEETPAGE for this page.
//
#define GETHPAGE(ppd, i) ExternalizeHPROPSHEETPAGE(GETPISP(ppd, i))

//
//  GETPPSP - Obtain the PPSP for this page.  We get the PISP
//            and then retrieve the PROPSHEETHEADER part.
//

#define GETPPSP(ppd, i) (&GETPISP(ppd, i)->_psp)

//
//  HASANSISHADOW
//
//  Does this authoritative property sheet page have an ANSI shadow?
//
//  If we are built ANSI, then the canonical PSP is equal to the
//  ANSI version, so there is no shadow.  (It's already the real thing.)
//
#define HASANSISHADOW(pisp) ((pisp)->_cpfx.pispShadow)

//
//  HIDEWIZ97HEADER
//
//      Nonzero if we are a WIZARD97 property sheet but we should
//      hide the header for this page.

#define HIDEWIZ97HEADER(ppd, i) \
        (((ppd)->psh.dwFlags & PSH_WIZARD97) && \
          (GETPPSP(ppd, i)->dwFlags & PSP_HIDEHEADER))

//
//  Stub macros so we don't have to put "#ifdef BIG_ENDIAN" everywhere.
//
#ifndef BIG_ENDIAN
#define MwReadDWORD(lpByte)   *(LPDWORD)(lpByte)
#define MwWriteDWORD(lpByte, dwValue)   *(LPDWORD)(lpByte) = dwValue
#endif

//
//  End of helper macros
//

//
//  Functions shared between prsht.c and prpage.c
//
PISP AllocPropertySheetPage(DWORD dwClientSize);
HWND _CreatePage(LPPROPDATA ppd, PISP pisp, HWND hwndParent, LANGID langidMUI);
HPROPSHEETPAGE WINAPI _CreatePropertySheetPage(LPCPROPSHEETPAGE psp, BOOL fNeedShadow, BOOL fWx86);

typedef LPTSTR (STDMETHODCALLTYPE *STRDUPPROC)(LPCTSTR ptsz);

BOOL CopyPropertyPageStrings(LPPROPSHEETPAGE ppsp, STRDUPPROC pfnStrDup);
void FreePropertyPageStrings(LPCPROPSHEETPAGE ppsp);

BOOL ThunkPropSheetHeaderAtoW (LPCPROPSHEETHEADERA ppshA,
                                LPPROPSHEETHEADERW ppsh);
void FreePropSheetHeaderW(LPPROPSHEETHEADERW ppsh);

STDAPI_(LPTSTR) StrDup_AtoW(LPCTSTR ptsz);


typedef struct 
{
    POINT pt;               // Dialog box dimensions (DLU)
    HICON hIcon;            // Page icon
    PAGEFONTDATA pfd;       // Font info
    BOOL bRTL;              // If tab caption should be right to left reading
    BOOL bMirrored;            // if the page contains mirroring flags
    BOOL bDialogEx;         // Is it a DIALOGEX?
    DWORD dwStyle;          // Dialog style
    TCHAR szCaption[128 + 50];  // Caption as stored in template

} PAGEINFOEX;

//
//  These flags control which parts of the PAGEINFOEX get filled in.
//
#define GPI_PT          0x0000      // so cheap, we always fetch it
#define GPI_ICON        0x0001
#define GPI_FONT        0x0002      // PAGEFONTDATA
#define GPI_BRTL        0x0000      // so cheap, we always fetch it
#define GPI_BMIRROR     0x0000      // so cheap, we always fetch it
#define GPI_DIALOGEX    0x0000      // so cheap, we always fetch it
#define GPI_CAPTION     0x0004
#define GPI_ALL         0x0007

BOOL WINAPI GetPageInfoEx(LPPROPDATA ppd, PISP pisp, PAGEINFOEX *ppi, LANGID langidMUI, DWORD flags);

// SHELLFONT means that you are a DIALOGEX and have the DS_SHELLFONT bits set
// Although this is supported only on NT5, the flag is still meaningful on
// Win9x to indicate an implicit PSH_USEPAGEFONT.
#define IsPageInfoSHELLFONT(ppi) \
    ((ppi)->bDialogEx && DS_SHELLFONT == (DS_SHELLFONT & (ppi)->dwStyle))

// Prsht_PrepareTemplate operating systems types
// Used as array indices. Be careful !!

typedef enum {
    PSPT_OS_WIN95_BIDI,    // Win95  BiDi
    PSPT_OS_WIN98_BIDI,    // Win98  BiDi   (Or Higher)
    PSPT_OS_WINNT4_ENA,    // WinNT4 BiDi Ena, No Winnt4 BiDi loc
    PSPT_OS_WINNT5,        // WinNT5 (Or Higher)
    PSPT_OS_OTHER,         // Anything else ....
    PSPT_OS_MAX            
    } PSPT_OS;

// Prsht_PrepareTemplate property sheet type 
// Used as array indices. Be careful !!
typedef enum {
    PSPT_TYPE_MIRRORED,     // Mirrored first page OR mirrored Process
    PSPT_TYPE_ENABLED,      // First page Language is BiDi
    PSPT_TYPE_ENGLISH,      // Anything else ....
    PSPT_TYPE_MAX           
} PSPT_TYPE;

// Prsht_PrepareTemplate property sheet default behavior override
// Used as array indices. Be careful !!

typedef enum {
    PSPT_OVERRIDE_NOOVERRIDE,
    PSPT_OVERRIDE_USEPAGELANG,  // Overridden by PSH_USEPAGELANG
    PSPT_OVERRIDE_MAX
    } PSPT_OVERRIDE;

// Prsht_PrepareTemplate Preparation action
typedef enum {
    PSPT_ACTION_NOACTION,      // Don't touch whatever you've passed
    PSPT_ACTION_NOMIRRORING,   // Turn off mirroring
    PSPT_ACTION_FLIP,          // Turn off mirroring and flip
    PSPT_ACTION_LOADENGLISH,   // load English template
    PSPT_ACTION_WIN9XCOMPAT    // Tags the templae with DS_BIDI_RTL for Win9x compat
    } PSPT_ACTION;

ULONG_PTR PropPageActivateContext(LPPROPDATA ppd, PISP pisp);
void PropPageDeactivateContext(ULONG_PTR i);