FCIMPLEND FCIMPL0(StringObject*, SystemNative::_GetModuleFileName) { FCALL_CONTRACT; STRINGREF refRetVal = NULL; HELPER_METHOD_FRAME_BEGIN_RET_1(refRetVal); if (g_pCachedModuleFileName) { refRetVal = StringObject::NewString(g_pCachedModuleFileName); } else { SString wszFilePathString; WCHAR * wszFile = wszFilePathString.OpenUnicodeBuffer(MAX_LONGPATH); DWORD lgth = WszGetModuleFileName(NULL, wszFile, MAX_LONGPATH); if (!lgth) { COMPlusThrowWin32(); } wszFilePathString.CloseBuffer(lgth); refRetVal = StringObject::NewString(wszFilePathString.GetUnicode()); } HELPER_METHOD_FRAME_END(); return (StringObject*)OBJECTREFToObject(refRetVal); }
VOID LogAssert( LPCSTR szFile, int iLine, LPCSTR szExpr ) { SYSTEMTIME st; GetSystemTime(&st); WCHAR exename[300]; WszGetModuleFileName(NULL, exename, sizeof(exename)/sizeof(WCHAR)); LOG((LF_ASSERT, LL_FATALERROR, "FAILED ASSERT(PID %d [0x%08x], Thread: %d [0x%x]) (%lu/%lu/%lu: %02lu:%02lu:%02lu %s): File: %s, Line %d : %s\n", GetCurrentProcessId(), GetCurrentProcessId(), GetCurrentThreadId(), GetCurrentThreadId(), (ULONG)st.wMonth, (ULONG)st.wDay, (ULONG)st.wYear, 1 + (( (ULONG)st.wHour + 11 ) % 12), (ULONG)st.wMinute, (ULONG)st.wSecond, (st.wHour < 12) ? "am" : "pm", szFile, iLine, szExpr)); LOG((LF_ASSERT, LL_FATALERROR, "RUNNING EXE: %ws\n", exename)); }
VOID LogAssert( LPCSTR szFile, int iLine, LPCSTR szExpr ) { STATIC_CONTRACT_NOTHROW; STATIC_CONTRACT_GC_NOTRIGGER; STATIC_CONTRACT_SO_TOLERANT; STATIC_CONTRACT_DEBUG_ONLY; // Log asserts to the stress log. Note that we can't include the szExpr b/c that // may not be a string literal (particularly for formatt-able asserts). STRESS_LOG2(LF_ASSERT, LL_ALWAYS, "ASSERT:%s, line:%d\n", szFile, iLine); SYSTEMTIME st; #ifndef FEATURE_PAL GetLocalTime(&st); #else GetSystemTime(&st); #endif WCHAR exename[300]; WszGetModuleFileName(NULL, exename, sizeof(exename)/sizeof(WCHAR)); LOG((LF_ASSERT, LL_FATALERROR, "FAILED ASSERT(PID %d [0x%08x], Thread: %d [0x%x]) (%lu/%lu/%lu: %02lu:%02lu:%02lu %s): File: %s, Line %d : %s\n", GetCurrentProcessId(), GetCurrentProcessId(), GetCurrentThreadId(), GetCurrentThreadId(), (ULONG)st.wMonth, (ULONG)st.wDay, (ULONG)st.wYear, 1 + (( (ULONG)st.wHour + 11 ) % 12), (ULONG)st.wMinute, (ULONG)st.wSecond, (st.wHour < 12) ? "am" : "pm", szFile, iLine, szExpr)); LOG((LF_ASSERT, LL_FATALERROR, "RUNNING EXE: %ws\n", exename)); }
// EventReporter::EventReporter(EventReporterType type) { CONTRACTL { THROWS; GC_NOTRIGGER; MODE_ANY; } CONTRACTL_END; m_eventType = type; HMODULE hModule = WszGetModuleHandle(NULL); PathString appPath; DWORD ret = WszGetModuleFileName(hModule, appPath); fBufferFull = FALSE; InlineSString<256> ssMessage; if(!ssMessage.LoadResource(CCompRC::Optional, IDS_ER_APPLICATION)) m_Description.Append(W("Application: ")); else { m_Description.Append(ssMessage); } // If we were able to get an app name. if (ret != 0) {
//***************************************************************************** // This function will handle ignore codes and tell the user what is happening. //***************************************************************************** int _DbgBreakCheck( LPCSTR szFile, int iLine, LPCSTR szExpr) { TCHAR rcBuff[1024+_MAX_PATH]; TCHAR rcPath[_MAX_PATH]; TCHAR rcTitle[64]; _DBGIGNOREDATA *psData; long i; if (DebugBreakOnAssert()) { DebugBreak(); } DBGIGNORE* pDBGIFNORE = GetDBGIGNORE(); // Check for ignore all. for (i=0, psData = pDBGIFNORE->Ptr(); i<pDBGIFNORE->Count(); i++, psData++) { if (psData->iLine == iLine && _stricmp(psData->rcFile, szFile) == 0 && psData->bIgnore == true) return (false); } // Give assert in output for easy access. WszGetModuleFileName(0, rcPath, NumItems(rcPath)); swprintf(rcBuff, L"Assert failure(PID %d [0x%08x], Thread: %d [0x%x]): %hs\n" L" File: %hs, Line: %d Image:\n%s\n", GetCurrentProcessId(), GetCurrentProcessId(), GetCurrentThreadId(), GetCurrentThreadId(), szExpr, szFile, iLine, rcPath); WszOutputDebugString(rcBuff); // Write out the error to the console printf("%S\n", rcBuff); LogAssert(szFile, iLine, szExpr); FlushLogging(); // make certain we get the last part of the log fflush(stdout); if (NoGuiOnAssert()) { TerminateOnAssert(); } if (DebugBreakOnAssert()) { return(true); // like a retry } // Change format for message box. The extra spaces in the title // are there to get around format truncation. swprintf(rcBuff, L"%hs\n\n%hs, Line: %d\n\nAbort - Kill program\nRetry - Debug\nIgnore - Keep running\n" L"\n\nImage:\n%s\n", szExpr, szFile, iLine, rcPath); swprintf(rcTitle, L"Assert Failure (PID %d, Thread %d/%x) ", GetCurrentProcessId(), GetCurrentThreadId(), GetCurrentThreadId()); // Tell user there was an error. _DbgBreakCount++; int ret = WszMessageBoxInternal(NULL, rcBuff, rcTitle, MB_ABORTRETRYIGNORE | MB_ICONEXCLAMATION | COMPLUS_MB_SERVICE_NOTIFICATION); --_DbgBreakCount; HMODULE hKrnl32; switch(ret) { // For abort, just quit the app. case IDABORT: TerminateProcess(GetCurrentProcess(), 1); // WszFatalAppExit(0, L"Shutting down"); break; // Tell caller to break at the correct loction. case IDRETRY: hKrnl32 = WszLoadLibrary(L"kernel32.dll"); _ASSERTE(hKrnl32 != NULL); if(hKrnl32) { typedef BOOL (WINAPI *t_pDbgPres)(); t_pDbgPres pFcn = (t_pDbgPres) GetProcAddress(hKrnl32, "IsDebuggerPresent"); // If this function is available, use it. if (pFcn) { if (pFcn()) { SetErrorMode(0); } else LaunchJITDebugger(); } FreeLibrary(hKrnl32); } return (true); // If we want to ignore the assert, find out if this is forever. case IDIGNORE: swprintf(rcBuff, L"Ignore the assert for the rest of this run?\nYes - Assert will never fire again.\nNo - Assert will continue to fire.\n\n%hs\nLine: %d\n", szFile, iLine); if (WszMessageBoxInternal(NULL, rcBuff, L"Ignore Assert Forever?", MB_ICONQUESTION | MB_YESNO | COMPLUS_MB_SERVICE_NOTIFICATION) != IDYES) break; if ((psData = pDBGIFNORE->Append()) == 0) return (false); psData->bIgnore = true; psData->iLine = iLine; strcpy(psData->rcFile, szFile); break; } return (false); }
//***************************************************************************** // This is a routine to try to find a class implementation given its fully // qualified name by using the CORPATH environment variable. CORPATH is a list // of directories (like PATH). Before checking CORPATH, this checks the current // directory, then the directory that the exe lives in. The search is // performed by parsing off one element at a time from the class name, // appending it to the directory and looking for a subdirectory or image with // that name. If the subdirectory exists, it drills down into that subdirectory // and tries the next element of the class name. When it finally bottoms out // but can't find the image it takes the rest of the fully qualified class name // and appends them with intervening '.'s trying to find a matching DLL. // Example: // // CORPATH=c:\bin;c:\prog // classname = namespace.class // // checks the following things in order: // c:\bin\namespace, (if <-exists) c:\bin\namespace\class.dll, // c:\bin\namespace.dll, c:\bin\namespace.class.dll // c:\prog\namespace, (if <-exists) c:\prog\namespace\class.dll, // c:\prog\namespace.dll, c:\prog\namespace.class.dll //***************************************************************************** HRESULT CORPATHService::GetClassFromCORPath( __in __in_z LPWSTR wzClassname, // [IN] fully qualified class name mdTypeRef tr, // [IN] TypeRef to be resolved. IMetaModelCommon *pCommon, // [IN] Scope in which the TypeRef is defined. REFIID riid, // [IN] Interface type to be returned. IUnknown **ppIScope, // [OUT] Scope in which the TypeRef resolves. mdTypeDef *ptd) // [OUT] typedef corresponding the typeref { WCHAR rcCorPath[1024] = {W('\0')}; // The CORPATH environment variable. LPWSTR szCorPath = rcCorPath; // Used to parse CORPATH. int iLen; // Length of the directory. WCHAR rcCorDir[_MAX_PATH]; // Buffer for the directory. WCHAR *temp; // Used as a parsing temp. WCHAR *szSemiCol; // Get the CORPATH environment variable. if (WszGetEnvironmentVariable(W("CORPATH"), rcCorPath, sizeof(rcCorPath) / sizeof(WCHAR))) { // Force nul termination. rcCorPath[lengthof(rcCorPath)-1] = 0; // Try each directory in the path. for(;*szCorPath != W('\0');) { // Get the next directory off the path. if ((szSemiCol = wcschr(szCorPath, W(';')))) { temp = szCorPath; *szSemiCol = W('\0'); szCorPath = szSemiCol + 1; } else { temp = szCorPath; szCorPath += wcslen(temp); } if ((iLen = (int)wcslen(temp)) >= _MAX_PATH) continue; wcscpy_s(rcCorDir, COUNTOF(rcCorDir), temp); // Check if we can find the class in the directory. if (CORPATHService::GetClassFromDir(wzClassname, rcCorDir, iLen, tr, pCommon, riid, ppIScope, ptd) == S_OK) return S_OK; } } //<TODO>These should go before the path search, but it will cause test // some headaches right now, so we'll give them a little time to transition.</TODO> // Try the current directory first. if ((iLen = WszGetCurrentDirectory(_MAX_PATH, rcCorDir)) > 0 && CORPATHService::GetClassFromDir(wzClassname, rcCorDir, iLen, tr, pCommon, riid, ppIScope, ptd) == S_OK) { return S_OK; } // Try the app directory next. if ((iLen = WszGetModuleFileName(NULL, rcCorDir, _MAX_PATH)) > 0) { // Back up to the last path separator. while (--iLen >= 0 && rcCorDir[iLen] != W('\\') && rcCorDir[iLen] != W('/')) { } if (iLen > 0 && CORPATHService::GetClassFromDir( wzClassname, rcCorDir, iLen, tr, pCommon, riid, ppIScope, ptd) == S_OK) { return (S_OK); } } // Couldn't find the class. return S_FALSE; } // CORPATHService::GetClassFromCORPath
LPSTR FillSymbolSearchPathThrows(CQuickBytes &qb) { STATIC_CONTRACT_GC_NOTRIGGER; STATIC_CONTRACT_CANNOT_TAKE_LOCK; SCAN_IGNORE_FAULT; // Faults from Wsz funcs are handled. #ifndef DACCESS_COMPILE // not allowed to do allocation if current thread suspends EE. if (IsSuspendEEThread ()) return NULL; #endif InlineSString<MAX_SYM_PATH> rcBuff ; // Working buffer WCHAR rcVerString[64]; // Extension for install directory. int chTotal = 0; // How full is working buffer. int ch; // If the NT symbol server path vars are there, then use those. chTotal = WszGetEnvironmentVariable(W("_NT_SYMBOL_PATH"), rcBuff); if (chTotal + 1 < MAX_SYM_PATH) rcBuff.Append(W(';')); // Copy the defacto NT symbol path as well. size_t sympathLength = chTotal + NumItems(DEFAULT_SYM_PATH) + 1; // integer overflow occurred if (sympathLength < (size_t)chTotal || sympathLength < NumItems(DEFAULT_SYM_PATH)) { return NULL; } if (sympathLength < MAX_SYM_PATH) { rcBuff.Append(DEFAULT_SYM_PATH); chTotal = rcBuff.GetCount(); } // Next, if there is a URTTARGET, add that since that is where ndpsetup places // your symobls on an install. PathString rcBuffTemp; ch = WszGetEnvironmentVariable(W("URTTARGET"), rcBuffTemp); rcBuff.Append(rcBuffTemp); if (ch != 0 && (chTotal + ch + 1 < MAX_SYM_PATH)) { size_t chNewTotal = chTotal + ch; if (chNewTotal < (size_t)chTotal || chNewTotal < (size_t)ch) { // integer overflow occurred return NULL; } chTotal += ch; rcBuff.Append(W(';')); } #ifndef SELF_NO_HOST // Fetch the path location of the engine dll and add that path as well, just // in case URTARGET didn't cut it either. // For no-host builds of utilcode, we don't necessarily have an engine DLL in the // process, so skip this part. ch = WszGetModuleFileName(GetCLRModuleHack(), rcBuffTemp); size_t pathLocationLength = chTotal + ch + 1; // integer overflow occurred if (pathLocationLength < (size_t)chTotal || pathLocationLength < (size_t)ch) { return NULL; } if (ch != 0 && (pathLocationLength < MAX_SYM_PATH)) { chTotal = chTotal + ch - NumItems(STR_ENGINE_NAME); rcBuff.Append(W(';')); } #endif // Now we have a working buffer with a bunch of interesting stuff. Time // to convert it back to ansi for the imagehlp api's. Allocate the buffer // 2x bigger to handle worst case for MBCS. ch = ::WszWideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, rcBuff, -1, 0, 0, 0, 0); LPSTR szRtn = (LPSTR) qb.AllocNoThrow(ch + 1); if (!szRtn) return NULL; WszWideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, rcBuff, -1, szRtn, ch+1, 0, 0); return (szRtn); }
void Disassembler::StaticInitialize() { LIMITED_METHOD_CONTRACT; #if USE_COREDISTOOLS_DISASSEMBLER _ASSERTE(!IsAvailable()); HMODULE libraryHandle = nullptr; PathString libPath; DWORD result = WszGetModuleFileName(nullptr, libPath); if (result == 0) { #ifdef _DEBUG wprintf( W("GetModuleFileName failed, function 'DisasmInstruction': error %u\n"), GetLastError()); #endif // _DEBUG return; } #if defined(FEATURE_PAL) WCHAR delim = W('/'); #else WCHAR delim = W('\\'); #endif LPCWSTR libFileName = MAKEDLLNAME(W("coredistools")); PathString::Iterator iter = libPath.End(); if (libPath.FindBack(iter, delim)) { libPath.Truncate(++iter); libPath.Append(libFileName); } else { _ASSERTE(!"unreachable"); } LPCWSTR libraryName = libPath.GetUnicode(); libraryHandle = CLRLoadLibrary(libraryName); do { if (libraryHandle == nullptr) { #ifdef _DEBUG wprintf(W("LoadLibrary failed for '%s': error %u\n"), libraryName, GetLastError()); #endif // _DEBUG break; } External_InitDisasm = reinterpret_cast<decltype(External_InitDisasm)>(GetProcAddress(libraryHandle, "InitDisasm")); if (External_InitDisasm == nullptr) { #ifdef _DEBUG wprintf( W("GetProcAddress failed for library '%s', function 'InitDisasm': error %u\n"), libraryName, GetLastError()); #endif // _DEBUG break; } External_DisasmInstruction = reinterpret_cast<decltype(External_DisasmInstruction)>(GetProcAddress(libraryHandle, "DisasmInstruction")); if (External_DisasmInstruction == nullptr) { #ifdef _DEBUG wprintf( W("GetProcAddress failed for library '%s', function 'DisasmInstruction': error %u\n"), libraryName, GetLastError()); #endif // _DEBUG break; } External_FinishDisasm = reinterpret_cast<decltype(External_FinishDisasm)>(GetProcAddress(libraryHandle, "FinishDisasm")); if (External_FinishDisasm == nullptr) { #ifdef _DEBUG wprintf( W("GetProcAddress failed for library '%s', function 'FinishDisasm': error %u\n"), libraryName, GetLastError()); #endif // _DEBUG break; } // Set this last to indicate successful load of the library and all exports s_libraryHandle = libraryHandle; _ASSERTE(IsAvailable()); return; } while (false); _ASSERTE(!IsAvailable()); #endif // USE_COREDISTOOLS_DISASSEMBLER }
//***************************************************************************** // The main dll entry point for this module. This routine is called by the // OS when the dll gets loaded. Control is simply deferred to the main code. //***************************************************************************** BOOL WINAPI DbgDllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) { // Save off the instance handle for later use. switch (dwReason) { case DLL_PROCESS_ATTACH: { #ifndef FEATURE_PAL g_hInst = hInstance; #else int err = PAL_InitializeDLL(); if(err != 0) { return FALSE; } #endif #if defined(_DEBUG) static int BreakOnDILoad = -1; if (BreakOnDILoad == -1) BreakOnDILoad = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_BreakOnDILoad); if (BreakOnDILoad) { _ASSERTE(!"DI Loaded"); } #endif #if defined(LOGGING) { PathString rcFile; WszGetModuleFileName(hInstance, rcFile); LOG((LF_CORDB, LL_INFO10000, "DI::DbgDllMain: load right side support from file '%s'\n", rcFile.GetUnicode())); } #endif #ifdef RSCONTRACTS // alloc a TLS slot DbgRSThread::s_TlsSlot = TlsAlloc(); _ASSERTE(DbgRSThread::s_TlsSlot != TLS_OUT_OF_INDEXES); #endif #if defined(FEATURE_DBGIPC_TRANSPORT_DI) g_pDbgTransportTarget = new (nothrow) DbgTransportTarget(); if (g_pDbgTransportTarget == NULL) return FALSE; if (FAILED(g_pDbgTransportTarget->Init())) return FALSE; #endif // FEATURE_DBGIPC_TRANSPORT_DI } break; case DLL_THREAD_DETACH: { #ifdef STRESS_LOG StressLog::ThreadDetach((ThreadStressLog*) ClrFlsGetValue(TlsIdx_StressLog)); #endif #ifdef RSCONTRACTS // DbgRSThread are lazily created when we call GetThread(), // So we don't need to do anything in DLL_THREAD_ATTACH, // But this is our only chance to destroy the thread object. DbgRSThread * p = DbgRSThread::GetThread(); p->Destroy(); #endif } break; case DLL_PROCESS_DETACH: { #if defined(FEATURE_DBGIPC_TRANSPORT_DI) if (g_pDbgTransportTarget != NULL) { g_pDbgTransportTarget->Shutdown(); delete g_pDbgTransportTarget; g_pDbgTransportTarget = NULL; } #endif // FEATURE_DBGIPC_TRANSPORT_DI #ifdef RSCONTRACTS TlsFree(DbgRSThread::s_TlsSlot); DbgRSThread::s_TlsSlot = TLS_OUT_OF_INDEXES; #endif } break; } return TRUE; }
HRESULT LoadDataAccessDll(HINSTANCE mscorModule, REFIID ifaceId, ICLRDataTarget* target, HMODULE* dllHandle, void** iface) { HRESULT status; WCHAR accessDllPath[MAX_PATH]; HMODULE accessDll; // // Load the access DLL from the same directory // as the runtime DLL. // if (!WszGetModuleFileName(mscorModule, accessDllPath, NumItems(accessDllPath))) { return HRESULT_FROM_GetLastError(); } PWSTR pathTail = wcsrchr(accessDllPath, '\\'); if (!pathTail) { return E_INVALIDARG; } pathTail++; PWSTR eeFlavor = L"wks"; if (_snwprintf_s(pathTail, _countof(accessDllPath) + (accessDllPath - pathTail), NumItems(accessDllPath) - (pathTail - accessDllPath), MAKEDLLNAME_W(L"mscordac%s"), eeFlavor) <= 0) { return E_INVALIDARG; } accessDll = WszLoadLibrary(accessDllPath); if (!accessDll) { return HRESULT_FROM_GetLastError(); } // // Get the access interface and have it // enumerate the interesting memory in the target process. // void* ifacePtr; PFN_CLRDataCreateInstance entry = (PFN_CLRDataCreateInstance) GetProcAddress(accessDll, "CLRDataCreateInstance"); if (!entry) { status = HRESULT_FROM_GetLastError(); FreeLibrary(accessDll); } else if ((status = entry(ifaceId, target, &ifacePtr)) != S_OK) { FreeLibrary(accessDll); } else { *dllHandle = accessDll; *iface = ifacePtr; } return status; }
//***************************************************************************** // This is a routine to try to find a class implementation given its fully // qualified name by using the CORPATH environment variable. CORPATH is a list // of directories (like PATH). Before checking CORPATH, this checks the current // directory, then the directory that the exe lives in. The search is // performed by parsing off one element at a time from the class name, // appending it to the directory and looking for a subdirectory or image with // that name. If the subdirectory exists, it drills down into that subdirectory // and tries the next element of the class name. When it finally bottoms out // but can't find the image it takes the rest of the fully qualified class name // and appends them with intervening '.'s trying to find a matching DLL. // Example: // // CORPATH=c:\bin;c:\prog // classname = namespace.class // // checks the following things in order: // c:\bin\namespace, (if <-exists) c:\bin\namespace\class.dll, // c:\bin\namespace.dll, c:\bin\namespace.class.dll // c:\prog\namespace, (if <-exists) c:\prog\namespace\class.dll, // c:\prog\namespace.dll, c:\prog\namespace.class.dll //***************************************************************************** HRESULT CORPATHService::GetClassFromCORPath( __in __in_z LPWSTR wzClassname, // [IN] fully qualified class name mdTypeRef tr, // [IN] TypeRef to be resolved. IMetaModelCommon *pCommon, // [IN] Scope in which the TypeRef is defined. REFIID riid, // [IN] Interface type to be returned. IUnknown **ppIScope, // [OUT] Scope in which the TypeRef resolves. mdTypeDef *ptd) // [OUT] typedef corresponding the typeref { PathString rcCorPath; // The CORPATH environment variable. LPWSTR szCorPath; // Used to parse CORPATH. int iLen; // Length of the directory. PathString rcCorDir; // Buffer for the directory. WCHAR *temp; // Used as a parsing temp. WCHAR *szSemiCol; // Get the CORPATH environment variable. if (WszGetEnvironmentVariable(W("CORPATH"), rcCorPath)) { NewArrayHolder<WCHAR> szCorPathHolder = rcCorPath.GetCopyOfUnicodeString(); szCorPath = szCorPathHolder.GetValue(); // Try each directory in the path. for(;*szCorPath != W('\0');) { // Get the next directory off the path. if ((szSemiCol = wcschr(szCorPath, W(';')))) { temp = szCorPath; *szSemiCol = W('\0'); szCorPath = szSemiCol + 1; } else { temp = szCorPath; szCorPath += wcslen(temp); } rcCorDir.Set(temp); // Check if we can find the class in the directory. if (CORPATHService::GetClassFromDir(wzClassname, rcCorDir, tr, pCommon, riid, ppIScope, ptd) == S_OK) return S_OK; } } //<TODO>These should go before the path search, but it will cause test // some headaches right now, so we'll give them a little time to transition.</TODO> // Try the current directory first. if ((iLen = WszGetCurrentDirectory( rcCorDir)) > 0 && CORPATHService::GetClassFromDir(wzClassname, rcCorDir, tr, pCommon, riid, ppIScope, ptd) == S_OK) { return S_OK; } // Try the app directory next. if ((iLen = WszGetModuleFileName(NULL, rcCorDir)) > 0) { if(SUCCEEDED(CopySystemDirectory(rcCorDir, rcCorDir)) && CORPATHService::GetClassFromDir( wzClassname, rcCorDir, tr, pCommon, riid, ppIScope, ptd) == S_OK) { return (S_OK); } } // Couldn't find the class. return S_FALSE; } // CORPATHService::GetClassFromCORPath