Нужно получить строку, содержащую цепочку вызывающих модулей

Всем привет и заранее спасибо. Мне нужно получить строку, содержащую цепочку вызывающих модулей:

  • Консольное приложение C# exe (C# 1.exe), которое содержит только функцию Main, в которой вызывается функция FunctionDLL() библиотеки C# 2.dll

    Main() { FunctionDLL() }

  • Библиотека C# (C# 2.dll), которая содержит одну функцию FunctionDLL (), эта функция вызывает функцию GetModulePaths () из библиотеки C ++ C ++ 3.dll

    public static string FunctionDLL() { return GetModulePaths(); }

  • Библиотека C++ (C++ 3.dll), которая содержит одну функцию GetModulePaths () и возвращает строку, содержащую цепочку вызывающих модулей. Мне нужно получить список полных путей к модулям строгого порядка, например::

    "C:\Projects\C# 1.exe C:\Projects\C# 2.dll C:\Projects\C++ 3.dll"

РЕШЕНО невозможно получить из неуправляемого кода стектрэйс (и пути к вызывающим модулям соответсвенно) на управляемый код, который его вызывает. максимум что я смог получить из неуправляемой С++ DLL - это путь к .Net модулю clr.dll из управляемого - можно. смотри пример тут:

https://www.codeproject.com/Articles/17386/Get-the-calling-module-that-invoked-your-function


Ответы (1 шт):

Автор решения: Maverick

Невозможно получить из неуправляемого кода стектрэйс (и пути к вызывающим модулям соответсвенно) на управляемый код, который его вызывает. Для решения проблемы можно создать C++ библиотеку смешанного типа (mixed type, Common Language Runtime Support (/clr)). Здесь анализируется, является ли полученный с помощью метода CaptureStackBackTrace() модуль модулем управляемого кода, это происходит с помощью вызова метода управляемого кода (С++/CLI) IsDotNetRuntime. И если это модуль управляемого кода, то с помощью метода GetDotNetCallerFileName() получаем путь к нему. Вот пример управляемого кода в этой библиотеке:

int GetDotNetCallerFileName(string& module)
{

    int res = FALSE;
    try
    {
        Assembly^ callerAssembly = Assembly::GetCallingAssembly();
        if (callerAssembly == nullptr)
            return FALSE;
        String^ sysdir = System::Runtime::InteropServices::RuntimeEnvironment::GetRuntimeDirectory();
        //skip all .net framework assemblies and calls from the same assembly

        String^ strCallerPath = callerAssembly->Location;
        String^ directoryName = nullptr;
        if (strCallerPath != nullptr)
            directoryName = Path::GetDirectoryName(strCallerPath) + "\\";

        while (directoryName != nullptr && (String::Compare(sysdir, directoryName, true) == 0)
            || callerAssembly == Assembly::GetExecutingAssembly())
        {
            strCallerPath = nullptr;
            callerAssembly = callerAssembly->GetCallingAssembly();
            directoryName = nullptr;
            if (strCallerPath != nullptr)
                directoryName = Path::GetDirectoryName(strCallerPath) + "\\";
            strCallerPath = callerAssembly->Location;
        }


        pin_ptr<const wchar_t> wch = PtrToStringChars(strCallerPath);
        size_t convertedChars = 0;
        size_t  sizeInBytes = ((strCallerPath->Length + 1) * 2);
        errno_t err = 0;
        char* ch = (char*)malloc(sizeInBytes);

        err = wcstombs_s(&convertedChars,
            ch, sizeInBytes,
            wch, sizeInBytes);
        if (err == 0)
            module = ch;
        free(ch);
        res = TRUE;
    }
    catch (Exception^ e)
    {
        Console::WriteLine(e->Message);
    }
    finally
    {

    }
    return res;
}

BOOL IsDotNetRuntime(char* callerModulePath)
{
    //check for .net runtime path
    String^ path = Marshal::PtrToStringAnsi((IntPtr)callerModulePath);
    String^ directoryName;
    directoryName = Path::GetDirectoryName(path) + "\\";
    String^ sysdir = RuntimeEnvironment::GetRuntimeDirectory();
    if (String::Compare(sysdir, directoryName, true) == 0)
        return TRUE;
    return FALSE;
}
→ Ссылка