??xml version="1.0" encoding="utf-8" standalone="yes"?>国产精品久久久亚洲,久久夜色精品国产,大香伊人久久精品一区二区http://www.shnenglu.com/cppblog/category/2192.html??????????/description>zh-cnTue, 20 May 2008 00:29:33 GMTTue, 20 May 2008 00:29:33 GMT60《VC++动态链接库深入出》学习笔CNon-MFC DLL(?MFC 动态库)http://www.shnenglu.com/cppblog/archive/2007/02/05/18356.html潜龙?/dc:creator>潜龙?/author>Mon, 05 Feb 2007 12:20:00 GMThttp://www.shnenglu.com/cppblog/archive/2007/02/05/18356.htmlhttp://www.shnenglu.com/cppblog/comments/18356.htmlhttp://www.shnenglu.com/cppblog/archive/2007/02/05/18356.html#Feedback0http://www.shnenglu.com/cppblog/comments/commentRss/18356.htmlhttp://www.shnenglu.com/cppblog/services/trackbacks/18356.html静态链接库与动态链接库M区别Q?br /> 
        静态链接库与动态链接库都是׃n代码的方式,如果采用静态链接库Q则无论你愿不愿意,lib 中的指o都全部被直接包含在最l生成的 EXE 文g中了。但是若使用 DLLQ该 DLL 不必被包含在最l?EXE 文g中,EXE 文g执行时可以“动态”地引用和卸载这个与 EXE 独立?DLL 文g。静态链接库和动态链接库的另外一个区别在于静态链接库中不能再包含其他的动态链接库或者静态库Q而在动态链接库中还可以再包含其他的动态或静态链接库。静态链接库与静态链接库调用规则M比较如下?/p>

对于静态链接库(比较?Q?br />首先Q静态链接库的用需要库的开发者提供生成库?h头文件和.lib文g?br />
生成库的.h头文件中的声明格式如下:
extern "C" 函数q回cd 函数?参数?;
在调用程序的.cpp源代码文件中如下Q?br />#include "..\lib.h"
#pragma comment(lib,"..\\debug\\libTest.lib")
//指定与静态库一起链?br />
W二Q因为静态链接库是将全部指o都包含入调用E序生成的EXE文g中。因此如果用的是静态链接库Q那么也׃存在“导出某个函数提供给用户使用”的情况Q要想用得全要Q要不就都别要!:)

对于动态链接库Q?br />动态链接库的用需要库的开发者提供生成的.lib文g?dll文g。或者只提供dll文g?br />首先我们必须先注意到DLL内的函数分ؓ两种Q?
(1)DLL 导出函数Q可供应用程序调用;
(2)DLL 内部函数Q只能在 DLL E序使用Q应用程序无法调用它们?br />因此调用E序若想调用DLL中的某个函数p以某UŞ式或方式指明它到底想调用哪一个函数?/p>

因此q里衍生Z个问题:
W一Q如何调用?卌用的方式
W二Q不同调用方式对应的库的生成q程和调用规?/p>

我逐步展开问题?br />W一Q存在两U调用方式——动态调用和静态调?br />W二Q两U调用方式的库的生成q程和调用规?br />1〉动态调?br />
生成库的.h头文件中的声明格式如下:
extern "C" 函数q回cd __declspec(dllexport) 函数?参数?;
在调用程序的.cpp源代码文件中按如下流E调用:
在main函数代码的开始处
定义需要的DLL模块的句柄和此DLL模块模块中需要调用的函数的函数指针?br />定义好后紧接着是标准的三部曲Q?br />取得需要的DLL模块------>q回模块句柄
LoadLibrary("DLL模块路径")
取得需要的函数地址——?gt;q回函数指针GetProcAddress(模块句柄Q?函数?)
从内存中卸蝲DLL模块——?gt;FreeLibrary(模块句柄)
2>静态调?br />在调用程序的.cpp源代码文件中按如下流E调用:
#include.........
告诉~译器与 DLL 相对应的.lib 文g所在的路径及文件名
#pragma comment(lib,"路径和文件名")
extern "C" 函数q回cd _declspec(dllimport) 函数?参数?分号
int main()
{
..............
}
未完Q待l?......



]]>
转脓QVC++中对于处理消息的学习ȝhttp://www.shnenglu.com/cppblog/archive/2006/07/20/10248.html潜龙?/dc:creator>潜龙?/author>Thu, 20 Jul 2006 03:25:00 GMThttp://www.shnenglu.com/cppblog/archive/2006/07/20/10248.htmlhttp://www.shnenglu.com/cppblog/comments/10248.htmlhttp://www.shnenglu.com/cppblog/archive/2006/07/20/10248.html#Feedback0http://www.shnenglu.com/cppblog/comments/commentRss/10248.htmlhttp://www.shnenglu.com/cppblog/services/trackbacks/10248.htmlMessage Map

struct AFX_MSGMAP //消息映射?br />{
AFX_MSGMAP* pBaseMessageMap; //基类消息映射表的指针Q?br />AFX_MSGMAP_ENTRY* lpEntries; //消息入口表的指针Q?br />};

struct AFX_MSGMAP_ENTRY //消息映射入口?br />{
UINT nMessage; //消息Q?br />UINT nCode; //控g的通知码或WM_NOTIFY的通知?br />UINT nID; //控g的IDQ?0时ؓ Window 消息)
UINT nLastID; //最后一个控件的IDQ?br />UINT nSig; //信号cdQ?br />AFX_PMSG pfn; //消息函数的指针;
};

typedef void (CCmdTarget::*AFX_PMSG)(void); //消息映射函数Q?/p>

一、消息映图
1、DECLARE_MESSAGE_MAP()
展开Q?br />static AFX_MSGMAP_ENTRY _messageEntries[] //消息映射入口?
static AFX_MSGMAP messageMapQ?//消息映射表;
virtual AFX_MSGMAP* GetMessageMap() constQ?/q回消息映射 表的指针Q?/p>

2、BEGIN_MESSAGE_MAP(class_name,base_class_name)
①、定义GetMessageMap()函数Q代码如下:
{ return &class_name::messageMapQ}
②、初始化消息映射表,代码如下Q?br />AFX_MSGMAP class_name::messageMap={
&(base_class_name::messageMap)Q?br />&(class_name::_messageEntries)
}
③、初始化消息入口?br />AFX_MSGMAP_ENTRY class_name::_messageEntries[]={
//在这里添加消息和映射函数Q?/p>

3、END_MESSAGE_MAP()
{0,0,0,0,AfxSig_end,(AFX_PMSG)0}
} Q?//该括号和③相对应Q?/p>


二、消息类?br />1、命令消?WM_COMMAND)
所有派生自 CCmdTarget 的类都有资格接受WM_COMMAND?/p>

2、Window消息(WM_xxx)
所有派生自 CWnd 的类都有资格接受 WM_xxx?/p>

3、控件消?WM_NOTIFY)
控g向其父窗口通知消息?/p>

三、消息处?br />1、WM_xxx 消息处理
H口c?自n)处理→基cd理→CWnd∷DefWindowProc()处理Q?br />其所对应的宏一般ؓ在消?WM_ 前面加上 ON_?/p>

2、命令消息处?br />命o消息来自命o用户接口对象(菜单、加速键或工h按钮)发出的WM_COMMAND消息Q?br />㈠、WM_COMMAND消息
其所包含的类型和对应的宏如下Q?br />①、ON_COMMAND(ID,pfn)
标准的命令消息;

②、ON_COMMAND_EX(ID,pfn)
多个对象对同一个命?ID 的处理;
其函数的原型如下Q?br />afx_msg BOOL pfn(UINT nID)
说明Q?br />当返?TRUE 时表C已l处理,不用在消息处理链中l处理该命oQؓ FALSE 时表Cl在消息处理链中处理该命令?br />注意Q?br />其一Q在多对象处理中一定要使用该宏Q?br />其二Qpfn(UINT nID)(消息处理函数)q回值将其类型voidҎBOOLQ而且必须为FALSEQ?br />其三Q多个对象的处理是由高层向低层的q程Q即视图cZL架窗口类→应用程序类Q?/p>

③、ON_COMMAND_RANGE(nID,nLastID,pfn)
多个命o ID 提供相同的处理;
注意Q?br />其一Q确保nID、nLastID的值在 Resource.h 中是q箋的?br />其二Q一般在函数 pfn(UINT nID) 中加入参敎ͼ用来定那一个按钮点凅R?/p>

