//获取当前进程中所有线程,并存入ThreadInfo
EnumThreadInfo(ThreadInfo);
if (!ThreadInfo.empty())
{
vector<THREADENTRY32>::iterator iter = ThreadInfo.begin();
HANDLE CurrTh = GetCurrentThread();
for (iter = ThreadInfo.begin();  iter != ThreadInfo.end(); iter++)
{
HANDLE th = lpfnOpenThread(THREAD_SUSPEND_RESUME, FALSE, iter->th32ThreadID);
if (th == NULL)
{
ShowError("获取所有线程的句柄时失败!");
}
CONTEXT thtext = {0};
if (th != CurrTh)
{
DWORD err = SuspendThread(th);
if (err == 0xFFFFFFFF)
{
ShowError("挂起线程时失败!");
}
                        //执行到这句程序崩溃,错误代码为5.
if (GetThreadContext(th, &thtext))
{
IntelStackWalk(&thtext);
}
else
{
ShowError("获取所有线程的信息时失败!");
}
err = ResumeThread(th);
if (err == 0xFFFFFFFF)
{
ShowError("运行挂起的线程时失败!");
}
}
}
}
else
{
_tprintf("未找到任何线程。。");
}
以上是在win7下运行,
在XP下程序直接挂起并不返回了。这是怎么回事啊?为什么GetThreadContext时失败?

解决方案 »

  1.   

    GetThreadContext 之前 试试 thtext.ContextFlags = CONTEXT_CONTROL;
      

  2.   


    没有变化,GetThreadContext依然失败,错误代码5
      

  3.   

     需要权限 THREAD_QUERY_INFORMATION
      

  4.   

    lpfnOpenThread是OpenThread函数吧?
    HANDLE th = lpfnOpenThread(THREAD_SUSPEND_RESUME|THREAD_QUERY_INFORMATION, FALSE, iter->th32ThreadID);
      

  5.   


    是OpenThread函数。
    还是不行,错误代码5.。我的这段代码在一个异常处理函数中执行的,这个异常函数使用SetUnhandledExceptionFilter函数设置的。我跟过,如果我开了两个线程,在某一个线程崩溃时遍历当前进程中线程还是能找到两个线程的,任务管理器也是在崩溃时显示有两个线程,但就是执行GetThreadContext函数时报错,我本意是想在程序崩溃时保存当前进程中所有线程的堆栈信息。请再帮我看看还有那地方有问题。郁闷啊。
      

  6.   

    我觉得也有可能是权限的问题,我的函数EnumThreadInfo(ThreadInfo); 会获取当前系统下运行的所有进程中的线程,我是通过判断进程ID来分拣出来的,如果微软能这么轻易让其他程序访问其他进程中的线程那不就出问题了。。我的初衷是想获取本进程中的所有线程,获取线程的CONTEXT信息,我感觉我是绕了一大圈来获取本进程的线程句柄。我贴出获取线程ID的代码(用线程ID并使用openthread来获取线程句柄),看看还有没有其他方式来获取线程句柄(如果能直接获取到线程句柄最好了)。
    BOOL EnumThreadInfo(vector<THREADENTRY32> &ThreadInfo)  
    {  
    ThreadInfo.clear();
        // 定义线程信息结构   
        THREADENTRY32 te32 = {0} ; 
    te32.dwSize = sizeof(THREADENTRY32);

        //创建系统线程快照   
        HANDLE hThreadSnap = CreateToolhelp32Snapshot ( TH32CS_SNAPTHREAD, 0 ) ;  
        if ( hThreadSnap == INVALID_HANDLE_VALUE )  
            return FALSE ;   

        // 循环枚举当前进程中的线程信息   
    DWORD dwOwnerPID  = GetCurrentProcessId();
        if ( Thread32First ( hThreadSnap, &te32 ) )  
        {  
            do{  
    if (te32.th32OwnerProcessID == dwOwnerPID)
    {
    ThreadInfo.push_back(te32);
    }
            }while ( Thread32Next ( hThreadSnap, &te32 ) ) ;  
        } 
    else
    {
    CloseHandle ( hThreadSnap ) ;  
    return FALSE;
    }

        CloseHandle ( hThreadSnap ) ;  
        return TRUE ;  
    }
      

  7.   

    先判断,*iter是否当前线程,或者界面线程,然后再OpenThread
    否则当前线程,或者界面线程会挂起。
    挂起当前线程,你的这段代码,会挂起。
    挂起界面线程,你的界面会死掉。
    从NT起,到XP ,对于每个窗口程序,界面线程至少有两个,其中一个是界面线程的守护线程。
      

  8.   


    请问如何判断界面线程?我在openthread之前只有线程的ID,并且上面的程序中已经过滤了当前线程,当前线程不会挂起。就算界面线程被我挂起了,界面死了,但是其他线程还在跑,就会把界面线程解挂啊~~
      

  9.   

    其他线程处理界面消息吗????
    不处理界面消息,如何解挂,如果一个挂起的线程,使用锁和其他线程通讯,并且已经获得锁,就会造成和他公用锁的线程死锁。
    if (th != CurrTh) 
    这个是不能排除当前线程的,任何正在运行的线程,都是当前线程。
    当前线程句柄,是伪句柄,不是真正的句柄,要获取句柄;
    用DuplicateHandle 复制句柄。而且,你打开线程,在判断之前,没有执行判断,线程就已经挂起了。
    PS:
    判断界面线程,如果没有做特殊处理,窗口创建的线程就是界面线程,可能有两个,在界面创建和界面第1~n次显示的时候,获当前线程ID和句柄,直到找到两个不同线程为止(句柄值不是0 和-1)。这两个线程不能挂起。