现在在我自己的进程里面,我创建了一个线程,在这个线程里面使用
SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)KeyboardProc, NULL, GetCurrentThreadId());
设置了一个键盘钩子。
  我想问的问题是:钩子的作用范围是当前的线程(见上面的GetCurrentThreadId()),是不是只要这个线程存在,所以的当前进程的键盘消息都会被我hook住呢?
  另外,我的这个线程被我结束了,钩子也同时失去作用了(不是因为我使用了UnHook函数,而是因为线程没有了),怎么才能使我的钩子在当前进程内有效,不论创建钩子的线程是否终结呢?
  不要使用全局钩子啊,我只希望我的钩子在当前进程有效,也别告诉我必须在主线程创建啊,我必须在另外一个线程里面创建啊:)原因比较特殊,可以参见我的另外一个问题:
http://expert.csdn.net/Expert/topic/2666/2666477.xml?temp=.3817713

解决方案 »

  1.   

    你用GetProcessThreadID(大概是它,可能拼写错了)得到的返回值(记住是返回值)就应该是线程ID,将这里的第一个参数要指向进程句柄就可以了,第二个参数是返回进程ID!
      

  2.   

    应该不会有GetProcessThreadID这个API吧?,如果要有,怎么判断得到的线程就是主线程ID?,楼主的题目关键就是要找目标进程的主线程,目标进程有几个线程,甚至哪几个线程ID都可以得到的。用THREADSTRUCT32结构。不过主线程,暂时还想不到,
      

  3.   

    GR(永远问问题) 可以去查MSDN,我保证有,我说过,函数的第一个参数是进程句柄,但是我的拼写可能错了,现在的系统是me,没有装VS,我这段时间正在做屏幕取词,在挂接钩子和替换API地址时用到了。
      

  4.   

    不过看了一下记事本,竟然只有一个线程,那就好办多了,toolhelp32就可以解决问题了,THREADSTRUCT32里第四个参数指明了线程是被哪个进程所创建,首先枚举线程,然后对照是否是记事本所创建,找到之后拿到这个ThreadID,HOOK.OK了,
      

  5.   

    没见GetProcessThreadID这个api
    这个问题不解决了不甘心啊
    另外问一下,如果我是用SetWindowLong来改变window的回调函数,处理其中的键盘消息,是不是和键盘钩子差不多呢?
    我觉得应该不一样啊。
      

  6.   

    SetWindowsHookEx最后一个参数决定了钩子的作用域,钩子实际上是位于消息处理链首的一个静态函数,它能第一个对消息做出响应。楼主可能不太明白最后一个参数的含义,钩子捕获的是发往这个ID所指线程的消息!所以,如果设置成GetCurrentThreadId(),钩子的作用将随线程的终结而消失。把这个参数改成你主线程的ID,就可以满足要求了。主线程的ID可以通过lParam传给线程函数,这里应该没有疑问吧?
      

  7.   

    它的主线程是notepad.不是它自己的,
      

  8.   

    呵呵
      fzd999(花差花差) :
      http://expert.csdn.net/Expert/topic/2666/2666477.xml?temp=.3817713,看看这里,其实是通过CreateRemoteProcess创建的,我的线程函数实际上是LoadLibrary,参数是我要load的dll地址,所以没有你说的lParam,而且我也没有能力来传这个lParam。
      kinghawk(惊鸿):只找到一个GetWindowThreadProcessId,这个要有窗口才成啊,我创建这个线程的时候还没有创建窗口啊!
      

  9.   

    GetWindowThreadProcessId这个函数写hook的都应该用过,不是用来判断主线程的,是根据一个窗口来拿进程ID和线程ID的.
      

  10.   

    你有本事远程注入,就应该先得到那个进程的ID,得到了还有什么疑问????
    -------------------------------------
      确实我可以知道,但这样要自己写回调函数很麻烦啊,我调试没有成功,我想看能不能在loadlibrary的时候让函数自己从dllmain中完成,这样很好调试啊,难道真的没有办法得到主线程了?
      

  11.   

    但是你应该很容易得到主进程的句柄,这个并不难,因为主进程是你自己的进程,而且第一个参数不一定非要有窗口,算了,如果明天还没有解决我给你段代码。
    另:GR(永远问问题):
    我从没有说这个函数是用来判断主线程的,我一再强调第一个参数应该是主进程的句柄,而且楼主现在需要的也是主线程ID。
      

  12.   

    主进程不是我的进程,我是远程注入dll的,主进程是别人的:)
    所以GetWindowThreadProcessId感觉我无法得到我想要的参数!
      

  13.   

    哦.我其实是很想知道怎么才能弄到目标进程的主线程ID的方法,说话如果有点急大哥们不要见怪.我想我应该理解了楼主提出的问题,他是在用远程创建线程的方法在注入DLL,这个问题的关键不是他拿不拿的到自己进程的ID,而是拿不拿的到远进程,也就是宿主进程里的主线程ID,
    当然,挂到宿主进程的其他线程上也是可以的.另外,kinghawk(惊鸿) ( ) 的关于主进程的句柄这种说法我不太了解,虚心请教一下
      

  14.   

    另:GR(永远问问题):
    我从没有说这个函数是用来判断主线程的,我一再强调第一个参数应该是主进程的句柄,而且楼主现在需要的也是主线程ID。
    那我试试
    GetWindowThreadProcessId(GetCurrentProcess,NULL);
      

  15.   

    GetWindowThreadProcessId((HWND)GetCurrentProcess(),NULL)
    这样来指定线程是不行的啊!
      

  16.   

    lsaturn(土星-站了一晚),总之你要得到这个ID不是?那就干脆野蛮一点,EnumProccesses,花不了几毫秒的
      

  17.   

    我是这么来做的
    HANDLE hSnapShot;
    THREADENTRY32 te;
    hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, GetCurrentProcessId());
    然后用
    Thread32First和Thread32Next来枚举线程
    不知道怎么才能枚举完啊?
      

  18.   

    THREADSTRUCT32这个结构里有你要的参数
      

  19.   

    THREADSTRUCT32
    msdn里面找不到这个结构啊!
      

  20.   

    THREADENTRY32,,记错了。是这个。
      

  21.   

    for(BOOL bOK = Thread32First(hSnapShot, &te); bOK; bOK = Thread32Next(hSnapShot, &te))
    {
        if(dwCurProcId == te.th32OwnerProcessID)
    {
    hHook = SetHook(WH_KEYBOARD, (HOOKPROC)KeyboardProc, NULL, te.th32ThreadID);
    }
    }
    怎么这样还是hook不了所有的线程呢?
      

  22.   

    对了dwCurProId = GetCurrentProcessId()
      

  23.   

    我才发现
    HANDLE hSnapShot;
    THREADENTRY32 te;
    hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
    BOOL bOK = Thread32First(hSnapShot, &te);
    一直都是FALSE啊
    这是怎么回事啊?
      

  24.   

    我知道了
    是忘了这个
    te.dwSize = sizeof(THREADENTRY32);
    但是现在怎么还是不行啊!
    太郁闷了啊!
    键盘钩子要显示的对话框一闪就消失了啊,真是很奇怪啊!
      

  25.   

    知道为什么一闪就消失了!
    我的对话框显示程序是这样的
    if(ShowWindow(hwndMain, SW_SHOW)) //切换显示状态
    {
    ShowWindow(hwndMain, SW_HIDE);
    }
    因为用了一个线程来加载,所以当前程序有两个线程,所以按了键盘钩子设定的键之后,一个线程使它显示,一个线程使它消失,前面也说了,我是对当前进程的每个线程设了键盘钩子的
    for(BOOL bOK = Thread32First(hSnapShot, &te); bOK; bOK = Thread32Next(hSnapShot, &te))
    {
        if(dwCurProcId == te.th32OwnerProcessID)
    {
    hHook = SetHook(WH_KEYBOARD, (HOOKPROC)KeyboardProc, NULL, te.th32ThreadID);
    }
    }
    但是我的线程明明已经马上就结束了的啊(我用Process Viewer来看的)所以应该只有一个线程了,怎么键盘钩子的回调函数还是调用两次呢?
      

  26.   

    哎,这样hook进程的所有线程还是不好啊,这样会使我的回调函数被多次调用的啊,应该怎么才能找到主线程呢?
      

  27.   

    当你的线程注入成功后,GetCurrentProcessId就是目标 进程id