//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1995 - 1999 // // File: celib.cpp // // Contents: helper functions // //-------------------------------------------------------------------------- #include "pch.cpp" #pragma hdrstop #include "celib.h" #include //+-------------------------------------------------------------------------- // ceDecodeObject -- call CryptDecodeObject, and allocate memory for output // //+-------------------------------------------------------------------------- #pragma warning(push) #pragma warning(disable: 4100) // unreferenced formal parameter BOOL ceDecodeObject( IN DWORD dwEncodingType, IN LPCSTR lpszStructType, IN BYTE const *pbEncoded, IN DWORD cbEncoded, IN BOOL fCoTaskMemAlloc, // referenced only by assert OUT VOID **ppvStructInfo, OUT DWORD *pcbStructInfo) { BOOL b; assert(!fCoTaskMemAlloc); *ppvStructInfo = NULL; *pcbStructInfo = 0; while (TRUE) { b = CryptDecodeObject( dwEncodingType, lpszStructType, pbEncoded, cbEncoded, 0, // dwFlags *ppvStructInfo, pcbStructInfo); if (b && 0 == *pcbStructInfo) { SetLastError((DWORD) HRESULT_FROM_WIN32(ERROR_INVALID_DATA)); b = FALSE; } if (!b) { if (NULL != *ppvStructInfo) { HRESULT hr = GetLastError(); LocalFree(*ppvStructInfo); *ppvStructInfo = NULL; SetLastError(hr); } break; } if (NULL != *ppvStructInfo) { break; } *ppvStructInfo = (BYTE *) LocalAlloc(LMEM_FIXED, *pcbStructInfo); if (NULL == *ppvStructInfo) { b = FALSE; break; } } return(b); } #pragma warning(pop) #pragma warning(push) #pragma warning(disable: 4100) // unreferenced formal parameter BOOL ceEncodeObject( IN DWORD dwEncodingType, IN LPCSTR lpszStructType, IN VOID const *pvStructInfo, IN DWORD dwFlags, // referenced only by assert IN BOOL fCoTaskMemAlloc, // referenced only by assert OUT BYTE **ppbEncoded, OUT DWORD *pcbEncoded) { BOOL b; assert(0 == dwFlags); assert(!fCoTaskMemAlloc); *ppbEncoded = NULL; *pcbEncoded = 0; while (TRUE) { b = CryptEncodeObject( dwEncodingType, lpszStructType, const_cast(pvStructInfo), *ppbEncoded, pcbEncoded); if (b && 0 == *pcbEncoded) { SetLastError((DWORD) HRESULT_FROM_WIN32(ERROR_INVALID_DATA)); b = FALSE; } if (!b) { if (NULL != *ppbEncoded) { HRESULT hr = GetLastError(); LocalFree(*ppbEncoded); *ppbEncoded = NULL; SetLastError(hr); } break; } if (NULL != *ppbEncoded) { break; } *ppbEncoded = (BYTE *) LocalAlloc(LMEM_FIXED, *pcbEncoded); if (NULL == *ppbEncoded) { b = FALSE; break; } } return(b); } #pragma warning(pop) // The returned pszObjId is a constant that must not be freed. CryptFindOIDInfo // has a static internal database that is valid until crypt32.dll is unloaded. WCHAR const * ceGetOIDNameA( IN char const *pszObjId) { CRYPT_OID_INFO const *pInfo = NULL; WCHAR const *pwszName = L""; // First try looking up the ObjectId as an Extension or Attribute, because // we get a better Display Name, especially for Subject RDNs: CN, L, etc. // If that fails, look it up withoput restricting the group. pInfo = CryptFindOIDInfo( CRYPT_OID_INFO_OID_KEY, (VOID *) pszObjId, CRYPT_EXT_OR_ATTR_OID_GROUP_ID); if (NULL == pInfo || NULL == pInfo->pwszName || L'\0' == pInfo->pwszName[0]) { pInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, (VOID *) pszObjId, 0); } if (NULL != pInfo && NULL != pInfo->pwszName && L'\0' != pInfo->pwszName[0]) { pwszName = pInfo->pwszName; } return(pwszName); } WCHAR const * ceGetOIDName( IN WCHAR const *pwszObjId) { char *pszObjId = NULL; WCHAR const *pwszName = L""; if (!ceConvertWszToSz(&pszObjId, pwszObjId, -1)) { _JumpError(E_OUTOFMEMORY, error, "ceConvertWszToSz"); } pwszName = ceGetOIDNameA(pszObjId); error: if (NULL != pszObjId) { LocalFree(pszObjId); } return(pwszName); } WCHAR * ceDuplicateString( IN WCHAR const *pwsz) { WCHAR *pwszOut; pwszOut = (WCHAR *) LocalAlloc( LMEM_FIXED, (wcslen(pwsz) + 1) * sizeof(pwsz[0])); if (NULL != pwszOut) { wcscpy(pwszOut, pwsz); } return(pwszOut); } BOOL ceConvertWszToSz( OUT CHAR **ppsz, IN WCHAR const *pwc, IN LONG cwc) { BOOL fOk = FALSE; LONG cch = 0; *ppsz = NULL; while (TRUE) { cch = WideCharToMultiByte( GetACP(), 0, // dwFlags pwc, cwc, // cchWideChar, -1 => null terminated *ppsz, cch, NULL, NULL); if (0 >= cch) { DWORD err; err = GetLastError(); ceERRORPRINTLINE("WideCharToMultiByte", err); if (NULL != *ppsz) { LocalFree(*ppsz); *ppsz = NULL; } break; } if (NULL != *ppsz) { fOk = TRUE; break; } *ppsz = (CHAR *) LocalAlloc(LMEM_FIXED, cch + 1); if (NULL == *ppsz) { break; } } return(fOk); } BOOL ceConvertWszToBstr( OUT BSTR *pbstr, IN WCHAR const *pwc, IN LONG cb) { BOOL fOk = FALSE; BSTR bstr; ceFreeBstr(pbstr); do { bstr = NULL; if (NULL != pwc) { if (-1 == cb) { cb = wcslen(pwc) * sizeof(WCHAR); } bstr = SysAllocStringByteLen((char const *) pwc, cb); if (NULL == bstr) { break; } } *pbstr = bstr; fOk = TRUE; } while (FALSE); return(fOk); } BOOL ceConvertSzToWsz( OUT WCHAR **ppwsz, IN char const *pch, IN LONG cch) { BOOL fOk = FALSE; LONG cwc = 0; *ppwsz = NULL; while (TRUE) { cwc = MultiByteToWideChar(GetACP(), 0, pch, cch, *ppwsz, cwc); if (0 >= cwc) { DWORD err; err = GetLastError(); ceERRORPRINTLINE("MultiByteToWideChar", err); if (NULL != *ppwsz) { LocalFree(*ppwsz); *ppwsz = NULL; } break; } if (NULL != *ppwsz) { fOk = TRUE; break; } *ppwsz = (WCHAR *) LocalAlloc(LMEM_FIXED, (cwc + 1) * sizeof(WCHAR)); if (NULL == *ppwsz) { break; } } return(fOk); } BOOL ceConvertSzToBstr( OUT BSTR *pbstr, IN CHAR const *pch, IN LONG cch) { BOOL fOk = FALSE; BSTR bstr = NULL; LONG cwc = 0; ceFreeBstr(pbstr); if (-1 == cch) { cch = strlen(pch); } while (TRUE) { cwc = MultiByteToWideChar(GetACP(), 0, pch, cch, bstr, cwc); if (0 >= cwc) { //hr = ceHLastError(); //printf("MultiByteToWideChar returned %d (%x)\n", hr, hr); break; } if (NULL != bstr) { bstr[cwc] = L'\0'; *pbstr = bstr; fOk = TRUE; break; } bstr = SysAllocStringLen(NULL, cwc); if (NULL == bstr) { break; } } return(fOk); } VOID ceFreeBstr( IN OUT BSTR *pstr) { if (NULL != *pstr) { SysFreeString(*pstr); *pstr = NULL; } } HRESULT ceHError( IN HRESULT hr) { assert(S_FALSE != hr); if (S_OK != hr && S_FALSE != hr && !FAILED(hr)) { hr = HRESULT_FROM_WIN32(hr); if ((HRESULT) 0 == HRESULT_CODE(hr)) { // A call failed without properly setting an error condition! hr = E_UNEXPECTED; } assert(FAILED(hr)); } return(hr); } HRESULT ceHLastError(VOID) { return(ceHError(GetLastError())); } VOID ceErrorPrintLine( IN char const *pszFile, IN DWORD line, IN char const *pszMessage, IN WCHAR const *pwszData, IN HRESULT hr) { CHAR ach[4096]; LONG cch; #pragma prefast(disable:53, "PREfast bug 650") cch = _snprintf( ach, sizeof(ach), "CeLib: Error: %hs(%u): %hs%hs%ws%hs 0x%x (%d)\n", pszFile, line, pszMessage, NULL == pwszData? "" : szLPAREN, NULL == pwszData? L"" : pwszData, NULL == pwszData? "" : szRPAREN, hr, hr); #pragma prefast(enable:53, "re-enable") if (0 > cch || sizeof(ach) <= cch) { strcpy(&ach[sizeof(ach) - 5], "...\n"); } OutputDebugStringA(ach); wprintf(L"%hs", ach); } HRESULT ceDateToFileTime( IN DATE const *pDate, OUT FILETIME *pft) { SYSTEMTIME st; HRESULT hr = S_OK; if (*pDate == 0.0) { GetSystemTime(&st); } else { if (!VariantTimeToSystemTime(*pDate, &st)) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); _JumpError(hr, error, "VariantTimeToSystemTime"); } } if (!SystemTimeToFileTime(&st, pft)) { hr = ceHLastError(); _JumpError(hr, error, "SystemTimeToFileTime"); } error: return(hr); } HRESULT ceFileTimeToDate( IN FILETIME const *pft, OUT DATE *pDate) { SYSTEMTIME st; HRESULT hr = S_OK; if (!FileTimeToSystemTime(pft, &st)) { hr = ceHLastError(); _JumpError(hr, error, "FileTimeToSystemTime"); } if (!SystemTimeToVariantTime(&st, pDate)) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); _JumpError(hr, error, "SystemTimeToVariantTime"); } error: return(hr); } VOID ceMakeExprDateTime( IN OUT FILETIME *pft, IN LONG lDelta, IN enum ENUM_PERIOD enumPeriod) { LLFILETIME llft; LONGLONG llDelta; BOOL fSysTimeDelta; llft.ft = *pft; llDelta = lDelta; fSysTimeDelta = FALSE; switch (enumPeriod) { case ENUM_PERIOD_WEEKS: llDelta *= CVT_WEEKS; break; case ENUM_PERIOD_DAYS: llDelta *= CVT_DAYS; break; case ENUM_PERIOD_HOURS: llDelta *= CVT_HOURS; break; case ENUM_PERIOD_MINUTES: llDelta *= CVT_MINUTES; break; case ENUM_PERIOD_SECONDS: break; default: fSysTimeDelta = TRUE; break; } if (fSysTimeDelta) { SYSTEMTIME SystemTime; FileTimeToSystemTime(&llft.ft, &SystemTime); switch (enumPeriod) { case ENUM_PERIOD_MONTHS: if (0 > lDelta) { DWORD dwDelta = (DWORD) -lDelta; SystemTime.wYear -= (WORD) (dwDelta / 12) + 1; SystemTime.wMonth += 12 - (WORD) (dwDelta % 12); } else { SystemTime.wMonth = (WORD) lDelta + SystemTime.wMonth; } if (12 < SystemTime.wMonth) { SystemTime.wYear += (SystemTime.wMonth - 1) / 12; SystemTime.wMonth = ((SystemTime.wMonth - 1) % 12) + 1; } break; case ENUM_PERIOD_YEARS: SystemTime.wYear = (WORD) lDelta + SystemTime.wYear; break; default: SystemTime.wYear += 1; break; } DoConvert: if (!SystemTimeToFileTime(&SystemTime, &llft.ft)) { if (GetLastError() != ERROR_INVALID_PARAMETER) { assert(!"Unable to do time conversion"); return; } // In some cases we'll convert to an invalid month-end // only one month changes length from year to year if (SystemTime.wMonth == 2) { // > 29? try leap year if (SystemTime.wDay > 29) { SystemTime.wDay = 29; goto DoConvert; } // == 29? try non-leap year else if (SystemTime.wDay == 29) { SystemTime.wDay = 28; goto DoConvert; } } // sept (9), apr(4), jun(6), nov(11) all have 30 days else if ((SystemTime.wMonth == 9) || (SystemTime.wMonth == 4) || (SystemTime.wMonth == 6) || (SystemTime.wMonth == 11)) { if (SystemTime.wDay > 30) { SystemTime.wDay = 30; goto DoConvert; } } // should never get here assert(!"Month/year processing: inaccessible code"); return; } } else { llft.ll += llDelta * CVT_BASE; } *pft = llft.ft; } HRESULT ceMakeExprDate( IN OUT DATE *pDate, IN LONG lDelta, IN enum ENUM_PERIOD enumPeriod) { HRESULT hr; FILETIME ft; hr = ceDateToFileTime(pDate, &ft); _JumpIfError(hr, error, "ceDateToFileTime"); ceMakeExprDateTime(&ft, lDelta, enumPeriod); hr = ceFileTimeToDate(&ft, pDate); _JumpIfError(hr, error, "ceFileTimeToDate"); error: return(hr); } typedef struct _UNITSTABLE { WCHAR const *pwszString; enum ENUM_PERIOD enumPeriod; } UNITSTABLE; UNITSTABLE g_aut[] = { { wszPERIODSECONDS, ENUM_PERIOD_SECONDS }, { wszPERIODMINUTES, ENUM_PERIOD_MINUTES }, { wszPERIODHOURS, ENUM_PERIOD_HOURS }, { wszPERIODDAYS, ENUM_PERIOD_DAYS }, { wszPERIODWEEKS, ENUM_PERIOD_WEEKS }, { wszPERIODMONTHS, ENUM_PERIOD_MONTHS }, { wszPERIODYEARS, ENUM_PERIOD_YEARS }, }; #define CUNITSTABLEMAX (sizeof(g_aut)/sizeof(g_aut[0])) HRESULT ceTranslatePeriodUnits( IN WCHAR const *pwszPeriod, IN LONG lCount, OUT enum ENUM_PERIOD *penumPeriod, OUT LONG *plCount) { HRESULT hr; UNITSTABLE const *put; for (put = g_aut; put < &g_aut[CUNITSTABLEMAX]; put++) { if (0 == celstrcmpiL(pwszPeriod, put->pwszString)) { *penumPeriod = put->enumPeriod; if (0 > lCount) { lCount = MAXLONG; } *plCount = lCount; hr = S_OK; goto error; } } hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); error: return(hr); } //+------------------------------------------------------------------------- // ceVerifyObjIdA - verify the passed pszObjId is valid as per X.208 // // Encode and Decode the Object Id and make sure it suvives the round trip. // The first number must be 0, 1 or 2. // Enforce all characters are digits and dots. // Enforce that no dot starts or ends the Object Id, and disallow double dots. // Enforce there is at least one dot separator. // If the first number is 0 or 1, the second number must be between 0 & 39. // If the first number is 2, the second number can be any value. //-------------------------------------------------------------------------- HRESULT ceVerifyObjIdA( IN CHAR const *pszObjId) { HRESULT hr; BYTE *pbEncoded = NULL; DWORD cbEncoded; CRYPT_ATTRIBUTE ainfo; CRYPT_ATTRIBUTE *painfo = NULL; DWORD cbainfo; char const *psz; int i; ainfo.pszObjId = const_cast(pszObjId); ainfo.cValue = 0; ainfo.rgValue = NULL; if (!ceEncodeObject( X509_ASN_ENCODING, PKCS_ATTRIBUTE, &ainfo, 0, FALSE, &pbEncoded, &cbEncoded)) { hr = ceHLastError(); _JumpError(hr, error, "ceEncodeObject"); } if (!ceDecodeObject( X509_ASN_ENCODING, PKCS_ATTRIBUTE, pbEncoded, cbEncoded, FALSE, (VOID **) &painfo, &cbainfo)) { hr = ceHLastError(); _JumpError(hr, error, "ceDecodeObject"); } hr = E_INVALIDARG; if (0 != strcmp(ainfo.pszObjId, painfo->pszObjId)) { _JumpError(hr, error, "bad ObjId: decode mismatch"); } for (psz = painfo->pszObjId; '\0' != *psz; psz++) { // must be a digit or a dot separator if (!isdigit(*psz)) { if ('.' != *psz) { _JumpError(hr, error, "bad ObjId: bad char"); } // can't have dot at start, double dots or dot at end if (psz == painfo->pszObjId || '.' == psz[1] || '\0' == psz[1]) { _JumpError(hr, error, "bad ObjId: dot location"); } } } psz = strchr(painfo->pszObjId, '.'); if (NULL == psz) { _JumpError(hr, error, "bad ObjId: must have at least one dot"); } i = atoi(painfo->pszObjId); switch (i) { case 0: case 1: i = atoi(++psz); if (0 > i || 39 < i) { _JumpError(hr, error, "bad ObjId: 0. or 1. must be followed by 0..39"); } break; case 2: break; default: _JumpError(hr, error, "bad ObjId: must start with 0, 1 or 2"); } hr = S_OK; error: if (NULL != pbEncoded) { LocalFree(pbEncoded); } if (NULL != painfo) { LocalFree(painfo); } return(hr); } HRESULT ceVerifyObjId( IN WCHAR const *pwszObjId) { HRESULT hr; CHAR *pszObjId = NULL; if (!ceConvertWszToSz(&pszObjId, pwszObjId, -1)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "ceConvertWszToSz"); } hr = ceVerifyObjIdA(pszObjId); _JumpIfErrorStr(hr, error, "ceVerifyObjIdA", pwszObjId); error: if (NULL != pszObjId) { LocalFree(pszObjId); } return(hr); } HRESULT ceVerifyAltNameString( IN LONG NameChoice, IN BSTR strName) { HRESULT hr = S_OK; CERT_ALT_NAME_INFO AltName; CERT_ALT_NAME_ENTRY Entry; CERT_OTHER_NAME OtherName; char *pszObjectId = NULL; DWORD cbEncoded; ZeroMemory(&AltName, sizeof(AltName)); AltName.cAltEntry = 1; AltName.rgAltEntry = &Entry; ZeroMemory(&Entry, sizeof(Entry)); Entry.dwAltNameChoice = NameChoice; switch (NameChoice) { case CERT_ALT_NAME_RFC822_NAME: Entry.pwszRfc822Name = strName; break; case CERT_ALT_NAME_DNS_NAME: Entry.pwszDNSName = strName; break; case CERT_ALT_NAME_URL: Entry.pwszURL = strName; break; case CERT_ALT_NAME_REGISTERED_ID: if (!ceConvertWszToSz(&pszObjectId, strName, -1)) { hr = E_OUTOFMEMORY; ceERRORPRINTLINE("ceConvertWszToSz", hr); goto error; } Entry.pszRegisteredID = pszObjectId; break; case CERT_ALT_NAME_OTHER_NAME: Entry.pOtherName = &OtherName; OtherName.pszObjId = szOID_NT_PRINCIPAL_NAME; OtherName.Value.cbData = SysStringByteLen(strName); OtherName.Value.pbData = (BYTE *) strName; break; case CERT_ALT_NAME_DIRECTORY_NAME: Entry.DirectoryName.cbData = SysStringByteLen(strName); Entry.DirectoryName.pbData = (BYTE *) strName; break; case CERT_ALT_NAME_IP_ADDRESS: Entry.IPAddress.cbData = SysStringByteLen(strName); Entry.IPAddress.pbData = (BYTE *) strName; break; //case CERT_ALT_NAME_X400_ADDRESS: //case CERT_ALT_NAME_EDI_PARTY_NAME: default: hr = E_INVALIDARG; ceERRORPRINTLINE("NameChoice", hr); goto error; } // Encode CERT_ALT_NAME_INFO: if (!CryptEncodeObject( X509_ASN_ENCODING, X509_ALTERNATE_NAME, &AltName, NULL, &cbEncoded)) { hr = ceHLastError(); ceERRORPRINTLINE("ceEncodeObject", hr); goto error; } error: if (NULL != pszObjectId) { LocalFree(pszObjectId); } return(hr); } HRESULT ceDispatchSetErrorInfoSub( IN HRESULT hrError, OPTIONAL IN WCHAR const *pwszIDispatchMethod, OPTIONAL IN WCHAR const *pwszDescription, OPTIONAL IN WCHAR const *pwszSource, OPTIONAL IN IID const *piid, OPTIONAL IN WCHAR const *pwszHelpFile, IN DWORD dwHelpFileContext) { HRESULT hr; WCHAR const *pwszError = NULL; ICreateErrorInfo *pCreateErrorInfo = NULL; IErrorInfo *pErrorInfo = NULL; if (NULL != pwszIDispatchMethod) { pwszError = ceGetErrorMessageText(hrError, TRUE); } hr = CreateErrorInfo(&pCreateErrorInfo); _JumpIfError(hr, error, "CreateErrorInfo"); if (NULL != piid) { hr = pCreateErrorInfo->SetGUID(*piid); _PrintIfError(hr, "SetGUID"); } if (NULL != pwszSource) { hr = pCreateErrorInfo->SetSource(const_cast(pwszSource)); _PrintIfError(hr, "SetSource"); } if (NULL != pwszDescription) { hr = pCreateErrorInfo->SetDescription( const_cast(pwszDescription)); _PrintIfError(hr, "SetDescription"); } if (NULL != pwszHelpFile) { hr = pCreateErrorInfo->SetHelpFile(const_cast(pwszHelpFile)); _PrintIfError(hr, "SetHelpFile"); hr = pCreateErrorInfo->SetHelpContext(dwHelpFileContext); _PrintIfError(hr, "SetHelpContext"); } hr = pCreateErrorInfo->QueryInterface( IID_IErrorInfo, (VOID **) &pErrorInfo); _JumpIfError(hr, error, "QueryInterface"); SetErrorInfo(0, pErrorInfo); hr = S_OK; error: if (NULL != pwszError) { LocalFree(const_cast(pwszError)); } if (NULL != pErrorInfo) { pErrorInfo->Release(); } if (NULL != pCreateErrorInfo) { pCreateErrorInfo->Release(); } return(hr); } HRESULT ceDispatchSetErrorInfo( IN HRESULT hrError, IN WCHAR const *pwszDescription, OPTIONAL IN WCHAR const *pwszProgId, OPTIONAL IN IID const *piid) { HRESULT hr; WCHAR const *pwszError = NULL; WCHAR *pwszText = NULL; if (NULL == pwszDescription) { hr = E_POINTER; _JumpError(hr, error, "NULL pointer"); } assert(FAILED(hrError)); pwszError = ceGetErrorMessageText(hrError, TRUE); if (NULL == pwszError) { _PrintError(E_OUTOFMEMORY, "myGetErrorMessageText"); } else { pwszText = (WCHAR *) LocalAlloc( LMEM_FIXED, (wcslen(pwszDescription) + 1 + wcslen(pwszError) + 1) * sizeof(WCHAR)); if (NULL == pwszText) { _PrintError(E_OUTOFMEMORY, "LocalAlloc"); } else { wcscpy(pwszText, pwszDescription); wcscat(pwszText, L" "); wcscat(pwszText, pwszError); } } hr = ceDispatchSetErrorInfoSub( hrError, NULL, // pwszIDispatchMethod NULL != pwszText? pwszText : const_cast(pwszDescription), pwszProgId, piid, NULL, // pwszHelpFile 0); // dwHelpFileContext _PrintIfError(hr, "ceDispatchSetErrorInfoSub"); error: if (NULL != pwszText) { LocalFree(pwszText); } if (NULL != pwszError) { LocalFree(const_cast(pwszError)); } return(hrError); // return input error! } int ceWtoI( IN WCHAR const *string, OUT BOOL *pfValid) { HRESULT hr; WCHAR szBuf[16]; WCHAR *szTmp = szBuf; int cTmp = ARRAYSIZE(szBuf); int i = 0; WCHAR const *pwsz; BOOL fSawDigit = FALSE; if (pfValid == NULL) { hr = E_POINTER; _JumpError(hr, error, "NULLPARAM"); } *pfValid = FALSE; assert(NULL != pfValid); cTmp = FoldString( MAP_FOLDDIGITS, string, -1, szTmp, cTmp); if (cTmp == 0) { hr = ceHLastError(); if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) == hr) { hr = S_OK; cTmp = FoldString( MAP_FOLDDIGITS, string, -1, NULL, 0); szTmp = (WCHAR*)LocalAlloc(LMEM_FIXED, cTmp*sizeof(WCHAR)); if (NULL == szTmp) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } cTmp = FoldString( MAP_FOLDDIGITS, string, -1, szTmp, cTmp); if (cTmp == 0) hr = ceHLastError(); } _JumpIfError(hr, error, "FoldString"); } pwsz = szTmp; while (iswspace(*pwsz)) { pwsz++; } while (iswdigit(*pwsz)) { fSawDigit = TRUE; pwsz++; } while (iswspace(*pwsz)) { pwsz++; } if (L'\0' == *pwsz) { *pfValid = fSawDigit; } i = _wtoi(szTmp); error: if (szTmp && (szTmp != szBuf)) LocalFree(szTmp); return i; } HRESULT ceGetMachineDnsName( OUT WCHAR **ppwszDnsName) { HRESULT hr; WCHAR *pwszDnsName = NULL; DWORD cwc; COMPUTER_NAME_FORMAT NameType = ComputerNameDnsFullyQualified; *ppwszDnsName = NULL; while (TRUE) { cwc = 0; if (!GetComputerNameEx(NameType, NULL, &cwc)) { hr = ceHLastError(); if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr && ComputerNameDnsFullyQualified == NameType) { _PrintError(hr, "GetComputerNameEx(DnsFullyQualified) -- switching to NetBIOS"); NameType = ComputerNameNetBIOS; continue; } if (HRESULT_FROM_WIN32(ERROR_MORE_DATA) != hr) { _JumpError(hr, error, "GetComputerNameEx"); } break; } } pwszDnsName = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR)); if (NULL == pwszDnsName) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } if (!GetComputerNameEx(NameType, pwszDnsName, &cwc)) { hr = ceHLastError(); _JumpError(hr, error, "GetComputerNameEx"); } *ppwszDnsName = pwszDnsName; pwszDnsName = NULL; hr = S_OK; error: if (NULL != pwszDnsName) { LocalFree(pwszDnsName); } return(hr); } HRESULT ceGetComputerNames( OUT WCHAR **ppwszDnsName, OUT WCHAR **ppwszOldName) { HRESULT hr; DWORD cwc; WCHAR *pwszOldName = NULL; *ppwszOldName = NULL; *ppwszDnsName = NULL; cwc = MAX_COMPUTERNAME_LENGTH + 1; pwszOldName = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR)); if (NULL == pwszOldName) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } if (!GetComputerName(pwszOldName, &cwc)) { hr = ceHLastError(); _JumpError(hr, error, "GetComputerName"); } hr = ceGetMachineDnsName(ppwszDnsName); _JumpIfError(hr, error, "ceGetMachineDnsName"); *ppwszOldName = pwszOldName; pwszOldName = NULL; error: if (NULL != pwszOldName) { LocalFree(pwszOldName); } return(hr); } HRESULT _IsConfigLocal( IN WCHAR const *pwszConfig, IN WCHAR const *pwszDnsName, IN WCHAR const *pwszOldName, OPTIONAL OUT WCHAR **ppwszMachine, OUT BOOL *pfLocal) { HRESULT hr; WCHAR *pwszMachine = NULL; WCHAR const *pwsz; DWORD cwc; *pfLocal = FALSE; if (NULL != ppwszMachine) { *ppwszMachine = NULL; } while (L'\\' == *pwszConfig) { pwszConfig++; } pwsz = wcschr(pwszConfig, L'\\'); if (NULL != pwsz) { cwc = SAFE_SUBTRACT_POINTERS(pwsz, pwszConfig); } else { cwc = wcslen(pwszConfig); } pwszMachine = (WCHAR *) LocalAlloc(LMEM_FIXED, (cwc + 1) * sizeof(WCHAR)); if (NULL == pwszMachine) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } CopyMemory(pwszMachine, pwszConfig, cwc * sizeof(WCHAR)); pwszMachine[cwc] = L'\0'; if (0 == celstrcmpiL(pwszMachine, pwszDnsName) || 0 == celstrcmpiL(pwszMachine, pwszOldName)) { *pfLocal = TRUE; } if (NULL != ppwszMachine) { *ppwszMachine = pwszMachine; pwszMachine = NULL; } hr = S_OK; error: if (NULL != pwszMachine) { LocalFree(pwszMachine); } return(hr); } HRESULT ceIsConfigLocal( IN WCHAR const *pwszConfig, OPTIONAL OUT WCHAR **ppwszMachine, OUT BOOL *pfLocal) { HRESULT hr; WCHAR *pwszDnsName = NULL; WCHAR *pwszOldName = NULL; *pfLocal = FALSE; if (NULL != ppwszMachine) { *ppwszMachine = NULL; } hr = ceGetComputerNames(&pwszDnsName, &pwszOldName); _JumpIfError(hr, error, "ceGetComputerNames"); hr = _IsConfigLocal( pwszConfig, pwszDnsName, pwszOldName, ppwszMachine, pfLocal); _JumpIfError(hr, error, "_IsConfigLocal"); error: if (NULL != pwszDnsName) { LocalFree(pwszDnsName); } if (NULL != pwszOldName) { LocalFree(pwszOldName); } return(hr); } HRESULT ceBuildPathAndExt( IN WCHAR const *pwszDir, IN WCHAR const *pwszFile, OPTIONAL IN WCHAR const *pwszExt, OUT WCHAR **ppwszPath) { HRESULT hr; WCHAR *pwsz; DWORD cwc; *ppwszPath = NULL; cwc = wcslen(pwszDir) + 1 + wcslen(pwszFile) + 1; if (NULL != pwszExt) { cwc += wcslen(pwszExt); } pwsz = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR)); if (NULL == pwsz) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } wcscpy(pwsz, pwszDir); if (L'\\' != pwsz[wcslen(pwsz) - 1]) { wcscat(pwsz, L"\\"); } wcscat(pwsz, pwszFile); if (NULL != pwszExt) { wcscat(pwsz, pwszExt); } *ppwszPath = pwsz; hr = S_OK; error: return(hr); } // Locale-independent case-ignore string compare int celstrcmpiL( IN WCHAR const *pwsz1, IN WCHAR const *pwsz2) { // CSTR_LESS_THAN(1) - CSTR_EQUAL(2) == -1 string 1 less than string 2 // CSTR_EQUAL(2) - CSTR_EQUAL(2) == 0 string 1 equal to string 2 // CSTR_GREATER_THAN(3) - CSTR_EQUAL(2) == 1 string 1 greater than string 2 return(CompareString( LOCALE_INVARIANT, NORM_IGNORECASE, pwsz1, -1, pwsz2, -1) - CSTR_EQUAL); }