Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2450 lines
92 KiB

////////////////////////////////////////////////////////////////////////////////
//
// propdlg.c
//
// The Properties dialog for MS Office.
//
// Change history:
//
// Date Who What
// --------------------------------------------------------------------------
// 06/09/94 B. Wentz Created file
// 01/16/95 martinth Finished sticky dlg stuff.
// We have to call ApplyStickyDlgCoor
// in the first WM_INITDIALOG, don't ask me why,
// but otherwise we have redraw problems. Likewise,
// we have to call SetStickyDlgCoor in the first
// PSN_RESET/PSN_APPLY, I have no idea why, since
// the main dialog shouldn't have been deleted but
// it is. Thus we have to add calls everywhere.
// Could it be that the tabs are getting deleted
// one by one and the dialog changes size? Dunno.
// But this works, so change at your own risk!;-)
// 07/08/96 MikeHill Ignore unsupported (non-UDTYPE) properties.
////////////////////////////////////////////////////////////////////////////////
#include "priv.h"
#pragma hdrstop
int ScanDateNums(TCHAR *pch, TCHAR *pszSep, unsigned int aiNum[], int cNum, int iYear);
BOOL PASCAL FConvertDate(LPTSTR lpstz, DWORD cchMax, LPFILETIME lpft);
#include "propdlg.h"
#include "strings.h"
#include "msohelp.h"
// Max size of time/date string
#define TIMEDATEMAX 256
// Check button actions
#define CLEAR 0
#define CHECKED 1
#define GREYED 2
// Number of property sheet pages
#define PAGESMAX 5
// Max size for "short" temp buffers
#define SHORTBUFMAX 128
// The pages
#define itabCUSTOM 0
#define itabFIRST itabCUSTOM
// Defines for printing file sizes
#define DELIMITER TEXT(',')
#define iszBYTES 0
#define iszORDERKB 1
#define iszORDERMB 2
#define iszORDERGB 3
#define iszORDERTB 4
static TCHAR rgszOrders[iszORDERTB+1][SHORTBUFMAX];
// "bytes", // iszBYTES
// "KB", // iszORDERKB
// "MB", // iszORDERMB
// "GB", // iszORDERGB
// "TB" // iszORDERTB
// note that szBYTES is defined above...
#define iszPAGES 1
#define iszPARA 2
#define iszLINES 3
#define iszWORDS 4
#define iszCHARS 5
#define iszSLIDES 6
#define iszNOTES 7
#define iszHIDDENSLIDES 8
#define iszMMCLIPS 9
#define iszFORMAT 10
// Strings for the statistics listbox
static TCHAR rgszStats[iszFORMAT+1][SHORTBUFMAX];
// "Bytes:", // iszBYTES
// "Pages:", // iszPAGES
// "Paragraphs:", // iszPARA
// "Lines:", // iszLINES
// "Words:", // iszWORDS
// "Characters:", // iszCHARS
// "Slides:", // iszSLIDES
// "Notes:", // iszNOTES
// "Hidden Slides:", // iszHIDDENSLIDES
// "Multimedia Clips:", // iszMMCLIPS
// "Presentation Format:"// iszFORMAT
#define BASE10 10
// Number of pre-defined custom names
#define NUM_BUILTIN_CUSTOM_NAMES 27
#define iszTEXT 0
#define iszDATE 1
#define iszNUM 2
#define iszBOOL 3
#define iszUNKNOWN 4
// Strings for the types of user-defined properties
static TCHAR rgszTypes[iszUNKNOWN+1][SHORTBUFMAX];
// "Text", // iszTEXT
// "Date", // iszDATE
// "Number", // iszNUM
// "Yes or No", // iszBOOL
// "Unknown" // iszUNKNOWN
#define iszNAME 0
#define iszVAL 1
#define iszTYPE 2
// Strings for the column headings for the statistics tab
static TCHAR rgszStatHeadings[iszVAL+1][SHORTBUFMAX];
// "Statistic Name", // iszNAME
// "Value" // iszVAL
// Strings for the column headings for custom tab
static TCHAR rgszHeadings[iszTYPE+1][SHORTBUFMAX];
// "Property Name", // iszNAME
// "Value", // iszVAL
// "Type" // iszTYPE
#define iszTRUE 0
#define iszFALSE 1
// Strings for Booleans
static TCHAR rgszBOOL[iszFALSE+1][SHORTBUFMAX];
// "Yes", // iszTRUE
// "No" // iszFALSE
#define iszADD 0
#define iszMODIFY 1
// Strings for the Add button
static TCHAR rgszAdd[iszMODIFY+1][SHORTBUFMAX];
// "Add", // iszADD
// "Modify" // iszMODIFY
#define iszVALUE 0
#define iszSOURCE 1
// Strings for the source/value caption
static TCHAR rgszValue[iszSOURCE+1][SHORTBUFMAX];
// "Value:", // iszVALUE
// "Source:" // iszSOURCE
// Date formatting codes
#define MMDDYY TEXT('0')
#define DDMMYY TEXT('1')
#define YYMMDD TEXT('2')
#define OLEEPOCH 1900
#define SYSEPOCH 1601
#define ONECENTURY 100
#define YEARINCENTURY(year) ((year) % ONECENTURY)
#define CENTURYFROMYEAR(year) ((year) - YEARINCENTURY(year))
//
// Global data, to be deleted when FShowOfficePropDlg exits
//
static LPTSTR glpstzName;
static LPTSTR glpstzValue;
static int giLinkIcon;
static int giInvLinkIcon;
static int giBlankIcon;
static HBRUSH hBrushPropDlg = NULL;
const TCHAR g_szHelpFile[] = TEXT("windows.hlp");
//
// Internal prototypes
//
INT_PTR CALLBACK FGeneralDlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
INT_PTR CALLBACK FSummaryDlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
INT_PTR CALLBACK FStatisticsDlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
INT_PTR CALLBACK FCustomDlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
INT_PTR CALLBACK FContentsDlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
INT_PTR CALLBACK FPropHeaderDlgProc (HWND hwnd, UINT message, LONG lParam);
//static int CALLBACK ListViewCompareFunc(LPARAM, LPARAM, LPARAM);
void PASCAL SetEditValLpsz (LPPROPVARIANT lppropvar, HWND hdlg, DWORD dwID );
BOOL PASCAL GetEditValLpsz (LPPROPVARIANT lppropvar, HWND hDlg, DWORD dwId);
BOOL PASCAL FAllocAndGetValLpstz (HWND hDlg, DWORD dwId, LPTSTR *lplpstz);
BOOL PASCAL FAllocString (LPTSTR *lplpstz, DWORD cb);
void PASCAL ClearEditControl (HWND hDlg, DWORD dwId);
UDTYPES PASCAL UdtypesGetNumberType (LPTSTR lpstz, NUM *lpnumval,
BOOL (*lpfnFSzToNum)(NUM *, LPTSTR));
void PASCAL PrintTimeInDlg (HWND hDlg, DWORD dwId, FILETIME *pft);
void PASCAL PrintEditTimeInDlg (HWND hDlg, FILETIME *pft);
void PASCAL PopulateUDListView (HWND hWnd, LPUDOBJ lpUDObj);
void PASCAL AddUDPropToListView (LPUDOBJ lpUDObj, HWND hWnd, LPTSTR lpszName, LPPROPVARIANT lppropvar, int iItem,
BOOL fLink, BOOL fLinkInvalid, BOOL fMakeVisible);
VOID PASCAL InitListView (HWND hDlg, int irgLast, TCHAR rgsz[][SHORTBUFMAX], BOOL fImageList);
WORD PASCAL WUdtypeToSz (LPPROPVARIANT lppropvar, LPTSTR sz, DWORD cchMax,
BOOL (*lpfnFNumToSz)(NUM *, LPTSTR, DWORD));
BOOL PASCAL FSwapControls (HWND hWndVal, HWND hWndLinkVal, HWND hWndBoolTrue, HWND hWndBoolFalse, HWND hWndGroup, HWND hWndType, HWND hWndValText, BOOL fLink, BOOL fBool);
VOID PASCAL PopulateControls (LPUDOBJ lpUDObj, LPTSTR szName, DWORD cLinks, DWQUERYLD lpfnDwQueryLinkData, HWND hDlg,
HWND hWndName, HWND hWndVal, HWND hWndValText, HWND hWndLink, HWND hWndLinkVal, HWND hWndType,
HWND hWndBoolTrue, HWND hWndBoolFalse, HWND hWndGroup, HWND hWndAdd, HWND hWndDelete, BOOL *pfLink, BOOL *pfAdd);
BOOL PASCAL FSetupAddButton (DWORD iszType, BOOL fLink, BOOL *pfAdd, HWND hWndAdd, HWND hWndVal, HWND hWndName, HWND hDlg);
BOOL PASCAL FCreateListOfLinks (DWORD cLinks, DWQUERYLD lpfnDwQueryLinkData, HWND hWndLinkVal);
BOOL PASCAL FSetTypeControl (UDTYPES udtype, HWND hWndType);
void PASCAL DeleteItem (LPUDOBJ lpUDObj, HWND hWndLV, int iItem, TCHAR sz[]);
void PASCAL ResetTypeControl (HWND hDlg, DWORD dwId, DWORD *piszType);
BOOL PASCAL FDisplayConversionWarning (HWND hDlg);
BOOL PASCAL FLoadTextStrings (void);
BOOL FGetCustomPropFromDlg(LPALLOBJS lpallobjs, HWND hDlg);
VOID SetCustomDlgDefButton(HWND hDlg, int IDNew);
INT PASCAL ISavePropDlgChanges(LPALLOBJS, HWND, HWND);
/* WinHelp stuff. */
static const DWORD rgIdhGeneral[] =
{
IDD_ITEMICON, IDH_GENERAL_ICON,
IDD_NAME, IDH_GENERAL_NAME_BY_ICON,
IDD_FILETYPE, IDH_GENERAL_FILETYPE,
IDD_FILETYPE_LABEL, IDH_GENERAL_FILETYPE,
IDD_LOCATION, IDH_GENERAL_LOCATION,
IDD_LOCATION_LABEL, IDH_GENERAL_LOCATION,
IDD_FILESIZE, IDH_GENERAL_FILESIZE,
IDD_FILESIZE_LABEL, IDH_GENERAL_FILESIZE,
IDD_FILENAME, IDH_GENERAL_MSDOSNAME,
IDD_FILENAME_LABEL, IDH_GENERAL_MSDOSNAME,
IDD_CREATED, IDH_GENERAL_CREATED,
IDD_CREATED_LABEL, IDH_GENERAL_CREATED,
IDD_LASTMODIFIED, IDH_GENERAL_MODIFIED,
IDD_LASTMODIFIED_LABEL, IDH_GENERAL_MODIFIED,
IDD_LASTACCESSED, IDH_GENERAL_ACCESSED,
IDD_LASTACCESSED_LABEL, IDH_GENERAL_ACCESSED,
IDD_ATTRIBUTES_LABEL, IDH_GENERAL_ATTRIBUTES,
IDD_READONLY, IDH_GENERAL_READONLY,
IDD_HIDDEN, IDH_GENERAL_HIDDEN,
IDD_ARCHIVE, IDH_GENERAL_ARCHIVE,
IDD_SYSTEM, IDH_GENERAL_SYSTEM
};
static const DWORD rgIdhSummary[] =
{
IDD_SUMMARY_TITLE, IDH_SUMMARY_TITLE,
IDD_SUMMARY_TITLE_LABEL, IDH_SUMMARY_TITLE,
IDD_SUMMARY_SUBJECT, IDH_SUMMARY_SUBJECT,
IDD_SUMMARY_SUBJECT_LABEL, IDH_SUMMARY_SUBJECT,
IDD_SUMMARY_AUTHOR, IDH_SUMMARY_AUTHOR,
IDD_SUMMARY_AUTHOR_LABEL, IDH_SUMMARY_AUTHOR,
IDD_SUMMARY_MANAGER, IDH_SUMMARY_MANAGER,
IDD_SUMMARY_MANAGER_LABEL, IDH_SUMMARY_MANAGER,
IDD_SUMMARY_COMPANY, IDH_SUMMARY_COMPANY,
IDD_SUMMARY_COMPANY_LABEL, IDH_SUMMARY_COMPANY,
IDD_SUMMARY_CATEGORY, IDH_SUMMARY_CATEGORY,
IDD_SUMMARY_CATEGORY_LABEL, IDH_SUMMARY_CATEGORY,
IDD_SUMMARY_KEYWORDS, IDH_SUMMARY_KEYWORDS,
IDD_SUMMARY_KEYWORDS_LABEL, IDH_SUMMARY_KEYWORDS,
IDD_SUMMARY_COMMENTS, IDH_SUMMARY_COMMENTS,
IDD_SUMMARY_COMMENTS_LABEL, IDH_SUMMARY_COMMENTS,
IDD_SUMMARY_TEMPLATE, IDH_SUMMARY_TEMPLATE,
IDD_SUMMARY_TEMPLATETEXT, IDH_SUMMARY_TEMPLATE,
IDD_SUMMARY_SAVEPREVIEW, IDH_SUMMARY_SAVEPREVIEW
};
static const DWORD rgIdhStatistics[] =
{
IDD_STATISTICS_CREATED, IDH_STATISTICS_CREATED,
IDD_STATISTICS_CREATED_LABEL, IDH_STATISTICS_CREATED,
IDD_STATISTICS_CHANGED, IDH_STATISTICS_MODIFIED,
IDD_STATISTICS_CHANGED_LABEL, IDH_STATISTICS_MODIFIED,
IDD_STATISTICS_ACCESSED, IDH_STATISTICS_ACCESSED,
IDD_STATISTICS_ACCESSED_LABEL, IDH_STATISTICS_ACCESSED,
IDD_STATISTICS_LASTPRINT, IDH_STATISTICS_LASTPRINT,
IDD_STATISTICS_LASTPRINT_LABEL, IDH_STATISTICS_LASTPRINT,
IDD_STATISTICS_LASTSAVEBY, IDH_STATISTICS_LASTSAVEBY,
IDD_STATISTICS_LASTSAVEBY_LABEL, IDH_STATISTICS_LASTSAVEBY,
IDD_STATISTICS_REVISION, IDH_STATISTICS_REVISION,
IDD_STATISTICS_REVISION_LABEL, IDH_STATISTICS_REVISION,
IDD_STATISTICS_TOTALEDIT, IDH_STATISTICS_TOTALEDIT,
IDD_STATISTICS_TOTALEDIT_LABEL, IDH_STATISTICS_TOTALEDIT,
IDD_STATISTICS_LVLABEL, IDH_STATISTICS_LISTVIEW,
IDD_STATISTICS_LISTVIEW, IDH_STATISTICS_LISTVIEW
};
static const DWORD rgIdhContents[] =
{
IDD_CONTENTS_LISTBOX_LABEL, IDH_CONTENTS_LISTBOX,
IDD_CONTENTS_LISTBOX, IDH_CONTENTS_LISTBOX
};
static const DWORD rgIdhCustom[] =
{
IDD_CUSTOM_NAME, IDH_CUSTOM_NAME,
IDD_CUSTOM_NAME_LABEL, IDH_CUSTOM_NAME,
IDD_CUSTOM_TYPE, IDH_CUSTOM_TYPE,
IDD_CUSTOM_TYPE_LABEL, IDH_CUSTOM_TYPE,
IDD_CUSTOM_VALUE, IDH_CUSTOM_VALUE,
IDD_CUSTOM_VALUETEXT, IDH_CUSTOM_VALUE,
IDD_CUSTOM_LINKVALUE, IDH_CUSTOM_LINKVALUE,
IDD_CUSTOM_BOOLTRUE, IDH_CUSTOM_BOOLYES,
IDD_CUSTOM_BOOLFALSE, IDH_CUSTOM_BOOLYES,
IDD_CUSTOM_ADD, IDH_CUSTOM_ADDBUTTON,
IDD_CUSTOM_DELETE, IDH_CUSTOM_DELETEBUTTON,
IDD_CUSTOM_LINK, IDH_CUSTOM_LINKCHECK,
IDD_CUSTOM_LISTVIEW, IDH_CUSTOM_LISTVIEW,
IDD_CUSTOM_LISTVIEW_LABEL, IDH_CUSTOM_LISTVIEW
};
void FOfficeInitPropInfo(PROPSHEETPAGE * lpPsp, DWORD dwFlags, LPARAM lParam, LPFNPSPCALLBACK pfnCallback)
{
lpPsp[itabCUSTOM-itabFIRST].dwSize = sizeof(PROPSHEETPAGE);
lpPsp[itabCUSTOM-itabFIRST].dwFlags = dwFlags;
lpPsp[itabCUSTOM-itabFIRST].hInstance = g_hmodThisDll;
lpPsp[itabCUSTOM-itabFIRST].pszTemplate = MAKEINTRESOURCE (IDD_CUSTOM);
lpPsp[itabCUSTOM-itabFIRST].pszIcon = NULL;
lpPsp[itabCUSTOM-itabFIRST].pszTitle = NULL;
lpPsp[itabCUSTOM-itabFIRST].pfnDlgProc = FCustomDlgProc;
lpPsp[itabCUSTOM-itabFIRST].pfnCallback = pfnCallback;
lpPsp[itabCUSTOM-itabFIRST].pcRefParent = NULL;
lpPsp[itabCUSTOM-itabFIRST].lParam = lParam;
}
////////////////////////////////////////////////////////////////////////////////
//
// Attach
//
// Purpose:
// Assigns HPROPSHEETPAGE to appropriate data block member.
//
////////////////////////////////////////////////////////////////////////////////
BOOL FAttach( LPALLOBJS lpallobjs, PROPSHEETPAGE* ppsp, HPROPSHEETPAGE hPage )
{
#define ASSIGN_PAGE_HANDLE( pfn, phpage ) \
if( ppsp->pfnDlgProc == pfn ) { *(phpage) = hPage ; return TRUE ; }
ASSIGN_PAGE_HANDLE( FCustomDlgProc, &lpallobjs->lpUDObj->m_hPage );
return FALSE;
}
////////////////////////////////////////////////////////////////////////////////
//
// PropPageInit
//
// Purpose:
// Keep track which pages have been init, such that we can know when we
// can do the apply.
//
////////////////////////////////////////////////////////////////////////////////
void PropPageInit(LPALLOBJS lpallobjs, int iPage)
{
if (iPage > lpallobjs->iMaxPageInit)
lpallobjs->iMaxPageInit = iPage;
}
////////////////////////////////////////////////////////////////////////////////
//
// ApplyChangesBackToFile
//
// Purpose:
// See if this is now the time to apply the changes back to the file
//
////////////////////////////////////////////////////////////////////////////////
BOOL ApplyChangesBackToFile(
HWND hDlg,
BOOL bFinalEdit /* user clicked OK rather than Apply*/,
LPALLOBJS lpallobjs,
int iPage)
{
HRESULT hres;
BOOL fOK = FALSE;
LPSTORAGE lpStg;
WCHAR wszPath[ MAX_PATH ];
if (iPage != lpallobjs->iMaxPageInit)
return TRUE; // no errors
hres = StringCchCopy(wszPath, ARRAYSIZE(wszPath), lpallobjs->szPath);
if (SUCCEEDED(hres))
{
hres = StgOpenStorageEx(wszPath,STGM_READWRITE|STGM_SHARE_EXCLUSIVE,STGFMT_ANY,0,NULL,NULL,
&IID_IStorage, (void**)&lpStg );
}
if (SUCCEEDED(hres) && lpStg)
{
fOK = (BOOL)DwOfficeSaveProperties( lpStg,
lpallobjs->lpSIObj,
lpallobjs->lpDSIObj,
lpallobjs->lpUDObj,
0, // Flags
STGM_READWRITE | STGM_SHARE_EXCLUSIVE
);
// Release the Storage (we don't need to commit it;
// it's in dicrect-mode).
lpStg->lpVtbl->Release (lpStg);
lpStg= NULL;
//
// if we did properly save out the properties, than we should
// clear the we have changed things flag...
//
if (fOK)
{
lpallobjs->fPropDlgChanged = FALSE;
lpallobjs->fPropDlgPrompted = FALSE;
}
} // if (SUCCEEDED(hres) && lpStorage)
if (!fOK)
{
UINT nMsgFlags = bFinalEdit ? MB_OKCANCEL /* give option to not dismiss page*/ : MB_OK;
if (ShellMessageBox(g_hmodThisDll, GetParent(hDlg),
MAKEINTRESOURCE(idsErrorOnSave), NULL,
nMsgFlags | MB_ICONHAND, PathFindFileName(lpallobjs->szPath)) == IDOK)
{
fOK = TRUE;
}
PropSheet_UnChanged(GetParent(hDlg), hDlg);
}
return fOK;
} // ApplyChangesBackToFile
int gOKButtonID; // need this to store the ID of the OK button, since it's not in the dlg template
////////////////////////////////////////////////////////////////////////////////
//
// FCustomDlgProc
//
// Purpose:
// Custom tab control
//
////////////////////////////////////////////////////////////////////////////////
INT_PTR CALLBACK FCustomDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
LPALLOBJS lpallobjs = (LPALLOBJS)GetWindowLongPtr(hDlg, DWLP_USER);
switch (message)
{
case WM_INITDIALOG:
{
PROPSHEETPAGE *ppspDlg = (PROPSHEETPAGE *) lParam;
int irg;
HICON hIcon, hInvIcon;
lpallobjs = (LPALLOBJS)ppspDlg->lParam;
PropPageInit(lpallobjs, itabCUSTOM);
SetWindowLongPtr(hDlg, DWLP_USER, ppspDlg->lParam);
gOKButtonID = LOWORD(SendMessage(hDlg, DM_GETDEFID, 0L, 0L));
AssertSz ((sizeof(NUM) == (sizeof(FILETIME))), TEXT("Ok, who changed base type sizes?"));
//
// Fill out the Name dropdown
//
for (irg = 0; irg < NUM_BUILTIN_CUSTOM_NAMES; ++irg)
{
if (CchGetString( idsCustomName1+ irg,
lpallobjs->CDP_sz,
sizeof(lpallobjs->CDP_sz))
)
{
SendDlgItemMessage(hDlg, IDD_CUSTOM_NAME, CB_ADDSTRING, 0, (LPARAM)lpallobjs->CDP_sz);
}
// else, just don't add it
}
//
// Fill out the type drop-down & select the text type
//
for (irg = 0; irg <= iszBOOL; irg++)
{
SendDlgItemMessage(hDlg, IDD_CUSTOM_TYPE, CB_ADDSTRING, 0, (LPARAM) rgszTypes[irg]);
}
ResetTypeControl (hDlg, IDD_CUSTOM_TYPE, &lpallobjs->CDP_iszType);
//
// Set the link checkbox to be off.
//
lpallobjs->CDP_fLink = FALSE;
SendDlgItemMessage( hDlg,
IDD_CUSTOM_LINK,
BM_SETCHECK,
(WPARAM) lpallobjs->CDP_fLink,
0
);
ShowWindow( GetDlgItem( hDlg, IDD_CUSTOM_LINK ), SW_HIDE );
SendDlgItemMessage( hDlg,
IDD_CUSTOM_VALUETEXT,
WM_SETTEXT,
0,
(LPARAM) rgszValue[iszVALUE]
);
//
// Hang on to the window handle of the value edit control & others
//
lpallobjs->CDP_hWndVal = GetDlgItem (hDlg, IDD_CUSTOM_VALUE);
lpallobjs->CDP_hWndName = GetDlgItem (hDlg, IDD_CUSTOM_NAME);
lpallobjs->CDP_hWndLinkVal = GetDlgItem (hDlg, IDD_CUSTOM_LINKVALUE);
lpallobjs->CDP_hWndValText = GetDlgItem (hDlg, IDD_CUSTOM_VALUETEXT);
lpallobjs->CDP_hWndBoolTrue = GetDlgItem (hDlg, IDD_CUSTOM_BOOLTRUE);
lpallobjs->CDP_hWndBoolFalse = GetDlgItem (hDlg, IDD_CUSTOM_BOOLFALSE);
lpallobjs->CDP_hWndGroup = GetDlgItem (hDlg, IDD_CUSTOM_GBOX);
lpallobjs->CDP_hWndAdd = GetDlgItem (hDlg, IDD_CUSTOM_ADD);
lpallobjs->CDP_hWndDelete = GetDlgItem (hDlg, IDD_CUSTOM_DELETE);
lpallobjs->CDP_hWndType = GetDlgItem (hDlg, IDD_CUSTOM_TYPE);
lpallobjs->CDP_hWndCustomLV = GetDlgItem(hDlg, IDD_CUSTOM_LISTVIEW);
InitListView (lpallobjs->CDP_hWndCustomLV, iszTYPE, rgszHeadings, TRUE);
//
// Initially disable the Add & Delete buttons
//
EnableWindow (lpallobjs->CDP_hWndAdd, FALSE);
EnableWindow (lpallobjs->CDP_hWndDelete, FALSE);
lpallobjs->CDP_fAdd = TRUE;
//
// Don't let the user enter too much text
// If you change this value, you must change the buffer
// size (szDate) in FConvertDate
//
SendMessage (lpallobjs->CDP_hWndVal, EM_LIMITTEXT, BUFMAX-1, 0);
SendMessage (lpallobjs->CDP_hWndName, EM_LIMITTEXT, BUFMAX-1, 0);
//
// Add the link icon to the image list
//
hIcon = LoadIcon (g_hmodThisDll, MAKEINTRESOURCE (IDD_LINK_ICON));
hInvIcon = LoadIcon (g_hmodThisDll, MAKEINTRESOURCE (IDD_INVLINK_ICON));
if (hIcon != NULL)
{
lpallobjs->CDP_hImlS = ListView_GetImageList( lpallobjs->CDP_hWndCustomLV, TRUE );
giLinkIcon = MsoImageList_ReplaceIcon( lpallobjs->CDP_hImlS, -1, hIcon );
Assert ((giLinkIcon != -1));
giInvLinkIcon = MsoImageList_ReplaceIcon (lpallobjs->CDP_hImlS, -1, hInvIcon);
Assert ((giInvLinkIcon != -1));
}
else
{
DebugSz (TEXT("Icon load failed"));
}
//
// Make a temporary copy of the custom data
//
FMakeTmpUDProps (lpallobjs->lpUDObj);
//
// Fill in the list view box with any data from the object
//
PopulateUDListView (lpallobjs->CDP_hWndCustomLV, lpallobjs->lpUDObj);
//
// See if the client supports links - turn off checkbox if they don't
//
lpallobjs->CDP_cLinks = 0;
if (!lpallobjs->CDP_cLinks)
{
EnableWindow (GetDlgItem (hDlg, IDD_CUSTOM_LINK), FALSE);
EnableWindow (lpallobjs->CDP_hWndLinkVal, FALSE);
}
return TRUE;
break;
}
case WM_CTLCOLORBTN :
case WM_CTLCOLORDLG :
case WM_CTLCOLORSTATIC :
if (hBrushPropDlg == NULL)
break;
DeleteObject(hBrushPropDlg);
if ((hBrushPropDlg = CreateSolidBrush(GetSysColor(COLOR_BTNFACE))) == NULL)
break;
SetBkColor ((HDC) wParam, GetSysColor (COLOR_BTNFACE));
SetTextColor((HDC) wParam, GetSysColor(COLOR_WINDOWTEXT));
return (INT_PTR) hBrushPropDlg;
case WM_SYSCOLORCHANGE:
PostMessage(lpallobjs->CDP_hWndCustomLV, WM_SYSCOLORCHANGE, wParam, lParam);
return TRUE;
break;
//
// This message is posted when ever the user does something with the
// Name field. That allows the system to finish what they are doing
// and fill in the edit field if they have to. See bug 2820.
//
case WM_USER+0x1000:
if (!(lpallobjs->CDP_fLink && (lpallobjs->lpfnDwQueryLinkData == NULL)))
{
lpallobjs->CDP_iszType = (int)SendMessage (lpallobjs->CDP_hWndType, CB_GETCURSEL, 0, 0);
FSetupAddButton (lpallobjs->CDP_iszType, lpallobjs->CDP_fLink, &lpallobjs->CDP_fAdd, lpallobjs->CDP_hWndAdd, lpallobjs->CDP_hWndVal, lpallobjs->CDP_hWndName, hDlg);
if (FAllocAndGetValLpstz (hDlg, IDD_CUSTOM_NAME, &glpstzName))
{
LPUDPROP lpudp = LpudpropFindMatchingName (lpallobjs->lpUDObj, glpstzName);
if (lpudp != NULL)
{
if (lpallobjs->CDP_fAdd)
{
SendMessage (lpallobjs->CDP_hWndAdd, WM_SETTEXT, 0, (LPARAM) rgszAdd[iszMODIFY]);
lpallobjs->CDP_fAdd = FALSE;
}
}
}
EnableWindow(lpallobjs->CDP_hWndDelete, FALSE); // If the user touches the Name field, disable Delete button
// Are we showing an invalid link?
if (lpallobjs->CDP_fLink && !IsWindowEnabled(GetDlgItem(hDlg,IDD_CUSTOM_LINK)))
{
// Turn off the link checkbox
lpallobjs->CDP_fLink = FALSE;
SendDlgItemMessage (hDlg, IDD_CUSTOM_LINK, BM_SETCHECK, (WPARAM) lpallobjs->CDP_fLink, 0);
if (lpallobjs->CDP_cLinks) // Could be that the app is allowing links
EnableWindow (GetDlgItem (hDlg, IDD_CUSTOM_LINK), TRUE);
// Clear the value window
ClearEditControl (lpallobjs->CDP_hWndVal, 0);
FSwapControls (lpallobjs->CDP_hWndVal, lpallobjs->CDP_hWndLinkVal, lpallobjs->CDP_hWndBoolTrue, lpallobjs->CDP_hWndBoolFalse,
lpallobjs->CDP_hWndGroup, lpallobjs->CDP_hWndType, lpallobjs->CDP_hWndValText, FALSE, FALSE);
}
}
return(TRUE);
break;
case WM_COMMAND :
switch (HIWORD (wParam))
{
case BN_CLICKED :
switch (LOWORD (wParam))
{
case IDD_CUSTOM_ADD :
if (FGetCustomPropFromDlg(lpallobjs, hDlg))
{
PropSheet_Changed(GetParent(hDlg), hDlg);
}
return(FALSE); // return 0 'cuz we process the message
break;
case IDD_CUSTOM_DELETE :
// Assert (fItemSel);
// fItemSel = FALSE; // We're about to delete it!
DeleteItem (lpallobjs->lpUDObj, lpallobjs->CDP_hWndCustomLV, lpallobjs->CDP_iItem, lpallobjs->CDP_sz);
// Turn off the link checkbox if it was on.
lpallobjs->CDP_fLink = FALSE;
SendDlgItemMessage (hDlg, IDD_CUSTOM_LINK, BM_SETCHECK, (WPARAM) lpallobjs->CDP_fLink, 0);
ClearEditControl (lpallobjs->CDP_hWndVal, 0);
FSwapControls (lpallobjs->CDP_hWndVal, lpallobjs->CDP_hWndLinkVal, lpallobjs->CDP_hWndBoolTrue, lpallobjs->CDP_hWndBoolFalse,
lpallobjs->CDP_hWndGroup, lpallobjs->CDP_hWndType, lpallobjs->CDP_hWndValText, FALSE, FALSE);
FSetupAddButton (lpallobjs->CDP_iszType, lpallobjs->CDP_fLink, &lpallobjs->CDP_fAdd, lpallobjs->CDP_hWndAdd, lpallobjs->CDP_hWndVal, lpallobjs->CDP_hWndName, hDlg);
ResetTypeControl (hDlg, IDD_CUSTOM_TYPE, &lpallobjs->CDP_iszType);
SendMessage(lpallobjs->CDP_hWndName, CB_SETEDITSEL, 0, MAKELPARAM(0,-1)); // Select entire string
SendMessage(lpallobjs->CDP_hWndName, WM_CLEAR, 0, 0);
SetFocus(lpallobjs->CDP_hWndName);
// lpallobjs->fPropDlgChanged = TRUE;
PropSheet_Changed(GetParent(hDlg), hDlg);
return(FALSE); // return 0 'cuz we process the message
break;
case IDD_CUSTOM_LINK :
{
BOOL fMod = FALSE;
// Should never get a message from a disabled control
Assert (lpallobjs->CDP_cLinks);
lpallobjs->CDP_fLink = !lpallobjs->CDP_fLink;
SendDlgItemMessage (hDlg, IDD_CUSTOM_LINK, BM_SETCHECK, (WPARAM) lpallobjs->CDP_fLink, 0);
// If the link box is checked, the value edit needs to change
// to a combobox filled with link data
if (lpallobjs->CDP_fLink)
{
Assert ((lpallobjs->lpfnDwQueryLinkData != NULL));
FCreateListOfLinks (lpallobjs->CDP_cLinks, lpallobjs->lpfnDwQueryLinkData, lpallobjs->CDP_hWndLinkVal);
SendMessage (lpallobjs->CDP_hWndLinkVal, CB_SETCURSEL, 0, 0);
FSetTypeControl ((*lpallobjs->lpfnDwQueryLinkData) (QLD_LINKTYPE, 0, NULL, NULL), lpallobjs->CDP_hWndType);
}
else
ClearEditControl (lpallobjs->CDP_hWndVal, 0);
FSwapControls (lpallobjs->CDP_hWndVal, lpallobjs->CDP_hWndLinkVal, lpallobjs->CDP_hWndBoolTrue, lpallobjs->CDP_hWndBoolFalse,
lpallobjs->CDP_hWndGroup, lpallobjs->CDP_hWndType, lpallobjs->CDP_hWndValText, lpallobjs->CDP_fLink, FALSE);
// HACK, we don't want FSetupAddButton to change the text of the add
// button
if (!lpallobjs->CDP_fAdd)
fMod = lpallobjs->CDP_fAdd = TRUE;
// Set up the "Add" button correctly
FSetupAddButton (lpallobjs->CDP_iszType, lpallobjs->CDP_fLink, &lpallobjs->CDP_fAdd, lpallobjs->CDP_hWndAdd, lpallobjs->CDP_hWndVal, lpallobjs->CDP_hWndName, hDlg);
if (fMod)
lpallobjs->CDP_fAdd = FALSE;
return(FALSE); // return 0 'cuz we process the message
break;
}
case IDD_CUSTOM_BOOLTRUE:
case IDD_CUSTOM_BOOLFALSE:
{
BOOL fMod = FALSE;
lpallobjs->CDP_iszType = (int)SendMessage (lpallobjs->CDP_hWndType, CB_GETCURSEL, 0, 0);
// HACK, we don't want FSetupAddButton to change the text of the add
// button
if (!lpallobjs->CDP_fAdd)
fMod = lpallobjs->CDP_fAdd = TRUE;
FSetupAddButton (lpallobjs->CDP_iszType, lpallobjs->CDP_fLink, &lpallobjs->CDP_fAdd, lpallobjs->CDP_hWndAdd, lpallobjs->CDP_hWndVal, lpallobjs->CDP_hWndName, hDlg);
if (fMod)
lpallobjs->CDP_fAdd = FALSE;
return(FALSE);
}
default:
return(TRUE);
}
case CBN_CLOSEUP:
// Hack!!
// We need to post a message to ourselves to check if the user's
// actions entered text in the edit field.
PostMessage(hDlg, WM_USER+0x1000, 0L, 0L);
return(FALSE);
case CBN_SELCHANGE :
switch (LOWORD (wParam))
{
case IDD_CUSTOM_NAME :
// Hack!!
// We need to post a message to ourselves to check if the user's
// actions entered text in the edit field.
PostMessage(hDlg, WM_USER+0x1000, 0L, 0L);
return(FALSE); // return 0 'cuz we process the message
break;
case IDD_CUSTOM_TYPE :
{
BOOL fMod = FALSE;
// If the user picks the Boolean type from the combo box,
// we must replace the edit control for the value
// with radio buttons. If the Link checkbox is set,
// the type depends on the link value, not user selection
lpallobjs->CDP_iszType = (int)SendMessage ((HWND) lParam, CB_GETCURSEL, 0, 0);
FSwapControls (lpallobjs->CDP_hWndVal, lpallobjs->CDP_hWndLinkVal, lpallobjs->CDP_hWndBoolTrue, lpallobjs->CDP_hWndBoolFalse,
lpallobjs->CDP_hWndGroup, lpallobjs->CDP_hWndType, lpallobjs->CDP_hWndValText, lpallobjs->CDP_fLink, (lpallobjs->CDP_iszType == iszBOOL));
// HACK: FSwapControls() resets the type selection to be
// the first one (since all other clients need that to
// happen). In this case, the user has selected a new
// type, so we need to force it manually to what they picked.
SendMessage (lpallobjs->CDP_hWndType, CB_SETCURSEL, lpallobjs->CDP_iszType, 0);
// HACK: FSetupAddButton will change the Add button to
// say "Add" if lpallobjs->CDP_fAdd is FALSE. Since we just changed
// the button to "Modify", fake it out to not change
// the Add button by flipping lpallobjs->CDP_fAdd, then flipping it back.
if (!lpallobjs->CDP_fAdd)
fMod = lpallobjs->CDP_fAdd = TRUE;
FSetupAddButton (lpallobjs->CDP_iszType, lpallobjs->CDP_fLink, &lpallobjs->CDP_fAdd, lpallobjs->CDP_hWndAdd, lpallobjs->CDP_hWndVal, lpallobjs->CDP_hWndName, hDlg);
if (fMod)
lpallobjs->CDP_fAdd = FALSE;
return(FALSE); // return 0 'cuz we process the message
}
case IDD_CUSTOM_LINKVALUE :
// If the user has the "Link" box checked and starts picking
// link values, make sure that the "Type" combobox is updated
// to the type of the static value of the link.
{
DWORD irg;
AssertSz (lpallobjs->CDP_fLink, TEXT("Link box must be checked in order for this dialog to be visible!"));
// Get the link value from the combobox, and store
// the link name and static value.
irg = (int)SendMessage (lpallobjs->CDP_hWndLinkVal, CB_GETCURSEL, 0, 0);
Assert ((lpallobjs->lpfnDwQueryLinkData != NULL));
// REVIEW: If apps really need the name, we can get it here....
FSetTypeControl ((*lpallobjs->lpfnDwQueryLinkData) (QLD_LINKTYPE, irg, NULL, NULL), lpallobjs->CDP_hWndType);
return(FALSE); // return 0 'cuz we process the message
}
default:
return TRUE; // we didn't process message
}
case CBN_EDITCHANGE: // The user typed their own
switch (LOWORD (wParam))
{
case IDD_CUSTOM_NAME :
// Hack!!
// We need to post a message to ourselves to check if the user's
// actions entered text in the edit field.
PostMessage(hDlg, WM_USER+0x1000, 0L, 0L);
return(FALSE); // return 0 'cuz we process the message
break;
default:
return(TRUE);
break;
}
case EN_UPDATE :
switch (LOWORD (wParam))
{
case IDD_CUSTOM_VALUE :
{
BOOL fMod = FALSE;
if (FAllocAndGetValLpstz (hDlg, IDD_CUSTOM_NAME, &glpstzName))
{
LPUDPROP lpudp = LpudpropFindMatchingName (lpallobjs->lpUDObj, glpstzName);
if (lpudp != NULL)
{
if (lpallobjs->CDP_fAdd)
{
SendMessage (lpallobjs->CDP_hWndAdd, WM_SETTEXT, 0, (LPARAM) rgszAdd[iszMODIFY]);
lpallobjs->CDP_fAdd = FALSE;
}
}
// HACK: FSetupAddButton will change the Add button to
// say "Add" if lpallobjs->CDP_fAdd is FALSE. Since we just changed
// the button to "Modify", fake it out to not change
// the Add button by flipping lpallobjs->CDP_fAdd, then flipping it back.
if (!lpallobjs->CDP_fAdd)
fMod = lpallobjs->CDP_fAdd = TRUE;
FSetupAddButton (lpallobjs->CDP_iszType, lpallobjs->CDP_fLink, &lpallobjs->CDP_fAdd, lpallobjs->CDP_hWndAdd, lpallobjs->CDP_hWndVal, lpallobjs->CDP_hWndName, hDlg);
if (fMod)
lpallobjs->CDP_fAdd = FALSE;
}
return(FALSE); // return 0 'cuz we process the message
}
default:
return TRUE; // we didn't process message
}
case EN_KILLFOCUS :
switch (LOWORD (wParam))
{
// If the user finishes entering text in the Name edit control,
// be really cool and check to see if the name they entered
// is a property that is already defined. If it is,
// change the Add button to Modify.
case IDD_CUSTOM_NAME :
if (FAllocAndGetValLpstz (hDlg, IDD_CUSTOM_NAME, &glpstzName))
{
LPUDPROP lpudp = LpudpropFindMatchingName (lpallobjs->lpUDObj, glpstzName);
if (lpudp != NULL)
{
if (lpallobjs->CDP_fAdd)
{
SendMessage (lpallobjs->CDP_hWndAdd, WM_SETTEXT, 0, (LPARAM) rgszAdd[iszMODIFY]);
lpallobjs->CDP_fAdd = FALSE;
}
}
}
return FALSE;
default:
return TRUE;
}
default:
return TRUE;
} // switch
case WM_DESTROY:
MsoImageList_Destroy(lpallobjs->CDP_hImlS);
return FALSE;
case WM_NOTIFY :
switch (((NMHDR FAR *) lParam)->code)
{
case LVN_ITEMCHANGING :
// If an item is gaining focus, put it in the edit controls at
// the top of the dialog.
if (((NM_LISTVIEW FAR *) lParam)->uNewState & LVIS_SELECTED)
{
Assert ((((NM_LISTVIEW FAR *) lParam) != NULL));
lpallobjs->CDP_iItem = ((NM_LISTVIEW FAR *) lParam)->iItem;
ListView_GetItemText (lpallobjs->CDP_hWndCustomLV, lpallobjs->CDP_iItem, 0, lpallobjs->CDP_sz, BUFMAX);
PopulateControls (lpallobjs->lpUDObj, lpallobjs->CDP_sz, lpallobjs->CDP_cLinks, lpallobjs->lpfnDwQueryLinkData, hDlg,
GetDlgItem (hDlg, IDD_CUSTOM_NAME), lpallobjs->CDP_hWndVal, lpallobjs->CDP_hWndValText,
GetDlgItem (hDlg, IDD_CUSTOM_LINK), lpallobjs->CDP_hWndLinkVal, lpallobjs->CDP_hWndType,
lpallobjs->CDP_hWndBoolTrue, lpallobjs->CDP_hWndBoolFalse, lpallobjs->CDP_hWndGroup, lpallobjs->CDP_hWndAdd, lpallobjs->CDP_hWndDelete, &lpallobjs->CDP_fLink, &lpallobjs->CDP_fAdd);
return FALSE;
}
return TRUE;
break;
case PSN_APPLY :
if (IsWindowEnabled(lpallobjs->CDP_hWndAdd))
FGetCustomPropFromDlg(lpallobjs, hDlg);
// Swap the temp copy to be the real copy.
FDeleteTmpUDProps (lpallobjs->lpUDObj);
if (FUserDefShouldSave (lpallobjs->lpUDObj)
|| lpallobjs->fPropDlgChanged )
{
if( !ApplyChangesBackToFile(hDlg, (BOOL)((PSHNOTIFY*)lParam)->lParam, lpallobjs, itabCUSTOM) )
{
PostMessage( GetParent(hDlg), PSM_SETCURSEL, (WPARAM)-1, (LPARAM)lpallobjs->lpUDObj->m_hPage );
SetWindowLongPtr( hDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE );
return TRUE;
}
}
return PSNRET_NOERROR;
case PSN_RESET :
if (lpallobjs->fPropDlgChanged && !lpallobjs->fPropDlgPrompted)
{
if (ISavePropDlgChanges(lpallobjs, hDlg, ((NMHDR FAR *)lParam)->hwndFrom) != IDNO)
{
return(TRUE);
}
}
// User cancelled the changes, so just delete the tmp stuff.
FSwapTmpUDProps (lpallobjs->lpUDObj);
FDeleteTmpUDProps (lpallobjs->lpUDObj);
return TRUE;
case PSN_SETACTIVE :
return TRUE;
default:
break;
} // switch
break;
case WM_CONTEXTMENU:
WinHelp((HANDLE)wParam, NULL, HELP_CONTEXTMENU, (DWORD_PTR)rgIdhCustom);
break;
case WM_HELP:
WinHelp(((LPHELPINFO)lParam)->hItemHandle, NULL, HELP_WM_HELP, (DWORD_PTR)rgIdhCustom);
break;
} // switch
return FALSE;
} // FCustomDlgProc
//
// FGetCustomPropFromDlg
//
// Purpose: To get a custom property from the dialog.
// I.e. the user hit Add/Modify.
//
BOOL FGetCustomPropFromDlg(LPALLOBJS lpallobjs, HWND hDlg)
{
UDTYPES udtype;
NUM dbl;
LPVOID lpv;
int iItemT;
LPTSTR lpstzName;
LPVOID lpvSaveAsDword;
DWORD cch;
BOOL f;
lpstzName = NULL;
cch = 0;
if (FAllocAndGetValLpstz (hDlg, IDD_CUSTOM_NAME, &glpstzName))
{
LPUDPROP lpudp;
lpallobjs->CDP_fLink = FALSE; // just to be sure.
Assert(lpallobjs->CDP_fLink == TRUE || lpallobjs->CDP_fLink == FALSE);
// HACK: If the user enters a name that is already
// a property name, the default action of the object
// is to replace the data, treating it as an update.
// This will cause there to be 2 names in the listview
// though unless we just update the original one. So, first
// see if the new name is in the list already, and if
// it is, find it in the listview and set up to update it.
lpudp = LpudpropFindMatchingName (lpallobjs->lpUDObj, glpstzName);
if (lpudp != NULL)
{
LV_FINDINFO lvfi;
lvfi.flags = LVFI_STRING;
lvfi.psz = glpstzName;
iItemT = ListView_FindItem (lpallobjs->CDP_hWndCustomLV, -1, &lvfi);
}
else
{
iItemT = -1;
}
// Let's get the type, since this might be a MODIFY case
lpallobjs->CDP_iszType = (int)SendMessage(lpallobjs->CDP_hWndType, CB_GETCURSEL,0, 0);
// If the user has checked the link box, then the value
// must come from the client.
if (lpallobjs->CDP_fLink)
{
DWORD irg;
// Get the link name from the combobox, and store
// the link name and static value.
irg = (int)SendMessage (lpallobjs->CDP_hWndLinkVal, CB_GETCURSEL, 0, 0);
Assert ((lpallobjs->lpfnDwQueryLinkData != NULL));
Assert (((irg < lpallobjs->CDP_cLinks) && ((int) irg >= 0)));
cch = (DWORD)SendMessage (lpallobjs->CDP_hWndLinkVal, CB_GETLBTEXTLEN, irg, 0)+1; // Include the null-terminator
if (!FAllocString (&lpstzName, cch))
return(FALSE);
SendMessage (lpallobjs->CDP_hWndLinkVal, CB_GETLBTEXT, irg, (LPARAM) lpstzName );
// Set up the static type and value for display
// in the listbox
udtype = (UDTYPES) (*lpallobjs->lpfnDwQueryLinkData) (QLD_LINKTYPE, irg, NULL, lpstzName);
(*lpallobjs->lpfnDwQueryLinkData) (QLD_LINKVAL, irg, &lpv, lpstzName);
//
// HACK alert
//
// We want lpv to point to the value, not to be overloaded in the case of a dword or bool.
//
if ((udtype == wUDdw) || (udtype == wUDbool))
{
lpvSaveAsDword = lpv; // Really a DWORD
lpv = &lpvSaveAsDword;
}
}
else
{
if (lpallobjs->CDP_iszType != iszBOOL)
{
if (!FAllocAndGetValLpstz (hDlg, IDD_CUSTOM_VALUE, &glpstzValue))
return(FALSE);
}
// Convert the type in the combobox to a UDTYPES
switch (lpallobjs->CDP_iszType)
{
case iszTEXT :
udtype = wUDlpsz;
(LPTSTR) lpv = glpstzValue;
break;
case iszNUM :
udtype = UdtypesGetNumberType (glpstzValue, &dbl,
((LPUDINFO)lpallobjs->lpUDObj->m_lpData)->lpfnFSzToNum);
switch (udtype)
{
case wUDdw :
lpv = (DWORD *) &dbl;
break;
case wUDfloat :
(NUM *) lpv = &dbl;
break;
default :
(LPTSTR) lpv = glpstzValue;
// If the user doesn't want to convert the value to text, they can press "Cancel" and try again.
if (FDisplayConversionWarning (hDlg))
{
SetFocus(lpallobjs->CDP_hWndType);
return(FALSE);
}
udtype = wUDlpsz;
} // switch (udtype)
break;
case iszDATE :
if (FConvertDate (glpstzValue, lstrlen(glpstzValue) + 1, (LPFILETIME) &dbl))
{
udtype = wUDdate;
(NUM *) lpv = &dbl;
}
else
{
udtype = wUDlpsz;
(LPTSTR) lpv = glpstzValue;
// If the user doesn't want to convert the value to text, they can press "Cancel" and try again.
if (FDisplayConversionWarning (hDlg))
{
SetFocus(lpallobjs->CDP_hWndType);
return(FALSE);
}
}
break;
case iszBOOL :
{
udtype = wUDbool;
f = (BOOL)(SendMessage (lpallobjs->CDP_hWndBoolTrue, BM_GETSTATE, 0, 0) & BST_CHECKED);
lpv = &f;
break;
}
default :
AssertSz (0,TEXT("IDD_CUSTOM_TYPE combobox is whacked!"));
udtype = wUDinvalid;
} // switch (lpallobjs->CDP_iszType)
} // if (lpallobjs->CDP_fLink) ... else
// If we got valid input, add the property to the object
// and listbox.
if (udtype != wUDinvalid)
{
// The PropVariant created when we add this property.
LPPROPVARIANT lppropvar = NULL;
// The link data (link name itself) would have
// been stored above if the property was a link.
// This stores the static value that will eventually
// appear in the list view.
lppropvar = LppropvarUserDefAddProp (lpallobjs->lpUDObj, glpstzName, lpv, udtype,
(lpstzName != NULL) ? lpstzName : NULL,
(lpstzName != NULL) ? TRUE : FALSE, FALSE);
// HACK alert
//
// Here we want lpv be overloaded in the case of a dword or bool, since
// AddUDPropToListView calls WUdtypeToSz which assumes lpv is overloaded.
//
if ((udtype == wUDdw) || (udtype == wUDbool))
{
lpv = *(LPVOID *)lpv;
}
if (lppropvar)
{
AddUDPropToListView (lpallobjs->lpUDObj, lpallobjs->CDP_hWndCustomLV, glpstzName, lppropvar, iItemT, lpallobjs->CDP_fLink, fTrue, fTrue);
}
// For links, dealloc the buffer.
if (lpallobjs->CDP_fLink)
{
LocalFree(lpv);
lpv = NULL;
}
// Clear out the edit fields and disable the Add button again
SetCustomDlgDefButton(hDlg, gOKButtonID);
EnableWindow (lpallobjs->CDP_hWndAdd, FALSE);
SendMessage(lpallobjs->CDP_hWndName, CB_SETEDITSEL, 0, MAKELPARAM(0,-1)); // Select entire string
SendMessage(lpallobjs->CDP_hWndName, WM_CLEAR, 0, 0);
EnableWindow (lpallobjs->CDP_hWndDelete, FALSE);
// See bug 213
// if (fLink)
// {
// fLink = !fLink;
// SendDlgItemMessage (hDlg, IDD_CUSTOM_LINK, BM_SETCHECK, (WPARAM) fLink, 0);
// }
FSwapControls (lpallobjs->CDP_hWndVal, lpallobjs->CDP_hWndLinkVal,
lpallobjs->CDP_hWndBoolTrue, lpallobjs->CDP_hWndBoolFalse,
lpallobjs->CDP_hWndGroup, lpallobjs->CDP_hWndType,
lpallobjs->CDP_hWndValText, lpallobjs->CDP_fLink, lpallobjs->CDP_iszType == iszBOOL);
FSetupAddButton (lpallobjs->CDP_iszType, lpallobjs->CDP_fLink, &lpallobjs->CDP_fAdd, lpallobjs->CDP_hWndAdd, lpallobjs->CDP_hWndVal, lpallobjs->CDP_hWndName, hDlg);
// wUDbool doesn't use the edit control....
if (lpallobjs->CDP_iszType != iszBOOL)
ClearEditControl (lpallobjs->CDP_hWndVal, 0);
} // if (udtype != wUDinvalid)
SendDlgItemMessage(hDlg, IDD_CUSTOM_TYPE, CB_SETCURSEL, lpallobjs->CDP_iszType,0);
SetFocus(lpallobjs->CDP_hWndName);
// lpallobjs->fPropDlgChanged = TRUE;
if (lpstzName != NULL)
{
LocalFree(lpstzName);
}
return(TRUE);
}
return(FALSE);
}
/////////////////////////////////////////////////////////////////////////
//
// SetCustomDlgDefButton
//
// Set the new default button
//
/////////////////////////////////////////////////////////////////////////
VOID SetCustomDlgDefButton(HWND hDlg, int IDNew)
{
int IDOld;
if ((IDOld = LOWORD(SendMessage(hDlg, DM_GETDEFID, 0L, 0L))) != IDNew)
{
// Set the new default push button's control ID.
SendMessage(hDlg, DM_SETDEFID, IDNew, 0L);
// Set the new style.
SendDlgItemMessage(hDlg, IDNew, BM_SETSTYLE, BS_DEFPUSHBUTTON, MAKELPARAM(TRUE,0));
SendDlgItemMessage(hDlg, IDOld, BM_SETSTYLE, BS_PUSHBUTTON, MAKELPARAM(TRUE,0));
}
}
////////////////////////////////////////////////////////////////////////////////
//
// FAllocAndGetValLpstz
//
// Purpose:
// Gets the value from the edit box into the local buffer.
//
////////////////////////////////////////////////////////////////////////////////
BOOL PASCAL FAllocAndGetValLpstz (
HWND hDlg, // Handle of dialog control is in
DWORD dwId, // Id of control
LPTSTR *lplpstz) // Buffer
{
DWORD cch;
cch = (DWORD)SendDlgItemMessage (hDlg, dwId, WM_GETTEXTLENGTH, 0, 0);
cch++;
if (FAllocString (lplpstz, cch))
{
// Get the entry. Remember to null-terminate it.
cch = (DWORD)SendDlgItemMessage (hDlg, dwId, WM_GETTEXT, cch, (LPARAM) *lplpstz );
(*lplpstz)[cch] = TEXT('\0');
return TRUE;
}
return FALSE;
} // FAllocAndGetValLpstz
////////////////////////////////////////////////////////////////////////////////
//
// FAllocString
//
// Purpose:
// Allocates a string big enough to to hold cch char's. Only allocates if needed.
//
////////////////////////////////////////////////////////////////////////////////
BOOL PASCAL FAllocString (
LPTSTR *lplpstz,
DWORD cch)
{
// Figure out how many bytes we need to allocate.
DWORD cbNew = (cch * sizeof(TCHAR));
// And how many bytes we need to free.
DWORD cbOld = *lplpstz == NULL
? 0
: (lstrlen (*lplpstz) + 1) * sizeof(TCHAR);
// If we need to free or allocate data.
if (*lplpstz == NULL || cbNew > cbOld)
{
LPTSTR lpszNew;
// Allocate the new data.
lpszNew = LocalAlloc( LPTR, cbNew);
if (lpszNew == NULL)
{
return FALSE;
}
// Free the old data.
if (*lplpstz != NULL)
{
LocalFree(*lplpstz);
}
*lplpstz = lpszNew;
}
// Make this a valid (empty) string.
**lplpstz = TEXT('\0');
return TRUE;
} // FAllocString
////////////////////////////////////////////////////////////////////////////////
//
// ClearEditControl
//
// Purpose:
// Clears any text from an edit control
//
////////////////////////////////////////////////////////////////////////////////
void PASCAL
ClearEditControl
(HWND hDlg, // Dialog handle
DWORD dwId) // Id of edit control
{
// Really cheesey. Clear the edit control by selecting
// everything then clearing the selection
if (dwId == 0)
{
SendMessage (hDlg, EM_SETSEL, 0, -1);
SendMessage (hDlg, WM_CLEAR, 0, 0);
}
else
{
SendDlgItemMessage (hDlg, dwId, EM_SETSEL, 0, -1);
SendDlgItemMessage (hDlg, dwId, WM_CLEAR, 0, 0);
}
} // ClearEditControl
////////////////////////////////////////////////////////////////////////////////
//
// UdtypesGetNumberType
//
// Purpose:
// Gets the number type from the string and returns the value, either
// a float or dword in numval.
//
////////////////////////////////////////////////////////////////////////////////
UDTYPES PASCAL
UdtypesGetNumberType
(LPTSTR lpstz, // String containing the number
NUM *lpnumval, // The value of the number
BOOL (*lpfnFSzToNum)(NUM *, LPTSTR)) // Sz To Num routine, can be null
{
TCHAR *pc;
errno = 0;
*(DWORD *) lpnumval = wcstol(lpstz, &pc, 10);
if ((!errno) && (*pc == TEXT('\0')))
return wUDdw;
// Try doing a float conversion if int fails
if (lpfnFSzToNum != NULL)
{
if ((*lpfnFSzToNum)(lpnumval, lpstz))
return wUDfloat;
}
return wUDinvalid;
} // UdtypesGetNumberType
////////////////////////////////////////////////////////////////////////////////
//
// YearIndexFromShortDateFormat
//
//
// Determines the zero-based position index of the year component
// of a textual representation of the date based on the specified date format.
// This value may be used as the iYear arg to ScanDateNums function.
//
////////////////////////////////////////////////////////////////////////////////
int YearIndexFromShortDateFormat( TCHAR chFmt )
{
switch( chFmt )
{
case MMDDYY:
case DDMMYY:
return 2;
case YYMMDD:
return 0;
}
return -1;
}
////////////////////////////////////////////////////////////////////////////////
//
// IsGregorian
//
// Purpose:
// Reports whether the specified calendar is a gregorian calendar.
//
////////////////////////////////////////////////////////////////////////////////
BOOL IsGregorian( CALID calid )
{
switch (calid)
{
case CAL_GREGORIAN:
case CAL_GREGORIAN_US:
case CAL_GREGORIAN_ME_FRENCH:
case CAL_GREGORIAN_ARABIC:
case CAL_GREGORIAN_XLIT_ENGLISH:
case CAL_GREGORIAN_XLIT_FRENCH:
return TRUE;
// these are non-gregorian:
//case CAL_JAPAN
//case CAL_TAIWAN
//case CAL_KOREA
//case CAL_HIJRI
//case CAL_THAI
//case CAL_HEBREW
}
return FALSE;
}
////////////////////////////////////////////////////////////////////////////////
//
// GregorianYearFromAbbreviatedYear
//
// Purpose:
// Based on current locale settings, calculates the year corresponding to the
// specified 1- or 2-digit abbreviated value.
//
////////////////////////////////////////////////////////////////////////////////
int GregorianYearFromAbbreviatedYear( LCID lcid, CALID calid, int nAbbreviatedYear )
{
TCHAR szData[16];
LONG nYearHigh = -1;
int nBaseCentury;
int nYearInCentury = 0;
// We're handling two-digit values for gregorian calendars only
if (nAbbreviatedYear < 100)
{
// We don't support non-gregorian date windowing here
// because that would be insanely complex and prone to error -ccooney 2000/02/04
if( !IsGregorian( calid )
|| !GetCalendarInfo( lcid, calid, CAL_ITWODIGITYEARMAX|CAL_RETURN_NUMBER,
NULL, 0, &nYearHigh ) )
{
// In the absence of a default, use 2029 as the cutoff, just like monthcal.
nYearHigh = 2029;
}
//
// Copy the century of nYearHigh into nAbbreviatedYear.
//
nAbbreviatedYear += (nYearHigh - nYearHigh % 100);
//
// If it exceeds the max, then drop to previous century.
//
if (nAbbreviatedYear > nYearHigh)
nAbbreviatedYear -= 100;
}
return nAbbreviatedYear;
}
////////////////////////////////////////////////////////////////////////////////
//
// FConvertDate
//
// Purpose:
// Converts the given string to a date.
//
////////////////////////////////////////////////////////////////////////////////
BOOL
PASCAL
FConvertDate(
LPTSTR lpstz, // String having the date
DWORD cchMax,
LPFILETIME lpft // The date in FILETIME format
)
{
FILETIME ft;
SYSTEMTIME st;
TCHAR szSep[3];
TCHAR szFmt[10];
TCHAR szCalID[8];
unsigned int ai[3];
int iYear =-1; // index of ai member that represents the year value
CALID calid;
TCHAR szDate[256];
TCHAR szMonth[256];
TCHAR *pch;
TCHAR *pchT;
DWORD cch;
DWORD i;
if (!(GetLocaleInfo (LOCALE_USER_DEFAULT, LOCALE_IDATE, szFmt, ARRAYSIZE(szFmt))) ||
!(GetLocaleInfo (LOCALE_USER_DEFAULT, LOCALE_SDATE, szSep, ARRAYSIZE(szSep))) ||
!(GetLocaleInfo (LOCALE_USER_DEFAULT, LOCALE_ICALENDARTYPE, szCalID, ARRAYSIZE(szCalID))) )
return FALSE;
iYear = YearIndexFromShortDateFormat(szFmt[0]);
// Augh! It's an stz so we need to pass the DWORDs at the start
if (!ScanDateNums(lpstz, szSep, ai, sizeof(ai)/sizeof(unsigned int),iYear))
{
// Could be that the string contains the short version of the month, e.g. 03-Mar-95
StringCchCopy( szDate, ARRAYSIZE(szDate), lpstz ); // don't care if it truncates
pch = szDate;
// Let's get to the first character of the month, if there is one
while(((IsCharAlphaNumeric(*pch) && !IsCharAlpha(*pch)) || (*pch == szSep[0])) && (*pch != 0))
{
++pch;
}
// If we got to the end of the string, there really was an error
if (*pch == 0)
return(FALSE);
// Let's find the length of the month string
pchT = pch+1;
while ((*pchT != szSep[0]) && (*pchT != 0))
{
++pchT;
}
cch = (DWORD)(pchT - pch);
// Loop through all the months and see if we match one
// There can be 13 months
for (i = 1; i <= 13; ++i)
{
if (!GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SABBREVMONTHNAME1+i-1,
szMonth, ARRAYSIZE(szMonth)))
{
return(FALSE);
}
if (CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE | NORM_IGNOREKANATYPE | NORM_IGNOREWIDTH,
pch, cch, szMonth, lstrlen(szMonth)) == 2)
{
break;
}
}
if (i > 13)
return(FALSE);
// We found the month. wsprintf zero-terminates
if (FAILED(StringCchPrintf(pch, cch, TEXT("%u"), i)))
return(FALSE);
pch += lstrlen( pch );
while (*pch++ = *(pch+1));
// Try and convert again
if (!ScanDateNums(szDate, szSep, ai, 3, iYear))
return(FALSE);
} // if (!ScanDateNums(lpstz, szSep, ai, 3))
ZeroMemory(&st, sizeof(st));
switch (szFmt[0])
{
case MMDDYY:
st.wMonth = (WORD)ai[0];
st.wDay = (WORD)ai[1];
st.wYear = (WORD)ai[2];
break;
case DDMMYY:
st.wDay = (WORD)ai[0];
st.wMonth = (WORD)ai[1];
st.wYear = (WORD)ai[2];
break;
case YYMMDD:
st.wYear = (WORD)ai[0];
st.wMonth = (WORD)ai[1];
st.wDay = (WORD)ai[2];
break;
default:
return FALSE;
}
if (st.wYear < ONECENTURY)
{
calid = wcstol( szCalID, NULL, 10 );
st.wYear = (WORD)GregorianYearFromAbbreviatedYear(
LOCALE_USER_DEFAULT, calid, st.wYear );
}
if (!SystemTimeToFileTime (&st, &ft))
return(FALSE);
return(LocalFileTimeToFileTime(&ft, lpft));
} // FConvertDate
////////////////////////////////////////////////////////////////////////////////
//
// PopulateUDListView
//
// Purpose:
// Populates the entire ListView with the User-defined properties
// in the given object.
//
////////////////////////////////////////////////////////////////////////////////
void PASCAL
PopulateUDListView
(HWND hWnd, // Handle of list view window
LPUDOBJ lpUDObj) // UD Prop object
{
LPUDITER lpudi;
LPPROPVARIANT lppropvar;
BOOL fLink;
BOOL fLinkInvalid;
// Iterate through the list of user-defined properties, adding each
// one to the listview.
for( lpudi = LpudiUserDefCreateIterator (lpUDObj);
FUserDefIteratorValid (lpudi);
FUserDefIteratorNext (lpudi)
)
{
// Get the name of this property.
LPTSTR tszPropertyName = LpszUserDefIteratorName( lpudi );
// If the property has no name, or the name indicates that it
// is a hidden property, then move on to the next property.
if( tszPropertyName == NULL
||
*tszPropertyName == HIDDENPREFIX )
{
continue;
}
lppropvar = LppropvarUserDefGetIteratorVal (lpudi, &fLink, &fLinkInvalid);
if (lppropvar == NULL)
return;
// If this isn't a supported type, don't display it.
if( !ISUDTYPE(lppropvar->vt) )
continue;
//
// In the Shell, we want all links to show up as invalid, so set that here...
//
fLinkInvalid = TRUE;
AddUDPropToListView (lpUDObj, hWnd, LpszUserDefIteratorName (lpudi ), lppropvar, -1, fLink, fLinkInvalid, FALSE);
} // for( lpudi = LpudiUserDefCreateIterator (lpUDObj); ...
FUserDefDestroyIterator (&lpudi);
} // PopulateUDListView
////////////////////////////////////////////////////////////////////////////////
//
// AddUDPropToListView
//
// Purpose:
// Adds the given property to the list view or updates an existing one
// if iItem >= 0
//
////////////////////////////////////////////////////////////////////////////////
void PASCAL AddUDPropToListView (
LPUDOBJ lpUDObj,
HWND hWnd, // Handle of list view
LPTSTR lpszName, // Name of property
LPPROPVARIANT lppropvar, // The property value.
int iItem, // Index to add item at
BOOL fLink, // Indicates the value is a link
BOOL fLinkInvalid, // Is the link invalid?
BOOL fMakeVisible) // Should the property be forced to be visible
{
LV_ITEM lvi;
TCHAR sz[BUFMAX];
WORD irg;
BOOL fSuccess;
BOOL fUpdate;
// If iItem >= 0, then the item should be updated, otherwise,
// it should be added.
if (fUpdate = (iItem >= 0))
{
lvi.iItem = iItem;
if (fLink)
lvi.iImage = (fLinkInvalid) ? giInvLinkIcon : giLinkIcon;
else
lvi.iImage = giBlankIcon;
lvi.mask = LVIF_IMAGE;
lvi.iSubItem = iszNAME;
fSuccess = ListView_SetItem (hWnd, &lvi);
Assert (fSuccess); // We don't *really* care, just want to know when it happens
}
else
{
// This always adds to the end of the list....
lvi.iItem = ListView_GetItemCount (hWnd);
// First add the label to the list
lvi.iSubItem = iszNAME;
lvi.pszText = lpszName;
if (fLink)
lvi.iImage = (fLinkInvalid) ? giInvLinkIcon : giLinkIcon;
else
lvi.iImage = giBlankIcon;
lvi.mask = LVIF_TEXT | LVIF_IMAGE;
lvi.iItem = ListView_InsertItem (hWnd, &lvi);
if (lvi.iItem == 0)
ListView_SetItemState(hWnd, 0, LVIS_FOCUSED, LVIS_FOCUSED);
}
// Convert the data to a string and print it
lvi.mask = LVIF_TEXT;
irg = WUdtypeToSz (lppropvar, sz, BUFMAX, ((LPUDINFO)lpUDObj->m_lpData)->lpfnFNumToSz);
lvi.pszText = sz;
lvi.iSubItem = iszVAL;
fSuccess = ListView_SetItem (hWnd, &lvi);
Assert (fSuccess); // We don't *really* care, just want to know when it happens
// Put the type in the listview
lvi.iSubItem = iszTYPE;
lvi.pszText = (LPTSTR) rgszTypes[irg];
fSuccess = ListView_SetItem (hWnd, &lvi);
Assert (fSuccess); // We don't *really* care, just want to know when it happens
if (fMakeVisible)
{
fSuccess = ListView_EnsureVisible(hWnd, lvi.iItem, FALSE);
Assert (fSuccess); // We don't *really* care, just want to know when it happens
}
} // AddUDPropToListView
////////////////////////////////////////////////////////////////////////////////
//
// InitListView
//
// Purpose:
// Initializes a list view control
//
////////////////////////////////////////////////////////////////////////////////
void PASCAL
InitListView
(HWND hWndLV, // Handle of parent dialog
int irgLast, // Index of last column in array
TCHAR rgsz[][SHORTBUFMAX], // Array of column headings
BOOL fImageList) // Should the listview have an image list
{
HICON hIcon;
RECT rect;
HIMAGELIST hImlS;
LV_COLUMN lvc;
int irg;
lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH;
lvc.fmt = LVCFMT_LEFT;
// Initially force all columns to be the same size & fill the control.
GetClientRect(hWndLV, &rect);
// Subtract fudge factor
lvc.cx = (rect.right-rect.left)/(irgLast+1)-(GetSystemMetrics(SM_CXVSCROLL)/(irgLast+1));
// Add in all the columns.
for (irg = 0; irg <= irgLast; irg++)
{
lvc.pszText = rgsz[irg];
lvc.iSubItem = irg;
ListView_InsertColumn (hWndLV, irg, &lvc);
}
if (!fImageList)
return;
hIcon = LoadIcon (g_hmodThisDll, MAKEINTRESOURCE (IDD_BLANK_ICON));
if (hIcon != NULL)
{
hImlS = MsoImageList_Create (16, 16, TRUE, ICONSMAX, 0);
ListView_SetImageList (hWndLV, hImlS, LVSIL_SMALL);
giBlankIcon = MsoImageList_ReplaceIcon (hImlS, -1, hIcon);
Assert ((giBlankIcon != -1));
}
} // InitListView
////////////////////////////////////////////////////////////////////////////////
//
// FSwapControls
//
// Purpose:
// Swaps the controls needed to display link info.
//
////////////////////////////////////////////////////////////////////////////////
BOOL PASCAL
FSwapControls
(HWND hWndVal, // Handle of Value window
HWND hWndLinkVal, // Handle of Link Value Combo box
HWND hWndBoolTrue, // Handle of True radio button
HWND hWndBoolFalse, // Handle of False radio button
HWND hWndGroup, // Handle of Group box
HWND hWndType, // Handle of Type window
HWND hWndValText,
BOOL fLink, // Flag indicating a link
BOOL fBool) // Flag indicating a bool
{
if (fLink)
{
SendMessage (hWndValText, WM_SETTEXT, 0, (LPARAM) rgszValue[iszSOURCE]);
ShowWindow (hWndVal, SW_HIDE);
ShowWindow (hWndBoolTrue, SW_HIDE);
ShowWindow (hWndBoolFalse, SW_HIDE);
ShowWindow (hWndGroup, SW_HIDE);
ShowWindow (hWndLinkVal, SW_SHOW);
EnableWindow (hWndType, FALSE);
ClearEditControl (hWndVal, 0);
}
else
{
SendMessage (hWndValText, WM_SETTEXT, 0, (LPARAM) rgszValue[iszVALUE]);
ShowWindow (hWndLinkVal, SW_HIDE);
EnableWindow (hWndType, TRUE);
if (fBool)
{
ShowWindow (hWndVal, SW_HIDE);
ShowWindow (hWndBoolTrue, SW_SHOW);
ShowWindow (hWndBoolFalse, SW_SHOW);
ShowWindow (hWndGroup, SW_SHOW);
SendMessage (hWndBoolTrue, BM_SETCHECK, (WPARAM) CHECKED, 0);
SendMessage (hWndBoolFalse, BM_SETCHECK, (WPARAM) CLEAR, 0);
SendMessage (hWndType, CB_SETCURSEL, iszBOOL, 0);
ClearEditControl (hWndVal, 0);
}
else
{
ShowWindow (hWndVal, SW_SHOW);
EnableWindow(hWndVal, TRUE);
ShowWindow (hWndBoolTrue, SW_HIDE);
ShowWindow (hWndBoolFalse, SW_HIDE);
ShowWindow (hWndGroup, SW_HIDE);
SendMessage (hWndType, CB_SETCURSEL, iszTEXT, 0);
}
}
return TRUE;
} // FSwapControls
////////////////////////////////////////////////////////////////////////////////
//
// PopulateControls
//
// Purpose:
// Populates the edit controls with the appropriate date from the object
//
////////////////////////////////////////////////////////////////////////////////
VOID PASCAL PopulateControls (
LPUDOBJ lpUDObj, // Pointer to object
LPTSTR szName, // Name of the item to populate controls with
DWORD cLinks, // Number of links
DWQUERYLD lpfnDwQueryLinkData, // Pointer to app link callback
HWND hDlg, // Handle of the dialog
HWND hWndName, // Handle of the Name window
HWND hWndVal, // Handle of Value window
HWND hWndValText, // Handle of Value LTEXT
HWND hWndLink, // Handle of Link checkbox
HWND hWndLinkVal, // Handle of Link Value window
HWND hWndType, // Handle of Type window
HWND hWndBoolTrue, // Handle of True radio button
HWND hWndBoolFalse, // Handle of False radio button
HWND hWndGroup, // Handle of Group window
HWND hWndAdd, // Handle of Add button
HWND hWndDelete, // Handle of Delete button
BOOL *pfLink, // Indicates that the value is a link
BOOL *pfAdd) // Indicates the state of the Add button
{
UDTYPES udtype;
LPVOID lpv;
LPPROPVARIANT lppropvar; // A property from the UDObj linked-list.
BOOL f,fT;
TCHAR sz[BUFMAX];
LPUDPROP lpudp;
// Grab the type for the string and set up the dialog to have the right
// controls to display it.
udtype = UdtypesUserDefType (lpUDObj, szName);
AssertSz ((udtype != wUDinvalid), TEXT("User defined properties or ListView corrupt"));
// Get a name-specified property from the UD linked-list.
lppropvar = LppropvarUserDefGetPropVal (lpUDObj, szName, pfLink, &fT);
Assert (lppropvar != NULL || udtype == wUDbool || udtype == wUDdw);
if (lppropvar == NULL)
return;
lpv = LpvoidUserDefGetPropVal (lpUDObj, szName, UD_STATIC | UD_PTRWIZARD, pfLink, &fT);
Assert((lpv != NULL) || (udtype == wUDbool) || (udtype == wUDdw));
FSwapControls (hWndVal, hWndLinkVal, hWndBoolTrue, hWndBoolFalse, hWndGroup, hWndType, hWndValText, *pfLink, (udtype == wUDbool));
SendMessage (hWndType, CB_SETCURSEL, (WPARAM) WUdtypeToSz (lppropvar, (TCHAR *) sz, BUFMAX,
((LPUDINFO)lpUDObj->m_lpData)->lpfnFNumToSz), 0);
SendMessage (hWndLink, BM_SETCHECK, (WPARAM) *pfLink, 0);
if (cLinks) // Let's make sure we enable the window if links are allowed
EnableWindow(hWndLink, TRUE);
if (*pfLink)
{
FCreateListOfLinks (cLinks, lpfnDwQueryLinkData, hWndLinkVal);
lpv = LpvoidUserDefGetPropVal (lpUDObj, szName, UD_LINK | UD_PTRWIZARD, pfLink, &fT);
Assert (lpv != NULL || udtype == wUDbool || udtype == wUDdw);
AssertSz ((lpv != NULL), TEXT("Dialog is corrupt in respect to Custom Properties database"));
// This code is added for bug 188 and the code is ugly !! :)
lpudp = LpudpropFindMatchingName (lpUDObj, szName);
if ((lpudp != NULL) && (lpudp->fLinkInvalid))
{
SetCustomDlgDefButton(hDlg, IDD_CUSTOM_DELETE);
SendMessage(hWndName, WM_SETTEXT, 0, (LPARAM)szName);
SendMessage(hWndVal, WM_SETTEXT, 0, (LPARAM)lpv);
EnableWindow(hWndDelete, TRUE);
EnableWindow(hWndAdd, FALSE);
EnableWindow(hWndLink, FALSE);
EnableWindow(hWndType, FALSE);
ShowWindow(hWndLinkVal, SW_HIDE);
ShowWindow(hWndVal, SW_SHOW);
EnableWindow(hWndVal, FALSE);
return;
}
// Select the current link for this property in the combobox. If the link
// name no longer exists (there's some contrived cases where this can
// happen) then this will select nothing.
SendMessage (hWndLinkVal, CB_SELECTSTRING, 0, (LPARAM) lpv);
EnableWindow(hWndLink, TRUE);
}
else if (udtype == wUDbool)
{
SendMessage ((lpv) ? hWndBoolTrue : hWndBoolFalse, BM_SETCHECK, CHECKED, 0);
SendMessage ((lpv) ? hWndBoolFalse : hWndBoolTrue, BM_SETCHECK, CLEAR, 0);
EnableWindow(hWndType, TRUE);
}
else
{
SendMessage (hWndVal, WM_SETTEXT, 0, (LPARAM) sz);
EnableWindow (hWndVal, TRUE);
EnableWindow(hWndType, TRUE);
}
if (*pfAdd)
{
SendMessage (hWndAdd, WM_SETTEXT, 0, (LPARAM) rgszAdd[iszMODIFY]);
*pfAdd = FALSE;
}
// HACK: Because the EN_UPDATE handler for hWndName checks fAdd to
// see if the button should be set to Add, when we set the text
// in the edit control, the button will change to Add unless
// fAdd is set to TRUE. Temporarily set the flag to TRUE to force
// the button to not change. Restore the original value after the
// text has been set.
f = *pfAdd;
*pfAdd = TRUE;
SendMessage (hWndName, WM_SETTEXT, 0, (LPARAM) szName);
*pfAdd = f;
// If we can fill the data in the controls, turn on the
// Delete button too.
EnableWindow (hWndDelete, TRUE);
SetCustomDlgDefButton(hDlg, gOKButtonID);
EnableWindow (hWndAdd, FALSE);
} // PopulateControls
////////////////////////////////////////////////////////////////////////////////
//
// FSetupAddButton
//
// Purpose:
// Sets up the Add button correctly based on the type & flags.
//
////////////////////////////////////////////////////////////////////////////////
BOOL PASCAL
FSetupAddButton
(DWORD iszType, // Index of the type in combobox
BOOL fLink, // Indicates a link
BOOL *pfAdd, // Indicates if the Add button is showing
HWND hWndAdd, // Handle of Add button
HWND hWndVal, // Handle of value button
HWND hWndName, // Handle of Name
HWND hDlg) // Handle of dialog
{
// Once the user starts typing, we can enable the Add button
// if there is text in the name & the value (unless this
// is a link or boolean, in which case we don't care about
// the value).
BOOL f;
if ((iszType != iszBOOL) && (!fLink))
{
if (SendMessage (hWndVal, EM_LINELENGTH, 0, 0) != 0)
{
f = (SendMessage (hWndName, WM_GETTEXTLENGTH, 0, 0) != 0);
if (f)
SetCustomDlgDefButton(hDlg, IDD_CUSTOM_ADD);
else
SetCustomDlgDefButton(hDlg, gOKButtonID);
EnableWindow (hWndAdd, f);
}
else
{
SetCustomDlgDefButton(hDlg, gOKButtonID);
EnableWindow (hWndAdd, FALSE);
}
}
// If it's a bool or link, just check to see that the name
// has stuff in it.
else
{
f = SendMessage (hWndName, WM_GETTEXTLENGTH, 0, 0) != 0;
if (f)
SetCustomDlgDefButton(hDlg, IDD_CUSTOM_ADD);
else
SetCustomDlgDefButton(hDlg, gOKButtonID);
EnableWindow (hWndAdd, f);
}
if (!*pfAdd)
{
SendMessage (hWndAdd, WM_SETTEXT, 0, (LPARAM) rgszAdd[iszADD]);
*pfAdd = TRUE;
}
return TRUE;
} // FSetupAddButton
////////////////////////////////////////////////////////////////////////////////
//
// WUdtypeToSz
//
// Purpose:
// Converts the given type into a string representation. Returns the
// index in the type combobox of the type.
//
////////////////////////////////////////////////////////////////////////////////
WORD PASCAL WUdtypeToSz (
LPPROPVARIANT lppropvar, // Value with the type to be converted.
LPTSTR psz, // Buffer to put converted val in
DWORD cchMax, // Size of buffer (in chars)
BOOL (*lpfnFNumToSz)(NUM *, LPTSTR, DWORD))
{
SYSTEMTIME st;
WORD irg;
FILETIME ft;
Assert (lppropvar != NULL);
switch (lppropvar->vt)
{
case wUDlpsz :
StringCchCopy(psz, cchMax, lppropvar->pwszVal ); // don't care if it truncates
irg = iszTEXT;
break;
case wUDdate :
if (FScanMem((LPBYTE)&lppropvar->filetime,
0, sizeof(FILETIME))) // if the date struct is all 0's
{
*psz = 0; // display the empty string
}
else if (!FileTimeToLocalFileTime(&lppropvar->filetime, &ft)
|| !FileTimeToSystemTime (&ft, &st)
|| (!GetDateFormat (LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, psz, cchMax)))
{
#ifdef DEBUG
DWORD dwErr = GetLastError();
#endif DEBUG
irg = iszUNKNOWN;
*psz = 0;
break;
}
irg = iszDATE;
break;
case wUDdw :
Assert(cchMax >= 11);
Assert(lppropvar->vt == VT_I4);
StringCchPrintf(psz, cchMax, TEXT("%ld"), lppropvar->lVal); // don't care if it truncates
irg = iszNUM;
break;
case wUDfloat :
if (lpfnFNumToSz != NULL)
irg = (*lpfnFNumToSz)((NUM*)&lppropvar->dblVal, psz, cchMax) ? iszNUM : iszUNKNOWN;
else
{
irg = iszUNKNOWN;
*psz = 0;
}
break;
case wUDbool :
// don't care if it truncates
StringCchCopy( psz, cchMax, lppropvar->boolVal ? (LPTSTR) &rgszBOOL[iszTRUE] : (LPTSTR) &rgszBOOL[iszFALSE] );
irg = iszBOOL;
break;
default :
irg = iszUNKNOWN;
} // switch
return irg;
} // WUdtypeToSz
////////////////////////////////////////////////////////////////////////////////
//
// FCreateListOfLinks
//
// Purpose:
// Creates the dropdown list of linkable items.
//
////////////////////////////////////////////////////////////////////////////////
BOOL PASCAL FCreateListOfLinks(
DWORD cLinks, // Number of links
DWQUERYLD lpfnDwQueryLinkData, // Link data callback
HWND hWndLinkVal) // Link Value window handle
{
DWORD irg;
LPTSTR lpstz;
// If the combobox is already filled, don't fill it
if (irg = (int)SendMessage(hWndLinkVal, CB_GETCOUNT,0, 0))
{
Assert(irg == cLinks);
return(TRUE);
}
lpstz = NULL;
// Call back the client app to get the list of linkable
// values, and put them in the value combobox.
for (irg = 0; irg < cLinks; irg++)
{
lpstz = (TCHAR *) ((*lpfnDwQueryLinkData) (QLD_LINKNAME, irg, &lpstz, NULL));
if (lpstz != NULL)
{
SendMessage (hWndLinkVal, CB_INSERTSTRING, (WPARAM) -1, (LPARAM) lpstz);
LocalFree(lpstz);
// REVIEW: We probably ought to figure out a way to be more efficient here....
}
}
return TRUE;
} // FCreateListOfLinks
////////////////////////////////////////////////////////////////////////////////
//
// FSetTypeControl
//
// Purpose:
// Sets the type control to have the given type selected.
//
////////////////////////////////////////////////////////////////////////////////
BOOL PASCAL FSetTypeControl (
UDTYPES udtype, // Type to set the type to
HWND hWndType) // Handle of type control
{
WORD iType;
switch (udtype)
{
case wUDlpsz :
iType = iszTEXT;
break;
case wUDfloat :
case wUDdw :
iType = iszNUM;
break;
case wUDbool :
iType = iszBOOL;
break;
case wUDdate :
iType = iszDATE;
break;
default:
return FALSE;
}
SendMessage (hWndType, CB_SETCURSEL, (WPARAM) iType, 0);
return TRUE;
} // FSetTypeControl
////////////////////////////////////////////////////////////////////////////////
//
// DeleteItem
//
// Purpose:
// Deletes an item from the UD object and the listview.
//
////////////////////////////////////////////////////////////////////////////////
void PASCAL DeleteItem (
LPUDOBJ lpUDObj,
HWND hWndLV,
int iItem,
TCHAR sz[])
{
int i;
ListView_DeleteItem (hWndLV, iItem);
FUserDefDeleteProp (lpUDObj, sz);
// We just nuked the item with the focus, so let's get the new one
// if there are still items in the listview
if ((i = ListView_GetItemCount(hWndLV)) != 0)
{
// Figure out the index of the item to get the focus
i = (i == iItem) ? iItem - 1 : iItem;
ListView_SetItemState(hWndLV, i, LVIS_FOCUSED, LVIS_FOCUSED);
}
} // DeleteItem
////////////////////////////////////////////////////////////////////////////////
//
// ResetTypeControl
//
// Purpose:
// Resets the value of the type control to Text.
//
////////////////////////////////////////////////////////////////////////////////
void PASCAL ResetTypeControl (
HWND hDlg, // Handle of dialog
DWORD dwId, // Id of control
DWORD *piszType) // The type we've reset to
{
SendDlgItemMessage (hDlg, dwId, CB_SETCURSEL, iszTEXT, 0);
*piszType = iszTEXT;
} // ResetTypeControl
////////////////////////////////////////////////////////////////////////////////
//
// FDisplayConversionWarning
//
// Purpose:
// Displays a warning about types being converted. Returns TRUE if
// the user presses "Cancel"
//
////////////////////////////////////////////////////////////////////////////////
BOOL PASCAL FDisplayConversionWarning(HWND hDlg) // Handle of parent window
{
return (IdDoAlert(hDlg, idsPEWarningText, MB_ICONEXCLAMATION | MB_OKCANCEL) == IDCANCEL);
} // FDisplayConversionWarning
////////////////////////////////////////////////////////////////////////////////
//
// LoadTextStrings
//
// Purpose:
// Loads all of the text needed by the dialogs from the DLL.
//
////////////////////////////////////////////////////////////////////////////////
BOOL PASCAL FLoadTextStrings (void)
{
register int cLoads = 0;
register int cAttempts = 0;
// CchGetString returns a cch, so make it into a 1 or 0
// then add up the results,making sure we load as many as
// we try.
cLoads += (CchGetString (idsPEB, rgszOrders[iszBYTES], SHORTBUFMAX) && TRUE);
cAttempts++;
cLoads += (CchGetString (idsPEKB, rgszOrders[iszORDERKB], SHORTBUFMAX) && TRUE);
cAttempts++;
cLoads += (CchGetString (idsPEMB, rgszOrders[iszORDERMB], SHORTBUFMAX) && TRUE);
cAttempts++;
cLoads += (CchGetString (idsPEGB, rgszOrders[iszORDERGB], SHORTBUFMAX) && TRUE);
cAttempts++;
cLoads += (CchGetString (idsPETB, rgszOrders[iszORDERTB], SHORTBUFMAX) && TRUE);
cAttempts++;
cLoads += (CchGetString (idsPEBytes, rgszStats[iszBYTES], SHORTBUFMAX) && TRUE);
cAttempts++;
cLoads += (CchGetString (idsPEPages, rgszStats[iszPAGES], SHORTBUFMAX) && TRUE);
cAttempts++;
cLoads += (CchGetString (idsPEPara, rgszStats[iszPARA], SHORTBUFMAX) && TRUE);
cAttempts++;
cLoads += (CchGetString (idsPELines, rgszStats[iszLINES], SHORTBUFMAX) && TRUE);
cAttempts++;
cLoads += (CchGetString (idsPEWords, rgszStats[iszWORDS], SHORTBUFMAX) && TRUE);
cAttempts++;
cLoads += (CchGetString (idsPEChars, rgszStats[iszCHARS], SHORTBUFMAX) && TRUE);
cAttempts++;
cLoads += (CchGetString (idsPESlides, rgszStats[iszSLIDES], SHORTBUFMAX) && TRUE);
cAttempts++;
cLoads += (CchGetString (idsPENotes, rgszStats[iszNOTES], SHORTBUFMAX) && TRUE);
cAttempts++;
cLoads += (CchGetString (idsPEHiddenSlides, rgszStats[iszHIDDENSLIDES], SHORTBUFMAX) && TRUE);
cAttempts++;
cLoads += (CchGetString (idsPEMMClips, rgszStats[iszMMCLIPS], SHORTBUFMAX) && TRUE);
cAttempts++;
cLoads += (CchGetString (idsPEFormat, rgszStats[iszFORMAT], SHORTBUFMAX) && TRUE);
cAttempts++;
cLoads += (CchGetString (idsPEText, rgszTypes[iszTEXT], SHORTBUFMAX) && TRUE);
cAttempts++;
cLoads += (CchGetString (idsPEDate, rgszTypes[iszDATE], SHORTBUFMAX) && TRUE);
cAttempts++;
cLoads += (CchGetString (idsPENumber, rgszTypes[iszNUM], SHORTBUFMAX) && TRUE);
cAttempts++;
cLoads += (CchGetString (idsPEBool, rgszTypes[iszBOOL], SHORTBUFMAX) && TRUE);
cAttempts++;
cLoads += (CchGetString (idsPEUnknown, rgszTypes[iszUNKNOWN], SHORTBUFMAX) && TRUE);
cAttempts++;
cLoads += (CchGetString (idsPEStatName, rgszStatHeadings[iszNAME], SHORTBUFMAX) && TRUE);
cAttempts++;
cLoads += (CchGetString (idsPEValue, rgszStatHeadings[iszVAL], SHORTBUFMAX) && TRUE);
cAttempts++;
cLoads += (CchGetString (idsPEPropName, rgszHeadings[iszNAME], SHORTBUFMAX) && TRUE);
cAttempts++;
cLoads += (CchGetString (idsPEValue, rgszHeadings[iszVAL], SHORTBUFMAX) && TRUE);
cAttempts++;
cLoads += (CchGetString (idsPEType, rgszHeadings[iszTYPE], SHORTBUFMAX) && TRUE);
cAttempts++;
cLoads += (CchGetString (idsPETrue, rgszBOOL[iszTRUE], SHORTBUFMAX) && TRUE);
cAttempts++;
cLoads += (CchGetString (idsPEFalse, rgszBOOL[iszFALSE], SHORTBUFMAX) && TRUE);
cAttempts++;
cLoads += (CchGetString (idsPEAdd, rgszAdd[iszADD], SHORTBUFMAX) && TRUE);
cAttempts++;
cLoads += (CchGetString (idsPEModify, rgszAdd[iszMODIFY], SHORTBUFMAX) && TRUE);
cAttempts++;
cLoads += (CchGetString (idsPESource, rgszValue[iszSOURCE], SHORTBUFMAX) && TRUE);
cAttempts++;
cLoads += (CchGetString (idsPEValueColon, rgszValue[iszVALUE], BUFMAX) && TRUE);
cAttempts++;
return (cLoads == cAttempts);
} // LoadTextStrings
//
// Function: ISavePropDlgChanges
//
// Parameters:
//
// hwndDlg - dialog window handle
// hwndFrom - window handle from the NMHDR struct (see code above)
//
// Returns:
//
// TRUE since we handled the message.
//
// History:
//
// Created 09/16/94 martinth
//
int PASCAL ISavePropDlgChanges(LPALLOBJS lpallobjs, HWND hwndDlg, HWND hwndFrom)
{
TCHAR sz[BUFMAX];
int iRet = IDABORT; // MessageBox return.
LRESULT lRet = 0L; // (FALSE == dismiss property sheet).
if (CchGetString(idsCustomWarning, sz, ARRAYSIZE(sz)) == 0)
return(FALSE);
lpallobjs->fPropDlgPrompted = TRUE; // no warning next time!
iRet = MessageBox( hwndDlg, sz, TEXT("Warning"),
MB_ICONEXCLAMATION | MB_YESNOCANCEL );
switch( iRet )
{
case IDYES:
PropSheet_Apply(hwndFrom); // Let's get them changes
break;
// case IDNO: // do nothing
case IDCANCEL: // cancel and disallow sheet destroy.
lRet = TRUE;
break;
}
SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, lRet );
return iRet;
}