你的EXE是如何加载这个DLL的?
要知道如果是隐式链接,如果不引用DLL中的任何导出函数,则链接器会把该DLL从EXE的导入段中给取出的,最终导致DLL根本不会被加载到进程中。楼主需要用“进程查看器”之类的工具看下你的DLL是不是真的被加载到了EXE的地址空间了。
既然是DLL,那么DLL中最基本的DllMain含义楼主应该清楚吧,就像学习控制台编程,如果连main的含义都是一知半解就糟糕了。
要知道DllMain在 ul_reason_for_call等于DLL_PROCESS_ATTACH时,必须使DllMain函数返回TRUE,EXE才会成功加载该DLL的。
不管是隐式链接,还是显式链接, ul_reason_for_call的值最初都是DLL_PROCESS_ATTACH,我看见楼主的DLL代码根本就不对 ul_reason_for_call的值进行任何检查。起初, ul_reason_for_call的值为DLL_PROCESS_ATTACH,楼主必须应该使DllMain返回(return)TRUE,只有酱子EXE才会真正加载了这个DLL,可while(...)代码使得DllMain这个函数根本没有机会返回TRUE or FALSE;最奇怪的是最后是return messages.wParam。对于while这个语句的调用究竟放哪里好呢?呵呵,有办法的,但解释起来太麻烦了,估计楼主也无法理解。
楼主程序的构建环境是DLL,不能照搬EXE中的代码的,需要灵活运用,灵活应用的基础是要理解代码的含义,光知道有什么函数,有什么数据结构和怎样的调用顺序是远远不够的。
另外,提醒的是在DLL的DllMain有个很重要的hModule参数,这个参数就如同人的脊椎骨,绝对不能无视它的存在。像wincl.hInstance 的值就应该是hModule.
hModule究竟是什么东西,楼主需要有两块基石,一块是“进程地址空间布局”的分支知识,另一块是“PE文件布局”的分支知识。不易学习!
最后,不对ul_reason_for call进行检查也会使事情一团糟。要知道DllMain这个函数并不是只会被EXE调用一次的,当EXE程序对应的进程创建一个新的线程时,该函数也会被调用的,这个时候ul_reason_for_call值为DLL_THREAD_ATTACH,想象一下,如果进程里又创建了个新线程,楼主的DLL又会再创建一个窗口,这个算什么呢?当然,这个窗口在第二次是创建不起来的,因为RegisterClassEx会失败。