C++ 在运行时获取DLL路径

C++ 在运行时获取DLL路径,c++,dll,C++,Dll,我想从其代码中获取dll的目录(或文件)路径。(不是程序的.exe文件路径) 我尝试了几种我发现的方法: GetCurrentDir-获取当前目录路径。 GetModuleFileName-获取可执行文件的路径 那么我如何才能找到代码所在的dll呢? 我正在寻找类似C#的Assembly.getExecutionGassembly EXTERN_C IMAGE_DOS_HEADER __ImageBase; 尝试函数。您可以使用GetModuleHandleEx函数并获取DLL中静态函数的句

我想从其代码中获取dll的目录(或文件)路径。(不是程序的.exe文件路径)

我尝试了几种我发现的方法:
GetCurrentDir
-获取当前目录路径。
GetModuleFileName
-获取可执行文件的路径

那么我如何才能找到代码所在的dll呢?
我正在寻找类似C#的
Assembly.getExecutionGassembly

EXTERN_C IMAGE_DOS_HEADER __ImageBase;


尝试函数。

您可以使用
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()
函数中将其作为输入参数,只需将其保存到某个变量中,以便以后需要时使用。

这是一个Unicode修订版的顶级投票答案:

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, MAX_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;
}
CStringW thisDllDirPath()
{
CStringW thisPath=L“”;
WCHAR路径[最大路径];
hm模块hm;
if(getmodulehandlexw)(从地址获取模块句柄)
获取\u模块\u句柄\u EX\u标志\u未更改\u引用计数,
(LPWSTR)和此DLLDIRPATH,以及hm)
{
GetModuleFileName(hm,路径,最大路径);
PathRemoveFileSpecW(路径);
thisPath=CStringW(路径);
如果(!thisPath.IsEmpty()&&
thisPath.GetAt(thisPath.GetLength()-1)!=“\\”)
此路径+=L“\\”;
}

否则,如果(_DEBUG)std::wcout我想实现类似的功能,只是想将类似的函数转换成一个.dll-但您不能使用u ImageBase,因为它是特定于函数所在的.dll的。我甚至尝试过使用这种方法重写

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
//
//起源于:https://sourceforge.net/projects/diagnostic/
//
//与windows API函数类似,捕获当前调用堆栈的N帧。
//与windows API函数不同,它可用于托管函数和本机函数。
//
int CaptureStackBackTrace2(
int FramesToSkip,//[in]要跳过的帧,0-捕获所有内容。
int nFrames,//[in]要捕获的帧。
PVOID*BackTrace//[out]填充调用堆栈,总大小为nFrames-FramesToSkip
)
{
#ifdef_WIN64
语境记录;
RtlCaptureContext(&ContextRecord);
UINT-iFrame;
对于(iFrame=0;iFrame<(UINT)nframe;iFrame++)
{
DWORD64图像库;
PRUNTIME_FUNCTION pFunctionEntry=RtlLookupFunctionEntry(ContextRecord.Rip,&ImageBase,NULL);
if(pFunctionEntry==NULL)
{
如果(iFrame!=-1)
iFrame--;//最后吃,因为这是无效的。
打破
}
pvoidhandlerData;
DWORD64建立框架;
RtlVirtualUnwind(0/*UNW_FLAG_NHANDLER*/,,
ImageBase,
ContextRecord.Rip,
p功能输入,
&上下文记录,
&HandlerData,
&机构框架,
无效);
如果(帧跳过>(int)iFrame)
继续;
回溯[iFrame-FramesToSkip]=(PVOID)ContextRecord.Rip;
}
#否则
//
//此方法取自StackInfoManager.cpp/FillStackInfo
//  http://www.codeproject.com/Articles/11221/Easy-Detection-of-Memory-Leaks
//-稍微简化了功能本身。
//
int regEBP;
__asm mov regEBP,ebp;
long*pFrame=(long*)regEBP;//指向当前函数帧的指针
无效*无效指令;
int-iFrame=0;
//
//使用_try/_catch比使用ReadProcessMemory或VirtualProtect更快。
//在遇到异常后,我们返回迄今为止收集到的所有帧。
//
__试一试{
对于(;iFrameiFrame)
继续;
回溯[iFrame-FramesToSkip]=pndemistruction;
pFrame=(长*)(*pFrame);
}
}
__EXCEPTION(异常\u执行\u处理程序)
{
}
#endif/\u WIN64
iFrame-=FramesToSkip;
if(iFrame<0)
iFrame=0;
返回iFrame;
}//CaptureStackBackTrace2
//
//获取.dll完整路径或唯一目录。
//
CStringW GetDllPath(bool bPathOnly/*=false*/)
{
void*pfunc=&GetDllPath;
wchar_t path[MAX_path]={0};
内存\基本信息\信息;
hmodulehdll;
CaptureStackBackTrace2(1、2和pfunc);
//获取保存当前函数的模块的基址
虚拟查询(pfunc,&info,sizeof(内存基本信息));
//内存基本信息::AllocationBase对应于HMODULE
hdll=(HMODULE)info.AllocationBase;
//获取dll文件名
如果(!GetModuleFileName(hdll,路径,最大路径))
返回“L”;
如果(仅限bPathOnly)
{
wchar\u t*p=wcsrchr(路径“\\”);
如果(p)
*p=0;
}
返回路径;
}//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没有
//
//  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
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
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;
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;
...
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;
}