XPSRVCE.CPP

/////////////////////////////////////////////////////////////////////////////// 
//
// File Name
// XPSRVCE.CPP
//
// Description
// This file implements the entry points, XPProviderInit and
// ServiceEntry for this provider's DLL.
//
// Author
// Irving De la Cruz
//
// Revision: 1.7
//
// Written for Microsoft Windows Developer Support
// Copyright (c) 1995-1996 Microsoft Corporation. All rights reserved.
//
#include "XPWDSR.H"

// Remark this line to turn verbose tracing OFF
#define DO_INFO_TRACES
#ifdef DO_INFO_TRACES
#define InfoTrace(a) TraceInfoMessage(a)
#else
#define InfoTrace(a)
#endif // DO_INFO_TRACES

DTBLEDIT DtUploadTime = { sizeof(DTBLEDIT), fMapiUnicode, 5, PR_TMP_UPLOAD_TIME };
DTBLCHECKBOX DtGetHeaders = { sizeof(DTBLCHECKBOX), fMapiUnicode, PR_SMP_GET_HEADERS };

DTCTL XPConfigPage[] =
{
{ DTCT_PAGE, 0, NULL, 0, NULL, 0, &DtPage },
{ DTCT_EDIT, DT_REQUIRED, NULL, 0, szFilter, IDC_UPLOAD_TIME, &DtUploadTime },
{ DTCT_CHECKBOX, 0, NULL, 0, NULL, IDC_UPDATE_HEADERS, &DtGetHeaders },
{ DTCT_LABEL, 0, NULL, 0, NULL, IDC_STATIC1, &DtLabel },
{ DTCT_GROUPBOX, 0, NULL, 0, NULL, IDC_STATIC2, &DtGroupBox },
{ DTCT_GROUPBOX, 0, NULL, 0, NULL, IDC_STATIC3, &DtGroupBox }
};

TCHAR szDefaultTime[] = TEXT("23:59");

// Global pointer to the MAPI memory allocation functions
LPALLOCATEBUFFER gpfnAllocateBuffer; // MAPIAllocateBuffer function
LPALLOCATEMORE gpfnAllocateMore; // MAPIAllocateMore function
LPFREEBUFFER gpfnFreeBuffer; // MAPIFreeBuffer function

