Get DLL path at runtime

前端 未结 10 1330
梦谈多话
梦谈多话 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:16

    Imho, Remy Lebau’s answer is the best, but lacks like all other answers to render the directory of the DLL. I quote the original question: “I want to get a dll's directory (or file) path from within its code. (not the program's .exe file path).”

    As Remy and Jean-Marc Volle pointed out, the DLL entry function DllMain usually contained in dllmain.cpp provides the handle to the DLL. This handle is often necessary, so it will be saved in a global variable hMod. I also add variables of type std::wstring to store the fully qualified name and the parent path of the DLL.

    HMODULE hMod;
    std::wstring PathAndName;
    std::wstring OnlyPath;
    BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
    {
      switch (ul_reason_for_call)
      {
        case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH:
           case DLL_PROCESS_DETACH:
         break;
      }
      hMod = hModule;
      const int BUFSIZE = 4096;
      wchar_t buffer[BUFSIZE];
      if (::GetModuleFileNameW(hMod, buffer, BUFSIZE - 1) <= 0)
      {
        return TRUE;
      }
    
      PathAndName = buffer;
    
      size_t found = PathAndName.find_last_of(L"/\\");
      OnlyPath = PathAndName.substr(0, found);
    
      return TRUE;
    }
    

    These global variables can be used inside the DLL.

    0 讨论(0)
  • 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
    
    0 讨论(0)
  • 2020-11-28 23:26
    HMODULE hmod = GetCurrentModule();
    TCHAR szPath[MAX_PATH + 1] = 0;
    DWORD dwLen = GetModuleFileHName(hmod, szPath, MAX_PATH);
    
    0 讨论(0)
  • 2020-11-28 23:31

    GetModuleFileName() works fine from inside the DLL's codes. Just be sure NOT to set the first parameter to NULL, as that will get the filename of the calling process. You need to specify the DLL's actual module instance instead. You get that as an input parameter in the DLL's DllEntryPoint() function, just save it to a variable somewhere for later use when needed.

    0 讨论(0)
提交回复
热议问题