在DLL中创建窗口例程详解.docx
- 文档编号:14006803
- 上传时间:2023-06-19
- 格式:DOCX
- 页数:11
- 大小:19.18KB
在DLL中创建窗口例程详解.docx
《在DLL中创建窗口例程详解.docx》由会员分享,可在线阅读,更多相关《在DLL中创建窗口例程详解.docx(11页珍藏版)》请在冰点文库上搜索。
在DLL中创建窗口例程详解
关于DLL中创建窗口,实现消息处理的问题
有读者疑问:
我创建了一DLL工程,需要在DLL中创建一个窗口,然后实现其窗口消息处理。
用InitMsgWindow注册窗口类、创建窗口,经过调试,创建窗口成功(g_wndMsg不为空,GetLastError返回0)。
在窗口消息处理函数MyWinProc中需要对自定义消息SCS_MSG_DVBDATA等做处理。
在DLL导出函数中模拟了一个函数MyFun,不断向窗口发送自定义消息和WM_TIMER消息。
可是问题出来了,为何在调试过程中MyWinProc函数不响应呢?
或者说窗口捕获不到任何消息了。
请高手指教!
急!
!
HWNDg_wndMsg;//用于保存消息窗口的句柄
BOOLInitMsgWindow()
{//注册消息处理窗口类
WNDCLASSwc;
wc.style=CS_NOCLOSE¦CS_HREDRAW¦CS_VREDRAW;//窗口类型wc.lpfnWndProc=(WNDPROC)MyWinProc;//消息处理的回调函数wc.cbCl**tra=0;
wc.cbWndExtra=0;
wc.hInstance=AfxGetApp()->m_hInstance;wc.hIcon=NULL;
wc.hCursor=NULL;
wc.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);
wc.lpszMenuName=NULL;
wc.lpszClassName="MsgWindow";
if(!
:
:
RegisterClass(&wc))
returnFALSE;//创建消息处理窗口g_wndMsg=:
:
CreateWindow("MsgWindow","",WS_OVERLAPPEDWINDOW,0,0,50,50,NULL,NULL,AfxGetApp()->m_hInstance,NULL);
longerr=:
:
GetLastError();
if(!
g_wndMsg)
returnFALSE;
}//窗口消息处理函数LRESULTCALLBACKMyWinProc(HWNDhWnd,UINTmessage,WPARAMwParam,LPARAMlParam)
{switch(message)
{caseSCS_MSG_DVBCFG:
{break;}
caseSCS_MSG_DVBDATA:
{break;}
default:
return
DefWindowProc(hWnd,message,wParam,lParam);}
return0;}//DLL导出函数:
voidMyFun()
{for(inti=0;i<100;i)
{PostMessage(g_wndMsg,SCS_MSG_DVBDATA,NULL,NULL);
PostMessage(g_wndMsg,WM_TIMER,NULL,NULL);}
}
网友回答:
即使Dll创建了窗口,主程序如果没有消息循环的话Dll的窗口过程也没有机会得到调用。
举个例子,你在exe里面写:
MyFunc();Sleep(30000);那么在这30秒钟内你的消息都不可能得到执行。
但如果你写:
MyFunc();while(GetMessage(0,0,0,&msg)){DispatchMessage(&msg);}就可以得到执行。
当然如果主程序不是你自己写的就比较麻烦了,因为消息循环的代码很多种,甚至可以只取自己认识的窗口消息,忽略掉别的窗口的。
网友回答:
Up,如果我在DLL加一个消息循环的处理,可否解决呢?
思路:
单独生成一个线程,然后在该线程里进行消息循环处理,代码如下:
DWORDThdDealMessage(LPDWORDparam){MSGMsg;while(:
:
GetMessage(&Msg,NULL,0,0)){//处理SCS_MSG_DVBDATA消息if(Msg.message==SCS_MSG_DVBDATA){//DoSomething}if(Msg.message==WM_TIMER){//DoSomething}//TranslateMessage(&Msg);//DispatchMessage(&Msg);}return0;}}:
:
CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)TimerThread,0,0,NULL);可是结果还是失败啊。
怎样回事?
网友回答:
注意GetMessage的定义,它只能取本线程创建的窗口的消息。
当然你可以把窗口创建也放到线程函数中。
网友回答:
这样做,不是在DLL中加一个线程循环,而是调用DLL的这个函数(创建窗口那个)的时候,不直接创建窗口,而是创建一个线程,然后在线程里面,先创建窗口,再进入消息循环。
这时,DLL的函数已经返回,不会阻塞调用者执行。
窗口也有消息循环了。
工作就正常了。
那你随便发消息就可以了
在非主线程中创建窗口的方法
//============
//TITLE:
// 在非主线程中创建窗口
//AUTHOR:
// norains
//DATE:
// Saturday 29-December-2007
//Environment:
// VS2005+SDK-WINCE5.0-MIPSII
//================
很多朋友都会有过这样的经历,为什么在主线程中创建窗口且窗口工作很正常,但一移到非主线程(有的朋友喜欢叫它为工作线程),却无法正常工作.本文就这个问题和各位探讨,可能无法做到尽善尽美,但能抛砖引玉也算是欣慰了.
在主线程中创建一个能够正常工作的窗口,估计地球人都知道.
这是一段工作正常的代码:
#include"windows.h"
HWNDg_hWnd=NULL;
HINSTANCEg_hInst;
LRESULTWndProc(HWNDhWnd,UINTwMsg,WPARAMwParam,LPARAMlParam)
{
returnDefWindowProc(hWnd,wMsg,wParam,lParam);
}
voidCreateWnd(void)
{
WNDCLASSwc={0};
wc.style =0;
wc.lpfnWndProc =WndProc;
wc.cbClsExtra =0;
wc.cbWndExtra =0;
wc.hInstance =g_hInst;
wc.hIcon =NULL;
wc.hCursor =LoadCursor(NULL,IDC_ARROW);
wc.hbrBackground=(HBRUSH)GetSysColorBrush(COLOR_WINDOW);
wc.lpszMenuName =NULL;
wc.lpszClassName=TEXT("SimpleWindow");
RegisterClass(&wc);
g_hWnd=CreateWindowEx(0,
TEXT("SimpleWindow"),
TEXT("SimpleWindow"),
WS_VISIBLE,
0,
0,
200,
200,
NULL,
NULL,
g_hInst,
0);
}
intWINAPIWinMain( HINSTANCEhInstance,
HINSTANCEhPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
//TODO:
Placecodehere.
g_hInst=hInstance;
CreateWnd();
//Themessageloop
MSGmsg;
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return0;
}
如果我们创建一个线程,然后在这个线程中创建窗口,看看带给我们的是什么:
#include"windows.h"
HWNDg_hWnd=NULL;
HINSTANCEg_hInst;
LRESULTWndProc(HWNDhWnd,UINTwMsg,WPARAMwParam,LPARAMlParam)
{
returnDefWindowProc(hWnd,wMsg,wParam,lParam);
}
voidCreateWnd(void)
{
WNDCLASSwc={0};
wc.style =0;
wc.lpfnWndProc =WndProc;
wc.cbClsExtra =0;
wc.cbWndExtra =0;
wc.hInstance =g_hInst;
wc.hIcon =NULL;
wc.hCursor =LoadCursor(NULL,IDC_ARROW);
wc.hbrBackground=(HBRUSH)GetSysColorBrush(COLOR_WINDOW);
wc.lpszMenuName =NULL;
wc.lpszClassName=TEXT("SimpleWindow");
RegisterClass(&wc);
g_hWnd=CreateWindowEx(0,
TEXT("SimpleWindow"),
TEXT("SimpleWindow"),
WS_VISIBLE,
0,
0,
200,
200,
NULL,
NULL,
g_hInst,
0);
}
DWORDCreateThread(PVOIDpArg)
{
CreateWnd();
return0;
}
intWINAPIWinMain( HINSTANCEhInstance,
HINSTANCEhPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
//TODO:
Placecodehere.
g_hInst=hInstance;
HANDLEhThrd=CreateThread(NULL,0,CreateThread,NULL,0,NULL);
CloseHandle(hThrd);
//Themessageloop
MSGmsg;
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return0;
}
我们似乎什么都没见到,只是窗口一闪,啥都没了.因为g_hWnd为全局变量,我们的理智告诉我们,在主线程没有退出之前,g_hWnd是不会销毁的.而用断点调试,将会发现在WndProc函数中只能接收WM_CREATE及以后一些消息,之后的再也收不到了,特别是WM_PAINT似乎就凭空消失了!
那么,代码什么都没变更,只是移动到了分线程中,为何会出现这个问题呢?
一切似乎很简单,在MSDN中我们找到了答案(原文见:
Inamultithreadedapplication,anythreadcancalltheCreateWindow()APItocreateawindow.Therearenorestrictionsonwhichthread(s)cancreatewindows.
Itisimportanttonotethatthemessageloopandwindowprocedureforthewindowmustbeinthethreadthatcreatedthewindow.Ifadifferentthreadcreatesthewindow,thewindowwon’tgetmessagesfromDispatchMessage(),butwillgetmessagesfromothersources.Therefore,thewindowwillappearbutwon’tshowactivationorrepaint,cannotbemoved,won’treceivemousemessages,andsoon.
该段话大意是:
窗口在任何线程中都可以创建,但消息循环必须要和创建窗口在同一线程,否则窗口将无法从DispatchMessage()获取任何消息!
原来如此,最重要是这么一句:
Itisimportanttonotethatthemessageloopandwindowprocedureforthewindowmustbeinthethreadthatcreatedthewindow.
好吧,那么我们在支线程中放置消息循环代码,看看是什么结果吧:
#include"windows.h"
HWNDg_hWnd=NULL;
HINSTANCEg_hInst;
LRESULTWndProc(HWNDhWnd,UINTwMsg,WPARAMwParam,LPARAMlParam)
{
returnDefWindowProc(hWnd,wMsg,wParam,lParam);
}
voidCreateWnd(void)
{
WNDCLASSwc={0};
wc.style =0;
wc.lpfnWndProc =WndProc;
wc.cbClsExtra =0;
wc.cbWndExtra =0;
wc.hInstance =g_hInst;
wc.hIcon =NULL;
wc.hCursor =LoadCursor(NULL,IDC_ARROW);
wc.hbrBackground=(HBRUSH)GetSysColorBrush(COLOR_WINDOW);
wc.lpszMenuName =NULL;
wc.lpszClassName=TEXT("SimpleWindow");
RegisterClass(&wc);
g_hWnd=CreateWindowEx(0,
TEXT("SimpleWindow"),
TEXT("SimpleWindow"),
WS_VISIBLE,
0,
0,
200,
200,
NULL,
NULL,
g_hInst,
0);
}
DWORDCreateThread(PVOIDpArg)
{
CreateWnd();
//Themessageloop
MSGmsg;
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return0;
}
intWINAPIWinMain( HINSTANCEhInstance,
HINSTANCEhPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
//TODO:
Placecodehere.
g_hInst=hInstance;
HANDLEhThrd=CreateThread(NULL,0,CreateThread,NULL,0,NULL);
CloseHandle(hThrd);
MSGmsg;
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
} return0;
}
一切正常,如同在主线程创建一样!
当然了,还有点需要注意的,在这个例子中,由于消息循环在主线程和分线程都分别存在,如果在WndProc()调用PostQuitMessage(),那么退出的也仅仅是分线程,而主线程还是会不停地在等待消息,从而导致程序无法正常退出.不过倒不用过分担心,和这个示例代码不同,在实际代码编写中,在主线程往往都会创建主窗口,而在这个主窗口消息处理函数调用PostQuitMessage()则完全可以让主线程正常退出
事实告诉我们,非主线程创建窗口也能工作正常,只要我们注意一点:
消息循环必须要和创建窗口在同一线程!
VC中关于线程中创建对话框的问题
我用一个dll做了一对话框,希望在主窗口中弹出来,由于整体设计问题,所以需要是dll。
主程序中的调用dll的代码如下:
UINTProc(LPVOIDWParam)
{
typedefvoid(WINAPI*MYFUNC)(HWNDhWnd,WPARAMwParam,LPARAMlParam);
HINSTANCEhInstance;
hInstance=LoadLibrary(abc.dll);
MYFUNCmyFun=(MYFUNC)GetProcAddress(hInstance,abcdef);
myFun((HWND)WParam,0,0);
return1;
}
voidCTestDlg:
:
OnBnClickedOk()
{
//TODO:
在此添加控件通知处理程序代码
AfxBeginThread(Proc,GetSafeHwnd());
//OnOK();
}
该对话框能够被调用起来,但是问题是该对话框起来后,主窗口被禁止了,就像模态对话框一样。
我dll中的代码如下:
voidWINAPIDCSmallGhost(HWNDhWnd,WPARAMwParam,LPARAMlParam)
{
try{
CSmallGhostdlg;
dlg.Create(IDD_ABC);
dlg.ShowWindow(SW_SHOW);
Sleep(10000);
}
catch(...){
}
}
}
麻烦各位兄弟帮我看看,我认为即使我在dll中用的是dlg.modal也不应该是这样的效果,
主界面不应该被阻止,麻烦各位大侠指点一下,谢谢!
dll中的函数名也应该改成如下,不好意思,请各位大侠看看,谢谢了!
voidWINAPIabcdef(HWNDhWnd,WPARAMwParam,LPARAMlParam)
{
try{
CSmallGhostdlg;
dlg.Create(IDD_ABC);
dlg.ShowWindow(SW_SHOW);
Sleep(10000);
}
catch(...){
}
}
}
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- DLL 创建 窗口 例程 详解