///////////////////////////////////////////////////////////////////////////////
// ServiceEntry()
//
// Parameters
// { Refer to MAPI Documentation on this method }
//
// Purpose
// Called by the profile setup API to display the provider
// configuration properties for this transport provider
//
// Return Value
// An HRESULT
//
HRESULT STDAPICALLTYPE ServiceEntry (HINSTANCE hInstance,
LPMALLOC pMallocObj,
LPMAPISUP pSupObj,
ULONG ulUIParam,
ULONG ulFlags,
ULONG ulContext,
ULONG ulCfgPropCount,
LPSPropValue pCfgProps,
LPPROVIDERADMIN pAdminProvObj,
LPMAPIERROR * ppMAPIError)
{
// Look at TRACES.H and TRACES.CPP for more options to the InitTraces() function
//InitTraces (0); // Send output only to the COM1 port
InitTraces (TRACES_CONSOLE | TRACES_NO_COM_OUTPUT); // Send output to a console window BUT NOT to the COM1
//InitTraces (TRACES_CONSOLE | TRACES_LOG_FILE); // Send output to COM1 port AND a console window AND to a log file in C:\MAPILOG.TXT

InfoTrace ("ServiceEntry function called");
HRESULT hResult = S_OK;
LPPROFSECT pProfileObj = NULL;
ULONG ulPropCount;
LPSPropValue pProps = NULL;
HANDLE hUIMutex = NULL;

// What context where were we called in?
if (MSG_SERVICE_INSTALL == ulContext ||
MSG_SERVICE_UNINSTALL == ulContext ||
MSG_SERVICE_PROVIDER_CREATE == ulContext ||
MSG_SERVICE_PROVIDER_DELETE == ulContext)
{
// We don't handle any of these contexts
TraceString1 ("ServiceEntry: Immediate return. Context: %d", ulContext);
goto ErrorExit;
}
TraceString1 ("ServiceEntry: Context for call: %d", ulContext);
ghInstance = hInstance;

// Get the MAPI memory allocation routines we'll be needing
hResult = pSupObj->GetMemAllocRoutines (&gpfnAllocateBuffer, &gpfnAllocateMore, &gpfnFreeBuffer);
if (hResult)
{
TraceResult ("ServiceEntry: Failed to get the memory allocation functions", hResult);
goto ErrorExit;
}

// Open the Profile Section for this service
hResult = pAdminProvObj->OpenProfileSection (NULL,
NULL,
MAPI_MODIFY,
&pProfileObj);
if (hResult)
{
goto ErrorExit;
}
if (MSG_SERVICE_CREATE == ulContext)
{
// If ServiceEntry is called because it the service is being created, we create a temporary
// file where we save the headers text file when the user updates them from
// the remote host. The headers should be persistent from session to
// session (using the same profile, of course) but unique per session.
TCHAR szTmpDir[_MAX_PATH], szFile[_MAX_PATH];
GetTempPath (_MAX_PATH, szTmpDir);
lstrcat (szTmpDir, WINDS_DATA_DIRECTORY);
CreateDirectory (szTmpDir, NULL);
GetTempFileName (szTmpDir, // Create the file in the system temp directory
TEXT("XRH"), // Our transport fixed prefix for temp files
0, // Use the time to create a pseudo-random number
szFile); // Destination buffer
SPropValue spvProps[4] = { 0 };
spvProps[0].ulPropTag = PR_SMP_HEADERS_FILENAME;
spvProps[0].Value.LPSZ = szFile;
SYSTEMTIME st;
GetLocalTime (&st);
st.wHour = 23; st.wMinute = 59; st.wSecond = 0;
spvProps[1].ulPropTag = PR_SMP_UPLOAD_TIME;
SystemTimeToFileTime (&st, &spvProps[1].Value.ft);
spvProps[2].ulPropTag = PR_SMP_CONNECTION_TYPE;
spvProps[2].Value.l = OFFLINE_CONNECT;
spvProps[3].ulPropTag = PR_SMP_GET_HEADERS;
spvProps[3].Value.b = TRUE;
hResult = pProfileObj->SetProps (sizeof(spvProps)/sizeof(SPropValue), spvProps, NULL);
TraceResult ("ServiceEntry: Failed to save the headers file name back into the profile", hResult);
}
// The profile section is open, get the properties out of it
hResult = pProfileObj->GetProps ((LPSPropTagArray)&sptLogonProps,
fMapiUnicode,
&ulPropCount,
&pProps);
if (FAILED(hResult))
{
TraceResult ("ServiceEntry: Failed to get profile section properties", hResult);
goto ErrorExit;
}
ASSERT (NUM_LOGON_PROPERTIES == ulPropCount);

if (MSG_SERVICE_DELETE == ulContext)
{
// If the service is being removed from a profile, we must cleanup
// any temporary file (i.e. the headers text file)
if (PR_SMP_HEADERS_FILENAME == pProps[HEADER_FILE].ulPropTag)
{
DeleteFile (pProps[HEADER_FILE].Value.LPSZ);
}
TCHAR szTmpDir[_MAX_PATH], szDownloadDir[_MAX_PATH];
GetTempPath (_MAX_PATH, szTmpDir);
lstrcat (szTmpDir, WINDS_DATA_DIRECTORY);
if (PR_SMP_MAILBOX_NAME == pProps[MAILBOX_NAME].ulPropTag)
{
wsprintf (szDownloadDir, WINDS_DOWNLOAD_DIR_NAME_FORMAT, szTmpDir, pProps[MAILBOX_NAME].Value.LPSZ);
RemoveDirectory (szDownloadDir);
}
RemoveDirectory (szTmpDir);
// We are done
hResult = S_OK;
goto ErrorExit;
}
// After the setup wizard has been called the ServiceEntry functions gets called
// with a set of properties obtained from the user for configuring this provider.
// Merge or replace those properties onto the one we obtained from the profile section.
if (pCfgProps && ulCfgPropCount)
{
hResult = MergeConfigProps (ulCfgPropCount, pCfgProps, pProps);
if (hResult)
{
goto ErrorExit;
}
}
// If we can, display the UI...
if (SERVICE_UI_ALWAYS & ulFlags || SERVICE_UI_ALLOWED & ulFlags)
{
CFGDLG CfgDialog = { 0 };
hUIMutex = CreateMutex (NULL, FALSE, CONFIG_UI_MUTEX);
if (NULL == hUIMutex)
{
TraceResult ("ServiceEntry: Failed to create UI mutext", GetLastError());
}
PrivInitialize3DCtl (hInstance);
if (WAIT_TIMEOUT == WaitForSingleObject (hUIMutex, 250)) // Wait for the MUTEX for 1/4 second
{
PrivateMessageBox (IDS_MSG_CONFIG_UI_IN_USE, (HWND)ulUIParam);
hResult = MAPI_E_BUSY;
goto ErrorExit;
}

// Fill in the logon UI structure
CfgDialog.hInst = hInstance;
CfgDialog.hWnd = (HWND)ulUIParam;
CfgDialog.ppProps = &pProps;
CfgDialog.pSupObj = pSupObj;
CfgDialog.ulFlags = MSG_SERVICE_UI_READ_ONLY & ulFlags ? UI_READONLY : 0;
CfgDialog.hUIMutex = NULL; // So that the DoLogonDlg() won't have to wait.
ShowPropsAgain:
hResult = DoLogonDlg (&CfgDialog);
if (hResult)
{
goto ErrorExit;
}
if (!PingRemoteServer ((HWND)ulUIParam, pProps))
{
goto ShowPropsAgain;
}
}
if (PR_SMP_MAILBOX_NAME == pProps[MAILBOX_NAME].ulPropTag)
{
TCHAR szTmpDir[_MAX_PATH], szDownloadDir[_MAX_PATH];
GetTempPath (_MAX_PATH, szTmpDir);
lstrcat (szTmpDir, WINDS_DATA_DIRECTORY);
wsprintf (szDownloadDir, WINDS_DOWNLOAD_DIR_NAME_FORMAT, szTmpDir, pProps[MAILBOX_NAME].Value.LPSZ);
CreateDirectory (szDownloadDir, NULL);
}

hResult = pProfileObj->SetProps (NUM_LOGON_PROPERTIES, pProps, NULL);
TraceResult ("ServiceEntry: Failed to save the properties back into the profile", hResult);

ErrorExit:
// Clean up
if (pProfileObj)
{
pProfileObj->Release();
}
if (gpfnFreeBuffer)
{
gpfnFreeBuffer (pProps);
}
if (hUIMutex)
{
ReleaseMutex (hUIMutex);
CloseHandle (hUIMutex);
}
// In case the DLL was loaded, unload it.
// This DLL gets loaded and initialized in the call to DoLogonDlg()
PrivUninitialize3DCtl (hInstance);

// If we have remote connections going on, close them now
TerminateRemoteConnections();

// Close down the traces
UnInitTraces();
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// DoLogonDlg()
//
// Parameters
// pCfgDialog Pointer to an CFGDLG structure.
//
// Purpose
// This functions gets called to display the configuration properties for
// this transport. When invoked, it will parse the transport logon
// property array and initialize the fields in the property sheet with it.
// The function could also get invoked to display the settings in
// READ-ONLY mode in which case we disable writing to the editable fields.
//
// Return Value
// An HRESULT
//
HRESULT WINAPI DoLogonDlg (PCFGDLG pCfgDialog)
{
DWORD dwWait = WaitForSingleObject (pCfgDialog->hUIMutex, 1000); // Wait for the MUTEX for 1 second
PrivInitialize3DCtl (pCfgDialog->hInst);
if (WAIT_TIMEOUT == dwWait)
{
PrivateMessageBox (IDS_MSG_CONFIG_UI_IN_USE, pCfgDialog->hWnd);
return MAPI_E_BUSY;
}

LPMAPITABLE pTableObj= NULL;
ULONG ulPropCount;
SizedSPropTagArray(NUM_LOGON_PROPERTIES, sptCfgProps);
CopyMemory (&sptCfgProps, &sptLogonProps, sizeof(sptLogonProps));
sptCfgProps.aulPropTag[UPLOAD_TIME] = PR_TMP_UPLOAD_TIME;

// Take ownership of the property value array, so calling code
// will not leak memory
LPSPropValue pProps = *pCfgDialog->ppProps;
*pCfgDialog->ppProps = NULL;

// Retrieve the dialog title string
TCHAR szDialogTitle[64], szTimeString[32];
LoadString (pCfgDialog->hInst, IDS_SERVICE_PROPERTY_SHEETS_TITLE, szDialogTitle, 64);
CUIMAPIProp * pPropObj = NULL;
HRESULT hResult = S_OK;
try
{
pPropObj = new CUIMAPIProp (pCfgDialog->hInst,
gpfnAllocateBuffer,
gpfnAllocateMore,
gpfnFreeBuffer,
pCfgDialog->ulFlags & UI_READONLY);
if (!pPropObj)
{
hResult = E_OUTOFMEMORY;
}
}
catch (CException & Exception)
{
hResult = Exception.GetError();
}
if (hResult)
{
goto ErrorExit;
}

ASSERT (PR_SMP_UPLOAD_TIME == pProps[UPLOAD_TIME].ulPropTag);
GetTimeString (szTimeString, pProps[UPLOAD_TIME].Value.ft);
pProps[UPLOAD_TIME].ulPropTag = PR_TMP_UPLOAD_TIME;
pProps[UPLOAD_TIME].Value.LPSZ = szTimeString;

hResult = pPropObj->SetProps (NUM_LOGON_PROPERTIES, pProps, NULL);
if (hResult)
{
TraceResult ("DoLogonDlg: Failed to set the properties", hResult);
goto ErrorExit;
}
DTPAGE DtPropPages[2];
DtPropPages[0].cctl = NUM_CFG_USERINFO_PAGE_CTLS; // Count of controls in the ConfigPage array
DtPropPages[0].lpszComponent = szBlank;
DtPropPages[0].lpszResourceName = MAKEINTRESOURCE (IDD_CFG_USERINFO);
DtPropPages[0].lpctl = UserConfigPage;

DtPropPages[1].cctl = sizeof(XPConfigPage)/sizeof(DTCTL); // Count of controls in the ConfigPage array
DtPropPages[1].lpszComponent = szBlank;
DtPropPages[1].lpszResourceName = MAKEINTRESOURCE (IDD_CFG_XPCONNECT);
DtPropPages[1].lpctl = XPConfigPage;

// If the UI_READONLY flag is set, then we are being called from the
// SettingDialog method in Read Only mode. Disable all of the controls
// on the property sheets, else Enable them
if (pCfgDialog->ulFlags & UI_READONLY)
{
// Disable the controls (make them read-only)
DtPropPages[0].lpctl[1].ulCtlFlags &= ~(DT_EDITABLE | DT_SET_IMMEDIATE);
DtPropPages[0].lpctl[7].ulCtlFlags &= ~(DT_EDITABLE | DT_SET_IMMEDIATE);
DtPropPages[1].lpctl[1].ulCtlFlags &= ~DT_EDITABLE;
DtPropPages[1].lpctl[2].ulCtlFlags &= ~DT_EDITABLE;
}
else
{
// Enable the controls (make them read/write)
DtPropPages[0].lpctl[1].ulCtlFlags |= (DT_EDITABLE | DT_SET_IMMEDIATE);
DtPropPages[0].lpctl[7].ulCtlFlags |= (DT_EDITABLE | DT_SET_IMMEDIATE);
DtPropPages[1].lpctl[1].ulCtlFlags |= DT_EDITABLE;
DtPropPages[1].lpctl[2].ulCtlFlags |= DT_EDITABLE;
}

// Create the display table for the logon dialog. It is based on dialog
// resources plus the static information at the head of this module.
LPTABLEDATA pTableData;
hResult = BuildDisplayTable (gpfnAllocateBuffer,
gpfnAllocateMore,
gpfnFreeBuffer,
NULL,
pCfgDialog->hInst,
sizeof(DtPropPages)/sizeof(DTPAGE),
DtPropPages,
fMapiUnicode,
&pTableObj,
&pTableData);
if (!hResult)
{
pPropObj->SetTableData (pTableData);
pTableData->Release();

// Display the dialog/property sheets
DisplayPropsAgain:
hResult = pCfgDialog->pSupObj->DoConfigPropsheet ((ULONG)pCfgDialog->hWnd,
0,
szDialogTitle,
pTableObj,
pPropObj,
0); // Default index for the top property sheet
if (!hResult)
{
// Retrieve the altered data
gpfnFreeBuffer (pProps);
pProps = NULL;
hResult = pPropObj->GetProps ((LPSPropTagArray)&sptCfgProps, fMapiUnicode, &ulPropCount, &pProps);
if (hResult)
{
if (MAPI_W_ERRORS_RETURNED == hResult)
{
if (PR_TMP_UPLOAD_TIME != pProps[UPLOAD_TIME].ulPropTag)
{
pProps[UPLOAD_TIME].ulPropTag = PR_TMP_UPLOAD_TIME;
pProps[UPLOAD_TIME].Value.LPSZ = szDefaultTime;
}
hResult = S_OK;
}
else
{
TraceResult ("DoLogonDlg: GetProps failed", hResult);
goto ErrorExit;
}
}
// Check the Server name
if (!IsValidServerName (pProps[SERVER_NAME].Value.LPSZ))
{
gpfnFreeBuffer (pProps);
pProps = NULL;
PrivateMessageBox (IDS_MSG_INVALID_SERVER_NAME, pCfgDialog->hWnd);
goto DisplayPropsAgain;
}

ASSERT (PR_TMP_UPLOAD_TIME == pProps[UPLOAD_TIME].ulPropTag);
SYSTEMTIME st;
GetLocalTime (&st);
if (ParseTime (pProps[UPLOAD_TIME].Value.LPSZ, &st.wHour, &st.wMinute))
{
pProps[UPLOAD_TIME].ulPropTag = PR_SMP_UPLOAD_TIME;
SystemTimeToFileTime (&st, &pProps[UPLOAD_TIME].Value.ft);
}
else
{
gpfnFreeBuffer (pProps);
pProps = NULL;
PrivateMessageBox (IDS_MSG_BAD_TIME_FORMAT, pCfgDialog->hWnd);
goto DisplayPropsAgain;
}

// Return the new property array
*pCfgDialog->ppProps = pProps;
pProps = NULL; // do not free this in cleanup code below
}
}

ErrorExit:
// Release objects
if (pTableObj)
{
pTableObj->Release();
}
if (pPropObj)
{
pPropObj->Release();
}
gpfnFreeBuffer (pProps);
PrivUninitialize3DCtl (pCfgDialog->hInst);
ReleaseMutex (pCfgDialog->hUIMutex);
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// ParseTime()
//
// Parameters
// [IN] pszTime String in the form HH:MM.
// [OUT] pwHour Hour of day, 0-23
// [OUT] pwMinute Minute of hour, 0-59
//
// Purpose
// This function parses the string in pszTime and returns the numbers
// for the hour and minute of day in a 24 hour clock format.
//
// Return Value
// TRUE on success, FALSE if we failed or the string passed
// in is invalid.
//
BOOL WINAPI ParseTime (LPTSTR pszTime, WORD * pwHour, WORD * pwMinute)
{
TCHAR szTemp[6];
lstrcpy (szTemp, pszTime);
LPTSTR pszSubStr = strtok(szTemp, TEXT(":"));
if (!pszSubStr)
{
return FALSE;
}
*pwHour = atoi (pszSubStr);
if (*pwHour < 0 || *pwHour > 23)
{
return FALSE;
}
pszSubStr = strtok (NULL, TEXT(" "));
if (!pszSubStr)
{
return FALSE;
}
*pwMinute = atoi(pszSubStr);
if (*pwMinute < 0 || *pwMinute > 59)
{
return FALSE;
}
return TRUE;
}

///////////////////////////////////////////////////////////////////////////////
// GetTimeString()
//
// Parameters
// [OUT] pszTime Pointer to a buffer where the function copies the
// formatted time string. The buffer must have been
// allocated by the caller.
// [IN] FileTime FILETIME structure with the time for the string.
//
// Purpose
// This function returns a string formatted as "HH:MM"
// The formatted string is returned in a buffer supplied by the caller
// of the function.
//
// Return Value
// None.
//
void WINAPI GetTimeString (LPTSTR pszTime, FILETIME FileTime)
{
// Convert the FILETIME structure to a more readable form
SYSTEMTIME sysTime;
FileTimeToSystemTime (&FileTime, &sysTime);
wsprintf (pszTime, TEXT("%d:%02d"), sysTime.wHour, sysTime.wMinute);
}

///////////////////////////////////////////////////////////////////////////////
// GetMAPIError()
//
// Parameters
// ppMAPIError Pointer to a location where the newly
// allocated MAPIERROR structure is returened.
// ulFlags Flags for the allocation of the structure
// hError Handle to the error for which a string will
// be returned
// hInstance Handle to instance of DLL where the resource
// strings are located
//
// Purpose
// This provider implements a shared function for the two different
// GetLastError methods in the IMAPIFolder and IMAPIStatus interfaces.
// These interfaces do not maintain (cached) the last error result, so
// we trust the client that the hError passed in is indeed the last error.
// This simplifies implementation of GetLastError, but it will give up
// giving error strings on the exact context of the actual last error
// in the case a client passes the wrong hResult.
// ISV's should weight the benefits and trade-off of this implementation.
//
// Return Value
// An HRESULT
//
HRESULT WINAPI GetMAPIError (LPMAPIERROR * ppMAPIError,
ULONG ulFlags,
HRESULT hError,
HINSTANCE hInstance)
{
// The following array maps a string identifier (IDS) to an hResult
// The order of HRESULTs in the array has an external dependency:
// the order of elements in the array is dictated by the IDS definitions
// in RESOURCE.H. This implicit association must be maintained for the
// strings associated with string identifiers to make sense. Thus, if
// either this structure or the RESOURCE.H defines changes, the other
// must change to match it
static const HRESULT MapOfhResults[] =
{
S_OK,

E_FAIL,
E_OUTOFMEMORY,
E_INVALIDARG,
E_NOINTERFACE,
E_ACCESSDENIED,

MAPI_E_BUSY,
MAPI_E_NO_SUPPORT,
MAPI_E_NOT_FOUND,
MAPI_E_UNKNOWN_FLAGS,
MAPI_E_VERSION,
MAPI_E_INVALID_ENTRYID,
MAPI_E_USER_CANCEL,
MAPI_E_DISK_ERROR,
MAPI_E_CORRUPT_DATA,
MAPI_E_BAD_CHARWIDTH,
MAPI_E_UNCONFIGURED,


CO_E_NOTINITIALIZED, // This error could only be comming from the server

MAPI_W_ERRORS_RETURNED
};

// Default the a return value in case we don't have the specified error
// Allocate the memory for the MAPIERROR structure. The caller is
// responsible for free this
HRESULT hResult = gpfnAllocateBuffer (sizeof(MAPIERROR), (LPVOID *)ppMAPIError);
if (hResult)
{
TraceResult ("GetMAPIError: Failed to allocate memory for the MAPIERROR structure", hResult);
return hResult;
}

// Zero-out all the members in the structure
ZeroMemory (*ppMAPIError, sizeof(MAPIERROR));
(*ppMAPIError)->ulVersion = MAPI_ERROR_VERSION;
// See if we have the string for the error. If so, make a copy
// and pass it back. The memory for the string will be linked to
// the memory of the structure so that the caller can make a
// single release on the structure

// Search for the hResult in the HRESULT map
UINT i, uMaxNum, uStringID;
uStringID = 0;
uMaxNum = sizeof (MapOfhResults) / sizeof (HRESULT);
for (i=0; i<uMaxNum; i++ )
{
if (MapOfhResults[i] == hError)
{
break;
}
}

if (i == uMaxNum)
{
(*ppMAPIError)->ulLowLevelError = LOWORD(hError);
if (HRESULT_FACILITY(hError) == FACILITY_RPC)
{
uStringID = IDS_RPC_ERROR;
}
else
{
if (HRESULT_FACILITY(hError) == FACILITY_WIN32 ||
HRESULT_FACILITY(hError) == FACILITY_NULL)
{
uStringID = IDS_SYSTEM_ERROR;
}
else
{
uStringID = IDS_E_UNKNOWN_ERROR;
}
}
}
else
{
uStringID = i + IDS_SUCCESS;
}

TCHAR szBuffer[512];
int nCharsRead = LoadString (hInstance, uStringID, szBuffer, sizeof(szBuffer) -1);
if (!nCharsRead)
{
TraceString1 ("GetMAPIError: Could not find error string for ID %d", uStringID);
hResult = MAPI_E_NOT_FOUND;
}
else
{
// Allocate memory for return variable and set it.
// The memory for this string is linked to the memory in the pMemBlock parameter
hResult = gpfnAllocateMore (Cbtszsize (szBuffer),
*ppMAPIError,
(LPVOID *)&(*ppMAPIError)->lpszError);
if (!hResult)
{
lstrcpy ((*ppMAPIError)->lpszError, szBuffer);
hResult = gpfnAllocateMore (Cbtszsize (TRANSPORT_DISPLAY_NAME_STRING),
*ppMAPIError,
(LPVOID *)&(*ppMAPIError)->lpszComponent);
if (!hResult)
{
lstrcpy ((*ppMAPIError)->lpszComponent, TRANSPORT_DISPLAY_NAME_STRING);
}
else
{
TraceResult ("GetMAPIError: Failed to allocate the memory for the component string", hResult);
}
}
else
{
TraceResult ("GetMAPIError: Failed to allocate the memory for the error string", hResult);
}
}

if (hResult)
{
gpfnFreeBuffer (*ppMAPIError);
*ppMAPIError = NULL;
}
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// XPProviderInit()
//
// Parameters
// { Refer to MAPI Documentation on this method }
//
// Purpose
// Entry point called by the MAPI spooler when a profile uses this
// transport. The spooler calls this method and expects a pointer to an
// implementation of the IXPProvider interface. MAPI uses the returned
// IXPProvider interface pointer to logon on the transport provider
//
// Return Value
// An HRESULT
//
STDINITMETHODIMP XPProviderInit (HINSTANCE hInstance,
LPMALLOC pMallocObj,
LPALLOCATEBUFFER pfnAllocateBuffer,
LPALLOCATEMORE pfnAllocateMore,
LPFREEBUFFER pfnFreeBuffer,
ULONG ulFlags,
ULONG ulMAPIVer,
ULONG * pulProviderVer,
LPXPPROVIDER * ppXPProviderObj)
{
// Look at TRACES.H and TRACES.CPP for more options to the InitTraces() function
//InitTraces (0); // Send output only to the COM1 port
InitTraces (TRACES_CONSOLE | TRACES_NO_COM_OUTPUT); // Send output to a console window BUT NOT to the COM1
//InitTraces (TRACES_CONSOLE | TRACES_LOG_FILE); // Send output to COM1 port AND a console window AND to a log file in C:\MAPILOG.TXT
InfoTrace ("XPProviderInit function called");
*pulProviderVer = CURRENT_SPI_VERSION;
if (ulMAPIVer < CURRENT_SPI_VERSION)
{
TraceMessage ("XPProviderInit: The version of the subsystem cannot handle this version of the provider");
return MAPI_E_VERSION;
}
// Save the pointer to the allocation routines in global variables
gpfnAllocateBuffer = pfnAllocateBuffer;
gpfnAllocateMore = pfnAllocateMore;
gpfnFreeBuffer = pfnFreeBuffer;
ghInstance = hInstance;
// Allocate a new XPProvider object, the constructor will initialize the data member
CXPProvider * pXPProvider = new CXPProvider (hInstance);
if (!pXPProvider)
{
TraceMessage ("XPProviderInit: Failed to allocate a new CXPProvider object");
return E_OUTOFMEMORY;
}
// Copy pointer to the allocated object back into the return IXPProvider object pointer
*ppXPProviderObj = (LPXPPROVIDER)pXPProvider;
return S_OK;
}

// End of file for XPSRVCE.CPP