㈡、CN_UPDATE_COMMAND_UI消息
当菜单项、工h按钮{[命o用户接口对象]要更新其状态时所对应的消息,它所包含的类型和对应的宏如下Q?br />①、ON_UPDATE_COMMAND_UI(ID,pfn)
其中函数的原型如下:
afx_msg void pfn(CCmdUI* pCmdUI)

②、ON_UPDATE_COMMAND_UI_RANGE(nID,nLastID,pfn)
该函数可以处理一l[命o用户接口对象]的外观;
其中函数的原型如下:
afx_msg void pfn(CCmdUI* pCmdUI)
重要Q?br />CCmdUI 中的 m_nID 成员表示不同?IDQ因此可以利用它来进行区别处理?/p>

3、控件的通知消息
从控件和子窗口发送到父窗口的WM_COMMAND通知消息(卛_发送命令消息中加入控g的通知??br />注意Q在 Window9x 新控件中不再传送WM_COMMAND通知消息Q而是发?WM_NOTIFY 消息Q但Z兼容Q旧有的控gq是传送WM_COMMAND消息?br />例如Q?br />CEdit控g向父H口发?EN_CHANGE 通知代码的WM_COMMAND消息?br />注意Q框架像传送其?WM_ 消息一样传送通知消息Q但有一个例外,即由 [按钮] 控g发送的 BN_CLICKED 通知消息Q被作ؓ命o消息特别处理?br />㈠、WM_COMMAND 其所对应的宏如下Q?br />①、ON_CONTROL(通知? nID,fn)
②、ON_CONTROL_RANGE(通知? nFirstID,nEndID,fn)
注意Q?br />q两个宏的应用和 ON_COMMAND、ON_COMMAND_RANGE相同Q所不同的是在宏前面加入[通知码]?br />注意Q可以根据不同的控g的[通知码]z出特定的宏,其所z的宏一般ؓ?[通知码] 前面加上 ON_?br />㈡、WM_NOTIFY 其所对应的宏如下Q?br />①、ON_NOTIFY(通知? nID,fn)
其中函数的原型如下:
afx_msg void fn(NMHDR* pNotifyStruct,LRESULT* result)
其中l构Q?br />typedef struct tagNMHDR {
HWND hwndFrom; //发送通知消息的控件的句柄Q?br />UINT idFrom; //发送通知消息的控件的 IDQ?br />UINT code; //通知码;
} NMHDR;

②、ON_NOTIFY_EX(通知? nID,fn)
表示一个消息在多个对象的成员函Cq行处理?br />其中函数的原型如下:
afx_msg BOOL fn(UINT nID,NMHDR* pNotifyStruct,LRESULT* result)
说明Q?br />它必返?BOOL cd的数|其意义和 ON_COMMAND_EX 相同?/p>

③、ON_NOTIFY_RANGE(通知? nFirstID,nEnd,fn)
表示多个控g的通知消息在同一个函Cq行处理?br />其中函数的原型如下:
afx_msg void fn(UINT nID,NMHDR* pNotifyStruct,LRESULT* result)
说明Q?br />其意义和ON_COMMAND_RANGE相同?/p>

4、反消息处?br />父窗口在处理控gH口的通知消息WM_CTLCOLOR、WM_COMMAND、WM_NOTIFYӞ会把该消息{化ؓ反射消息Qƈ转交l控件子H口处理Q只有在控g子窗体不处理该消息时Q父H口才有Z处理?br />注意Q在cȝ属性对话框中的消息面可查反射消息(前面?="标志)
①、WM_CTLCOLOR_REFLECT反射消息
其所对应的宏如下Q?br />ON_WM_CTLCOLOR_REFLECT()
反射消息函数的原型:
HBRUSH class_name∷CtlColor(CDC* pDC,UINT nCtlColor)
{
return NULL;
}
该函数用来重|控件的色Q注意:必须 return CBrush才有效?/p>


5、自定义的窗口消?br />自定义窗口消息的消息标志都大于WM_USER(臛_是WM_USER+100Q因多控仉使用q一范围的WM_USER消息)
使用自定义的消息分ؓ二步Q?br />①、在 Resource.h 中定义消息标?br />#define WM_MYMSG (WM_USER+1000)

②、在消息映射表中加入消息映射?br />BEGIN_MESSAGE_MAP()

ON_MESSAGE(WM_MYMSG,fn)
END_MESSAGE_MAP()
说明Q?br />其对应的宏ؓ ON_MESSAGE()Q其成员函数的原型ؓQ?br />afx_msg LRESULT fn(WPARAM,LPARAM)

6、登记消?br />①、在pȝ中注册ƈ获取一个登记消息的消息标记
UINT RegisterWindowMessage(LPCTSTR)
说明Q?br />通过 API 函数来注册消息标讎ͼ其中 LPCTSTR 为用LL字符丌Ӏ例如:
UINT WM_MYMSG=RegisterWindowMessage("MYMSG");
其中 WM_MYMSG 是自定义无符h型的消息标记?/p>

②、在消息映射表中加入消息映射?br />BEGIN_MESSAGE_MAP()

ON_REGISTERED_MESSAGE(WM_MYMSG,fn)
END_MESSAGE_MAP()
说明Q?br />其对应的宏ؓ ON_REGISTERED_MESSAGE()Q其成员函数的原型ؓQ?br />afx_msg LRESULT fn(WPARAM,LPARAM)
注意Q登记消息可以实现跨q程的数据通讯?/p>

7、线E消?br />只有l承自CWinThreadcL能允许处理线E消息?br />①、定义线E的消息标记
有两U方法:
(1)、用自定义的消息标讎ͼ卻IWM_USERQ?br />(2)、用登记的消息标记Q即QRegisterWindowMessageQ?/p>

②、在CWinThreadl承cȝ消息映射表中d?br />ON_THREAD_MESSAGE(消息标记,fn) //自定义的消息Q?br />ON_REGISTERED_THREAD_MESSAGE(消息标记,fn) //登记?//消息
③、其函数的原型如下:
afx_msg void fn(WPARAM wPARAM,LPARAM lParam)

④、引发线E消?br />U程消息的引发必调?CWinThread cȝPostThreadMessage消息投递到U程消息队列中?br />注意Q可以通过 AfxGetApp() 函数获取一个全局的应用对象?br />PostThreadMessage(UINT,WPARAM,LPARAM)

8、WM_COPYDATA
操作pȝl护一块内存来理 WM_COPYDATA 消息Q该消息主要用于跨进E传递数据,传递的数据量达?232?br />①、定义一?COPYDATASTRUCT 数据l构
typedef struct tagCOPYDATASTRUCT {
DWORD dwData; //自定义的Ҏ数据Q?br />DWORD cbData; //以字节ؓ单位?lpData 的大;
PVOID lpData; //传送的数据内存块的指针Q?br />} COPYDATASTRUCT;

②、其所对应的宏
ON_WM_COPYDATA()

③、其所对应的函数的原型
afx_msg BOOL OnCopyData(CWnd*,COPYDATASTRUCT*)
说明Q?br />CWnd*Q发送该消息的窗口的指针Q?/p>


9、投递和发送消?br />通过向一个窗体投递或发送消息,可以间接地驱动窗体的消息q程?br />投?PostMessage)Q将消息攑ֈU程的消息队列中Q然后不{线E处理该消息q接返回到调用斏V?br />发?SendMessage)Q当一个线E向目标U程发送消息时Q该U程要一直等待,直到目标U程处理了该消息为止?br />①、投递消?br />BOOL CWnd∷PostMessage(UINT,WPARAM=0,LPARAM=0)
说明Q?br />CWndQ目标窗口;
该函数将一条消息放入到应用E序的消息队列,然后不等H口处理q接返回?/p>

②、发送消?br />LRESULT CWnd∷SendMessage(UINT,WPARAM=0,LPARAM=0)
说明Q?br />CWndQ目标窗口;
该函数将一条消息放入到应用E序的消息队列,{待H口处理后才q回?br />Z避免U程陷入怹{待状态,可以用SendMessageTimeout代替SendMessageQ?br />LRESULT SendMessageTimeout(HWND,UINT,WPARAM,LPARAM,UINT,UINT,PDWORD_PTR)
说明Q?br />HWNDQ窗口句柄;
UINTQ消息发送的选项QؓSMTO_BLOCKӞ可以防止U程?限等待,x据一定的时D回?br />UINTQ超Ӟ以毫Uؓ单位Q?br />PDWORD_PTRQ返回|
注意QCWnd没有对该函数的包装?/p>

③、投递和发送消?br />BOOL CWnd∷SendNotifyMessage(UINT,WPARAM,LPARAM)
说明Q?br />CWndQ目标窗口;
该消息具有SendMessage和PostMessage两种功能Q?br />当目标窗口和发送窗口ؓ同一个线E时Q则相当于SendMessage的功能;否则当不为同一个线E时Q则为PostMessage的功能?/p>

6-1、投递和发?WM_XXX 消息
在发送标准的 WINDOW 消息Ӟ只要该消息?ID、wParam、lParam参数攑֜ SendMessage()和PostMessage()函数的相应位|即可?/p>

6-2、投递和发送命令消息和控g的通知消息
在投递和发送命令消息时Q消息的 ID?WM_COMMADNQ而对于不同的菜单V加速键、控件则wParam、lParam的取g同?br />wParam分成低、高两部分,低部分ؓ菜单V加速键、控件的ID。高部分则:
菜单:0Q加速键Q?Q控Ӟ通知?br />lParamQ当控g时是控g的句柄,否则?NULL?/p>

对于wParam参数可以采用自定义宏Q?br />WPARAM MAKEWPARAM(WORD wLow,WORD wHigh)

6-3、投递和发送自定义的窗口消?br />在投递和发送自定义的窗口消息时Q参?wParam、lParam 没有特别的涵义,只和普通函数的形参一栯行数据的传递?br />注意Q?br />PostMessage ?SendMessage 是不同的Q前者投递后p回,而后者必ȝ到消息处理后再返回;所以在参数?[局部] ?[临时]Ӟ使用PostMessage函数会引发错?除非参数使用 指针Q则可避免错?Q而必M用SendMessage函数?br />6-4、投递和发送注册的H口消息
?6-3 基本一P但它要特别注意的问题是:在跨q程的处理消息时Q如果将消息PostMessage、SendMessage到某个进E?AQ则必须在进E?B 中获取进E?A 的窗口类名,q过H口cd获取H口的指针,最后再Ҏ指针调用 PostMessage、SendMessage 函数?br />注意Q在获取H口的指针时Q可以根据窗口类名或H口的标题?/p>


6-5、投递和发送WM_COPYDATA消息
SendMessage(消息标记,WPARAM,LPARAM)
其中Q?br />消息标记QWM_COPYDATAQ?br />WPARAMQ发送该消息的窗口句柄;
LPARAMQCOPYDATASTRUCTl构的指针,先通过(LPVOID)q行转换Q再通过(LPARAM)q行转换Q如下Ş式:
(LPARAM)(LPVOID)&cds



]]>
转脓QVC常用数据cd使用转换详解http://www.shnenglu.com/cppblog/archive/2006/07/20/10247.html潜龙?/dc:creator>潜龙?/author>Thu, 20 Jul 2006 03:24:00 GMThttp://www.shnenglu.com/cppblog/archive/2006/07/20/10247.htmlhttp://www.shnenglu.com/cppblog/comments/10247.htmlhttp://www.shnenglu.com/cppblog/archive/2006/07/20/10247.html#Feedback0http://www.shnenglu.com/cppblog/comments/commentRss/10247.htmlhttp://www.shnenglu.com/cppblog/services/trackbacks/10247.html我们先定义一些常见类型变量借以说明

int i = 100;
long l = 2001;
float f=300.2;
double d=12345.119;
char username[]="E佩?;
char temp[200];
char *buf;
CString str;
_variant_t v1;
_bstr_t v2;

一、其它数据类型{换ؓ字符?


短整?int)
itoa(i,temp,10);///i转换为字W串攑օtemp?最后一个数字表C十q制
itoa(i,temp,2); ///按二q制方式转换
长整?long)
ltoa(l,temp,10);
点?float,double)
用fcvt可以完成转换,q是MSDN中的例子:
int decimal, sign;
char *buffer;
double source = 3.1415926535;
buffer = _fcvt( source, 7, &decimal, &sign );
q行l果:source: 3.1415926535 buffer: '31415927' decimal: 1 sign: 0
decimal表示数点的位置,sign表示W号:0为正敎ͼ1?
CString变量
str = "2008北京奥运";
buf = (LPSTR)(LPCTSTR)str;
BSTR变量
BSTR bstrValue = ::SysAllocString(L"E序?);
char * buf = _com_util::ConvertBSTRToString(bstrValue);
SysFreeString(bstrValue);
AfxMessageBox(buf);
delete(buf);
CComBSTR变量
CComBSTR bstrVar("test");
char *buf = _com_util::ConvertBSTRToString(bstrVar.m_str);
AfxMessageBox(buf);
delete(buf);

_bstr_t变量
_bstr_tcd是对BSTR的封装,因ؓ已经重蝲?操作W,所以很Ҏ使用
_bstr_t bstrVar("test");
const char *buf = bstrVar;///不要修改buf中的内容
AfxMessageBox(buf);


通用Ҏ(针对非COM数据cd)
用sprintf完成转换
char  buffer[200];
char  c = '1';
int   i = 35;
long  j = 1000;
float f = 1.7320534f;
sprintf( buffer, "%c",c);
sprintf( buffer, "%d",i);
sprintf( buffer, "%d",j);
sprintf( buffer, "%f",f);

二、字W串转换为其它数据类?
strcpy(temp,"123");

短整?int)
i = atoi(temp);
长整?long)
l = atol(temp);
点(double)
d = atof(temp);
CString变量
CString name = temp;
BSTR变量
BSTR bstrValue = ::SysAllocString(L"E序?);
...///完成对bstrValue的?
SysFreeString(bstrValue);

CComBSTR变量
CComBSTRcd变量可以直接赋?
CComBSTR bstrVar1("test");
CComBSTR bstrVar2(temp);

_bstr_t变量
_bstr_tcd的变量可以直接赋?
_bstr_t bstrVar1("test");
_bstr_t bstrVar2(temp);


三、其它数据类型{换到CString
使用CString的成员函数Format来{?例如:


整数(int)
str.Format("%d",i);
点?float)
str.Format("%f",i);
字符串指?char *){已l被CString构造函数支持的数据cd可以直接赋?
str = username;
对于Format所不支持的数据cdQ可以通过上面所说的关于其它数据cd转化到char *的方法先转到char *Q然后赋值给CString变量?

四、BSTR、_bstr_t与CComBSTR


CComBSTR 是ATL对BSTR的封装,_bstr_t是C++对BSTR的封?BSTR?2位指?但ƈ不直接指向字串的~冲区?
char *转换到BSTR可以q样:
BSTR b=_com_util::ConvertStringToBSTR("数据");///使用前需要加上comutil.h和comsupp.lib
SysFreeString(bstrValue);
反之可以使用
char *p=_com_util::ConvertBSTRToString(b);
delete p;
具体可以参考一Q二D落里的具体说明?

CComBSTR与_bstr_t对大量的操作W进行了重蝲Q可以直接进?,!=,=={操作,所以用非常方ѝ?
特别是_bstr_t,大家使用它?


五、VARIANT 、_variant_t ?COleVariant


VARIANT的结构可以参考头文gVC98\Include\OAIDL.H中关于结构体tagVARIANT的定义?
对于VARIANT变量的赋|首先lvt成员赋|指明数据cdQ再对联合结构中相同数据cd的变量赋|举个例子Q?
VARIANT va;
int a=2001;
va.vt=VT_I4;///指明整型数据
va.lVal=a; ///赋?

对于不马上赋值的VARIANTQ最好先用Void VariantInit(VARIANTARG FAR* pvarg);q行初始?其本质是vt讄为VT_EMPTY,下表我们列Dvt与常用数据的对应关系:

Byte bVal;  // VT_UI1.
Short iVal;  // VT_I2.
long lVal;  // VT_I4.
float fltVal;  // VT_R4.
double dblVal;  // VT_R8.
VARIANT_BOOL boolVal;  // VT_BOOL.
SCODE scode;  // VT_ERROR.
CY cyVal;  // VT_CY.
DATE date;  // VT_DATE.
BSTR bstrVal;  // VT_BSTR.
DECIMAL FAR* pdecVal  // VT_BYREF|VT_DECIMAL.
IUnknown FAR* punkVal;  // VT_UNKNOWN.
IDispatch FAR* pdispVal;  // VT_DISPATCH.
SAFEARRAY FAR* parray;  // VT_ARRAY|*.
Byte FAR* pbVal;  // VT_BYREF|VT_UI1.
short FAR* piVal;  // VT_BYREF|VT_I2.
long FAR* plVal;  // VT_BYREF|VT_I4.
float FAR* pfltVal;  // VT_BYREF|VT_R4.
double FAR* pdblVal;  // VT_BYREF|VT_R8.
VARIANT_BOOL FAR* pboolVal;  // VT_BYREF|VT_BOOL.
SCODE FAR* pscode;  // VT_BYREF|VT_ERROR.
CY FAR* pcyVal;  // VT_BYREF|VT_CY.
DATE FAR* pdate;  // VT_BYREF|VT_DATE.
BSTR FAR* pbstrVal;  // VT_BYREF|VT_BSTR.
IUnknown FAR* FAR* ppunkVal;  // VT_BYREF|VT_UNKNOWN.
IDispatch FAR* FAR* ppdispVal;  // VT_BYREF|VT_DISPATCH.
SAFEARRAY FAR* FAR* pparray;  // VT_ARRAY|*.
VARIANT FAR* pvarVal;  // VT_BYREF|VT_VARIANT.
void FAR* byref;  // Generic ByRef.
char cVal;  // VT_I1.
unsigned short uiVal;  // VT_UI2.
unsigned long ulVal;  // VT_UI4.
int intVal;  // VT_INT.
unsigned int uintVal;  // VT_UINT.
char FAR * pcVal;  // VT_BYREF|VT_I1.
unsigned short FAR * puiVal;  // VT_BYREF|VT_UI2.
unsigned long FAR * pulVal;  // VT_BYREF|VT_UI4.
int FAR * pintVal;  // VT_BYREF|VT_INT.
unsigned int FAR * puintVal;  //VT_BYREF|VT_UINT.


_variant_t是VARIANT的封装类Q其赋值可以用强制类型{换,其构造函C自动处理q些数据cd?
使用旉加上#include
例如Q?
long l=222;
ing i=100;
_variant_t lVal(l);
lVal = (long)i;


COleVariant的用与_variant_t的方法基本一P请参考如下例子:
COleVariant v3 = "字符?, v4 = (long)1999;
CString str =(BSTR)v3.pbstrVal;
long i = v4.lVal;


六、其它一些COM数据cd

ҎProgID得到CLSID
HRESULT CLSIDFromProgID( LPCOLESTR lpszProgID,LPCLSID pclsid);
CLSID clsid;
CLSIDFromProgID( L"MAPI.Folder",&clsid);

ҎCLSID得到ProgID
WINOLEAPI ProgIDFromCLSID( REFCLSID clsid,LPOLESTR * lplpszProgID);
例如我们已经定义?CLSID_IApplication,下面的代码得到ProgID
LPOLESTR pProgID = 0;
ProgIDFromCLSID( CLSID_IApplication,&pProgID);
...///可以使用pProgID
CoTaskMemFree(pProgID);//不要忘记释放

七、ANSI与Unicode
UnicodeUCؓ宽字W型字串,COM里用的都是Unicode字符丌Ӏ?

ANSI转换到Unicode
(1)通过Lq个宏来实现Q例? CLSIDFromProgID( L"MAPI.Folder",&clsid);
(2)通过MultiByteToWideChar函数实现转换,例如:
char *szProgID = "MAPI.Folder";
WCHAR szWideProgID[128];
CLSID clsid;
long lLen = MultiByteToWideChar(CP_ACP,0,szProgID,strlen(szProgID),szWideProgID,sizeof(szWideProgID));
szWideProgID[lLen] = '\0';
(3)通过A2W宏来实现,例如:
USES_CONVERSION;
CLSIDFromProgID( A2W(szProgID),&clsid);
Unicode转换到ANSI
(1)使用WideCharToMultiByte,例如:
// 假设已经有了一个Unicode ?wszSomeString...
char szANSIString [MAX_PATH];
WideCharToMultiByte ( CP_ACP, WC_COMPOSITECHECK, wszSomeString, -1, szANSIString, sizeof(szANSIString), NULL, NULL );
(2)使用W2A宏来实现,例如:
USES_CONVERSION;
pTemp=W2A(wszSomeString);
八、其?

Ҏ息的处理中我们经帔R要将WPARAM或LPARAM{?2位数据(DWORD)分解成两?6位数据(WORD),例如Q?
LPARAM lParam;
WORD loValue = LOWORD(lParam);///取低16?
WORD hiValue = HIWORD(lParam);///取高16?


对于16位的数据(WORD)我们可以用同LҎ分解成高低两?位数?BYTE),例如:
WORD wValue;
BYTE loValue = LOBYTE(wValue);///取低8?
BYTE hiValue = HIBYTE(wValue);///取高8?


两个16位数据(WORDQ合?2位数?DWORD,LRESULT,LPARAM,或WPARAM)
LONG MAKELONG( WORD wLow, WORD wHigh );
WPARAM MAKEWPARAM( WORD wLow, WORD wHigh );
LPARAM MAKELPARAM( WORD wLow, WORD wHigh );
LRESULT MAKELRESULT( WORD wLow, WORD wHigh );


两个8位的数据(BYTE)合成16位的数据(WORD)
WORD MAKEWORD( BYTE bLow, BYTE bHigh );


从R(red),G(green),B(blue)三色得到COLORREFcd的颜色?
COLORREF RGB( BYTE byRed,BYTE byGreen,BYTE byBlue );
例如COLORREF bkcolor = RGB(0x22,0x98,0x34);


从COLORREFcd的颜色值得到RGB三个颜色?
BYTE Red = GetRValue(bkcolor); ///得到U颜?
BYTE Green = GetGValue(bkcolor); ///得到lK?
BYTE Blue = GetBValue(bkcolor); ///得到兰颜?


九、注意事?
假如需要用到ConvertBSTRToString此类函数,需要加上头文gcomutil.h,q在setting中加入comsupp.lib或者直接加?pragma comment( lib, "comsupp.lib" ) ?br />



]]>
转脓Q深度解析VC中的消息Q下Q?/title><link>http://www.shnenglu.com/cppblog/archive/2006/07/20/10246.html</link><dc:creator>潜龙?/dc:creator><author>潜龙?/author><pubDate>Thu, 20 Jul 2006 03:23:00 GMT</pubDate><guid>http://www.shnenglu.com/cppblog/archive/2006/07/20/10246.html</guid><wfw:comment>http://www.shnenglu.com/cppblog/comments/10246.html</wfw:comment><comments>http://www.shnenglu.com/cppblog/archive/2006/07/20/10246.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/cppblog/comments/commentRss/10246.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/cppblog/services/trackbacks/10246.html</trackback:ping><description><![CDATA[消息的接?<br /><br />   消息的接收主要有Q个函数QGetMessage、PeekMessage、WaitMessage?<br /><br />    GetMessage原型如下QBOOL GetMessage(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax); <br /><br />   该函数用来获取与hWnd参数所指定的窗口相关的且wMsgFilterMin和wMsgFilterMax参数所l出的消息D围内的消息。需要注意的是,如果hWnd为NULLQ则GetMessage获取属于调用该函数应用程序的MH口的消息,如果wMsgFilterMin和wMsgFilterMax都是Q,则GetMessagep回所有可得到的消息。函数获取之后将删除消息队列中的除WM_PAINT消息之外的其他消息,至于WM_PAINT则只有在其处理之后才被删除?<br /><br />   PeekMessage原型如下QBOOL PeekMessage(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax,UINT wRemoveMsgQ; <br /><br />   该函数用于查看应用程序的消息队列Q如果其中有消息将其放入lpMsg所指的l构中,不过Q与GetMessage不同的是QPeekMessage函数不会{到有消息放入队列时才返回。同P如果hWnd为NULLQ则PeekMessage获取属于调用该函数应用程序的MH口的消息,如果hWnd=-1Q那么函数只q回把hWnd参数为NULL的PostAppMessage函数送去的消息。如果wMsgFilterMin和wMsgFilterMax都是Q,则PeekMessagep回所有可得到的消息。函数获取之后将删除消息队列中的除WM_PAINT消息之外的其他消息,至于WM_PAINT则只有在其处理之后才被删除?<br /><br />   WaitMessage原型如下QBOOL VaitMessage();当一个应用程序无事可做时Q该函数将控制权交l另外的应用E序Q同时将该应用程序挂P直到一个新的消息被攑օ应用E序的队列之中才q回?<br /><br />   消息的处?<br /><br />   接下来我们谈一下消息的处理Q首先我们来看一下VC中的消息泵: <br /><br />   while(GetMessage(&msg, NULL, 0, 0)) <br />{ <br />if(!TranslateAccelerator(msg.hWnd, hAccelTable, &msg)) <br />{ <br />TranslateMessage(&msg); <br />DispatchMessage(&msg); <br />} <br />} <br /><br />   首先QGetMessage从进E的ȝE的消息队列中获取一个消息ƈ它复制到MSGl构Q如果队列中没有消息Q则GetMessage函数等待一个消息的到来以后才返回?如果你将一个窗口句柄作为第二个参数传入GetMessageQ那么只有指定窗口的的消息可以从队列中获得。GetMessage也可以从消息队列中过滤消息只接受消息队列中落在范围内的消息。这时候就要利用GetMessageQPeekMessage指定一个消息过滤器。这个过滤器是一个消息标识符的范围或者是一个窗体句柄,或者两者同时指定。当应用E序要查找一个后入消息队列的消息是很有用。WM_KEYFIRST ?WM_KEYLAST 帔R用于接受所有的键盘消息?WM_MOUSEFIRST ?WM_MOUSELAST 帔R用于接受所有的鼠标消息?<br /><br />   然后TranslateAccelerator判断该消息是不是一个按键消息ƈ且是一个加速键消息Q如果是Q则该函数将把几个按键消息{换成一个加速键消息传递给H口的回调函数。处理了加速键之后Q函数TranslateMessage把两个按键消息WM_KEYDOWN和WM_KEYUP转换成一个WM_CHARQ不q需要注意的是,消息WM_KEYDOWN,WM_KEYUP仍然传递给H口的回调函数?<br /><br />   处理完之后,DispatchMessage函数把此消息发送给该消息指定的H口中已讑֮的回调函数。如果消息是WM_QUITQ则GetMessageq回Q,从而退出@环体。应用程序可以用PostQuitMessage来结束自q消息循环。通常在主H口的WM_DESTROY消息中调用?<br /><br />   下面我们举一个常见的例子来说明q个消息늚q用Q?<br /><br />   if (::PeekMessage(&msg, m_hWnd, WM_KEYFIRST,WM_KEYLAST, PM_REMOVE)) <br />{ <br />if (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE)Q.Q?<br />} <br /><br />   q里我们接受所有的键盘消息Q所以就用WM_KEYFIRST ?WM_KEYLAST作ؓ参数。最后一个参数可以是PM_NOREMOVE 或?PM_REMOVEQ表C消息信息是否应该从消息队列中删除?<br /><br />   所以这D小代码是判断是否按下了Esc键,如果是就q行处理?<br /><br />H口q程 <br /><br />   H口q程是一个用于处理所有发送到q个H口的消息的函数。Q何一个窗口类都有一个窗口过E。同一个类的窗口用同LH口q程来响应消息?pȝ发送消息给H口q程消息数据作为参C递给他,消息到来之后Q按照消息类型排序进行处理,其中的参数则用来区分不同的消息,H口q程使用参数产生合适行为?<br /><br />   一个窗口过E不l常忽略消息Q如果他不处理,它会消息传回到执行默认的处理。窗口过E通过调用DefWindowProc来做q个处理。窗口过E必return一个g为它的消息处理结果。大多数H口只处理小部分消息和将其他的通过DefWindowProc传递给pȝ做默认的处理。窗口过E被所有属于同一个类的窗口共享,能ؓ不同的窗口处理消息。下面我们来看一下具体的实例Q?<br /><br />    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) <br />    { <br />int wmId, wmEvent; <br />PAINTSTRUCT ps; <br />HDC hdc; <br />TCHAR szHello[MAX_LOADSTRING]; <br />LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING); <br /><br />switch (message) <br />{ <br />case WM_COMMAND: <br />wmId = LOWORD(wParam); <br />wmEvent = HIWORD(wParam); <br />// Parse the menu selections: <br />switch (wmId) <br />{ <br />case IDM_ABOUT: <br />DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About); <br />break; <br />case IDM_EXIT: <br />DestroyWindow(hWnd); <br />break; <br />default: <br />return DefWindowProc(hWnd, message, wParam, lParam); <br />} <br />break; <br />case WM_PAINT: <br />hdc = BeginPaint(hWnd, &ps); <br />// TODO: Add any drawing code here... <br />RECT rt; <br />GetClientRect(hWnd, &rt); <br />DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER); <br />EndPaint(hWnd, &ps); <br />break; <br />case WM_DESTROY: <br />PostQuitMessage(0); <br />break; <br />default: <br />return DefWindowProc(hWnd, message, wParam, lParam); <br />    } <br />   return 0; <br />    } <br /><br />   消息分流?<br /><br />   通常的窗口过E是通过一个switch语句来实现的Q这个事情很烦,有没有更便的Ҏ呢?有,那就是消息分器Q利用消息分器Q我们可以把switch语句分成更小的函敎ͼ每一个消息都对应一个小函数Q这样做的好处就是对消息更容易管理?br /><br />          之所以被UCؓ消息分流器,是因ؓ它可以对M消息q行分流。下面我们做一个函数就很清楚了Q?<br /><br />   void MsgCracker(HWND hWnd,int id,HWND hWndCtl,UINT codeNotify) <br />{ <br />switch(id) <br />{ <br />case ID_A: <br />if(codeNotify==EN_CHANGE)... <br />break; <br />case ID_B: <br />if(codeNotify==BN_CLICKED)... <br />break; <br />.... <br />} <br />} <br /><br />   然后我们修改一下窗口过E: <br /><br />   LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) <br />{ <br />switch(message) <br />{ <br />HANDLE_MSG(hWnd,WM_COMMAND,MsgCracker); <br />HANDLE_MSG(hWnd,WM_DESTROY,MsgCracker); <br />default: <br />return DefWindowProc(hWnd, message, wParam, lParam); <br />    } <br />   return 0; <br />    } <br /><br />   在WindowsX.h中定义了如下的HANDLE_MSG宏: <br /><br />    #define HANDLE_MSG(hwnd,msg,fn) \ <br />switch(msg): return HANDLE_##msg((hwnd),(wParam),(lParam),(fn)); <br /><br />   实际上,HANDLE_WM_XXXX都是宏,例如QHANDLE_MSG(hWnd,WM_COMMAND,MsgCracker);被转换成如下定义: <br /><br />    #define HANDLE_WM_COMMAND(hwnd,wParam,lParam,fn)\ <br />((fn)((hwnd),(int)(LOWORD(wParam)),(HWND)(lParam),(UINT)HIWORD(wParam)),0L); <br /><br />   好了Q事情到了这一步,应该一切都明朗了?<br /><br />   不过Q我们发现在windowsx.h里面q有一个宏QFORWARD_WM_XXXXQ我们还是那WM_COMMANDZQ进行分析: <br /><br />    #define FORWARD_WM_COMMAND(hwnd, id, hwndCtl, codeNotify, fn) \ <br />(void)(fn)((hwnd), WM_COMMAND, MAKEWPARAM((UINT)(id),(UINT)(codeNotify)), (LPARAM)(HWND)(hwndCtl)) <br /><br />   所以实际上QFORWARD_WM_XXXX消息参数进行了重新构造,生成了wParam && lParamQ然后调用了我们定义的函数?<br /><br />MFC消息的处理实现方?<br /><br />   初看MFC中的各种消息Q以及在头脑中根p固的C++的媄响,我们可能很自然的׃惛_利用C++的三大特性之一Q虚拟机制来实现消息的传递,但是l过分析Q我们看C情ƈ不是x们想象的那样Q在MFC中消息是通过一U所谓的消息映射机制来处理的?<br /><br />   Z么呢Q在潘爱民老师译的《Visual C++技术内q》(W?版)中给Z详细的原因说明,我再要的说一遍。在CWndcM大约?10个消息,q有其它的MFC的类呢,v来消息太多了Q在C++中对E序中用到的每一个派生类都要有一个vtableQ每一个虚函数在vtable中都要占用一?字节大小的入口地址Q这样一来,对于每个特定cd的窗口或控gQ应用程序都需要一?40KB大小的表来支持虚拟消息控件函数?<br /><br />   如果说上面的H口或控件可以勉强实现的话,那么对于菜单命o消息及按钮命令消息呢Q因Z同的应用E序有不同的菜单和按钮,我们怎么处理呢?在MFC库的q种消息映射pȝ避免了使用大的vtableQƈ且能够在处理常规Windows消息的同时处理各U各L应用E序的命令消息?<br /><br />   说白了,MFC中的消息机制其实质是一张巨大的消息及其处理函数的一一对应表,然后加上分析处理q张表的应用框架内部的一些程序代?q样可以避免在SDK~程中用到的J琐的CASE语句?<br /><br />   MFC的消息映的基类CCmdTarget <br /><br />   如果你想让你的控件能够进行消息映,必MCCmdTargetcMz。CCmdTargetcLMFC处理命o消息的基、核心。MFCc设计了许多成员函数和一些成员数据,基本上是Z解决消息映射问题的,所有响应消息或事g的类都从它派生,例如Q应用程序类、框架类、文档类、视囄和各U各L控gcȝ{,q有很多?<br /><br />   不过q个c里面有Q个函数Ҏ息映非帔R要,一个是静态成员函数DispatchCmdMsgQ另一个是虚函数OnCmdMsg?<br /><br />   DispatchCmdMsg专门供MFC内部使用Q用来分发Windows消息。OnCmdMsg用来传递和发送消息、更新用L面对象的状态?<br /><br />   CCmdTarget对OnCmdMsg的默认实玎ͼ在当前命令目?this所?的类和基cȝ消息映射数组里搜索指定命令消息的消息处理函数?<br /><br />   q里使用虚拟函数GetMessageMap得到命o目标cȝ消息映射入口数组_messageEntriesQ然后在数组里匹配命令消息ID相同、控刉知代码也相同的消息映射条目。其中GetMessageMap是虚拟函敎ͼ所以可以确认当前命令目标的切cR?<br /><br />   如果扑ֈ了一个匹配的消息映射条目Q则使用DispachCmdMsg调用q个处理函数Q?<br /><br />   如果没有扑ֈQ则使用_GetBaseMessageMap得到基类的消息映数l,查找Q直到找到或搜寻了所有的基类Q到CCmdTargetQؓ止; <br /><br />   如果最后没有找刎ͼ则返回FASLE?<br /><br />   每个从CCmdTargetz的命令目标类都可以覆盖OnCmdMsgQ利用它来确定是否可以处理某条命令,如果不能Q就通过调用下一命o目标的OnCmdMsgQ把该命令送给下一个命令目标处理。通常Q派生类覆盖OnCmdMsg?Q要调用基类的被覆盖的OnCmdMsg?<br /><br />   在MFC框架中,一些MFC命o目标c覆盖了OnCmdMsgQ如框架H口c覆盖了该函敎ͼ实现了MFC的标准命令消息发送\径。必要的话,应用E序也可以覆盖OnCmdMsgQ改变一个或多个cM的发送规定,实现与标准框架发送规定不同的发送\径。例如,在以下情况可以作q样的处理:在要打断发送顺序的cM把命令传l一个非MFC默认对象Q在新的非默认对象中或在可能要传出命令的命o目标中?<br /><br />   消息映射的内?<br /><br />   通过ClassWizard为我们生成的代码Q我们可以看刎ͼ消息映射基本上分?大部分: <br /><br />   在头文g(.h)中有一个宏DECLARE_MESSAGE_MAP()Q他被放在了cȝ末尾Q是一个public属性的Q与之对应的是在实现部分Q?cpp)增加了一章消息映表Q内容如下: <br /><br />BEGIN_MESSAGE_MAP(当前c? 当前cȝ基类) <br />file://{{AFX_MSG_MAP(CMainFrame) <br /><br />  消息的入口项 <br /><br />file://}}AFX_MSG_MAP <br />END_MESSAGE_MAP() <br /><br />   但是仅是q两还q不以完成一条消息,要是一个消息工作,必须有以?个部分去协作Q?<br />1.在类的定义中加入相应的函数声明; <br /><br />  2.在类的消息映表中加入相应的消息映射入口; <br /><br />  3.在类的实C加入相应的函CQ?<br /><br />   消息的添?<br /><br />   有了上面的这些只是作为基Q我们接下来做我们最熟悉、最常用的工作:d消息。MFC消息的添加主要有2U方法:自动/手动Q我们就以这2U方法ؓ例,说一下如何添加消息?<br /><br />   1、利用Class Wizard实现自动d<br />   在菜单中选择View-->Class WizardQ也可以用单击鼠标右键,选择Class WizardQ同样可以激zClass Wizard。选择Message Map标签Q从Class namel合框中选取我们惌d消息的类。在Object IDs列表框中Q选取cȝ名称。此Ӟ Messages列表框显Ccȝ大多?若不是全部的?可重载成员函数和H口消息。类重蝲昄在列表的上部Q以实际虚构成员函数的大写字母来表C。其他ؓH口消息Q以大写字母出现Q描qC实际H口所能响应的消息ID。选中我们向添加的消息Q单击Add Function按钮QClass Wizard自动该消息dq来?<br /><br />   有时候,我们惌d的消息本应该出现在Message列表中,可是是找不刎ͼ怎么办?不要着急,我们可以利用Class Wizard上Class Info标签以扩展消息列表。在该页中,扑ֈMessage Filterl合框,通过它可以改变首中Messages列表框中的选项。这里,我们选择WindowQ从而显C所有的H口消息Q一把情况下Q你惌d的消息就可以在Message列表框中出现了,如果q没有,那就接着往下看Q) <br /><br />   2、手动地d消息处理函数 <br /><br />   如果在Messages列表框中仍然看不到我们想要的消息Q那么该消息可能是被pȝ忽略掉或者是你自己创建的Q在q种情况下,必自己手工添加。根据我们前面所说的消息工作?个部Ӟ我们一一q行处理Q?<br /><br />   1) 在类? h文g中添加处理函数的声明Q紧接在//}}AFX_MSG行之后加入声明,注意Q一定要以afx_msg开头?<br /><br />   通常Q添加处理函数声明的最好的地方是源代码中Class Wizardl护的表下面Q但是在它标记其领域的{{}}括弧外面。这些括弧中的Q何东襉K会被Class Wizard销毁?<br /><br />   2) 接着Q在用户cȝ.cpp文g中找?/}}AFX_MSG_MAP行,紧接在它之后加入消息入口V同P也是攑֜{ {} }的外?<br /><br />   3) 最后,在该文g中添加消息处理函数的实体<img src ="http://www.shnenglu.com/cppblog/aggbug/10246.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/cppblog/" target="_blank">潜龙?/a> 2006-07-20 11:23 <a href="http://www.shnenglu.com/cppblog/archive/2006/07/20/10246.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转脓Q深度解析VC中的消息(?http://www.shnenglu.com/cppblog/archive/2006/07/20/10245.html潜龙?/dc:creator>潜龙?/author>Thu, 20 Jul 2006 03:20:00 GMThttp://www.shnenglu.com/cppblog/archive/2006/07/20/10245.htmlhttp://www.shnenglu.com/cppblog/comments/10245.htmlhttp://www.shnenglu.com/cppblog/archive/2006/07/20/10245.html#Feedback0http://www.shnenglu.com/cppblog/comments/commentRss/10245.htmlhttp://www.shnenglu.com/cppblog/services/trackbacks/10245.html 队列消息和非队列消息
   从消息的发送途径来看Q消息可以分?U:队列消息和非队列消息。消息队列由可以分成pȝ消息队列和线E消息队列。系l消息队列由Windowsl护Q线E消息队列则由每个GUIU程自己q行l护Qؓ避免lnon-GUI现成创徏消息队列Q所有线E生时q没有消息队列,仅当U程W一ơ调用GDI函数数系l给U程创徏一个消息队列。队列消息送到pȝ消息队列Q然后到U程消息队列Q非队列消息直接送给目的H口q程?br />     对于队列消息Q最常见的是鼠标和键盘触发的消息Q例如WM_MOUSERMOVE,WM_CHAR{消息,q有一些其它的消息Q例如:WM_PAINT、WM_TIMER和WM_QUIT。当鼠标、键盘事件被触发后,相应的鼠标或键盘驱动E序׃把这些事件{换成相应的消息,然后输送到pȝ消息队列Q由Windowspȝ去进行处理。Windowspȝ则在适当的时机,从系l消息队列中取出一个消息,Ҏ前面我们所说的MSG消息l构定消息是要被送往那个H口Q然后把取出的消息送往创徏H口的线E的相应队列Q下面的事情pqE消息队列操心了QWindows开始忙自己的事情去了。线E看到自q消息队列中有消息Q就从队列中取出来,通过操作pȝ发送到合适的H口q程d理?br />     一般来ԌpȝL消息Post在消息队列的末尾。这样保证窗口以先进先出的顺序接受消息。然?WM_PAINT是一个例外,同一个窗口的多个 WM_PAINT被合q成一?WM_PAINT 消息, 合ƈ所有的无效区域C个无效区域。合qWM_PAIN的目的是Z减少hH口的次数?br />    非队列消息将会绕q系l队列和消息队列Q直接将消息发送到H口q程Q。系l发送非队列消息通知H口Q系l发送消息通知H口?例如,当用hzM个窗口系l发送WM_ACTIVATE, WM_SETFOCUS, and WM_SETCURSOR。这些消息通知H口它被ȀzM。非队列消息也可以由当应用程序调用系l函C生。例?当程序调用SetWindowPospȝ发送WM_WINDOWPOSCHANGED消息。一些函C发送非队列消息Q例如下面我们要谈到的函数?br />    
     消息的发?/font>
     了解了上面的q些基础理论之后Q我们就可以q行一下简单的消息发送与接收?br />     把一个消息发送到H口?U方式:发送、寄送和q播?br />     发送消息的函数有SendMessage、SendMessageCallback、SendNotifyMessage、SendMessageTimeoutQ寄送消息的函数主要有PostMessage、PostThreadMessage、PostQuitMessageQ广播消息的函数我知道的只有BroadcastSystemMessage、BroadcastSystemMessageEx?br />     SendMessage的原型如下:LRESULT SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam)Q这个函C要是向一个或多个H口发送一条消息,一直等到消息被处理之后才会q回。不q需要注意的是,如果接收消息的窗口是同一个应用程序的一部分Q那么这个窗口的H口函数p作ؓ一个子E序马上被调用;如果接收消息的窗口是被另外的U程所创徏的,那么H口pȝ切换到相应的线Eƈ且调用相应的H口函数Q这条消息不会被放进目标应用E序队列中。函数的q回值是由接收消息的H口的窗口函数返回,q回的值取决于被发送的消息?br />     PostMessage的原型如下:BOOL PostMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam)Q该函数把一条消息放|到创徏hWndH口的线E的消息队列中,该函C{消息被处理马上将控制q回。需要注意的是,如果hWnd参数为HWND_BROADCASTQ那么,消息被寄送给pȝ中的所有的重叠H口和弹出窗口,但是子窗口不会收到该消息Q如果hWnd参数为NULLQ则该函数类gdwThreadID参数讄成当前线E的标志来调用PostThreadMEssage函数?br />   从上面的q2个具有代表性的函数Q我们可以看出消息的发送方式和寄送方式的区别所在:被发送的消息是否会被立即处理Q函数是否立卌回。被发送的消息会被立即处理Q处理完毕后函数才会q回Q被寄送的消息不会被立卛_理,他被攑ֈ一个先q先出的队列中,一直等到应用程序空U的时候才会被处理Q不q函数放|消息后立即q回?br />   实际上,发送消息到一个窗口处理过E和直接调用H口处理q程之间q没有太大的区别Q他们直接的唯一区别在于你可以要求操作pȝ截获所有被发送的消息Q但是不能够截获对窗口处理过E的直接调用?br />   以寄送方式发送的消息通常是与用户输入事g相对应的Q因些事件不是十分紧q,可以q行~慢的缓冲处理,例如鼠标、键盘消息会被寄送,而按钮等消息则会被发送?br />   q播消息用得比较,BroadcastSystemMessage函数原型如下Q?br />      long BroadcastSystemMessage(DWORD dwFlags,LPDWORD lpdwRecipients,UINT uiMessage,WPARAM wParam,LPARAM lParam);该函数可以向指定的接收者发送一条消息,q些接收者可以是应用E序、可安装的驱动程序、网l驱动程序、系l别的讑֤驱动消息和他们的Ll合。需要注意的是,如果dwFlags参数是BSF_QUERYq且臛_一个接收者返回了BROADCAST_QUERY_DENYQ则q回gؓQ,如果没有指定BSF_QUERYQ则函数消息发送给所有接收者,q且忽略其返回倹{?

   消息的接?/font>
  
消息的接收主要有Q个函数QGetMessage、PeekMessage、WaitMessage?br />   GetMessage原型如下QBOOL GetMessage(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax);该函数用来获取与hWnd参数所指定的窗口相关的且wMsgFilterMin和wMsgFilterMax参数所l出的消息D围内的消息。需要注意的是,如果hWnd为NULLQ则GetMessage获取属于调用该函数应用程序的MH口的消息,如果wMsgFilterMin和wMsgFilterMax都是Q,则GetMessagep回所有可得到的消息。函数获取之后将删除消息队列中的除WM_PAINT消息之外的其他消息,至于WM_PAINT则只有在其处理之后才被删除?br />   PeekMessage原型如下QBOOL PeekMessage(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax,UINT wRemoveMsgQ;该函数用于查看应用程序的消息队列Q如果其中有消息将其放入lpMsg所指的l构中,不过Q与GetMessage不同的是QPeekMessage函数不会{到有消息放入队列时才返回。同P如果hWnd为NULLQ则PeekMessage获取属于调用该函数应用程序的MH口的消息,如果hWnd=-1Q那么函数只q回把hWnd参数为NULL的PostAppMessage函数送去的消息。如果wMsgFilterMin和wMsgFilterMax都是Q,则PeekMessagep回所有可得到的消息。函数获取之后将删除消息队列中的除WM_PAINT消息之外的其他消息,至于WM_PAINT则只有在其处理之后才被删除?br />   WaitMessage原型如下QBOOL VaitMessage();当一个应用程序无事可做时Q该函数将控制权交l另外的应用E序Q同时将该应用程序挂P直到一个新的消息被攑օ应用E序的队列之中才q回?/p>

      消息的处?/font>
   接下来我们谈一下消息的处理Q首先我们来看一下VC中的消息泵:
   while(GetMessage(&msg, NULL, 0, 0))
      {
 if(!TranslateAccelerator(msg.hWnd, hAccelTable, &msg))
         {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
         }
      }

      首先QGetMessage从进E的ȝE的消息队列中获取一个消息ƈ它复制到MSGl构Q如果队列中没有消息Q则GetMessage函数等待一个消息的到来以后才返回?如果你将一个窗口句柄作为第二个参数传入GetMessageQ那么只有指定窗口的的消息可以从队列中获得。GetMessage也可以从消息队列中过滤消息只接受消息队列中落在范围内的消息。这时候就要利用GetMessageQPeekMessage指定一个消息过滤器。这个过滤器是一个消息标识符的范围或者是一个窗体句柄,或者两者同时指定。当应用E序要查找一个后入消息队列的消息是很有用。WM_KEYFIRST ?WM_KEYLAST 帔R用于接受所有的键盘消息?WM_MOUSEFIRST ?WM_MOUSELAST 帔R用于接受所有的鼠标消息?
   然后TranslateAccelerator判断该消息是不是一个按键消息ƈ且是一个加速键消息Q如果是Q则该函数将把几个按键消息{换成一个加速键消息传递给H口的回调函数。处理了加速键之后Q函数TranslateMessage把两个按键消息WM_KEYDOWN和WM_KEYUP转换成一个WM_CHARQ不q需要注意的是,消息WM_KEYDOWN,WM_KEYUP仍然传递给H口的回调函数。   ?
   处理完之后,DispatchMessage函数把此消息发送给该消息指定的H口中已讑֮的回调函数。如果消息是WM_QUITQ则GetMessageq回Q,从而退出@环体。应用程序可以用PostQuitMessage来结束自q消息循环。通常在主H口的WM_DESTROY消息中调用?br />   下面我们举一个常见的例子来说明q个消息늚q用Q?br />   if (::PeekMessage(&msg, m_hWnd, WM_KEYFIRST,WM_KEYLAST, PM_REMOVE))
      {
          if (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE)Q.Q?br />      }
    q里我们接受所有的键盘消息Q所以就用WM_KEYFIRST ?WM_KEYLAST作ؓ参数。最后一个参数可以是PM_NOREMOVE 或?PM_REMOVEQ表C消息信息是否应该从消息队列中删除。               ?
     所以这D小代码是判断是否按下了Esc键,如果是就q行处理?/p>

   H口q程
   H口q程是一个用于处理所有发送到q个H口的消息的函数。Q何一个窗口类都有一个窗口过E。同一个类的窗口用同LH口q程来响应消息?pȝ发送消息给H口q程消息数据作为参C递给他,消息到来之后Q按照消息类型排序进行处理,其中的参数则用来区分不同的消息,H口q程使用参数产生合适行为?br />   一个窗口过E不l常忽略消息Q如果他不处理,它会消息传回到执行默认的处理。窗口过E通过调用DefWindowProc来做q个处理。窗口过E必return一个g为它的消息处理结果。大多数H口只处理小部分消息和将其他的通过DefWindowProc传递给pȝ做默认的处理。窗口过E被所有属于同一个类的窗口共享,能ؓ不同的窗口处理消息。下面我们来看一下具体的实例Q?br />   LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
   {
 int wmId, wmEvent;
 PAINTSTRUCT ps;
 HDC hdc;
 TCHAR szHello[MAX_LOADSTRING];
 LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);

 switch (message)
 {
  case WM_COMMAND:
   wmId    = LOWORD(wParam);
   wmEvent = HIWORD(wParam);
   // Parse the menu selections:
   switch (wmId)
   {
    case IDM_ABOUT:
       DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
       break;
    case IDM_EXIT:
       DestroyWindow(hWnd);
       break;
    default:
       return DefWindowProc(hWnd, message, wParam, lParam);
   }
   break;
  case WM_PAINT:
   hdc = BeginPaint(hWnd, &ps);
   // TODO: Add any drawing code here...
   RECT rt;
   GetClientRect(hWnd, &rt);
   DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER);
   EndPaint(hWnd, &ps);
   break;
  case WM_DESTROY:
   PostQuitMessage(0);
   break;
  default:
   return DefWindowProc(hWnd, message, wParam, lParam);
      }
     return 0;
   }

   消息分流?/font>
   通常的窗口过E是通过一个switch语句来实现的Q这个事情很烦,有没有更便的Ҏ呢?有,那就是消息分器Q利用消息分器Q我们可以把switch语句分成更小的函敎ͼ每一个消息都对应一个小函数Q这样做的好处就是对消息更容易管理?br />   之所以被UCؓ消息分流器,是因ؓ它可以对M消息q行分流。下面我们做一个函数就很清楚了Q?br />   void MsgCracker(HWND hWnd,int id,HWND hWndCtl,UINT codeNotify)
      {
          switch(id)
          {
     case ID_A:
                  if(codeNotify==EN_CHANGE)...
                  break;
             case ID_B:
                  if(codeNotify==BN_CLICKED)...
                  break;
             ....
           }
      }
      然后我们修改一下窗口过E:
   LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
      {
 switch(message)
         {
             HANDLE_MSG(hWnd,WM_COMMAND,MsgCracker);
             HANDLE_MSG(hWnd,WM_DESTROY,MsgCracker);
     default:
  return DefWindowProc(hWnd, message, wParam, lParam);
      }
       return 0;
   }
      在WindowsX.h中定义了如下的HANDLE_MSG宏:
   #define HANDLE_MSG(hwnd,msg,fn) \
             switch(msg): return HANDLE_##msg((hwnd),(wParam),(lParam),(fn));
      实际上,HANDLE_WM_XXXX都是宏,例如QHANDLE_MSG(hWnd,WM_COMMAND,MsgCracker);被转换成如下定义:
   #define HANDLE_WM_COMMAND(hwnd,wParam,lParam,fn)\
             ((fn)((hwnd),(int)(LOWORD(wParam)),(HWND)(lParam),(UINT)HIWORD(wParam)),0L);
      好了Q事情到了这一步,应该一切都明朗了?br />   不过Q我们发现在windowsx.h里面q有一个宏QFORWARD_WM_XXXXQ我们还是那WM_COMMANDZQ进行分析:
   #define FORWARD_WM_COMMAND(hwnd, id, hwndCtl, codeNotify, fn) \
     (void)(fn)((hwnd), WM_COMMAND, MAKEWPARAM((UINT)(id),(UINT)(codeNotify)), (LPARAM)(HWND)(hwndCtl))
   所以实际上QFORWARD_WM_XXXX消息参数进行了重新构造,生成了wParam && lParamQ然后调用了我们定义的函数?br />   好了Q事情到q里也算是也D落了,明天我们再分析消息在MFC中的处理?/p>

]]>
转脓:深度解析VC中的消息(?http://www.shnenglu.com/cppblog/archive/2006/07/20/10244.html潜龙?/dc:creator>潜龙?/author>Thu, 20 Jul 2006 03:19:00 GMThttp://www.shnenglu.com/cppblog/archive/2006/07/20/10244.htmlhttp://www.shnenglu.com/cppblog/comments/10244.htmlhttp://www.shnenglu.com/cppblog/archive/2006/07/20/10244.html#Feedback0http://www.shnenglu.com/cppblog/comments/commentRss/10244.htmlhttp://www.shnenglu.com/cppblog/services/trackbacks/10244.html
消息是指什么?
消息pȝ对于一个win32E序来说十分重要Q它是一个程序运行的动力源泉。一个消息,是系l定义的一?2位的|他唯一的定义了一个事Ӟ向Windows发出一个通知Q告诉应用程序某个事情发生了。例如,单击鼠标、改变窗口尺寸、按下键盘上的一个键都会使Windows发送一个消息给应用E序?br />消息本n是作Z个记录传递给应用E序的,q个记录中包含了消息的类型以及其他信息。例如,对于单击鼠标所产生的消息来_q个记录中包含了单击鼠标时的坐标。这个记录类型叫做MSGQMSG含有来自windows应用E序消息队列的消息信息,它在Windows中声明如下:
typedef struct tagMsg
{
HWND hwnd; 接受该消息的H口句柄
UINT message; 消息帔R标识W,也就是我们通常所说的消息?br />WPARAM wParam; 32位消息的特定附加信息Q确切含义依赖于消息?br />LPARAM lParam; 32位消息的特定附加信息Q确切含义依赖于消息?br />DWORD time; 消息创徏时的旉
POINT pt; 消息创徏时的鼠标/光标在屏q坐标系中的位置
}MSG;
消息可以ql或者应用程序生。系l在发生输入事g时生消息。D个例? 当用h? Ud鼠标或者单L件。系l也产生消息以响应由应用E序带来的变? 比如应用E序改变pȝ字体改变H体大小。应用程序可以生消息ɽH体执行dQ或者与其他应用E序中的H口通讯?

消息中有什么?
我们l出了上面的注释Q是不是会对消息l构有了一个比较清楚的认识Q如果还没有Q那么我们再试着l出下面的解释:
hwnd 32位的H口句柄。窗口可以是Mcd的屏q对象,因ؓWin32能够l护大多数可视对象的句柄(H口、对话框、按钮、编辑框{??br />message用于区别其他消息的常量|q些帔R可以是Windows单元中预定义的常量,也可以是自定义的帔R。消息标识符以常量命名的方式指出消息的含义。当H口q程接收到消息之后,他就会用消息标识符来决定如何处理消息。例如、WM_PAINT告诉H口q程H体客户改变了需要重l。符号常量指定系l消息属于的cdQ其前缀指明了处理解释消息的H体的类型?br />wParam 通常是一个与消息有关的常量|也可能是H口或控件的句柄?br />lParam 通常是一个指向内存中数据的指针。由于WParam、lParam和Pointer都是32位的Q因此,它们之间可以怺转换?br />
消息标识W的?br />pȝ保留消息标识W的值在0x0000?x03ff(WM_USER-1)范围。这些Dpȝ定义消息使用?应用E序不能使用q些值给自己的消息。我们顺便说一下具有标志性的消息|
WM_NULL---0x0000 I消息?br />0x0001----0x0087 主要是窗口消息?br />0x00A0----0x00A9 非客户区消息
0x0100----0x0108 键盘消息
0x0111----0x0126 菜单消息
0x0132----0x0138 颜色控制消息
0x0200----0x020A 鼠标消息
0x0211----0x0213 菜单循环消息
0x0220----0x0230 多文档消?br />0x03E0----0x03E8 DDE消息
0x0400 WM_USER
0x8000 WM_APP
0x0400----0x7FFF 应用E序自定义私有消?br />
消息有哪几种Q?br />其实Qwindows中的消息虽然很多Q但是种cdƈ不繁杂,大体上有3U:H口消息、命令消息和控g通知消息?br />H口消息大概是系l中最为常见的消息Q它是指由操作系l和控制其他H口的窗口所使用的消息。例如CreateWindow、DestroyWindow和MoveWindow{都会激发窗口消息,q有我们在上面谈到的单击鼠标所产生的消息也是一U窗口消息?br />命o消息Q这是一U特D的H口消息Q他用来处理从一个窗口发送到另一个窗口的用户hQ例如按下一个按钮,他就会向ȝ口发送一个命令消息?br />控g通知消息Q是指这样一U消息,一个窗口内的子控g发生了一些事情,需要通知父窗口。通知消息只适用于标准的H口控g如按钮、列表框、组合框、编辑框Q以及Windows公共控g如树状视图、列表视囄。例如,单击或双M个控件、在控g中选择部分文本、操作控件的滚动条都会生通知消息?她类g命o消息Q当用户与控件窗口交互时Q那么控仉知消息׃从控件窗口发送到它的ȝ口。但是这U消息的存在q不是ؓ了处理用户命令,而是Z让主H口能够改变控gQ例如加载、显C数据。例如按下一个按钮,他向父窗口发送的消息也可以看作是一个控仉知消息Q单击鼠标所产生的消息可以由ȝ口直接处理,然后交给控gH口处理?br />其中H口消息及控仉知消息主要q口类即直接或间接由CWNDcL生类处理。相对窗口消息及控g通知消息而言Q命令消息的处理对象范围广得多Q它不仅可以q口类处理Q还可以由文档类Q文档模板类及应用类所处理?br />׃控g通知消息很重要的Qh们用的也比较多,但是具体的含义往往令初学者晕头{向,所以我军_把常见的几个列出来供大家参考:
按扭控g
BN_CLICKED 用户单击了按?br />BN_DISABLE 按钮被禁?br />BN_DOUBLECLICKED 用户双击了按?br />BN_HILITE ?户加亮了按钮
BN_PAINT 按钮应当重画
BN_UNHILITE 加亮应当L
l合框控?br />CBN_CLOSEUP l合框的列表框被关闭
CBN_DBLCLK 用户双击了一个字W串
CBN_DROPDOWN l合框的列表框被拉出
CBN_EDITCHANGE 用户修改了编辑框中的文本
CBN_EDITUPDATE ~辑框内的文本即更?br />CBN_ERRSPACE l合框内存不?br />CBN_KILLFOCUS l合框失去输入焦?br />CBN_SELCHANGE 在组合框中选择了一?br />CBN_SELENDCANCEL 用户的选择应当被取?br />CBN_SELENDOK 用户的选择是合法的
CBN_SETFOCUS l合框获得输入焦?br />~辑框控?br />EN_CHANGE ~辑框中的文本己更新
EN_ERRSPACE ~辑框内存不?br />EN_HSCROLL 用户点击了水qx动条
EN_KILLFOCUS ~辑框正在失去输入焦?br />EN_MAXTEXT 插入的内容被截断
EN_SETFOCUS ~辑框获得输入焦?br />EN_UPDATE ~辑框中的文本将要更?br />EN_VSCROLL 用户点击了垂直滚动条消息含义
列表框控?br />LBN_DBLCLK 用户双击了一?br />LBN_ERRSPACE 列表框内存不?br />LBN_KILLFOCUS 列表框正在失去输入焦?br />LBN_SELCANCEL 选择被取?br />LBN_SELCHANGE 选择了另一?br />LBN_SETFOCUS 列表框获得输入焦?br />

]]>
CWnd下几个相似的WindowMessage Functions的讨?/title><link>http://www.shnenglu.com/cppblog/archive/2006/07/20/10242.html</link><dc:creator>潜龙?/dc:creator><author>潜龙?/author><pubDate>Thu, 20 Jul 2006 00:40:00 GMT</pubDate><guid>http://www.shnenglu.com/cppblog/archive/2006/07/20/10242.html</guid><wfw:comment>http://www.shnenglu.com/cppblog/comments/10242.html</wfw:comment><comments>http://www.shnenglu.com/cppblog/archive/2006/07/20/10242.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.shnenglu.com/cppblog/comments/commentRss/10242.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/cppblog/services/trackbacks/10242.html</trackback:ping><description><![CDATA[ <strong>首先概要的说<br /></strong>SendMessage<br />向CWnd对象发送一个消息,<strong>直到q条消息被处理之后才q回<br /></strong>PostMessage<br />一条消息放入应用程序的消息队列Q?strong>然后不等H口处理q条消息直接q回<br /></strong>SendNotifyMessage<br />一条消息发送到H口q尽快返回,<strong>q回的速度取决于该H口是否是由调用U程所创徏<br />下面我逐条l细说明<br /></strong>CWnd::SendMessage<br />LRESULT SendMessage( UINT message, WPARAM wParam = 0, LPARAMlParam = 0 );<br />q回?: <strong>消息处理的结果;它的g赖于发送的消息?/strong><br />参数 : message    指定了要发送的消息?br />            wParam    指定了与消息有关的附加信息?br />            lParam      指定了与消息有关的附加信息?br />说明 :  q个函数向窗口发送指定的消息 ?br />             SendMessage成员函数直接调用H口q程q在H口q程处理了消息以后才q回?br />              q与PostMessage成员函数形成ҎQ该函数消息放入窗口的消息队列q立卌回?br /><br /><br />CWnd::PostMessage<br />BOOL PostMessage( UINT message, WPARAM wParam = 0, LPARAM lParam =0 );<br />q回?: <strong>如果公布了消息,则返回非零|否则q回0?/strong><br />参数 :    message    指定了要公布的消息?br />               wParam    指定了附加的消息信息。这个参数的内容依赖于要公布的消息?br />                lParam     指定了附加的消息信息。这个参数的内容依赖于要公布的消息?br />说明 : q个函数一个消息放入窗口的消息队列Q然后直接返回,q不{待对应的窗口处理消息?br />           消息队列中的消息是通过调用Windows的GetMessage或PeekMessage函数来获得的。可以通过Windows的PostMessage函数来访问其它应用程序?br /><br /><br />CWnd::SendNotifyMessage<br />BOOL SendNotifyMessage( UINT message, WPARAM wParam, LPARAMlParam );<br />q回值?: <strong>如果函数成功Q则q回非零|否则q回0?br /></strong>参数 :     message    指定了要发送的消息?br />                wParam    指定了与消息有关的附加信息?br />                lParam      指定了与消息有关的附加信息?br />说明 : q个函数向窗口发送指定的消息?br />            如果H口是由调用U程创徏的,则SendNotifyMessage调用H口的窗口过E,q在H口处理了消息之后返回。如果窗口是由其它线E创建的Q则SendNotifyMessage消息传递给H口q程q立卌回;它ƈ不等待窗口过E结束处理消息?br /><br /><br />单ȝ一下,<br />   <strong>PostMessage只负责将消息攑ֈ消息队列中,不确定何时及是否处理<br />    SendMessage要等到受到消息处理的q回码(DWordcdQ后才l?br />    PostMessage执行后马上返?br />    SendMessage必须{到消息被处理后才会q回?br /></strong>   <strong>SendMessage消息发出后,如不能尽快得到解军_应,则会DE序的停滞,所以此函数慎用。PostMessage则无此后果,不过你要是用PostMessageQ那你的消息不知道要{到猴年马月才能被处理。SendMessage可以保证你的消息在得不到处理的情况下谁也别想动你的窗口?br />     无论是PostMessageq是SendMessage均由ȝE处理?br />Windows的线E有UI(用户接口)U程和工作线E,一般工作线E没有自q消息循环Q而UI(用户接口)U程有自q消息循环?br />    所以一般主U程应该是UI(用户接口)U程Q其余的处理特定d的线E都是工作线E,它们把消息发l主U程Q由ȝE的消息处理函数处理?br />SendMessage是阻塞的Q它要等CU程处理完消息后才返回的?br />而PostMessage是非d的,调用之后Q立卌回,而没有去兛_ȝE又没有处理q个消息?br /></strong><img src ="http://www.shnenglu.com/cppblog/aggbug/10242.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/cppblog/" target="_blank">潜龙?/a> 2006-07-20 08:40 <a href="http://www.shnenglu.com/cppblog/archive/2006/07/20/10242.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>qVC/MFC下窗口的拖放http://www.shnenglu.com/cppblog/archive/2006/07/18/10200.html潜龙?/dc:creator>潜龙?/author>Tue, 18 Jul 2006 09:40:00 GMThttp://www.shnenglu.com/cppblog/archive/2006/07/18/10200.htmlhttp://www.shnenglu.com/cppblog/comments/10200.htmlhttp://www.shnenglu.com/cppblog/archive/2006/07/18/10200.html#Feedback4http://www.shnenglu.com/cppblog/comments/commentRss/10200.htmlhttp://www.shnenglu.com/cppblog/services/trackbacks/10200.htmlH口在接收客户区或非客户区的鼠标消息之前Q它都一定首先接收到光标的屏q坐标和WM_NCHITTEST消息。大多数应用E序q不处理WM_NCHITTEST消息Q而是让Windows自行处理WM_NCHITTEST消息?br />例程1[工程名ht]      本例E阻止在一个标题栏上的双击影响H口
头文件htView.h中添加afx_msg void OnNcLButtonDblClk(UINT nHitTest,CPoint point);
L件htView.cpp中添加ON_WM_NCLBUTTONDBLCLK()?br />void CHtView::OnNcLButtonDblClk(UINT nHitTest,CPoint point);
{
    if( nHitTest != HTCAPTION)
       CView::OnNcLButtonDblClk(nHitTest,point);
}



例程2 [工程名hit]     本例E实C客户区的H口拖动
头文件hitView.h中添加afx_msg UINT OnNcHitTest(CPoint point);
L件hitView.cpp中添加ON_WM_NCHITTEST()?br />UINT CHitView::OnNcHitTest(CPoint point)
{
    UINT nHitTest = CView::OnNcHitTest(point);
    if(nHitTest == HTCLIENT)
    nHitTest = HTCAPTION;
    return nHitTest;
}

需要源代码例程的可以给我留a?img src ="http://www.shnenglu.com/cppblog/aggbug/10200.html" width = "1" height = "1" />

]]>
转蝲自天蝎之?Windows~程中SetViewportOrg与SetWindowOrg的理?http://www.shnenglu.com/cppblog/archive/2006/07/12/9716.html潜龙?/dc:creator>潜龙?/author>Wed, 12 Jul 2006 02:08:00 GMThttp://www.shnenglu.com/cppblog/archive/2006/07/12/9716.htmlhttp://www.shnenglu.com/cppblog/comments/9716.htmlhttp://www.shnenglu.com/cppblog/archive/2006/07/12/9716.html#Feedback2http://www.shnenglu.com/cppblog/comments/commentRss/9716.htmlhttp://www.shnenglu.com/cppblog/services/trackbacks/9716.htmlWindows~程中SetViewportOrg与SetWindowOrg的理?/div>
关键?/b>Q?MFC,    SetWindowOrg,    SetViewportOrg,    深入出MFC                                          

最q突然又很有Ȁ情的开始看Jeff Prosise的那?Programming Windows with MFC, 2 ed."。尽是英文版的Q但是感觉这本书上手比喉l的那本所谓的 深入出MFC 要容易理解的多。候同学给ZU故弄玄虚故作深沉的感觉Q而Jeff Prosise的这本书才真正的U得上是深入出?/p>

管如此Q其中有关GDIl图中的坐标映射部分q是有一个问题没有搞清楚Q那是SetWindowOrg和SetViewportOrgq两个函数到底应该如何理解。潘爱民译的那本VC内幕没有讲清楚;Jeff Prosise的这本书没有讲清楚;MSDN上的东西看的也是一头雾_Charles Petzold的那本书q没有来得及看。因个问题,昨天晚上是带着遗憾的困惑入睡的?/p>

ȝ来说Q我对这两个函数的理解导致的l果是与实际E序q行的结果截然相反。依据MSDN上的解释Q有一个很严重的问题没有阐q清楚,那就是:所谓的SetWindowOrg(x, y)函数Q到底是表示set window origin to (x, y)q是set window origin as (x, y)Qto和as在执行的时候,其操作的效果是截然相反的?/p>

set window origin to (x, y)表示坐标原点设|到(x, y)Q即?x, y)作ؓ坐标原点Q此时原点坐标不再ؓ(0, 0)Q?br />set window origin as (x, y)表示原来的原点(0, 0)的坐标改?x, y)Q即所有点的坐标增?+x, +y)Q?/p>

现在我的理解是:应该?set window origin to (x, y)。这U理解基于以下几个前提:
1. 所有绘图语句中l出的坐标,全部是逻辑坐标Q即?window 中的坐标(相对于viewport所表示的设备坐标而言);
2. 所有用戯看到的点Q其讑֤坐标一定是位于(0, 0)?1024, 768)范围内;(假设昄器ؓ输出讑֤Q采用MM_TEXT映射方式Q且屏幕分L率ؓ1024*768);
3. 所谓?0,0)原点,原点的坐标一定就?0,0)”这U理解,是错误的Q?br />4. Viewport中的坐标表示讑֤坐标QWindow中的坐标表示逻辑坐标Q?br />5. 当在逻辑坐标中指定新的原点后Q在执行映射Ӟ讑֤坐标的原点一定要与逻辑坐标的新原点重合Q反q来也是一P即两个坐标系的原点一定要重合?/p>

