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

  • Corporate e-Learning technology has a long and diverse pedigree. As far back as the 1980s, companies were adopting computer-based training to supplement traditional classroom activities. More recently, rich web-based applications have added streaming audio and video, real-time collaboration and other new tools to the e-Learning mix. At the same time, the growing availability of informal learning tools--a category that includes everything from web searches to social media posts--are having a major impact on …

  • Live Event Date: August 20, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT When you look at natural user interfaces as a developer, it isn't just fun and games. There are some very serious, real-world usage models of how things can help make the world a better place – things like Intel® RealSense™ technology. Check out this upcoming eSeminar and join the panel of experts, both from inside and outside of Intel, as they discuss how natural user interfaces will likely be getting adopted in a wide variety …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds