// --convreg.cpp----------------------------------------------------------------
//
// Conversion registry code.
// Locates converters that are stored in DLLs from info stored in the
// registry.
//
// Copyright (C) Microsoft Corp. 1986-1996. All Rights Reserved.
//
// -----------------------------------------------------------------------------
#include "convincl.h"
#include "convreg.chk"
//
// String constants used to find registry keys.
//
static const LPWSTR pszMAPIConvKey = L"SOFTWARE\\Classes\\MAPI Conversions";
//
// Conversion KEY values.
//
static const LPWSTR pszClassesKey = L"Classes";
static const LPWSTR pszPointKey = L"Point";
static const LPWSTR pszOptionsKey = L"Options";
//
// limiting constants.
//
static const int cMaxKeyNameSize = 100; // maximum conversion key size.
// Static variables shared by all instances
HKEY CEDKConvReg::ms_hkConversions = NULL; // handle to conversion key.
CClassName * CEDKConvReg::ms_pcnClasses = NULL; // common cache of conversion info
CDllCache * CEDKConvReg::ms_pDllCache = NULL; // common DLL cache
//$--CEDKConvReg::CEDKConvReg------------------------------------------
//
// DESCRIPTION: CEDKConvReg class constructor
//
// INPUT: none
//
// RETURNS: nothing
//
//---------------------------------------------------------------------
CEDKConvReg::CEDKConvReg()
{
DEBUGPRIVATE("CEDKConvReg::CEDKConvReg()\n");
}
//$--CEDKConvReg::~CEDKConvReg-----------------------------------------
//
// DESCRIPTION: CEDKConvReg class destructor
//
// INPUT: none
//
// RETURNS: nothing
//
//---------------------------------------------------------------------
CEDKConvReg::~CEDKConvReg()
{
DEBUGPRIVATE("CEDKConvReg::~CEDKConvReg()\n");
}
//$--CEDKConvReg::HrEDKInitialize-----------------------------------------
//
// DESCRIPTION: Perform loading part of Conversion registry initialization.
//
// INPUT: none
//
// RETURNS: HRESULT -- NOERROR if successful,
// E_FAIL otherwise
//
//---------------------------------------------------------------------
HRESULT CEDKConvReg::HrEDKInitialize()
{
HRESULT hr = NOERROR; // return code
LONG lRet = ERROR_SUCCESS; // win32 return code
DEBUGPRIVATE("CEDKConvReg::HrEDKInitialize()\n");
//
// Skip initialization if it has already been done.
//
if(ms_pcnClasses != NULL)
{
goto cleanup;
}
// consistency checking
ASSERTERROR(ms_hkConversions == NULL,"NULL ms_hkConversions variable");
// Create the DLL cache.
ms_pDllCache = new CDllCache;
if ( ms_pDllCache == NULL )
{
hr = HR_LOG(E_OUTOFMEMORY);
goto cleanup;
}
//
// Open key that contains all conversions.
//
lRet = RegOpenKeyExW(
HKEY_LOCAL_MACHINE,
pszMAPIConvKey,
0,
KEY_READ,
&ms_hkConversions);
if(lRet != ERROR_SUCCESS)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
//
// Parse the contented keys and values.
//
hr = HrEDKParseConfiguration();
cleanup:
RETURN(hr);
}
//$--CEDKConvReg::HrEDKParseConfiguration---------------------------------
//
// DESCRIPTION: Parse the list of all conversions from the registry conversion keys
//
// INPUT: none
//
// RETURNS: HRESULT -- NOERROR if no error successful,
// EDK_E_END_OF_FILE if syntax error
// E_FAIL otherwise
//
//---------------------------------------------------------------------
HRESULT CEDKConvReg::HrEDKParseConfiguration() // RETURNS: HRESULT
{
HRESULT hr = NOERROR; // return code
LONG lRet = 0;
HKEY hkDll = NULL;
HKEY hkEntryPoint = NULL;
DEBUGPRIVATE("CEDKConvReg::HrEDKParseConfiguration()\n");
// consistency checking
ASSERTERROR(ms_hkConversions != NULL,"NULL ms_hkConversions parameter");
ASSERTERROR(ms_pcnClasses == NULL,"NULL ms_pcnClasses parameter");
m_bSyntaxError = FALSE;
//
// Enumerate all conversion DLLs. These are sub-keys of hkConversions
// At the same time, load each DLL found and add to the DLL cache.
//
UINT iDll = 0; // DLL index
for(iDll = 0;;iDll++)
{
FILETIME ftDummy = {0};
WCHAR szDll[cMaxKeyNameSize+1] = {0};
DWORD dwDummy = cMaxKeyNameSize;
// DLL loop bounds
ASSERTERROR(iDll >= 0 && iDll < 1024,"iDll out of bounds");
//
// Get the next key
//
lRet = RegEnumKeyExW(
ms_hkConversions, iDll, szDll, &dwDummy, NULL, NULL, NULL, &ftDummy);
if(lRet == ERROR_NO_MORE_ITEMS)
break;
if(lRet != ERROR_SUCCESS)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
//
// Open the conversion DLL key
//
lRet = RegOpenKeyExW(ms_hkConversions, szDll, 0L, KEY_READ, &hkDll);
if(lRet != ERROR_SUCCESS)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
// Add the conversion DLL to the global DLL cache.
// (This also loads the DLL.)
hr = ms_pDllCache->HrAdd(
szDll); // DLL name to load and add
if ( FAILED(hr) )
{
goto cleanup;
}
//
// enumerate all entry point keys contained in the DLL key.
//
int iEntryPoint = 0;
for (iEntryPoint = 0;;iEntryPoint++)
{
WCHAR szEntryPoint[cMaxKeyNameSize+1] = {0};
// Entry point loop bounds
ASSERTERROR(
iEntryPoint >= 0 && iEntryPoint < 1024,
"iEntryPoint out of bounds");
dwDummy = cMaxKeyNameSize;
lRet = RegEnumKeyExW(
hkDll, iEntryPoint, szEntryPoint, &dwDummy, NULL, NULL, NULL, &ftDummy);
if(lRet == ERROR_NO_MORE_ITEMS)
break;
if(lRet != ERROR_SUCCESS)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
//
// Open the entry point
//
lRet = RegOpenKeyExW(hkDll, szEntryPoint, 0L, KEY_READ, &hkEntryPoint);
if(lRet != ERROR_SUCCESS)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
//
// Get values and put them in the in-memory structure.
//
hr = HrEDKRecordValues(hkEntryPoint, szDll, szEntryPoint);
if(hr == EDK_E_END_OF_FILE)
{
// Error reported by HrEDKRecordValues
hr = HR_LOG(NOERROR); // not a critical error
}
if(FAILED(hr))
{
goto cleanup;
}
//
// Close entry point key.
//
REGCLOSEKEY(hkEntryPoint);
}
if(!iEntryPoint)
{
EDKSyntaxError(
szDll,
NULL,
NULL,
NULL,
NULL);
}
//
// Close DLL key.
//
REGCLOSEKEY(hkDll);
}
if(!iDll)
{
EDKSyntaxError(
NULL,
NULL,
NULL,
NULL,
NULL);
}
cleanup:
REGCLOSEKEY(hkDll);
REGCLOSEKEY(hkEntryPoint);
if(m_bSyntaxError)
{
hr = HR_LOG(EDK_E_END_OF_FILE);
}
ASSERTERROR(hkDll == NULL,"NULL hkDll variable");
ASSERTERROR(hkEntryPoint == NULL,"NULL hkEntryPoint variable");
RETURN(hr);
}
//$--CEDKConvReg::HrEDKRecordValues---------------------------------------
//
// DESCRIPTION: We have found an entry point. Get its details and record them in
// the in-memory list of classes/entry points.
//
// INPUT: hkEntryPoint -- entry point key
// pszDll -- DLL name
// pszEntryPoint -- name of DLL's entry point function
//
// RETURNS: HRESULT -- NOERROR if successful,
// E_INVALIDARG if bad input,
// EDK_E_END_OF_FILE if bad syntax,
// E_FAIL otherwise
//
//---------------------------------------------------------------------
HRESULT CEDKConvReg::HrEDKRecordValues( // RETURN: HRESULT
// if a required value is not present
// SyntaxError() is also called.
IN HKEY const hkEntryPoint, // Entry point key that contain details
IN LPCWSTR pszDll, // dll containing entry point.
IN LPCWSTR pszEntryPoint) // name of entry point in dll.
{
HRESULT hr = NOERROR; // return code
PVOID pClasses = NULL;
PVOID pPoint = NULL;
PVOID pOptions = NULL;
DWORD cbSize = 0;
DWORD nType = 0;
LPCWSTR pszClassName = NULL;
CDllEntryPoint *pEntryPoint = NULL;
DEBUGPRIVATE("CEDKConvReg::HrEDKRecordValues()\n");
// check input parameters
hr = CHK_CEDKConvReg_HrEDKRecordValues(hkEntryPoint, pszDll,
pszEntryPoint);
if ( FAILED(hr) )
{
RETURN(hr);
}
//
// Get the key values.
//
//
// Supported classes.
//
hr = HrGetArbSizeValue(hkEntryPoint, pszClassesKey,
pClasses, cbSize, nType);
if(hr == EDK_E_END_OF_FILE || nType != REG_MULTI_SZ)
{
hr = HR_LOG(EDK_E_END_OF_FILE);
}
if(FAILED(hr))
{
goto cleanup;
}
//
// Conversion point.
//
hr = HrGetArbSizeValue(hkEntryPoint, pszPointKey,
pPoint, cbSize, nType);
if(hr == EDK_E_END_OF_FILE || nType != REG_SZ)
{
hr = HR_LOG(EDK_E_END_OF_FILE);
}
if(FAILED(hr))
{
goto cleanup;
}
//
// Options.
//
hr = HrGetArbSizeValue(hkEntryPoint, pszOptionsKey,
pOptions, cbSize, nType);
// ignore absent value.
if(SUCCEEDED(hr) && nType != REG_SZ)
{
hr = HR_LOG(EDK_E_END_OF_FILE);
goto cleanup;
}
else
{
hr = HR_LOG(NOERROR);
}
//
// Setup pointer to first class name.
//
pszClassName = (LPCWSTR)pClasses;
ASSERTERROR(pszClassName != NULL, "Bad pszClassName");
ASSERTERROR(pPoint != NULL, "Bad pPoint");
if( (*pszClassName == 0) || (*((LPWSTR)pPoint) == 0) )
{
hr = HR_LOG(EDK_E_END_OF_FILE);
goto cleanup;
}
//
// Create a new entry point.
//
pEntryPoint = new CDllEntryPoint;
if(pEntryPoint == NULL)
{
goto cleanup;
}
hr = pEntryPoint->HrEDKSet(
pszDll, (LPCWSTR)pszEntryPoint, (LPCWSTR)pPoint, (LPWSTR)pOptions);
if(FAILED(hr))
{
goto cleanup;
}
//
// For each class in pClasses
//
for(; *pszClassName; pszClassName += lstrlenW(pszClassName)+1)
{
//
// Make a new class structre
//
CClassName * pNewClass = new CClassName;
if(pNewClass == NULL)
{
hr = HR_LOG(E_FAIL);
goto cleanup;
}
hr = pNewClass->HrEDKSet(pszClassName, pEntryPoint);
if(FAILED(hr))
{
delete pNewClass;
goto cleanup;
}
//
// insert class in list of classes.
//
CClassName ** ppcnTmp = &ms_pcnClasses;
for(;;)
{
ASSERTERROR(ppcnTmp != NULL,"NULL ppcnTmp variable");
if(*ppcnTmp == NULL)
break;
ASSERTERROR(*ppcnTmp != NULL,"NULL *ppcnTmp variable");
if(pNewClass->cNameLength() >= (*ppcnTmp)->cNameLength())
break;
ppcnTmp= &((*ppcnTmp)->m_pcnNext);
}
pNewClass->m_pcnNext = *ppcnTmp;
*ppcnTmp = pNewClass;
}
cleanup:
if ( hr == EDK_E_END_OF_FILE )
{
// report syntax error to event log
EDKSyntaxError(
(LPWSTR) pszDll,
(LPWSTR) pszEntryPoint,
(LPWSTR) pClasses,
(LPWSTR) pOptions,
(LPWSTR) pPoint);
}
MAPIFREEBUFFER(pClasses);
MAPIFREEBUFFER(pPoint);
MAPIFREEBUFFER(pOptions);
if(pEntryPoint != NULL)
{
pEntryPoint->Release();
pEntryPoint = NULL;
}
RETURN(hr);
}
//$--CEDKConvReg::HrEDKSearchOpen---------------------------------------------
//
// DESCRIPTION: Initiate the search for candidate converters.
// Call HrEDKSearchNext to find subsequent converters.
// Must call SearchClose after finished, even if errors
// are returned.
//
// INPUT: pszConversionPoint -- what conversion point
// pszContentClass -- what class
//
// OUTPUT: pep -- hold candidate conversion if found
//
// RETURNS: HRESULT -- NOERROR if successful,
// E_INVALIDARG if bad input
// E_FAIL otherwise.
//
//---------------------------------------------------------------------
HRESULT CEDKConvReg::HrEDKSearchOpen( // returns HRESULT
IN LPCWSTR pszConversionPoint, // what conversion point.
IN LPCWSTR pszContentClass, // what class
OUT CDllEntryPoint * &pep) // holds candidate if found.
{
HRESULT hr = NOERROR; // return code
DEBUGPRIVATE("CEDKConvReg::HrEDKSearchOpen()\n");
// check for bad input
hr = CHK_CEDKConvReg_HrEDKSearchOpen(pszConversionPoint,
pszContentClass, pep);
if ( FAILED(hr) )
{
RETURN(hr);
}
m_ppep = &pep;
m_pszConversionPoint = pszConversionPoint;
m_pszContentClass = pszContentClass;
m_pcnCurrentClass = ms_pcnClasses;
RETURN(hr);
}
//$--CEDKConvReg::HrEDKSearchNext-----------------------------------------
//
// DESCRIPTION: Find the next candidate conversion. HrEDKSearchOpen must be called
// first. SearchClose must be called after. EDK_E_END_OF_FILE indicates that
// no candidates can be found.
//
// INPUT: none
//
// RETURNS: HRESULT -- NOERROR if successful,
// EDK_E_END_OF_FILE is no candidates found,
// E_FAIL otherwise.
//
//---------------------------------------------------------------------
HRESULT CEDKConvReg::HrEDKSearchNext() // RETURNS: HRESULT
{
HRESULT hr = NOERROR; // return code
CDllEntryPoint * pdepTmp = NULL; // temporary conversion DLL
HRESULT hrT = NOERROR; // temporary return code
BOOL fFound = FALSE; // TRUE if found DLL
DEBUGPRIVATE("CEDKConvReg::HrEDKSearchNext()\n");
//
// Search remaining conversions.
//
while (m_pcnCurrentClass != NULL)
{
CClassName * pcnTmp = m_pcnCurrentClass;
m_pcnCurrentClass = m_pcnCurrentClass->m_pcnNext;
pdepTmp = pcnTmp->pEntryPoint();
hrT = HrStrstriW(
pcnTmp->pszClassName(), // substring
m_pszContentClass); // message class
if ( FAILED(hrT) )
{
// not a match,
// continue.
continue;
}
// Class names "match"
// Check conversion pointer for a match.
LPWSTR lpszCurPoint = pdepTmp->pszGwPoint();
if ( lstrcmpiW(m_pszConversionPoint, lpszCurPoint) == 0 )
{
//
// found a match, break;
//
fFound = TRUE;
break;
}
}
// Check to make sure that conversion was found.
if ( (fFound == FALSE) || (pdepTmp == NULL) )
{
hr = HR_LOG(EDK_E_END_OF_FILE);
goto cleanup;
}
*m_ppep = pdepTmp;
cleanup:
RETURN(hr);
}
//$--CEDKConvReg::EDKSearchClose------------------------------------------
//
// DESCRIPTION: must be called after HrEDKSearchOpen.
//
// INPUT: none
//
// RETURNS: void
//
//---------------------------------------------------------------------
void CEDKConvReg::EDKSearchClose() // RETURNS: void
{
DEBUGPRIVATE("CEDKConvReg::EDKSearchClose()\n");
}
//$--CEDKConvReg::EDKFree-------------------------------------------------
//
// DESCRIPTION: internal routine to free conversion structure.
//
// INPUT: none
//
// RETURNS: void
//
//---------------------------------------------------------------------
void CEDKConvReg::EDKFree() // RETURNS: void
{
DEBUGPRIVATE("CEDKConvReg::EDKFree()\n");
CClassName * pcnTmp = ms_pcnClasses;
while (pcnTmp != NULL)
{
CClassName * pcnNext = pcnTmp->m_pcnNext;
delete pcnTmp;
pcnTmp = pcnNext;
}
ms_pcnClasses = NULL;
REGCLOSEKEY(ms_hkConversions);
// delete the DLL cache. (This also unloads the DLLs previously
// loaded.
delete ms_pDllCache;
ms_pDllCache = NULL;
}
//$--CEDKConvReg::EDKDumpMappings-----------------------------------------
//
// DESCRIPTION: debug routine to display mappings.
//
// INPUT: none
//
// RETURNS: void
//
//---------------------------------------------------------------------
void CEDKConvReg::EDKDumpMappings() // RETURNS void
{
DEBUGPRIVATE("CEDKConvReg::EDKDumpMappings()\n");
CClassName * pcnTmp = ms_pcnClasses;
// incompatabile with WINWRAP _tprintf(TEXT("Dump of mappings...\n"));
while (pcnTmp != NULL)
{
pcnTmp->EDKDump();
pcnTmp = pcnTmp->m_pcnNext;
}
}
//$--CEDKConvReg::EDKSyntaxError------------------------------------------
//
// DESCRIPTION: debug routine called whenever a syntax error is detected.
//
// INPUT: pszDll -- DLL key name
// pszEntryPoint -- entry point name
// pszClass -- message class key name
// pszOptions -- conversion options key name
// pszPoint -- conversion point key name
//
// RETURNS: VOID
//
//---------------------------------------------------------------------
VOID CEDKConvReg::EDKSyntaxError( // RETURNS: VOID
IN LPWSTR pszDll, // DLL name
IN LPWSTR pszEntryPoint, // entry point name
IN LPWSTR pszClass, // message class
IN LPWSTR pszOptions, // conversion options
IN LPWSTR pszPoint) // conversion point
{
LPWSTR lpszBlank = L""; // blank string
LPWSTR lpszDllName = lpszBlank; // conversion DLL name
LPWSTR lpszEntry = lpszBlank; // entry point name
LPWSTR lpszPoint = lpszBlank; // conversion point
LPWSTR lpszClass = lpszBlank; // message class
LPWSTR lpszOptions = lpszBlank; // options
DEBUGPRIVATE("CEDKConvReg::EDKSyntaxError()\n");
// No check function for this routine. It is an event
// logging routine and all parameters may be NULL.
m_bSyntaxError = TRUE;
if ( pszDll != NULL )
{
lpszDllName = pszDll;
}
if ( pszEntryPoint != NULL )
{
lpszEntry = pszEntryPoint;
}
if ( pszPoint != NULL )
{
lpszPoint = pszPoint;
}
if ( pszClass != NULL )
{
lpszClass = pszClass;
}
if ( pszOptions != NULL )
{
lpszOptions = pszOptions;
}
// Log event to the event log.
EventLogMsgW(
MESGXLAT_CNV_BAD_SYNTAX, // event identfier
5, // # of strings
lpszDllName, // string 1
lpszEntry,
lpszClass,
lpszOptions,
lpszPoint,
0); // # of error codes
}