今天,距离我开始实习(2007.08.06)到工作马上就一年了,这一年中,我学到了很多东西,东西很杂,有时候自己都忘记了看过的一些东西。稀落算算,看得也有十几本书了,有的走马观花,有的爱不释手。不过这些书对我的成长起到了决定性的作用。所以在接下来的日子里,我要重温旧梦,达到更高的境界,因为愚人打算要飞得更高。
案例一,如何在vc中支持shell 以及dde。
在vc中,利用MFC建立的程序,在CMyApp的InitInstance()中,增加EnableShellOpen(),以及RegisterShellFileTypes()。就可以支持双击打开,以及dde。
为了支持 dde, 跟到代码中可以看到
void CDocManager::RegisterShellFileTypes(BOOL bCompat)中有部分相关代码
……………………
// path/shell/open/ddeexec = [open("%1")]
strTemp.Format(_afxShellOpenFmt, (LPCTSTR)strFileTypeId,
(LPCTSTR)_afxDDEExec);
if (!_AfxSetRegKey(strTemp, _afxDDEOpen))
……………………
于是,运行完后,可以看到在注册表中对应的程序文件中有如下键值:
HKEY_CLASSES_ROOT中对应有ddeexec对应键值[open(“% 1” )]。
在vc的DOCMGR.CPP中有如下定义
AFX_STATIC_DATA const TCHAR _afxShellOpenFmt[] = _T("%s//shell//open//%s");
AFX_STATIC_DATA const TCHAR _afxShellPrintFmt[] = _T("%s//shell//print//%s");
AFX_STATIC_DATA const TCHAR _afxShellPrintToFmt[] = _T("%s//shell//printto//%s");
AFX_STATIC_DATA const TCHAR _afxDefaultIconFmt[] = _T("%s//DefaultIcon");
AFX_STATIC_DATA const TCHAR _afxShellNewFmt[] = _T("%s//ShellNew");
#define DEFAULT_ICON_INDEX 0
AFX_STATIC_DATA const TCHAR _afxIconIndexFmt[] = _T(",%d");
AFX_STATIC_DATA const TCHAR _afxCommand[] = _T("command");
AFX_STATIC_DATA const TCHAR _afxOpenArg[] = _T(" /"%1/"");
AFX_STATIC_DATA const TCHAR _afxPrintArg[] = _T(" /p /"%1/"");
AFX_STATIC_DATA const TCHAR _afxPrintToArg[] = _T(" /pt /"%1/" /"%2/" /"%3/" /"%4/"");
AFX_STATIC_DATA const TCHAR _afxDDEArg[] = _T(" /dde");
AFX_STATIC_DATA const TCHAR _afxDDEExec[] = _T("ddeexec");
AFX_STATIC_DATA const TCHAR _afxDDEOpen[] = _T("[open(/"%1/")]");
AFX_STATIC_DATA const TCHAR _afxDDEPrint[] = _T("[print(/"%1/")]");
AFX_STATIC_DATA const TCHAR _afxDDEPrintTo[] = _T("[printto(/"%1/",/"%2/",/"%3/",/"%4/")]");
AFX_STATIC_DATA const TCHAR _afxShellNewValueName[] = _T("NullFile");
AFX_STATIC_DATA const TCHAR _afxShellNewValue[] = _T("");
支持注册表的注册。
关于DDE,首先从WM_DDE_EXECUTE消息开始,在CFrameWnd中有如下消息映射
ON_MESSAGE(WM_DDE_INITIATE, OnDDEInitiate)
ON_MESSAGE(WM_DDE_EXECUTE, OnDDEExecute)
ON_MESSAGE(WM_DDE_TERMINATE, OnDDETerminate)
OnDDEExecute中会触发
if (!AfxGetApp()->OnDDECommand(szCommand))
于是,最终调用到BOOL CDocManager::OnDDECommand(LPTSTR lpszCommand)中,不过这里有点需要注意的情况:
// always ACK the execute command - even if we do nothing
LRESULT CFrameWnd::OnDDEExecute(WPARAM wParam, LPARAM lParam)
{
// unpack the DDE message
UINT unused;
HGLOBAL hData;
VERIFY(UnpackDDElParam(WM_DDE_EXECUTE, lParam, &unused, (UINT*)&hData));
// get the command string
TCHAR szCommand[_MAX_PATH * 2];
LPCTSTR lpsz = (LPCTSTR)GlobalLock(hData);
lstrcpyn(szCommand, lpsz, _countof(szCommand));
GlobalUnlock(hData);
// acknowledge now - before attempting to execute
::PostMessage((HWND)wParam, WM_DDE_ACK, (WPARAM)m_hWnd,
ReuseDDElParam(lParam, WM_DDE_EXECUTE, WM_DDE_ACK,
(UINT)0x8000, (UINT)hData));
// don't execute the command when the window is disabled
if (!IsWindowEnabled())
{
TRACE1("Warning: DDE command '%s' ignored because window is disabled./n",
szCommand);
return 0;
}
// execute the command
if (!AfxGetApp()->OnDDECommand(szCommand))
TRACE1("Error: failed to execute DDE command '%s'./n", szCommand);
return 0L ;
}
以上是VC6.0的源码,不过在VS2003中,这里有个错误,即漏掉了语句
lstrcpyn(szCommand, lpsz, _countof(szCommand));所以对DDE的支持失败。
注:可以从CodeGuru上找到类似的说明。
解决方法: 在自己的CMainFrame中重写
ON_MESSAGE(WM_DDE_EXECUTE, OnDDEExecute)
以及 OnDDEExecute函数。
案例二,关于CScrollView。
感觉这里好像有个bug,就是在
SetScrollSizes()后调用ScrollToPosition()。如果doc的大小明显小于View的ClientRect时,那么ScrollToPosition()中的参数不管设多少,其返回Scroll的Position不为零。
感觉很是奇怪,最后的解决办法在自己在调用ScrollToPosition时提前判断一下,viewRect的大小是否大于DocRect来解决问题的。