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);
}
Exemple #2
0
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));
}
Exemple #3
0
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)
    {
Exemple #5
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);
}
Exemple #6
0
//*****************************************************************************
// 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
Exemple #7
0
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);
}
Exemple #8
0
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
}
Exemple #9
0
//*****************************************************************************
// 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;
}
Exemple #11
0
//*****************************************************************************
// 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