下面举例说明Q?MM_TEXT映射模式)


(1)
CRect rect(0, 0, 200, 200);
dc.rectangle(rect);
上面的语句在屏幕的最左上角绘制一个正方Ş;(因ؓ此时逻辑坐标与设备坐标没有偏U?

(2)
dc.SetViewportOrg(100, 100);
CRect rect(0, 0, 200, 200);
dc.rectangle(rect);
设备坐标的原点讄?100, 100)Q即讑֤坐标的原点不?0, 0)处,而是?100, 100)处;此时若执行映的话,逻辑坐标的原?0, 0)需要与讑֤坐标的原?100, 100)重合(参考前?)Q那么此时绘制的矩Ş(0, 0, 200, 200)的坐?为逻辑坐标Q参考前?)在设备坐标中׃映射?100, 100, 300, 300)Q最l我们在昄器上看到的会是一个向右下方偏U?100, 100)的一个边长ؓ200的正方Ş(用户看到的点是在讑֤坐标中的Q参考前?)

(3)
dc.SetWindowOrg(100, 100);
CRect rect(0, 0, 200, 200);
dc.rectangle(rect);
逻辑坐标的原点设|到(100, 100)Q即逻辑坐标的原点不?0, 0)处,而是?100, 100)处;此时若执行映的话,讑֤坐标的原?0, 0)需要与逻辑坐标的原?100, 100)重合(参考前?)Q那么此时绘制的矩Ş(0, 0, 200, 200)的坐?为逻辑坐标Q参考前?)在设备坐标中׃映射?-100, -100, 100, 100)Q最l我们在昄器上看到的会是一个只?/4个大的矩Ş的一部分(事实上相当于向左上方偏移(100, 100)的一个边长ؓ200的正方Ş。注意:用户看到的点是在讑֤坐标中的Q参考前?)

