【发布时间】:2011-12-30 12:24:31
【问题描述】:
背景:
我在 Win32 中编写了一个多线程应用程序,我从 C# 代码开始,使用 System.Diagnostics 命名空间中的 Process 类。
现在,在 C# 代码中,我想获取在 Win32 应用程序中创建的每个线程的起始地址的名称/符号,以便我可以将线程相关信息(例如 CPU 使用率)记录到数据库中。基本上,C# 代码会启动 Win32 应用程序的多个实例,监视它们,如果需要则终止,然后将 info/error/exceptions/reason/etc 记录到数据库中。
为此,我封装了两个 Win32 API 即。 SymInitialize 和 SymFromAddr 在我自己编写的程序员友好的 API 中,如下所示:
extern "C"
{
//wraps SymInitialize
DllExport bool initialize_handler(HANDLE hModue);
//wraps SymFromAddr
DllExport bool get_function_symbol(HANDLE hModule, //in
void *address, //in
char *name); //out
}
然后使用 pinvoke 从 C# 代码调用这些 API。但它不起作用,GetLastError 给了126 error code 这意味着:
找不到指定的模块
我将Process.Handle 作为hModule 传递给这两个函数; initialize_handler 似乎有效,但 get_function_symbol 无效;它给出了上述错误。我不确定我是否传递了正确的句柄。我尝试传递以下句柄:
Process.MainWindowHandle
Process.MainModule.BaseAddress
两者都在第一步本身失败(即调用initialize_handler 时)。我将Process.Threads[i].StartAddress 作为第二个参数传递,这似乎是失败的原因,因为ProcessThread.StartAddress 似乎是RtlUserThreadStart 函数的地址,不是特定的启动函数的地址到应用程序。 MSDN says about it:
每个 Windows 线程实际上都是在系统提供的函数中开始执行的,而不是应用程序提供的函数。因此,对于系统中的每个 Windows 进程,主线程的起始地址都是相同的(因为它表示系统提供的函数的地址)。 不过,StartAddress 属性允许您获取特定于您的应用程序的起始函数地址。
但它没有说明如何使用 ProcessThread.StartAddress 获取特定于应用程序的 startinbg 函数地址。
问题:
我的问题归结为从另一个应用程序(用 C# 编写)获取 win32 线程的起始地址,一旦我得到它,我也会使用上述 API 获取名称。那么如何获取起始地址呢?
我从 C++ 代码测试了我的符号查找 API。如果给出正确的开头地址,则可以将地址解析为符号。
这是我的 p/invoke 声明:
[DllImport("UnmanagedSymbols.dll", SetLastError = true, CallingConvention= CallingConvention.Cdecl)]
static extern bool initialize_handler(IntPtr hModule);
[DllImport("UnmanagedSymbols.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
static extern bool get_function_symbol(IntPtr hModule, IntPtr address, StringBuilder name);
【问题讨论】:
-
您忘记发布 [DllImport] 声明,如果它在 C++ 中工作,肯定是问题的原因。
-
@HansPassant:我意识到了这一点,因此我立即发布了。
-
返回类型需要[MarshalAs],C++ bool == byte。但这不太可能是原因。 ProcessThread.StartAddress 不确定,因为线程实际上是从 Windows 函数 (RtlUserThreadStart) 开始的。文档承诺会提供一些帮助,但我不知道这在流程外能有多好。显然,这不是您在 C++ 中测试过的。
-
那么你想用“名称/起始地址的符号”来识别线程吗?如果是这样,难道您不能只跟踪您创建的线程或将线程名称设置为您想要的任何名称吗?
-
①问题标题是“给定[...]起始地址,如何获取函数名”,但大部分问题都集中在获取起始地址上。 ② “我将 Process.Threads[i].StartAddress 作为第二个参数传递”这句话不清楚:作为什么函数的第二个参数? ③ 你将什么作为第三个参数传递给
SymInitialize? — 请用您的问题解决这些问题,这样您将有更高的机会得到满意的答案。
标签: c# c++ dll process pinvoke