Using a Simple MAPI in API that Runs as a Windows NT Service

Environment: Internet and Networking, E-Mail

Introduction

As you should know, a Win NT service is an application that does not have a user interface and can run (if configured) automatically every time the workstation/server boots. This is an advantage for some applications that need to be executed without user intervention (the user is not required to log in and execute an application) and they're running permanently in an infinite cycle, waiting for an event to do one or more tasks.

An example of this is the application that I'm developing. In general, its main goals are:

  1. Send via e-mail some documents every time they are modified, to their destination registered on a MSSQL database.
  2. Reply to request of those documents made by clients anywhere.

Enumerating the Problems

The first problem (and the objective of this article) was how to make an application run as a service. I found the article http://msdn.microsoft.com/library/default.asp?url=/library/en-us/mapi/html/_mapi1book_windows_nt_service_client_applications.asp in MSDN that explains it. I would like to take your attention to the following rules so the service can work:

  1. The e-mail account must be configured. This means that you have to log on to Win NT and configure the e-mail on Control Panel + Mail.
  2. The Service has to run with the user-configured mail account, as explained in Point 1. To do this, go to Control Panel + Service + <double-click on the service you want to change> and change the Log On As from System Account to This Account: and input the user name, password, and then confirm the password.
  3. The user has to be a member of the \Administrators group on the machine where the service is running. Check the MSDN article for more information.

The second problem was how to read and send e-mail. To do this, I found a class in the article http://codeguru.earthweb.com/internet/imapi.shtml and added some more functionality to read mail to it (great class).

The Solution

The main function to run the service application is the logon using the Mail profile configured in Point 1:

// Global application objects
CIMapi  gMail;
CHAR    gcMailProfileName[MAX_PATH];

HRESULT EfaLogOnMail ()
{
  HRESULT              hRes = S_OK;
  BOOL                 bRes = TRUE;
  MAPIINIT_0           MapiInitParams;
  LPMAPISESSION FAR    lppSession;
  char                 cMsg[1024];

  //******* Get the profile name from the "Mail.ini" file ******//
  bRes = EfaGetConfigOption (INI_FILE, "[Inicializacao]",
                             PROFILE_NAME, gcMailProfileName);
  if (bRes != TRUE)
  {
    sprintf (cMsg, "Não foi possmvel obter o nome do perfil do
             mail\n", hRes);
    EfaWriteLog (LOG_FILE, cMsg);
    return (S_FALSE);
  }

//*************** Initializes MAPI *****************************//
  MapiInitParams.ulFlags        = MAPI_NT_SERVICE;
  MapiInitParams.ulVersion      = MAPI_INIT_VERSION;
  hRes = MAPIInitialize ((LPVOID)&MapiInitParams);
  if (hRes != S_OK)
  {
    sprintf (cMsg, "MAPIInitialize falhou com erro = %i\n",
             hRes);
    EfaWriteLog (LOG_FILE, cMsg);
    return (hRes);
  }

  hRes = OleInitialize (NULL);
  if (hRes != S_OK)
  {
    sprintf (cMsg, "OleInitialize falhou com erro = %i\n", hRes);
    EfaWriteLog (LOG_FILE, cMsg);
    return (hRes);
  }

  //******* Executes the Log On *******//
  hRes = MAPILogonEx (0, gcMailProfileName, NULL,
                         MAPI_NT_SERVICE +
                         MAPI_NO_MAIL,
                         &lppSession);
  if (hRes != S_OK)
  {
    sprintf (cMsg, "MAPILogonEx falhou com erro = %i\n", hRes);
    EfaWriteLog (LOG_FILE, cMsg);
    return (hRes);
  }

  // Executes Log On again to initialize the session handle on the
  // CIMAPI class
  bRes = gMail.Logon (gcMailProfileName, NULL);
  if (bRes == FALSE)
  {
    sprintf (cMsg, "CIMapi::Logon falhou com erro = %i\n",
             gMail.Error
()); 
    EfaWriteLog (LOG_FILE, cMsg);
    return ((HRESULT)gMail.Error ());
  }

  // Test to send e-mail
  // EfaTestSendMail ();

  // Test to read e-mails
  // EfaTestGetMail ();

  return (bRes);
}

Notes

  1. To be honest, I don't know if it is possible to debug a service (maybe debugging attaching to a process), so to simply debug the application, just uncomment the lines below on the code and between EfaLogOnMail and EfaLogOffMail add your code to be executed. These lines are just before the code needed for the service definition.
  2.       // COMMENT THE FOLLOWING LINES TO RUN AS A WINNT
          // SERVICE //
          EfaLogOnMail ();
          EfaLogOffMail ();
          return (0);
          // COMMENT THE FOLLOWING LINES TO RUN AS A WINNT
          // SERVICE //
    
  3. Don't forget to edit "Mail.ini" and change the option ProfileName = <your profile name>.
  4. To install the service, just run the application in command prompt with the following arguments:
  5.     To Install   -> Mail.exe -i <Path to executable>
        To Uninstall -> Mail.exe -u
        To display this message -> Mail.exe -h
    
  6. I'm sorry for the log and commented messages. I didn't have time to translate all of them.

I hope this can be helpful.

Downloads

Download source - 123 Kb


Comments

  • Debugging a service

    Posted by Legacy on 06/26/2003 12:00am

    Originally posted by: Petko Popov

    Try putting a DebugBreak() command in the DEBUG build of the service. When the breakpoint is reached, click on the Cancel button of the message to debug the code; the debugger will attach to the service

    Reply
  • Debugging services as they startup

    Posted by Legacy on 09/26/2002 12:00am

    Originally posted by: John P

    I just came across some words in "Inside Windows 2000" (Solomon, Russinovich) that may help those that want to debug services as they startup, rather than after they have already started.

    In the Registry under HLKM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options, you can add keys that alter the functionality of CreateProcess and allow you to override the execution of a specific image file and in its place have a debugger run.

    There is an example key in the Registry called "Your Image File Name Here..." that shows you the basic format for entering the required information.

    With this functionality you can have services debugged as they startup as opposed to after they have already started. Or you can use this to play evil tricks on your friends' computers while they are not looking =) Your choice.

    For more information on this topic see "Inside Windows 2000" in Chapter 6 "Processes, Threads, and Jobs" on page 309.

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • When it comes to desktops – physical or virtual – it's all about the applications. Cloud-hosted virtual desktops are growing fast because you get local data center-class security and 24x7 access with the complete personalization and flexibility of your own desktop. Organizations make five common mistakes when it comes to planning and implementing their application management strategy. This eBook tells you what they are and how to avoid them, and offers real-life case studies on customers who didn't let …

  • Live Event Date: May 6, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT While you likely have very good reasons for remaining on WinXP after end of support -- an estimated 20-30% of worldwide devices still are -- the bottom line is your security risk is now significant. In the absence of security patches, attackers will certainly turn their attention to this new opportunity. Join Lumension Vice President Paul Zimski in this one-hour webcast to discuss risk and, more importantly, 5 pragmatic risk mitigation techniques …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds