propdlg.c
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 134k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. ////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // propdlg.c
  4. //
  5. // The Properties dialog for MS Office.
  6. //
  7. // Change history:
  8. //
  9. // Date         Who             What
  10. // --------------------------------------------------------------------------
  11. // 06/09/94     B. Wentz        Created file
  12. // 01/16/95     martinth        Finished sticky dlg stuff.  Lemme just say that
  13. //                              it's pretty lame.  We have to call ApplyStickyDlgCoor
  14. //                              in the first WM_INITDIALOG, don't ask me why,
  15. //                              but otherwise we have redraw problems.  Likewise,
  16. //                              we have to call SetStickyDlgCoor in the first
  17. //                              PSN_RESET/PSN_APPLY, I have no idea why, since
  18. //                              the main dialog shouldn't have been deleted but
  19. //                              it is.  Thus we have to add calls everywhere.
  20. //                              Could it be that the tabs are getting deleted
  21. //                              one by one and the dialog changes size?  Dunno.
  22. //                              But this works, so change at your own risk!;-)
  23. // 07/08/96     MikeHill        Ignore unsupported (non-UDTYPE) properties.
  24. ////////////////////////////////////////////////////////////////////////////////
  25. #include "priv.h"
  26. #pragma hdrstop
  27. #include <winnls.h>
  28. #include <prsht.h>
  29. #include <commctrl.h>
  30. #include <shlwapi.h>
  31. #include <shlapip.h>
  32. #include "propdlg.h"
  33. #include "strings.h"
  34. #include "msohelp.h"
  35. // Max size of time/date string
  36. #define TIMEDATEMAX     256
  37. // Check button actions
  38. #define CLEAR   0
  39. #define CHECKED 1
  40. #define GREYED  2
  41. // Number of property sheet pages
  42. #define PAGESMAX        5
  43. // Max size for "short" temp buffers
  44. #define SHORTBUFMAX     128
  45. // The pages
  46. #ifdef _WIN2000_DOCPROP_
  47. #define itabCUSTOM          0
  48. #define itabFIRST           itabCUSTOM
  49. #else //_WIN2000_DOCPROP_
  50. #define itabGENERAL         0
  51. #define itabSUMMARY         1
  52. #define itabSTATISTICS      2
  53. #define itabCONTENTS        3
  54. #define itabCUSTOM          4
  55. #define itabFIRST           itabSUMMARY
  56. #endif //_WIN2000_DOCPROP_
  57. // Defines for printing file sizes
  58. #define DELIMITER   TEXT(',')
  59. #define iszBYTES               0
  60. #define iszORDERKB             1
  61. #define iszORDERMB             2
  62. #define iszORDERGB             3
  63. #define iszORDERTB             4
  64. static TCHAR rgszOrders[iszORDERTB+1][SHORTBUFMAX];
  65. //  "bytes",        // iszBYTES
  66. //  "KB",           // iszORDERKB
  67. //  "MB",           // iszORDERMB
  68. //  "GB",           // iszORDERGB
  69. //  "TB"            // iszORDERTB
  70. // note that szBYTES is defined above...
  71. #define iszPAGES         1
  72. #define iszPARA          2
  73. #define iszLINES         3
  74. #define iszWORDS         4
  75. #define iszCHARS         5
  76. #define iszSLIDES        6
  77. #define iszNOTES         7
  78. #define iszHIDDENSLIDES  8
  79. #define iszMMCLIPS       9
  80. #define iszFORMAT        10
  81. // Strings for the statistics listbox
  82. static TCHAR rgszStats[iszFORMAT+1][SHORTBUFMAX];
  83. //  "Bytes:",             // iszBYTES
  84. //  "Pages:",             // iszPAGES
  85. //  "Paragraphs:",        // iszPARA
  86. //  "Lines:",             // iszLINES
  87. //  "Words:",             // iszWORDS
  88. //  "Characters:",        // iszCHARS
  89. //  "Slides:",            // iszSLIDES
  90. //  "Notes:",             // iszNOTES
  91. //  "Hidden Slides:",     // iszHIDDENSLIDES
  92. //  "Multimedia Clips:",  // iszMMCLIPS
  93. //  "Presentation Format:"// iszFORMAT
  94. #define BASE10          10
  95. // Number of pre-defined custom names
  96. #define NUM_BUILTIN_CUSTOM_NAMES 27
  97. #define iszTEXT         0
  98. #define iszDATE         1
  99. #define iszNUM          2
  100. #define iszBOOL         3
  101. #define iszUNKNOWN      4
  102. // Strings for the types of user-defined properties
  103. static TCHAR rgszTypes[iszUNKNOWN+1][SHORTBUFMAX];
  104. //  "Text",               // iszTEXT
  105. //  "Date",               // iszDATE
  106. //  "Number",             // iszNUM
  107. //  "Yes or No",          // iszBOOL
  108. //  "Unknown"             // iszUNKNOWN
  109. #define iszNAME         0
  110. #define iszVAL          1
  111. #define iszTYPE         2
  112. // Strings for the column headings for the statistics tab
  113. static TCHAR rgszStatHeadings[iszVAL+1][SHORTBUFMAX];
  114. //  "Statistic Name",     // iszNAME
  115. //  "Value"               // iszVAL
  116. // Strings for the column headings for custom tab
  117. static TCHAR rgszHeadings[iszTYPE+1][SHORTBUFMAX];
  118. //  "Property Name",      // iszNAME
  119. //  "Value",              // iszVAL
  120. //  "Type"                // iszTYPE
  121. #define iszTRUE  0
  122. #define iszFALSE 1
  123. // Strings for Booleans
  124. static TCHAR rgszBOOL[iszFALSE+1][SHORTBUFMAX];
  125. //  "Yes",       // iszTRUE
  126. //  "No"         // iszFALSE
  127. #define iszADD          0
  128. #define iszMODIFY       1
  129. // Strings for the Add button
  130. static TCHAR rgszAdd[iszMODIFY+1][SHORTBUFMAX];
  131. //  "Add",        // iszADD
  132. //  "Modify"      // iszMODIFY
  133. #define iszVALUE     0
  134. #define iszSOURCE    1
  135. // Strings for the source/value caption
  136. static TCHAR rgszValue[iszSOURCE+1][SHORTBUFMAX];
  137. //  "Value:",     // iszVALUE
  138. //  "Source:"     // iszSOURCE
  139. // Date formatting codes
  140. #define MMDDYY  TEXT('0')
  141. #define DDMMYY  TEXT('1')
  142. #define YYMMDD  TEXT('2')
  143. #define OLEEPOCH 1900
  144. #define SYSEPOCH 1601
  145. #define ONECENTURY 100
  146. #define YEARINCENTURY(year)     ((year) % ONECENTURY)
  147. #define CENTURYFROMYEAR(year)   ((year) - YEARINCENTURY(year))
  148. //
  149. // Global data, to be deleted when FShowOfficePropDlg exits
  150. //
  151. static LPTSTR glpstzName;
  152. static LPTSTR glpstzValue;
  153. static int giLinkIcon;
  154. static int giInvLinkIcon;
  155. static int giBlankIcon;
  156. static HBRUSH hBrushPropDlg = NULL;
  157. const TCHAR g_szHelpFile[] = TEXT("windows.hlp");
  158. //
  159. // Internal prototypes
  160. //
  161. INT_PTR CALLBACK FGeneralDlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
  162. INT_PTR CALLBACK FSummaryDlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
  163. INT_PTR CALLBACK FStatisticsDlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
  164. INT_PTR CALLBACK FCustomDlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
  165. INT_PTR CALLBACK FContentsDlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
  166. INT_PTR CALLBACK FPropHeaderDlgProc (HWND hwnd, UINT message, LONG lParam);
  167. //static int  CALLBACK ListViewCompareFunc(LPARAM, LPARAM, LPARAM);
  168. void PASCAL SetEditValLpsz (LPPROPVARIANT lppropvar, HWND hdlg, DWORD dwID );
  169. BOOL PASCAL GetEditValLpsz (LPPROPVARIANT lppropvar, HWND hDlg, DWORD dwId);
  170. BOOL PASCAL FAllocAndGetValLpstz (HWND hDlg, DWORD dwId, LPTSTR *lplpstz);
  171. BOOL PASCAL FAllocString (LPTSTR *lplpstz, DWORD cb);
  172. void PASCAL ClearEditControl (HWND hDlg, DWORD dwId);
  173. UDTYPES PASCAL UdtypesGetNumberType (LPTSTR lpstz, NUM *lpnumval,
  174.                                      BOOL (*lpfnFSzToNum)(NUM *, LPTSTR));
  175. void PASCAL PrintTimeInDlg (HWND hDlg, DWORD dwId, FILETIME *pft);
  176. void PASCAL PrintEditTimeInDlg (HWND hDlg, FILETIME *pft);
  177. void PASCAL AddItemToListView (HWND hWnd, DWORD_PTR dw, const TCHAR *lpsz, BOOL fString);
  178. void PASCAL PopulateUDListView (HWND hWnd, LPUDOBJ lpUDObj);
  179. void PASCAL AddUDPropToListView (LPUDOBJ lpUDObj, HWND hWnd, LPTSTR lpszName, LPPROPVARIANT lppropvar, int iItem,
  180.                                  BOOL fLink, BOOL fLinkInvalid, BOOL fMakeVisible);
  181. VOID PASCAL InitListView (HWND hDlg, int irgLast, TCHAR rgsz[][SHORTBUFMAX], BOOL fImageList);
  182. WORD PASCAL WUdtypeToSz (LPPROPVARIANT lppropvar, LPTSTR sz, DWORD cchMax,
  183.                          BOOL (*lpfnFNumToSz)(NUM *, LPTSTR, DWORD));
  184. BOOL PASCAL FSwapControls (HWND hWndVal, HWND hWndLinkVal, HWND hWndBoolTrue, HWND hWndBoolFalse, HWND hWndGroup, HWND hWndType, HWND hWndValText, BOOL fLink, BOOL fBool);
  185. VOID PASCAL PopulateControls (LPUDOBJ lpUDObj, LPTSTR szName, DWORD cLinks, DWQUERYLD lpfnDwQueryLinkData, HWND hDlg,
  186.                               HWND hWndName, HWND hWndVal, HWND hWndValText, HWND hWndLink, HWND hWndLinkVal, HWND hWndType,
  187.                               HWND hWndBoolTrue, HWND hWndBoolFalse, HWND hWndGroup, HWND hWndAdd, HWND hWndDelete, BOOL *pfLink, BOOL *pfAdd);
  188. BOOL PASCAL FSetupAddButton (DWORD iszType, BOOL fLink, BOOL *pfAdd, HWND hWndAdd, HWND hWndVal, HWND hWndName, HWND hDlg);
  189. BOOL PASCAL FCreateListOfLinks (DWORD cLinks, DWQUERYLD lpfnDwQueryLinkData, HWND hWndLinkVal);
  190. BOOL PASCAL FSetTypeControl (UDTYPES udtype, HWND hWndType);
  191. void PASCAL DeleteItem (LPUDOBJ lpUDObj, HWND hWndLV, int iItem, TCHAR sz[]);
  192. void PASCAL ResetTypeControl (HWND hDlg, DWORD dwId, DWORD *piszType);
  193. BOOL PASCAL FDisplayConversionWarning (HWND hDlg);
  194. BOOL PASCAL FLoadTextStrings (void);
  195. BOOL FGetCustomPropFromDlg(LPALLOBJS lpallobjs, HWND hDlg);
  196. VOID SetCustomDlgDefButton(HWND hDlg, int IDNew);
  197. INT PASCAL ISavePropDlgChanges(LPALLOBJS, HWND, HWND);
  198. /* WinHelp stuff. */
  199. static const DWORD rgIdhGeneral[] =
  200. {
  201.     IDD_ITEMICON,     IDH_GENERAL_ICON,
  202.         IDD_NAME,         IDH_GENERAL_NAME_BY_ICON,
  203.         IDD_FILETYPE,     IDH_GENERAL_FILETYPE,
  204.         IDD_FILETYPE_LABEL,     IDH_GENERAL_FILETYPE,
  205.         IDD_LOCATION,     IDH_GENERAL_LOCATION,
  206.         IDD_LOCATION_LABEL,     IDH_GENERAL_LOCATION,
  207.         IDD_FILESIZE,     IDH_GENERAL_FILESIZE,
  208.         IDD_FILESIZE_LABEL,     IDH_GENERAL_FILESIZE,
  209.         IDD_FILENAME,     IDH_GENERAL_MSDOSNAME,
  210.         IDD_FILENAME_LABEL,     IDH_GENERAL_MSDOSNAME,
  211.         IDD_CREATED,      IDH_GENERAL_CREATED,
  212.         IDD_CREATED_LABEL,      IDH_GENERAL_CREATED,
  213.         IDD_LASTMODIFIED, IDH_GENERAL_MODIFIED,
  214.         IDD_LASTMODIFIED_LABEL, IDH_GENERAL_MODIFIED,
  215.         IDD_LASTACCESSED, IDH_GENERAL_ACCESSED,
  216.         IDD_LASTACCESSED_LABEL, IDH_GENERAL_ACCESSED,
  217.         IDD_ATTRIBUTES_LABEL, IDH_GENERAL_ATTRIBUTES,
  218.         IDD_READONLY,     IDH_GENERAL_READONLY,
  219.         IDD_HIDDEN,       IDH_GENERAL_HIDDEN,
  220.         IDD_ARCHIVE,      IDH_GENERAL_ARCHIVE,
  221.         IDD_SYSTEM,       IDH_GENERAL_SYSTEM
  222. };
  223. static const DWORD rgIdhSummary[] =
  224. {
  225.     IDD_SUMMARY_TITLE,    IDH_SUMMARY_TITLE,
  226.         IDD_SUMMARY_TITLE_LABEL,    IDH_SUMMARY_TITLE,
  227.         IDD_SUMMARY_SUBJECT,  IDH_SUMMARY_SUBJECT,
  228.         IDD_SUMMARY_SUBJECT_LABEL,  IDH_SUMMARY_SUBJECT,
  229.         IDD_SUMMARY_AUTHOR,   IDH_SUMMARY_AUTHOR,
  230.         IDD_SUMMARY_AUTHOR_LABEL,   IDH_SUMMARY_AUTHOR,
  231.         IDD_SUMMARY_MANAGER,  IDH_SUMMARY_MANAGER,
  232.         IDD_SUMMARY_MANAGER_LABEL,  IDH_SUMMARY_MANAGER,
  233.         IDD_SUMMARY_COMPANY,  IDH_SUMMARY_COMPANY,
  234.         IDD_SUMMARY_COMPANY_LABEL,  IDH_SUMMARY_COMPANY,
  235.         IDD_SUMMARY_CATEGORY, IDH_SUMMARY_CATEGORY,
  236.         IDD_SUMMARY_CATEGORY_LABEL, IDH_SUMMARY_CATEGORY,
  237.         IDD_SUMMARY_KEYWORDS, IDH_SUMMARY_KEYWORDS,
  238.         IDD_SUMMARY_KEYWORDS_LABEL, IDH_SUMMARY_KEYWORDS,
  239.         IDD_SUMMARY_COMMENTS, IDH_SUMMARY_COMMENTS,
  240.         IDD_SUMMARY_COMMENTS_LABEL, IDH_SUMMARY_COMMENTS,
  241.         IDD_SUMMARY_TEMPLATE, IDH_SUMMARY_TEMPLATE,
  242.         IDD_SUMMARY_TEMPLATETEXT, IDH_SUMMARY_TEMPLATE,
  243.         IDD_SUMMARY_SAVEPREVIEW, IDH_SUMMARY_SAVEPREVIEW
  244. };
  245. static const DWORD rgIdhStatistics[] =
  246. {
  247.     IDD_STATISTICS_CREATED,    IDH_STATISTICS_CREATED,
  248.         IDD_STATISTICS_CREATED_LABEL,    IDH_STATISTICS_CREATED,
  249.         IDD_STATISTICS_CHANGED,    IDH_STATISTICS_MODIFIED,
  250.         IDD_STATISTICS_CHANGED_LABEL,    IDH_STATISTICS_MODIFIED,
  251.         IDD_STATISTICS_ACCESSED,   IDH_STATISTICS_ACCESSED,
  252.         IDD_STATISTICS_ACCESSED_LABEL,   IDH_STATISTICS_ACCESSED,
  253.         IDD_STATISTICS_LASTPRINT,  IDH_STATISTICS_LASTPRINT,
  254.         IDD_STATISTICS_LASTPRINT_LABEL,  IDH_STATISTICS_LASTPRINT,
  255.         IDD_STATISTICS_LASTSAVEBY, IDH_STATISTICS_LASTSAVEBY,
  256.         IDD_STATISTICS_LASTSAVEBY_LABEL, IDH_STATISTICS_LASTSAVEBY,
  257.         IDD_STATISTICS_REVISION,   IDH_STATISTICS_REVISION,
  258.         IDD_STATISTICS_REVISION_LABEL,   IDH_STATISTICS_REVISION,
  259.         IDD_STATISTICS_TOTALEDIT,  IDH_STATISTICS_TOTALEDIT,
  260.         IDD_STATISTICS_TOTALEDIT_LABEL,  IDH_STATISTICS_TOTALEDIT,
  261.         IDD_STATISTICS_LVLABEL,   IDH_STATISTICS_LISTVIEW,
  262.         IDD_STATISTICS_LISTVIEW,   IDH_STATISTICS_LISTVIEW
  263. };
  264. static const DWORD rgIdhContents[] =
  265. {
  266.     IDD_CONTENTS_LISTBOX_LABEL, IDH_CONTENTS_LISTBOX,
  267.         IDD_CONTENTS_LISTBOX, IDH_CONTENTS_LISTBOX
  268. };
  269. static const DWORD rgIdhCustom[] =
  270. {
  271.     IDD_CUSTOM_NAME,      IDH_CUSTOM_NAME,
  272.         IDD_CUSTOM_NAME_LABEL,      IDH_CUSTOM_NAME,
  273.         IDD_CUSTOM_TYPE,      IDH_CUSTOM_TYPE,
  274.         IDD_CUSTOM_TYPE_LABEL,      IDH_CUSTOM_TYPE,
  275.         IDD_CUSTOM_VALUE,     IDH_CUSTOM_VALUE,
  276.         IDD_CUSTOM_VALUETEXT,     IDH_CUSTOM_VALUE,
  277.         IDD_CUSTOM_LINKVALUE, IDH_CUSTOM_LINKVALUE,
  278.         IDD_CUSTOM_BOOLTRUE,  IDH_CUSTOM_BOOLYES,
  279.         IDD_CUSTOM_BOOLFALSE, IDH_CUSTOM_BOOLYES,
  280.         IDD_CUSTOM_ADD,       IDH_CUSTOM_ADDBUTTON,
  281.         IDD_CUSTOM_DELETE,    IDH_CUSTOM_DELETEBUTTON,
  282.         IDD_CUSTOM_LINK,      IDH_CUSTOM_LINKCHECK,
  283.         IDD_CUSTOM_LISTVIEW,  IDH_CUSTOM_LISTVIEW,
  284.         IDD_CUSTOM_LISTVIEW_LABEL,  IDH_CUSTOM_LISTVIEW
  285. };
  286. void FOfficeInitPropInfo(PROPSHEETPAGE * lpPsp, DWORD dwFlags, LPARAM lParam, LPFNPSPCALLBACK pfnCallback)
  287. {
  288. #ifndef _WIN2000_DOCPROP_
  289.     lpPsp[itabSUMMARY-itabFIRST].dwSize = sizeof(PROPSHEETPAGE);
  290.     lpPsp[itabSUMMARY-itabFIRST].dwFlags = dwFlags;
  291.     lpPsp[itabSUMMARY-itabFIRST].hInstance = g_hmodThisDll;
  292.     lpPsp[itabSUMMARY-itabFIRST].pszTemplate = MAKEINTRESOURCE (IDD_SUMMARY);
  293.     lpPsp[itabSUMMARY-itabFIRST].pszIcon = NULL;
  294.     lpPsp[itabSUMMARY-itabFIRST].pszTitle = NULL;
  295.     lpPsp[itabSUMMARY-itabFIRST].pfnDlgProc = FSummaryDlgProc;
  296.     lpPsp[itabSUMMARY-itabFIRST].pfnCallback = pfnCallback;
  297.     lpPsp[itabSUMMARY-itabFIRST].pcRefParent = NULL;
  298.     lpPsp[itabSUMMARY-itabFIRST].lParam = lParam;
  299.     
  300.     lpPsp[itabSTATISTICS-itabFIRST].dwSize = sizeof(PROPSHEETPAGE);
  301.     lpPsp[itabSTATISTICS-itabFIRST].dwFlags = dwFlags;
  302.     lpPsp[itabSTATISTICS-itabFIRST].hInstance = g_hmodThisDll;
  303.     lpPsp[itabSTATISTICS-itabFIRST].pszTemplate = MAKEINTRESOURCE (IDD_STATISTICS);
  304.     lpPsp[itabSTATISTICS-itabFIRST].pszIcon = NULL;
  305.     lpPsp[itabSTATISTICS-itabFIRST].pszTitle = NULL;
  306.     lpPsp[itabSTATISTICS-itabFIRST].pfnDlgProc = FStatisticsDlgProc;
  307.     lpPsp[itabSTATISTICS-itabFIRST].pfnCallback = pfnCallback;
  308.     lpPsp[itabSTATISTICS-itabFIRST].pcRefParent = NULL;
  309.     lpPsp[itabSTATISTICS-itabFIRST].lParam = lParam;
  310.     
  311.     lpPsp[itabCONTENTS-itabFIRST].dwSize = sizeof(PROPSHEETPAGE);
  312.     lpPsp[itabCONTENTS-itabFIRST].dwFlags = dwFlags;
  313.     lpPsp[itabCONTENTS-itabFIRST].hInstance = g_hmodThisDll;
  314.     lpPsp[itabCONTENTS-itabFIRST].pszTemplate = MAKEINTRESOURCE (IDD_CONTENTS);
  315.     lpPsp[itabCONTENTS-itabFIRST].pszIcon = NULL;
  316.     lpPsp[itabCONTENTS-itabFIRST].pszTitle = NULL;
  317.     lpPsp[itabCONTENTS-itabFIRST].pfnDlgProc = FContentsDlgProc;
  318.     lpPsp[itabCONTENTS-itabFIRST].pfnCallback = pfnCallback;
  319.     lpPsp[itabCONTENTS-itabFIRST].pcRefParent = NULL;
  320.     lpPsp[itabCONTENTS-itabFIRST].lParam = lParam;
  321. #endif // _WIN2000_DOCPROP_
  322.     lpPsp[itabCUSTOM-itabFIRST].dwSize = sizeof(PROPSHEETPAGE);
  323.     lpPsp[itabCUSTOM-itabFIRST].dwFlags = dwFlags;
  324.     lpPsp[itabCUSTOM-itabFIRST].hInstance = g_hmodThisDll;
  325.     lpPsp[itabCUSTOM-itabFIRST].pszTemplate = MAKEINTRESOURCE (IDD_CUSTOM);
  326.     lpPsp[itabCUSTOM-itabFIRST].pszIcon = NULL;
  327.     lpPsp[itabCUSTOM-itabFIRST].pszTitle = NULL;
  328.     lpPsp[itabCUSTOM-itabFIRST].pfnDlgProc = FCustomDlgProc;
  329.     lpPsp[itabCUSTOM-itabFIRST].pfnCallback = pfnCallback;
  330.     lpPsp[itabCUSTOM-itabFIRST].pcRefParent = NULL;
  331.     lpPsp[itabCUSTOM-itabFIRST].lParam = lParam;
  332.     
  333. }
  334. ////////////////////////////////////////////////////////////////////////////////
  335. //
  336. // Attach
  337. //
  338. // Purpose:
  339. //  Assigns HPROPSHEETPAGE to appropriate data block member.
  340. //
  341. ////////////////////////////////////////////////////////////////////////////////
  342. BOOL FAttach( LPALLOBJS lpallobjs, PROPSHEETPAGE* ppsp, HPROPSHEETPAGE hPage )
  343. {
  344.     #define ASSIGN_PAGE_HANDLE( pfn, phpage ) 
  345.         if( ppsp->pfnDlgProc == pfn ) { *(phpage) = hPage ; return TRUE ; }
  346. #if _WIN2000_DOCPROP_
  347.     ASSIGN_PAGE_HANDLE( FCustomDlgProc,     &lpallobjs->lpUDObj->m_hPage );
  348. #else  // _WIN2000_DOCPROP_
  349.     ASSIGN_PAGE_HANDLE( FSummaryDlgProc,    &lpallobjs->lpSIObj->m_hPage );
  350.     ASSIGN_PAGE_HANDLE( FStatisticsDlgProc, &lpallobjs->lpDSIObj->m_hPage );
  351.     ASSIGN_PAGE_HANDLE( FCustomDlgProc,     &lpallobjs->lpUDObj->m_hPage );
  352. #endif // _WIN2000_DOCPROP_
  353.     return FALSE;
  354. }
  355. ////////////////////////////////////////////////////////////////////////////////
  356. //
  357. // PropPageInit
  358. //
  359. // Purpose:
  360. //  Keep track which pages have been init, such that we can know when we
  361. //  can do the apply.
  362. //
  363. ////////////////////////////////////////////////////////////////////////////////
  364. void PropPageInit(LPALLOBJS lpallobjs, int iPage)
  365. {
  366.     if (iPage > lpallobjs->iMaxPageInit)
  367.         lpallobjs->iMaxPageInit = iPage;
  368. }
  369. ////////////////////////////////////////////////////////////////////////////////
  370. //
  371. // ApplyChangesBackToFile
  372. //
  373. // Purpose:
  374. //     See if this is now the time to apply the changes back to the file
  375. //
  376. ////////////////////////////////////////////////////////////////////////////////
  377. BOOL ApplyChangesBackToFile(
  378.     HWND hDlg, 
  379.     BOOL bFinalEdit /* user clicked OK rather than Apply*/, 
  380.     LPALLOBJS lpallobjs, 
  381.     int iPage)
  382. {
  383.     HRESULT     hres;
  384.     BOOL        fOK = FALSE;
  385.     LPSTORAGE   lpStg;
  386.     WCHAR       wszPath[ MAX_PATH ];
  387.     
  388.     if (iPage != lpallobjs->iMaxPageInit)
  389.         return TRUE;    // no errors
  390.     
  391.     
  392. #ifdef UNICODE
  393.     lstrcpyn(wszPath, lpallobjs->szPath, ARRAYSIZE(wszPath));
  394. #else
  395.     MultiByteToWideChar(CP_ACP, 0, lpallobjs->szPath, -1, wszPath, ARRAYSIZE(wszPath));
  396. #endif
  397. #ifdef WINNT
  398.     hres = StgOpenStorageEx(wszPath,STGM_READWRITE|STGM_SHARE_EXCLUSIVE,STGFMT_ANY,0,NULL,NULL,
  399.                             &IID_IStorage, (void**)&lpStg );
  400. #else
  401.     hres = StgOpenStorage(wszPath, NULL, STGM_READWRITE|STGM_SHARE_EXCLUSIVE, NULL, 0L, &lpStg );
  402. #endif
  403.     if (SUCCEEDED(hres) && lpStg)
  404.     {
  405.         MESSAGE(TEXT("Now trying to save out properties"));
  406.         fOK = (BOOL)DwOfficeSaveProperties( lpStg,
  407.             lpallobjs->lpSIObj,
  408.             lpallobjs->lpDSIObj,
  409.             lpallobjs->lpUDObj,
  410.             0,          // Flags
  411.             STGM_READWRITE | STGM_SHARE_EXCLUSIVE
  412.             );
  413.         
  414.         // Release the Storage (we don't need to commit it;
  415.         // it's in dicrect-mode).
  416.         
  417.         lpStg->lpVtbl->Release (lpStg);
  418.         lpStg= NULL;
  419.         
  420.         
  421.         //
  422.         // if we did properly save out the properties, than we should
  423.         // clear the we have changed things flag...
  424.         //
  425.         if (fOK)
  426.         {
  427.             lpallobjs->fPropDlgChanged = FALSE;
  428.             lpallobjs->fPropDlgPrompted = FALSE;
  429.         }
  430.     }   // if (SUCCEEDED(hres) && lpStorage)
  431.     
  432.     if (!fOK)
  433.     {
  434.         UINT nMsgFlags = bFinalEdit ? MB_OKCANCEL /* give option to not dismiss page*/ : MB_OK;
  435.         
  436.         if (ShellMessageBox(g_hmodThisDll, GetParent(hDlg),
  437.             MAKEINTRESOURCE(idsErrorOnSave), NULL,
  438.             nMsgFlags | MB_ICONHAND, PathFindFileName(lpallobjs->szPath)) == IDOK)
  439.         {
  440.             fOK = TRUE;
  441.         }
  442.         PropSheet_UnChanged(GetParent(hDlg), hDlg);
  443.     }
  444.    
  445.     return fOK;
  446. }   // ApplyChangesBackToFile
  447. ////////////////////////////////////////////////////////////////////////////////
  448. //
  449. // FSummaryDlgProc
  450. //
  451. // Purpose:
  452. //  Summary window dialog handler.
  453. //
  454. ////////////////////////////////////////////////////////////////////////////////
  455. #ifndef _WIN2000_DOCPROP_
  456. INT_PTR CALLBACK  FSummaryDlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  457. {
  458.     DWORD dwMask;
  459.     DWORD dwT;
  460.     LPALLOBJS lpallobjs = (LPALLOBJS)GetWindowLongPtr(hDlg, DWLP_USER);
  461.     
  462.     switch (message)
  463.     {
  464.     case WM_INITDIALOG :
  465.         {
  466.             PROPSHEETPAGE *ppspDlg = (PROPSHEETPAGE *) lParam;
  467.             LPSIOBJ lpSIObj;    // All SumInfo data
  468.             LPDSIOBJ lpDSIObj;  // All DocSumInfo (first section)
  469.             LPPROPVARIANT rgpropvarSumInfo, rgpropvarDocSumInfo;
  470.             
  471.             lpallobjs = (LPALLOBJS)ppspDlg->lParam;
  472.             
  473.             PropPageInit(lpallobjs, itabSUMMARY);
  474.             
  475.             SetWindowLongPtr(hDlg, DWLP_USER, ppspDlg->lParam);
  476.             
  477.             lpSIObj = lpallobjs->lpSIObj;
  478.             lpDSIObj = lpallobjs->lpDSIObj;
  479.             dwMask = lpallobjs->dwMask;
  480.             
  481.             //
  482.             // Validate our data.
  483.             //
  484.             if ((lpSIObj == NULL) ||
  485.                 (lpSIObj->m_lpData == NULL) ||
  486.                 (lpDSIObj == NULL) ||
  487.                 (lpDSIObj->m_lpData == NULL))
  488.             {
  489.                 AssertSz (0, TEXT("Bad object data in Summary dlg"));
  490.                 return FALSE;
  491.             }
  492.             
  493.             //
  494.             // Since we'll be referencing the PropVariants a lot, get
  495.             // a pointer directly to them.
  496.             //
  497.             rgpropvarSumInfo = GETSINFO(lpSIObj)->rgpropvar;
  498.             rgpropvarDocSumInfo = GETSINFO(lpDSIObj)->rgpropvar;
  499.             
  500.             //
  501.             // Copy the properties from the PropVariants to the Edit controls.
  502.             //
  503.             SetEditValLpsz (&rgpropvarSumInfo[ PVSI_TITLE ], hDlg, IDD_SUMMARY_TITLE);
  504.             SetEditValLpsz (&rgpropvarSumInfo[ PVSI_SUBJECT ], hDlg, IDD_SUMMARY_SUBJECT);
  505.             SetEditValLpsz (&rgpropvarSumInfo[ PVSI_AUTHOR ], hDlg, IDD_SUMMARY_AUTHOR);
  506.             SetEditValLpsz (&rgpropvarSumInfo[ PVSI_COMMENTS ], hDlg, IDD_SUMMARY_COMMENTS);
  507.             SetEditValLpsz (&rgpropvarSumInfo[ PVSI_KEYWORDS ], hDlg, IDD_SUMMARY_KEYWORDS);
  508.             
  509.             //
  510.             // Show the name of the template, if it exists, otherwise
  511.             // don't even show the field.
  512.             //
  513.             if (rgpropvarSumInfo[ PVSI_TEMPLATE ].vt == VT_LPTSTR)
  514.             {
  515.                 SetEditValLpsz (&rgpropvarSumInfo[ PVSI_TEMPLATE ], hDlg, IDD_SUMMARY_TEMPLATE);
  516.             }
  517.             else
  518.             {
  519.                 EnableWindow (GetDlgItem (hDlg, IDD_SUMMARY_TEMPLATETEXT), SW_HIDE);
  520.             }
  521.             
  522.             SetEditValLpsz (&rgpropvarDocSumInfo[ PVDSI_CATEGORY ], hDlg, IDD_SUMMARY_CATEGORY);
  523.             SetEditValLpsz (&rgpropvarDocSumInfo[ PVDSI_COMPANY ], hDlg, IDD_SUMMARY_COMPANY);
  524.             SetEditValLpsz (&rgpropvarDocSumInfo[ PVDSI_MANAGER ], hDlg, IDD_SUMMARY_MANAGER);
  525.             SetEditValLpsz (&rgpropvarSumInfo[ PVSI_COMMENTS ], hDlg, IDD_SUMMARY_COMMENTS);
  526.             
  527.             if (dwMask & OSPD_NOSAVEPREVIEW)
  528.             {
  529.                 ShowWindow(GetDlgItem(hDlg, IDD_SUMMARY_SAVEPREVIEW), SW_HIDE);
  530.             }
  531.             else
  532.             {
  533.                 if (!GETSINFO(lpSIObj)->fSaveSINail)
  534.                     GETSINFO(lpSIObj)->fSaveSINail = (dwMask & OSPD_SAVEPREVIEW_ON);
  535.                 
  536. #ifdef SHELL
  537.                 if (!GETSINFO(lpSIObj)->fSaveSINail)
  538.                     
  539.                     EnableWindow (GetDlgItem (hDlg, IDD_SUMMARY_SAVEPREVIEW), FALSE);
  540.                 
  541.                 else
  542. #endif
  543.                     SendDlgItemMessage(hDlg, IDD_SUMMARY_SAVEPREVIEW, BM_SETCHECK,
  544.                     (WPARAM) GETSINFO(lpSIObj)->fSaveSINail,0);
  545.             }
  546.             
  547.             
  548.             lpallobjs->fPropDlgChanged = FALSE;    // It might have been set by the EN_UPDATE check, so let's reset it here
  549.         }
  550.         return TRUE;
  551.         
  552.     case WM_CTLCOLOREDIT    :
  553.         if ((HWND)lParam != GetDlgItem(hDlg, IDD_SUMMARY_TEMPLATE)) // only change color for the
  554.             break;                                                   // the template
  555.     case WM_CTLCOLORDLG     :
  556.     case WM_CTLCOLORSTATIC  :
  557.         if (hBrushPropDlg == NULL)
  558.             break;
  559.         DeleteObject(hBrushPropDlg);
  560.         if ((hBrushPropDlg = CreateSolidBrush(GetSysColor(COLOR_BTNFACE))) == NULL)
  561.             break;
  562.         SetBkColor ((HDC) wParam, GetSysColor (COLOR_BTNFACE));
  563.         SetTextColor((HDC) wParam, GetSysColor(COLOR_WINDOWTEXT));
  564.         return (INT_PTR) hBrushPropDlg;
  565.         
  566.     case WM_COMMAND:
  567.         
  568.         {
  569.             BOOL fNailChanged = FALSE;
  570.             
  571.             AssertSz( (lpallobjs != NULL && lpallobjs->lpSIObj != NULL),
  572.                 TEXT("Invalid global structure in WM_COMMAND" ));
  573.             
  574.             if ((HIWORD (wParam) == BN_CLICKED) && (LOWORD(wParam) == IDD_SUMMARY_SAVEPREVIEW))
  575.             {
  576.                 GETSINFO(lpallobjs->lpSIObj)->fSaveSINail = !GETSINFO(lpallobjs->lpSIObj)->fSaveSINail;
  577.                 OfficeDirtySIObj (lpallobjs->lpSIObj, TRUE);
  578.                 fNailChanged = TRUE;
  579.             }
  580.             
  581.             if (HIWORD (wParam) == EN_UPDATE
  582.                 ||
  583.                 fNailChanged)
  584.             {
  585.                 lpallobjs->fPropDlgChanged = TRUE;
  586.                 PropSheet_Changed(GetParent(hDlg), hDlg);
  587.             }
  588.             
  589.             break;
  590.         }
  591.         
  592.     case WM_NOTIFY :
  593.         
  594.         switch (((NMHDR FAR *) lParam)->code)
  595.         {
  596.         case PSN_APPLY :
  597.             
  598.             //
  599.             // Save what user entered.
  600.             //
  601.             
  602.             {
  603.                 LPSIOBJ  lpSIObj;       // All SumInfo data
  604.                 LPDSIOBJ lpDSIObj;      // All DocSumInfo data
  605.                 
  606.                 BOOL fSIChanged = FALSE;    // The SumInfo properties have changed
  607.                 BOOL fDSIChanged = FALSE;   // The DocSumInfo properties have changed
  608.                 
  609.                 // SumInfo and DocSumInfo properties.
  610.                 LPPROPVARIANT rgpropvarSumInfo, rgpropvarDocSumInfo;
  611.                 
  612.                 lpSIObj = lpallobjs->lpSIObj;
  613.                 rgpropvarSumInfo = GETSINFO(lpSIObj)->rgpropvar;
  614.                 
  615.                 lpDSIObj = lpallobjs->lpDSIObj;
  616.                 rgpropvarDocSumInfo = GETDSINFO(lpDSIObj)->rgpropvar;
  617.                 
  618.                 fSIChanged |= GetEditValLpsz (&rgpropvarSumInfo[PVSI_TITLE], hDlg, IDD_SUMMARY_TITLE);
  619.                 fSIChanged |= GetEditValLpsz (&rgpropvarSumInfo[PVSI_SUBJECT], hDlg, IDD_SUMMARY_SUBJECT);
  620.                 fSIChanged |= GetEditValLpsz (&rgpropvarSumInfo[PVSI_AUTHOR], hDlg, IDD_SUMMARY_AUTHOR);
  621.                 fSIChanged |= GetEditValLpsz (&rgpropvarSumInfo[PVSI_COMMENTS], hDlg, IDD_SUMMARY_COMMENTS);
  622.                 fSIChanged |= GetEditValLpsz (&rgpropvarSumInfo[PVSI_KEYWORDS], hDlg, IDD_SUMMARY_KEYWORDS);
  623.                 fSIChanged |= GetEditValLpsz (&rgpropvarSumInfo[PVSI_TEMPLATE], hDlg, IDD_SUMMARY_TEMPLATE);
  624.                 fDSIChanged |= GetEditValLpsz (&rgpropvarDocSumInfo[PVDSI_CATEGORY], hDlg, IDD_SUMMARY_CATEGORY);
  625.                 fDSIChanged |= GetEditValLpsz (&rgpropvarDocSumInfo[PVDSI_MANAGER], hDlg, IDD_SUMMARY_MANAGER);
  626.                 fDSIChanged |= GetEditValLpsz (&rgpropvarDocSumInfo[PVDSI_COMPANY], hDlg, IDD_SUMMARY_COMPANY);
  627.                 
  628.                 if (fSIChanged)
  629.                 {
  630.                     OfficeDirtySIObj (lpSIObj, TRUE);
  631.                 }
  632.                 
  633.                 if (fDSIChanged)
  634.                 {
  635.                     OfficeDirtyDSIObj (lpDSIObj, TRUE);
  636.                 }
  637.                 
  638.                 MESSAGE (TEXT("PSN_APPLY - Summary Page"));
  639.                 
  640.                 if (FSumInfoShouldSave (lpSIObj)
  641.                     || FDocSumShouldSave (lpDSIObj)
  642.                     || lpallobjs->fPropDlgChanged )
  643.                 {
  644.                     ApplyChangesBackToFile(hDlg, (BOOL)((PSHNOTIFY*)lParam)->lParam, lpallobjs, itabSUMMARY);
  645.                 }
  646.                 
  647.             }
  648.             return TRUE;
  649.             
  650.         case PSN_QUERYCANCEL:
  651.             if (lpallobjs->fPropDlgChanged && !lpallobjs->fPropDlgPrompted)
  652.                 ISavePropDlgChanges(lpallobjs, hDlg, ((NMHDR FAR *)lParam)->hwndFrom);
  653.             return TRUE;
  654.             
  655.         case PSN_SETACTIVE :
  656.             return TRUE;
  657.             
  658.         } // switch (WM_NOTIFY)
  659.         break;
  660.         
  661.         case WM_CLOSE:
  662.             //
  663.             // This page contains multi-line edit controls, which swallow
  664.             // the ESC key but generat a WM_CLOSE.  We need to pass this
  665.             // message on to our parent (the property sheet) so that it is
  666.             // handled correctly...
  667.             //
  668.             PostMessage( GetParent(hDlg), WM_CLOSE, wParam, lParam );
  669.             break;
  670.             
  671.         case WM_CONTEXTMENU:
  672.             WinHelp((HANDLE)wParam, NULL, HELP_CONTEXTMENU, (DWORD_PTR)rgIdhSummary);
  673.             break;
  674.             
  675.         case WM_HELP:
  676.             WinHelp(((LPHELPINFO)lParam)->hItemHandle, NULL, HELP_WM_HELP, (DWORD_PTR)rgIdhSummary);
  677.             break;
  678.     } // switch (message)
  679.     
  680.     return FALSE;
  681.     
  682. } // FSummaryDlgProc
  683. #endif //_WIN2000_DOCPROP_
  684. ////////////////////////////////////////////////////////////////////////////////
  685. //
  686. // FStatisticsDlgProc
  687. //
  688. // Purpose;
  689. //  Displays the Statistics dialog
  690. //
  691. ////////////////////////////////////////////////////////////////////////////////
  692. #ifndef _WIN2000_DOCPROP_
  693. INT_PTR CALLBACK FStatisticsDlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  694. {
  695.     HWND hWndLV;
  696.     LPSIOBJ lpSIObj;    // All SumInfo data.
  697.     LPDSIOBJ lpDSIObj;  // All DocSumInfo data.
  698.     LPPROPVARIANT rgpropvarSumInfo, rgpropvarDocSumInfo;
  699.     
  700.     HANDLE hFile;
  701.     FILETIME ftTime;
  702.     DWORD dwT;
  703.     BOOL fListData;    // Did we stick some data in the listview??
  704.     
  705.     switch (message)
  706.     {
  707.     case WM_INITDIALOG :
  708.         {
  709.             PROPSHEETPAGE *ppspDlg = (PROPSHEETPAGE *) lParam;
  710.             LPALLOBJS lpallobjs = (LPALLOBJS)ppspDlg->lParam;
  711.             
  712.             // Page does not do apply so don't worry
  713.             // PropPageInit(lpallobjs, itabSTATISTICS);
  714.             
  715.             lpSIObj = lpallobjs->lpSIObj;    // Get the summary object.
  716.             lpDSIObj = lpallobjs->lpDSIObj;  // Get the doc sum. object.
  717.             
  718.             if (lpSIObj->m_lpData == NULL ||
  719.                 lpDSIObj->m_lpData == NULL)
  720.             {
  721.                 MESSAGE (TEXT("Invalid SumInfo or DocSumInfo object"));
  722.                 return FALSE;
  723.             }
  724.             
  725.             rgpropvarSumInfo = GETSINFO(lpSIObj)->rgpropvar;
  726.             rgpropvarDocSumInfo = GETSINFO(lpDSIObj)->rgpropvar;
  727.             
  728.             // Let the app update the stats if they provided a callback
  729.             if (((LPSINFO) ((LPOFFICESUMINFO) lpSIObj)->m_lpData)->lpfnFUpdateStats != NULL)
  730.                 (*(((LPSINFO) ((LPOFFICESUMINFO) lpSIObj)->m_lpData)->lpfnFUpdateStats))(
  731.                 GetFocus(),
  732.                 lpSIObj, lpDSIObj);
  733.             
  734.             hWndLV = GetDlgItem(hDlg, IDD_STATISTICS_LISTVIEW);
  735.             InitListView (hWndLV, iszVAL, rgszStatHeadings, FALSE);
  736.             
  737.             // Last saved by
  738.             
  739.             if (rgpropvarSumInfo[ PVSI_LASTAUTHOR ].vt == VT_LPTSTR)
  740.             {
  741.                 SendDlgItemMessage
  742.                     (hDlg, IDD_STATISTICS_LASTSAVEBY, WM_SETTEXT, 0,
  743.                     (LPARAM) rgpropvarSumInfo[ PVSI_LASTAUTHOR ].pszVal);
  744.             }
  745.             
  746.             
  747.             // Revision #
  748.             
  749.             if (rgpropvarSumInfo[ PVSI_REVNUMBER ].vt == VT_LPTSTR)
  750.             {
  751.                 SendDlgItemMessage
  752.                     (hDlg, IDD_STATISTICS_REVISION, WM_SETTEXT, 0,
  753.                     (LPARAM) rgpropvarSumInfo[ PVSI_REVNUMBER ].pszVal);
  754.             }
  755.             
  756.             
  757.             fListData = FALSE;
  758.             if (rgpropvarSumInfo[ PVSI_PAGECOUNT ].vt == VT_I4)
  759.             {
  760.                 AddItemToListView (hWndLV, rgpropvarSumInfo[ PVSI_PAGECOUNT ].lVal,
  761.                     rgszStats[iszPAGES], FALSE);
  762.                 fListData = TRUE;
  763.             }
  764.             
  765.             if (rgpropvarDocSumInfo[ PVDSI_SLIDECOUNT ].vt == VT_I4)
  766.             {
  767.                 AddItemToListView (hWndLV, rgpropvarDocSumInfo[ PVDSI_SLIDECOUNT ].lVal,
  768.                     rgszStats[iszSLIDES], FALSE);
  769.                 fListData = TRUE;
  770.             }
  771.             
  772.             if (rgpropvarDocSumInfo[ PVDSI_PARACOUNT ].vt == VT_I4)
  773.             {
  774.                 AddItemToListView (hWndLV, rgpropvarDocSumInfo[ PVDSI_PARACOUNT ].lVal,
  775.                     rgszStats[iszPARA], FALSE);
  776.                 fListData = TRUE;
  777.             }
  778.             
  779.             if (rgpropvarDocSumInfo[ PVDSI_LINECOUNT ].vt == VT_I4)
  780.             {
  781.                 AddItemToListView (hWndLV, rgpropvarDocSumInfo[ PVDSI_LINECOUNT ].lVal,
  782.                     rgszStats[iszLINES], FALSE);
  783.                 fListData = TRUE;
  784.             }
  785.             
  786.             if (rgpropvarSumInfo[ PVSI_WORDCOUNT ].vt == VT_I4)
  787.             {
  788.                 AddItemToListView (hWndLV, rgpropvarSumInfo[ PVSI_WORDCOUNT ].lVal,
  789.                     rgszStats[iszWORDS], FALSE);
  790.                 fListData = TRUE;
  791.             }
  792.             
  793.             if (rgpropvarSumInfo[ PVSI_CHARCOUNT ].vt == VT_I4)
  794.             {
  795.                 AddItemToListView (hWndLV, rgpropvarSumInfo[ PVSI_CHARCOUNT ].lVal,
  796.                     rgszStats[iszCHARS], FALSE);
  797.                 fListData = TRUE;
  798.             }
  799.             
  800.             if (rgpropvarDocSumInfo[ PVDSI_BYTECOUNT ].vt == VT_I4)
  801.             {
  802.                 AddItemToListView (hWndLV, rgpropvarDocSumInfo[ PVDSI_BYTECOUNT ].lVal,
  803.                     rgszStats[iszBYTES], FALSE);
  804.                 fListData = TRUE;
  805.             }
  806.             
  807.             if (rgpropvarDocSumInfo[ PVDSI_NOTECOUNT ].vt == VT_I4)
  808.             {
  809.                 AddItemToListView (hWndLV, rgpropvarDocSumInfo[ PVDSI_NOTECOUNT ].lVal,
  810.                     rgszStats[iszNOTES], FALSE);
  811.                 fListData = TRUE;
  812.             }
  813.             
  814.             if (rgpropvarDocSumInfo[ PVDSI_HIDDENCOUNT ].vt == VT_I4)
  815.             {
  816.                 AddItemToListView (hWndLV, rgpropvarDocSumInfo[ PVDSI_HIDDENCOUNT ].lVal,
  817.                     rgszStats[iszHIDDENSLIDES], FALSE);
  818.                 fListData = TRUE;
  819.             }
  820.             
  821.             if (rgpropvarDocSumInfo[ PVDSI_MMCLIPCOUNT ].vt == VT_I4)
  822.             {
  823.                 AddItemToListView (hWndLV, rgpropvarDocSumInfo[ PVDSI_MMCLIPCOUNT ].lVal,
  824.                     rgszStats[iszMMCLIPS], FALSE);
  825.                 fListData = TRUE;
  826.             }
  827.             
  828.             if (rgpropvarDocSumInfo[ PVDSI_PRESFORMAT ].vt == VT_LPTSTR)
  829.             {
  830.                 AddItemToListView (hWndLV, (DWORD_PTR) rgpropvarDocSumInfo[ PVDSI_PRESFORMAT ].pszVal,
  831.                     rgszStats[iszFORMAT], TRUE);
  832.                 fListData = TRUE;
  833.             }
  834.             
  835.             if (!fListData)
  836.             {
  837.                 ShowWindow(GetDlgItem(hDlg, IDD_LINE_2), SW_HIDE);
  838.                 ShowWindow(GetDlgItem(hDlg, IDD_STATISTICS_LVLABEL), SW_HIDE);
  839.                 ShowWindow(hWndLV, SW_HIDE);
  840.                 hWndLV = NULL;
  841.             }
  842.             
  843.             if (!lpallobjs->fFiledataInit)
  844.             {
  845.                 hFile = FindFirstFile(lpallobjs->szPath, &lpallobjs->filedata);
  846.                 lpallobjs->fFiledataInit = TRUE;
  847.                 if (hFile != INVALID_HANDLE_VALUE)
  848.                 {
  849.                     FindClose(hFile);
  850.                     lpallobjs->fFindFileSuccess = TRUE;
  851.                 }
  852.             }
  853.             
  854.             if (lpallobjs->fFindFileSuccess)
  855.             {
  856.                 // Last Access
  857.                 PrintTimeInDlg (hDlg, IDD_STATISTICS_ACCESSED, &(lpallobjs->filedata.ftLastAccessTime));
  858.                 
  859.                 // Last modified
  860.                 PrintTimeInDlg (hDlg, IDD_STATISTICS_CHANGED, &(lpallobjs->filedata.ftLastWriteTime));
  861.             }
  862.             
  863.             
  864.             // Create Time
  865.             if (rgpropvarSumInfo[ PVSI_CREATE_DTM ].vt == VT_FILETIME)
  866.             {
  867.                 PrintTimeInDlg(hDlg, IDD_STATISTICS_CREATED,
  868.                     &rgpropvarSumInfo[ PVSI_CREATE_DTM ].filetime);
  869.             }
  870.             
  871.             
  872.             // Last Printed Time
  873.             if (rgpropvarSumInfo[ PVSI_LASTPRINTED ].vt == VT_FILETIME)
  874.             {
  875.                 PrintTimeInDlg(hDlg, IDD_STATISTICS_LASTPRINT,
  876.                     &rgpropvarSumInfo[ PVSI_LASTPRINTED ].filetime);
  877.             }
  878.             
  879.             // Total Edit Time
  880.             // If we are not allowing time tracking display 0 minutes
  881.             if (GETSINFO(lpSIObj)->fNoTimeTracking)
  882.             {
  883.                 ftTime.dwLowDateTime = 0;
  884.                 ftTime.dwHighDateTime = 0;
  885.                 PrintEditTimeInDlg(hDlg, &ftTime);
  886.             }
  887.             else if (rgpropvarSumInfo[ PVSI_EDITTIME ].vt == VT_FILETIME)
  888.             {
  889.                 PrintEditTimeInDlg(hDlg, &rgpropvarSumInfo[ PVSI_EDITTIME ].filetime);
  890.             }
  891.             
  892.             //        lpallobjs->fPropDlgChanged = FALSE;
  893.       }
  894.       return TRUE;
  895.       
  896.     case WM_CTLCOLORBTN     :
  897.     case WM_CTLCOLOREDIT    :
  898.     case WM_CTLCOLORDLG     :
  899.     case WM_CTLCOLORSTATIC  :
  900.         if (hBrushPropDlg == NULL)
  901.             break;
  902.         DeleteObject(hBrushPropDlg);
  903.         if ((hBrushPropDlg = CreateSolidBrush(GetSysColor(COLOR_BTNFACE))) == NULL)
  904.             break;
  905.         SetBkColor ((HDC) wParam, GetSysColor (COLOR_BTNFACE));
  906.         SetTextColor((HDC) wParam, GetSysColor(COLOR_WINDOWTEXT));
  907.         return (INT_PTR) hBrushPropDlg;
  908.         
  909.     case WM_SYSCOLORCHANGE:
  910.         hWndLV = GetDlgItem(hDlg, IDD_STATISTICS_LISTVIEW);
  911.         PostMessage(hWndLV, WM_SYSCOLORCHANGE, wParam, lParam);
  912.         return TRUE;
  913.         break;
  914.         
  915.     case WM_NOTIFY :
  916.         
  917.         switch (((NMHDR FAR *) lParam)->code)
  918.         {
  919.         case PSN_SETACTIVE :
  920.             return TRUE;
  921.             
  922.         case PSN_RESET:
  923.         case PSN_APPLY:
  924.             MESSAGE (TEXT("PSN_APPLY - Statistics Page"));
  925.             
  926.             return TRUE;
  927.             
  928.         } // switch
  929.         break;
  930.         
  931.         case WM_CONTEXTMENU:
  932.             WinHelp((HANDLE)wParam, NULL, HELP_CONTEXTMENU, (DWORD_PTR)rgIdhStatistics);
  933.             break;
  934.             
  935.         case WM_HELP:
  936.             WinHelp(((LPHELPINFO)lParam)->hItemHandle, NULL, HELP_WM_HELP, (DWORD_PTR)rgIdhStatistics);
  937.             break;
  938.     } // switch
  939.     
  940.     return FALSE;
  941.     
  942. } // FStatisticsDlgProc
  943. #endif //_WIN2000_DOCPROP_
  944. ////////////////////////////////////////////////////////////////////////////////
  945. //
  946. // FContentsDlgProc
  947. //
  948. // Purpose:
  949. //  Display the contents dialog
  950. //
  951. ////////////////////////////////////////////////////////////////////////////////
  952. #ifndef _WIN2000_DOCPROP_
  953. INT_PTR CALLBACK FContentsDlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  954. {
  955.     LPDSIOBJ lpDSIObj;                  // All DocSumInfo data.
  956.     LPPROPVARIANT rgpropvarDocSumInfo;  // Just the DocSumInfo properties.
  957.     
  958.     switch (message)
  959.     {
  960.     case WM_INITDIALOG :
  961.         {
  962.             BOOL fInitDialogSuccess = TRUE;
  963.             PROPSHEETPAGE *ppspDlg = (PROPSHEETPAGE *)lParam;
  964.             SHORT cT;
  965.             LRESULT lError;
  966.             TCHAR *psz;
  967.             TCHAR ch;
  968.             
  969.             ULONG cHeadings;    // Number of document headings
  970.             ULONG cDocParts;    // Total count of document parts.
  971.             
  972.             LPPROPVARIANT rgpropvarHeadings;    // The Variant|Vector of heading pairs
  973.             LPTSTR        *rglptstrDocParts;    // The document parts.
  974.             
  975.             ULONG ulHeadingIndex;       // Index into rgpropvarHeadings
  976.             ULONG ulTotalDocPartIndex;  // Index into rglptstrDocParts
  977.             ULONG ulSubDocPartIndex;    // Index into rglptstrDocParts for the current heading
  978.             
  979.             ULONG  cbDocPart = 0;           // # bytes in a particular docpart.
  980.             LPTSTR tszDocumentPart = NULL;  // One DocPart with a pre-pending tab.
  981.             
  982.             lpDSIObj = ((LPALLOBJS)ppspDlg->lParam)->lpDSIObj;  // Get the document sum. object.
  983.             
  984.             // Validate our objects.
  985.             
  986.             if (lpDSIObj == NULL || lpDSIObj->m_lpData == NULL)
  987.                 return FALSE;
  988.             
  989.             // Get to the DocSumInfo properties.
  990.             
  991.             rgpropvarDocSumInfo = GETDSINFO(lpDSIObj)->rgpropvar;
  992.             
  993.             // See if we have any headings.
  994.             
  995.             if (rgpropvarDocSumInfo[ PVDSI_HEADINGPAIR ].vt != (VT_VECTOR | VT_VARIANT))
  996.             {
  997.                 // Nothing to display.
  998.                 return FALSE;
  999.             }
  1000.             
  1001.             // Get the Heading-Pair array and count.  Validate the size of the array.
  1002.             
  1003.             cHeadings = rgpropvarDocSumInfo[ PVDSI_HEADINGPAIR ].capropvar.cElems;
  1004.             rgpropvarHeadings = rgpropvarDocSumInfo[ PVDSI_HEADINGPAIR ].capropvar.pElems;
  1005.             
  1006.             if (cHeadings == 0)
  1007.             {
  1008.                 goto ExitCaseWM_INITDIALOG;
  1009.             }
  1010.             
  1011.             if (cHeadings & 0x1)
  1012.             {
  1013.                 // This is an invalid array; the elements always come in (heading,count) pairs,
  1014.                 // so there should be an even number of elements in the array.
  1015.                 
  1016.                 MESSAGE (TEXT("Invalid Headings array (should be an even number of elements)"));
  1017.                 goto ExitCaseWM_INITDIALOG;
  1018.             }
  1019.             
  1020.             
  1021.             // Get the DocParts array and its size.  All elements of this array are LPTSTRs.
  1022.             // Note that this array need not exist.
  1023.             
  1024.             cDocParts = 0;
  1025.             if (rgpropvarDocSumInfo[ PVDSI_DOCPARTS ].vt == (VT_VECTOR | VT_LPTSTR))
  1026.             {
  1027.                 rglptstrDocParts = (LPTSTR*) rgpropvarDocSumInfo[ PVDSI_DOCPARTS ].calpstr.pElems;
  1028.                 cDocParts = rgpropvarDocSumInfo[ PVDSI_DOCPARTS ].calpstr.cElems;
  1029.             }
  1030.             
  1031.             // Loop through the Heading-Pair array.  For each heading, we'll write it
  1032.             // to the list box, and then use the associated count to write Document Parts
  1033.             // to the list box.  We'll stop when we've processed the array, or when
  1034.             // fInitDialogSuccess goes FALSE.
  1035.             
  1036.             ulTotalDocPartIndex = 0;
  1037.             for (ulHeadingIndex = 0;
  1038.             (ulHeadingIndex < cHeadings) && fInitDialogSuccess;
  1039.             ulHeadingIndex+=2)
  1040.             {
  1041.                 // Verify that the next two elements in the Heading-Pair array are
  1042.                 // a string and a Long.
  1043.                 
  1044.                 if (rgpropvarHeadings[ ulHeadingIndex ].vt != VT_LPTSTR
  1045.                     ||
  1046.                     rgpropvarHeadings[ ulHeadingIndex + 1 ].vt != VT_I4)
  1047.                 {
  1048.                     MESSAGE (TEXT("Invalid Heading Pair type"));
  1049.                     fInitDialogSuccess = FALSE;
  1050.                     break;
  1051.                 }
  1052.                 
  1053.                 // Write the Heading to the list box.
  1054.                 
  1055.                 lError = SendDlgItemMessage (
  1056.                     hDlg, IDD_CONTENTS_LISTBOX, LB_ADDSTRING, (WPARAM) 0,
  1057.                     (LPARAM) rgpropvarHeadings[ ulHeadingIndex ].pszVal );
  1058.                 
  1059.                 if (lError == LB_ERR || lError == LB_ERRSPACE)
  1060.                 {
  1061.                     MESSAGE(TEXT("Could not write to list box"));
  1062.                     fInitDialogSuccess = FALSE;
  1063.                     break;
  1064.                 }
  1065.                 
  1066.                 // Verify that the DocParts we've written so far, plus those we're about
  1067.                 // to write, don't exceed the total in the DocParts array.
  1068.                 
  1069.                 if (ulTotalDocPartIndex + rgpropvarHeadings[ ulHeadingIndex + 1 ].lVal
  1070.                     > cDocParts)
  1071.                 {
  1072.                     MESSAGE (TEXT("Invalid doc-part count for heading"));
  1073.                     fInitDialogSuccess = FALSE;
  1074.                     break;
  1075.                 }
  1076.                 
  1077.                 // Now loop through the document parts that are associated with this
  1078.                 // heading.  We'll insert a tab character in front of each string
  1079.                 // so that the display looks better.  We'll stop when we've processed
  1080.                 // all the DocParts under this heading, or when fInitDialogSuccess goes
  1081.                 // FALSE;
  1082.                 
  1083.                 for (ulSubDocPartIndex = ulTotalDocPartIndex;
  1084.                 fInitDialogSuccess
  1085.                     && (ulSubDocPartIndex
  1086.                     < ulTotalDocPartIndex + rgpropvarHeadings[ ulHeadingIndex + 1 ].lVal);
  1087.                 ulSubDocPartIndex++)
  1088.                 {
  1089.                     
  1090.                     // Determine how big the DocumentPart string is, including a NULL
  1091.                     // terminator, and including a tab character that we're going to insert.
  1092.                     
  1093.                     cbDocPart  // Count the characters.
  1094. #ifdef UNICODE
  1095.                         = CchTszLen (rglptstrDocParts[ ulSubDocPartIndex ]) + 2;
  1096. #else
  1097.                     = CchAnsiSzLen (rglptstrDocParts[ ulSubDocPartIndex ]) + 2;
  1098. #endif
  1099.                     cbDocPart *= sizeof(TCHAR);    // Convert to a *byte* count.
  1100.                     
  1101.                     // Alloc a buffer which will hold a tab character followed by the DocPart string.
  1102.                     // Since there's no easy way to add cleanup code for this case block,
  1103.                     // we must ensure that we free this buffer before any break could possibly
  1104.                     // occur.
  1105.                     
  1106.                     tszDocumentPart = PvMemAlloc (cbDocPart);
  1107.                     
  1108.                     if (tszDocumentPart == NULL)
  1109.                     {
  1110.                         AssertSz (0, TEXT("Couldn't alloc memory for doc-part display"));
  1111.                         fInitDialogSuccess = FALSE;
  1112.                         break;
  1113.                     }
  1114.                     
  1115.                     // Put the tab in the new string, followed by the DocPart string.
  1116.                     
  1117.                     *tszDocumentPart = TEXT('t');
  1118.                     PbMemCopy(&tszDocumentPart[1],
  1119.                         rglptstrDocParts[ ulSubDocPartIndex ],
  1120.                         cbDocPart - sizeof(TCHAR)); // Subtract the size of the tab
  1121.                     
  1122.                     // Write the result to the list box, and free the temporary string.
  1123.                     
  1124.                     lError = SendDlgItemMessage (
  1125.                         hDlg, IDD_CONTENTS_LISTBOX, LB_ADDSTRING, (WPARAM) 0,
  1126.                         (LPARAM) tszDocumentPart);
  1127.                     
  1128.                     if (tszDocumentPart != NULL)
  1129.                     {
  1130.                         VFreeMemP (tszDocumentPart, cbDocPart);
  1131.                         tszDocumentPart = NULL;
  1132.                         cbDocPart = 0;
  1133.                     }
  1134.                     
  1135.                     if (lError == LB_ERR || lError == LB_ERRSPACE)
  1136.                     {
  1137.                         AssertSz (0, TEXT("Could not write to list box"));
  1138.                         fInitDialogSuccess = FALSE;
  1139.                         break;
  1140.                     }
  1141.                     
  1142.                 }   // for (ulSubDocPartIndex = ulTotalDocPartIndex; ...
  1143.                 
  1144.                 // Add the cont for all the doc-parts that we just displayed
  1145.                 // to the total.
  1146.                 
  1147.                 ulTotalDocPartIndex = ulSubDocPartIndex;
  1148.                 
  1149.             }   // for (ulHeadingIndex = 0; ulHeadingIndex < cHeadings; ulHeadingIndex++)
  1150.             
  1151.             fInitDialogSuccess = TRUE;
  1152.             
  1153. ExitCaseWM_INITDIALOG:
  1154.             
  1155.             // Now that the headings and document-parts are in the dialog,
  1156.             // we don't need to hold on to them any longer.
  1157.             
  1158.             PropVariantClear (&GETDSINFO(lpDSIObj)->rgpropvar[PVDSI_HEADINGPAIR]);
  1159.             PropVariantClear (&GETDSINFO(lpDSIObj)->rgpropvar[PVDSI_DOCPARTS]);
  1160.             
  1161.             return fInitDialogSuccess;
  1162.             
  1163.         }   // end - case WM_INITDIALOG
  1164.         
  1165.     case WM_CTLCOLORBTN     :
  1166.     case WM_CTLCOLORDLG     :
  1167.     case WM_CTLCOLORSTATIC  :
  1168.         if (hBrushPropDlg == NULL)
  1169.             break;
  1170.         DeleteObject(hBrushPropDlg);
  1171.         if ((hBrushPropDlg = CreateSolidBrush(GetSysColor(COLOR_BTNFACE))) == NULL)
  1172.             break;
  1173.         SetBkColor ((HDC) wParam, GetSysColor (COLOR_BTNFACE));
  1174.         SetTextColor((HDC) wParam, GetSysColor(COLOR_WINDOWTEXT));
  1175.         return (INT_PTR) hBrushPropDlg;
  1176.         
  1177.     case WM_NOTIFY :
  1178.         
  1179.         switch (((NMHDR FAR *) lParam)->code)
  1180.         {
  1181.         case PSN_SETACTIVE :
  1182.             return TRUE;
  1183.         case PSN_RESET:
  1184.         case PSN_APPLY:
  1185.             MESSAGE (TEXT("PSN_APPLY - Contents Page"));
  1186.             return TRUE;
  1187.             
  1188.         } // switch
  1189.         break;
  1190.         
  1191.         case WM_CONTEXTMENU:
  1192.             WinHelp((HANDLE)wParam, NULL, HELP_CONTEXTMENU, (DWORD_PTR)rgIdhContents);
  1193.             break;
  1194.             
  1195.         case WM_HELP:
  1196.             WinHelp(((LPHELPINFO)lParam)->hItemHandle, NULL, HELP_WM_HELP, (DWORD_PTR)rgIdhContents);
  1197.             break;
  1198.     } // switch
  1199.     
  1200.     return FALSE;
  1201.     
  1202.     
  1203. } // FContentsDlgProc
  1204. #endif // _WIN2000_DOCPROP_
  1205. int  gOKButtonID;  // need this to store the ID of the OK button, since it's not in the dlg template
  1206. ////////////////////////////////////////////////////////////////////////////////
  1207. //
  1208. // FCustomDlgProc
  1209. //
  1210. // Purpose:
  1211. //  Custom tab control
  1212. //
  1213. ////////////////////////////////////////////////////////////////////////////////
  1214. INT_PTR CALLBACK FCustomDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  1215. {
  1216.     LPALLOBJS lpallobjs = (LPALLOBJS)GetWindowLongPtr(hDlg, DWLP_USER);
  1217.     
  1218.     switch (message)
  1219.     {
  1220.     case WM_INITDIALOG:
  1221.         {
  1222.             PROPSHEETPAGE *ppspDlg = (PROPSHEETPAGE *) lParam;
  1223.             int irg;
  1224.             HICON hIcon, hInvIcon;
  1225.             
  1226.             lpallobjs = (LPALLOBJS)ppspDlg->lParam;
  1227.             
  1228.             PropPageInit(lpallobjs, itabCUSTOM);
  1229.             
  1230.             SetWindowLongPtr(hDlg, DWLP_USER, ppspDlg->lParam);
  1231.             gOKButtonID = LOWORD(SendMessage(hDlg, DM_GETDEFID, 0L, 0L));
  1232.             
  1233.             AssertSz ((sizeof(NUM) == (sizeof(FILETIME))), TEXT("Ok, who changed base type sizes?"));
  1234.             
  1235.             //
  1236.             // Fill out the Name dropdown
  1237.             //
  1238.             for (irg = 0; irg < NUM_BUILTIN_CUSTOM_NAMES; ++irg)
  1239.             {
  1240.                 if (!CchGetString( idsCustomName1+ irg,
  1241.                     lpallobjs->CDP_sz,
  1242.                     sizeof(lpallobjs->CDP_sz))
  1243.                     )
  1244.                 {
  1245.                     return(FALSE);
  1246.                 }
  1247.                 SendDlgItemMessage(hDlg, IDD_CUSTOM_NAME, CB_ADDSTRING, 0, (LPARAM)lpallobjs->CDP_sz);
  1248.             }
  1249.             
  1250.             //
  1251.             // Fill out the type drop-down & select the text type
  1252.             //
  1253.             for (irg = 0; irg <= iszBOOL; irg++)
  1254.             {
  1255.                 SendDlgItemMessage(hDlg, IDD_CUSTOM_TYPE, CB_ADDSTRING, 0, (LPARAM) rgszTypes[irg]);
  1256.             }
  1257.             
  1258.             ResetTypeControl (hDlg, IDD_CUSTOM_TYPE, &lpallobjs->CDP_iszType);
  1259.             
  1260.             //
  1261.             // Set the link checkbox to be off.
  1262.             //
  1263.             lpallobjs->CDP_fLink = FALSE;
  1264.             
  1265.             SendDlgItemMessage( hDlg,
  1266.                 IDD_CUSTOM_LINK,
  1267.                 BM_SETCHECK,
  1268.                 (WPARAM) lpallobjs->CDP_fLink,
  1269.                 0
  1270.                 );
  1271. #ifndef __CUSTOM_LINK_ENABLED__
  1272.             ShowWindow( GetDlgItem( hDlg, IDD_CUSTOM_LINK ), SW_HIDE );
  1273. #endif  __CUSTOM_LINK_ENABLED__
  1274.             
  1275.             SendDlgItemMessage( hDlg,
  1276.                 IDD_CUSTOM_VALUETEXT,
  1277.                 WM_SETTEXT,
  1278.                 0,
  1279.                 (LPARAM) rgszValue[iszVALUE]
  1280.                 );
  1281.             
  1282.             //
  1283.             // Hang on to the window handle of the value edit control & others
  1284.             //
  1285.             lpallobjs->CDP_hWndVal = GetDlgItem (hDlg, IDD_CUSTOM_VALUE);
  1286.             lpallobjs->CDP_hWndName = GetDlgItem (hDlg, IDD_CUSTOM_NAME);
  1287.             lpallobjs->CDP_hWndLinkVal = GetDlgItem (hDlg, IDD_CUSTOM_LINKVALUE);
  1288.             lpallobjs->CDP_hWndValText = GetDlgItem (hDlg, IDD_CUSTOM_VALUETEXT);
  1289.             lpallobjs->CDP_hWndBoolTrue = GetDlgItem (hDlg, IDD_CUSTOM_BOOLTRUE);
  1290.             lpallobjs->CDP_hWndBoolFalse = GetDlgItem (hDlg, IDD_CUSTOM_BOOLFALSE);
  1291.             lpallobjs->CDP_hWndGroup = GetDlgItem (hDlg, IDD_CUSTOM_GBOX);
  1292.             lpallobjs->CDP_hWndAdd = GetDlgItem (hDlg, IDD_CUSTOM_ADD);
  1293.             lpallobjs->CDP_hWndDelete = GetDlgItem (hDlg, IDD_CUSTOM_DELETE);
  1294.             lpallobjs->CDP_hWndType = GetDlgItem (hDlg, IDD_CUSTOM_TYPE);
  1295.             lpallobjs->CDP_hWndCustomLV = GetDlgItem(hDlg, IDD_CUSTOM_LISTVIEW);
  1296.             InitListView (lpallobjs->CDP_hWndCustomLV, iszTYPE, rgszHeadings, TRUE);
  1297.             
  1298.             //
  1299.             // Initially disable the Add & Delete buttons
  1300.             //
  1301.             EnableWindow (lpallobjs->CDP_hWndAdd, FALSE);
  1302.             EnableWindow (lpallobjs->CDP_hWndDelete, FALSE);
  1303.             lpallobjs->CDP_fAdd = TRUE;
  1304.             
  1305.             //
  1306.             // Don't let the user enter too much text
  1307.             // If you change this value, you must change the buffer
  1308.             // size (szDate) in FConvertDate
  1309.             //
  1310.             SendMessage (lpallobjs->CDP_hWndVal, EM_LIMITTEXT, BUFMAX-1, 0);
  1311.             SendMessage (lpallobjs->CDP_hWndName, EM_LIMITTEXT, BUFMAX-1, 0);
  1312.             
  1313.             //
  1314.             // Add the link icon to the image list
  1315.             //
  1316.             hIcon = LoadIcon (g_hmodThisDll, MAKEINTRESOURCE (IDD_LINK_ICON));
  1317.             hInvIcon = LoadIcon (g_hmodThisDll, MAKEINTRESOURCE (IDD_INVLINK_ICON));
  1318.             if (hIcon != NULL)
  1319.             {
  1320.                 lpallobjs->CDP_hImlS = ListView_GetImageList( lpallobjs->CDP_hWndCustomLV, TRUE );
  1321.                 giLinkIcon = MsoImageList_ReplaceIcon( lpallobjs->CDP_hImlS, -1, hIcon );
  1322.                 Assert ((giLinkIcon != -1));
  1323.                 
  1324.                 giInvLinkIcon = MsoImageList_ReplaceIcon (lpallobjs->CDP_hImlS, -1, hInvIcon);
  1325.                 Assert ((giInvLinkIcon != -1));
  1326.             }
  1327.             else
  1328.             {
  1329.                 DebugSz (TEXT("Icon load failed"));
  1330.             }
  1331.             
  1332.             //
  1333.             // Make a temporary copy of the custom data
  1334.             //
  1335.             FMakeTmpUDProps (lpallobjs->lpUDObj);
  1336.             
  1337.             //
  1338.             // Fill in the list view box with any data from the object
  1339.             //
  1340.             PopulateUDListView (lpallobjs->CDP_hWndCustomLV, lpallobjs->lpUDObj);
  1341.             
  1342.             //
  1343.             // See if the client supports links - turn off checkbox if they don't
  1344.             //
  1345.             lpallobjs->CDP_cLinks =
  1346. #ifdef __CUSTOM_LINK_ENABLED__
  1347.                 (lpallobjs->lpfnDwQueryLinkData != NULL)                      ?
  1348.                 (*lpallobjs->lpfnDwQueryLinkData) (QLD_CLINKS, 0, NULL, NULL) :
  1349. #endif __CUSTOM_LINK_ENABLED__
  1350.             0;
  1351.             if (!lpallobjs->CDP_cLinks)
  1352.             {
  1353.                 EnableWindow (GetDlgItem (hDlg, IDD_CUSTOM_LINK), FALSE);
  1354.                 EnableWindow (lpallobjs->CDP_hWndLinkVal, FALSE);
  1355.             }
  1356.             
  1357.             //        lpallobjs->fPropDlgChanged = FALSE;
  1358.             //      fItemSel = FALSE;
  1359.             return TRUE;
  1360.             break;
  1361.       }
  1362.       
  1363.     case WM_CTLCOLORBTN     :
  1364.     case WM_CTLCOLORDLG     :
  1365.     case WM_CTLCOLORSTATIC  :
  1366.         if (hBrushPropDlg == NULL)
  1367.             break;
  1368.         DeleteObject(hBrushPropDlg);
  1369.         if ((hBrushPropDlg = CreateSolidBrush(GetSysColor(COLOR_BTNFACE))) == NULL)
  1370.             break;
  1371.         SetBkColor ((HDC) wParam, GetSysColor (COLOR_BTNFACE));
  1372.         SetTextColor((HDC) wParam, GetSysColor(COLOR_WINDOWTEXT));
  1373.         return (INT_PTR) hBrushPropDlg;
  1374.         
  1375.     case WM_SYSCOLORCHANGE:
  1376.         PostMessage(lpallobjs->CDP_hWndCustomLV, WM_SYSCOLORCHANGE, wParam, lParam);
  1377.         return TRUE;
  1378.         break;
  1379.         
  1380.         //
  1381.         // This message is posted when ever the user does something with the
  1382.         // Name field.  That allows the system to finish what they are doing
  1383.         // and fill in the edit field if they have to.  See bug 2820.
  1384.         //
  1385.     case WM_USER+0x1000:
  1386.         if (!(lpallobjs->CDP_fLink && (lpallobjs->lpfnDwQueryLinkData == NULL)))
  1387.         {
  1388.             lpallobjs->CDP_iszType = (int)SendMessage (lpallobjs->CDP_hWndType, CB_GETCURSEL, 0, 0);
  1389.             FSetupAddButton (lpallobjs->CDP_iszType, lpallobjs->CDP_fLink, &lpallobjs->CDP_fAdd, lpallobjs->CDP_hWndAdd, lpallobjs->CDP_hWndVal, lpallobjs->CDP_hWndName, hDlg);
  1390.             if (FAllocAndGetValLpstz (hDlg, IDD_CUSTOM_NAME, &glpstzName))
  1391.             {
  1392.                 LPUDPROP lpudp = LpudpropFindMatchingName (lpallobjs->lpUDObj, (LPTSTR)PSTR (glpstzName));
  1393.                 if (lpudp != NULL)
  1394.                 {
  1395.                     if (lpallobjs->CDP_fAdd)
  1396.                     {
  1397.                         SendMessage (lpallobjs->CDP_hWndAdd, WM_SETTEXT, 0, (LPARAM) rgszAdd[iszMODIFY]);
  1398.                         lpallobjs->CDP_fAdd = FALSE;
  1399.                     }
  1400.                 }
  1401.             }
  1402.             EnableWindow(lpallobjs->CDP_hWndDelete, FALSE);   // If the user touches the Name field, disable Delete button
  1403.             // Are we showing an invalid link?
  1404.             if (lpallobjs->CDP_fLink && !IsWindowEnabled(GetDlgItem(hDlg,IDD_CUSTOM_LINK)))
  1405.             {
  1406.                 // Turn off the link checkbox
  1407.                 lpallobjs->CDP_fLink = FALSE;
  1408.                 SendDlgItemMessage (hDlg, IDD_CUSTOM_LINK, BM_SETCHECK, (WPARAM) lpallobjs->CDP_fLink, 0);
  1409.                 if (lpallobjs->CDP_cLinks)   // Could be that the app is allowing links
  1410.                     EnableWindow (GetDlgItem (hDlg, IDD_CUSTOM_LINK), TRUE);
  1411.                 // Clear the value window
  1412.                 ClearEditControl (lpallobjs->CDP_hWndVal, 0);
  1413.                 FSwapControls (lpallobjs->CDP_hWndVal, lpallobjs->CDP_hWndLinkVal, lpallobjs->CDP_hWndBoolTrue, lpallobjs->CDP_hWndBoolFalse,
  1414.                     lpallobjs->CDP_hWndGroup, lpallobjs->CDP_hWndType, lpallobjs->CDP_hWndValText, FALSE, FALSE);
  1415.             }
  1416.         }
  1417.         return(TRUE);
  1418.         break;
  1419.         
  1420.     case WM_COMMAND :
  1421.         switch (HIWORD (wParam))
  1422.         {
  1423.         case BN_CLICKED :
  1424.             switch (LOWORD (wParam))
  1425.             {
  1426.             case IDD_CUSTOM_ADD :
  1427.                 if (FGetCustomPropFromDlg(lpallobjs, hDlg))
  1428.                 {
  1429.                     PropSheet_Changed(GetParent(hDlg), hDlg);
  1430.                 }
  1431.                 
  1432.                 return(FALSE);     // return 0 'cuz we process the message
  1433.                 break;
  1434.                 
  1435.             case IDD_CUSTOM_DELETE :
  1436.                 //              Assert (fItemSel);
  1437.                 
  1438.                 //              fItemSel = FALSE;                 // We're about to delete it!
  1439.                 DeleteItem (lpallobjs->lpUDObj, lpallobjs->CDP_hWndCustomLV, lpallobjs->CDP_iItem, lpallobjs->CDP_sz);
  1440.                 
  1441.                 // Turn off the link checkbox if it was on.
  1442.                 lpallobjs->CDP_fLink = FALSE;
  1443.                 SendDlgItemMessage (hDlg, IDD_CUSTOM_LINK, BM_SETCHECK, (WPARAM) lpallobjs->CDP_fLink, 0);
  1444.                 ClearEditControl (lpallobjs->CDP_hWndVal, 0);
  1445.                 
  1446.                 FSwapControls (lpallobjs->CDP_hWndVal, lpallobjs->CDP_hWndLinkVal, lpallobjs->CDP_hWndBoolTrue, lpallobjs->CDP_hWndBoolFalse,
  1447.                     lpallobjs->CDP_hWndGroup, lpallobjs->CDP_hWndType, lpallobjs->CDP_hWndValText, FALSE, FALSE);
  1448.                 
  1449.                 FSetupAddButton (lpallobjs->CDP_iszType, lpallobjs->CDP_fLink, &lpallobjs->CDP_fAdd, lpallobjs->CDP_hWndAdd, lpallobjs->CDP_hWndVal, lpallobjs->CDP_hWndName, hDlg);
  1450.                 ResetTypeControl (hDlg, IDD_CUSTOM_TYPE, &lpallobjs->CDP_iszType);
  1451.                 SendMessage(lpallobjs->CDP_hWndName, CB_SETEDITSEL, 0, MAKELPARAM(0,-1));     // Select entire string
  1452.                 SendMessage(lpallobjs->CDP_hWndName, WM_CLEAR, 0, 0);
  1453.                 SetFocus(lpallobjs->CDP_hWndName);
  1454.                 //              lpallobjs->fPropDlgChanged = TRUE;
  1455.                 PropSheet_Changed(GetParent(hDlg), hDlg);
  1456.                 return(FALSE);     // return 0 'cuz we process the message
  1457.                 break;
  1458.                 
  1459.             case IDD_CUSTOM_LINK :
  1460.                 {
  1461.                     BOOL fMod = FALSE;
  1462.                     // Should never get a message from a disabled control
  1463.                     Assert (lpallobjs->CDP_cLinks);
  1464.                     
  1465.                     lpallobjs->CDP_fLink = !lpallobjs->CDP_fLink;
  1466.                     SendDlgItemMessage (hDlg, IDD_CUSTOM_LINK, BM_SETCHECK, (WPARAM) lpallobjs->CDP_fLink, 0);
  1467.                     
  1468.                     // If the link box is checked, the value edit needs to change
  1469.                     // to a combobox filled with link data
  1470.                     if (lpallobjs->CDP_fLink)
  1471.                     {
  1472.                         Assert ((lpallobjs->lpfnDwQueryLinkData != NULL));
  1473.                         
  1474.                         FCreateListOfLinks (lpallobjs->CDP_cLinks, lpallobjs->lpfnDwQueryLinkData, lpallobjs->CDP_hWndLinkVal);
  1475.                         SendMessage (lpallobjs->CDP_hWndLinkVal, CB_SETCURSEL, 0, 0);
  1476.                         FSetTypeControl ((*lpallobjs->lpfnDwQueryLinkData) (QLD_LINKTYPE, 0, NULL, NULL), lpallobjs->CDP_hWndType);
  1477.                     }
  1478.                     else
  1479.                         ClearEditControl (lpallobjs->CDP_hWndVal, 0);
  1480.                     
  1481.                     FSwapControls (lpallobjs->CDP_hWndVal, lpallobjs->CDP_hWndLinkVal, lpallobjs->CDP_hWndBoolTrue, lpallobjs->CDP_hWndBoolFalse,
  1482.                         lpallobjs->CDP_hWndGroup, lpallobjs->CDP_hWndType, lpallobjs->CDP_hWndValText, lpallobjs->CDP_fLink, FALSE);
  1483.                     
  1484.                     // HACK, we don't want FSetupAddButton to change the text of the add
  1485.                     // button
  1486.                     if (!lpallobjs->CDP_fAdd)
  1487.                         fMod = lpallobjs->CDP_fAdd = TRUE;
  1488.                     // Set up the "Add" button correctly
  1489.                     FSetupAddButton (lpallobjs->CDP_iszType, lpallobjs->CDP_fLink, &lpallobjs->CDP_fAdd, lpallobjs->CDP_hWndAdd, lpallobjs->CDP_hWndVal, lpallobjs->CDP_hWndName, hDlg);
  1490.                     if (fMod)
  1491.                         lpallobjs->CDP_fAdd = FALSE;
  1492.                     return(FALSE);     // return 0 'cuz we process the message
  1493.                     break;
  1494.                 }
  1495.             case IDD_CUSTOM_BOOLTRUE:
  1496.             case IDD_CUSTOM_BOOLFALSE:
  1497.                 {
  1498.                     BOOL fMod = FALSE;
  1499.                     lpallobjs->CDP_iszType = (int)SendMessage (lpallobjs->CDP_hWndType, CB_GETCURSEL, 0, 0);
  1500.                     
  1501.                     // HACK, we don't want FSetupAddButton to change the text of the add
  1502.                     // button
  1503.                     if (!lpallobjs->CDP_fAdd)
  1504.                         fMod = lpallobjs->CDP_fAdd = TRUE;
  1505.                     FSetupAddButton (lpallobjs->CDP_iszType, lpallobjs->CDP_fLink, &lpallobjs->CDP_fAdd, lpallobjs->CDP_hWndAdd, lpallobjs->CDP_hWndVal, lpallobjs->CDP_hWndName, hDlg);
  1506.                     if (fMod)
  1507.                         lpallobjs->CDP_fAdd = FALSE;
  1508.                     
  1509.                     return(FALSE);
  1510.                 }
  1511.                 
  1512.             default:
  1513.                 return(TRUE);
  1514.             }
  1515.             
  1516.             case CBN_CLOSEUP:
  1517.                 // Hack!!
  1518.                 // We need to post a message to ourselves to check if the user's
  1519.                 // actions entered text in the edit field.
  1520.                 PostMessage(hDlg, WM_USER+0x1000, 0L, 0L);
  1521.                 return(FALSE);
  1522.                 
  1523.             case CBN_SELCHANGE :
  1524.                 switch (LOWORD (wParam))
  1525.                 {
  1526.                 case IDD_CUSTOM_NAME  :
  1527.                     // Hack!!
  1528.                     // We need to post a message to ourselves to check if the user's
  1529.                     // actions entered text in the edit field.
  1530.                     PostMessage(hDlg, WM_USER+0x1000, 0L, 0L);
  1531.                     return(FALSE);     // return 0 'cuz we process the message
  1532.                     break;
  1533.                     
  1534.                 case IDD_CUSTOM_TYPE :
  1535.                     {
  1536.                         BOOL fMod = FALSE;
  1537.                         // If the user picks the Boolean type from the combo box,
  1538.                         // we must replace the edit control for the value
  1539.                         // with radio buttons.  If the Link checkbox is set,
  1540.                         // the type depends on the link value, not user selection
  1541.                         lpallobjs->CDP_iszType = (int)SendMessage ((HWND) lParam, CB_GETCURSEL, 0, 0);
  1542.                         FSwapControls (lpallobjs->CDP_hWndVal, lpallobjs->CDP_hWndLinkVal, lpallobjs->CDP_hWndBoolTrue, lpallobjs->CDP_hWndBoolFalse,
  1543.                             lpallobjs->CDP_hWndGroup, lpallobjs->CDP_hWndType, lpallobjs->CDP_hWndValText, lpallobjs->CDP_fLink, (lpallobjs->CDP_iszType == iszBOOL));
  1544.                         // HACK: FSwapControls() resets the type selection to be
  1545.                         // the first one (since all other clients need that to
  1546.                         // happen).  In this case, the user has selected a new
  1547.                         // type, so we need to force it manually to what they picked.
  1548.                         SendMessage (lpallobjs->CDP_hWndType, CB_SETCURSEL, lpallobjs->CDP_iszType, 0);
  1549.                         // HACK: FSetupAddButton will change the Add button to
  1550.                         // say "Add" if lpallobjs->CDP_fAdd is FALSE.  Since we just changed
  1551.                         // the button to "Modify", fake it out to not change
  1552.                         // the Add button by flipping lpallobjs->CDP_fAdd, then flipping it back.
  1553.                         if (!lpallobjs->CDP_fAdd)
  1554.                             fMod = lpallobjs->CDP_fAdd = TRUE;
  1555.                         
  1556.                         FSetupAddButton (lpallobjs->CDP_iszType, lpallobjs->CDP_fLink, &lpallobjs->CDP_fAdd, lpallobjs->CDP_hWndAdd, lpallobjs->CDP_hWndVal, lpallobjs->CDP_hWndName, hDlg);
  1557.                         if (fMod)
  1558.                             lpallobjs->CDP_fAdd = FALSE;
  1559.                         return(FALSE);     // return 0 'cuz we process the message
  1560.                     }
  1561.                 case IDD_CUSTOM_LINKVALUE :
  1562.                     // If the user has the "Link" box checked and starts picking
  1563.                     // link values, make sure that the "Type" combobox is updated
  1564.                     // to the type of the static value of the link.
  1565.                     {
  1566.                         DWORD irg;
  1567.                         
  1568.                         AssertSz (lpallobjs->CDP_fLink, TEXT("Link box must be checked in order for this dialog to be visible!"));
  1569.                         
  1570.                         // Get the link value from the combobox, and store
  1571.                         // the link name and static value.
  1572.                         irg = (int)SendMessage (lpallobjs->CDP_hWndLinkVal, CB_GETCURSEL, 0, 0);
  1573.                         
  1574.                         Assert ((lpallobjs->lpfnDwQueryLinkData != NULL));
  1575.                         
  1576.                         // REVIEW: If apps really need the name, we can get it here....
  1577.                         FSetTypeControl ((*lpallobjs->lpfnDwQueryLinkData) (QLD_LINKTYPE, irg, NULL, NULL), lpallobjs->CDP_hWndType);
  1578.                         return(FALSE);     // return 0 'cuz we process the message
  1579.                     }
  1580.                 default:
  1581.                     return TRUE;      // we didn't process message
  1582.                 }
  1583.                 
  1584.                 case CBN_EDITCHANGE:     // The user typed their own
  1585.                     switch (LOWORD (wParam))
  1586.                     {
  1587.                     case IDD_CUSTOM_NAME  :
  1588.                         // Hack!!
  1589.                         // We need to post a message to ourselves to check if the user's
  1590.                         // actions entered text in the edit field.
  1591.                         PostMessage(hDlg, WM_USER+0x1000, 0L, 0L);
  1592.                         return(FALSE);     // return 0 'cuz we process the message
  1593.                         break;
  1594.                     default:
  1595.                         return(TRUE);
  1596.                         break;
  1597.                     }
  1598.                     
  1599.                     case EN_UPDATE :
  1600.                         switch (LOWORD (wParam))
  1601.                         {
  1602.                             
  1603.                         case IDD_CUSTOM_VALUE :
  1604.                             {
  1605.                                 BOOL fMod = FALSE;
  1606.                                 
  1607.                                 if (FAllocAndGetValLpstz (hDlg, IDD_CUSTOM_NAME, &glpstzName))
  1608.                                 {
  1609.                                     LPUDPROP lpudp = LpudpropFindMatchingName (lpallobjs->lpUDObj, (LPTSTR)PSTR (glpstzName));
  1610.                                     if (lpudp != NULL)
  1611.                                     {
  1612.                                         if (lpallobjs->CDP_fAdd)
  1613.                                         {
  1614.                                             SendMessage (lpallobjs->CDP_hWndAdd, WM_SETTEXT, 0, (LPARAM) rgszAdd[iszMODIFY]);
  1615.                                             lpallobjs->CDP_fAdd = FALSE;
  1616.                                         }
  1617.                                     }
  1618.                                     // HACK: FSetupAddButton will change the Add button to
  1619.                                     // say "Add" if lpallobjs->CDP_fAdd is FALSE.  Since we just changed
  1620.                                     // the button to "Modify", fake it out to not change
  1621.                                     // the Add button by flipping lpallobjs->CDP_fAdd, then flipping it back.
  1622.                                     if (!lpallobjs->CDP_fAdd)
  1623.                                         fMod = lpallobjs->CDP_fAdd = TRUE;
  1624.                                     
  1625.                                     FSetupAddButton (lpallobjs->CDP_iszType, lpallobjs->CDP_fLink, &lpallobjs->CDP_fAdd, lpallobjs->CDP_hWndAdd, lpallobjs->CDP_hWndVal, lpallobjs->CDP_hWndName, hDlg);
  1626.                                     if (fMod)
  1627.                                         lpallobjs->CDP_fAdd = FALSE;
  1628.                                 }
  1629.                                 return(FALSE);     // return 0 'cuz we process the message
  1630.                             }
  1631.                         default:
  1632.                             return TRUE;      // we didn't process message
  1633.                         }
  1634.                         
  1635.                         case EN_KILLFOCUS :
  1636.                             switch (LOWORD (wParam))
  1637.                             {
  1638.                                 // If the user finishes entering text in the Name edit control,
  1639.                                 // be really cool and check to see if the name they entered
  1640.                                 // is a property that is already defined.  If it is,
  1641.                                 // change the Add button to Modify.
  1642.                             case IDD_CUSTOM_NAME :
  1643.                                 if (FAllocAndGetValLpstz (hDlg, IDD_CUSTOM_NAME, &glpstzName))
  1644.                                 {
  1645.                                     LPUDPROP lpudp = LpudpropFindMatchingName (lpallobjs->lpUDObj, (LPTSTR)PSTR (glpstzName));
  1646.                                     if (lpudp != NULL)
  1647.                                     {
  1648.                                         if (lpallobjs->CDP_fAdd)
  1649.                                         {
  1650.                                             SendMessage (lpallobjs->CDP_hWndAdd, WM_SETTEXT, 0, (LPARAM) rgszAdd[iszMODIFY]);
  1651.                                             lpallobjs->CDP_fAdd = FALSE;
  1652.                                         }
  1653.                                     }
  1654.                                 }
  1655.                                 return FALSE;
  1656.                                 
  1657.                             default:
  1658.                                 return TRUE;
  1659.                             }
  1660.                             default:
  1661.                                 return TRUE;
  1662.         } // switch
  1663.         
  1664.     case WM_DESTROY:
  1665.         MsoImageList_Destroy(lpallobjs->CDP_hImlS);
  1666.         return FALSE;
  1667.         
  1668.     case WM_NOTIFY :
  1669.         
  1670.         switch (((NMHDR FAR *) lParam)->code)
  1671.         {
  1672.         case LVN_ITEMCHANGING :
  1673.             // If an item is gaining focus, put it in the edit controls at
  1674.             // the top of the dialog.
  1675.             if (((NM_LISTVIEW FAR *) lParam)->uNewState & LVIS_SELECTED)
  1676.             {
  1677.                 Assert ((((NM_LISTVIEW FAR *) lParam) != NULL));
  1678.                 lpallobjs->CDP_iItem = ((NM_LISTVIEW FAR *) lParam)->iItem;
  1679.                 ListView_GetItemText (lpallobjs->CDP_hWndCustomLV, lpallobjs->CDP_iItem, 0, lpallobjs->CDP_sz, BUFMAX);
  1680.                 PopulateControls (lpallobjs->lpUDObj, lpallobjs->CDP_sz, lpallobjs->CDP_cLinks, lpallobjs->lpfnDwQueryLinkData, hDlg,
  1681.                     GetDlgItem (hDlg, IDD_CUSTOM_NAME), lpallobjs->CDP_hWndVal, lpallobjs->CDP_hWndValText,
  1682.                     GetDlgItem (hDlg, IDD_CUSTOM_LINK), lpallobjs->CDP_hWndLinkVal, lpallobjs->CDP_hWndType,
  1683.                     lpallobjs->CDP_hWndBoolTrue, lpallobjs->CDP_hWndBoolFalse, lpallobjs->CDP_hWndGroup, lpallobjs->CDP_hWndAdd, lpallobjs->CDP_hWndDelete, &lpallobjs->CDP_fLink, &lpallobjs->CDP_fAdd);
  1684.                 
  1685.                 return FALSE;
  1686.             }
  1687.             return TRUE;
  1688.             break;
  1689.             
  1690. #ifdef OFFICE_96
  1691.         case LVN_COLUMNCLICK:
  1692.             // We only sort the name column
  1693.             if (((LPARAM)((NM_LISTVIEW *)lParam)->iSubItem == 0))
  1694.                 ListView_SortItems(((NM_LISTVIEW *) lParam)->hdr.lpallobjs->CDP_hWndFrom, ListViewCompareFunc,0);
  1695.             return TRUE;
  1696. #endif
  1697.             
  1698.         case PSN_APPLY :
  1699.             if (IsWindowEnabled(lpallobjs->CDP_hWndAdd))
  1700.                 FGetCustomPropFromDlg(lpallobjs, hDlg);
  1701.             // Swap the temp copy to be the real copy.
  1702.             FDeleteTmpUDProps (lpallobjs->lpUDObj);
  1703.             MESSAGE (TEXT("PSN_APPLY - Custom Page"));
  1704.             
  1705.             if (FUserDefShouldSave (lpallobjs->lpUDObj)
  1706.                 || lpallobjs->fPropDlgChanged )
  1707.             {
  1708.                 if( !ApplyChangesBackToFile(hDlg, (BOOL)((PSHNOTIFY*)lParam)->lParam, lpallobjs, itabCUSTOM) )
  1709.                 {
  1710.                     PostMessage( GetParent(hDlg), PSM_SETCURSEL, (WPARAM)-1, (LPARAM)lpallobjs->lpUDObj->m_hPage );