Получить путь к DLL во время выполнения



Я хочу получить dll путь к каталогу (или файлу) из его кода. (не программа .путь к файлу exe)



Я пробовал несколько методов, которые я нашел:
GetCurrentDir - возвращает текущий путь к каталогу.
GetModuleFileName - возвращает путь к исполняемому файлу.



Итак, как я могу узнать, в какой dll код находится ?

Я ищу что-то похожее на C#'ы Assembly.GetExecutingAssembly

846   9  

9 ответов:

EXTERN_C IMAGE_DOS_HEADER __ImageBase;

....

WCHAR   DllPath[MAX_PATH] = {0};
GetModuleFileNameW((HINSTANCE)&__ImageBase, DllPath, _countof(DllPath));

можно использовать GetModuleHandleEx функция и получить дескриптор статической функции в вашей DLL. Вы найдете дополнительную информацию здесь.

после этого вы можете использовать GetModuleFileName чтобы получить путь от дескриптора, который вы только что получили. Более подробная информация об этом звонке здесь.

полный пример:

char path[MAX_PATH];
HMODULE hm = NULL;

if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | 
        GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
        (LPCSTR) &functionInThisDll, &hm) == 0)
{
    int ret = GetLastError();
    fprintf(stderr, "GetModuleHandle failed, error = %d\n", ret);
    // Return or however you want to handle an error.
}
if (GetModuleFileName(hm, path, sizeof(path)) == 0)
{
    int ret = GetLastError();
    fprintf(stderr, "GetModuleFileName failed, error = %d\n", ret);
    // Return or however you want to handle an error.
}

// The path variable should now contain the full filepath for this DLL.

GetModuleFileName() отлично работает изнутри кодов DLL. Только не устанавливайте первый параметр в NULL Как вам имя вызывающего процесса. Вместо этого необходимо указать фактический экземпляр модуля DLL. Вы получаете это в качестве входного параметра в DLL DllEntryPoint() функция, просто сохраните его в переменную где-нибудь для последующего использования, когда это необходимо.

попробовать GetModuleFileName

вот Юникод, пересмотренная версия верхнего проголосованного ответа:

CStringW thisDllDirPath()
{
    CStringW thisPath = L"";
    WCHAR path[MAX_PATH];
    HMODULE hm;
    if( GetModuleHandleExW( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | 
                            GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
                            (LPWSTR) &thisDllDirPath, &hm ) )
    {
        GetModuleFileNameW( hm, path, sizeof(path) );
        PathRemoveFileSpecW( path );
        thisPath = CStringW( path );
        if( !thisPath.IsEmpty() && 
            thisPath.GetAt( thisPath.GetLength()-1 ) != '\' ) 
            thisPath += L"\";
    }
    else if( _DEBUG ) std::wcout << L"GetModuleHandle Error: " << GetLastError() << std::endl;

    if( _DEBUG ) std::wcout << L"thisDllDirPath: [" << CStringW::PCXSTR( thisPath ) << L"]" << std::endl;       
    return thisPath;
}

Я хотел добиться чего-то подобного, только хотел сделать подобную функцию в один .dll-но тогда вы не можете использовать __ImageBase, так как это специфично для этого .dll, где находится функция. Я даже пытался переопределить с помощью approach

GetDllPath( HMODULE hDll = (HMODULE) __ImageBase)

но это тоже не сработало. (По какой-то причине возвращает путь приложения после этого.)

тогда я понял - почему я не использую VirtualQuery, а использую указатель функции и получаю HMODULE оттуда. Но опять же - как получить указатель функции вызывающего абонента ?

и теперь он возвращается к определению стека вызовов - я не буду беспокоить вас всеми грязными деталями, просто следуйте ссылкам ссылочных ссылок.

вот весь снимок кода:

//
//  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

для пользователей Delphi:

SysUtils.GetModuleName(hInstance);              //Works; hInstance is a special global variable
SysUtils.GetModuleName(0);                      //Fails; returns the name of the host exe process
SysUtils.GetModuleName(GetModuleFilename(nil)); //Fails; returns the name of the host exe process

в случае, если ваш Delphi не имеет SysUtils.GetModuleName, объявляется как:

function GetModuleName(Module: HMODULE): string;
var
   modName: array[0..32767] of Char; //MAX_PATH is for a single filename; paths can be up to 32767 in NTFS - or longer.
begin
   {
      Retrieves the fully qualified path for the file that contains the specified module. 
      The module must have been loaded by the current process.
   }
   SetString(Result, modName, GetModuleFileName(Module, modName, Length(modName)));
end;

при условии, что вы реализовали следующую точку входа dll: (обычно dllmain.cpp)

BOOL APIENTRY DllMain( HMODULE hModule,
                   DWORD  ul_reason_for_call,
                   LPVOID lpReserved
                 )

Вы можете просто сделать:

switch (ul_reason_for_call)
{ 
case DLL_PROCESS_ATTACH:
{
    TCHAR dllFilePath[512 + 1] = { 0 };
    GetModuleFileNameA(hModule, dllFilePath, 512)
}
    break;
case DLL_THREAD_ATTACH: break;
...

dllFilePath будет содержать путь к тому, где был загружен текущий код dll. В этом случае hModule передается процессом загрузки dll.

HMODULE hmod = GetCurrentModule();
TCHAR szPath[MAX_PATH + 1] = 0;
DWORD dwLen = GetModuleFileHName(hmod, szPath, MAX_PATH);

Comments

    Ничего не найдено.