大神帮忙看下这里(已在程序里标出)的UnhookWindowsHookEx有什么作用,我感觉去掉也可以呀?可是一去掉就崩溃,这个dll的作用是跨进程subclass 开始按钮,然后交换鼠标左右键? #include <windows.h>
#include "HookInjEx_DLL.h"
#pragma data_seg (".shared")
int g_bSubclassed = 0;
UINT WM_HOOKEX = 0;
HWND g_hWnd = 0;
HHOOK g_hHook = 0;
#pragma data_seg () #pragma comment(linker,"/SECTION:.shared,RWS") HINSTANCE hDll; // New & old window procedure of the subclassed START button
WNDPROC OldProc = NULL;
LRESULT CALLBACK NewProc( HWND,UINT,WPARAM,LPARAM );
//-------------------------------------------------------------
// DllMain
//
BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
 )
{
if( ul_reason_for_call == DLL_PROCESS_ATTACH ) 
{
hDll = (HINSTANCE) hModule;
::DisableThreadLibraryCalls( hDll ); if( WM_HOOKEX==NULL )
WM_HOOKEX = ::RegisterWindowMessage( "WM_HOOKEX_RK" );
    }

    return TRUE;
}
#define pCW ((CWPSTRUCT*)lParam) LRESULT HookProc (
  int code,       
  WPARAM wParam, 
  LPARAM lParam  
)
{
if( (pCW->message == WM_HOOKEX) && pCW->lParam ) 
{
//就是下面这行的UnhookWindowsHookEx有什么作用,我感觉去掉也可以呀?可是一去掉就崩溃,为什么??
::UnhookWindowsHookEx( g_hHook ); if( g_bSubclassed ) 
goto END; char lib_name[MAX_PATH]; 
::GetModuleFileName( hDll, lib_name, MAX_PATH );

if( !::LoadLibrary( lib_name ) )
goto END;
OldProc = (WNDPROC) 
::SetWindowLong( g_hWnd, GWL_WNDPROC, (long)NewProc );
if( OldProc==NULL )
::FreeLibrary( hDll );
else {
::MessageBeep(MB_OK);
g_bSubclassed = true;
}
}
else if( pCW->message == WM_HOOKEX ) 
{
::UnhookWindowsHookEx( g_hHook );
if( !SetWindowLong( g_hWnd, GWL_WNDPROC, (long)OldProc ) )
goto END; ::FreeLibrary( hDll ); ::MessageBeep(MB_OK);
g_bSubclassed = false;
} END:
return ::CallNextHookEx(g_hHook, code, wParam, lParam);
}
//-------------------------------------------------------------
// NewProc
// Notice: - new window procedure for the START button;
// - it just swaps the left & right muse clicks;
//
LRESULT CALLBACK NewProc(
  HWND hwnd,      // handle to window
  UINT uMsg,      // message identifier
  WPARAM wParam,  // first message parameter
  LPARAM lParam   // second message parameter
)
{
switch (uMsg) 
{
case WM_LBUTTONDOWN: uMsg = WM_RBUTTONDOWN; break;
case WM_LBUTTONUP:  uMsg = WM_RBUTTONUP; break; case WM_RBUTTONDOWN: uMsg = WM_LBUTTONDOWN; break;
case WM_RBUTTONUP:   uMsg = WM_LBUTTONUP; break; case WM_LBUTTONDBLCLK: uMsg = WM_RBUTTONDBLCLK; break;
case WM_RBUTTONDBLCLK: uMsg = WM_LBUTTONDBLCLK; break;
}

return CallWindowProc( OldProc,hwnd,uMsg,wParam,lParam );
}
//-------------------------------------------------------------
// InjectDll
// Notice: 
// - injects "HookInjEx.dll" into "explorer.exe" (via SetWindowsHookEx);
// - subclasses the START button (see HookProc for more details);
//
// Parameters: - hWnd = START button handle
//
// Return value: 1 - success;
// 0 - failure;
//
int InjectDll( HWND hWnd )
{
g_hWnd = hWnd; // Hook "explorer.exe"
g_hHook = SetWindowsHookEx( WH_CALLWNDPROC,(HOOKPROC)HookProc,
hDll, GetWindowThreadProcessId(hWnd,NULL) );
if( g_hHook==NULL )
return 0;

// By the time SendMessage returns, 
// the START button has already been subclassed
SendMessage( hWnd,WM_HOOKEX,0,1 ); return g_bSubclassed;
}
//-------------------------------------------------------------
// UnmapDll
// Notice: 
// - restores the old window procedure for the START button;
// - unmapps the DLL from the remote process
//   (see HookProc for more details);
//
// Return value: 1 - success;
// 0 - failure;
//
int UnmapDll( )
{
g_hHook = SetWindowsHookEx( WH_CALLWNDPROC,(HOOKPROC)HookProc,
hDll, GetWindowThreadProcessId(g_hWnd,NULL) ); if( g_hHook==NULL )
return 0;

SendMessage( g_hWnd,WM_HOOKEX,0,0 ); return (g_bSubclassed == NULL);
}windowscallback

