home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / dbmsg / mapi / route.cli / client.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-11  |  51.9 KB  |  1,943 lines

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