我寫了一個託盤程序,前面的功能都正常。最近新家了一個菜單項,在點擊該菜單項時將我自己的一個DLL注入到其他的程序中。
DLL中有一個消息鉤子,兩個版本鉤子都正確。可是在Release版本中消息鉤子函數根本沒有被調用,Debug版本完全正常,所有功能都能實現。
大家幫幫忙呀!很急。不知道是託盤程序的問題還是DLL的問題。用Debug版託盤主程序+Release版DLL沒有問題,但是是Release版主程序+debug版DLL沒有反應。

解决方案 »

  1.   

    ASSERT在Release版本中是不会被编译的你去找一下
    DEBUG和RELEASE 版本差异及调试相关问题
    可查看:http://www.ieee.org.cn/dispbbs.asp?boardID=61&ID=38904
      

  2.   

    同一个程序的Release版和debug版实际上是不一样的,
    里面会有好多区别,千万不能混用。
    否则会出很多把你煮了也解决不了的bug
      

  3.   

    DLL和主程序都用Release版也有問題,我現在不知道問題在哪裡,所以才混用的。
      

  4.   

    你Dll注入成功了吗,何不Attach上调试一下看中间哪步有没有fail掉
      

  5.   

    Release版本检测的比较严格,比如变量的初始化值debug会给其初始化,Release就有可能没有。
    如果还不行的话,就用message探测的办法一步一步来定位了。
      

  6.   

    下面是转载的关于release报错  但debug正常的几种情况1. Runtime Library:链接哪种运行时刻函数库通常只对程序的性能产生影响。调试版本的 Runtime Library 包含了调试信息,并采用了一些保护机制以帮助发现错误,因此性能不如发布版本。编译器提供的 Runtime Library 通常很稳定,不会造成 Release 版错误;倒是由于 Debug 的 Runtime Library 加强了对错误的检测,如堆内存分配,有时会出现 Debug 有错但 Release 正常的现象。应当指出的是,如果 Debug 有错,即使 Release 正常,程序肯定是有 Bug 的,只不过可能是 Release 版的某次运行没有表现出来而已。 
      2. 优化:这是造成错误的主要原因,因为关闭优化时源程序基本上是直接翻译的,而打开优化后编译器会作出一系列假设。这类错误主要有以下几种: 
      (1) 帧指针(Frame Pointer)省略(简称 FPO ):在函数调用过程中,所有调用信息(返回地址、参数)以及自动变量都是放在栈中的。若函数的声明与实现不同(参数、返回值、调用方式),就会产生错误 ————但 Debug 方式下,栈的访问通过 EBP 寄存器保存的地址实现,如果没有发生数组越界之类的错误(或是越界“不多”),函数通常能正常执行;Release 方式下,优化会省略 EBP 栈基址指针,这样通过一个全局指针访问栈就会造成返回地址错误是程序崩溃。C++ 的强类型特性能检查出大多数这样的错误,但如果用了强制类型转换,就不行了。你可以在 Release 版本中强制加入 /Oy- 编译选项来关掉帧指针省略,以确定是否此类错误。此类错误通常有: 
      ● MFC 消息响应函数书写错误。正确的应为 
      afx_msg LRESULT OnMessageOwn(WPARAM wparam, LPARAM lparam); 
      ON_MESSAGE 宏包含强制类型转换。防止这种错误的方法之一是重定义 ON_MESSAGE 宏,把下列代码加到 stdafx.h 中(在#include "afxwin.h"之后),函数原形错误时编译会报错 
      #undef ON_MESSAGE 
      #define ON_MESSAGE(message, memberFxn) { message, 0, 0, 0, AfxSig_lwl, (AFX_PMSG)(AFX_PMSGW)(static_cast< LRESULT (AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM) > (&memberFxn) }, (2) volatile 型变量:volatile 告诉编译器该变量可能被程序之外的未知方式修改(如系统、其他进程和线程)。优化程序为了使程序性能提高,常把一些变量放在寄存器中(类似于 register 关键字),而其他进程只能对该变量所在的内存进行修改,而寄存器中的值没变。如果你的程序是多线程的,或者你发现某个变量的值与预期的不符而你确信已正确的设置了,则很可能遇到这样的问题。这种错误有时会表现为程序在最快优化出错而最小优化正常。把你认为可疑的变量加上 volatile 试试。 
      (3) 变量优化:优化程序会根据变量的使用情况优化变量。例如,函数中有一个未被使用的变量,在 Debug 版中它有可能掩盖一个数组越界,而在 Release 版中,这个变量很可能被优化调,此时数组越界会破坏栈中有用的数据。当然,实际的情况会比这复杂得多。与此有关的错误有: 
      ● 非法访问,包括数组越界、指针错误等。例如 
    [pre]  void fn(void)  {  int i;  i = 1;  int a[4];  {  int j;  j = 1;  }  a[-1] = 1;//当然错误不会这么明显,例如下标是变量  a[4] = 1;        }[/pre]    j 虽然在数组越界时已出了作用域,但其空间并未收回,因而 i 和 j 就会掩盖越界。而 Release 版由于 i、j 并未其很大作用可能会被优化掉,从而使栈被破坏。 
      3. _DEBUG 与 NDEBUG :当定义了 _DEBUG 时,assert() 函数会被编译,而 NDEBUG 时不被编译。除此之外,VC++中还有一系列断言宏。这包括: 
    [pre]  ANSI C 断言 void assert(int expression );  C Runtime Lib 断言 _ASSERT( booleanExpression );  _ASSERTE( booleanExpression );  MFC 断言 ASSERT( booleanExpression );  VERIFY( booleanExpression );  ASSERT_VALID( pObject );  ASSERT_KINDOF( classname, pobject );  ATL 断言 ATLASSERT( booleanExpression ); [/pre]    此外,TRACE() 宏的编译也受 _DEBUG 控制。 
      所有这些断言都只在 Debug版中才被编译,而在 Release 版中被忽略。唯一的例外是 VERIFY() .事实上,这些宏都是调用了 assert() 函数,只不过附加了一些与库有关的调试代码。如果你在这些宏中加入了任何程序代码,而不只是布尔表达式(例如赋值、能改变变量值的函数调用 等),那么 Release 版都不会执行这些操作,从而造成错误。初学者很容易犯这类错误,查找的方法也很简单,因为这些宏都已在上面列出,只要利用 VC++ 的 Find in Files 功能在工程所有文件中找到用这些宏的地方再一一检查即可。另外,有些高手可能还会加入 #ifdef _DEBUG 之类的条件编译,也要注意一下。 
      顺便值得一提的是 VERIFY() 宏,这个宏允许你将程序代码放在布尔表达式里。这个宏通常用来检查 Windows API 的返回值。有些人可能为这个原因而滥用 VERIFY() ,事实上这是危险的,因为 VERIFY() 违反了断言的思想,不能使程序代码和调试代码完全分离,最终可能会带来很多麻烦。因此,专家们建议尽量少用这个宏。 
      4. /GZ 选项:这个选项会做以下这些事 
      (1) 初始化内存和变量。包括用 0xCC 初始化所有自动变量,0xCD ( Cleared Data ) 初始化堆中分配的内存(即动态分配的内存,例如 new ),0xDD ( Dead Data ) 填充已被释放的堆内存(例如 delete ),0xFD( deFencde Data ) 初始化受保护的内存(debug 版在动态分配内存的前后加入保护内存以防止越界访问),其中括号中的词是微软建议的助记词。这样做的好处是这些值都很大,作为指针是不可能的(而且 32 位系统中指针很少是奇数值,在有些系统中奇数的指针会产生运行时错误),作为数值也很少遇到,而且这些值也很容易辨认,因此这很有利于在 Debug 版中发现 Release 版才会遇到的错误。要特别注意的是,很多人认为编译器会用 0 来初始化变量,这是错误的(而且这样很不利于查找错误)。 
      (2) 通过函数指针调用函数时,会通过检查栈指针验证函数调用的匹配性。(防止原形不匹配) 
      (3) 函数返回前检查栈指针,确认未被修改。(防止越界访问和原形不匹配,与第二项合在一起可大致模拟帧指针省略 FPO ) 
      通常 /GZ 选项会造成 Debug 版出错而 Release 版正常的现象,因为 Release 版中未初始化的变量是随机的,这有可能使指针指向一个有效地址而掩盖了非法访问。 
      除此之外,/Gm /GF 等选项造成错误的情况比较少,而且他们的效果显而易见,比较容易发现。 
      

  7.   

    回复thenshesaid :
       DLL注入成功了。回复na_he :
       我的变量都初始化了,没使用未初始化的变量。回复wangtengchao :
       我的响应函数是ON_COMMAND
      

  8.   

    1. 确认钩子注册成功
    2. 用Process Explorer查看DLL是不是被LOAD入其他进程了
    3. 钩子处理过程可以打印一些信息看是否进入
    4. 钩子DLL是否依赖到了其他DLL?如MSVCRTD之类
      

  9.   

    1. 确认钩子注册成功 
    2. 用Process Explorer查看DLL是不是被LOAD入其他进程了 
    3. 钩子处理过程可以打印一些信息看是否进入 
    4. 钩子DLL是否依赖到了其他DLL?如MSVCRTD之类 
    1.确认过了
    3.处理过程进入了
    4.不依赖
      

  10.   

    指针好好检查下,还有程序里的try catch看抛出的异常是否能正确的被catch昨天我就因为
    抛出的异常是一个类,而catch那是一个指针导致我程序老自动关闭。我初学,经验不多,仅供参考。
      

  11.   

    使用结构体时,结构体大小是否指定?
    托盘程序的 NOTIFYICONDATA 中的成员cbSize 不能用sizeof(NOTIFYICONDATA)取得,应该用shellapi.h中提供的宏,其实就是sizeof取得的大小减去最后一个有效成员的大小。
      

  12.   

    回复lfm13720 :
        我是用sizeof(NOTIFYICONDATA),可是在我没加新功能之前正常呀!应该和这个没关系吧?回复nwao7890 :
        我没用try catch。是不是DLL中的指针也要分配内存呀?我是直接强制转换的参数。LRESULT CALLBACK CallWndRetProc(int nCode, WPARAM wParam, LPARAM lParam)
    {
    CWPRETSTRUCT* cMes = (CWPRETSTRUCT*)lParam;
    ……
    return CallNextHookEx(g_hhook, nCode, wParam, lParam);
    }
      

  13.   


    顶!我一般都是这样的 尤其是DLL。
      

  14.   

    建议几在 DLL初始化函数处加个断点
      

  15.   


    BOOL bFind = FALSE; //是否启动QQ程序
    HWND parenthwnd = NULL; //QQ主程序句柄parenthwnd = ::FindWindowEx(NULL, parenthwnd, "#32770", NULL);
    HWND hwnd = parenthwnd; //第一个找到的句柄
    do 
    {
    //QQ特有的类,用来确认找到的句柄属于QQ早期版本
    HWND childHwnd = ::FindWindowEx(parenthwnd, NULL, "Tencent_QQBar", "");
    //找到启动的早期QQ程序,跳出循环
    if (childHwnd)
    {
    bFind = TRUE;
    break;
    }
    //查找下一个窗口
    parenthwnd = ::FindWindowEx(NULL, parenthwnd, "#32770", NULL);
    } while (parenthwnd != hwnd); //遍历未结束
    if (bFind)
    {
    g_hhook = SetWindowsHookEx(WH_CALLWNDPROCRET, (HOOKPROC)CallWndRetProc, theApp.m_hInstance, 0);
    if (g_hhook)
    {
    //g_hhook成功,安装键盘钩子,捕捉是否要朗读聊天记录
    g_khook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)HookProc, theApp.m_hInstance, 0);
    return TRUE;
    }
    else
    AfxMessageBox("安装钩子失败,请再试一次!");
    return FALSE;
    }
    //未找到启动的QQ程序,提示用户启动QQ
    AfxMessageBox(_T("请先启动QQ2008程序!"));
    return FALSE;以上是安装钩子的代码。因为可能同时使用多个QQ,所以安装的是全局钩子,在钩子函数中进行判断是不是QQ程序。
    这个代码编译成DLL后,在Debug版中注入QQ成功,一切功能都可以完成。但是在RELEASE版中,DLL注入其他的进程都成功了,可是就是不能注入QQ所在的进程。为什么呀?是我的程序的问题吗?
      

  16.   

    关掉那些防护软件试试
    再不成试试CreateRemoteThread的方法注入DLL到QQ进程看成功否
    再不成就WinDbg在QQ进程断LoadLibrary看看