CLIENT.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:52k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /*
  2.  -  C L I E N T . C
  3.  -
  4.  *    Purpose:
  5.  *      Sample routing mail client for the MAPI SDK.
  6.  *      Exclusively uses the Extended MAPI interface.
  7.  *
  8.  *  Copyright 1986-1996, Microsoft Corporation. All Rights Reserved.
  9.  *
  10.  */
  11. #include <string.h>
  12. #include <stdlib.h>
  13. #include <windows.h>
  14. #include <windowsx.h>
  15. #ifdef _WIN32
  16. #include <objerror.h>
  17. #include <objbase.h>
  18. #endif
  19. #ifdef WIN16
  20. #include <compobj.h>
  21. #endif
  22. #include <mapiutil.h>
  23. #include <mapidbg.h>
  24. #include <mapix.h>
  25. #include <mapiwin.h>
  26. #include <pdkver.h>
  27. #include <mapiform.h>
  28. #include <ole2.h>
  29. #include <wrap3d.h>
  30. #define USES_IID_IMAPIStatus 1
  31. #define USES_IID_IMessage  1
  32. #include <mapiguid.h>
  33. #include "client.h"
  34. #include "bitmap.h"
  35. #include "route.h"
  36. #ifdef _WIN32
  37. #include "chsfld.h"
  38. #endif
  39. #ifdef WIN16
  40. #define GWL_USERDATA    DWL_USER
  41. #endif
  42. /* Application instance */
  43. HANDLE hInst;
  44.                             
  45. /* Static Data */
  46. static ULONG cbeidFolderToView;
  47. static LPENTRYID lpeidFolderToView = NULL;
  48. LPADRBOOK pabAddrB = NULL;
  49. LPMAPISESSION pses = NULL;
  50. LPMDB pmdb = NULL;
  51. LPMAPIFOLDER pfldOutBox = NULL;
  52. LPSPropValue pvalSentMailEID = NULL;
  53. HCURSOR hWaitCur;
  54. LPVOID lpCtl3d = NULL;      /* 3D control context */
  55. #ifdef _WIN32
  56. /* Choose folder stuff */
  57. HMODULE             g_hChsFldDll;
  58. HRPICKFOLDER        g_lpfnHrPickFolder;
  59. ULONG               cbCFDState = 0;
  60. LPBYTE              pbCFDState = NULL;
  61. #endif /*_WIN32 */
  62. int PASCAL
  63. WinMain (HINSTANCE hInstance, HINSTANCE hPrevInst, LPSTR lpszCmd, int nCmdShow)
  64. {
  65.     MSG msg;
  66.     if (!hPrevInst)
  67.         if (!InitApplication (hInstance))
  68.             return (FALSE);
  69.     if (!InitInstance (hInstance, nCmdShow))
  70.         return (FALSE);
  71.     while (GetMessage (&msg, 0, 0, 0))
  72.     {
  73.         TranslateMessage (&msg);
  74.         DispatchMessage (&msg);
  75.     }
  76.     DeinitApplication ();
  77.     return (msg.wParam);
  78. }
  79. /*
  80.  -  InitApplication
  81.  -
  82.  *  Purpose:
  83.  *      Initialize the application.
  84.  *
  85.  *  Parameters:
  86.  *      hInstance   - Instance handle
  87.  *
  88.  *  Returns:
  89.  *      True/False
  90.  *
  91.  */
  92. BOOL
  93. InitApplication (HANDLE hInstance)
  94. {
  95.     WNDCLASS wc;
  96.     wc.style = 0;
  97.     wc.lpfnWndProc = MainWndProc;
  98.     wc.cbClsExtra = 0;
  99.     wc.cbWndExtra = 0;
  100.     wc.hInstance = hInstance;
  101.     wc.hIcon = LoadIcon (hInstance, "NoMail");
  102.     wc.hCursor = LoadCursor (0, IDC_ARROW);
  103.     wc.hbrBackground = GetStockObject (WHITE_BRUSH);
  104.     wc.lpszMenuName = "MailMenu";
  105.     wc.lpszClassName = "RoutingSample";
  106.     return (RegisterClass (&wc));
  107. }
  108. /*
  109.  -  InitInstance
  110.  -
  111.  *  Purpose:
  112.  *      Initialize this instance.
  113.  *
  114.  *  Parameters:
  115.  *      hInstance   - Instance handle
  116.  *      nCmdShow    - Do we show the window?
  117.  *
  118.  *  Returns:
  119.  *      True/False
  120.  *
  121.  */
  122. BOOL
  123. InitInstance (HANDLE hInstance, int nCmdShow)
  124. {
  125.     HWND hWnd;
  126.     BOOL fInit;
  127.     BOOL f;
  128.     hInst = hInstance;
  129.     fInit = InitMAPI(0);
  130.     if (!lpCtl3d)
  131.     {
  132.         lpCtl3d = CTL3D_Initialize(hInstance);
  133.         CTL3D_AutoSubclass(lpCtl3d, hInstance, &f);
  134.     }
  135.     hWnd = CreateWindow ("RoutingSample", "Routing Sample", WS_OVERLAPPEDWINDOW,
  136.         5, 5, 550, 75, 0, 0, hInst, NULL);
  137.     if (!hWnd)
  138.         return (FALSE);
  139.     ShowWindow (hWnd, nCmdShow);
  140.     UpdateWindow (hWnd);
  141.     hWaitCur = LoadCursor(0, IDC_WAIT);
  142.     if (fInit)
  143.     {
  144.         if (ClientLogon (hWnd))
  145.             ToggleMenuState (hWnd, TRUE);
  146.     }
  147.     return (fInit);
  148. }
  149. BOOL
  150. InitMAPI (HWND hWnd)
  151. {
  152.     HRESULT hr;
  153.     hr = MAPIInitialize(NULL);
  154.     if(hr)
  155.     {
  156.         MakeMessageBox(hWnd, GetScode(hr), IDS_MAPIINIF, NULL, MBS_ERROR);
  157.         return FALSE;
  158.     }
  159.     return TRUE;
  160. }
  161. void
  162. DeinitApplication ()
  163. {
  164.     DeinitMAPI ();
  165.     CTL3D_Uninitialize(lpCtl3d);
  166.     lpCtl3d = NULL;
  167. #ifdef _WIN32
  168.     if(g_hChsFldDll)
  169.         FreeLibrary(g_hChsFldDll);
  170.         
  171. #endif /* _WIN32 */
  172. }
  173. void
  174. DeinitMAPI ()
  175. {
  176.     MAPIUninitialize();
  177. }
  178. /*
  179.  *  Log on to MAPI
  180.  *  
  181.  *  Error messages are in subroutings.
  182.  *
  183.  *  Globals:
  184.  *      pses        MAPI session handle
  185.  *      pmdb        MAPI message store object
  186.  *      pabAddrB    MAPI address book object
  187.  *      pfldOutBox  Out folder
  188.  *      pvalSentMailEID     EntryID of the "Sent mail" folder
  189.  */
  190. BOOL ClientLogon (HWND hWnd)
  191. {
  192.     HRESULT hr;
  193.     /* We should not yet be logged on*/
  194.     Assert(pses == NULL);
  195.     Assert(pmdb == NULL);
  196.     
  197.         /* MAPILogon might yield control to Windows. So to prevent the user
  198.     from clicking "logon" while we are in the process of loggin on we
  199.     have to disable it*/
  200.     SecureMenu(hWnd, TRUE);
  201.     /* Create a MAPI session*/
  202.     hr = MAPILogonEx((ULONG) hWnd, NULL, NULL,
  203.             MAPI_EXTENDED | MAPI_EXPLICIT_PROFILE | MAPI_LOGON_UI |
  204.             MAPI_NEW_SESSION, &pses);
  205.     if(hr)
  206.     {
  207.         SecureMenu(hWnd, FALSE);
  208.         pses = NULL;
  209.         if (GetScode(hr) != MAPI_E_USER_CANCEL)
  210.             MakeMessageBox (hWnd, GetScode(hr), IDS_LOGONFAIL, NULL, MBS_ERROR);
  211.         return FALSE;
  212.     }
  213.     pmdb = OpenDefaultStore(hWnd);
  214.     if (!pmdb) goto err;
  215.     pabAddrB = OpenAddressBook(hWnd);
  216.     if (!pabAddrB) goto err;
  217.     if(!OpenOutFolder(hWnd, &pfldOutBox)) goto err;
  218.     
  219.     /* retrieve the EntryID of the sentmail folder and change the property tag
  220.         so that it is ready to use on a message*/
  221.     hr = HrGetOneProp((LPMAPIPROP)pmdb, PR_IPM_SENTMAIL_ENTRYID, &pvalSentMailEID);
  222.     if(hr)
  223.     {
  224.         goto err;
  225.     }
  226.     pvalSentMailEID->ulPropTag = PR_SENTMAIL_ENTRYID;
  227.     return TRUE;
  228. err:
  229.     
  230.     ClientLogoff(hWnd);
  231.     SecureMenu(hWnd, FALSE);
  232.     
  233.     return FALSE;
  234. }
  235. /*
  236.  *  Releases  the global objects and logs off MAPI.
  237.  *
  238.  *  Globals:
  239.  *      pses        Extended-MAPI session object
  240.  *      pmdb        Extended-MAPI message store object
  241.  *      pabAddrB        Address Book
  242.  *      pfldOutBox  out folder
  243.  *      pvalSetmailEID contains EID of the "Sent" folder
  244.  */
  245. VOID
  246. ClientLogoff (HWND hWnd)
  247. {
  248. #ifdef _WIN32
  249.     MAPIFreeBuffer(pbCFDState);
  250.     pbCFDState = NULL;
  251.     cbCFDState = 0;
  252. #endif
  253.     UlRelease(pfldOutBox);
  254.     pfldOutBox = NULL;
  255.     UlRelease(pmdb);
  256.     pmdb = NULL;
  257.     UlRelease(pabAddrB);
  258.     pabAddrB = NULL;
  259.     MAPIFreeBuffer(pvalSentMailEID);
  260.     pvalSentMailEID = NULL;
  261.     pses->lpVtbl->Logoff(pses, (ULONG)hWnd, MAPI_LOGOFF_UI, 0);
  262.     UlRelease(pses);
  263.     pses = NULL;
  264.     SetWindowText(hWnd, "Routing Sample");
  265. }
  266. LPMDB
  267. OpenDefaultStore(HWND hWnd)
  268. {
  269.     HRESULT hr;
  270.     LPMDB lpmdb = NULL;
  271.     LPMAPITABLE ptable = NULL;
  272.     LPSRowSet prows = NULL;
  273.     LPSPropValue pvalProp = NULL;
  274.     static SizedSPropTagArray(2, columns) =
  275.                 { 2, { PR_DEFAULT_STORE, PR_ENTRYID} };
  276.     SPropValue valDefStore;
  277.     SPropertyRestriction restpropDefStore;
  278.     SRestriction restDefStore;
  279.     
  280.     valDefStore.ulPropTag = PR_DEFAULT_STORE;
  281.     valDefStore.dwAlignPad = 0;
  282.     valDefStore.Value.b = TRUE;
  283.     restpropDefStore.relop = RELOP_EQ;
  284.     restpropDefStore.ulPropTag = PR_DEFAULT_STORE;
  285.     restpropDefStore.lpProp = &valDefStore;
  286.     restDefStore.rt = RES_PROPERTY;
  287.     restDefStore.res.resProperty = restpropDefStore;
  288.     hr = pses->lpVtbl->GetMsgStoresTable(pses, 0, &ptable);
  289.     if (HR_FAILED(hr))
  290.     {
  291.         MakeMessageBox (hWnd, GetScode(hr), IDS_STORETBLFAIL, NULL, MBS_ERROR);
  292.         goto ret;
  293.     }
  294.     
  295.     hr = HrQueryAllRows(ptable, (LPSPropTagArray) &columns, &restDefStore, NULL, 0, &prows);
  296.     if (HR_FAILED(hr))
  297.     {
  298.         MakeMessageBox (hWnd, GetScode(hr), IDS_QUERYROWFAIL, NULL, MBS_ERROR);
  299.         goto ret;
  300.     }
  301.     if (prows == NULL || prows->cRows == 0
  302.         || prows->aRow[0].lpProps[1].ulPropTag != PR_ENTRYID)
  303.     {
  304.         MakeMessageBox (hWnd, 0L, IDS_NODEFAULTSTORE, NULL, MBS_ERROR);
  305.         goto ret;
  306.     }
  307.     
  308.     Assert(prows->cRows == 1);
  309.     hr = pses->lpVtbl->OpenMsgStore(pses, (ULONG)hWnd,
  310.                         prows->aRow[0].lpProps[1].Value.bin.cb,
  311.                         (LPENTRYID)prows->aRow[0].lpProps[1].Value.bin.lpb,
  312.                         NULL, MDB_WRITE | MAPI_DEFERRED_ERRORS, &lpmdb);
  313.     if (HR_FAILED(hr))
  314.     {
  315.         if (GetScode(hr) != MAPI_E_USER_CANCEL)
  316.             MakeMessageBox (hWnd, GetScode(hr), IDS_OPENSTOREFAIL, NULL, MBS_ERROR);
  317.         Assert(lpmdb == NULL);
  318.         goto ret;
  319.     }
  320.     if(hr) /*if we have a warning, display it and succeed */
  321.     {
  322.         LPMAPIERROR perr = NULL;
  323.         pses->lpVtbl->GetLastError(pses, hr, 0, &perr);
  324.         MakeMessageBox(hWnd, GetScode(hr), IDS_OPENSTOREWARN, perr, MBS_ERROR);
  325.         MAPIFreeBuffer(perr);
  326.     }
  327.     Assert(lpmdb != NULL);
  328.     hr = HrGetOneProp((LPMAPIPROP)lpmdb, PR_DISPLAY_NAME, &pvalProp);
  329.     if(!hr)
  330.     {   
  331.         char buf[128];
  332.         wsprintf(buf, "Routing Sample: %s", pvalProp->Value.lpszA);
  333.         SetWindowText(hWnd, buf);
  334.         MAPIFreeBuffer(pvalProp);
  335.     }
  336.                     
  337. ret:
  338.     FreeProws(prows);
  339.     UlRelease(ptable);
  340.     return lpmdb;
  341. }
  342. #ifdef _WIN32
  343. BOOL FGetFoldChooser(void)
  344. {
  345.     UINT uiErrMode;
  346.     
  347.     if(g_lpfnHrPickFolder)
  348.         return TRUE;
  349.     Assert(!g_hChsFldDll);
  350.     uiErrMode = SetErrorMode(SEM_NOOPENFILEERRORBOX);
  351.     g_hChsFldDll = LoadLibrary(szChsFldDllName);
  352.     SetErrorMode(uiErrMode);
  353.     if(g_hChsFldDll)
  354.     {
  355.         if((g_lpfnHrPickFolder = (HRPICKFOLDER)GetProcAddress(g_hChsFldDll,
  356.                                         szChsFldFnName)))
  357.         {
  358.             return TRUE;
  359.         }
  360.         DebugTrace("route.cli: GetProcAddress for %s failed", szChsFldFnName);
  361.         
  362.         FreeLibrary(g_hChsFldDll);
  363.         g_hChsFldDll = NULL;
  364.     }
  365.     else
  366.     {
  367.         DebugTrace("smpfrm: failed to load choose folder dlln");
  368.     }
  369.     return FALSE;
  370. }
  371. #endif /* _WIN32 */
  372. /*
  373.  -  MainWndProc
  374.  -
  375.  *   Purpose:
  376.  *      Main Window Procedure.
  377.  *      Handles the menu bar and standard window messages.
  378.  *
  379.  *   Parameters:
  380.  *       hWnd
  381.  *       message
  382.  *       wParam
  383.  *       lParam
  384.  *
  385.  *   Returns:
  386.  *
  387.  *
  388.  */
  389. LONG FAR PASCAL
  390. MainWndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  391. {
  392.     switch (msg)
  393.     {
  394.     HANDLE_MSG(hWnd, WM_COMMAND, MAIN_OnCommand);
  395.     
  396.     case WM_ENDSESSION:
  397.         DestroyWindow (hWnd);
  398.         break;
  399.     case WM_CLOSE:
  400.     case WM_DESTROY:
  401.         if (pses)
  402.             ClientLogoff (hWnd);
  403.         PostQuitMessage (0);
  404.         break;
  405.     default:
  406.         return (DefWindowProc (hWnd, msg, wParam, lParam));
  407.     }
  408.     return FALSE;
  409. }
  410. LONG MAIN_OnCommand(HWND hWnd, int id, HWND hwndCtl, UINT codeNotify)
  411. {
  412.     HRESULT hr;
  413. #ifndef _WIN32
  414.     LPDIALOGDATA pDialogData;
  415. #endif
  416.     LPMESSAGE pmsgOutgoing = NULL;
  417.     ULONG ulMsgToken = 0;
  418.     
  419.     switch (id)
  420.     {
  421.     case IDM_NEWFORM:
  422.         {
  423.             LPMAPIFORMMGR pfmmgr = NULL;
  424.             LPMAPIFORMINFO pfminfo = NULL;          
  425.             LPSPropValue pvalMsgClass = NULL;
  426.             LPMESSAGE pmsgForm = NULL;
  427.             hr = MAPIOpenFormMgr(pses, &pfmmgr);
  428.             if(!hr)
  429.             {
  430.                 hr = pfmmgr->lpVtbl->SelectForm(pfmmgr, (ULONG) hWnd, 0, NULL, NULL, &pfminfo);
  431.                 if(!hr)
  432.                 {
  433.                     
  434.                     /*Get the form's msg class */
  435.                     hr = HrGetOneProp((LPMAPIPROP)pfminfo, PR_MESSAGE_CLASS, &pvalMsgClass);
  436.                     DebugTraceResult(HrGetOneProp, hr);
  437.                     
  438.                     if(!hr)
  439.                     {
  440.                         /*create new message*/
  441.                         if(CreateOutMessage(&pmsgForm))
  442.                         {
  443.                             hr = pses->lpVtbl->PrepareForm(pses, NULL, pmsgForm, (LPULONG) &ulMsgToken);
  444.                             if(S_OK != GetScode(hr))
  445.                             {
  446.                                 DebugTrace("Client: PrepareForm failed");
  447.                                 break;
  448.                             }
  449.                             UlRelease(pmsgForm);
  450.                             pmsgForm = NULL;
  451.                 
  452.                             hr = pses->lpVtbl->ShowForm(pses, (ULONG) hWnd, pmdb, pfldOutBox,
  453.                                                         NULL, ulMsgToken, NULL, MAPI_NEW_MESSAGE,
  454.                                                         0, MSGFLAG_UNSENT | MSGFLAG_READ, 0,
  455.                                                         pvalMsgClass->Value.lpszA );
  456.                             if(S_OK != GetScode(hr))
  457.                             MakeMessageBox(hWnd, GetScode(hr), IDS_SHOWFORM, NULL, MBS_ERROR);
  458.                         }
  459.                         else
  460.                             MakeMessageBox(hWnd, 1, IDS_CRTOUTMSG, NULL, MBS_ERROR);
  461.                     }
  462.                     MAPIFreeBuffer(pvalMsgClass);
  463.                     UlRelease(pfminfo);
  464.                 }
  465.                 UlRelease(pfmmgr);
  466.             }
  467.         }
  468.                 
  469.         break;              
  470.                 
  471.     case IDM_LOGON:
  472.         if (!pses)
  473.         {
  474.             if (ClientLogon (hWnd))
  475.                 ToggleMenuState (hWnd, TRUE);
  476.         }
  477.         break;
  478.     
  479.     case IDM_LOGOFF:
  480.         if (pses)
  481.         {
  482.             ClientLogoff (hWnd);
  483.             ToggleMenuState (hWnd, FALSE);
  484.         }
  485.         break;                  
  486.         
  487.     case IDM_HIER:
  488.         Assert(pses);
  489.         //on win32 use the sample Choose Folder Dialog
  490. #ifdef _WIN32 
  491.         {
  492.             HRESULT hr;
  493.             LPMAPIFOLDER pfld = NULL;
  494.             LPMDB pmdbNew = NULL;
  495.             if(!FGetFoldChooser())
  496.                 return TRUE;
  497.                 
  498.             hr = (*g_lpfnHrPickFolder)(NULL, hWnd, pses, &pfld, &pmdbNew,
  499.                                     &cbCFDState, &pbCFDState);
  500.             if(HR_SUCCEEDED(hr))
  501.             {
  502.                 LPSPropValue pval = NULL;
  503.                 UlRelease(pmdb);
  504.                 pmdb = pmdbNew;
  505.                 pmdbNew = NULL;
  506.                 hr = HrGetOneProp((LPMAPIPROP)pmdb, PR_DISPLAY_NAME, &pval);
  507.                 if(!hr)
  508.                 {   
  509.                     char buf[128];
  510.                     wsprintf(buf, "Routing Sample: %s", pval->Value.lpszA);
  511.                     SetWindowText(hWnd, buf);
  512.                     MAPIFreeBuffer(pval);
  513.                     pval = NULL;
  514.                 }
  515.     
  516.                 hr = HrGetOneProp((LPMAPIPROP)pfld, PR_ENTRYID, &pval);
  517.                 if(!hr)
  518.                 {
  519.                     cbeidFolderToView = pval->Value.bin.cb;
  520.                     lpeidFolderToView = (LPENTRYID)pval->Value.bin.lpb;
  521.                     DialogBox (hInst, "InBox", hWnd, InBoxDlgProc);
  522.                     cbeidFolderToView = 0;
  523.                     lpeidFolderToView = NULL;
  524.                     MAPIFreeBuffer(pval);
  525.                 }
  526.                 
  527.                 UlRelease(pfld);
  528.             }
  529.         }
  530. #else
  531.         
  532.         Assert(pmdb);
  533.         if (pDialogData = CreateDialogData (iHierarchy))
  534.             DialogBoxParam (hInst, "HierarchyTable", hWnd, CommonDlgProc, (LPARAM)pDialogData);
  535. #endif /* _WIN32 */
  536.         break;
  537. #ifndef _WIN32        
  538.     case IDM_OPEN:
  539.         Assert(pses);
  540.         if (pDialogData = CreateDialogData (iStores))
  541.             DialogBoxParam (hInst, "OpenStore", hWnd, CommonDlgProc, (LPARAM)pDialogData);
  542.         break;
  543. #endif /* _WIN32 */
  544.                                                                       
  545.     case IDM_ROUTE:
  546.         Assert(pses);
  547.         DialogBoxParam(hInst, "RouteNote", hWnd, RouteNoteDlgProc, (LPARAM) NULL );
  548.         break;
  549.     case IDM_READ:
  550.         Assert(pses);
  551.         Assert(pmdb);
  552.         Assert(lpeidFolderToView == NULL);
  553.         {
  554.             /* Get the entry ID of the Inbox from the message store. */
  555.             if ((hr = pmdb->lpVtbl->GetReceiveFolder(pmdb,
  556.                     "IPM", 0,
  557.                     &cbeidFolderToView, &lpeidFolderToView, NULL))
  558.                         == hrSuccess)
  559.             {
  560.                 DialogBox (hInst, "InBox", hWnd, InBoxDlgProc);
  561.                 MAPIFreeBuffer(lpeidFolderToView);
  562.                 lpeidFolderToView = NULL;
  563.             }
  564.             else
  565.                 MakeMessageBox (hWnd, GetScode(hr), IDS_GETRCVFAIL, NULL, MBS_ERROR);
  566.         }
  567.         break;
  568.     case IDM_SEND:
  569.         Assert(pses);
  570.         {
  571.             if(CreateOutMessage(&pmsgOutgoing))
  572.             {
  573.                 hr = pses->lpVtbl->PrepareForm(pses, NULL, pmsgOutgoing, (LPULONG) &ulMsgToken);
  574.                 if(S_OK != GetScode(hr))
  575.                 {
  576.                     DebugTrace("Client: PrepareForm failed");
  577.                     break;
  578.                 }
  579.                 UlRelease(pmsgOutgoing);
  580.                 pmsgOutgoing = NULL;
  581.                 
  582.                 hr = pses->lpVtbl->ShowForm(pses, (ULONG) hWnd, pmdb, pfldOutBox, NULL, ulMsgToken,
  583.                                             NULL, MAPI_NEW_MESSAGE, 0, MSGFLAG_UNSENT | MSGFLAG_READ, 0, "IPM.Note");
  584.                 if(S_OK != GetScode(hr))
  585.                     MakeMessageBox(hWnd, GetScode(hr), IDS_SHOWFORM, NULL, MBS_ERROR);
  586.             }
  587.             else
  588.                 MakeMessageBox(hWnd, 1, IDS_CRTOUTMSG, NULL, MBS_ERROR);                
  589.         }
  590.         break;
  591.           
  592.     case IDM_ABOUT:
  593.         DialogBox (hInst, "AboutBox", hWnd, AboutDlgProc);
  594.         break;
  595.     
  596.     case IDM_EXIT:
  597.         if (pses)
  598.             ClientLogoff (hWnd);
  599.     
  600.         PostQuitMessage (0);
  601.         break;
  602.         default:
  603.             return TRUE;
  604.     }
  605.     return FALSE;
  606. }
  607.     
  608. /*
  609.  *  Displays an About dialog for the sample client.
  610.  */
  611. BOOL CALLBACK
  612. AboutDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  613. {
  614.     char    rgchVersion[80];
  615.     switch (msg)
  616.     {
  617.     case WM_INITDIALOG:
  618.         wsprintf(rgchVersion, "Version %d.%d.%d (%s)", rmj, rmm, rup,
  619.             szVerName && *szVerName ? szVerName : "BUDDY");
  620.         SetDlgItemText(hDlg, IDC_VERSION, rgchVersion);
  621.         return TRUE;
  622.     case WM_COMMAND:
  623.         if (wParam == IDOK || wParam == IDCANCEL)
  624.         {
  625.             EndDialog (hDlg, TRUE);
  626.             return TRUE;
  627.         }
  628.         break;
  629.     }
  630.     return FALSE;
  631. }
  632.             
  633. /*
  634.  *  Handles the Inbox list view, its command buttons.
  635.  *  The main window is a listbox presenting a summary line for
  636.  *  each message in the Inbox. There are command buttons for
  637.  *  refreshing the list, displaying a message, and deleting a
  638.  *  message.
  639.  *
  640.  *  All operations are on single messages; multiple selection is
  641.  *  not supported.
  642.  *
  643.  *  The EntryID of the folder to examine is passed in using
  644.  *  the global lpeidFolderToView.
  645.  */
  646. BOOL CALLBACK
  647. InBoxDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  648. {
  649.     LPMSGID lpMsgIdList = NULL;
  650.     HCURSOR hOldCur;
  651.     LPMESSAGE pmsgRead = NULL;
  652.     ULONG ulObjType = 0;
  653.     ULONG ulMsgToken = 0;
  654.     LPINBOXDATA pIBData = NULL;
  655.     switch (msg)
  656.     {
  657.     case WM_INITDIALOG:
  658.         if(MAPIAllocateBuffer(sizeof(INBOXDATA), &pIBData))
  659.         {
  660.             EndDialog(hDlg, FALSE);
  661.             return TRUE;
  662.         }
  663.         
  664.         hOldCur = SetCursor(hWaitCur);
  665.         ZeroMemory(pIBData, sizeof(INBOXDATA));
  666.         
  667.         InitBmps(hDlg, IDC_MSG);
  668.         /* Populate List Box with all messages in InBox. */
  669.         PopulateMessages(hDlg, pIBData);
  670.         SetCursor(hOldCur);
  671.         SetFocus (GetDlgItem (hDlg, IDC_MSG));
  672.         SetWindowLong(hDlg, GWL_USERDATA, (LONG)pIBData);
  673.         return TRUE;
  674.         break;
  675.     case WM_SETFOCUS:
  676.         SetFocus (GetDlgItem (hDlg, IDC_MSG));
  677.         break;
  678.     case WM_MEASUREITEM:
  679.         /* Sets the height of the owner-drawn List-Box */
  680.         MeasureItem(hDlg, (MEASUREITEMSTRUCT *)lParam);
  681.         break;
  682.     case WM_DRAWITEM:
  683.         DrawItem((DRAWITEMSTRUCT *)lParam);
  684.         break;
  685.     case WM_CHARTOITEM:     /* don't select item by character*/
  686.         return  -2;
  687.     /* Handled by IDC_DELETE */
  688.     case WM_DELETEITEM:
  689.         return TRUE;
  690.     HANDLE_MSG(hDlg, WM_COMMAND, INBOX_OnCommand);
  691.         break;
  692.     }
  693.     return FALSE;
  694. }
  695. void INBOX_OnCommand(HWND hDlg, int id, HWND hwndCtl, UINT codeNotify)
  696. {
  697.     LPMSGID lpMsgNode = NULL;
  698.     LPINBOXDATA pibData = NULL;
  699.     HCURSOR hOldCur;
  700.     UINT nIndex;
  701.     RECT Rect;
  702.     LPMESSAGE pmsgRead = NULL;
  703.     ULONG ulObjType = 0;
  704.     HRESULT hr;
  705.     ULONG ulMsgToken = 0;
  706.     ULONG cProps = 0;
  707.     LPSPropValue pvalProps = NULL;
  708.     LONG lStat = 0, lFlags = 0, lAccess = 0;
  709.     LPSTR lpszMsgClass = "IPM.Note";
  710.     enum { PRSTAT, PRFLAGS, PRACCESS, PRCLASS, PRDIM};      /* used to retrieve props*/
  711.     SizedSPropTagArray(PRDIM, sptaSFProps) =                /*required for ShowForm call*/
  712.     { PRDIM, {PR_MSG_STATUS, PR_MESSAGE_FLAGS, PR_ACCESS_LEVEL, PR_MESSAGE_CLASS} };
  713.     
  714.     switch (id)
  715.     {
  716.     
  717.     case IDC_FLUSH:
  718.         hr = DeliverNow(hDlg);
  719.         if(hr)
  720.             break;
  721.          /*fall through if the flush was succesfull*/
  722.     case IDC_NEW:
  723.         
  724.         pibData = (LPINBOXDATA)GetWindowLong(hDlg, GWL_USERDATA);
  725.         if(!pibData)
  726.         {
  727.             DebugTrace("Client: userdata == 0 (inboxdlgproc)");
  728.         }
  729.         hOldCur = SetCursor(hWaitCur);
  730.     
  731.         /* Destroy the old message list. */
  732.         FreeMsgList (pibData->lpMsgIdList);
  733.         pibData->lpMsgIdList = NULL;
  734.         /* Populate List Box with all messages in InBox. */
  735.         PopulateMessages(hDlg, pibData);
  736.         
  737.         SetCursor(hOldCur);
  738.         break;
  739.     case IDC_MSG:
  740.         if(codeNotify != LBN_DBLCLK)
  741.         break;
  742.         /* FALL THROUGH to read the double-clicked message */
  743.     
  744.     case IDC_READ:
  745.         nIndex = (UINT)ListBox_GetCurSel(GetDlgItem(hDlg, IDC_MSG));
  746.         if (nIndex == LB_ERR)
  747.         break;
  748.     
  749.         lpMsgNode = (LPMSGID)ListBox_GetItemData(GetDlgItem(hDlg, IDC_MSG), nIndex);
  750.         if (lpMsgNode)
  751.         {   
  752.             hr = pmdb->lpVtbl->OpenEntry(pmdb, lpMsgNode->cbEID, lpMsgNode->lpEID,
  753.                                 NULL, MAPI_BEST_ACCESS | MAPI_DEFERRED_ERRORS,
  754.                                 &ulObjType, (LPUNKNOWN FAR *) &pmsgRead);
  755.     
  756.             if(S_OK != GetScode(hr))
  757.             {
  758.                 LPMAPIERROR perr = NULL;
  759.                 
  760.                 pmdb->lpVtbl->GetLastError(pmdb, hr, 0, &perr);
  761.                 MakeMessageBox(hDlg, GetScode(hr), IDS_READFAIL, perr, MBS_ERROR);
  762.                 MAPIFreeBuffer(perr);
  763.                 DebugTrace("Client: OpenEntry failed");
  764.                 break;
  765.             }
  766.             else
  767.             { 
  768.                 Assert(ulObjType == MAPI_MESSAGE);
  769.     
  770.                 lpMsgNode->fUnRead = FALSE;
  771.         
  772.                 /* get all the props in one call */
  773.                 hr = pmsgRead->lpVtbl->
  774.                 GetProps(pmsgRead, (LPSPropTagArray)&sptaSFProps, 0,
  775.                                                     &cProps, &pvalProps);
  776.                 if(HR_SUCCEEDED(hr))
  777.                 {
  778.                     if(pvalProps[PRSTAT].ulPropTag == PR_MSG_STATUS) 
  779.                         lStat = pvalProps[PRSTAT].Value.l;
  780.                     if(pvalProps[PRFLAGS].ulPropTag == PR_MESSAGE_FLAGS)
  781.                         lFlags = pvalProps[PRFLAGS].Value.l;
  782.                     if(pvalProps[PRACCESS].ulPropTag == PR_ACCESS_LEVEL)
  783.                         lAccess = pvalProps[PRACCESS].Value.l;
  784.                     if(pvalProps[PRCLASS].ulPropTag == PR_MESSAGE_CLASS)
  785.                         lpszMsgClass = pvalProps[PRCLASS].Value.lpszA;
  786.                 }
  787.                 
  788.                 else
  789.                 {
  790.                     DebugTrace("Client: GetProps (for ShowForm) failed");
  791.                     break;
  792.                 }
  793.                 
  794.                 if (!lstrcmpi(lpszMsgClass, lpszSmplRTMsgClass))
  795.                 {
  796.                     DialogBoxParam(hInst, "RouteNote", hDlg, RouteNoteDlgProc, (LPARAM) pmsgRead);
  797.                     /* RouteNoteDlgPropc will release pmsgRead*/
  798.                 }
  799.                 else
  800.                 {                                   
  801.                     hr = pses->lpVtbl->PrepareForm(pses, NULL, pmsgRead, (LPULONG) &ulMsgToken);
  802.                     if(S_OK != GetScode(hr))
  803.                     {
  804.                         DebugTrace("Client: PrepareForm failed");
  805.                         MAPIFreeBuffer(pvalProps);
  806.                         break;
  807.                     }
  808.                     UlRelease(pmsgRead);
  809.                     pmsgRead = NULL;
  810.                     hr = pses->lpVtbl->ShowForm(pses, (ULONG) hDlg, pmdb, pfldOutBox, NULL, ulMsgToken,
  811.                                             NULL, 0, lStat, lFlags, lAccess, lpszMsgClass);
  812.                     
  813.                 }
  814.             }
  815.             
  816.         }
  817.         
  818.         MAPIFreeBuffer(pvalProps);
  819.         pvalProps = NULL;
  820.         /* Update the Messages List-Box with new icon */
  821.         lpMsgNode = NULL;
  822.         ListBox_GetItemRect(GetDlgItem(hDlg, IDC_MSG),nIndex, (LPARAM) &Rect);
  823.         InvalidateRect(GetDlgItem(hDlg, IDC_MSG), &Rect, FALSE);
  824.         
  825.         break;
  826.         
  827.     case IDC_DELETE:
  828.         {
  829.         ENTRYLIST el;
  830.         SBinary sb;
  831.         
  832.         nIndex = (UINT)ListBox_GetCurSel(GetDlgItem(hDlg, IDC_MSG));
  833.         if (nIndex == LB_ERR)
  834.             break;
  835.     
  836.         pibData = (LPINBOXDATA)GetWindowLong(hDlg, GWL_USERDATA);
  837.         if(!pibData)
  838.         {
  839.             DebugTrace("Client: userdata == 0 (inboxdlgproc)");
  840.         }
  841.         
  842.         lpMsgNode = (LPMSGID) ListBox_GetItemData(GetDlgItem(hDlg, IDC_MSG),
  843.                                                 nIndex);
  844.         if (lpMsgNode)
  845.         {   
  846.             sb.cb = lpMsgNode->cbEID;
  847.             sb.lpb = (LPBYTE)lpMsgNode->lpEID;
  848.             el.cValues = 1;
  849.             el.lpbin = &sb;
  850.             hr = pibData->pfld->lpVtbl->
  851.                     DeleteMessages(pibData->pfld, &el, 0, NULL, 0);
  852.             DeleteMsgNode (lpMsgNode, &pibData->lpMsgIdList);
  853.         }
  854.         ListBox_DeleteString(GetDlgItem(hDlg, IDC_MSG), nIndex);
  855.         }
  856.         break;
  857.     
  858.     case IDC_CLOSE:
  859.     case IDCANCEL:
  860.         pibData = (LPINBOXDATA)GetWindowLong(hDlg, GWL_USERDATA);
  861.         if(!pibData)
  862.         {
  863.             DebugTrace("Client: userdata == 0 (inboxdlgproc)");
  864.             
  865.         }
  866.         
  867.         FreeMsgList (pibData->lpMsgIdList);
  868.         pibData->lpMsgIdList = NULL;
  869.         UlRelease(pibData->pfld);
  870.         pibData->pfld = NULL;
  871.         MAPIFreeBuffer(pibData);
  872.         pibData = NULL;
  873.         DeInitBmps();
  874.         EndDialog (hDlg, TRUE);
  875.         break;
  876.     
  877.     default:
  878.         break;
  879.     }
  880. }
  881. /*
  882.  *  DeliverNow flushes outbound and inboud queues.
  883.  *
  884.  */
  885. HRESULT DeliverNow(HWND hWnd)
  886. {
  887.     HRESULT hr;
  888.     LPMAPISTATUS pstatSpooler = NULL;
  889.     ULONG ulObjType = 0;
  890.     LPMAPITABLE ptblStatus = NULL;
  891.     SizedSPropTagArray(1, columns) =
  892.                 { 1, { PR_ENTRYID} };
  893.     SPropValue valSpooler;
  894.     SPropertyRestriction restpropSpooler;
  895.     SRestriction restSpooler;
  896.     LPSRowSet prows = NULL;
  897.     
  898.     /*Build property restriction (PR_RESOURCE_TYPE == MAPI_SPOOLER)*/
  899.     valSpooler.ulPropTag = PR_RESOURCE_TYPE;
  900.     valSpooler.dwAlignPad = 0;
  901.     valSpooler.Value.l = MAPI_SPOOLER;
  902.     restpropSpooler.relop = RELOP_EQ;
  903.     restpropSpooler.ulPropTag = PR_RESOURCE_TYPE;
  904.     restpropSpooler.lpProp = &valSpooler;
  905.     restSpooler.rt = RES_PROPERTY;
  906.     restSpooler.res.resProperty = restpropSpooler;
  907.     /*open session status table*/
  908.     hr = pses->lpVtbl->GetStatusTable(pses, 0, &ptblStatus);
  909.     if(hr)
  910.     {
  911.         DebugTraceResult(GetStatusTable, hr);
  912.         goto err;
  913.     }
  914.     /*find a row corresponding to the spooler*/
  915.     hr = HrQueryAllRows(ptblStatus, (LPSPropTagArray) &columns, &restSpooler, NULL, 0, &prows);
  916.     if (HR_FAILED(hr))
  917.     {
  918.         DebugTraceResult(HrQueryAllRows, hr);
  919.         goto err;
  920.     }
  921.     Assert(prows && prows->cRows == 1); /*hope the spooler is always there */
  922.     Assert(prows->aRow[0].lpProps[0].ulPropTag == PR_ENTRYID);
  923.     
  924.     /*open spooler as a status object*/
  925.     hr = pses->lpVtbl->
  926.             OpenEntry(pses, prows->aRow->lpProps->Value.bin.cb,
  927.                         (LPENTRYID)prows->aRow->lpProps->Value.bin.lpb,
  928.                         &IID_IMAPIStatus, MAPI_BEST_ACCESS, &ulObjType,
  929.                         (LPUNKNOWN FAR *) &pstatSpooler);
  930.     if(hr)
  931.     {
  932.         DebugTraceResult(OpenEntry, hr);
  933.         goto err;
  934.     }
  935.     Assert(ulObjType == MAPI_STATUS);
  936.     /*call FlushQueues()*/
  937.     hr = pstatSpooler->lpVtbl->FlushQueues(pstatSpooler, (ULONG) hWnd, 0, NULL, 
  938.                                             FLUSH_DOWNLOAD | FLUSH_UPLOAD);
  939.     if(hr)
  940.     {
  941.         DebugTraceResult(FlushQueues, hr);
  942.         goto err;
  943.     }
  944.     
  945.     /*release all used objects*/
  946. err:
  947.     UlRelease(ptblStatus);
  948.     FreeProws(prows);
  949.     UlRelease(pstatSpooler);
  950.     return hr;
  951. }
  952.     /*
  953.  -  MakeMessageBox
  954.  -
  955.  *  Purpose:
  956.  *      Gets resource string and displays an error message box.
  957.  *
  958.  *  Parameters:
  959.  *      hWnd            - Handle to parent window
  960.  *      sc              - SCODE
  961.  *      idString        - Resource ID of message in StringTable
  962.  *      perr            - pointer to MAPIERROR from last GetLastError
  963.  *      fStyle          - style for MessageBox
  964.  *
  965.  *  Returns:
  966.  *      Void
  967.  *
  968.  */
  969. void
  970. MakeMessageBox (HWND hWnd, SCODE sc, UINT idString, LPMAPIERROR perr, UINT fStyle)
  971. {
  972.     char szMessage[512];
  973.     char szbuf[256];
  974.     if(!LoadString (hInst, idString, szMessage, 255))
  975.         return;
  976.     if(perr)
  977.     {
  978.         wsprintf(szbuf, "n%sn%snLowLevelError: 0x%08lx context: %ld ", (perr->lpszError ? perr->lpszError:""),
  979.                         perr->lpszComponent ? perr->lpszComponent:"", perr->ulLowLevelError, perr->ulContext);
  980.         lstrcat(szMessage, szbuf);
  981.     }
  982.     if (sc)
  983.     {
  984.         wsprintf (szbuf, "nReturn Code: 0x%08lx", sc);
  985.         lstrcat (szMessage, szbuf);
  986.     }
  987.     MessageBox (hWnd, szMessage, "Sample Routing Form", fStyle);
  988. }
  989. /*
  990.  * Common Dialog Proc for store and folder listboxes
  991.  *
  992.  */
  993. BOOL CALLBACK
  994. CommonDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  995. {
  996.     MEASUREITEMSTRUCT *pmis;
  997.     DRAWITEMSTRUCT *pdis;
  998.     HCURSOR hOldCur;
  999.     LPDIALOGDATA pdd = (LPDIALOGDATA) GetWindowLong(hDlg, DWL_USER);
  1000.     switch (msg)
  1001.     {
  1002.     case WM_INITDIALOG:
  1003.         /* Remember the address of our dialog data*/
  1004.         SetWindowLong(hDlg, DWL_USER, lParam);
  1005.         pdd = (LPDIALOGDATA)lParam;
  1006.         Assert(pdd->poarHead == NULL);
  1007.         /*/ Load up the rows of the dialog*/
  1008.         hOldCur = SetCursor(hWaitCur);
  1009.         PopulateStores (hDlg, &pdd->poarHead, pdd->iDlgType,
  1010.             pdd->cbEntryID, pdd->lpEntryID);
  1011.         SetCursor(hOldCur);
  1012.         SetFocus (GetDlgItem (hDlg, IDC_MSG));
  1013.         return TRUE;
  1014.     case WM_DESTROY:
  1015.         /* Discard our dialog data*/
  1016.         FreeOarList(&pdd->poarHead);
  1017.         MAPIFreeBuffer(pdd);
  1018.         return TRUE;
  1019.     case WM_SETFOCUS:
  1020.         SetFocus (GetDlgItem (hDlg, IDC_MSG));
  1021.         break;
  1022.     case WM_MEASUREITEM:
  1023.         /* Sets the height of the owner-drawn List-Box */
  1024.         pmis = (MEASUREITEMSTRUCT *) lParam;
  1025.         pmis->itemHeight = 15;
  1026.         break;
  1027.     case WM_DRAWITEM:
  1028.         pdis = (DRAWITEMSTRUCT *) lParam;
  1029.         DrawOarItem (pdis, pdd->iDlgType);
  1030.         break;
  1031.     case WM_CHARTOITEM:     /* don't select item by character*/
  1032.         return -2;
  1033.     /* Handled by IDC_DELETE */
  1034.     case WM_DELETEITEM:
  1035.         return TRUE;
  1036. //  HANDLE_MSG(hDlg, WM_COMMAND, Common_OnCommand);
  1037.     case WM_COMMAND:
  1038.         return ((Common_OnCommand)((hDlg), (int)(wParam), (HWND)(LOWORD(lParam)), 0L));
  1039.     }   /* switch (msg) */
  1040.     return FALSE;
  1041. }
  1042. BOOL Common_OnCommand(HWND hDlg, int id, HWND hwndCtl, UINT codeNotify)
  1043. {
  1044.     LPDIALOGDATA pdd = (LPDIALOGDATA) GetWindowLong(hDlg, DWL_USER);
  1045.     switch (id)
  1046.     {
  1047.     case IDC_MSG:
  1048.         if(codeNotify != LBN_DBLCLK)
  1049.             break;
  1050.             /* FALL THROUGH to read the double-clicked store */
  1051.     case IDC_DOWN:
  1052.     case IDC_READ:
  1053.         /*/ open a Hierarchy or Store*/
  1054.     {
  1055.             /*/ Open one of the items in the list*/
  1056.         LPMDB pmdbTemp;
  1057.         UINT nIndex;
  1058.         LPOAR poar;
  1059.         LPSPropValue pProp;
  1060.         LPSPropValue pvalProp = NULL;
  1061.         HRESULT hr;
  1062.         nIndex = (UINT)ListBox_GetCurSel(GetDlgItem(hDlg, IDC_MSG));
  1063.         if (nIndex == LB_ERR)
  1064.             return TRUE;
  1065.         poar = (LPOAR) ListBox_GetItemData(GetDlgItem(hDlg, IDC_MSG), nIndex);
  1066.         if (!poar)
  1067.             return TRUE;
  1068.                 /* PropFindProp from mapiutil.h */
  1069.         pProp = PpropFindProp(poar->lpProps,  poar->cValues, PR_ENTRYID);
  1070.         
  1071.         Assert(pProp);
  1072.         /*/ Every row should have an EntryID */
  1073.         
  1074.         if (pdd->iDlgType == iStores)
  1075.         {
  1076.             hr = pses->lpVtbl->OpenMsgStore(pses,
  1077.                 (ULONG)hDlg,
  1078.                 pProp->Value.bin.cb,
  1079.                 (LPENTRYID)pProp->Value.bin.lpb,
  1080.                 NULL, MDB_WRITE, &pmdbTemp);
  1081.             if (HR_FAILED(hr))
  1082.             {
  1083.                 if (GetScode(hr) != MAPI_E_USER_CANCEL)
  1084.                     MakeMessageBox (hDlg, GetScode(hr), IDS_OPENSTOREFAIL, NULL, MBS_ERROR);
  1085.                 return TRUE;
  1086.                 }
  1087.             if(hr) /*if we have a warning*/
  1088.             {
  1089.                 LPMAPIERROR perr = NULL;
  1090.                 pses->lpVtbl->GetLastError(pses, hr, 0, &perr);
  1091.                 MakeMessageBox(hDlg, GetScode(hr), IDS_OPENSTOREWARN, perr, MBS_ERROR);
  1092.                 MAPIFreeBuffer(perr);
  1093.             }
  1094.             Assert(hr == hrSuccess);    /* no warnings (for now?)*/
  1095.             UlRelease(pmdb);
  1096.             pmdb = pmdbTemp;
  1097.             /*Change the caption of the main window */
  1098.             hr = HrGetOneProp((LPMAPIPROP)pmdb, PR_DISPLAY_NAME, &pvalProp);
  1099.             if(!hr)
  1100.             {
  1101.                 char buf[128];
  1102.             
  1103.                 wsprintf(buf, "Routing Sample: %s", pvalProp->Value.lpszA);
  1104.                 SetWindowText(GetParent(hDlg), buf);
  1105.                 MAPIFreeBuffer(pvalProp);
  1106.                 pvalProp = NULL;
  1107.             }
  1108.                     
  1109.             EndDialog (hDlg, TRUE);
  1110.             return TRUE;
  1111.         }
  1112.         Assert (pdd->iDlgType == iHierarchy);
  1113.         if (id == IDC_DOWN)
  1114.         {
  1115.             LPDIALOGDATA pDialogData;
  1116.             if (pDialogData = CreateDialogData (iHierarchy))
  1117.             {
  1118.                 pDialogData->cbEntryID = pProp->Value.bin.cb;
  1119.                 pDialogData->lpEntryID = (LPENTRYID)pProp->Value.bin.lpb;
  1120.                 DialogBoxParam (hInst, "HierarchyTable", hDlg, CommonDlgProc, (LPARAM)pDialogData);
  1121.             }
  1122.         }
  1123.         else    /* IDC_READ */
  1124.         {
  1125.             /* OPEN a contents table*/
  1126.             Assert(lpeidFolderToView == NULL);
  1127.             cbeidFolderToView = pProp->Value.bin.cb;
  1128.             lpeidFolderToView = (LPENTRYID)pProp->Value.bin.lpb;
  1129.             DialogBox (hInst, "InBox", hDlg, InBoxDlgProc);
  1130.             lpeidFolderToView = NULL;
  1131.         }
  1132.     }
  1133.     return TRUE;
  1134.     case IDC_CLOSE:
  1135.     case IDCANCEL:
  1136.         EndDialog (hDlg, TRUE);
  1137.         return TRUE;
  1138.     }
  1139.     return TRUE;
  1140. }
  1141. /*
  1142.  -  PopulateStores
  1143.  -
  1144.  *  Accumulate all the rows of a table onto the OAR list.
  1145.  *  idlgType indicates iStores, iHierarchy.
  1146.  *
  1147.  *  If iHierarchy, the EntryID of the folder is in cb/lpeid.
  1148.  */
  1149. VOID
  1150. PopulateStores ( HWND hDlg, LPOAR FAR * ppoarHead, int idlgType,
  1151.         ULONG cb, LPENTRYID lpeid)
  1152. {
  1153.     HRESULT hr;
  1154.     SCODE sc;
  1155.     LPMAPIFOLDER pfld = NULL;
  1156.     LPMAPITABLE ptable = NULL;
  1157.     LPSRowSet prows = NULL;
  1158.     LPSPropValue pvalProp = NULL;
  1159.     UINT idx;
  1160.     /* Get the list of available message stores or folderes from MAPI*/
  1161.     Assert(pses);
  1162.     switch (idlgType)
  1163.     {
  1164.     case iStores:
  1165.         if (hr = pses->lpVtbl->GetMsgStoresTable(pses, 0, &ptable))
  1166.         {
  1167.             MakeMessageBox (hDlg, GetScode(hr), IDS_STORETBLFAIL, NULL, MBS_ERROR);
  1168.             goto ret;
  1169.         }
  1170.         break;
  1171.     case iHierarchy:
  1172.         {
  1173.             ULONG ulObjType;
  1174.             if (hr = pmdb->lpVtbl->OpenEntry(pmdb, cb, lpeid, NULL,
  1175.                                 MAPI_DEFERRED_ERRORS,
  1176.                             &ulObjType, (LPUNKNOWN FAR *) &pfld))
  1177.             {
  1178.                 MakeMessageBox (hDlg, GetScode(hr), IDS_OPENFOLDERFAIL, NULL, MBS_ERROR);
  1179.                 goto ret;
  1180.             }
  1181.             Assert(ulObjType == MAPI_FOLDER);
  1182.             if (hr = pfld->lpVtbl->GetHierarchyTable(pfld, MAPI_DEFERRED_ERRORS,
  1183.                                                         &ptable))
  1184.             {
  1185.                 MakeMessageBox (hDlg, GetScode(hr), IDS_STORETBLFAIL, NULL, MBS_ERROR);
  1186.                 goto ret;
  1187.             }
  1188.             hr = HrGetOneProp((LPMAPIPROP)pfld, PR_DISPLAY_NAME, &pvalProp);
  1189.             if(!hr)
  1190.             {
  1191.                 if(*pvalProp->Value.lpszA)
  1192.                     SetWindowText(hDlg, pvalProp->Value.lpszA);
  1193.                 MAPIFreeBuffer(pvalProp);
  1194.                 pvalProp = NULL;
  1195.             }
  1196.                     
  1197.         }
  1198.         break;
  1199.     default:
  1200.         Assert(0);
  1201.     }
  1202.     if(hr = HrQueryAllRows(ptable, NULL, NULL, NULL, 1000l, &prows))
  1203.     {
  1204.         MakeMessageBox (hDlg, GetScode(hr), IDS_QUERYROWFAIL, NULL, MBS_ERROR);
  1205.         goto ret;
  1206.     }
  1207.     for(idx = 0; idx < prows->cRows; ++idx)
  1208.     {
  1209.         LPOAR poar = NULL;
  1210.         sc = MAPIAllocateBuffer(sizeof(OAR), &poar);
  1211.         if (sc)
  1212.         {
  1213.             hr = ResultFromScode(sc);
  1214.             FreeProws(prows);   /* free ENTIRE row*/
  1215.             break;
  1216.         }
  1217.         /*/ Transfer the data of the row to our OAR structure.*/
  1218.         poar->cValues = prows->aRow[idx].cValues;
  1219.         poar->lpProps = prows->aRow[idx].lpProps;
  1220.         /* Put OAR at head of the list*/
  1221.         if (*ppoarHead)
  1222.             (*ppoarHead)->lpPrev = poar;
  1223.         poar->lpPrev = NULL;
  1224.         poar->lpNext = (*ppoarHead);
  1225.         *ppoarHead  = poar;
  1226.         ListBox_AddString(GetDlgItem(hDlg, IDC_MSG), (LONG) poar);
  1227.     }
  1228.     
  1229.     MAPIFreeBuffer(prows);  /* free OUTER buffer only*/
  1230. ret:
  1231.     UlRelease(ptable);
  1232.     UlRelease(pfld);
  1233. }
  1234. /*
  1235.  -  FreeOarList
  1236.  -
  1237.  *  Free the memory of the rows on the screen.
  1238.  *  Zero the pointer passed in.
  1239.  */
  1240. VOID
  1241. FreeOarList (LPOAR FAR *ppoarHead)
  1242. {
  1243.     LPOAR poar = *ppoarHead;
  1244.     while (poar)
  1245.     {
  1246.         LPOAR poarTemp = poar;
  1247.         poar = poarTemp->lpNext;
  1248.         MAPIFreeBuffer(poarTemp->lpProps);
  1249.         MAPIFreeBuffer(poarTemp);
  1250.     }
  1251.     *ppoarHead = NULL;
  1252. }
  1253. /*
  1254.  -  DrawOarItem
  1255.  -
  1256.  *  Purpose:
  1257.  *      Paint the client area of the owner-drawn listbox.
  1258.  *
  1259.  *  Parameters:
  1260.  *      pdis        - Pointer to a DRAWITEMSTRUCT
  1261.  *
  1262.  *  Returns:
  1263.  *      void
  1264.  *
  1265.  */
  1266. VOID
  1267. DrawOarItem (DRAWITEMSTRUCT FAR * pdis, int idlgType)
  1268. {
  1269.     HBRUSH hSolidBrush = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
  1270.     HBRUSH hOldBrush = SelectObject(pdis->hDC, hSolidBrush);
  1271.     if (ODA_DRAWENTIRE & pdis->itemAction)
  1272.     {
  1273.         LPOAR poar;
  1274.         LPSPropValue pProp;
  1275.         UINT c;
  1276.         /* Clear the item Rectangle */
  1277.         PatBlt (pdis->hDC, pdis->rcItem.left, pdis->rcItem.top,
  1278.             pdis->rcItem.right - pdis->rcItem.left,
  1279.             pdis->rcItem.bottom - pdis->rcItem.top, PATCOPY);
  1280.         /* Draw the item */
  1281.         poar = (LPOAR) pdis->itemData;
  1282.         for (pProp = poar->lpProps, c = (UINT)poar->cValues;
  1283.             c > 0;
  1284.             c-- , pProp++)
  1285.         {
  1286.             /* Identify the Default Store*/
  1287.             if (idlgType == iStores
  1288.                     && pProp->ulPropTag == PR_DEFAULT_STORE && pProp->Value.b)
  1289.                 TextOut (pdis->hDC, pdis->rcItem.left + 10, pdis->rcItem.top+2,
  1290.                     TEXT(">"), 1);
  1291.             if (pProp->ulPropTag == PR_DISPLAY_NAME)
  1292.                 TextOut (pdis->hDC, pdis->rcItem.left + 20, pdis->rcItem.top+2,
  1293.                     pProp->Value.LPSZ,
  1294.                     lstrlen (pProp->Value.LPSZ));
  1295.         }
  1296.         /* Invert item rectangle if item is selected */
  1297.         if (ODS_SELECTED & pdis->itemState)
  1298.             PatBlt (pdis->hDC, pdis->rcItem.left, pdis->rcItem.top,
  1299.                 pdis->rcItem.right - pdis->rcItem.left,
  1300.                 pdis->rcItem.bottom - pdis->rcItem.top, DSTINVERT);
  1301.         /* Draw a focus rectangle if item has focus */
  1302.         if (ODS_FOCUS & pdis->itemState)
  1303.             DrawFocusRect (pdis->hDC, &pdis->rcItem);
  1304.     }
  1305.     else
  1306.     {
  1307.         /* Invert the item if the selection state is changing */
  1308.         if (ODA_SELECT & pdis->itemAction)
  1309.             PatBlt (pdis->hDC, pdis->rcItem.left, pdis->rcItem.top,
  1310.                 pdis->rcItem.right - pdis->rcItem.left,
  1311.                 pdis->rcItem.bottom - pdis->rcItem.top, DSTINVERT);
  1312.         /* Draw a focus if the focus state is changing */
  1313.         if (ODA_FOCUS & pdis->itemAction)
  1314.             DrawFocusRect (pdis->hDC, &pdis->rcItem);
  1315.     }
  1316.     SelectObject(pdis->hDC, hOldBrush);
  1317.     DeleteObject(hSolidBrush);
  1318. }
  1319. /* Fill the lppMsgIdList with info about the messages in the specified folder. */
  1320. enum { E_EID=0, E_SUBJECT, E_SENDER_NAME, E_MSG_DEL_TIME, E_FLAGS, E_PRIORITY, E_CONVERS_KEY,
  1321.         E_SEARCH_KEY, E_CLASS, E_RECORD_KEY, E_PTINBOXDIM};
  1322. SizedSPropTagArray(E_PTINBOXDIM, ptInbox) =
  1323. {
  1324.     E_PTINBOXDIM,
  1325.     {
  1326.         PR_ENTRYID,
  1327.         PR_SUBJECT,
  1328.         PR_SENDER_NAME,
  1329.         PR_MESSAGE_DELIVERY_TIME,
  1330.         PR_MESSAGE_FLAGS,
  1331.         PR_PRIORITY,
  1332.         PR_CONVERSATION_KEY,
  1333.         PR_SEARCH_KEY,
  1334.         PR_MESSAGE_CLASS,
  1335.         PR_RECORD_KEY
  1336.     }
  1337. };
  1338. VOID
  1339. PopulateMessages( HWND hDlg, LPINBOXDATA pibData )
  1340. {
  1341.     LPMAPIFOLDER pfld = pibData->pfld;
  1342.     LPMAPITABLE ptable = NULL;
  1343.     LPSRowSet prows = NULL;
  1344.     HRESULT hr;
  1345.     ULONG ulType;
  1346.     SizedSSortOrderSet(1, sos) =
  1347.         { 1, 0, 0, { PR_MESSAGE_DELIVERY_TIME, TABLE_SORT_ASCEND } };
  1348.     UINT nIndex;
  1349.     LPMSGID lpMsgNode;
  1350.     LPSPropValue pvalProp = NULL;
  1351.     ListBox_ResetContent(GetDlgItem(hDlg, IDC_MSG));
  1352.     if(!pfld)
  1353.     {
  1354.         /* Open the right folder, and get the list of messages. */
  1355.         hr = pmdb->lpVtbl->OpenEntry(pmdb,cbeidFolderToView, lpeidFolderToView,
  1356.                                  NULL, MAPI_BEST_ACCESS | MAPI_DEFERRED_ERRORS,
  1357.                                     &ulType, (LPUNKNOWN FAR *)&pfld);
  1358.         if(GetScode(hr) != S_OK)    goto ret;
  1359.         Assert(ulType == MAPI_FOLDER);
  1360.         pibData->pfld = pfld;
  1361.         hr = HrGetOneProp((LPMAPIPROP)pfld, PR_DISPLAY_NAME, &pvalProp);
  1362.         if(!hr)
  1363.         {
  1364.             if(*pvalProp->Value.lpszA)
  1365.                 SetWindowText(hDlg, pvalProp->Value.lpszA);
  1366.             MAPIFreeBuffer(pvalProp);
  1367.             pvalProp = NULL;
  1368.         }
  1369.     }
  1370.     hr = pfld->lpVtbl->GetContentsTable(pfld, MAPI_DEFERRED_ERRORS, &ptable);
  1371.     if (hr)
  1372.         goto ret;
  1373.     if (hr = HrQueryAllRows(ptable, (LPSPropTagArray) &ptInbox, NULL,
  1374.         (LPSSortOrderSet) &sos, 0, &prows))
  1375.     {
  1376.         MakeMessageBox (hDlg, GetScode(hr), IDS_QUERYROWFAIL, NULL, MBS_ERROR);
  1377.         goto ret;
  1378.     }
  1379.     for (nIndex = 0; nIndex < prows->cRows; ++nIndex)
  1380.     {
  1381.         lpMsgNode = MakeMsgNode(prows->aRow + nIndex);
  1382.         if (lpMsgNode)
  1383.         {
  1384.             InsertMsgNode(lpMsgNode, &pibData->lpMsgIdList);
  1385.             ListBox_AddString(GetDlgItem(hDlg, IDC_MSG),(LONG) lpMsgNode);
  1386.         }
  1387.     }
  1388.     FreeProws(prows);
  1389.     
  1390. ret:
  1391.     UlRelease(ptable);
  1392. }
  1393. /*
  1394.  -  MakeMsgNode
  1395.  -
  1396.  *  Purpose:
  1397.  *      Allocate memory for a new MSGID node and initialize its
  1398.  *      data members to the values passed in.
  1399.  *      A separate allocation is used for each property which is pretty
  1400.  *      wastefull. This can be changed to a smarter allocation scheme.
  1401.  *
  1402.  *  Parameters:
  1403.  *      
  1404.  *  Return:
  1405.  *      lpMsgNode       - Pointer to new node
  1406.  */
  1407. LPMSGID
  1408. MakeMsgNode (LPSRow prow)
  1409. {
  1410.     LPMSGID lpMsgNode = NULL;
  1411.     if (!prow)
  1412.         goto err;
  1413.     if (MAPIAllocateBuffer (sizeof (MSGID), (LPVOID far *) & lpMsgNode))
  1414.         goto err;
  1415.     ZeroMemory(lpMsgNode, sizeof (MSGID));
  1416.     if(prow->lpProps[E_FLAGS].ulPropTag == PR_MESSAGE_FLAGS)
  1417.     {
  1418.         lpMsgNode->fHasAttach = !!(prow->lpProps[E_FLAGS].Value.l & MSGFLAG_HASATTACH);
  1419.         lpMsgNode->fUnRead = !(prow->lpProps[E_FLAGS].Value.l & MSGFLAG_READ);
  1420.     }
  1421.     if(prow->lpProps[E_EID].ulPropTag == PR_ENTRYID)
  1422.     {   
  1423.         if (MAPIAllocateMore(prow->lpProps[E_EID].Value.bin.cb, lpMsgNode,
  1424.                     (LPVOID FAR *)&lpMsgNode->lpEID))
  1425.             goto err;
  1426.         CopyMemory(lpMsgNode->lpEID, prow->lpProps[E_EID].Value.bin.lpb, prow->lpProps[E_EID].Value.bin.cb);
  1427.         lpMsgNode->cbEID = prow->lpProps[E_EID].Value.bin.cb;
  1428.     }
  1429.     if(prow->lpProps[E_SENDER_NAME].ulPropTag == PR_SENDER_NAME)
  1430.     {
  1431.         if (MAPIAllocateMore (lstrlen (prow->lpProps[E_SENDER_NAME].Value.LPSZ) + 1,
  1432.                     lpMsgNode, (LPVOID far *) & lpMsgNode->lpszFrom))
  1433.         goto err;
  1434.         lstrcpy (lpMsgNode->lpszFrom, prow->lpProps[E_SENDER_NAME].Value.LPSZ);
  1435.     }
  1436.         
  1437.     if(prow->lpProps[E_SUBJECT].ulPropTag == PR_SUBJECT)
  1438.     {
  1439.         if (MAPIAllocateMore (lstrlen (prow->lpProps[E_SUBJECT].Value.LPSZ) + 1, lpMsgNode,
  1440.                     (LPVOID far *) & lpMsgNode->lpszSubject))
  1441.             goto err;
  1442.         lstrcpy (lpMsgNode->lpszSubject, prow->lpProps[E_SUBJECT].Value.LPSZ);
  1443.     }
  1444.     
  1445.     if(prow->lpProps[E_MSG_DEL_TIME].ulPropTag == PR_MESSAGE_DELIVERY_TIME)
  1446.     {
  1447.         if (MAPIAllocateMore (32, lpMsgNode,(LPVOID far *) & lpMsgNode->lpszDateRec))
  1448.             goto err;
  1449.         FormatFILETIME (&prow->lpProps[E_MSG_DEL_TIME].Value.ft, lpMsgNode->lpszDateRec);
  1450.     }
  1451.     
  1452.     return lpMsgNode;
  1453. err:
  1454.     MAPIFreeBuffer (lpMsgNode);
  1455.     return NULL;
  1456. }
  1457. /*
  1458.  -  InsertMsgNode
  1459.  -
  1460.  *  Purpose:
  1461.  *      We insert the nodes
  1462.  *      at the beginning of the list.  This can be
  1463.  *      replaced with a routine that inserts sorted on
  1464.  *      different criteria, like DateReceived, From, or
  1465.  *      Subject.
  1466.  *
  1467.  *  Parameters:
  1468.  *      lpMsgNode       - Pointer to a MSGID node
  1469.  *      lppMsgHead      - Pointer to the head of the list
  1470.  *
  1471.  *  Return:
  1472.  *      Void.
  1473.  */
  1474. void
  1475. InsertMsgNode (LPMSGID lpMsgNode, LPMSGID * lppMsgHead)
  1476. {
  1477.     if (*lppMsgHead)
  1478.     {
  1479.         lpMsgNode->lpNext = *lppMsgHead;
  1480.         (*lppMsgHead)->lpPrev = lpMsgNode;
  1481.     }
  1482.     else
  1483.         lpMsgNode->lpNext = NULL;
  1484.     /* The next 2 assignments are here in case the node came from somewhere */
  1485.     /* other than a call to MakeMsgNode () in which case we aren't sure */
  1486.     /* they're already NULL. */
  1487.     lpMsgNode->lpPrev = NULL;
  1488.     *lppMsgHead = lpMsgNode;
  1489. }
  1490. /*
  1491.  -  DeleteMsgNode
  1492.  -
  1493.  *  Purpose:
  1494.  *      Removes the node passed in from the list.  This
  1495.  *      may seem like a strange way to do this but it's
  1496.  *      not, because the Owner-Drawn List Box gives us
  1497.  *      direct access to elements in the list that makes
  1498.  *      it easier to do things this way.
  1499.  *
  1500.  *  Parameters:
  1501.  *      lpMsgNode       - Pointer to the MSGID node to delete
  1502.  *      lppMsgHead      - Pointer to the head of the list
  1503.  *
  1504.  *  Return:
  1505.  *      Void.
  1506.  */
  1507. void
  1508. DeleteMsgNode (LPMSGID lpMsgNode, LPMSGID * lppMsgHead)
  1509. {
  1510.     if (!lpMsgNode)
  1511.         return;
  1512.     if (lpMsgNode->lpPrev)
  1513.     {
  1514.         /* Adjust Previous node to point to Next*/
  1515.         Assert(*lppMsgHead != lpMsgNode);
  1516.         lpMsgNode->lpPrev->lpNext = lpMsgNode->lpNext;
  1517.     }
  1518.     else
  1519.     {
  1520.         /*/ Adjust Head to point to Next*/
  1521.         Assert(*lppMsgHead == lpMsgNode);
  1522.         *lppMsgHead = lpMsgNode->lpNext;
  1523.     }
  1524.     /* Adjust next node to point to Previous*/
  1525.     if (lpMsgNode->lpNext)
  1526.         lpMsgNode->lpNext->lpPrev = lpMsgNode->lpPrev;
  1527.     MAPIFreeBuffer (lpMsgNode);
  1528.     return;
  1529. }
  1530. /*
  1531.  -  FindNode
  1532.  -
  1533.  *  Purpose:
  1534.  *      Returns a pointer to the node with EntryID equal to *pEntryID.
  1535.  *      Returns NULL if node doesn't exist.
  1536.  *
  1537.  *  Parameters:
  1538.  *      lpMsgHead       - Pointer to the head of the list
  1539.  *      pEntryID + cbEntryID    - Message ID to search for
  1540.  *
  1541.  *  Return:
  1542.  *      lpMsgNode       - Pointer to the node returned
  1543.  */
  1544. LPMSGID
  1545. FindNode (LPMSGID lpMsgHead, LPENTRYID pEntryID, ULONG cbEntryID)
  1546. {
  1547.     ULONG fl;
  1548.     HRESULT hr;
  1549.     Assert(pmdb);
  1550.     while (lpMsgHead)
  1551.     {
  1552.         hr = pmdb->lpVtbl->CompareEntryIDs(pmdb, cbEntryID, pEntryID, lpMsgHead->cbEID, lpMsgHead->lpEID,
  1553.                                             0, &fl);
  1554.         if(S_OK != GetScode(hr))
  1555.             return NULL;
  1556.         if(fl)
  1557.             break;
  1558.         lpMsgHead = lpMsgHead->lpNext;
  1559.     }
  1560.     return lpMsgHead;
  1561. }
  1562. /*
  1563.  -  FreeMsgList
  1564.  -
  1565.  *  Purpose:
  1566.  *      Walks down the MsgList and frees each node.
  1567.  *
  1568.  *  Parameters:
  1569.  *      lpMsgHead       - Pointer to the head of the list
  1570.  *
  1571.  *  Return:
  1572.  *      Void.
  1573.  */
  1574. void
  1575. FreeMsgList (LPMSGID lpMsgHead)
  1576. {
  1577.     LPMSGID lpT;
  1578.     while (lpMsgHead)
  1579.     {
  1580.         lpT = lpMsgHead;
  1581.         lpMsgHead = lpMsgHead->lpNext;
  1582.         MAPIFreeBuffer (lpT);
  1583.     }
  1584. }
  1585. /*
  1586.  -  ToggleMenuState
  1587.  -
  1588.  *  Purpose:
  1589.  *      Enables/Disables menu items depending on the session state.
  1590.  *
  1591.  *  Parameters:
  1592.  *      hWnd            - handle to the window/dialog who called us
  1593.  *      fLoggedOn       - TRUE if logged on, FALSE if logged off
  1594.  *
  1595.  *  Return:
  1596.  *      Void.
  1597.  */
  1598. void ToggleMenuState(HWND hWnd, BOOL fLoggedOn)
  1599. {
  1600.     EnableMenuItem (GetMenu (hWnd), IDM_HIER,     !fLoggedOn);
  1601.     EnableMenuItem (GetMenu (hWnd), IDM_OPEN,     !fLoggedOn);
  1602.     EnableMenuItem (GetMenu (hWnd), IDM_LOGOFF,   !fLoggedOn);
  1603.     EnableMenuItem (GetMenu (hWnd), IDM_ROUTE,    !fLoggedOn);
  1604.     EnableMenuItem (GetMenu (hWnd), IDM_READ,     !fLoggedOn);
  1605.     EnableMenuItem (GetMenu (hWnd), IDM_SEND,     !fLoggedOn);
  1606.     EnableMenuItem (GetMenu (hWnd), IDM_NEWFORM,  !fLoggedOn);
  1607.     EnableMenuItem (GetMenu (hWnd), IDM_LOGON,    fLoggedOn);
  1608.     EnableMenuItem (GetMenu (hWnd), IDM_EXIT,       FALSE);
  1609. }
  1610. //
  1611. //  SecureMenu
  1612. //
  1613. //  Purpose:
  1614. //      Enables/Disables Logon and Exit menu items.
  1615. //      CMCLogon might yield control to Windows, so the user might be able to
  1616. //      access the window menu (for example click Logon) after we call
  1617. //      MAPILogon, but before it returns.
  1618. //
  1619. //  Parameters:
  1620. //      hWnd            - handle to the window/dialog who called us
  1621. //      fBeforeLogon    - TRUE when this function is called when we are about
  1622. //                      to call MAPILogon, FALSE if called after logon (failed)
  1623. //                      if Logon succeddes ToggleMenuState is called instead of
  1624. //                      this function.
  1625. //
  1626. //  Return:
  1627. //      Void.
  1628. //
  1629. void SecureMenu(HWND hWnd, BOOL fBeforeLogon)
  1630. {
  1631.     EnableMenuItem (GetMenu (hWnd), IDM_LOGON, fBeforeLogon);
  1632.     EnableMenuItem (GetMenu (hWnd), IDM_EXIT,  fBeforeLogon);
  1633. }
  1634. /*
  1635.  *  Formats a Win32 file time as a MAPI date/time string.
  1636.  *  NOTE: converts from GMT to local time.
  1637.  */
  1638. void FormatFILETIME(FILETIME *pft, LPSTR szTime)
  1639. {
  1640.     FILETIME        ft;
  1641.     SYSTEMTIME      systime;
  1642.     FileTimeToLocalFileTime(pft, &ft);
  1643.     FileTimeToSystemTime(&ft, &systime);
  1644.     wsprintf(szTime,
  1645.         "%04.4d/%02.2d/%02.2d %02.2d:%02.2d",
  1646.         systime.wYear, systime.wMonth, systime.wDay,
  1647.         systime.wHour, systime.wMinute);
  1648. }
  1649. /*
  1650.  *  Create a data block used in CommonDlgProc to remember
  1651.  *  the entire chain of rows in the scrolling list box.
  1652.  */
  1653. LPDIALOGDATA
  1654. CreateDialogData (int iDlgType)
  1655. {
  1656.     LPDIALOGDATA pDialogData;
  1657.     SCODE sc;
  1658.     sc = MAPIAllocateBuffer(sizeof(DIALOGDATA), &pDialogData);
  1659.     if (sc)
  1660.     {
  1661.         MakeMessageBox (0, MAPI_E_NOT_ENOUGH_MEMORY, IDS_OPERATION, NULL, MBS_ERROR);
  1662.         return NULL;
  1663.     }
  1664.     pDialogData->iDlgType = iDlgType;
  1665.     pDialogData->poarHead = NULL;
  1666.     pDialogData->cbEntryID = 0;
  1667.     pDialogData->lpEntryID = NULL;
  1668.     return pDialogData;
  1669. }