【作? xqscorpion?



]]>
转蝲Q理解SetWindowOrg,SetViewportOrg,SetWindowExt,SetViewportExthttp://www.shnenglu.com/cppblog/archive/2006/07/12/9715.html潜龙?/dc:creator>潜龙?/author>Wed, 12 Jul 2006 02:07:00 GMThttp://www.shnenglu.com/cppblog/archive/2006/07/12/9715.htmlhttp://www.shnenglu.com/cppblog/comments/9715.htmlhttp://www.shnenglu.com/cppblog/archive/2006/07/12/9715.html#Feedback3http://www.shnenglu.com/cppblog/comments/commentRss/9715.htmlhttp://www.shnenglu.com/cppblog/services/trackbacks/9715.html 理解SetWindowOrg,SetViewportOrg,SetWindowExt,SetViewportExt
按习惯,(0,0)原点,原点是(0,0)Q但是如果用此来理解windows的map modeQ就会走弯\。其实,E微改变一下观念,windows的map mode比较好理解了。D例说明:

page space---->device space
pDC->SetMapMode(MM_LOMETRIC);
pDC->SetWindowOrg(40,0);  //q句“设定”page space的原点ؓ(40,0)Q注意,
//q时(40,0)是原点Q原点就?40,0)q个点,其实Q?0,0)与原Ҏ有必然联pR这
//一句对下面的画囑և数在page space中所作的图不会有M影响。一句话QSetWindowOrg
//是指定一下,page space中哪个点为原炏V?br />pDC->Rectangle(0,0,100,-100);
pDC->Rectangle(0,-100,50,-200);

