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

Windows Kernel

Development Platform:

Visual C++

  1.                     SetWindowLongPtr( hDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE );
  2.                     return TRUE;
  3.                 }
  4.             }
  5.             return PSNRET_NOERROR;
  6.             
  7.         case PSN_RESET :
  8.             if (lpallobjs->fPropDlgChanged && !lpallobjs->fPropDlgPrompted)
  9.             {
  10.                 // BUGBUG typo here but I don't know what the author wanted
  11.                 if (ISavePropDlgChanges(lpallobjs, hDlg, ((NMHDR FAR *)lParam)->hwndFrom) != IDNO);
  12.                 return(TRUE);
  13.             }
  14.             // User cancelled the changes, so just delete the tmp stuff.
  15.             FSwapTmpUDProps (lpallobjs->lpUDObj);
  16.             FDeleteTmpUDProps (lpallobjs->lpUDObj);
  17.             return TRUE;
  18.             
  19.         case PSN_SETACTIVE :
  20.             return TRUE;
  21.             
  22.         default:
  23.             break;
  24.         } // switch
  25.         break;
  26.         
  27.         case WM_CONTEXTMENU:
  28.             WinHelp((HANDLE)wParam, NULL, HELP_CONTEXTMENU, (DWORD_PTR)rgIdhCustom);
  29.             break;
  30.             
  31.         case WM_HELP:
  32.             WinHelp(((LPHELPINFO)lParam)->hItemHandle, NULL, HELP_WM_HELP, (DWORD_PTR)rgIdhCustom);
  33.             break;
  34.     } // switch
  35.     
  36.     return FALSE;
  37.     
  38. } // FCustomDlgProc
  39. //
  40. // FGetCustomPropFromDlg
  41. //
  42. // Purpose: To get a custom property from the dialog.
  43. //          I.e. the user hit Add/Modify.
  44. //
  45. BOOL FGetCustomPropFromDlg(LPALLOBJS lpallobjs, HWND hDlg)
  46. {
  47.     UDTYPES udtype;
  48.     NUM dbl;
  49.     LPVOID lpv;
  50.     int iItemT;
  51.     LPTSTR lpstzName;
  52.     LPVOID lpvSaveAsDword;
  53.     DWORD cch;
  54.     BOOL f;
  55.     
  56.     lpstzName = NULL;
  57.     cch = 0;
  58.     
  59.     if (FAllocAndGetValLpstz (hDlg, IDD_CUSTOM_NAME, &glpstzName))
  60.     {
  61.         LPUDPROP lpudp;
  62.         
  63. #ifdef __CUSTOM_LINK_ENABLED__
  64.         lpallobjs->CDP_fLink = SendDlgItemMessage(hDlg, IDD_CUSTOM_LINK, BM_GETCHECK, 0, 0);
  65. #else
  66.         lpallobjs->CDP_fLink = FALSE; // just to be sure.
  67. #endif __CUSTOM_LINK_ENABLED__
  68.         Assert(lpallobjs->CDP_fLink == TRUE || lpallobjs->CDP_fLink == FALSE);
  69.         
  70.         // HACK: If the user enters a name that is already
  71.         // a property name, the default action of the object
  72.         // is to replace the data, treating it as an update.
  73.         // This will cause there to be 2 names in the listview
  74.         // though unless we just update the original one.  So, first
  75.         // see if the new name is in the list already, and if
  76.         // it is, find it in the listview and set up to update it.
  77.         
  78.         lpudp = LpudpropFindMatchingName (lpallobjs->lpUDObj, (LPTSTR)PSTR (glpstzName));
  79.         if (lpudp != NULL)
  80.         {
  81.             LV_FINDINFO lvfi;
  82.             
  83.             lvfi.flags = LVFI_STRING;
  84.             lvfi.psz = (LPTSTR) PSTR (glpstzName);
  85.             iItemT = ListView_FindItem (lpallobjs->CDP_hWndCustomLV, -1, &lvfi);
  86.             
  87.             // If the property is being modified and the link
  88.             // box is not checked, we need to remove the link
  89.             // data and the IMoniker from the object.
  90.             
  91.             //           if (!lpallobjs->CDP_fLink)
  92.             //                {
  93.             //                FUserDefAddProp (lpallobjs->lpUDObj, PSTR (glpstzName), NULL,
  94.             //                                 wUDlpsz, TRUE, FALSE, FALSE);
  95.             //                FUserDefAddProp (lpallobjs->lpUDObj, PSTR (glpstzName), NULL,
  96.             //                                 wUDlpsz, FALSE, FALSE, TRUE);
  97.             //                }
  98.         }
  99.         else
  100.             iItemT = -1;
  101.         
  102.         // Let's get the type, since this might be a MODIFY case
  103.         
  104.         lpallobjs->CDP_iszType = (int)SendMessage(lpallobjs->CDP_hWndType, CB_GETCURSEL,0, 0);
  105.         
  106.         // If the user has checked the link box, then the value
  107.         // must come from the client.
  108.         
  109.         if (lpallobjs->CDP_fLink)
  110.         {
  111.             DWORD irg;
  112.             
  113.             // Get the link name from the combobox, and store
  114.             // the link name and static value.
  115.             
  116.             irg = (int)SendMessage (lpallobjs->CDP_hWndLinkVal, CB_GETCURSEL, 0, 0);
  117.             
  118.             Assert ((lpallobjs->lpfnDwQueryLinkData != NULL));
  119.             Assert (((irg < lpallobjs->CDP_cLinks) && (irg >= 0)));
  120.             
  121.             cch = (DWORD)SendMessage (lpallobjs->CDP_hWndLinkVal, CB_GETLBTEXTLEN, irg, 0)+1; // Include the null-terminator
  122.             
  123.             if (!FAllocString (&lpstzName, cch))
  124.                 return(FALSE);
  125.             
  126.             SendMessage (lpallobjs->CDP_hWndLinkVal, CB_GETLBTEXT, irg, (LPARAM) PSTR (lpstzName));
  127.             
  128.             // Set up the static type and value for display
  129.             // in the listbox
  130.             
  131.             udtype = (UDTYPES) (*lpallobjs->lpfnDwQueryLinkData) (QLD_LINKTYPE, irg, NULL, (LPTSTR)PSTR (lpstzName));
  132.             (*lpallobjs->lpfnDwQueryLinkData) (QLD_LINKVAL, irg, &lpv, (LPTSTR)PSTR (lpstzName));
  133.             
  134.             //
  135.             // HACK alert
  136.             //
  137.             // We want lpv to point to the value, not to be overloaded in the case of a dword or bool.
  138.             //
  139.             
  140.             if ((udtype == wUDdw) || (udtype == wUDbool))
  141.             {
  142.                 lpvSaveAsDword = lpv; // Really a DWORD
  143.                 lpv = &lpvSaveAsDword;
  144.             }
  145.             
  146.             // Add the link name itself to the object
  147.             
  148.             //         FUserDefAddProp (lpallobjs->lpUDObj, PSTR (glpstzName), PSTR (lpstzName),
  149.             //                          wUDlpsz, TRUE, FALSE, FALSE);
  150.             
  151.         }   // if (lpallobjs->CDP_fLink)
  152.         
  153.         else
  154.         {
  155.             if (lpallobjs->CDP_iszType != iszBOOL)
  156.             {
  157.                 if (!FAllocAndGetValLpstz (hDlg, IDD_CUSTOM_VALUE, &glpstzValue))
  158.                     return(FALSE);
  159.             }
  160.             
  161.             // Convert the type in the combobox to a UDTYPES
  162.             
  163.             switch (lpallobjs->CDP_iszType)
  164.             {
  165.             case iszTEXT :
  166.                 udtype = wUDlpsz;
  167.                 (LPTSTR) lpv = (LPTSTR)PSTR (glpstzValue);
  168.                 break;
  169.                 
  170.             case iszNUM :
  171.                 udtype = UdtypesGetNumberType (glpstzValue, &dbl,
  172.                     ((LPUDINFO)lpallobjs->lpUDObj->m_lpData)->lpfnFSzToNum);
  173.                 switch (udtype)
  174.                 {
  175.                 case wUDdw :
  176.                     lpv = (DWORD *) &dbl;
  177.                     break;
  178.                     
  179.                 case wUDfloat :
  180.                     (NUM *) lpv = &dbl;
  181.                     break;
  182.                     
  183.                 default :
  184.                     (LPTSTR) lpv = (LPTSTR)PSTR (glpstzValue);
  185.                     
  186.                     // If the user doesn't want to convert the value to text, they can press "Cancel" and try again.
  187.                     
  188.                     if (FDisplayConversionWarning (hDlg))
  189.                     {
  190.                         SetFocus(lpallobjs->CDP_hWndType);
  191.                         return(FALSE);
  192.                     }
  193.                     udtype = wUDlpsz;
  194.                     
  195.                 }   // switch (udtype)
  196.                 break;
  197.                 
  198.                 case iszDATE :
  199.                     
  200.                     if (FConvertDate (glpstzValue, (LPFILETIME) &dbl))
  201.                     {
  202.                         udtype = wUDdate;
  203.                         (NUM *) lpv = &dbl;
  204.                     }
  205.                     else
  206.                     {
  207.                         udtype = wUDlpsz;
  208.                         (LPTSTR) lpv = (LPTSTR)PSTR (glpstzValue);
  209.                         // If the user doesn't want to convert the value to text, they can press "Cancel" and try again.
  210.                         if (FDisplayConversionWarning (hDlg))
  211.                         {
  212.                             SetFocus(lpallobjs->CDP_hWndType);
  213.                             return(FALSE);
  214.                         }
  215.                     }
  216.                     break;
  217.                     
  218.                 case iszBOOL :
  219.                     {
  220.                         udtype = wUDbool;
  221.                         f = (BOOL)(SendMessage (lpallobjs->CDP_hWndBoolTrue, BM_GETSTATE, 0, 0) & BST_CHECKED);
  222.                         lpv = &f;
  223.                         break;
  224.                     }
  225.                     
  226.                 default :
  227.                     AssertSz (0,TEXT("IDD_CUSTOM_TYPE combobox is whacked!"));
  228.                     udtype = wUDinvalid;
  229.                     
  230.             }   // switch (lpallobjs->CDP_iszType)
  231.             
  232.         }   // if (lpallobjs->CDP_fLink) ... else
  233.         
  234.         
  235.         // If we got valid input, add the property to the object
  236.         // and listbox.
  237.         
  238.         if (udtype != wUDinvalid)
  239.         {
  240.             // The PropVariant created when we add this property.
  241.             LPPROPVARIANT lppropvar = NULL;
  242.             
  243.             // The link data (link name itself) would have
  244.             // been stored above if the property was a link.
  245.             // This stores the static value that will eventually
  246.             // appear in the list view.
  247.             
  248.             lppropvar = LppropvarUserDefAddProp (lpallobjs->lpUDObj, glpstzName, lpv, udtype,
  249.                 (lpstzName != NULL) ? lpstzName : NULL,
  250.                 (lpstzName != NULL) ? TRUE : FALSE, FALSE);
  251.             
  252.             // HACK alert
  253.             //
  254.             // Here we want lpv be overloaded in the case of a dword or bool, since
  255.             // AddUDPropToListView calls WUdtypeToSz which assumes lpv is overloaded.
  256.             //
  257.             
  258.             if ((udtype == wUDdw) || (udtype == wUDbool))
  259.             {
  260.                 lpv = *(LPVOID *)lpv;
  261.             }
  262.             
  263.             AddUDPropToListView (lpallobjs->lpUDObj, lpallobjs->CDP_hWndCustomLV, (LPTSTR)PSTR (glpstzName), lppropvar, iItemT, lpallobjs->CDP_fLink, fTrue, fTrue);
  264.             
  265.             // For links, dealloc the buffer.
  266.             
  267.             if (lpallobjs->CDP_fLink)
  268.                 DeallocValue (&lpv, udtype);
  269.             
  270.             // Clear out the edit fields and disable the Add button again
  271.             SetCustomDlgDefButton(hDlg, gOKButtonID);
  272.             EnableWindow (lpallobjs->CDP_hWndAdd, FALSE);
  273.             SendMessage(lpallobjs->CDP_hWndName, CB_SETEDITSEL, 0, MAKELPARAM(0,-1));     // Select entire string
  274.             SendMessage(lpallobjs->CDP_hWndName, WM_CLEAR, 0, 0);
  275.             EnableWindow (lpallobjs->CDP_hWndDelete, FALSE);
  276.             // See bug 213
  277.             //                    if (fLink)
  278.             //                    {
  279.             //                      fLink = !fLink;
  280.             //                      SendDlgItemMessage (hDlg, IDD_CUSTOM_LINK, BM_SETCHECK, (WPARAM) fLink, 0);
  281.             //                    }
  282.             FSwapControls (lpallobjs->CDP_hWndVal, lpallobjs->CDP_hWndLinkVal,
  283.                 lpallobjs->CDP_hWndBoolTrue, lpallobjs->CDP_hWndBoolFalse,
  284.                 lpallobjs->CDP_hWndGroup, lpallobjs->CDP_hWndType,
  285.                 lpallobjs->CDP_hWndValText, lpallobjs->CDP_fLink, lpallobjs->CDP_iszType == iszBOOL);
  286.             FSetupAddButton (lpallobjs->CDP_iszType, lpallobjs->CDP_fLink, &lpallobjs->CDP_fAdd, lpallobjs->CDP_hWndAdd, lpallobjs->CDP_hWndVal, lpallobjs->CDP_hWndName, hDlg);
  287.             
  288.             // wUDbool doesn't use the edit control....
  289.             if (lpallobjs->CDP_iszType != iszBOOL)
  290.                 ClearEditControl (lpallobjs->CDP_hWndVal, 0);
  291.             
  292.         }   // if (udtype != wUDinvalid)
  293.         
  294.         SendDlgItemMessage(hDlg, IDD_CUSTOM_TYPE, CB_SETCURSEL, lpallobjs->CDP_iszType,0);
  295.         SetFocus(lpallobjs->CDP_hWndName);
  296.         //          lpallobjs->fPropDlgChanged = TRUE;
  297.         if (lpstzName != NULL)
  298.             VFreeMemP(lpstzName, CBTSTR (lpstzName));
  299.         return(TRUE);
  300.     }
  301.     return(FALSE);
  302.     
  303. }
  304. /////////////////////////////////////////////////////////////////////////
  305. //
  306. // SetCustomDlgDefButton
  307. //
  308. // Set the new default button
  309. //
  310. /////////////////////////////////////////////////////////////////////////
  311. VOID SetCustomDlgDefButton(HWND hDlg, int IDNew)
  312. {
  313.     int IDOld;
  314.     
  315.     if ((IDOld = LOWORD(SendMessage(hDlg, DM_GETDEFID, 0L, 0L))) != IDNew)
  316.     {
  317.         // Set the new default push button's control ID.
  318.         SendMessage(hDlg, DM_SETDEFID, IDNew, 0L);
  319.         
  320.         // Set the new style.
  321.         SendDlgItemMessage(hDlg, IDNew, BM_SETSTYLE, BS_DEFPUSHBUTTON, MAKELPARAM(TRUE,0));
  322.         
  323.         SendDlgItemMessage(hDlg, IDOld, BM_SETSTYLE, BS_PUSHBUTTON, MAKELPARAM(TRUE,0));
  324.     }
  325. }
  326. #ifdef OFFICE_96
  327. ////////////////////////////////////////////////////////////////////////////////
  328. //
  329. // ListViewCompareFunc
  330. //
  331. // Purpose:
  332. //    Compares two items in a listview
  333. //    We only sort the name column.
  334. //
  335. // Returns
  336. //    A negative value if item 1 should come before item 2
  337. //    A positive value if item 1 should come after item 2
  338. //    Zero if the two items are equivalent
  339. //
  340. ////////////////////////////////////////////////////////////////////////////////
  341. int CALLBACK ListViewCompareFunc
  342. (
  343.  LPARAM lParam1,      // lParam of the LV_ITEM struct  (property name)
  344.  LPARAM lParam2,      // lParam of the LV_ITEM struct  (property name)
  345.  LPARAM lParamSort)   // Index of column to sore
  346. {
  347.     return(lstrcmp((LPTSTR)lParam1, (LPTSTR)lParam2));
  348. }
  349. #endif
  350. ////////////////////////////////////////////////////////////////////////////////
  351. //
  352. // PrintTimeInDlg
  353. //
  354. // Purpose:
  355. //  Prints the locale-specific time representation in control in the dialog.
  356. //
  357. ////////////////////////////////////////////////////////////////////////////////
  358. #ifndef _WIN2000_DOCPROP_
  359. void PASCAL
  360. PrintTimeInDlg (
  361.                 HWND hDlg,                           // Dialog handle
  362.                 DWORD dwId,                          // Control id
  363.                 LPFILETIME lpft)                     // The time
  364. {
  365.     SYSTEMTIME st;
  366.     TCHAR szBuf[80], szTmp[64];
  367.     const TCHAR *c_szSpace = TEXT(" ");
  368.     
  369.     if ((lpft != NULL) && (lpft->dwLowDateTime != 0) && (lpft->dwHighDateTime != 0))
  370.     {
  371.         FILETIME ft;
  372.         
  373.         FileTimeToLocalFileTime(lpft, &ft);   // get in local time
  374.         FileTimeToSystemTime(&ft, &st);
  375.         
  376.         GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, szBuf,ARRAYSIZE(szBuf));
  377.         // BUGBUG: this doesn't handle international: time may need to come first
  378.         // don't bother with the time if it is NULL
  379.         if (st.wHour || st.wMinute || st.wSecond)
  380.         {
  381.             lstrcat(szBuf, c_szSpace);
  382.             GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, szTmp, ARRAYSIZE(szTmp));
  383.             lstrcat(szBuf, szTmp);
  384.         }
  385.         
  386.         SetDlgItemText(hDlg, dwId, szBuf);
  387.     }
  388. } // PrintTimeInDlg
  389. #endif //_WIN2000_DOCPROP_
  390. ////////////////////////////////////////////////////////////////////////////////
  391. //
  392. // PrintEditTimeInDlg
  393. //
  394. // Purpose:
  395. //  Prints the total edit time in the dialog.
  396. //
  397. ////////////////////////////////////////////////////////////////////////////////
  398. #ifndef _WIN2000_DOCPROP_
  399. void PASCAL PrintEditTimeInDlg (
  400.                                 HWND hDlg,                           // Dialog handle
  401.                                 LPFILETIME lpft)                     // The time
  402. {
  403.     TCHAR sz[100];
  404.     
  405.     // Remember that the 64 bit number in lpft is units of 100ns
  406.     VFtToSz(lpft, sz, ARRAYSIZE(sz), TRUE);
  407.     SetDlgItemText(hDlg, IDD_STATISTICS_TOTALEDIT, sz);
  408.     
  409. } // PrintEditTimeInDlg
  410. #endif _WIN2000_DOCPROP_
  411. ////////////////////////////////////////////////////////////////////////////////
  412. //
  413. //  SetEditValLpsz
  414. //
  415. //  Purpose:
  416. //      If this PropVariant holds a LPTSTR, it is written
  417. //      to the caller-specified Edit Control.  If it is not
  418. //      an LPTSTR, it is not treated as an error (it might
  419. //      simply be a VT_EMPTY ... a non-existent property).
  420. //
  421. ////////////////////////////////////////////////////////////////////////////////
  422. #ifndef _WIN2000_DOCPROP_
  423. void PASCAL SetEditValLpsz(
  424.                            LPPROPVARIANT    lppropvar,          // PropVariant
  425.                            HWND             hDlg,               // Dialog handle
  426.                            DWORD            dwID )              // Edit control ID
  427. {
  428.     
  429.     if (lppropvar->vt == VT_LPTSTR)
  430.     {
  431.         SendDlgItemMessage
  432.             (hDlg, dwID, WM_SETTEXT, 0, (LPARAM) lppropvar->pszVal);
  433.         
  434.         PropVariantClear( lppropvar );
  435.     }
  436. }
  437. #endif
  438. ////////////////////////////////////////////////////////////////////////////////
  439. //
  440. //  GetEditValLpsz
  441. //
  442. //  Purpose:
  443. //      Reads the string from the caller-specified edit
  444. //      control, and loads it into a PropVariant.
  445. //      If the Edit control says that it has not been
  446. //      modified, then we don't read anything, and 
  447. //      return FALSE.
  448. //
  449. ////////////////////////////////////////////////////////////////////////////////
  450. #ifndef _WIN2000_DOCPROP_
  451. BOOL PASCAL GetEditValLpsz(
  452.                            LPPROPVARIANT lppropvar,             // Sum info PropVariants
  453.                            HWND hDlg,                           // Dialog handle
  454.                            DWORD dwId)                          // Edit control id
  455. {
  456.     BOOL  fChanged = FALSE;
  457.     DWORD cb, cch;
  458.     
  459.     // Did the data change?
  460.     
  461.     if ((BOOL) SendDlgItemMessage (hDlg, dwId, EM_GETMODIFY, 0, 0))
  462.     {
  463.         LPTSTR tszNew;
  464.         
  465.         // Yes, it changed.  Ask the Edit control how big the
  466.         // string is.
  467.         
  468.         cch = (DWORD)SendDlgItemMessage (hDlg, dwId, WM_GETTEXTLENGTH, 0, 0);
  469.         
  470.         cb = ( cch + 1 ) * sizeof (TCHAR);  // Includes the NULL.
  471.         
  472.         // Allocate a new string for this PropVariant, and set 
  473.         // the VT.
  474.         
  475.         if ( !(tszNew = CoTaskMemAlloc (cb)))
  476.         {
  477.             goto Exit;
  478.         }
  479.         
  480.         PropVariantClear( lppropvar );
  481.         
  482.         lppropvar->vt = VT_LPTSTR;
  483.         (LPTSTR) lppropvar->pszVal = tszNew;
  484.         
  485.         // Get the string from the edit control into the buffer
  486.         // (the size of the buffer in characters is cch+1, including
  487.         // the NULL).
  488.         
  489.         SendDlgItemMessage (hDlg, dwId, WM_GETTEXT, (WPARAM) cch+1,
  490.             (LPARAM) lppropvar->pszVal);
  491.         
  492.         fChanged = TRUE;
  493.         
  494.     }   // if ((BOOL) SendDlgItemMessage (hDlg, dwId, EM_GETMODIFY, 0, 0))
  495.     
  496.     
  497.     //  ----
  498.     //  Exit
  499.     //  ----
  500.     
  501. Exit:
  502.     
  503.     return (fChanged);
  504.     
  505. } // GetEditValLpsz
  506. #endif //_WIN2000_DOCPROP_
  507. ////////////////////////////////////////////////////////////////////////////////
  508. //
  509. // FAllocAndGetValLpstz
  510. //
  511. // Purpose:
  512. //  Gets the value from the edit box into the local buffer.
  513. //
  514. ////////////////////////////////////////////////////////////////////////////////
  515. BOOL PASCAL FAllocAndGetValLpstz (
  516.                                   HWND hDlg,                           // Handle of dialog control is in
  517.                                   DWORD dwId,                          // Id of control
  518.                                   LPTSTR *lplpstz)                      // Buffer
  519. {
  520.     DWORD cch;
  521.     
  522.     cch = (DWORD)SendDlgItemMessage (hDlg, dwId, WM_GETTEXTLENGTH, 0, 0);
  523.     cch++;
  524.     
  525.     if (FAllocString (lplpstz, cch))
  526.     {
  527.         // Get the entry.  Remember to null-terminate it.
  528.         cch = (DWORD)SendDlgItemMessage (hDlg, dwId, WM_GETTEXT, cch, (LPARAM) PSTR (*lplpstz));
  529.         ((LPTSTR)(PSTR (*lplpstz)))[cch] = TEXT('');
  530.         
  531.         return TRUE;
  532.     }
  533.     
  534.     return FALSE;
  535.     
  536. } // FAllocAndGetValLpstz
  537. ////////////////////////////////////////////////////////////////////////////////
  538. //
  539. // FAllocString
  540. //
  541. // Purpose:
  542. //  Allocates a string big enough to to hold cch char's.  Only allocates if needed.
  543. //
  544. ////////////////////////////////////////////////////////////////////////////////
  545. BOOL PASCAL FAllocString (
  546.                           LPTSTR *lplpstz,
  547.                           DWORD cch)
  548. {
  549.     // Figure out how many bytes we need to allocate.
  550.     
  551.     DWORD cbNew = (cch * sizeof(TCHAR));
  552.     
  553.     // And how many bytes we need to free.
  554.     
  555.     DWORD cbOld = *lplpstz == NULL
  556.         ? 0
  557.         : (CchTszLen (*lplpstz) + 1) * sizeof(TCHAR);
  558.     
  559.     
  560.     // If we need to free or allocate data.
  561.     
  562.     if (*lplpstz == NULL || cbNew > cbOld)
  563.     {
  564.         LPTSTR lpszNew;
  565.         
  566.         // Allocate the new data.
  567.         
  568.         lpszNew = PvMemAlloc(cbNew);
  569.         if (lpszNew == NULL)
  570.         {
  571.             return FALSE;
  572.         }
  573.         
  574.         // Free the old data.
  575.         
  576.         if (*lplpstz != NULL)
  577.             VFreeMemP(*lplpstz, cbOld);
  578.         
  579.         *lplpstz = lpszNew;
  580.         
  581.     }
  582.     
  583.     // Make this a valid (empty) string.
  584.     
  585.     **lplpstz = TEXT('');
  586.     
  587.     return TRUE;
  588.     
  589. } // FAllocString
  590. ////////////////////////////////////////////////////////////////////////////////
  591. //
  592. // ClearEditControl
  593. //
  594. // Purpose:
  595. //  Clears any text from an edit control
  596. //
  597. ////////////////////////////////////////////////////////////////////////////////
  598. void PASCAL
  599. ClearEditControl
  600. (HWND hDlg,                           // Dialog handle
  601.  DWORD dwId)                          // Id of edit control
  602. {
  603.     // Really cheesey.  Clear the edit control by selecting
  604.     // everything then clearing the selection
  605.     if (dwId == 0)
  606.     {
  607.         SendMessage (hDlg, EM_SETSEL, 0, -1);
  608.         SendMessage (hDlg, WM_CLEAR, 0, 0);
  609.     }
  610.     else
  611.     {
  612.         SendDlgItemMessage (hDlg, dwId, EM_SETSEL, 0, -1);
  613.         SendDlgItemMessage (hDlg, dwId, WM_CLEAR, 0, 0);
  614.     }
  615.     
  616. } // ClearEditControl
  617. ////////////////////////////////////////////////////////////////////////////////
  618. //
  619. // UdtypesGetNumberType
  620. //
  621. // Purpose:
  622. //  Gets the number type from the string and returns the value, either
  623. //  a float or dword in numval.
  624. //
  625. ////////////////////////////////////////////////////////////////////////////////
  626. UDTYPES PASCAL
  627. UdtypesGetNumberType
  628. (LPTSTR lpstz,                                   // String containing the number
  629.  NUM *lpnumval,                              // The value of the number
  630.  BOOL (*lpfnFSzToNum)(NUM *, LPTSTR))   // Sz To Num routine, can be null
  631. {
  632.     TCHAR *pc;
  633.     
  634.     errno = 0;
  635.     *(DWORD *) lpnumval = strtol ((LPTSTR)PSTR (lpstz), &pc, 10);
  636.     
  637.     if ((!errno) && (*pc == TEXT('')))
  638.         return wUDdw;
  639.     
  640.     // Try doing a float conversion if int fails
  641.     
  642.     if (lpfnFSzToNum != NULL)
  643.     {
  644.         if ((*lpfnFSzToNum)(lpnumval, (LPTSTR)PSTR(lpstz)))
  645.             return wUDfloat;
  646.     }
  647.     
  648.     return wUDinvalid;
  649.     
  650. } // UdtypesGetNumberType
  651. ////////////////////////////////////////////////////////////////////////////////
  652. //
  653. // YearIndexFromShortDateFormat
  654. //
  655. // 
  656. //  Determines the zero-based position index of the year component
  657. //  of a textual representation of the date based on the specified date format.
  658. //  This value may be used as the iYear arg to ScanDateNums function.
  659. //
  660. ////////////////////////////////////////////////////////////////////////////////
  661. int YearIndexFromShortDateFormat( TCHAR chFmt )
  662. {
  663.     switch( chFmt )
  664.     {
  665.         case MMDDYY:
  666.         case DDMMYY:
  667.             return 2;
  668.         case YYMMDD:
  669.             return 0;
  670.     }
  671.     return -1;
  672. }
  673. ////////////////////////////////////////////////////////////////////////////////
  674. //
  675. //  IsGregorian
  676. //
  677. //  Purpose:
  678. //      Reports whether the specified calendar is a gregorian calendar.
  679. //
  680. ////////////////////////////////////////////////////////////////////////////////
  681. BOOL IsGregorian( CALID calid )
  682. {
  683.     switch (calid)
  684.     {
  685.         case CAL_GREGORIAN:
  686.         case CAL_GREGORIAN_US:
  687.         case CAL_GREGORIAN_ME_FRENCH:
  688.         case CAL_GREGORIAN_ARABIC:
  689.         case CAL_GREGORIAN_XLIT_ENGLISH:
  690.         case CAL_GREGORIAN_XLIT_FRENCH:
  691.             return TRUE;
  692.         //  these are non-gregorian:
  693.         //case CAL_JAPAN
  694.         //case CAL_TAIWAN
  695.         //case CAL_KOREA
  696.         //case CAL_HIJRI
  697.         //case CAL_THAI
  698.         //case CAL_HEBREW
  699.     }
  700.     return FALSE;
  701. }
  702. ////////////////////////////////////////////////////////////////////////////////
  703. //
  704. //  GregorianYearFromAbbreviatedYear
  705. //
  706. //  Purpose:
  707. //      Based on current locale settings, calculates the year corresponding to the
  708. //  specified 1- or 2-digit abbreviated value.
  709. //
  710. ////////////////////////////////////////////////////////////////////////////////
  711. int GregorianYearFromAbbreviatedYear( LCID lcid, CALID calid, int nAbbreviatedYear )
  712. {
  713.     TCHAR szData[16];   
  714.     LONG  nYearHigh = -1;
  715.     int   nBaseCentury;
  716.     int   nYearInCentury = 0;
  717.     //  We're handling two-digit values for gregorian calendars only
  718.     if (nAbbreviatedYear < 100)
  719.     {
  720.         // BUGBUG: why do we not support non-gregorian?
  721.         if( !IsGregorian( calid )
  722.             || !GetCalendarInfo( lcid, calid, CAL_ITWODIGITYEARMAX|CAL_RETURN_NUMBER,
  723.                               NULL, 0, &nYearHigh ) )
  724.         {
  725.             // In the absence of a default, use 2029 as the cutoff, just like monthcal.
  726.             nYearHigh = 2029;
  727.         }
  728.         //
  729.         //  Copy the century of nYearHigh into nAbbreviatedYear.
  730.         //
  731.         nAbbreviatedYear += (nYearHigh - nYearHigh % 100);
  732.         //
  733.         //  If it exceeds the max, then drop to previous century.
  734.         //
  735.         if (nAbbreviatedYear > nYearHigh)
  736.             nAbbreviatedYear -= 100;
  737.     }
  738.     return nAbbreviatedYear;
  739. }
  740. ////////////////////////////////////////////////////////////////////////////////
  741. //
  742. // FConvertDate
  743. //
  744. // Purpose:
  745. //  Converts the given string to a date.
  746. //
  747. ////////////////////////////////////////////////////////////////////////////////
  748. BOOL PASCAL FConvertDate
  749. (LPTSTR lpstz,                         // String having the date
  750.  LPFILETIME lpft)                     // The date in FILETIME format
  751. {
  752.     
  753.     FILETIME ft;
  754.     SYSTEMTIME st;
  755.     TCHAR szSep[3];
  756.     TCHAR szFmt[10];
  757.     TCHAR szCalID[8];
  758.     unsigned int ai[3];
  759.     int   iYear =-1; // index of ai member that represents the year value
  760.     CALID calid;
  761.     TCHAR szDate[256];
  762.     TCHAR szMonth[256];
  763.     TCHAR *pch;
  764.     TCHAR *pchT;
  765.     DWORD cch;
  766.     DWORD i;
  767.     if (!(GetLocaleInfo (LOCALE_USER_DEFAULT, LOCALE_IDATE, szFmt, ARRAYSIZE(szFmt))) ||
  768.         !(GetLocaleInfo (LOCALE_USER_DEFAULT, LOCALE_SDATE, szSep, ARRAYSIZE(szSep))) ||
  769.         !(GetLocaleInfo (LOCALE_USER_DEFAULT, LOCALE_ICALENDARTYPE, szCalID, ARRAYSIZE(szCalID))) )
  770.         return FALSE;
  771.     iYear = YearIndexFromShortDateFormat(szFmt[0]);
  772.     
  773.     // Augh!  It's an stz so we need to pass the DWORDs at the start
  774.     if (!ScanDateNums(lpstz, szSep, ai, sizeof(ai)/sizeof(unsigned int),iYear))
  775.     {
  776.         // Could be that the string contains the short version of the month, e.g. 03-Mar-95
  777.         PbMemCopy(szDate, lpstz, CBTSTR(lpstz)); 
  778.         pch = szDate;
  779.         
  780.         // Let's get to the first character of the month, if there is one
  781.         while((isdigit(*pch) || (*pch == szSep[0])) && (*pch != 0))
  782.             ++pch;
  783.         
  784.         // If we got to the end of the string, there really was an error
  785.         if (*pch == 0)
  786.             return(FALSE);
  787.         
  788.         // Let's find the length of the month string
  789.         pchT = pch+1;
  790.         while ((*pchT != szSep[0]) && (*pchT != 0))
  791.             ++pchT;
  792.         cch = (DWORD)(pchT - pch);
  793.         
  794.         // Loop through all the months and see if we match one
  795.         // There can be 13 months
  796.         for (i = 1; i <= 13; ++i)
  797.         {
  798.             if (!GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SABBREVMONTHNAME1+i-1,
  799.                 szMonth, ARRAYSIZE(szMonth)))
  800.                 return(FALSE);
  801.             
  802.             if (CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE | NORM_IGNOREKANATYPE | NORM_IGNOREWIDTH,
  803.                 pch, cch, szMonth, CchTszLen(szMonth)) == 2)
  804.                 break;
  805.         }
  806.         
  807.         if (i > 13)
  808.             return(FALSE);
  809.         
  810.         // We found the month. wsprintf zero-terminates
  811.         cch = wsprintf(pch, TEXT("%u"), i);
  812.         pch += cch;
  813.         while (*pch++ = *(pch+1));
  814.         
  815.         // Try and convert again
  816.         if (!ScanDateNums(szDate, szSep, ai, 3, iYear))
  817.             return(FALSE);
  818.         
  819.     } // if (!ScanDateNums(lpstz, szSep, ai, 3))
  820.     
  821.     FillBuf (&st, 0, sizeof(st));
  822.     
  823.     switch (szFmt[0])
  824.     {
  825.     case MMDDYY:
  826.         st.wMonth = (WORD)ai[0];
  827.         st.wDay = (WORD)ai[1];
  828.         st.wYear = (WORD)ai[2];
  829.         break;
  830.     case DDMMYY:
  831.         st.wDay = (WORD)ai[0];
  832.         st.wMonth = (WORD)ai[1];
  833.         st.wYear = (WORD)ai[2];
  834.         break;
  835.     case YYMMDD:
  836.         st.wYear = (WORD)ai[0];
  837.         st.wMonth = (WORD)ai[1];
  838.         st.wDay = (WORD)ai[2];
  839.         break;
  840.     default:
  841.         return FALSE;
  842.     }
  843.     
  844.     if (st.wYear < ONECENTURY)
  845.     {
  846.         calid = strtol( szCalID, NULL, 10 );
  847.         st.wYear = (WORD)GregorianYearFromAbbreviatedYear( 
  848.             LOCALE_USER_DEFAULT, calid, st.wYear );
  849.     }
  850.     
  851.     if (!SystemTimeToFileTime (&st, &ft))
  852.         return(FALSE);
  853.     return(LocalFileTimeToFileTime(&ft, lpft));
  854.     
  855. } // FConvertDate
  856. ////////////////////////////////////////////////////////////////////////////////
  857. //
  858. // PopulateUDListView
  859. //
  860. // Purpose:
  861. //  Populates the entire ListView with the User-defined properties
  862. //  in the given object.
  863. //
  864. ////////////////////////////////////////////////////////////////////////////////
  865. void PASCAL
  866. PopulateUDListView
  867. (HWND hWnd,                   // Handle of list view window
  868.  LPUDOBJ lpUDObj)             // UD Prop object
  869. {
  870.     LPUDITER lpudi;
  871.     LPPROPVARIANT lppropvar;
  872.     BOOL fLink;
  873.     BOOL fLinkInvalid;
  874.     
  875.     // Iterate through the list of user-defined properties, adding each
  876.     // one to the listview.
  877.     
  878.     for( lpudi = LpudiUserDefCreateIterator (lpUDObj);
  879.     FUserDefIteratorValid (lpudi);
  880.     FUserDefIteratorNext (lpudi)
  881.         )
  882.     {
  883.         // Get the name of this property.
  884.         
  885.         LPTSTR tszPropertyName
  886.             = LpszUserDefIteratorName( lpudi, 1, (LPTSTR) UD_PTRWIZARD );
  887.         
  888.         // If the property has no name, or the name indicates that it
  889.         // is a hidden property, then move on to the next property.
  890.         
  891.         if( tszPropertyName == NULL
  892.             ||
  893.             *tszPropertyName == HIDDENPREFIX )
  894.         {
  895.             continue;
  896.         }
  897.         
  898.         lppropvar = LppropvarUserDefGetIteratorVal (lpudi, &fLink, &fLinkInvalid);
  899.         if (lppropvar == NULL)
  900.             return;
  901.         
  902.         // If this isn't a supported type, don't display it.
  903.         if( !ISUDTYPE(lppropvar->vt) )
  904.             continue;
  905.         
  906.         
  907. #ifdef SHELL
  908.         //
  909.         // In the Shell, we want all links to show up as invalid, so set that here...
  910.         //
  911.         
  912.         fLinkInvalid = TRUE;
  913. #endif
  914.         
  915.         AddUDPropToListView (lpUDObj, hWnd, LpszUserDefIteratorName (lpudi, 1, (TCHAR *) UD_PTRWIZARD),
  916.             lppropvar, -1, fLink, fLinkInvalid, FALSE);
  917.         
  918.     } // for( lpudi = LpudiUserDefCreateIterator (lpUDObj); ...
  919.     
  920.     FUserDefDestroyIterator (&lpudi);
  921.     
  922. } // PopulateUDListView
  923. ////////////////////////////////////////////////////////////////////////////////
  924. //
  925. // AddUDPropToListView
  926. //
  927. // Purpose:
  928. //  Adds the given property to the list view or updates an existing one
  929. //  if iItem >= 0
  930. //
  931. ////////////////////////////////////////////////////////////////////////////////
  932. void PASCAL AddUDPropToListView (
  933.                                  LPUDOBJ lpUDObj,
  934.                                  HWND hWnd,                   // Handle of list view
  935.                                  LPTSTR lpszName,             // Name of property
  936.                                  LPPROPVARIANT lppropvar,     // The property value.
  937.                                  int iItem,                   // Index to add item at
  938.                                  BOOL fLink,                  // Indicates the value is a link
  939.                                  BOOL fLinkInvalid,           // Is the link invalid?
  940.                                  BOOL fMakeVisible)           // Should the property be forced to be visible
  941. {
  942.     LV_ITEM lvi;
  943.     TCHAR sz[BUFMAX];
  944.     WORD irg;
  945.     BOOL fSuccess;
  946.     BOOL fUpdate;
  947.     
  948.     // If iItem >= 0, then the item should be updated, otherwise,
  949.     // it should be added.
  950.     
  951.     if (fUpdate = (iItem >= 0))
  952.     {
  953.         lvi.iItem = iItem;
  954.         if (fLink)
  955.             lvi.iImage = (fLinkInvalid) ? giInvLinkIcon : giLinkIcon;
  956.         else
  957.             lvi.iImage = giBlankIcon;
  958.         
  959.         lvi.mask = LVIF_IMAGE;
  960.         lvi.iSubItem = iszNAME;
  961.         
  962.         fSuccess = ListView_SetItem (hWnd, &lvi);
  963.         Assert (fSuccess);           // We don't *really* care, just want to know when it happens
  964.     }
  965.     else
  966.     {
  967.         // This always adds to the end of the list....
  968.         lvi.iItem = ListView_GetItemCount (hWnd);
  969.         
  970.         // First add the label to the list
  971.         lvi.iSubItem = iszNAME;
  972.         lvi.pszText = lpszName;
  973.         
  974.         if (fLink)
  975.             lvi.iImage = (fLinkInvalid) ? giInvLinkIcon : giLinkIcon;
  976.         else
  977.             lvi.iImage = giBlankIcon;
  978.         lvi.mask = LVIF_TEXT | LVIF_IMAGE;
  979.         
  980.         lvi.iItem = ListView_InsertItem (hWnd, &lvi);
  981.         if (lvi.iItem == 0)
  982.             ListView_SetItemState(hWnd, 0, LVIS_FOCUSED, LVIS_FOCUSED);
  983.     }
  984.     
  985.     // Convert the data to a string and print it
  986.     
  987.     lvi.mask = LVIF_TEXT;
  988.     irg = WUdtypeToSz (lppropvar, sz, BUFMAX, ((LPUDINFO)lpUDObj->m_lpData)->lpfnFNumToSz);
  989.     lvi.pszText = sz;
  990.     lvi.iSubItem = iszVAL;
  991.     fSuccess = ListView_SetItem (hWnd, &lvi);
  992.     Assert (fSuccess);           // We don't *really* care, just want to know when it happens
  993.     
  994.     // Put the type in the listview
  995.     
  996.     lvi.iSubItem = iszTYPE;
  997.     lvi.pszText = (LPTSTR) rgszTypes[irg];
  998.     fSuccess = ListView_SetItem (hWnd, &lvi);
  999.     Assert (fSuccess);           // We don't *really* care, just want to know when it happens
  1000.     if (fMakeVisible)
  1001.     {
  1002.         fSuccess = ListView_EnsureVisible(hWnd, lvi.iItem, FALSE);
  1003.         Assert (fSuccess);           // We don't *really* care, just want to know when it happens
  1004.     }
  1005.     
  1006.     //  if (fUpdate)
  1007.     //  {
  1008.     //    ListView_RedrawItems (hWnd, lvi.iItem, lvi.iItem);
  1009.     //    UpdateWindow (hWnd);
  1010.     //  }
  1011.     
  1012. } // AddUDPropToListView
  1013. ////////////////////////////////////////////////////////////////////////////////
  1014. //
  1015. // AddItemToListView
  1016. //
  1017. // Purpose:
  1018. //  Adds the given string and number to the end of a listview
  1019. //
  1020. ////////////////////////////////////////////////////////////////////////////////
  1021. void PASCAL
  1022. AddItemToListView
  1023. (HWND hWnd,                           // ListView handle
  1024.  DWORD_PTR dw,                         // Number to add
  1025.  const TCHAR *lpsz,                    // String to add
  1026.  BOOL fString)                        // Indicates if dw is actually a string
  1027. {
  1028.     LV_ITEM lvi;
  1029.     TCHAR sz[BUFMAX];
  1030.     BOOL fSuccess;
  1031.     
  1032.     if (!fString)
  1033.         // _itoa (dw, sz, BASE10);
  1034.         wsprintf(sz, TEXT("%lu"), dw);
  1035.     
  1036.     // This always adds to the end of the list....
  1037.     lvi.iItem = ListView_GetItemCount (hWnd);
  1038.     
  1039.     // First add the label to the list
  1040.     lvi.mask = LVIF_TEXT;
  1041.     lvi.iSubItem = iszNAME;
  1042.     lvi.pszText = (LPTSTR) lpsz;
  1043.     lvi.iItem = ListView_InsertItem (hWnd, &lvi);
  1044.     if (lvi.iItem == 0)     // Adding the 1st item
  1045.         ListView_SetItemState(hWnd, 0, LVIS_FOCUSED, LVIS_FOCUSED);
  1046.     
  1047.     Assert ((lvi.iItem != -1));
  1048.     
  1049.     // Then add the value
  1050.     lvi.mask = LVIF_TEXT;
  1051.     lvi.iSubItem = iszVAL;
  1052.     lvi.pszText = (fString) ? (LPTSTR) dw : sz;
  1053.     fSuccess = ListView_SetItem (hWnd, &lvi);
  1054.     
  1055.     Assert (fSuccess);
  1056.     
  1057. } // AddItemToListView
  1058. ////////////////////////////////////////////////////////////////////////////////
  1059. //
  1060. // InitListView
  1061. //
  1062. // Purpose:
  1063. //  Initializes a list view control
  1064. //
  1065. ////////////////////////////////////////////////////////////////////////////////
  1066. void PASCAL
  1067. InitListView
  1068. (HWND hWndLV,                   // Handle of parent dialog
  1069.  int irgLast,                 // Index of last column in array
  1070.  TCHAR rgsz[][SHORTBUFMAX],    // Array of column headings
  1071.  BOOL fImageList)              // Should the listview have an image list
  1072. {
  1073.     HICON hIcon;
  1074.     RECT rect;
  1075.     HIMAGELIST hImlS;
  1076.     LV_COLUMN lvc;
  1077.     int irg;
  1078.     
  1079.     lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH;
  1080.     lvc.fmt = LVCFMT_LEFT;
  1081.     
  1082.     // Initially force all columns to be the same size & fill the control.
  1083.     GetClientRect(hWndLV, &rect);
  1084.     // Subtract fudge factor
  1085.     lvc.cx = (rect.right-rect.left)/(irgLast+1)-(GetSystemMetrics(SM_CXVSCROLL)/(irgLast+1));
  1086.     
  1087.     // Add in all the columns.
  1088.     for (irg = 0; irg <= irgLast; irg++)
  1089.     {
  1090.         lvc.pszText = rgsz[irg];
  1091.         lvc.iSubItem = irg;
  1092.         ListView_InsertColumn (hWndLV, irg, &lvc);
  1093.     }
  1094.     
  1095.     if (!fImageList)
  1096.         return;
  1097.     
  1098.     hIcon = LoadIcon (g_hmodThisDll, MAKEINTRESOURCE (IDD_BLANK_ICON));
  1099.     if (hIcon != NULL)
  1100.     {
  1101.         hImlS = MsoImageList_Create (16, 16, TRUE, ICONSMAX, 0);
  1102.         ListView_SetImageList (hWndLV, hImlS, LVSIL_SMALL);
  1103.         giBlankIcon = MsoImageList_ReplaceIcon (hImlS, -1, hIcon);
  1104.         Assert ((giBlankIcon != -1));
  1105.     }
  1106.     
  1107. } // InitListView
  1108. ////////////////////////////////////////////////////////////////////////////////
  1109. //
  1110. // FSwapControls
  1111. //
  1112. // Purpose:
  1113. //  Swaps the controls needed to display link info.
  1114. //
  1115. ////////////////////////////////////////////////////////////////////////////////
  1116. BOOL PASCAL
  1117. FSwapControls
  1118. (HWND hWndVal,                        // Handle of Value window
  1119.  HWND hWndLinkVal,                    // Handle of Link Value Combo box
  1120.  HWND hWndBoolTrue,                   // Handle of True radio button
  1121.  HWND hWndBoolFalse,                  // Handle of False radio button
  1122.  HWND hWndGroup,                      // Handle of Group box
  1123.  HWND hWndType,                       // Handle of Type window
  1124.  HWND hWndValText,
  1125.  BOOL fLink,                          // Flag indicating a link
  1126.  BOOL fBool)                          // Flag indicating a bool
  1127. {
  1128.     if (fLink)
  1129.     {
  1130.         SendMessage (hWndValText, WM_SETTEXT, 0, (LPARAM) rgszValue[iszSOURCE]);
  1131.         ShowWindow (hWndVal, SW_HIDE);
  1132.         ShowWindow (hWndBoolTrue, SW_HIDE);
  1133.         ShowWindow (hWndBoolFalse, SW_HIDE);
  1134.         ShowWindow (hWndGroup, SW_HIDE);
  1135.         ShowWindow (hWndLinkVal, SW_SHOW);
  1136.         EnableWindow (hWndType, FALSE);
  1137.         ClearEditControl (hWndVal, 0);
  1138.     }
  1139.     else
  1140.     {
  1141.         SendMessage (hWndValText, WM_SETTEXT, 0, (LPARAM) rgszValue[iszVALUE]);
  1142.         ShowWindow (hWndLinkVal, SW_HIDE);
  1143.         EnableWindow (hWndType, TRUE);
  1144.         
  1145.         if (fBool)
  1146.         {
  1147.             ShowWindow (hWndVal, SW_HIDE);
  1148.             ShowWindow (hWndBoolTrue, SW_SHOW);
  1149.             ShowWindow (hWndBoolFalse, SW_SHOW);
  1150.             ShowWindow (hWndGroup, SW_SHOW);
  1151.             SendMessage (hWndBoolTrue, BM_SETCHECK, (WPARAM) CHECKED, 0);
  1152.             SendMessage (hWndBoolFalse, BM_SETCHECK, (WPARAM) CLEAR, 0);
  1153.             SendMessage (hWndType, CB_SETCURSEL, iszBOOL, 0);
  1154.             ClearEditControl (hWndVal, 0);
  1155.         }
  1156.         else
  1157.         {
  1158.             ShowWindow (hWndVal, SW_SHOW);
  1159.             EnableWindow(hWndVal, TRUE);
  1160.             ShowWindow (hWndBoolTrue, SW_HIDE);
  1161.             ShowWindow (hWndBoolFalse, SW_HIDE);
  1162.             ShowWindow (hWndGroup, SW_HIDE);
  1163.             SendMessage (hWndType, CB_SETCURSEL, iszTEXT, 0);
  1164.         }
  1165.     }
  1166.     
  1167.     return TRUE;
  1168.     
  1169. } // FSwapControls
  1170. ////////////////////////////////////////////////////////////////////////////////
  1171. //
  1172. // PopulateControls
  1173. //
  1174. // Purpose:
  1175. //  Populates the edit controls with the appropriate date from the object
  1176. //
  1177. ////////////////////////////////////////////////////////////////////////////////
  1178. VOID PASCAL PopulateControls (
  1179.                               LPUDOBJ lpUDObj,                     // Pointer to object
  1180.                               LPTSTR szName,                        // Name of the item to populate controls with
  1181.                               DWORD cLinks,                        // Number of links
  1182.                               DWQUERYLD lpfnDwQueryLinkData,       // Pointer to app link callback
  1183.                               HWND hDlg,                           // Handle of the dialog
  1184.                               HWND hWndName,                       // Handle of the Name window
  1185.                               HWND hWndVal,                        // Handle of Value window
  1186.                               HWND hWndValText,                    // Handle of Value LTEXT
  1187.                               HWND hWndLink,                       // Handle of Link checkbox
  1188.                               HWND hWndLinkVal,                    // Handle of Link Value window
  1189.                               HWND hWndType,                       // Handle of Type window
  1190.                               HWND hWndBoolTrue,                   // Handle of True radio button
  1191.                               HWND hWndBoolFalse,                  // Handle of False radio button
  1192.                               HWND hWndGroup,                      // Handle of Group window
  1193.                               HWND hWndAdd,                        // Handle of Add button
  1194.                               HWND hWndDelete,                     // Handle of Delete button
  1195.                               BOOL *pfLink,                        // Indicates that the value is a link
  1196.                               BOOL *pfAdd)                         // Indicates the state of the Add button
  1197. {
  1198.     UDTYPES udtype;
  1199.     LPVOID lpv;
  1200.     LPPROPVARIANT lppropvar;            // A property from the UDObj linked-list.
  1201.     BOOL f,fT;
  1202.     TCHAR sz[BUFMAX];
  1203.     LPUDPROP lpudp;
  1204.     
  1205.     // Grab the type for the string and set up the dialog to have the right
  1206.     // controls to display it.
  1207.     udtype = UdtypesUserDefType (lpUDObj, szName);
  1208.     AssertSz ((udtype != wUDinvalid), TEXT("User defined properties or ListView corrupt"));
  1209.     
  1210.     // Get a name-specified property from the UD linked-list.
  1211.     
  1212.     lppropvar = LppropvarUserDefGetPropVal (lpUDObj, szName, pfLink, &fT);
  1213.     Assert (lppropvar != NULL || udtype == wUDbool || udtype == wUDdw);
  1214.     if (lppropvar == NULL)
  1215.         return;
  1216.     
  1217.     lpv = LpvoidUserDefGetPropVal (lpUDObj, szName, 1, NULL, UD_STATIC | UD_PTRWIZARD, pfLink, &fT);
  1218.     Assert((lpv != NULL) || (udtype == wUDbool) || (udtype == wUDdw));
  1219.     
  1220.     FSwapControls (hWndVal, hWndLinkVal, hWndBoolTrue, hWndBoolFalse, hWndGroup, hWndType, hWndValText, *pfLink, (udtype == wUDbool));
  1221.     
  1222.     SendMessage (hWndType, CB_SETCURSEL, (WPARAM) WUdtypeToSz (lppropvar, (TCHAR *) sz, BUFMAX,
  1223.         ((LPUDINFO)lpUDObj->m_lpData)->lpfnFNumToSz), 0);
  1224.     SendMessage (hWndLink, BM_SETCHECK, (WPARAM) *pfLink, 0);
  1225.     if (cLinks)                       // Let's make sure we enable the window if links are allowed
  1226.         EnableWindow(hWndLink, TRUE);
  1227.     
  1228.     if (*pfLink)
  1229.     {
  1230.         FCreateListOfLinks (cLinks, lpfnDwQueryLinkData, hWndLinkVal);
  1231.         lpv = LpvoidUserDefGetPropVal (lpUDObj, szName, 1, NULL, UD_LINK | UD_PTRWIZARD, pfLink, &fT);
  1232.         Assert (lpv != NULL || udtype == wUDbool || udtype == wUDdw);
  1233.         //    if (lpfnDwQueryLinkData == NULL)
  1234.         //    {
  1235.         //      SetCustomDlgDefButton(hDlg, gOKButtonID);
  1236.         //      EnableWindow (hWndAdd, FALSE);
  1237.         //      SendMessage (hWndLinkVal, CB_INSERTSTRING, (WPARAM) -1, (LPARAM) lpv);
  1238.         //    }
  1239.         AssertSz ((lpv != NULL), TEXT("Dialog is corrupt in respect to Custom Properties database"));
  1240.         
  1241.         // This code is added for bug 188 and the code is ugly !! :)
  1242.         lpudp = LpudpropFindMatchingName (lpUDObj, szName);
  1243.         if ((lpudp != NULL) && (lpudp->fLinkInvalid))
  1244.         {
  1245.             SetCustomDlgDefButton(hDlg, IDD_CUSTOM_DELETE);
  1246.             SendMessage(hWndName, WM_SETTEXT, 0, (LPARAM)szName);
  1247.             SendMessage(hWndVal, WM_SETTEXT, 0, (LPARAM)lpv);
  1248.             EnableWindow(hWndDelete, TRUE);
  1249.             EnableWindow(hWndAdd, FALSE);
  1250.             EnableWindow(hWndLink, FALSE);
  1251.             EnableWindow(hWndType, FALSE);
  1252.             ShowWindow(hWndLinkVal, SW_HIDE);
  1253.             ShowWindow(hWndVal, SW_SHOW);
  1254.             EnableWindow(hWndVal, FALSE);
  1255.             return;
  1256.         }
  1257.         
  1258.         // Select the current link for this property in the combobox.  If the link
  1259.         // name no longer exists (there's some contrived cases where this can
  1260.         // happen) then this will select nothing.
  1261.         SendMessage (hWndLinkVal, CB_SELECTSTRING, 0, (LPARAM) lpv);
  1262.         EnableWindow(hWndLink, TRUE);
  1263.     }
  1264.     else if (udtype == wUDbool)
  1265.     {
  1266.         SendMessage ((lpv) ? hWndBoolTrue : hWndBoolFalse, BM_SETCHECK, CHECKED, 0);
  1267.         SendMessage ((lpv) ? hWndBoolFalse : hWndBoolTrue, BM_SETCHECK, CLEAR, 0);
  1268.         EnableWindow(hWndType, TRUE);
  1269.     }
  1270.     else
  1271.     {
  1272.         SendMessage (hWndVal, WM_SETTEXT, 0, (LPARAM) sz);
  1273.         EnableWindow (hWndVal, TRUE);
  1274.         EnableWindow(hWndType, TRUE);
  1275.     }
  1276.     
  1277.     if (*pfAdd)
  1278.     {
  1279.         SendMessage (hWndAdd, WM_SETTEXT, 0, (LPARAM) rgszAdd[iszMODIFY]);
  1280.         *pfAdd = FALSE;
  1281.     }
  1282.     
  1283.     // HACK: Because the EN_UPDATE handler for hWndName checks fAdd to
  1284.     // see if the button should be set to Add, when we set the text
  1285.     // in the edit control, the button will change to Add unless
  1286.     // fAdd is set to TRUE.  Temporarily set the flag to TRUE to force
  1287.     // the button to not change.  Restore the original value after the
  1288.     // text has been set.
  1289.     f = *pfAdd;
  1290.     *pfAdd = TRUE;
  1291.     SendMessage (hWndName, WM_SETTEXT, 0, (LPARAM) szName);
  1292.     *pfAdd = f;
  1293.     // If we can fill the data in the controls, turn on the
  1294.     // Delete button too.
  1295.     //  fItemSel = TRUE;
  1296.     EnableWindow (hWndDelete, TRUE);
  1297.     SetCustomDlgDefButton(hDlg, gOKButtonID);
  1298.     EnableWindow (hWndAdd, FALSE);
  1299. } // PopulateControls
  1300. ////////////////////////////////////////////////////////////////////////////////
  1301. //
  1302. // FSetupAddButton
  1303. //
  1304. // Purpose:
  1305. //  Sets up the Add button correctly based on the type & flags.
  1306. //
  1307. ////////////////////////////////////////////////////////////////////////////////
  1308. BOOL PASCAL
  1309. FSetupAddButton
  1310. (DWORD iszType,                       // Index of the type in combobox
  1311.  BOOL fLink,                          // Indicates a link
  1312.  BOOL *pfAdd,                         // Indicates if the Add button is showing
  1313.  HWND hWndAdd,                        // Handle of Add button
  1314.  HWND hWndVal,                        // Handle of value button
  1315.  HWND hWndName,                       // Handle of Name
  1316.  HWND hDlg)                           // Handle of dialog
  1317. {
  1318.     // Once the user starts typing, we can enable the Add button
  1319.     // if there is text in the name & the value (unless this
  1320.     // is a link or boolean, in which case we don't care about
  1321.     // the value).
  1322.     BOOL f;
  1323.     
  1324.     if ((iszType != iszBOOL) && (!fLink))
  1325.     {
  1326.         if (SendMessage (hWndVal, EM_LINELENGTH, 0, 0) != 0)
  1327.         {
  1328.             f = (SendMessage (hWndName, WM_GETTEXTLENGTH, 0, 0) != 0);
  1329.             if (f)
  1330.                 SetCustomDlgDefButton(hDlg, IDD_CUSTOM_ADD);
  1331.             else
  1332.                 SetCustomDlgDefButton(hDlg, gOKButtonID);
  1333.             EnableWindow (hWndAdd, f);
  1334.         }
  1335.         else
  1336.         {
  1337.             SetCustomDlgDefButton(hDlg, gOKButtonID);
  1338.             EnableWindow (hWndAdd, FALSE);
  1339.         }
  1340.     }
  1341.     // If it's a bool or link, just check to see that the name
  1342.     // has stuff in it.
  1343.     else
  1344.     {
  1345.         f = SendMessage (hWndName, WM_GETTEXTLENGTH, 0, 0) != 0;
  1346.         if (f)
  1347.             SetCustomDlgDefButton(hDlg, IDD_CUSTOM_ADD);
  1348.         else
  1349.             SetCustomDlgDefButton(hDlg, gOKButtonID);
  1350.         EnableWindow (hWndAdd, f);
  1351.     }
  1352.     
  1353.     if (!*pfAdd)
  1354.     {
  1355.         SendMessage (hWndAdd, WM_SETTEXT, 0, (LPARAM) rgszAdd[iszADD]);
  1356.         *pfAdd = TRUE;
  1357.     }
  1358.     
  1359.     return TRUE;
  1360.     
  1361. }  // FSetupAddButton
  1362. ////////////////////////////////////////////////////////////////////////////////
  1363. //
  1364. // WUdtypeToSz
  1365. //
  1366. // Purpose:
  1367. //  Converts the given type into a string representation.  Returns the
  1368. //  index in the type combobox of the type.
  1369. //
  1370. ////////////////////////////////////////////////////////////////////////////////
  1371. WORD PASCAL WUdtypeToSz (
  1372.                          LPPROPVARIANT lppropvar,    // Value with the type to be converted.
  1373.                          LPTSTR sz,                  // Buffer to put converted val in
  1374.                          DWORD cchMax,               // Size of buffer (in chars)
  1375.                          BOOL (*lpfnFNumToSz)(NUM *, LPTSTR, DWORD))
  1376. {
  1377.     SYSTEMTIME st;
  1378.     WORD irg;
  1379.     FILETIME ft;
  1380.     
  1381.     Assert (lppropvar != NULL);
  1382.     
  1383.     switch (lppropvar->vt)
  1384.     {
  1385.     case wUDlpsz :
  1386.         PbSzNCopy (sz, lppropvar->pwszVal, cchMax);
  1387.         irg = iszTEXT;
  1388.         break;
  1389.         
  1390.     case wUDdate :
  1391.         if (FScanMem((LPBYTE)&lppropvar->filetime,
  1392.             0, sizeof(FILETIME))) // if the date struct is all 0's
  1393.         {
  1394.             *sz = 0;                       // display the empty string
  1395.         }
  1396.         else if (!FileTimeToLocalFileTime(&lppropvar->filetime, &ft)
  1397.             || !FileTimeToSystemTime (&ft, &st)
  1398.             || (!GetDateFormat (LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, sz, cchMax)))
  1399.         {
  1400. #ifdef DEBUG
  1401.             DWORD dwErr = GetLastError();    
  1402. #endif DEBUG            
  1403.             irg = iszUNKNOWN;
  1404.             *sz = 0;
  1405.             break;
  1406.         }
  1407.         
  1408.         irg = iszDATE;
  1409.         break;
  1410.         
  1411.     case wUDdw :
  1412.         Assert(cchMax >= 11);
  1413.         Assert(lppropvar->vt == VT_I4);
  1414.         
  1415.         wsprintf (sz, TEXT("%ld"), lppropvar->lVal);
  1416.         irg = iszNUM;
  1417.         break;
  1418.         
  1419.     case wUDfloat :
  1420.         if (lpfnFNumToSz != NULL)
  1421.             irg = (*lpfnFNumToSz)((NUM*)&lppropvar->dblVal, sz, cchMax) ? iszNUM : iszUNKNOWN;
  1422.         else
  1423.         {
  1424.             irg = iszUNKNOWN;
  1425.             *sz = 0;
  1426.         }
  1427.         break;
  1428.         
  1429.     case wUDbool :
  1430.         PbSzNCopy (sz,
  1431.             lppropvar->boolVal ? (LPTSTR) &rgszBOOL[iszTRUE] : (LPTSTR) &rgszBOOL[iszFALSE],
  1432.             cchMax);
  1433.         irg = iszBOOL;
  1434.         break;
  1435.         
  1436.     default :
  1437.         irg = iszUNKNOWN;
  1438.         
  1439.     } // switch
  1440.     
  1441.     return irg;
  1442.     
  1443. } // WUdtypeToSz
  1444. ////////////////////////////////////////////////////////////////////////////////
  1445. //
  1446. // FCreateListOfLinks
  1447. //
  1448. // Purpose:
  1449. //  Creates the dropdown list of linkable items.
  1450. //
  1451. ////////////////////////////////////////////////////////////////////////////////
  1452. BOOL PASCAL FCreateListOfLinks(
  1453.                                DWORD cLinks,                                // Number of links
  1454.                                DWQUERYLD lpfnDwQueryLinkData,               // Link data callback
  1455.                                HWND hWndLinkVal)                            // Link Value window handle
  1456. {
  1457.     DWORD irg;
  1458.     LPTSTR lpstz;
  1459.     
  1460.     // If the combobox is already filled, don't fill it
  1461.     if (irg = (int)SendMessage(hWndLinkVal, CB_GETCOUNT,0, 0))
  1462.     {
  1463.         Assert(irg == cLinks);
  1464.         return(TRUE);
  1465.     }
  1466.     
  1467.     lpstz = NULL;
  1468.     
  1469.     // Call back the client app to get the list of linkable
  1470.     // values, and put them in the value combobox.
  1471.     for (irg = 0; irg < cLinks; irg++)
  1472.     {
  1473.         lpstz = (TCHAR *) ((*lpfnDwQueryLinkData) (QLD_LINKNAME, irg, &lpstz, NULL));
  1474.         if (lpstz != NULL)
  1475.         {
  1476.             SendMessage (hWndLinkVal, CB_INSERTSTRING, (WPARAM) -1, (LPARAM) PSTR (lpstz));
  1477.             VFreeMemP(lpstz, CBTSTR(lpstz));
  1478.             // REVIEW: We probably ought to figure out a way to be more efficient here....
  1479.         }
  1480.     }
  1481.     
  1482.     return TRUE;
  1483.     
  1484. } // FCreateListOfLinks
  1485. ////////////////////////////////////////////////////////////////////////////////
  1486. //
  1487. // FSetTypeControl
  1488. //
  1489. // Purpose:
  1490. //  Sets the type control to have the given type selected.
  1491. //
  1492. ////////////////////////////////////////////////////////////////////////////////
  1493. BOOL PASCAL FSetTypeControl (
  1494.                              UDTYPES udtype,                      // Type to set the type to
  1495.                              HWND hWndType)                       // Handle of type control
  1496. {
  1497.     WORD iType;
  1498.     
  1499.     switch (udtype)
  1500.     {
  1501.     case wUDlpsz :
  1502.         iType = iszTEXT;
  1503.         break;
  1504.     case wUDfloat :
  1505.     case wUDdw    :
  1506.         iType = iszNUM;
  1507.         break;
  1508.     case wUDbool  :
  1509.         iType = iszBOOL;
  1510.         break;
  1511.     case wUDdate :
  1512.         iType = iszDATE;
  1513.         break;
  1514.     default:
  1515.         return FALSE;
  1516.     }
  1517.     SendMessage (hWndType, CB_SETCURSEL, (WPARAM) iType, 0);
  1518.     
  1519.     return TRUE;
  1520.     
  1521. } // FSetTypeControl
  1522. ////////////////////////////////////////////////////////////////////////////////
  1523. //
  1524. // DeleteItem
  1525. //
  1526. // Purpose:
  1527. //  Deletes an item from the UD object and the listview.
  1528. //
  1529. ////////////////////////////////////////////////////////////////////////////////
  1530. void PASCAL DeleteItem (
  1531.                         LPUDOBJ lpUDObj,
  1532.                         HWND hWndLV,
  1533.                         int iItem,
  1534.                         TCHAR sz[])
  1535. {
  1536.     int i;
  1537.     
  1538.     ListView_DeleteItem (hWndLV, iItem);
  1539.     FUserDefDeleteProp (lpUDObj, sz);
  1540.     
  1541.     // We just nuked the item with the focus, so let's get the new one
  1542.     // if there are still items in the listview
  1543.     if ((i = ListView_GetItemCount(hWndLV)) != 0)
  1544.     {
  1545.         // Figure out the index of the item to get the focus
  1546.         i = (i == iItem) ? iItem - 1 : iItem;
  1547.         ListView_SetItemState(hWndLV, i, LVIS_FOCUSED, LVIS_FOCUSED);
  1548.     }
  1549.     
  1550. } // DeleteItem
  1551. ////////////////////////////////////////////////////////////////////////////////
  1552. //
  1553. // ResetTypeControl
  1554. //
  1555. // Purpose:
  1556. //  Resets the value of the type control to Text.
  1557. //
  1558. ////////////////////////////////////////////////////////////////////////////////
  1559. void PASCAL ResetTypeControl (
  1560.                               HWND hDlg,                           // Handle of dialog
  1561.                               DWORD dwId,                          // Id of control
  1562.                               DWORD *piszType)                     // The type we've reset to
  1563. {
  1564.     SendDlgItemMessage (hDlg, dwId, CB_SETCURSEL, iszTEXT, 0);
  1565.     *piszType = iszTEXT;
  1566. } // ResetTypeControl
  1567. ////////////////////////////////////////////////////////////////////////////////
  1568. //
  1569. // FDisplayConversionWarning
  1570. //
  1571. // Purpose:
  1572. //  Displays a warning about types being converted.  Returns TRUE if
  1573. //  the user presses "Cancel"
  1574. //
  1575. ////////////////////////////////////////////////////////////////////////////////
  1576. BOOL PASCAL FDisplayConversionWarning(HWND hDlg)                   // Handle of parent window
  1577. {
  1578.     return (IdDoAlert(hDlg, idsPEWarningText, MB_ICONEXCLAMATION | MB_OKCANCEL) == IDCANCEL);
  1579. } // FDisplayConversionWarning
  1580. ////////////////////////////////////////////////////////////////////////////////
  1581. //
  1582. // LoadTextStrings
  1583. //
  1584. // Purpose:
  1585. //  Loads all of the text needed by the dialogs from the DLL.
  1586. //
  1587. ////////////////////////////////////////////////////////////////////////////////
  1588. BOOL PASCAL FLoadTextStrings (void)
  1589. {
  1590.     register int cLoads = 0;
  1591.     register int cAttempts = 0;
  1592.     
  1593.     // CchGetString returns a cch, so make it into a 1 or 0
  1594.     // then add up the results,making sure we load as many as
  1595.     // we try.
  1596.     cLoads += (CchGetString (idsPEB, rgszOrders[iszBYTES], SHORTBUFMAX) && TRUE);
  1597.     cAttempts++;
  1598.     cLoads += (CchGetString (idsPEKB, rgszOrders[iszORDERKB], SHORTBUFMAX) && TRUE);
  1599.     cAttempts++;
  1600.     cLoads += (CchGetString (idsPEMB, rgszOrders[iszORDERMB], SHORTBUFMAX) && TRUE);
  1601.     cAttempts++;
  1602.     cLoads += (CchGetString (idsPEGB, rgszOrders[iszORDERGB], SHORTBUFMAX) && TRUE);
  1603.     cAttempts++;
  1604.     cLoads += (CchGetString (idsPETB, rgszOrders[iszORDERTB], SHORTBUFMAX) && TRUE);
  1605.     cAttempts++;
  1606.     
  1607.     cLoads += (CchGetString (idsPEBytes, rgszStats[iszBYTES], SHORTBUFMAX) && TRUE);
  1608.     cAttempts++;
  1609.     cLoads += (CchGetString (idsPEPages, rgszStats[iszPAGES], SHORTBUFMAX) && TRUE);
  1610.     cAttempts++;
  1611.     cLoads += (CchGetString (idsPEPara, rgszStats[iszPARA], SHORTBUFMAX) && TRUE);
  1612.     cAttempts++;
  1613.     cLoads += (CchGetString (idsPELines, rgszStats[iszLINES], SHORTBUFMAX) && TRUE);
  1614.     cAttempts++;
  1615.     cLoads += (CchGetString (idsPEWords, rgszStats[iszWORDS], SHORTBUFMAX) && TRUE);
  1616.     cAttempts++;
  1617.     cLoads += (CchGetString (idsPEChars, rgszStats[iszCHARS], SHORTBUFMAX) && TRUE);
  1618.     cAttempts++;
  1619.     cLoads += (CchGetString (idsPESlides, rgszStats[iszSLIDES], SHORTBUFMAX) && TRUE);
  1620.     cAttempts++;
  1621.     cLoads += (CchGetString (idsPENotes, rgszStats[iszNOTES], SHORTBUFMAX) && TRUE);
  1622.     cAttempts++;
  1623.     cLoads += (CchGetString (idsPEHiddenSlides, rgszStats[iszHIDDENSLIDES], SHORTBUFMAX) && TRUE);
  1624.     cAttempts++;
  1625.     cLoads += (CchGetString (idsPEMMClips, rgszStats[iszMMCLIPS], SHORTBUFMAX) && TRUE);
  1626.     cAttempts++;
  1627.     cLoads += (CchGetString (idsPEFormat, rgszStats[iszFORMAT], SHORTBUFMAX) && TRUE);
  1628.     cAttempts++;
  1629.     
  1630.     cLoads += (CchGetString (idsPEText, rgszTypes[iszTEXT], SHORTBUFMAX) && TRUE);
  1631.     cAttempts++;
  1632.     cLoads += (CchGetString (idsPEDate, rgszTypes[iszDATE], SHORTBUFMAX) && TRUE);
  1633.     cAttempts++;
  1634.     cLoads += (CchGetString (idsPENumber, rgszTypes[iszNUM], SHORTBUFMAX) && TRUE);
  1635.     cAttempts++;
  1636.     cLoads += (CchGetString (idsPEBool, rgszTypes[iszBOOL], SHORTBUFMAX) && TRUE);
  1637.     cAttempts++;
  1638.     cLoads += (CchGetString (idsPEUnknown, rgszTypes[iszUNKNOWN], SHORTBUFMAX) && TRUE);
  1639.     cAttempts++;
  1640.     
  1641.     cLoads += (CchGetString (idsPEStatName, rgszStatHeadings[iszNAME], SHORTBUFMAX) && TRUE);
  1642.     cAttempts++;
  1643.     cLoads += (CchGetString (idsPEValue, rgszStatHeadings[iszVAL], SHORTBUFMAX) && TRUE);
  1644.     cAttempts++;
  1645.     
  1646.     cLoads += (CchGetString (idsPEPropName, rgszHeadings[iszNAME], SHORTBUFMAX) && TRUE);
  1647.     cAttempts++;
  1648.     cLoads += (CchGetString (idsPEValue, rgszHeadings[iszVAL], SHORTBUFMAX) && TRUE);
  1649.     cAttempts++;
  1650.     cLoads += (CchGetString (idsPEType, rgszHeadings[iszTYPE], SHORTBUFMAX) && TRUE);
  1651.     cAttempts++;
  1652.     
  1653.     cLoads += (CchGetString (idsPETrue, rgszBOOL[iszTRUE], SHORTBUFMAX) && TRUE);
  1654.     cAttempts++;
  1655.     cLoads += (CchGetString (idsPEFalse, rgszBOOL[iszFALSE], SHORTBUFMAX) && TRUE);
  1656.     cAttempts++;
  1657.     
  1658.     cLoads += (CchGetString (idsPEAdd, rgszAdd[iszADD], SHORTBUFMAX) && TRUE);
  1659.     cAttempts++;
  1660.     cLoads += (CchGetString (idsPEModify, rgszAdd[iszMODIFY], SHORTBUFMAX) && TRUE);
  1661.     cAttempts++;
  1662.     
  1663.     cLoads += (CchGetString (idsPESource, rgszValue[iszSOURCE], SHORTBUFMAX) && TRUE);
  1664.     cAttempts++;
  1665.     cLoads += (CchGetString (idsPEValueColon, rgszValue[iszVALUE], BUFMAX) && TRUE);
  1666.     cAttempts++;
  1667.     
  1668.     
  1669.     return (cLoads == cAttempts);
  1670.     
  1671. } // LoadTextStrings
  1672. //
  1673. // Function: ISavePropDlgChanges
  1674. //
  1675. // Parameters:
  1676. //
  1677. //    hwndDlg - dialog window handle
  1678. //    hwndFrom - window handle from the NMHDR struct (see code above)
  1679. //
  1680. // Returns:
  1681. //
  1682. //       TRUE since we handled the message.
  1683. //
  1684. // History:
  1685. //
  1686. //    Created 09/16/94  martinth
  1687. //
  1688. int PASCAL ISavePropDlgChanges(LPALLOBJS lpallobjs, HWND hwndDlg, HWND hwndFrom)
  1689. {
  1690.     TCHAR   sz[BUFMAX];
  1691.     int     iRet = IDABORT; // MessageBox return.
  1692.     LRESULT lRet = 0L;      // (FALSE == dismiss property sheet).
  1693.     
  1694.     if (CchGetString(idsCustomWarning, sz, ARRAYSIZE(sz)) == 0)
  1695.         return(FALSE);
  1696.     
  1697.     lpallobjs->fPropDlgPrompted = TRUE;  // no warning next time!
  1698.     iRet = MessageBox( hwndDlg, sz, TEXT("Warning"),
  1699.                        MB_ICONEXCLAMATION | MB_YESNOCANCEL );    
  1700.     switch( iRet )
  1701.     {
  1702.     case IDYES:
  1703.         PropSheet_Apply(hwndFrom);  // Let's get them changes
  1704.         break;
  1705.     // case IDNO:                   // do nothing
  1706.     case IDCANCEL:                  // cancel and disallow sheet destroy.
  1707. lRet = TRUE;
  1708.         break;
  1709.     }
  1710.     SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, lRet );
  1711.     return iRet;
  1712. }