Get DLL path at runtime

前端 未结 10 1391
梦谈多话
梦谈多话 2020-11-28 22:31

I want to get a dll\'s directory (or file) path from within its code. (not the program\'s .exe file path)

I\'ve tried a few methods I\'ve found:

10条回答
  •  再見小時候
    2020-11-28 23:21

    I wanted to achieve something similar, except wanted to make similar function into one .dll - but then you cannot use __ImageBase, since it's specific to that .dll where function is located. I've even tried to override using approach

    GetDllPath( HMODULE hDll = (HMODULE) __ImageBase)
    

    But that did not work our either. (For some reason returns application path after that.)

    Then I've figured out - why I don't use VirtualQuery, and use function pointer and get HMODULE from there. But again - how to get function pointer of caller ?

    And now it gets back to call stack determination - I won't bother you with all dirty details, just follow links of referred links.

    Here is whole code snapshot:

    //
    //  Originated from: https://sourceforge.net/projects/diagnostic/
    //
    //  Similar to windows API function, captures N frames of current call stack.
    //  Unlike windows API function, works with managed and native functions.
    //
    int CaptureStackBackTrace2( 
        int FramesToSkip,                   //[in] frames to skip, 0 - capture everything.
        int nFrames,                        //[in] frames to capture.
        PVOID* BackTrace                    //[out] filled callstack with total size nFrames - FramesToSkip
    )
    {
    #ifdef _WIN64
        CONTEXT ContextRecord;
        RtlCaptureContext(&ContextRecord);
    
        UINT iFrame;
        for (iFrame = 0; iFrame < (UINT)nFrames; iFrame++)
        {
            DWORD64 ImageBase;
            PRUNTIME_FUNCTION pFunctionEntry = RtlLookupFunctionEntry(ContextRecord.Rip, &ImageBase, NULL);
    
            if (pFunctionEntry == NULL)
            {
                if (iFrame != -1)
                    iFrame--;           // Eat last as it's not valid.
                break;
            }
    
            PVOID HandlerData;
            DWORD64 EstablisherFrame;
            RtlVirtualUnwind(0 /*UNW_FLAG_NHANDLER*/,
                ImageBase,
                ContextRecord.Rip,
                pFunctionEntry,
                &ContextRecord,
                &HandlerData,
                &EstablisherFrame,
                NULL);
    
            if(FramesToSkip > (int)iFrame)
                continue;
    
            BackTrace[iFrame - FramesToSkip] = (PVOID)ContextRecord.Rip;
        }
    #else
        //
        //  This approach was taken from StackInfoManager.cpp / FillStackInfo
        //  http://www.codeproject.com/Articles/11221/Easy-Detection-of-Memory-Leaks
        //  - slightly simplified the function itself.
        //
        int regEBP;
        __asm mov regEBP, ebp;
    
        long *pFrame = (long*)regEBP;               // pointer to current function frame
        void* pNextInstruction;
        int iFrame = 0;
    
        //
        // Using __try/_catch is faster than using ReadProcessMemory or VirtualProtect.
        // We return whatever frames we have collected so far after exception was encountered.
        //
        __try {
            for (; iFrame < nFrames; iFrame++)
            {
                pNextInstruction = (void*)(*(pFrame + 1));
    
                if (!pNextInstruction)     // Last frame
                    break;
    
                if (FramesToSkip > iFrame)
                    continue;
    
                BackTrace[iFrame - FramesToSkip] = pNextInstruction;
                pFrame = (long*)(*pFrame);
            }
        }
        __except (EXCEPTION_EXECUTE_HANDLER)
        {
        }
    
    #endif //_WIN64
        iFrame -= FramesToSkip;
        if(iFrame < 0)
            iFrame = 0;
    
        return iFrame;
    } //CaptureStackBackTrace2
    
    
    
    //
    //  Gets .dll full path or only directory.
    //
    CStringW GetDllPath( bool bPathOnly /* = false */ )
    {
        void* pfunc = &GetDllPath;
        wchar_t path[MAX_PATH] = { 0 };
        MEMORY_BASIC_INFORMATION info;
        HMODULE hdll;
    
        CaptureStackBackTrace2(1, 2, &pfunc);
    
        // Get the base address of the module that holds the current function
        VirtualQuery(pfunc, &info, sizeof(MEMORY_BASIC_INFORMATION));
    
        // MEMORY_BASIC_INFORMATION::AllocationBase corresponds to HMODULE
        hdll = (HMODULE)info.AllocationBase;
    
        // Get the dll filename
        if ( !GetModuleFileName( hdll, path, MAX_PATH ) )
            return L"";
    
        if ( bPathOnly )
        {
            wchar_t* p = wcsrchr( path, '\\' );
            if ( p )
                *p = 0;
        }
    
        return path;
    } //GetDllPath
    

提交回复
热议问题