Jiang,Sheng ,a Microsoft Most Valuable Professional of Visual C++, became a Visual C++ programmer at 1999. He actives on several online Visual C++ forums ,blogs and newsgroups
8/20/2005
MFC,欢乐与痛苦
//如果这段代码可以工作,那么它的作者是Jiangsheng
//否则我不知道它的作者
void __stdcall CFrontPageAddin::OnClickButtonExportCHM(IDispatch* /*Office::_CommandBarButton*
*/ Ctrl,VARIANT_BOOL * CancelDefault)
{
AtlTrace(_T(" CFPAnt::OnClickButtonExportCHM\n"));
//create a thread to avoid assert failure
CDialogThread* pDialogThread=
(CDialogThread*)AfxBeginThread(RUNTIME_CLASS(CDialogThread),
THREAD_PRIORITY_NORMAL,
0,
CREATE_SUSPENDED,NULL);
if(pDialogThread)
{
pDialogThread->m_prc=RUNTIME_CLASS(CExportCHMSheet);
pDialogThread->ResumeThread();
pDialogThread->WaitForDoModal();
delete pDialogThread;
}
}
class CDialogThread : public CWinThread
{
......
int m_nModalResult;
CRuntimeClass* m_prc;
void WaitForDoModal();
......
};
CDialogThread::CDialogThread()
{
m_bAutoDelete=FALSE;
m_prc=NULL;
m_nModalResult=0;
}
BOOL CDialogThread::InitInstance()
{
// TODO: perform and per-thread initialization here
AFX_MANAGE_STATE(AfxGetAppModuleState());
AFX_MODULE_STATE* pModuleState=AfxGetModuleState();
pModuleState->m_hCurrentInstanceHandle=_Module.GetModuleInstance();
AfxSetResourceHandle(_Module.GetModuleInstance());
if(m_prc)
{
if(m_prc->IsDerivedFrom(RUNTIME_CLASS(CDialog)))
{
CDialog* pDialog=(CDialog*)m_prc->CreateObject();
if(pDialog)
{
m_pMainWnd=pDialog;
m_nModalResult=pDialog->DoModal();
}
}
else if(m_prc->IsDerivedFrom(RUNTIME_CLASS(CPropertySheet)))
{
CPropertySheet* pDialog=(CPropertySheet*)m_prc->CreateObject();
if(pDialog)
{
m_pMainWnd=pDialog;
m_nModalResult=pDialog->DoModal();
}
}
}
return FALSE;
}
void CDialogThread::WaitForDoModal()
{
//from http://blogs.msdn.com/oldnewthing/archive/2005/02/17/375307.aspx
MSG msg;
UINT cRecords = 0;
while (true) {
switch (MsgWaitForMultipleObjects(1, &m_hThread,
FALSE, INFINITE, QS_ALLINPUT)) {
case WAIT_OBJECT_0:
return ; // event has been signalled
break;
case WAIT_OBJECT_0+1:
// we have a message - peek and dispatch it
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
break;
default:
return ; // unexpected failure
}
}
}
使用VC6.0编译通过。
上面的方法只对于DLL之类的组件比较有用。对于使用MFC的应用程序来说,上面的方法比较繁琐。比较简单的方法还是使用MFC向导来创建应用程序,然后再添加ATL或者.Net之类的额外支持。参考微软知识库文章Q181505和Q824480。
参考
BUG: You receive an "ASSERT in wincore.cpp" assert when an MFC application calls a function in MFC regular DLL in Visual C++(http://support.microsoft.com/kb/194300)
PRB: ATL COM AppWizard Doesn't Offer MFC Support for .EXE(http://support.microsoft.com/kb/181505)
PRB:为 C++ DLL 项目建立托管扩展时出现链接器警告(http://support.microsoft.com/kb/814472)
BUG: "HRESULT - 0x80010106" Error When You Run a Managed C++ Application(http://support.microsoft.com/kb/824480)
7/09/2005
Hook DHTML Commands
Hook DHTML Commands
浏览器在执行很多命令之前都会允许容器来替换默认的处理。在执行一些默认的命令之前,系统会查询用户对IDocHostUIHandler的实现对象的IOleCommandTarget接口,调用默认(NULL)或者CGID_DocHostCommandHandler命令组的命令。如果容器的对应命令处理返回S_OK。那么默认的处理就不会被调用。
下面列出一些可以在容器中自定义的操作:(这些常量的定义位于docobj.h中)
- OLECMDID_PRINT,默认命令组
- OLECMDID_SHOWSCRIPTERROR, CGID_DocHostCommandHandler命令组
- OLECMDID_FOCUSVIEWCONTROLSQUERY, CGID_DocHostCommandHandler命令组
- OLECMDID_SHOWPAGEACTIONMENU, CGID_DocHostCommandHandler命令组
MFC提供了一些比较容易扩展的类和宏,这样可以很容易地在扩展容器来实现新的接口。这里使用CCmdTarget类提供的GetInterfaceHook虚函数来进行扩展。
浏览器控件访问容器的方式是查询容器的IDocHostUIHandler接口,而对于浏览器辅助对象(Browser Helper Object/ BHO),不能修改容器来增加一个新的接口。这时候可以通过HTML文档的ICustomDoc接口来设置自己的IDocHostUIHandler接口。
在捕获容器的命令的过程中发现一些其他命令也被发送到容器(按时间顺序):
| 行为 | 命令组 | 命令 |
| 加载 | NULL | OLECMDID_SETDOWNLOADSTATE |
| 000214D0-0000-0000-C000-000000000046 | OLECMDID_PASTESPECIAL/ OLECMDID_HIDETOOLBARS / OLECMDID_PREREFRESH/ OLECMDID_ONUNLOAD | |
| NULL | OLECMDID_SETPROGRESSMAX/ OLECMDID_SETPROGRESSPOS/ OLECMDID_SETDOWNLOADSTATE | |
| 打印 | CGID_DocHostCommandHandler | OLECMDID_PRINT |
| 刷新 | CGID_DocHostCommandHandler | 0x1799 |
| NULL | OLECMDID_PREREFRESH/ OLECMDID_SETPROGRESSMAX/ OLECMDID_SETPROGRESSPOS/ OLECMDID_SETDOWNLOADSTATE | |
| 000214D0-0000-0000-C000-000000000046
| OLECMDID_ONUNLOAD/ OLECMDID_PREREFRESH |
不是所有常用操作都会转发到容器。OLECMDID_PRINTPREVIEW、OLECMDID_SAVEAS、OLECMDID_REFRESH看起来就没有被转发。
参考文档:
- MSDN文章 MFC技术文档TN038 MFC/OLE IUnknown Implementation (http://msdn.microsoft.com/library/en-us/vclib/html/_mfcnotes_tn038.asp)
- 微软知识库文章 Q261003 How to handle script errors as a WebBrowser control host (http://support.microsoft.com/kb/261003)
- 微软知识库文章 Q317024 Script error notification is not sent to Exec method of WebBrowser Host(http://support.microsoft.com/kb/317024)
- MSDN文章 WebBrowser Customization (http://msdn.microsoft.com/workshop/browser/hosting/wbcustomization.asp)
- 微软知识库文章 Q267240 How to print custom headers and footers for a WebBrowser control in Internet Explorer (http://support.microsoft.com/kb/267240)
Visual Studio 2005 June CTP的资源编辑器似乎有点问题,改过资源就保存不到原文件了,只能保存到另一个文件,关闭Visual Stuio之后替换(关闭solution都不行)。
7/05/2005
Visual Studio 2005中MFC的变化
一些源代码的变化:
对CLR、.Net类库和Winform控件的支持。
多处安全性的增强,对于函数参数和消息影射类型的检查加强。对ISAPI的支持看起来改动很大。
对基于64位处理器的软件开发的支持。
一些过时功能,例如MFC的DAO类,的使用受到限制。对于64位开发环境,MFC的DAO类是被禁用的。
OLE控件容器和激活状态的改进
新增加的ENSURE宏在ASSERT之外还可以抛出异常。
修正了一些BUG
VC7引入的对GetHtmlDocument()的引用导致内存泄漏的问题。
CHtmlView::ExecFormsCommand中调用IOleCommandTarget::Exec时参数写反了的问题
把CArchiveException::generic修改为CArchiveException::genericException以避免潜在的关键字冲突(微软看起来又准备引入一个新的关键字)
6/30/2005
把WinDbg集成到Visual Studio中
标题 : WinDbg
命令行: C:\masm32\debug\windbg.exe (这不是一个典型路径,但是既然MASM里面有了,我也懒得再去下一个来装,如果是单独下载安装的话,命令行可能像这样:"C:\Program Files\Debugging Tools for Windows\windbg.exe")
参数:-ee c++ -G -i "$(TargetDir)" -y "$(TargetDir)" -QY -logo -QSY -sdce -WF "$(ProjectFileName).WEW" "$(TargetPath)"
(命令行太长的时候windbg会工作不正常。至于这些参数的含义——呃,还是去下一个Debug Tools For Windows回来装上看文档比较好。)
初始目录: $(ProjectDir)
当然,调试的代码不限于C++,实际上,我主要是用windbg来调试汇编代码。
6/08/2005
使用WinDbg调试VC程序
调试Visual Studio .Net 的程序需要用户是管理员或者"Debug User"用户组成员。如果登录用户不是该组成员,那么也可以用WinDbg来调试程序。