Получить путь к DLL во время выполнения
Я хочу получить dll путь к каталогу (или файлу) из его кода. (не программа .путь к файлу exe)
Я пробовал несколько методов, которые я нашел:GetCurrentDir - возвращает текущий путь к каталогу.GetModuleFileName - возвращает путь к исполняемому файлу.
Итак, как я могу узнать, в какой dll код находится ?
Я ищу что-то похожее на C#'ы Assembly.GetExecutingAssembly
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. Вы получаете это в качестве входного параметра в DLLDllEntryPoint()функция, просто сохраните его в переменную где-нибудь для последующего использования, когда это необходимо.
попробовать 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