#include #include #include DECLARE_INFOLEVEL(ol) #define ntfsChk(a) olChk(a) #define ntfsErr(a,b) olErr(a,b) #define ntfsDebugOut(a) olDebugOut(a) #define ntfsAssert(a) olAssert(a) //+--------------------------------------------------------------------------- // // Function: DfOpenStorageEx // // Synopsis: Open storage and stream objects // // Arguments: [pwcsUsersName] - pathanme of the file // [fCreateAPI] - create or open // [grfMode] - open mode flags // [grfAttrs] - reserved // [stgfmt] - storage format // [pSecurity] - reserved // [pTransaction] - reserved // [riid] - GUID of interface pointer to return // [ppObjectOpen] - interface pointer to return // Returns: Appropriate status code // // History: 12-Jul-95 HenryLee Created // //---------------------------------------------------------------------------- STDAPI DfOpenStorageEx ( const WCHAR* pwcsUsersName, BOOL fCreateAPI, // create vs open DWORD grfMode, DWORD stgfmt, // enum DWORD grfAttrs, // reserved STGOPTIONS *pStgOptions, void * reserved, WCHAR * pwcsNameSnapshot, REFIID riid, void ** ppObjectOpen) { HRESULT sc = S_OK; DWORD dwFullPathLen; WCHAR awcsFullName[_MAX_PATH], *pwcsFile; // // The ANY and STORAGE formats recursivly call back through here // for the correct real format (DOCFILE, NATIVE or FILE). We only call // GetFullPathName on real formats, to avoid redundant calls as we // recurse. // This then *requires* that the ANY and STORAGE must recurse (i.e. can't // call NFFOpen or NSS directly) because the filename has not been // properly prepared. // // For STGFMT_DOCFILE, let the docfile layer handle name checking // if(STGFMT_ANY != stgfmt && STGFMT_STORAGE != stgfmt && STGFMT_DOCFILE != stgfmt) { dwFullPathLen = GetFullPathNameW(pwcsUsersName, _MAX_PATH, awcsFullName,&pwcsFile); if (dwFullPathLen == 0) { DWORD dwErr = GetLastError(); // In some circumstances (name == " ", for instance), // GetFullPathNameW can return 0 and GetLastError returns 0. // We want to return STG_E_INVALIDNAME for these. if (dwErr != NOERROR) { ntfsErr(EH_Err, Win32ErrorToScode(dwErr)); } else { ntfsErr(EH_Err, STG_E_INVALIDNAME); } } else if (dwFullPathLen > _MAX_PATH) ntfsErr(EH_Err, STG_E_PATHNOTFOUND); } //----------------------------------------- // Switch on STGFMT_ // STORAGE, NATIVE, DOCFILE, FILE, ANY // switch(stgfmt) { case STGFMT_FILE: { ntfsChk( NFFOpen( awcsFullName, grfMode, NFFOPEN_NORMAL, fCreateAPI, riid, ppObjectOpen) ); } // case STGFMT_FILE break; case STGFMT_ANY: { DWORD stgfmt=STGFMT_STORAGE; // // Attempting to CREATE a Storage with STGFMT_ANY is ambiguous, // On NTFS either STGFMT_NATIVE or STGFMT_FILE could be appropriate, // and is therefore invalid. // if (fCreateAPI) ntfsChk (STG_E_INVALIDPARAMETER); // // If the file is a storage then try STGFMT_STORAGE. // Otherwise try STGFMT_FILE. // If StgIsStorageFile() error'ed go ahead into the STGFMT_STORAGE // for consistant error return values. // if( S_OK == CNtfsStorage::IsNffAppropriate( pwcsUsersName ) ) stgfmt = STGFMT_FILE; sc = DfOpenStorageEx (pwcsUsersName, fCreateAPI, grfMode, stgfmt, grfAttrs, pStgOptions, reserved, pwcsNameSnapshot, riid, ppObjectOpen); ntfsChk(sc); } // case STGFMT_ANY; break; default: ntfsErr (EH_Err, STG_E_INVALIDPARAMETER); break; } EH_Err: return sc; }; //+--------------------------------------------------------------------------- // // Function: StgCreateStorageEx, public // // Synopsis: Creates a storage or stream object // // Arguments: [pwcsName] - pathname of file // [grfMode] - open mode flags // [stgfmt] - storage format // [grfAttrs] - reserved // [pSecurity] - reserved // [pTransaction] - reserved // [riid] - GUID of interface pointer to return // [ppObjectOpen] - interface pointer to return // // Returns: Appropriate status code // // History: 12-Jul-95 HenryLee Created // //---------------------------------------------------------------------------- typedef HRESULT (*PFNStgCreateStorageEx)( const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, void *pSecurity, void *pTransaction, REFIID riid, void **ppObjectOpen ); typedef HRESULT (*PFNStgOpenStorageEx)( const WCHAR *pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, void *pSecurity, void *pTransaction, REFIID riid, void **ppObjectOpen ); HINSTANCE HInstOle32() { static HINSTANCE hinstOLE32 = NULL; if( NULL == hinstOLE32 ) hinstOLE32 = LoadLibrary( TEXT("ole32.dll") ); return( hinstOLE32 ); } WINOLEAPI StgCreateStorageEx (IN const WCHAR* pwcsName, IN DWORD grfMode, IN DWORD stgfmt, // enum IN DWORD grfAttrs, // reserved IN STGOPTIONS * pStgOptions, IN void * reserved, IN REFIID riid, OUT void ** ppObjectOpen) { HRESULT sc = S_OK; WCHAR awcsTmpPath[_MAX_PATH]; ntfsChk(ValidatePtrBuffer(ppObjectOpen)); *ppObjectOpen = NULL; if (grfAttrs != 0) ntfsErr(EH_Err, STG_E_INVALIDFLAG); if ((grfMode & STGM_RDWR) == STGM_READ || (grfMode & (STGM_DELETEONRELEASE | STGM_CONVERT)) == (STGM_DELETEONRELEASE | STGM_CONVERT)) ntfsErr(EH_Err, STG_E_INVALIDFLAG); if( STGFMT_FILE == stgfmt && (IID_IPropertySetStorage == riid || IID_IStorage == riid || IID_IPropertyBagEx == riid) ) { ntfsChk (DfOpenStorageEx (pwcsName, TRUE, grfMode, stgfmt, grfAttrs, pStgOptions, reserved, NULL, riid, ppObjectOpen)); } else { static PFNStgCreateStorageEx pfnStgCreateStorageEx = NULL; if( NULL == pfnStgCreateStorageEx ) pfnStgCreateStorageEx = (PFNStgCreateStorageEx) GetProcAddress( HInstOle32(), "StgCreateStorageEx" ); if( NULL == pfnStgCreateStorageEx ) ntfsChk( E_FAIL ); ntfsChk( pfnStgCreateStorageEx( pwcsName, grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen )); } ntfsDebugOut((DEB_TRACE, "Out StgCreateStorageEx => %p\n", *ppObjectOpen)); EH_Err: return sc; } //+--------------------------------------------------------------------------- // // Function: StgOpenStorageEx // // Synopsis: Open storage and stream objects // // Arguments: [pwcsName] - pathanme of the file // [grfMode] - open mode flags // [grfAttrs] - reserved // [stgfmt] - storage format // [pSecurity] - reserved // [pTransaction] - reserved // [riid] - GUID of interface pointer to return // [ppObjectOpen] - interface pointer to return // Returns: Appropriate status code // // History: 12-Jul-95 HenryLee Created // //---------------------------------------------------------------------------- WINOLEAPI StgOpenStorageEx (IN const WCHAR* pwcsName, IN DWORD grfMode, IN DWORD stgfmt, // enum IN DWORD grfAttrs, // reserved IN STGOPTIONS * pStgOptions, IN void * reserved, IN REFIID riid, OUT void ** ppObjectOpen) { HRESULT sc = S_OK; WCHAR awcsTmpPath[_MAX_PATH]; WCHAR * pwcsNameSnapshot = NULL; ntfsDebugOut((DEB_TRACE, "In StgOpenStorageEx(%ws, %p, %p, %p, %p)\n", pwcsName, grfMode, stgfmt, riid, ppObjectOpen)); ntfsChk(ValidatePtrBuffer(ppObjectOpen)); *ppObjectOpen = NULL; if (pStgOptions!= NULL || reserved != NULL) ntfsErr (EH_Err, STG_E_INVALIDPARAMETER); if (grfAttrs != 0) ntfsErr(EH_Err, STG_E_INVALIDFLAG); ntfsChk (ValidateNameW (pwcsName, _MAX_PATH)); if( (IID_IPropertySetStorage == riid || IID_IStorage == riid || IID_IPropertyBagEx == riid) && ( STGFMT_FILE == stgfmt || STGFMT_ANY == stgfmt && S_OK != StgIsStorageFile(pwcsName) ) ) { ntfsChk (DfOpenStorageEx (pwcsName, FALSE, grfMode, stgfmt, grfAttrs, pStgOptions, reserved, pwcsNameSnapshot, riid, ppObjectOpen)); } else { static PFNStgOpenStorageEx pfnStgOpenStorageEx = NULL; if( NULL == pfnStgOpenStorageEx ) pfnStgOpenStorageEx = (PFNStgOpenStorageEx) GetProcAddress( HInstOle32(), "StgOpenStorageEx" ); if( NULL == pfnStgOpenStorageEx ) ntfsChk( E_FAIL ); ntfsChk( pfnStgOpenStorageEx( pwcsName, grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen )); } ntfsDebugOut((DEB_TRACE, "Out StgOpenStorageEx => %p\n", *ppObjectOpen)); EH_Err: return sc; } // Copied from stg\docfile\funcs.cxx #ifdef WIN32 SCODE Win32ErrorToScode(DWORD dwErr) { olAssert((dwErr != NO_ERROR) && aMsg("Win32ErrorToScode called on NO_ERROR")); SCODE sc = STG_E_UNKNOWN; switch (dwErr) { case ERROR_INVALID_FUNCTION: sc = STG_E_INVALIDFUNCTION; break; case ERROR_FILE_NOT_FOUND: sc = STG_E_FILENOTFOUND; break; case ERROR_PATH_NOT_FOUND: sc = STG_E_PATHNOTFOUND; break; case ERROR_TOO_MANY_OPEN_FILES: sc = STG_E_TOOMANYOPENFILES; break; case ERROR_ACCESS_DENIED: case ERROR_NETWORK_ACCESS_DENIED: sc = STG_E_ACCESSDENIED; break; case ERROR_INVALID_HANDLE: sc = STG_E_INVALIDHANDLE; break; case ERROR_NOT_ENOUGH_MEMORY: sc = STG_E_INSUFFICIENTMEMORY; break; case ERROR_NO_MORE_FILES: sc = STG_E_NOMOREFILES; break; case ERROR_WRITE_PROTECT: sc = STG_E_DISKISWRITEPROTECTED; break; case ERROR_SEEK: sc = STG_E_SEEKERROR; break; case ERROR_WRITE_FAULT: sc = STG_E_WRITEFAULT; break; case ERROR_READ_FAULT: sc = STG_E_READFAULT; break; case ERROR_SHARING_VIOLATION: sc = STG_E_SHAREVIOLATION; break; case ERROR_LOCK_VIOLATION: sc = STG_E_LOCKVIOLATION; break; case ERROR_HANDLE_DISK_FULL: case ERROR_DISK_FULL: sc = STG_E_MEDIUMFULL; break; case ERROR_FILE_EXISTS: case ERROR_ALREADY_EXISTS: sc = STG_E_FILEALREADYEXISTS; break; case ERROR_INVALID_PARAMETER: sc = STG_E_INVALIDPARAMETER; break; case ERROR_INVALID_NAME: case ERROR_BAD_PATHNAME: case ERROR_FILENAME_EXCED_RANGE: sc = STG_E_INVALIDNAME; break; case ERROR_INVALID_FLAGS: sc = STG_E_INVALIDFLAG; break; default: sc = WIN32_SCODE(dwErr); break; } return sc; } #endif //+-------------------------------------------------------------- // // Function: ValidateSNB, private // // Synopsis: Validates SNB memory // // Arguments: [snb] - SNB // // Returns: Appropriate status code // // History: 10-Jun-92 DrewB Created // //--------------------------------------------------------------- #include // ***** From stg\docfile\funcs.cxx SCODE ValidateSNB(SNBW snb) { SCODE sc; olDebugOut((DEB_ITRACE, "In ValidateSNB(%p)\n", snb)); for (;;) { olChk(ValidatePtrBuffer(snb)); if (*snb == NULL) break; olChk(ValidateNameW(*snb, CWCMAXPATHCOMPLEN)); snb++; } olDebugOut((DEB_ITRACE, "Out ValidateSNB\n")); return S_OK; EH_Err: return sc; } //+-------------------------------------------------------------- // // Function: CheckName, public // // Synopsis: Checks name for illegal characters and length // // Arguments: [pwcsName] - Name // // Returns: Appropriate status code // // History: 11-Feb-92 DrewB Created // 04-Dec-95 SusiA Optimized // //--------------------------------------------------------------- // ***** From stg\docfile\funcs.cxx #ifdef OLEWIDECHAR SCODE CheckName(WCHAR const *pwcsName) { LPCWSTR pChar; //Each character's position in the array is detrmined by its ascii numeric //value. ":" is 58, so bit 58 of the array will be 1 if ":" is illegal. //32bits per position in the array, so 58/32 is in Invalid[1]. //58%32 = 28th bit ( 0x04000000 ) in Invalid[1]. /* Invalid characters: : / ! \ */ static ULONG const Invalid[128/32] = {0x00000000,0x04008002,0x10000000,0x00000000}; SCODE sc = STG_E_INVALIDNAME; olDebugOut((DEB_ITRACE, "In CheckName(%ws)\n", pwcsName)); __try { for (pChar = (LPCWSTR)pwcsName; pChar <= (LPCWSTR) &pwcsName[CWCMAXPATHCOMPLEN]; pChar++) { if (*pChar == L'\0') { sc = S_OK; break; // Success } // Test to see if this is an invalid character if (*pChar < 128 && // All values above 128 are valid (Invalid[*pChar / 32] & (1 << (*pChar % 32))) != 0) // check to see if this character's bit is set { break; // Failure: invalid Char } } } __except (EXCEPTION_EXECUTE_HANDLER) { } olDebugOut((DEB_ITRACE, "Out CheckName\n")); return sc; } #endif /* // Forwarders to the nt5props.dll version of the property APIs. EXTERN_C HRESULT PrivPropVariantCopy ( PROPVARIANT * pvarDest, const PROPVARIANT * pvarSrc ) { return( PropVariantCopy( pvarDest, pvarSrc )); } EXTERN_C HRESULT PrivPropVariantClear ( PROPVARIANT * pvar ) { return( PropVariantClear( pvar )); } EXTERN_C HRESULT PrivFreePropVariantArray ( ULONG cVariants, PROPVARIANT * rgvars ) { return( FreePropVariantArray( cVariants, rgvars )); } EXTERN_C ULONG PrivStgPropertyLengthAsVariant( IN SERIALIZEDPROPERTYVALUE const *pprop, IN ULONG cbprop, IN USHORT CodePage, IN BYTE flags ) { return( StgPropertyLengthAsVariant( pprop, cbprop, CodePage, flags )); } EXTERN_C SERIALIZEDPROPERTYVALUE * PrivStgConvertVariantToProperty( IN PROPVARIANT const *pvar, IN USHORT CodePage, OPTIONAL OUT SERIALIZEDPROPERTYVALUE *pprop, IN OUT ULONG *pcb, IN PROPID pid, IN BOOLEAN fVariantVectorOrArray, // Used for recursive calls OPTIONAL OUT ULONG *pcIndirect) { return( StgConvertVariantToProperty( pvar, CodePage, pprop, pcb, pid, fVariantVectorOrArray, pcIndirect )); } */ //+-------------------------------------------------------------- // // Function: VerifyPerms, private // // Synopsis: Checks flags to see if they are valid // // Arguments: [grfMode] - Permissions // [fRoot] - TRUE if checking root storage // // Returns: Appropriate status code // // Notes: This routine is called when opening a root storage // or a subelement. When changing root permissions, // use the fRoot flag to preserve compatibily for // return codes when opening subelements // // History: 19-Mar-92 DrewB Created // //--------------------------------------------------------------- SCODE VerifyPerms(DWORD grfMode, BOOL fRoot) { SCODE sc = S_OK; olDebugOut((DEB_ITRACE, "In VerifyPerms(%lX)\n", grfMode)); // Check for valid flags if ((grfMode & STGM_RDWR) > STGM_READWRITE || (grfMode & STGM_DENY) > STGM_SHARE_DENY_NONE || (grfMode & ~(STGM_RDWR | STGM_DENY | STGM_DIRECT | STGM_TRANSACTED | STGM_PRIORITY | STGM_CREATE | STGM_CONVERT | STGM_NOSCRATCH | #ifndef DISABLE_NOSNAPSHOT STGM_NOSNAPSHOT | #endif #if WIN32 >= 300 STGM_EDIT_ACCESS_RIGHTS | #endif STGM_FAILIFTHERE | STGM_DELETEONRELEASE))) olErr(EH_Err, STG_E_INVALIDFLAG); // If priority is specified... if (grfMode & STGM_PRIORITY) { // Make sure no priority-denied permissions are specified if ((grfMode & STGM_RDWR) == STGM_WRITE || (grfMode & STGM_RDWR) == STGM_READWRITE || (grfMode & STGM_TRANSACTED)) olErr(EH_Err, STG_E_INVALIDFLAG); } // Check to make sure only one existence flag is specified // FAILIFTHERE is zero so it can't be checked if ((grfMode & (STGM_CREATE | STGM_CONVERT)) == (STGM_CREATE | STGM_CONVERT)) olErr(EH_Err, STG_E_INVALIDFLAG); // If not transacted and not priority, you can either be // read-only deny write or read-write deny all if ((grfMode & (STGM_TRANSACTED | STGM_PRIORITY)) == 0) { if ((grfMode & STGM_RDWR) == STGM_READ) { // we're asking for read-only access if ((grfMode & STGM_DENY) != STGM_SHARE_EXCLUSIVE && #ifdef DIRECTWRITERLOCK (!fRoot || (grfMode & STGM_DENY) != STGM_SHARE_DENY_NONE) && #endif (grfMode & STGM_DENY) != STGM_SHARE_DENY_WRITE) { // Can't allow others to have write access olErr(EH_Err, STG_E_INVALIDFLAG); } } else { // we're asking for write access #ifdef DIRECTWRITERLOCK if ((grfMode & STGM_DENY) != STGM_SHARE_EXCLUSIVE && (!fRoot || (grfMode & STGM_DENY) != STGM_SHARE_DENY_WRITE)) #else if ((grfMode & STGM_DENY) != STGM_SHARE_EXCLUSIVE) #endif { // Can't allow others to have any access olErr(EH_Err, STG_E_INVALIDFLAG); } } } //If this is not a root open, we can't pass STGM_NOSCRATCH or // STGM_NOSNAPSHOT if (!fRoot && (grfMode & (STGM_NOSCRATCH | STGM_NOSNAPSHOT))) { olErr(EH_Err, STG_E_INVALIDFLAG); } if (grfMode & STGM_NOSCRATCH) { if (((grfMode & STGM_RDWR) == STGM_READ) || ((grfMode & STGM_TRANSACTED) == 0)) { olErr(EH_Err, STG_E_INVALIDFLAG); } } if (grfMode & STGM_NOSNAPSHOT) { if (((grfMode & STGM_DENY) == STGM_SHARE_EXCLUSIVE) || ((grfMode & STGM_DENY) == STGM_SHARE_DENY_WRITE) || ((grfMode & STGM_TRANSACTED) == 0) || ((grfMode & STGM_NOSCRATCH) != 0) || ((grfMode & STGM_CREATE) != 0) || ((grfMode & STGM_CONVERT) != 0)) { olErr(EH_Err, STG_E_INVALIDFLAG); } } olDebugOut((DEB_ITRACE, "Out VerifyPerms\n")); // Fall through EH_Err: return sc; } //+-------------------------------------------------------------- // // Function: StgIsStorageFileHandle, private // // Synopsis: Determines whether a handle is open on a storage file. // Spun off from StgIsStorageFile. Internaly we use this // // Arguments: [hf] - Open File Handle (caller must seek it to 0) // // Returns: S_OK, S_FALSE or error codes // // History: 07-May-98 MikeHill Created // 05-June-98 BChapman Return Errors not just S_FALSE. // Add optional Overlapped pointer. // //--------------------------------------------------------------- STDAPI StgIsStorageFileHandle( HANDLE hf, LPOVERLAPPED povlp ) { DWORD cbRead; BYTE stgHeader[sizeof(SStorageFile)]; SCODE sc; LONG status; OVERLAPPED ovlp; FillMemory( stgHeader, sizeof(SStorageFile), 0xDE ); if (povlp == NULL) { ovlp.Offset = 0; ovlp.OffsetHigh = 0; ovlp.hEvent = NULL; } if( !ReadFile( hf, &stgHeader, sizeof( stgHeader ), &cbRead, (povlp == NULL) ? &ovlp : povlp ) ) { if( NULL != povlp ) { status = GetLastError(); if( ERROR_IO_PENDING == status) { status = ERROR_SUCCESS; if( !GetOverlappedResult( hf, povlp, &cbRead, TRUE ) ) status = GetLastError(); } if(ERROR_SUCCESS != status && ERROR_HANDLE_EOF != status) olChk( HRESULT_FROM_WIN32( status ) ); } else olErr( EH_Err, LAST_STG_SCODE ); } // Don't worry about short reads. If the read is short then // the signature checks will fail. sc = CheckSignature( ((SStorageFile*)stgHeader)->abSig ); if(S_OK == sc) goto EH_Err; // Done, return "Yes" olChk(sc); // It didn't error. sc != S_OK then it // Must be S_FALSE. olAssert(S_FALSE == sc); EH_Err: if( (STG_E_OLDFORMAT == sc) || (STG_E_INVALIDHEADER == sc) ) sc = S_FALSE; return sc; } //+--------------------------------------------------------------------------- // // Function: CheckSignature, private // // Synopsis: Checks the given memory against known signatures // // Arguments: [pb] - Pointer to memory to check // // Returns: S_OK - Current signature // S_FALSE - Beta 2 signature, but still successful // Appropriate status code // // History: 23-Jul-93 DrewB Created from header.cxx code // //---------------------------------------------------------------------------- //Identifier for first bytes of Beta 1 Docfiles const BYTE SIGSTG_B1[] = {0xd0, 0xcf, 0x11, 0xe0, 0x0e, 0x11, 0xfc, 0x0d}; const USHORT CBSIGSTG_B1 = sizeof(SIGSTG_B1); //Identifier for first bytes of Beta 2 Docfiles const BYTE SIGSTG_B2[] = {0x0e, 0x11, 0xfc, 0x0d, 0xd0, 0xcf, 0x11, 0xe0}; const BYTE CBSIGSTG_B2 = sizeof(SIGSTG_B2); SCODE CheckSignature(BYTE *pb) { SCODE sc; olDebugOut((DEB_ITRACE, "In CheckSignature(%p)\n", pb)); // Check for ship Docfile signature first if (memcmp(pb, SIGSTG, CBSIGSTG) == 0) sc = S_OK; // Check for Beta 2 Docfile signature else if (memcmp(pb, SIGSTG_B2, CBSIGSTG_B2) == 0) sc = S_FALSE; // Check for Beta 1 Docfile signature else if (memcmp(pb, SIGSTG_B1, CBSIGSTG_B1) == 0) sc = STG_E_OLDFORMAT; else sc = STG_E_INVALIDHEADER; olDebugOut((DEB_ITRACE, "Out CheckSignature => %lX\n", sc)); return sc; } //+--------------------------------------------------------------------------- // // Function: dfwcsnicmp, public // // Synopsis: wide character string compare that interoperates with what // we did on 16-bit windows. // // Arguments: [wcsa] -- First string // [wcsb] -- Second string // [len] -- Length to compare to // // Returns: > 0 if wcsa > wcsb // < 0 if wcsa < wcsb // 0 is wcsa == wcsb // // History: 11-May-95 PhilipLa Created // 22-Nov-95 SusiA Optimize comparisons // // Notes: This function is necessary because on 16-bit windows our // wcsnicmp function converted everything to uppercase and // compared the strings, whereas the 32-bit runtimes convert // everything to lowercase and compare. This means that the // sort order is different for string containing [\]^_` // //---------------------------------------------------------------------------- int dfwcsnicmp(const WCHAR *wcsa, const WCHAR *wcsb, size_t len) { if (!len) return 0; while (--len && *wcsa && ( *wcsa == *wcsb || CharUpperW((LPWSTR)*wcsa) == CharUpperW((LPWSTR)*wcsb))) { wcsa++; wcsb++; } return (int)(LONG_PTR)CharUpperW((LPWSTR)*wcsa) - (int)(LONG_PTR)CharUpperW((LPWSTR)*wcsb); } //+--------------------------------------------------------------------------- // // Member: ValidateNameW, public // // Synopsis: Validate that a name is valid and no longer than the // size specified. // // Arguments: [pwcsName] -- Pointer to wide character string // [cchMax] -- Maximum length for string // // Returns: Appropriate status code // // History: 23-Nov-98 PhilipLa Created // // Notes: // //---------------------------------------------------------------------------- SCODE ValidateNameW(LPCWSTR pwcsName, UINT cchMax) { SCODE sc = S_OK; #if WIN32 == 200 if (IsBadReadPtrW(pwcsName, sizeof(WCHAR))) sc = STG_E_INVALIDNAME; #else if (IsBadStringPtrW(pwcsName, cchMax)) sc = STG_E_INVALIDNAME; #endif else { __try { if ((UINT)lstrlenW(pwcsName) >= cchMax) sc = STG_E_INVALIDNAME; } __except (EXCEPTION_EXECUTE_HANDLER) { sc = STG_E_INVALIDNAME; } } return sc; }