解决方案 »

  1.   

    上面的代码去掉::UnhookWindowsHookEx( g_hHook );之后,是不是只会在第二次执行时才会出错?
      

  2.   

    Nova,不知道你自己是否已经找到问题的原因了。今天我抽空看了一下,我将关键点以图片的方式贴上:
    图1
    图2
      

  3.   

    看不懂你想说什么,debugger_chen
      

  4.   

    明天要回家了,估计也上不了网,故将分析过程与你要注释那行代码后报错的解决方案贴上,正文如下:
    --------------------------
    导致资源管理器崩溃的根源:
    注入到Explorer.exe进程中的HookInjEx.dll产生AV异常。导致错误的位置:
    位于HookInjEx_DLL.cpp文件的HookProc过程中的“::FreeLibrary( hDll );”代码后,具体的调用栈可以查看上面的图2,正是崩溃时的栈回溯。是什么原因导致上述的AV错误:
    祸起钩子。首先需要说明,使用SetWindowsHookEx安装钩子时,后安装的钩子会处子钩子链的最前端。钩子的卸载需要使用UnhookWindowsHookEx。重复安装的钩子不会“覆盖”。分析“案”发过程:
    1、启动主程序HookInjEx,当点击“Inject Dll”按钮时,获得资源管理器上的“开始”按钮的句柄(注:在Win7上测试上面的代码时,获取“开始”按钮的句柄使用“hStart = ::FindWindow ("BUTTON",NULL);”代码,否则在Win7上取的句柄为空),然后调用HookInjEx.dll导出的InjectDll过程。在此过程之前还有一个在DllMain过程中需要说明的操作,调用RegisterWindowMessage向系统注册了一个系统范围内惟一的消息。
    2、在InjectDll中安装了一个全局的WH_CALLWNDPROC类型的钩子,接着向"BUTTON"这个窗口发送了一个注册的消息,消息的WPARAM=0, LPARAM=1。这个消息的发送,将导致HookProc的调用。
    3、在HookProc过程中,因LPARAM=1为1,先使用LoadLibrary( lib_name )加载模块。接着使用SetWindowLong修改窗口的窗口过程。注:在这个过程中因你将"::UnhookWindowsHookEx( g_hHook );"这句注释了,这将导致此钩子过程仍然处于钩子链中。
    4、此时在“桌面”的“开始”按钮上测试效果正确。
    6、接着退出程序或点击“Unmap Dll”按钮,调用到HookInjEx.dll导出的UnmapDll过程。
    7、在UnmapDll过程中,再次调用SetWindowsHookEx安装了同样的一个钩子(注:共两个钩子了,因为之前的钩子并没有被卸载)。接下来使用SendMessage发送了一个WPARAM=0,LPARAM=0的消息。同样导致钩子链上的HookProc被调用。
    8、在HookProc的else if 分支处开始执行,首先卸载链上的过程,接着调用SetWindowLong恢复”Button“的窗口过程,然后释放了Dll(并未真的Free,引用计数变为1)。接下来执行“return ::CallNextHookEx(g_hHook, code, wParam, lParam);”对钩子链上的下一个钩子进行调用。
    9、然而,这就引发当前钩子过程HookProc被再次调用。同上,首先卸载链上的过程,接着调用SetWindowLong恢复”Button“的窗口过程,然后释放了Dll,此时HookInjEx.dll被正真的从内存卸载,而后从FreeLibraray返回时,eip指针并指向一个不可以为Read的内存区域。这样就更发生了AV错误。
    这也是为什么发生错误时,模块的名字变为Unloaded module。注释掉“::UnhookWindowsHookEx( g_hHook ); ”且不报错的方案:
    (也是对上面分析的一个证明)
    再定义一个HHOOK类型的变量HHOOK   g_hOoldHook = 0;用于保存上上一次的安装的钩子句柄。
    修改1:int InjectDll( HWND hWnd )
    {
    g_hWnd = hWnd; // Hook "explorer.exe"

    //DC add
    if(g_hHook ) g_hOoldHook = g_hHook;
    g_hHook = SetWindowsHookEx( WH_CALLWNDPROC,(HOOKPROC)HookProc,
    hDll, GetWindowThreadProcessId(hWnd,NULL) );
    if( g_hHook==NULL )
    return 0; // By the time SendMessage returns, 
    // the START button has already been subclassed
    SendMessage( hWnd,WM_HOOKEX,0,1 ); return g_bSubclassed;
    }
    修改2int UnmapDll( )
    {
    // DC add
    if( g_hHook ) g_hOoldHook = g_hHook;
    g_hHook = SetWindowsHookEx( WH_CALLWNDPROC,(HOOKPROC)HookProc,
    hDll, GetWindowThreadProcessId(g_hWnd,NULL) ); if( g_hHook==NULL )
    return 0; SendMessage( g_hWnd,WM_HOOKEX,0,0 ); return (g_bSubclassed == NULL);
    }
    修改3:
    LRESULT HookProc (
      int code,       
      WPARAM wParam, 
      LPARAM lParam  
      )
    {
    if( (pCW->message == WM_HOOKEX) && pCW->lParam ) 
    { //::UnhookWindowsHookEx( g_hHook );  //??为什么把这个地方给注释了,exploer.exe就崩溃了??? if( g_bSubclassed ) 
    goto END; char lib_name[MAX_PATH]; 
    ::GetModuleFileName( hDll, lib_name, MAX_PATH ); if( !::LoadLibrary( lib_name ) )
    goto END;
    OldProc = (WNDPROC) 
    ::SetWindowLong( g_hWnd, GWL_WNDPROC, (long)NewProc );
    if( OldProc==NULL )
    ::FreeLibrary( hDll );
    else {
    ::MessageBeep(MB_OK);
    g_bSubclassed = true;
    }
    }
    else if( pCW->message == WM_HOOKEX ) 
    {
    ::UnhookWindowsHookEx( g_hHook ); // DebugEr-CHEN 添加
    if( g_hOoldHook )
    ::UnhookWindowsHookEx( g_hOoldHook ); if( !SetWindowLong( g_hWnd, GWL_WNDPROC, (long)OldProc ) )
    goto END; ::FreeLibrary( hDll ); ::MessageBeep(MB_OK);
    g_bSubclassed = false;
    }END:
    return ::CallNextHookEx(g_hHook, code, wParam, lParam);
    }
      

  5.   

    修改3:LRESULT HookProc (
      int code,       
      WPARAM wParam, 
      LPARAM lParam  
      )
    {
    if( (pCW->message == WM_HOOKEX) && pCW->lParam ) 
    {//::UnhookWindowsHookEx( g_hHook );  //??为什么把这个地方给注释了,exploer.exe就崩溃了???if( g_bSubclassed ) 
    goto END; char lib_name[MAX_PATH]; 
    ::GetModuleFileName( hDll, lib_name, MAX_PATH );if( !::LoadLibrary( lib_name ) )
    goto END; 
    OldProc = (WNDPROC) 
    ::SetWindowLong( g_hWnd, GWL_WNDPROC, (long)NewProc );
    if( OldProc==NULL ) 
    ::FreeLibrary( hDll );
    else { 
    ::MessageBeep(MB_OK); 
    g_bSubclassed = true;

    }
    else if( pCW->message == WM_HOOKEX ) 
    {
    ::UnhookWindowsHookEx( g_hHook );// DebugEr-CHEN 添加
    if( g_hOoldHook )
    ::UnhookWindowsHookEx( g_hOoldHook );if( !SetWindowLong( g_hWnd, GWL_WNDPROC, (long)OldProc ) )
    goto END;::FreeLibrary( hDll ); ::MessageBeep(MB_OK);
    g_bSubclassed = false; 
    }END:
    return ::CallNextHookEx(g_hHook, code, wParam, lParam);