同理QSetViewportOrg也是指定一下,device space中哪个点为原点,两个坐标pL时Q两个原炚w合?br />
SetWindowExt讑֮page space的大,SetViewportOrg讑֮device space的大,其实Q真正有意义的只是两者的比例关系Q例如,在一?024*768的显C屏上:

pDC->SetMapMode(MM_ISOTROPIC);
pDC->SetWindowExt(10240,7680);
pDC->SetViewportExt(1024,768);
pDC->Rectangle(0,0,100,100);

  ׃M?0 pixels*10 pixels的矩形。其本质是QX方向Q每个逻辑单位?024/10240个象素,Y方向每个逻辑单位?68/7680个象素。因此,下面的代码有相同的作用:

pDC->SetMapMode(MM_ISOTROPIC);
pDC->SetWindowExt(102400,76800);
pDC->SetViewportExt(10240,7680);
pDC->Rectangle(0,0,100,100);

两者本质一P前者更易于理解?br />作? johnson    来源: 九九星个Z?-- E序设计 -- C++E序设计

]]>
þĻƷһ| þþþþùƷŮ| þþþþ| 99þùۺ| ŷ޹Ʒþ| ഺþ| þseƷһӰԺ| þþþƷѹĻ| Ʒһþù| þһ | þֻоƷ4| þùӰԺ| ˼˼þ99ѾƷ6| ij˾þþþӰԺѹۿ| ҹƷþþþ9999| ˳wwwþþ| þˬ˰| þ99þ99Ʒӿ | ŷۺϾþͼƬ| ŷСþþþþþ| þAVij| ޾Ʒtvþþþþþþ| þ99ֻƵƷ8| 鶹ƷþþƷɫۺ| ƷȾþav| պƷþþþþþõӰ| ҹƷþþþþ99| Ʒþ8xѹۿ| þþþƷ޳18վ | ٸ߳ҽоþþ| þ99ƷۺϹҳ| þþƷav| þۺϸϾþù| þùۺϾƷ| ŷ츾XXXXԾþþ| ۺþþ| ޾Ʒһ߾þ| ƷƷþþþ| ޹㽶þþþþ| þ99þ99СݾƷӿ| þþƷ99þþùŴ|