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 / common / lasterr.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-11  |  11.3 KB  |  404 lines

  1. //
  2. //  LASTERR.CPP
  3. //
  4. // implementation file for CLastError which implements the
  5. // GetLastError helper
  6. //
  7. //  
  8. //
  9. // Copyright (C) 1995 Microsoft Corp.
  10. //
  11.  
  12. #define STRICT
  13.  
  14. #include <windows.h>
  15. #include <stdarg.h>
  16. #include <stdio.h>
  17. #include <tchar.h>
  18. #include <ctype.h>
  19. #include <mapix.h>
  20. #include <mapidbg.h>
  21. #include "lasterr.h"
  22.  
  23. const int       CchMaxErrorMessage = 256;
  24.  
  25. extern const CHAR FAR  SzNull[] = "";
  26. char szErrUnknown[] = "Error description is not available";
  27.  
  28. //
  29. // some stuff to put a "Help" button on the error msgbox
  30. //
  31. #if defined(_WIN32)
  32. char szHelpFile[_MAX_PATH];
  33. VOID CALLBACK ErrorBoxCallBack(LPHELPINFO lpHelpInfo);
  34. #endif //_WIN32
  35.  
  36. static LPSTR aszErrorStrings[] = 
  37. {
  38.     "Not enough memory",
  39.     "Invalid arguments",
  40.     "Invalid object",
  41.     "Interface not supported",
  42.     "Access denied",
  43.     "No support",
  44.     "Wrong character set",
  45.     "Item not found",
  46.     "Call failed",
  47.     "User cancel",
  48.     "Errors returned",
  49.     "Invalid flags",
  50.     "Unexpected error",
  51.     "Can't perform the required action at this time"
  52. };
  53.  
  54. enum 
  55. {
  56.     IDS_E_OUTOFMEMORY,
  57.     IDS_INVALID_ARGUMENT,
  58.     IDS_INVALID_OBJECT,
  59.     IDS_INTERFACE_NOT_SUPPORTED,
  60.     IDS_ACCESS_DENIED,
  61.     IDS_NOT_SUPPORTED,
  62.     IDS_INVALID_CHARWIDTH,
  63.     IDS_NOT_FOUND,
  64.     IDS_CALL_FAILED,
  65.     IDS_USER_CANCEL,
  66.     IDS_ERRORS_RETURNED,
  67.     IDS_UNKNOWN_FLAGS,
  68.     IDS_UNEXPECTED,
  69.     IDS_CANTNOW
  70. };  
  71.  
  72. static int iFromHR(HRESULT hr)
  73. {
  74.     switch(GetScode(hr)) {
  75.     case MAPI_E_NOT_ENOUGH_MEMORY:      return IDS_E_OUTOFMEMORY;
  76.     case MAPI_E_INVALID_PARAMETER:      return IDS_INVALID_ARGUMENT;
  77.     case MAPI_E_INVALID_OBJECT:         return IDS_INVALID_OBJECT;
  78.     case MAPI_E_INTERFACE_NOT_SUPPORTED: return IDS_INTERFACE_NOT_SUPPORTED;
  79.     case MAPI_E_NO_ACCESS:              return IDS_ACCESS_DENIED;
  80.     case MAPI_E_NO_SUPPORT:             return IDS_NOT_SUPPORTED;
  81.     case MAPI_E_BAD_CHARWIDTH:          return IDS_INVALID_CHARWIDTH;
  82.     case MAPI_E_NOT_FOUND:              return IDS_NOT_FOUND;
  83.     case MAPI_E_CALL_FAILED:            return IDS_CALL_FAILED;
  84.     case MAPI_E_USER_CANCEL:            return IDS_USER_CANCEL;
  85.     case MAPI_W_ERRORS_RETURNED:        return IDS_ERRORS_RETURNED;
  86.     case MAPI_E_UNKNOWN_FLAGS:          return IDS_UNKNOWN_FLAGS;
  87.     case E_UNEXPECTED:                  return IDS_UNEXPECTED;
  88.     case OLEOBJ_S_CANNOT_DOVERB_NOW:    return IDS_CANTNOW;
  89.     // if it's not in this list you need to add it.
  90.     default:
  91.         DebugTrace("lasterr: bad arg to FORMScodeFromHR");
  92.         Assert(FALSE);
  93.         return 0;
  94.     }
  95. }
  96.  
  97. HRESULT CLastError::HrSetLastError(HRESULT hr)
  98. {
  99. #if defined(DEBUG)
  100.     //
  101.     //  Ensure that the error string exists -- when we set it not when
  102.     //  they ask for it.
  103.     //
  104.  
  105.     (void) iFromHR(hr);
  106. #endif
  107.  
  108.     //
  109.     //  Release any previous error
  110.     //
  111.  
  112.     if (m_pmapierr != NULL) {
  113.         MAPIFreeBuffer(m_pmapierr);
  114.         m_pmapierr = NULL;
  115.     }
  116.  
  117.     if (hr) {
  118.         m_eLastErr = eMAPI;
  119.     }
  120.     else {
  121.         m_eLastErr = eNoError;
  122.     }
  123.  
  124.     return (m_hrLast = hr);
  125. }
  126.  
  127. HRESULT CLastError::HrSetLastError(HRESULT hr, IUnknown* punk)
  128. {
  129.     Assert(punk && hr);     // we have to have an object and an error.
  130.  
  131.     m_eLastErr = eObject;
  132.     m_hrLast = hr;
  133.  
  134.     IMAPIProp* pmprp = (IMAPIProp*)punk;  // I hate this cast but c'est la vie.
  135.  
  136.     MAPIFreeBuffer(m_pmapierr);     // clean up previous error.
  137.     m_pmapierr = NULL;
  138.  
  139.     m_hrGLE = pmprp->GetLastError(hr, 0, &m_pmapierr);
  140.     if (m_hrGLE == S_OK) {
  141.         if (m_pmapierr == NULL) {
  142.             if (MAPIAllocateBuffer(sizeof(MAPIERROR), (void **) &m_pmapierr)) {
  143.                 m_hrGLE = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  144.             }
  145.             else {
  146.                 memset(m_pmapierr, 0, sizeof(MAPIERROR));
  147.                 m_pmapierr->ulVersion = MAPI_ERROR_VERSION;
  148.                 m_pmapierr->lpszError = szErrUnknown;
  149.                 m_pmapierr->lpszComponent = (char *) SzNull;
  150.             }
  151.         }
  152.         else if (m_pmapierr->lpszError == NULL) {
  153.             m_pmapierr->lpszError = (char *) SzNull;
  154.         }
  155.         else if (m_pmapierr->lpszComponent == NULL) {
  156.             m_pmapierr->lpszComponent = (char *) SzNull;
  157.         }
  158.     }
  159.     else {
  160.         if (m_pmapierr != NULL) {
  161.             MAPIFreeBuffer(m_pmapierr);
  162.             m_pmapierr = NULL;
  163.         }
  164.     }
  165.     return m_hrLast;
  166. }
  167.  
  168. HRESULT CLastError::HrGetLastError(HRESULT hr, DWORD dwFlags,
  169.                                    LPMAPIERROR FAR * lppMAPIError)
  170. {
  171.     //
  172.     //  Start with parameter validation
  173.     //
  174.  
  175.     if (IsBadWritePtr(lppMAPIError, sizeof(LPMAPIERROR))) {
  176.         return HrSetLastError(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  177.     }
  178.  
  179.     if (MAPI_UNICODE == (dwFlags & MAPI_UNICODE)) {
  180.         return HrSetLastError(ResultFromScode(MAPI_E_BAD_CHARWIDTH));
  181.     }
  182.  
  183.     //
  184.     //  Is the error asked for the last error registered with us?
  185.     //
  186.  
  187.     if (hr != m_hrLast) {
  188.         *lppMAPIError = NULL;
  189.         return S_OK;
  190.     }
  191.  
  192.     int         cch;
  193.     int         cb;
  194.     int         idsError;
  195.     TCHAR*      szMessage = 0;
  196.     TCHAR*      szComponent = 0;
  197.     LPMAPIERROR pmapierr = NULL;
  198.  
  199.     //
  200.     //  Based on the type of the last error, construct the appropriate
  201.     //  return object
  202.     //
  203.  
  204.     switch (m_eLastErr) {
  205.     case eMAPI:
  206.         //
  207.         //  The last error registered was a MAPI error code.  For mapi
  208.         //      error codes we map the MAPI error code into a resource
  209.         //      id and return the appropriate string.
  210.         //
  211.         // as to spec, we allocate a single buffer for message and
  212.         //      component.  no one will notice that we aren't doing
  213.         //      MAPIAllocateMore for component.
  214.         //
  215.         //   We make an assumption as to the maximum possible length
  216.         //      of the two strings combined.
  217.         //
  218.  
  219.         Assert(m_pmapierr == NULL);
  220.         if (MAPIAllocateBuffer(CchMaxErrorMessage*sizeof(TCHAR)+sizeof(MAPIERROR),
  221.                                (void**)&pmapierr)) {
  222.             return ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  223.         }
  224.  
  225.         //
  226.         //  Set the version number
  227.         //
  228.  
  229.         pmapierr->ulVersion = MAPI_ERROR_VERSION;
  230.         pmapierr->ulLowLevelError = 0;
  231.  
  232.         //
  233.         //   do the maping from the MAPI error code into a FORM string
  234.         //      value.  The FORM eror code code will be set as the low
  235.         //      level error value.
  236.         //
  237.  
  238.         idsError = iFromHR(m_hrLast);
  239.         pmapierr->ulContext = idsError;
  240.  
  241.         //
  242.         //  Set the error string pointer to the appropriate location
  243.         //      in the error buffer and load the error string.
  244.         //
  245.  
  246.         pmapierr->lpszError = (LPTSTR) (sizeof(MAPIERROR) +
  247.                                           (BYTE *) pmapierr);
  248.  
  249.         lstrcpy(pmapierr->lpszError, aszErrorStrings[idsError]);
  250.         cch = lstrlen(aszErrorStrings[idsError]);
  251.         
  252.         
  253.         //
  254.         // Set the componment string pointer to the appropriate location
  255.         //      in the error buffer and load the component string.
  256.         //
  257.  
  258.         pmapierr->lpszComponent = pmapierr->lpszError + cch + 1;
  259.         cch = CchMaxErrorMessage - cch - 1;
  260.  
  261.         lstrcpy(pmapierr->lpszComponent,
  262.                         m_szComponent ? m_szComponent : SzNull);
  263.         cch = lstrlen(pmapierr->lpszComponent);
  264.         
  265.         if (cch == 0) {
  266.             *(pmapierr->lpszComponent) = 0;
  267.         }
  268.  
  269.         break;
  270.  
  271.  
  272.     case eObject:
  273.         //
  274.         //  The last regisered error message came from an object.  If we
  275.         //      could not get the last error from the object, just return
  276.         //      the error it returned and we are done.
  277.         //
  278.  
  279.         if (m_hrGLE != NOERROR) {
  280.             Assert( m_pmapierr == NULL );
  281.             *lppMAPIError = NULL;
  282.             return m_hrGLE;
  283.         }
  284.  
  285.     case eExtended:
  286.         //
  287.         //  The last error was an extended error.  The error is in the
  288.         //      structure, we need to copy this structure and return
  289.         //      it back to the user
  290.         //
  291.  
  292.         Assert( m_pmapierr != NULL );
  293.         cb = lstrlen(m_pmapierr->lpszError) + lstrlen(m_pmapierr->lpszComponent);
  294.  
  295.         if (MAPIAllocateBuffer(cb + 2 + sizeof(MAPIERROR),
  296.                                (void **) &pmapierr)) {
  297.             return ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  298.         }
  299.  
  300.         *pmapierr = *m_pmapierr;
  301.         pmapierr->lpszError = (LPTSTR) (sizeof(MAPIERROR) + (BYTE *) pmapierr);
  302.         lstrcpy(pmapierr->lpszError, m_pmapierr->lpszError);
  303.         pmapierr->lpszComponent = pmapierr->lpszError +
  304.           lstrlen(pmapierr->lpszError) + 1;
  305.         lstrcpy(pmapierr->lpszComponent, m_pmapierr->lpszComponent);
  306.  
  307.         break;
  308.  
  309.     case eNoError:
  310.         break;
  311.  
  312.     default:
  313.         Assert(0);
  314.         return NOERROR;
  315.     }
  316.  
  317.     *lppMAPIError = pmapierr;
  318.     return ResultFromScode(S_OK);
  319. }
  320.  
  321.  
  322.  
  323. int CLastError::ShowError(HWND hWnd)
  324. {
  325.     char szMessage[512];
  326.     char szbuf[256];
  327.  
  328.     if(m_eLastErr != eObject || NULL == m_pmapierr) return 0;
  329.  
  330.     wsprintf(szMessage, "%s\n%s\nLowLevelError: 0x%08lx context: %ld ",
  331.                         (m_pmapierr->lpszError ? m_pmapierr->lpszError:""),
  332.                         m_pmapierr->lpszComponent ? m_pmapierr->lpszComponent:"",
  333.                         m_pmapierr->ulLowLevelError, m_pmapierr->ulContext);
  334.    
  335.     wsprintf (szbuf, "\nReturn Code: 0x%08lx", SCODE(m_hrLast));
  336.     lstrcat (szMessage, szbuf);
  337.     
  338. #if defined (_WIN32)
  339.     *szHelpFile = '\0';
  340.  
  341.     int iret;
  342.     BOOL fCanHelp;
  343.  
  344.     if(m_pmapierr->lpszError  &&  m_pmapierr->ulContext)
  345.         fCanHelp = TRUE;
  346.     else
  347.         fCanHelp = FALSE;
  348.         
  349.     if(fCanHelp)
  350.     {
  351.         DWORD dw = GetPrivateProfileString("Help File Mappings", m_pmapierr->lpszComponent,
  352.                             "", szHelpFile, _MAX_PATH, "mapisvc.inf");
  353.         if(0 == dw)
  354.             fCanHelp = FALSE;
  355.  
  356.         if(fCanHelp)
  357.         {
  358.             MSGBOXPARAMS mbp = {0};
  359.  
  360.             mbp.cbSize = sizeof(MSGBOXPARAMS);
  361.             mbp.hwndOwner = hWnd;
  362.             mbp.hInstance = NULL;
  363.             mbp.lpszText = szMessage;
  364.             mbp.lpszCaption = m_szComponent ? m_szComponent : "Error!";
  365.             mbp.dwStyle = MB_ICONSTOP | MB_OK | MB_HELP;
  366.             mbp.lpszIcon = NULL;
  367.             mbp.dwContextHelpId = m_pmapierr->ulContext;
  368.             mbp.lpfnMsgBoxCallback = ErrorBoxCallBack;
  369.             mbp.dwLanguageId = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
  370.  
  371.             iret = MessageBoxIndirect(&mbp);
  372.         }
  373.         
  374.     }
  375.  
  376.     
  377.     if(!fCanHelp)
  378.         iret = MessageBox (hWnd, szMessage,
  379.                     m_szComponent ? m_szComponent : "Error!",
  380.                         MB_ICONSTOP | MB_OK );
  381.  
  382.     *szHelpFile = '\0';
  383.  
  384.     return iret;
  385.  
  386. #else
  387.     return MessageBox (hWnd, szMessage,
  388.                      m_szComponent ? m_szComponent : "Error!",
  389.                          MB_ICONSTOP | MB_OK );
  390. #endif
  391. }
  392.  
  393. #if defined(_WIN32)
  394. VOID CALLBACK ErrorBoxCallBack(LPHELPINFO lpHelpInfo)
  395. {
  396.     Assert(*szHelpFile != '\0');
  397.  
  398.     WinHelp(NULL, szHelpFile, HELP_CONTEXT,
  399.             lpHelpInfo->dwContextId);
  400. }
  401. #endif //_WIN32
  402.  
  403.  
  404.